From 76830c5e22a248ed4c587becc1052f9ecb72ad1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Wed, 13 May 2026 14:59:20 +0000 Subject: [PATCH] chore: add log-tag lint + fix biome errors + pre-push hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scripts/lint-log-tags.sh: static check for invalid Crockford Base32 log tags (I/L/O/U) - fix two invalid log tags in ws-client.ts (6CJX2RLP→6CJX2R8P, T9W2KL5H→T9W2K35H) - fix biome errors: unused import, exhaustive deps, cognitive complexity suppression - add pre-push git hook running bun run check - integrate lint-log-tags into bun run check pipeline Refs #244 --- .githooks/pre-push | 6 +++++ package.json | 2 +- .../src/commands/serve/ws-client.ts | 4 ++-- .../workflow-graph/condition-edge.tsx | 15 +++--------- .../components/workflow-graph/use-layout.ts | 12 ++++------ scripts/lint-log-tags.sh | 24 +++++++++++++++++++ 6 files changed, 41 insertions(+), 22 deletions(-) create mode 100755 .githooks/pre-push create mode 100755 scripts/lint-log-tags.sh diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 0000000..e824202 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# pre-push hook: typecheck + biome + lint-log-tags +set -euo pipefail +echo "🔍 pre-push: running checks..." +bun run check +echo "✅ pre-push: all checks passed" diff --git a/package.json b/package.json index ef197f4..4509f84 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ ], "scripts": { "build": "bunx tsc --build", - "check": "bunx tsc --build && biome check .", + "check": "bunx tsc --build && biome check . && bash scripts/lint-log-tags.sh", "typecheck": "bunx tsc --build", "format": "biome format --write .", "test": "bun run --filter '*' test", diff --git a/packages/cli-workflow/src/commands/serve/ws-client.ts b/packages/cli-workflow/src/commands/serve/ws-client.ts index b58e49c..b53be3d 100644 --- a/packages/cli-workflow/src/commands/serve/ws-client.ts +++ b/packages/cli-workflow/src/commands/serve/ws-client.ts @@ -100,7 +100,7 @@ export function startGatewayWsClient(params: GatewayWsClientParams): () => void clearReconnectTimer(); const delayMs = Math.min(INITIAL_BACKOFF_MS * 2 ** attempt, MAX_BACKOFF_MS); attempt++; - params.log("6CJX2RLP", `gateway WebSocket reconnect in ${delayMs}ms (attempt ${attempt})`); + params.log("6CJX2R8P", `gateway WebSocket reconnect in ${delayMs}ms (attempt ${attempt})`); reconnectTimer = setTimeout(connect, delayMs); }; @@ -143,7 +143,7 @@ export function startGatewayWsClient(params: GatewayWsClientParams): () => void ws.addEventListener("message", (ev) => { const data = ev.data; if (typeof data !== "string") { - params.log("T9W2KL5H", "gateway WebSocket non-text frame ignored"); + params.log("T9W2K35H", "gateway WebSocket non-text frame ignored"); return; } void handleGatewayMessage(ws, data, params).catch((e: unknown) => { diff --git a/packages/workflow-dashboard/src/components/workflow-graph/condition-edge.tsx b/packages/workflow-dashboard/src/components/workflow-graph/condition-edge.tsx index 1c18864..e16d2f2 100644 --- a/packages/workflow-dashboard/src/components/workflow-graph/condition-edge.tsx +++ b/packages/workflow-dashboard/src/components/workflow-graph/condition-edge.tsx @@ -1,9 +1,4 @@ -import { - BaseEdge, - EdgeLabelRenderer, - type EdgeProps, - getSmoothStepPath, -} from "@xyflow/react"; +import { BaseEdge, EdgeLabelRenderer, type EdgeProps, getSmoothStepPath } from "@xyflow/react"; import type { ConditionEdgeData } from "./types.ts"; // Must match the FEEDBACK_OFFSET_X in use-layout.ts @@ -15,12 +10,7 @@ const FEEDBACK_RADIUS = 16; * Build an SVG path for a feedback (back) edge that routes to the right of the nodes. * The path goes: source right → arc → vertical up → arc → target right */ -function feedbackPath( - sourceX: number, - sourceY: number, - targetX: number, - targetY: number, -): string { +function feedbackPath(sourceX: number, sourceY: number, targetX: number, targetY: number): string { const rightX = Math.max(sourceX, targetX) + FEEDBACK_OFFSET_X; const r = FEEDBACK_RADIUS; @@ -42,6 +32,7 @@ function feedbackPath( return segments.join(" "); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: edge routing logic is inherently branchy export function ConditionEdge(props: EdgeProps) { const { id, diff --git a/packages/workflow-dashboard/src/components/workflow-graph/use-layout.ts b/packages/workflow-dashboard/src/components/workflow-graph/use-layout.ts index 4edb097..fef0d7d 100644 --- a/packages/workflow-dashboard/src/components/workflow-graph/use-layout.ts +++ b/packages/workflow-dashboard/src/components/workflow-graph/use-layout.ts @@ -1,7 +1,7 @@ import type { Edge, Node } from "@xyflow/react"; import { useMemo } from "react"; import type { WorkflowGraphEdge } from "../../api.ts"; -import type { ConditionEdgeData, NodeState, RoleNodeData, TerminalNodeData } from "./types.ts"; +import type { NodeState, RoleNodeData, TerminalNodeData } from "./types.ts"; const START_ID = "__start__"; const END_ID = "__end__"; @@ -41,6 +41,7 @@ function edgeKey(e: WorkflowGraphEdge): string { * Forward edges go from lower rank to higher rank; feedback edges go backwards. * Self-loops are neither forward nor feedback — they're handled separately. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: topological sort is inherently branchy function extractSpine(edges: readonly WorkflowGraphEdge[]): string[] { // Collect all node IDs const ids = new Set(); @@ -213,8 +214,8 @@ function computeLayout(input: LayoutInput): LayoutResult { isFallback, isFeedback, isSelfLoop, - labelX, - labelY, + labelX, + labelY, }, }; }); @@ -223,8 +224,5 @@ function computeLayout(input: LayoutInput): LayoutResult { } export function useLayout(input: LayoutInput): LayoutResult { - return useMemo( - () => computeLayout(input), - [input.edges, input.roles, input.nodeStates], - ); + return useMemo(() => computeLayout(input), [input]); } diff --git a/scripts/lint-log-tags.sh b/scripts/lint-log-tags.sh new file mode 100755 index 0000000..64f092f --- /dev/null +++ b/scripts/lint-log-tags.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Validate Crockford Base32 log tags in .log("TAG", ...) calls. +# Crockford Base32 excludes: I, L, O, U +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +BAD=0 + +while IFS= read -r match; do + file="${match%%:*}" + rest="${match#*:}" + line="${rest%%:*}" + tag=$(echo "$rest" | grep -oP '\.log\(\s*"\K[A-Za-z0-9]+') + if echo "$tag" | grep -qiE '[ILOU]'; then + echo " ❌ ${file}:${line} tag \"${tag}\" contains invalid Crockford Base32 char (I/L/O/U)" + BAD=1 + fi +done < <(grep -rn '\.log("[A-Za-z0-9]\{8\}"' "$ROOT/packages/" --include='*.ts' \ + | grep -v node_modules | grep -v '/dist/') + +if [ "$BAD" -eq 0 ]; then + echo " ✅ All log tags are valid Crockford Base32" +fi +exit $BAD