From 153178c545c497f29b3a35c15600684081f397b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E6=9C=88?= Date: Fri, 15 May 2026 09:10:39 +0800 Subject: [PATCH 1/2] fix: biome format issues (12 errors) --- packages/cli-workflow/src/cli-dispatch.ts | 2 +- .../src/commands/connect/ws-client.ts | 12 +-- packages/workflow-dashboard/src/app.tsx | 9 +- .../src/components/thread-detail.tsx | 71 ++++++++-------- .../src/components/workflow-detail.tsx | 82 +++++++++++++------ .../workflow-graph/condition-edge.tsx | 15 ++-- .../components/workflow-graph/role-node.tsx | 48 +++++++++-- .../workflow-graph/terminal-node.tsx | 8 +- .../components/workflow-graph/use-layout.ts | 6 +- .../src/components/workflow-list.tsx | 11 +-- .../workflow-dashboard/src/use-hash-route.ts | 9 +- packages/workflow-gateway/src/index.ts | 7 +- 12 files changed, 190 insertions(+), 90 deletions(-) diff --git a/packages/cli-workflow/src/cli-dispatch.ts b/packages/cli-workflow/src/cli-dispatch.ts index 2a420c3..3f3cad3 100644 --- a/packages/cli-workflow/src/cli-dispatch.ts +++ b/packages/cli-workflow/src/cli-dispatch.ts @@ -3,8 +3,8 @@ import { printCliError, printCliLine } from "./cli-output.js"; import { getCommandRegistry } from "./cli-registry.js"; import { formatCliUsage as formatCliUsageWithGroups } from "./cli-usage.js"; import { createCasDispatcher } from "./commands/cas/index.js"; -import { createInitDispatcher } from "./commands/init/index.js"; import { dispatchConnect } from "./commands/connect/index.js"; +import { createInitDispatcher } from "./commands/init/index.js"; import { dispatchSetup } from "./commands/setup/index.js"; import { createThreadDispatcher, dispatchLive, dispatchRun } from "./commands/thread/index.js"; import { createWorkflowDispatcher } from "./commands/workflow/index.js"; diff --git a/packages/cli-workflow/src/commands/connect/ws-client.ts b/packages/cli-workflow/src/commands/connect/ws-client.ts index aeaa5c1..aa59bb5 100644 --- a/packages/cli-workflow/src/commands/connect/ws-client.ts +++ b/packages/cli-workflow/src/commands/connect/ws-client.ts @@ -48,11 +48,13 @@ async function handleGatewayMessage( const headers = new Headers(req.headers); let resp: Response; try { - resp = await params.appFetch(new Request(localUrl, { - method: req.method, - headers, - body: req.body === null ? undefined : req.body, - })); + resp = await params.appFetch( + new Request(localUrl, { + method: req.method, + headers, + body: req.body === null ? undefined : req.body, + }), + ); } catch (e) { params.log("R4N7BQ3C", `app.fetch failed: ${String(e)}`); const errBody: WsResponse = { diff --git a/packages/workflow-dashboard/src/app.tsx b/packages/workflow-dashboard/src/app.tsx index 612dc3f..b96d11e 100644 --- a/packages/workflow-dashboard/src/app.tsx +++ b/packages/workflow-dashboard/src/app.tsx @@ -12,7 +12,8 @@ import { useHashRoute } from "./use-hash-route.ts"; export function App() { const [authed, setAuthed] = useState(hasApiKey()); - const { view, client, threadId, workflowName, setView, setClient, setThreadId, setWorkflowName } = useHashRoute(); + const { view, client, threadId, workflowName, setView, setClient, setThreadId, setWorkflowName } = + useHashRoute(); const [showRun, setShowRun] = useState(false); if (!authed) { @@ -51,7 +52,11 @@ export function App() { )} {client && view === "workflows" && workflowName !== null && ( - setWorkflowName(null)} /> + setWorkflowName(null)} + /> )} diff --git a/packages/workflow-dashboard/src/components/thread-detail.tsx b/packages/workflow-dashboard/src/components/thread-detail.tsx index 4a638d0..1eebc0a 100644 --- a/packages/workflow-dashboard/src/components/thread-detail.tsx +++ b/packages/workflow-dashboard/src/components/thread-detail.tsx @@ -96,42 +96,45 @@ export function ThreadDetail({ client, threadId, onBack }: Props) { // Track which occurrence to jump to next per role (cycling) const clickCycleRef = useRef>(new Map()); - const handleGraphNodeClick = useCallback((nodeId: string) => { - // Only allow clicks on lit (non-default) nodes - if (nodeStates.get(nodeId) === undefined || nodeStates.get(nodeId) === "default") return; + const handleGraphNodeClick = useCallback( + (nodeId: string) => { + // Only allow clicks on lit (non-default) nodes + if (nodeStates.get(nodeId) === undefined || nodeStates.get(nodeId) === "default") return; - // __start__: scroll to the first record (thread-start prompt) - if (nodeId === "__start__") { - const firstCard = document.querySelector('[data-record-index="0"]'); - if (firstCard !== null) firstCard.scrollIntoView({ behavior: "smooth", block: "center" }); - return; - } + // __start__: scroll to the first record (thread-start prompt) + if (nodeId === "__start__") { + const firstCard = document.querySelector('[data-record-index="0"]'); + if (firstCard !== null) firstCard.scrollIntoView({ behavior: "smooth", block: "center" }); + return; + } - // __end__: scroll to bottom - if (nodeId === "__end__") { - recordsEndRef.current?.scrollIntoView({ behavior: "smooth", block: "end" }); - return; - } + // __end__: scroll to bottom + if (nodeId === "__end__") { + recordsEndRef.current?.scrollIntoView({ behavior: "smooth", block: "end" }); + return; + } - // Role nodes: cycle through occurrences - const indices = indicesByRole.get(nodeId); - if (indices === undefined || indices.length === 0) return; + // Role nodes: cycle through occurrences + const indices = indicesByRole.get(nodeId); + if (indices === undefined || indices.length === 0) return; - const cycle = clickCycleRef.current.get(nodeId) ?? 0; - const idx = indices[cycle % indices.length]; - clickCycleRef.current.set(nodeId, cycle + 1); + const cycle = clickCycleRef.current.get(nodeId) ?? 0; + const idx = indices[cycle % indices.length]; + clickCycleRef.current.set(nodeId, cycle + 1); - const el = document.querySelector(`[data-record-index="${idx}"]`); - if (el !== null) { - el.scrollIntoView({ behavior: "smooth", block: "center" }); - if (highlightTimerRef.current !== null) clearTimeout(highlightTimerRef.current); - setHighlightedRole(nodeId); - highlightTimerRef.current = setTimeout(() => { - setHighlightedRole(null); - highlightTimerRef.current = null; - }, 1500); - } - }, [nodeStates, indicesByRole]); + const el = document.querySelector(`[data-record-index="${idx}"]`); + if (el !== null) { + el.scrollIntoView({ behavior: "smooth", block: "center" }); + if (highlightTimerRef.current !== null) clearTimeout(highlightTimerRef.current); + setHighlightedRole(nodeId); + highlightTimerRef.current = setTimeout(() => { + setHighlightedRole(null); + highlightTimerRef.current = null; + }, 1500); + } + }, + [nodeStates, indicesByRole], + ); useEffect(() => { return () => { @@ -285,7 +288,11 @@ export function ThreadDetail({ client, threadId, onBack }: Props) { ); } - return
; + return ( +
+ +
+ ); })}
diff --git a/packages/workflow-dashboard/src/components/workflow-detail.tsx b/packages/workflow-dashboard/src/components/workflow-detail.tsx index f6cbba8..a5f2b6a 100644 --- a/packages/workflow-dashboard/src/components/workflow-detail.tsx +++ b/packages/workflow-dashboard/src/components/workflow-detail.tsx @@ -76,7 +76,14 @@ function flattenSchema( ); for (const [pName, pDef] of Object.entries(variantProps)) { if (pDef.const !== undefined) continue; - const subRows = flattenProperty(pName, pDef, depth + 1, childPrefix, `${keyPrefix}v${vi}-`, variantRequired); + const subRows = flattenProperty( + pName, + pDef, + depth + 1, + childPrefix, + `${keyPrefix}v${vi}-`, + variantRequired, + ); rows.push(...subRows); } } @@ -121,7 +128,14 @@ function flattenProperty( if (prop.type === "object" && prop.properties !== undefined) { const childPrefix = depth > 0 ? `${parentPrefix} ` : " "; - rows.push(...flattenSchema(prop as Record, depth + 1, childPrefix, `${keyPrefix}${name}-`)); + rows.push( + ...flattenSchema( + prop as Record, + depth + 1, + childPrefix, + `${keyPrefix}${name}-`, + ), + ); } if (prop.type === "array") { @@ -134,7 +148,14 @@ function flattenProperty( if (hasOneOf) { const childPrefix = depth > 0 ? `${parentPrefix} ` : " "; - rows.push(...flattenSchema(prop as Record, depth + 1, childPrefix, `${keyPrefix}${name}-`)); + rows.push( + ...flattenSchema( + prop as Record, + depth + 1, + childPrefix, + `${keyPrefix}${name}-`, + ), + ); } return rows; @@ -142,13 +163,7 @@ function flattenProperty( // ── Components ────────────────────────────────────────────────────── -function RoleCard({ - roleName, - role, -}: { - roleName: string; - role: WorkflowRoleDescriptor; -}) { +function RoleCard({ roleName, role }: { roleName: string; role: WorkflowRoleDescriptor }) { const rows = flattenSchema(role.schema, 0, "", `${roleName}-`); return (
-

+

{roleName}

{role.description !== "" && ( @@ -178,9 +190,24 @@ function RoleCard({ - - - + + + @@ -200,8 +227,12 @@ function RoleCard({ > {r.name} - - + + ))} @@ -274,12 +305,8 @@ export function WorkflowDetail({ client, workflowName, onBack }: Props) {

{workflowName}

- {status === "loading" && ( -

Loading...

- )} - {status === "error" && ( -

Error: {error}

- )} + {status === "loading" &&

Loading...

} + {status === "error" &&

Error: {error}

} {detail !== null && (
@@ -327,7 +354,10 @@ export function WorkflowDetail({ client, workflowName, onBack }: Props) { className="rounded-lg border p-4" style={{ borderColor: "var(--color-border)", background: "var(--color-surface)" }} > -

+

{descriptor !== null && descriptor.description !== "" ? descriptor.description : "—"} 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 629df97..e29fea0 100644 --- a/packages/workflow-dashboard/src/components/workflow-graph/condition-edge.tsx +++ b/packages/workflow-dashboard/src/components/workflow-graph/condition-edge.tsx @@ -10,7 +10,13 @@ const FEEDBACK_RADIUS = 16; * Build an SVG path for a feedback (back) edge that routes to the given side of the nodes. * The path goes: source → arc → vertical up → arc → target */ -function feedbackPath(sourceX: number, sourceY: number, targetX: number, targetY: number, side: "right" | "left"): string { +function feedbackPath( + sourceX: number, + sourceY: number, + targetX: number, + targetY: number, + side: "right" | "left", +): string { const d = side === "right" ? 1 : -1; const offsetX = side === "right" @@ -88,12 +94,7 @@ export function ConditionEdge(props: EdgeProps) { return ( <> - + {label !== "" && (

- - - - - + + + + +
{icon !== null && ( )} - +
); } diff --git a/packages/workflow-dashboard/src/components/workflow-graph/terminal-node.tsx b/packages/workflow-dashboard/src/components/workflow-graph/terminal-node.tsx index 935949d..92f7a8f 100644 --- a/packages/workflow-dashboard/src/components/workflow-graph/terminal-node.tsx +++ b/packages/workflow-dashboard/src/components/workflow-graph/terminal-node.tsx @@ -50,7 +50,13 @@ export function TerminalNode(props: NodeProps) { isConnectable={false} /> ) : ( - + )} {isStart ? "▶" : "■"}
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 731f2cc..61a90b7 100644 --- a/packages/workflow-dashboard/src/components/workflow-graph/use-layout.ts +++ b/packages/workflow-dashboard/src/components/workflow-graph/use-layout.ts @@ -216,7 +216,11 @@ function computeLayout(input: LayoutInput): LayoutResult { id: edgeKey(e), source: e.from, target: e.to, - sourceHandle: isFeedback ? (feedbackSide === "left" ? "left-out" : "right-out") : "bottom-out", + sourceHandle: isFeedback + ? feedbackSide === "left" + ? "left-out" + : "right-out" + : "bottom-out", targetHandle: isFeedback ? (feedbackSide === "left" ? "left-in" : "right-in") : "top-in", type: "condition", data: { diff --git a/packages/workflow-dashboard/src/components/workflow-list.tsx b/packages/workflow-dashboard/src/components/workflow-list.tsx index c4bbf91..54461b6 100644 --- a/packages/workflow-dashboard/src/components/workflow-list.tsx +++ b/packages/workflow-dashboard/src/components/workflow-list.tsx @@ -28,7 +28,11 @@ export function WorkflowList({ client, onSelect }: Props) { type="button" onClick={() => onSelect(w.name)} className="w-full text-left p-4 rounded-lg border hover:opacity-90" - style={{ background: "var(--color-surface)", borderColor: "var(--color-border)", color: "var(--color-text)" }} + style={{ + background: "var(--color-surface)", + borderColor: "var(--color-border)", + color: "var(--color-text)", + }} >
{w.name} @@ -40,10 +44,7 @@ export function WorkflowList({ client, onSelect }: Props) { {w.hash !== null ? w.hash : "—"} {w.timestamp !== null ? ( - + Updated {new Date(w.timestamp).toLocaleString()} ) : null} diff --git a/packages/workflow-dashboard/src/use-hash-route.ts b/packages/workflow-dashboard/src/use-hash-route.ts index b3d6dc7..78ccc8a 100644 --- a/packages/workflow-dashboard/src/use-hash-route.ts +++ b/packages/workflow-dashboard/src/use-hash-route.ts @@ -80,17 +80,20 @@ export function useHashRoute(): { ); const setClient = useCallback( - (a: string | null) => navigate({ view: route.view, client: a, threadId: null, workflowName: null }), + (a: string | null) => + navigate({ view: route.view, client: a, threadId: null, workflowName: null }), [navigate, route.view], ); const setThreadId = useCallback( - (id: string | null) => navigate({ view: "threads", client: route.client, threadId: id, workflowName: null }), + (id: string | null) => + navigate({ view: "threads", client: route.client, threadId: id, workflowName: null }), [navigate, route.client], ); const setWorkflowName = useCallback( - (name: string | null) => navigate({ view: "workflows", client: route.client, threadId: null, workflowName: name }), + (name: string | null) => + navigate({ view: "workflows", client: route.client, threadId: null, workflowName: name }), [navigate, route.client], ); diff --git a/packages/workflow-gateway/src/index.ts b/packages/workflow-gateway/src/index.ts index 6de703b..b49e422 100644 --- a/packages/workflow-gateway/src/index.ts +++ b/packages/workflow-gateway/src/index.ts @@ -305,7 +305,12 @@ app.all("/api/clients/:client/*", async (c) => { headers: forwardRecord, body: bodyStr, }; - const proxyResp = await fetchThroughClientSocket(c.env, client, c.env.GATEWAY_SECRET, wsRequest); + const proxyResp = await fetchThroughClientSocket( + c.env, + client, + c.env.GATEWAY_SECRET, + wsRequest, + ); if (proxyResp.status !== 503) { return new Response(proxyResp.body, { status: proxyResp.status, From 15edc99c7284a44c540c74d2e38b5e375c4e58f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E6=9C=88?= Date: Fri, 15 May 2026 09:11:01 +0800 Subject: [PATCH 2/2] chore: add pre-push hook (check + test) and fix lint-log-tags for macOS --- .githooks/pre-push | 10 +++++++--- scripts/lint-log-tags.sh | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.githooks/pre-push b/.githooks/pre-push index e824202..09631c9 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -1,6 +1,10 @@ #!/usr/bin/env bash -# pre-push hook: typecheck + biome + lint-log-tags set -euo pipefail -echo "🔍 pre-push: running checks..." + +echo "🔍 Running check (tsc + biome + lint-log-tags)..." bun run check -echo "✅ pre-push: all checks passed" + +echo "🧪 Running tests..." +bun run test + +echo "✅ All checks passed!" diff --git a/scripts/lint-log-tags.sh b/scripts/lint-log-tags.sh index 64f092f..3b3700a 100755 --- a/scripts/lint-log-tags.sh +++ b/scripts/lint-log-tags.sh @@ -10,7 +10,7 @@ while IFS= read -r match; do file="${match%%:*}" rest="${match#*:}" line="${rest%%:*}" - tag=$(echo "$rest" | grep -oP '\.log\(\s*"\K[A-Za-z0-9]+') + tag=$(echo "$rest" | sed -n 's/.*\.log( *"\([A-Za-z0-9]*\)".*/\1/p') if echo "$tag" | grep -qiE '[ILOU]'; then echo " ❌ ${file}:${line} tag \"${tag}\" contains invalid Crockford Base32 char (I/L/O/U)" BAD=1
FieldTypeDescription + Field + + Type + + Description +
{r.type}{r.description || (r.isVariantHeader ? "" : "—")} + {r.type} + + {r.description || (r.isVariantHeader ? "" : "—")} +