chore: add log-tag lint + fix biome errors + pre-push hook
- 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
This commit is contained in:
Executable
+6
@@ -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"
|
||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bunx tsc --build",
|
"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",
|
"typecheck": "bunx tsc --build",
|
||||||
"format": "biome format --write .",
|
"format": "biome format --write .",
|
||||||
"test": "bun run --filter '*' test",
|
"test": "bun run --filter '*' test",
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export function startGatewayWsClient(params: GatewayWsClientParams): () => void
|
|||||||
clearReconnectTimer();
|
clearReconnectTimer();
|
||||||
const delayMs = Math.min(INITIAL_BACKOFF_MS * 2 ** attempt, MAX_BACKOFF_MS);
|
const delayMs = Math.min(INITIAL_BACKOFF_MS * 2 ** attempt, MAX_BACKOFF_MS);
|
||||||
attempt++;
|
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);
|
reconnectTimer = setTimeout(connect, delayMs);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ export function startGatewayWsClient(params: GatewayWsClientParams): () => void
|
|||||||
ws.addEventListener("message", (ev) => {
|
ws.addEventListener("message", (ev) => {
|
||||||
const data = ev.data;
|
const data = ev.data;
|
||||||
if (typeof data !== "string") {
|
if (typeof data !== "string") {
|
||||||
params.log("T9W2KL5H", "gateway WebSocket non-text frame ignored");
|
params.log("T9W2K35H", "gateway WebSocket non-text frame ignored");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void handleGatewayMessage(ws, data, params).catch((e: unknown) => {
|
void handleGatewayMessage(ws, data, params).catch((e: unknown) => {
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { BaseEdge, EdgeLabelRenderer, type EdgeProps, getSmoothStepPath } from "@xyflow/react";
|
||||||
BaseEdge,
|
|
||||||
EdgeLabelRenderer,
|
|
||||||
type EdgeProps,
|
|
||||||
getSmoothStepPath,
|
|
||||||
} from "@xyflow/react";
|
|
||||||
import type { ConditionEdgeData } from "./types.ts";
|
import type { ConditionEdgeData } from "./types.ts";
|
||||||
|
|
||||||
// Must match the FEEDBACK_OFFSET_X in use-layout.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.
|
* 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
|
* The path goes: source right → arc → vertical up → arc → target right
|
||||||
*/
|
*/
|
||||||
function feedbackPath(
|
function feedbackPath(sourceX: number, sourceY: number, targetX: number, targetY: number): string {
|
||||||
sourceX: number,
|
|
||||||
sourceY: number,
|
|
||||||
targetX: number,
|
|
||||||
targetY: number,
|
|
||||||
): string {
|
|
||||||
const rightX = Math.max(sourceX, targetX) + FEEDBACK_OFFSET_X;
|
const rightX = Math.max(sourceX, targetX) + FEEDBACK_OFFSET_X;
|
||||||
const r = FEEDBACK_RADIUS;
|
const r = FEEDBACK_RADIUS;
|
||||||
|
|
||||||
@@ -42,6 +32,7 @@ function feedbackPath(
|
|||||||
return segments.join(" ");
|
return segments.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: edge routing logic is inherently branchy
|
||||||
export function ConditionEdge(props: EdgeProps) {
|
export function ConditionEdge(props: EdgeProps) {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { Edge, Node } from "@xyflow/react";
|
import type { Edge, Node } from "@xyflow/react";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import type { WorkflowGraphEdge } from "../../api.ts";
|
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 START_ID = "__start__";
|
||||||
const END_ID = "__end__";
|
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.
|
* Forward edges go from lower rank to higher rank; feedback edges go backwards.
|
||||||
* Self-loops are neither forward nor feedback — they're handled separately.
|
* 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[] {
|
function extractSpine(edges: readonly WorkflowGraphEdge[]): string[] {
|
||||||
// Collect all node IDs
|
// Collect all node IDs
|
||||||
const ids = new Set<string>();
|
const ids = new Set<string>();
|
||||||
@@ -213,8 +214,8 @@ function computeLayout(input: LayoutInput): LayoutResult {
|
|||||||
isFallback,
|
isFallback,
|
||||||
isFeedback,
|
isFeedback,
|
||||||
isSelfLoop,
|
isSelfLoop,
|
||||||
labelX,
|
labelX,
|
||||||
labelY,
|
labelY,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -223,8 +224,5 @@ function computeLayout(input: LayoutInput): LayoutResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useLayout(input: LayoutInput): LayoutResult {
|
export function useLayout(input: LayoutInput): LayoutResult {
|
||||||
return useMemo(
|
return useMemo(() => computeLayout(input), [input]);
|
||||||
() => computeLayout(input),
|
|
||||||
[input.edges, input.roles, input.nodeStates],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+24
@@ -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
|
||||||
Reference in New Issue
Block a user