From 7d3c049422e8d9428f9bc0add33ee484a20601f5 Mon Sep 17 00:00:00 2001 From: Lum1104 Date: Thu, 2 Apr 2026 14:52:34 +0800 Subject: [PATCH] fix: address all code review issues from both reviewers - Fix race condition: setGraph no longer wipes domainGraph on parallel fetch - Remove workflow/action aliases that conflicted with pipeline type - Remove duplicate onNodeDoubleClick handler in DomainGraphView - Add clearActiveDomain store action (replaces direct setState call) - Remove auto-switch to domain viewMode in setDomainGraph - Add DomainMetaSchema Zod validation for domainMeta fields - Add Array.isArray guards for domainMeta collections in NodeInfo - Remove as-any cast in getDomainMeta (use typed domainMeta directly) - Add "domain" filter category for domain/flow/step nodes - Keep flow discriminator in step ID normalization to prevent collisions - Update SKILL.md Phase 2 to use tool-based scanning (no missing script) - Update EDGE_LABELS comment to reflect 29 edge types - Bump version to 2.1.0 in all 4 required files Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude-plugin/marketplace.json | 2 +- .claude-plugin/plugin.json | 2 +- .cursor-plugin/plugin.json | 2 +- understand-anything-plugin/package.json | 2 +- .../src/__tests__/domain-normalize.test.ts | 2 +- .../core/src/__tests__/domain-types.test.ts | 4 ++-- .../core/src/__tests__/schema.test.ts | 4 ++-- .../core/src/analyzer/normalize-graph.ts | 19 ++++++++-------- .../packages/core/src/schema.ts | 13 +++++++++-- .../packages/dashboard/src/App.tsx | 1 + .../src/components/DomainGraphView.tsx | 22 +++++-------------- .../dashboard/src/components/GraphView.tsx | 3 +-- .../dashboard/src/components/NodeInfo.tsx | 8 +++---- .../packages/dashboard/src/store.ts | 16 ++++++++++---- .../skills/understand-domain/SKILL.md | 18 +++++++-------- 15 files changed, 62 insertions(+), 56 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index c67965a..d9b37a0 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,7 +9,7 @@ { "name": "understand-anything", "description": "Multi-agent codebase analysis with interactive dashboard, guided tours, and skill commands", - "version": "2.0.0", + "version": "2.1.0", "source": "./understand-anything-plugin" } ] diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 08d46de..a1229dd 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "understand-anything", "description": "AI-powered codebase understanding — analyze, visualize, and explain any project", - "version": "2.0.0", + "version": "2.1.0", "author": { "name": "Lum1104" }, diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index c1a0f00..2255fba 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "understand-anything", "displayName": "Understand Anything", "description": "AI-powered codebase understanding — analyze, visualize, and explain any project", - "version": "2.0.0", + "version": "2.1.0", "author": { "name": "Lum1104" }, diff --git a/understand-anything-plugin/package.json b/understand-anything-plugin/package.json index a330d4e..527b319 100644 --- a/understand-anything-plugin/package.json +++ b/understand-anything-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@understand-anything/skill", - "version": "2.0.0", + "version": "2.1.0", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/understand-anything-plugin/packages/core/src/__tests__/domain-normalize.test.ts b/understand-anything-plugin/packages/core/src/__tests__/domain-normalize.test.ts index 54c90f9..ed043f4 100644 --- a/understand-anything-plugin/packages/core/src/__tests__/domain-normalize.test.ts +++ b/understand-anything-plugin/packages/core/src/__tests__/domain-normalize.test.ts @@ -24,7 +24,7 @@ describe("normalizeNodeId — domain types", () => { name: "Validate", filePath: "src/validators/order.ts", }); - expect(result).toBe("step:src/validators/order.ts:validate"); + expect(result).toBe("step:create-order:src/validators/order.ts:validate"); }); it("normalizes step node IDs without filePath", () => { diff --git a/understand-anything-plugin/packages/core/src/__tests__/domain-types.test.ts b/understand-anything-plugin/packages/core/src/__tests__/domain-types.test.ts index b0a1051..5641964 100644 --- a/understand-anything-plugin/packages/core/src/__tests__/domain-types.test.ts +++ b/understand-anything-plugin/packages/core/src/__tests__/domain-types.test.ts @@ -110,8 +110,8 @@ describe("domain graph types", () => { it("normalizes domain type aliases", () => { const graph = structuredClone(domainGraph); (graph.nodes[0] as any).type = "business_domain"; - (graph.nodes[1] as any).type = "workflow"; - (graph.nodes[2] as any).type = "action"; + (graph.nodes[1] as any).type = "business_flow"; + (graph.nodes[2] as any).type = "business_step"; const result = validateGraph(graph); expect(result.success).toBe(true); expect(result.data!.nodes[0].type).toBe("domain"); diff --git a/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts b/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts index 7b3c440..92f676e 100644 --- a/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts +++ b/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts @@ -686,11 +686,11 @@ describe("Extended node/edge types", () => { } }); - it("auto-fixes new node type aliases: container->service, doc->document, workflow->flow, etc.", () => { + it("auto-fixes new node type aliases: container->service, doc->document, business_flow->flow, etc.", () => { const aliases: Record = { container: "service", doc: "document", - workflow: "flow", + business_flow: "flow", route: "endpoint", setting: "config", infra: "resource", diff --git a/understand-anything-plugin/packages/core/src/analyzer/normalize-graph.ts b/understand-anything-plugin/packages/core/src/analyzer/normalize-graph.ts index 6d71c44..898825d 100644 --- a/understand-anything-plugin/packages/core/src/analyzer/normalize-graph.ts +++ b/understand-anything-plugin/packages/core/src/analyzer/normalize-graph.ts @@ -72,16 +72,16 @@ export function normalizeNodeId( const { prefix, path } = stripToValidPrefix(trimmed); if (prefix) { - // For step nodes with filePath, reconstruct as step:filePath:stepSlug. - // This intentionally drops the flow slug (e.g. "create-order" in - // "step:create-order:validate") — the normalized form anchors to - // file paths instead of flow parentage, so the ID is stable across - // renames of the parent flow. + // For step nodes with filePath, reconstruct as step:flowSlug:filePath:stepSlug. + // Keeps the flow discriminator to avoid collisions when two flows + // have a same-named step in the same file. if (node.type === "step" && node.filePath) { - // Use the last colon-separated segment of the path as the step slug - const lastColon = path.lastIndexOf(":"); - const stepSlug = lastColon >= 0 ? path.slice(lastColon + 1) : path; - return `${prefix}:${node.filePath}:${stepSlug}`; + const segments = path.split(":"); + const stepSlug = segments.length > 0 ? segments[segments.length - 1] : path; + const flowSlug = segments.length > 1 ? segments[segments.length - 2] : ""; + return flowSlug + ? `${prefix}:${flowSlug}:${node.filePath}:${stepSlug}` + : `${prefix}:${node.filePath}:${stepSlug}`; } return `${prefix}:${path}`; } @@ -99,6 +99,7 @@ export function normalizeNodeId( // For step nodes with filePath, reconstruct as step:filePath:slug if (node.type === "step" && node.filePath) { const slug = path.toLowerCase().replace(/\s+/g, "-"); + // No flow discriminator available from bare path — use filePath:slug return `${expectedPrefix}:${node.filePath}:${slug}`; } return `${expectedPrefix}:${path}`; diff --git a/understand-anything-plugin/packages/core/src/schema.ts b/understand-anything-plugin/packages/core/src/schema.ts index 8839d33..fd59ecd 100644 --- a/understand-anything-plugin/packages/core/src/schema.ts +++ b/understand-anything-plugin/packages/core/src/schema.ts @@ -52,9 +52,9 @@ export const NODE_TYPE_ALIASES: Record = { // Domain aliases business_domain: "domain", process: "flow", - workflow: "flow", - action: "step", + business_flow: "flow", task: "step", + business_step: "step", }; // Aliases that LLMs commonly generate instead of canonical edge types @@ -317,6 +317,14 @@ export function autoFixGraph(data: Record): { return { data: result, issues }; } +const DomainMetaSchema = z.object({ + entities: z.array(z.string()).optional(), + businessRules: z.array(z.string()).optional(), + crossDomainInteractions: z.array(z.string()).optional(), + entryPoint: z.string().optional(), + entryType: z.enum(["http", "cli", "event", "cron", "manual"]).optional(), +}).passthrough(); + export const GraphNodeSchema = z.object({ id: z.string(), type: z.enum([ @@ -332,6 +340,7 @@ export const GraphNodeSchema = z.object({ tags: z.array(z.string()), complexity: z.enum(["simple", "moderate", "complex"]), languageNotes: z.string().optional(), + domainMeta: DomainMetaSchema.optional(), }).passthrough(); export const GraphEdgeSchema = z.object({ diff --git a/understand-anything-plugin/packages/dashboard/src/App.tsx b/understand-anything-plugin/packages/dashboard/src/App.tsx index 9b9b74b..d3d472d 100644 --- a/understand-anything-plugin/packages/dashboard/src/App.tsx +++ b/understand-anything-plugin/packages/dashboard/src/App.tsx @@ -357,6 +357,7 @@ function Dashboard({ accessToken }: { accessToken: string }) { { key: "docs", label: "Docs", color: "var(--color-node-document)" }, { key: "infra", label: "Infra", color: "var(--color-node-service)" }, { key: "data", label: "Data", color: "var(--color-node-table)" }, + { key: "domain", label: "Domain", color: "var(--color-node-concept)" }, ] as const).map((cat) => (