# Universal File Type Support — Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Extend Understand Anything to analyze 26+ non-code file types (Markdown, Dockerfile, YAML, SQL, Terraform, etc.) with new graph node/edge types, custom parsers, updated agent prompts, and dashboard visualization. **Architecture:** Extend the existing LanguageConfig + AnalyzerPlugin pipeline. Add 8 new node types and 8 new edge types to the schema. Build 12 lightweight regex/parser-based analyzers for structured formats, LLM-only for unstructured. Update all 5 agent prompts to handle non-code files. Add new node colors and sidebar rendering to the dashboard. **Tech Stack:** TypeScript, Zod, Vitest, React, React Flow, Zustand, TailwindCSS v4, `yaml` npm package, `@iarna/toml`, `jsonc-parser` **Design doc:** `docs/plans/2026-03-28-understand-anything-extension-design.md` --- ## Task 1: Extend Core Types — Node & Edge Types **Files:** - Modify: `understand-anything-plugin/packages/core/src/types.ts:1-116` - Test: `understand-anything-plugin/packages/core/src/types.test.ts` **Step 1: Write the failing test** In `types.test.ts`, add a test that imports and verifies the new node types exist on GraphNode and edge types exist on EdgeType: ```typescript import { describe, it, expect } from "vitest"; import type { GraphNode, GraphEdge, EdgeType, StructuralAnalysis } from "../types.js"; describe("Extended types", () => { it("accepts all 13 node types", () => { const nodeTypes: GraphNode["type"][] = [ "file", "function", "class", "module", "concept", "config", "document", "service", "table", "endpoint", "pipeline", "schema", "resource", ]; expect(nodeTypes).toHaveLength(13); }); it("accepts all 26 edge types", () => { const edgeTypes: EdgeType[] = [ "imports", "exports", "contains", "inherits", "implements", "calls", "subscribes", "publishes", "middleware", "reads_from", "writes_to", "transforms", "validates", "depends_on", "tested_by", "configures", "related", "similar_to", "deploys", "serves", "migrates", "documents", "provisions", "routes", "defines_schema", "triggers", ]; expect(edgeTypes).toHaveLength(26); }); it("StructuralAnalysis has optional non-code fields", () => { const analysis: StructuralAnalysis = { functions: [], classes: [], imports: [], exports: [], sections: [{ name: "Introduction", level: 1, lineRange: [1, 10] }], definitions: [{ name: "users", kind: "table", lineRange: [1, 20], fields: ["id", "name"] }], services: [{ name: "web", image: "node:22", ports: [3000] }], endpoints: [{ method: "GET", path: "/api/users", lineRange: [5, 15] }], steps: [{ name: "build", lineRange: [1, 5] }], resources: [{ name: "aws_s3_bucket.main", kind: "aws_s3_bucket", lineRange: [1, 10] }], }; expect(analysis.sections).toHaveLength(1); expect(analysis.definitions).toHaveLength(1); expect(analysis.services).toHaveLength(1); expect(analysis.endpoints).toHaveLength(1); expect(analysis.steps).toHaveLength(1); expect(analysis.resources).toHaveLength(1); }); }); ``` **Step 2: Run test to verify it fails** Run: `pnpm --filter @understand-anything/core test -- --run types.test` Expected: FAIL — TypeScript compilation errors for new types that don't exist yet **Step 3: Implement the type extensions** In `types.ts`, update the `GraphNode.type` union (line 12): ```typescript type: "file" | "function" | "class" | "module" | "concept" | "config" | "document" | "service" | "table" | "endpoint" | "pipeline" | "schema" | "resource"; ``` Update the `EdgeType` type (lines 1-7) to add 8 new edge types: ```typescript export type EdgeType = | "imports" | "exports" | "contains" | "inherits" | "implements" // Structural | "calls" | "subscribes" | "publishes" | "middleware" // Behavioral | "reads_from" | "writes_to" | "transforms" | "validates" // Data flow | "depends_on" | "tested_by" | "configures" // Dependencies | "related" | "similar_to" // Semantic | "deploys" | "serves" | "migrates" | "documents" // Infrastructure | "provisions" | "routes" | "defines_schema" | "triggers"; // Infrastructure ``` Extend `StructuralAnalysis` (after line 95) with new optional fields: ```typescript export interface SectionInfo { name: string; level: number; lineRange: [number, number]; } export interface DefinitionInfo { name: string; kind: string; // "table", "message", "type", "schema" lineRange: [number, number]; fields: string[]; } export interface ServiceInfo { name: string; image?: string; ports: number[]; } export interface EndpointInfo { method?: string; path: string; lineRange: [number, number]; } export interface StepInfo { name: string; lineRange: [number, number]; } export interface ResourceInfo { name: string; kind: string; lineRange: [number, number]; } export interface ReferenceResolution { source: string; target: string; referenceType: string; // "file", "image", "schema", "service" line?: number; } export interface StructuralAnalysis { functions: Array<{ name: string; lineRange: [number, number]; params: string[]; returnType?: string }>; classes: Array<{ name: string; lineRange: [number, number]; methods: string[]; properties: string[] }>; imports: Array<{ source: string; specifiers: string[]; lineNumber: number }>; exports: Array<{ name: string; lineNumber: number }>; // Non-code structural data (all optional for backward compat) sections?: SectionInfo[]; definitions?: DefinitionInfo[]; services?: ServiceInfo[]; endpoints?: EndpointInfo[]; steps?: StepInfo[]; resources?: ResourceInfo[]; } ``` Update `AnalyzerPlugin` interface (lines 109-115) — make `resolveImports` optional, add `extractReferences`: ```typescript export interface AnalyzerPlugin { name: string; languages: string[]; analyzeFile(filePath: string, content: string): StructuralAnalysis; resolveImports?(filePath: string, content: string): ImportResolution[]; extractCallGraph?(filePath: string, content: string): CallGraphEntry[]; extractReferences?(filePath: string, content: string): ReferenceResolution[]; } ``` **Step 4: Run test to verify it passes** Run: `pnpm --filter @understand-anything/core test -- --run types.test` Expected: PASS **Step 5: Commit** ```bash git add understand-anything-plugin/packages/core/src/types.ts understand-anything-plugin/packages/core/src/types.test.ts git commit -m "feat(core): extend GraphNode/EdgeType/StructuralAnalysis for non-code file types" ``` --- ## Task 2: Extend Schema Validation — Zod Schemas & Aliases **Files:** - Modify: `understand-anything-plugin/packages/core/src/schema.ts:1-554` - Test: `understand-anything-plugin/packages/core/src/__tests__/schema.test.ts` **Step 1: Write the failing tests** Add to `schema.test.ts`: ```typescript describe("Extended node/edge types", () => { it("validates nodes with new types: config, document, service, table, endpoint, pipeline, schema, resource", () => { const newTypes = ["config", "document", "service", "table", "endpoint", "pipeline", "schema", "resource"]; for (const type of newTypes) { const graph = structuredClone(validGraph); graph.nodes[0].type = type; const result = validateGraph(graph); expect(result.success).toBe(true); expect(result.data!.nodes[0].type).toBe(type); } }); it("validates edges with new types: deploys, serves, migrates, documents, provisions, routes, defines_schema, triggers", () => { const newTypes = ["deploys", "serves", "migrates", "documents", "provisions", "routes", "defines_schema", "triggers"]; for (const type of newTypes) { const graph = structuredClone(validGraph); graph.edges[0].type = type; const result = validateGraph(graph); expect(result.success).toBe(true); expect(result.data!.edges[0].type).toBe(type); } }); it("auto-fixes new node type aliases: container→service, doc→document, workflow→pipeline, etc.", () => { const aliases = { container: "service", doc: "document", workflow: "pipeline", route: "endpoint", setting: "config", infra: "resource", migration: "table" }; for (const [alias, canonical] of Object.entries(aliases)) { const graph = structuredClone(validGraph); (graph.nodes[0] as any).type = alias; const result = validateGraph(graph); expect(result.success).toBe(true); expect(result.data!.nodes[0].type).toBe(canonical); } }); it("auto-fixes new edge type aliases: describes→documents, creates→provisions, exposes→serves", () => { const aliases = { describes: "documents", creates: "provisions", exposes: "serves" }; for (const [alias, canonical] of Object.entries(aliases)) { const graph = structuredClone(validGraph); (graph.edges[0] as any).type = alias; const result = validateGraph(graph); expect(result.success).toBe(true); expect(result.data!.edges[0].type).toBe(canonical); } }); }); ``` **Step 2: Run test to verify it fails** Run: `pnpm --filter @understand-anything/core test -- --run schema.test` Expected: FAIL — Zod enum rejects new types **Step 3: Implement schema extensions** In `schema.ts`: 1. Update `EdgeTypeSchema` (line 4-10) — add 8 new edge types: ```typescript export const EdgeTypeSchema = z.enum([ "imports", "exports", "contains", "inherits", "implements", "calls", "subscribes", "publishes", "middleware", "reads_from", "writes_to", "transforms", "validates", "depends_on", "tested_by", "configures", "related", "similar_to", "deploys", "serves", "migrates", "documents", "provisions", "routes", "defines_schema", "triggers", ]); ``` 2. Update `NODE_TYPE_ALIASES` (line 13-22) — add new aliases: ```typescript export const NODE_TYPE_ALIASES: Record = { func: "function", fn: "function", method: "function", interface: "class", struct: "class", mod: "module", pkg: "module", package: "module", // New non-code aliases container: "service", deployment: "service", pod: "service", doc: "document", readme: "document", docs: "document", workflow: "pipeline", job: "pipeline", ci: "pipeline", action: "pipeline", route: "endpoint", api: "endpoint", query: "endpoint", mutation: "endpoint", setting: "config", env: "config", configuration: "config", infra: "resource", infrastructure: "resource", terraform: "resource", migration: "table", database: "table", db: "table", view: "table", proto: "schema", protobuf: "schema", definition: "schema", typedef: "schema", }; ``` 3. Update `EDGE_TYPE_ALIASES` (line 25-39) — add new aliases: ```typescript // Add these entries: describes: "documents", documented_by: "documents", creates: "provisions", exposes: "serves", listens: "serves", deploys_to: "deploys", migrates_to: "migrates", routes_to: "routes", triggers_on: "triggers", fires: "triggers", defines: "defines_schema", ``` 4. Update `GraphNodeSchema` (line 267-277) — extend type enum: ```typescript export const GraphNodeSchema = z.object({ id: z.string(), type: z.enum([ "file", "function", "class", "module", "concept", "config", "document", "service", "table", "endpoint", "pipeline", "schema", "resource", ]), name: z.string(), filePath: z.string().optional(), lineRange: z.tuple([z.number(), z.number()]).optional(), summary: z.string(), tags: z.array(z.string()), complexity: z.enum(["simple", "moderate", "complex"]), languageNotes: z.string().optional(), }); ``` **Step 4: Run test to verify it passes** Run: `pnpm --filter @understand-anything/core test -- --run schema.test` Expected: PASS **Step 5: Commit** ```bash git add understand-anything-plugin/packages/core/src/schema.ts understand-anything-plugin/packages/core/src/__tests__/schema.test.ts git commit -m "feat(core): extend Zod schemas and aliases for 8 new node/edge types" ``` --- ## Task 3: Update PluginRegistry — Optional resolveImports **Files:** - Modify: `understand-anything-plugin/packages/core/src/plugins/registry.ts:1-76` - Test: `understand-anything-plugin/packages/core/src/__tests__/plugin-registry.test.ts` **Step 1: Write the failing test** Add to `plugin-registry.test.ts`: ```typescript it("handles plugins with optional resolveImports (non-code plugins)", () => { const markdownPlugin: AnalyzerPlugin = { name: "markdown", languages: ["markdown"], analyzeFile: () => ({ functions: [], classes: [], imports: [], exports: [] }), // No resolveImports — optional }; registry.register(markdownPlugin); const result = registry.resolveImports("README.md", "# Hello"); expect(result).toBeNull(); // Returns null for plugins without resolveImports }); ``` **Step 2: Run test to verify it fails** Run: `pnpm --filter @understand-anything/core test -- --run plugin-registry.test` Expected: FAIL — current registry calls `plugin.resolveImports(...)` unconditionally **Step 3: Update PluginRegistry** In `registry.ts`, update `resolveImports` (line 62-66): ```typescript resolveImports(filePath: string, content: string): ImportResolution[] | null { const plugin = this.getPluginForFile(filePath); if (!plugin || !plugin.resolveImports) return null; return plugin.resolveImports(filePath, content); } ``` **Step 4: Run test to verify it passes** Run: `pnpm --filter @understand-anything/core test -- --run plugin-registry.test` Expected: PASS **Step 5: Commit** ```bash git add understand-anything-plugin/packages/core/src/plugins/registry.ts understand-anything-plugin/packages/core/src/__tests__/plugin-registry.test.ts git commit -m "feat(core): make resolveImports optional on AnalyzerPlugin" ``` --- ## Task 4: Add Non-Code Language Configs (26 configs) **Files:** - Create: `understand-anything-plugin/packages/core/src/languages/configs/markdown.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/yaml.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/json-config.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/toml.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/env.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/xml.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/dockerfile.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/sql.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/graphql.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/protobuf.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/terraform.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/github-actions.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/makefile.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/shell.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/html.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/css.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/openapi.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/kubernetes.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/docker-compose.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/json-schema.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/csv.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/restructuredtext.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/powershell.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/batch.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/jenkinsfile.ts` - Create: `understand-anything-plugin/packages/core/src/languages/configs/plaintext.ts` - Modify: `understand-anything-plugin/packages/core/src/languages/configs/index.ts` - Test: `understand-anything-plugin/packages/core/src/__tests__/language-registry.test.ts` **Step 1: Write the failing test** Add to `language-registry.test.ts`: ```typescript describe("Non-code language configs", () => { it("detects all non-code file types via extension", () => { const registry = LanguageRegistry.createDefault(); const expectations: [string, string][] = [ ["README.md", "markdown"], ["config.yaml", "yaml"], ["package.json", "json"], ["config.toml", "toml"], [".env", "env"], ["pom.xml", "xml"], ["Dockerfile", "dockerfile"], ["schema.sql", "sql"], ["schema.graphql", "graphql"], ["types.proto", "protobuf"], ["main.tf", "terraform"], ["Makefile", "makefile"], ["deploy.sh", "shell"], ["index.html", "html"], ["styles.css", "css"], ["data.csv", "csv"], ["deploy.ps1", "powershell"], ]; for (const [file, expectedId] of expectations) { const config = registry.getForFile(file); expect(config?.id, `${file} should be detected as ${expectedId}`).toBe(expectedId); } }); }); ``` **Step 2: Run test to verify it fails** Run: `pnpm --filter @understand-anything/core test -- --run language-registry.test` Expected: FAIL — no configs registered for non-code extensions **Step 3: Create all config files** Each config follows the same pattern as `typescript.ts`. Example for markdown: ```typescript // markdown.ts import type { LanguageConfig } from "../types.js"; export const markdownConfig = { id: "markdown", displayName: "Markdown", extensions: [".md", ".mdx"], concepts: ["headings", "links", "code blocks", "front matter", "lists", "tables", "images"], filePatterns: { entryPoints: ["README.md"], barrels: [], tests: [], config: [], }, } satisfies LanguageConfig; ``` Create similar configs for all 26 types. Key extension mappings: - yaml: `.yaml`, `.yml` - json: `.json`, `.jsonc` - toml: `.toml` - env: `.env` (Note: LanguageRegistry needs filename match, not just extension) - xml: `.xml` - dockerfile: `Dockerfile` (filename-based detection — needs special handling) - sql: `.sql` - graphql: `.graphql`, `.gql` - protobuf: `.proto` - terraform: `.tf`, `.tfvars` - github-actions: (detected by path `.github/workflows/*.yml` — defer to scanner) - makefile: `Makefile` (filename-based — needs special handling) - shell: `.sh`, `.bash`, `.zsh` - html: `.html`, `.htm` - css: `.css`, `.scss`, `.less` - csv: `.csv`, `.tsv` - powershell: `.ps1`, `.psm1` - batch: `.bat`, `.cmd` - plaintext: `.txt` - restructuredtext: `.rst` - jenkinsfile: (filename-based — `Jenkinsfile`) **Important:** For filename-based detection (Dockerfile, Makefile, Jenkinsfile), extend LanguageRegistry to support `filenames` array in addition to `extensions`. Add a `filenames?: string[]` field to `LanguageConfig` and update `getForFile()` to check basename against filenames when extension lookup fails. Update `configs/index.ts` to import and register all new configs in `builtinLanguageConfigs`. **Step 4: Run test to verify it passes** Run: `pnpm --filter @understand-anything/core test -- --run language-registry.test` Expected: PASS **Step 5: Commit** ```bash git add understand-anything-plugin/packages/core/src/languages/ git commit -m "feat(core): add 26 non-code language configs with filename-based detection" ``` --- ## Task 5: Build Custom Parsers (12 parsers) **Files:** - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/markdown-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/yaml-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/json-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/toml-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/env-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/dockerfile-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/sql-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/graphql-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/protobuf-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/terraform-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/makefile-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/shell-parser.ts` - Create: `understand-anything-plugin/packages/core/src/plugins/parsers/index.ts` - Test: `understand-anything-plugin/packages/core/src/__tests__/parsers.test.ts` Each parser implements `AnalyzerPlugin`. Build them TDD-style, one at a time. **Step 1: Write failing tests for all 12 parsers** Create `parsers.test.ts` with test suites for each parser. Example for MarkdownParser: ```typescript import { describe, it, expect } from "vitest"; import { MarkdownParser } from "../plugins/parsers/markdown-parser.js"; describe("MarkdownParser", () => { const parser = new MarkdownParser(); it("extracts heading sections", () => { const content = "# Title\n\nIntro\n\n## Section A\n\nContent A\n\n### Subsection\n\nContent B"; const result = parser.analyzeFile("README.md", content); expect(result.sections).toHaveLength(3); expect(result.sections![0]).toMatchObject({ name: "Title", level: 1 }); expect(result.sections![1]).toMatchObject({ name: "Section A", level: 2 }); expect(result.sections![2]).toMatchObject({ name: "Subsection", level: 3 }); }); it("extracts YAML front matter as imports", () => { const content = "---\ntitle: Test\ntags: [a, b]\n---\n# Content"; const result = parser.analyzeFile("post.md", content); expect(result.imports).toHaveLength(0); // Front matter is metadata, not imports }); it("extracts file references", () => { const parser2 = new MarkdownParser(); const content = "See [guide](./docs/guide.md) and ![img](./assets/logo.png)"; const refs = parser2.extractReferences!("README.md", content); expect(refs).toHaveLength(2); expect(refs[0]).toMatchObject({ target: "./docs/guide.md", referenceType: "file" }); expect(refs[1]).toMatchObject({ target: "./assets/logo.png", referenceType: "image" }); }); }); ``` Similar test suites for: - **DockerfileParser**: Extract FROM stages, EXPOSE ports, COPY sources - **SQLParser**: Extract CREATE TABLE, columns, foreign keys - **YAMLParser**: Extract top-level key hierarchy - **JSONParser**: Extract key structure, `$ref`/`$defs` - **TerraformParser**: Extract resource/module/variable blocks - **GraphQLParser**: Extract type/query/mutation/subscription definitions - **ProtobufParser**: Extract message/service/enum definitions - **MakefileParser**: Extract targets and dependencies - **ShellParser**: Extract function definitions and source commands - **TOMLParser**: Extract section structure - **EnvParser**: Extract variable names **Step 2: Run tests to verify they fail** Run: `pnpm --filter @understand-anything/core test -- --run parsers.test` Expected: FAIL — parser modules don't exist **Step 3: Implement all 12 parsers** Each parser follows this pattern: ```typescript import type { AnalyzerPlugin, StructuralAnalysis, ReferenceResolution } from "../../types.js"; export class MarkdownParser implements AnalyzerPlugin { name = "markdown-parser"; languages = ["markdown"]; analyzeFile(filePath: string, content: string): StructuralAnalysis { const sections = this.extractSections(content); return { functions: [], classes: [], imports: [], exports: [], sections, }; } extractReferences(filePath: string, content: string): ReferenceResolution[] { const refs: ReferenceResolution[] = []; // Match [text](path) and ![alt](path) const linkRegex = /!?\[([^\]]*)\]\(([^)]+)\)/g; let match; while ((match = linkRegex.exec(content)) !== null) { const target = match[2]; if (target.startsWith("http")) continue; // Skip external URLs const line = content.slice(0, match.index).split("\n").length; refs.push({ source: filePath, target, referenceType: match[0].startsWith("!") ? "image" : "file", line, }); } return refs; } private extractSections(content: string): SectionInfo[] { const sections: SectionInfo[] = []; const lines = content.split("\n"); for (let i = 0; i < lines.length; i++) { const match = lines[i].match(/^(#{1,6})\s+(.+)/); if (match) { sections.push({ name: match[2].trim(), level: match[1].length, lineRange: [i + 1, i + 1], }); } } // Fix lineRange end for each section (extends to next heading or EOF) for (let i = 0; i < sections.length; i++) { const next = sections[i + 1]; sections[i].lineRange[1] = next ? next.lineRange[0] - 1 : lines.length; } return sections; } } ``` Create `parsers/index.ts` that exports all parsers and a `registerAllParsers(registry: PluginRegistry)` helper. **Install new dependencies:** ```bash cd understand-anything-plugin/packages/core pnpm add yaml @iarna/toml jsonc-parser ``` **Step 4: Run tests to verify they pass** Run: `pnpm --filter @understand-anything/core test -- --run parsers.test` Expected: PASS **Step 5: Commit** ```bash git add understand-anything-plugin/packages/core/src/plugins/parsers/ understand-anything-plugin/packages/core/src/__tests__/parsers.test.ts understand-anything-plugin/packages/core/package.json understand-anything-plugin/packages/core/pnpm-lock.yaml git commit -m "feat(core): add 12 custom parsers for non-code file types" ``` --- ## Task 6: Update GraphBuilder — Support New Node Types **Files:** - Modify: `understand-anything-plugin/packages/core/src/analyzer/graph-builder.ts:1-207` - Test: `understand-anything-plugin/packages/core/src/analyzer/graph-builder.test.ts` **Step 1: Write the failing test** Add to `graph-builder.test.ts`: ```typescript describe("Non-code file support", () => { it("adds non-code file nodes with correct types", () => { const builder = new GraphBuilder("test", "abc123"); builder.addNonCodeFile("README.md", { nodeType: "document", summary: "Project documentation", tags: ["documentation"], complexity: "simple", }); const graph = builder.build(); expect(graph.nodes).toHaveLength(1); expect(graph.nodes[0].type).toBe("document"); expect(graph.nodes[0].id).toBe("file:README.md"); }); it("adds non-code child nodes (sections, definitions, services)", () => { const builder = new GraphBuilder("test", "abc123"); builder.addNonCodeFileWithAnalysis("schema.sql", { nodeType: "file", summary: "Database schema", tags: ["database"], complexity: "moderate", definitions: [{ name: "users", kind: "table", lineRange: [1, 20] as [number, number], fields: ["id", "name", "email"] }], }); const graph = builder.build(); // File node + table child node expect(graph.nodes).toHaveLength(2); expect(graph.nodes[1].type).toBe("table"); expect(graph.nodes[1].name).toBe("users"); // Contains edge expect(graph.edges.some(e => e.type === "contains" && e.target.includes("users"))).toBe(true); }); it("detects non-code languages from EXTENSION_LANGUAGE map", () => { const builder = new GraphBuilder("test", "abc123"); builder.addFile("config.yaml", { summary: "Config", tags: [], complexity: "simple" }); const graph = builder.build(); expect(graph.project.languages).toContain("yaml"); }); }); ``` **Step 2: Run test to verify it fails** Run: `pnpm --filter @understand-anything/core test -- --run graph-builder.test` Expected: FAIL — `addNonCodeFile` and `addNonCodeFileWithAnalysis` methods don't exist **Step 3: Implement GraphBuilder extensions** Add new methods to GraphBuilder: ```typescript interface NonCodeFileMeta extends FileMeta { nodeType: GraphNode["type"]; } interface NonCodeFileAnalysisMeta extends NonCodeFileMeta { definitions?: DefinitionInfo[]; services?: ServiceInfo[]; endpoints?: EndpointInfo[]; steps?: StepInfo[]; resources?: ResourceInfo[]; sections?: SectionInfo[]; } addNonCodeFile(filePath: string, meta: NonCodeFileMeta): void { const lang = detectLanguage(filePath); if (lang !== "unknown") this.languages.add(lang); const name = filePath.split("/").pop() ?? filePath; this.nodes.push({ id: `file:${filePath}`, type: meta.nodeType, name, filePath, summary: meta.summary, tags: meta.tags, complexity: meta.complexity, }); } addNonCodeFileWithAnalysis(filePath: string, meta: NonCodeFileAnalysisMeta): void { this.addNonCodeFile(filePath, meta); const fileId = `file:${filePath}`; // Create child nodes for definitions (tables, schemas, etc.) for (const def of meta.definitions ?? []) { const childId = `${def.kind}:${filePath}:${def.name}`; this.nodes.push({ id: childId, type: this.mapKindToNodeType(def.kind), name: def.name, filePath, lineRange: def.lineRange, summary: `${def.kind}: ${def.name} (${def.fields.length} fields)`, tags: [], complexity: meta.complexity, }); this.edges.push({ source: fileId, target: childId, type: "contains", direction: "forward", weight: 1 }); } // Create child nodes for services for (const svc of meta.services ?? []) { const childId = `service:${filePath}:${svc.name}`; this.nodes.push({ id: childId, type: "service", name: svc.name, filePath, summary: `Service ${svc.name}${svc.image ? ` (image: ${svc.image})` : ""}`, tags: [], complexity: meta.complexity, }); this.edges.push({ source: fileId, target: childId, type: "contains", direction: "forward", weight: 1 }); } // Similar for endpoints, steps, resources } private mapKindToNodeType(kind: string): GraphNode["type"] { const mapping: Record = { table: "table", view: "table", index: "table", message: "schema", type: "schema", enum: "schema", resource: "resource", module: "resource", service: "service", deployment: "service", job: "pipeline", stage: "pipeline", target: "pipeline", route: "endpoint", query: "endpoint", mutation: "endpoint", }; return mapping[kind] ?? "concept"; } ``` **Step 4: Run test to verify it passes** Run: `pnpm --filter @understand-anything/core test -- --run graph-builder.test` Expected: PASS **Step 5: Commit** ```bash git add understand-anything-plugin/packages/core/src/analyzer/graph-builder.ts understand-anything-plugin/packages/core/src/analyzer/graph-builder.test.ts git commit -m "feat(core): add non-code file support to GraphBuilder" ``` --- ## Task 7: Update Core Exports **Files:** - Modify: `understand-anything-plugin/packages/core/src/index.ts` **Step 1: Update exports to include new types and parsers** Add to `index.ts`: ```typescript // New structural analysis types export type { SectionInfo, DefinitionInfo, ServiceInfo, EndpointInfo, StepInfo, ResourceInfo, ReferenceResolution, } from "./types.js"; // Non-code parsers export { MarkdownParser, DockerfileParser, SQLParser, YAMLConfigParser, JSONConfigParser, TOMLParser, EnvParser, GraphQLParser, ProtobufParser, TerraformParser, MakefileParser, ShellParser, registerAllParsers, } from "./plugins/parsers/index.js"; ``` **Step 2: Build to verify exports work** Run: `pnpm --filter @understand-anything/core build` Expected: Success, no errors **Step 3: Commit** ```bash git add understand-anything-plugin/packages/core/src/index.ts git commit -m "feat(core): export new types and parsers from core" ``` --- ## Task 8: Update Agent Prompts — Project Scanner **Files:** - Modify: `understand-anything-plugin/skills/understand/project-scanner-prompt.md` **Step 1: Update the scanner to discover ALL file types** Key changes to the prompt: 1. Remove the code-only file filter — scan `.md`, `.yaml`, `.json`, `.sql`, `.tf`, `Dockerfile`, etc. 2. Add a `fileCategory` field to each discovered file: `"code" | "config" | "docs" | "infra" | "data" | "script" | "markup"` 3. Update the exclusion list — still exclude `node_modules/`, `.git/`, binaries, but include non-code files 4. Add category detection logic in the discovery script: - `.md`, `.rst`, `.txt` → `"docs"` - `.yaml`, `.yml`, `.json`, `.toml`, `.env`, `.xml` → `"config"` - `Dockerfile`, `docker-compose.*`, `.tf`, `.github/workflows/*`, `Makefile`, `Jenkinsfile` → `"infra"` - `.sql`, `.graphql`, `.proto`, `.schema.json`, `.csv` → `"data"` - `.sh`, `.bash`, `.ps1`, `.bat` → `"script"` - `.html`, `.css`, `.scss` → `"markup"` - Everything else → `"code"` 5. Update output schema to include `fileCategory` per file **Step 2: Commit** ```bash git add understand-anything-plugin/skills/understand/project-scanner-prompt.md git commit -m "feat(agents): update project-scanner to discover all file types" ``` --- ## Task 9: Update Agent Prompts — File Analyzer **Files:** - Modify: `understand-anything-plugin/skills/understand/file-analyzer-prompt.md` **Step 1: Add type-aware analysis prompts** Key changes: 1. Add a section at the top explaining file categories and how to analyze each: - **Code files** (current behavior): Extract functions, classes, imports, call graph - **Config files**: Extract key settings, what they configure, which code they affect - **Documentation files**: Extract sections/headings, key concepts, referenced code components - **Infrastructure files**: Extract services, ports, volumes, deployments, which code they deploy - **Data/Schema files**: Extract tables, columns, types, relationships, consuming code - **Pipeline files**: Extract jobs, steps, triggers, deployed targets 2. Update the output JSON schema to include new fields: - `sections` (for docs) - `definitions` (for data/schema) - `services` (for infra) - `endpoints` (for API schemas) - `steps` (for pipelines) - `resources` (for IaC) 3. Add `nodeType` field to output: what GraphNode type each file should become (file, config, document, service, etc.) 4. Update edge generation guidance: - Config files: generate `configures` edges to code files they affect - Doc files: generate `documents` edges to described code - Dockerfiles: generate `deploys` edges to code directories - SQL migrations: generate `migrates` edges to tables - CI configs: generate `triggers` edges to pipelines - API schemas: generate `defines_schema` edges to endpoints 5. Update tagging guidance with new tags: `documentation`, `configuration`, `infrastructure`, `database`, `api-schema`, `ci-cd`, `deployment`, `migration` **Step 2: Commit** ```bash git add understand-anything-plugin/skills/understand/file-analyzer-prompt.md git commit -m "feat(agents): add type-aware analysis prompts for non-code files" ``` --- ## Task 10: Update Agent Prompts — Architecture Analyzer **Files:** - Modify: `understand-anything-plugin/skills/understand/architecture-analyzer-prompt.md` **Step 1: Add non-code pattern detection** Key changes: 1. Add new architectural patterns to detect: - **Deployment topology**: Dockerfile → docker-compose → K8s manifests - **Data pipeline**: Schema definition → migration → API endpoint → client code - **Documentation coverage**: Which modules have corresponding docs - **Configuration graph**: Which config files affect which code paths 2. Update layer hints to include non-code layers: - `"infrastructure"` layer for Dockerfiles, K8s, Terraform - `"documentation"` layer for docs - `"data"` layer for SQL, schemas - `"ci-cd"` layer for GitHub Actions, Jenkinsfiles 3. Update script to compute cross-category dependency analysis (code→infra, code→config, etc.) **Step 2: Commit** ```bash git add understand-anything-plugin/skills/understand/architecture-analyzer-prompt.md git commit -m "feat(agents): add non-code pattern detection to architecture analyzer" ``` --- ## Task 11: Update Agent Prompts — Tour Builder **Files:** - Modify: `understand-anything-plugin/skills/understand/tour-builder-prompt.md` **Step 1: Add non-code tour stops** Key changes: 1. Update tour step guidance to include non-code files: - Step 1 could be README.md (project overview) - Infrastructure stops: "How the app gets containerized" - Data stops: "The database schema" - CI/CD stops: "How code gets deployed" 2. Update `languageLesson` to also cover non-code concepts: - Dockerfile: multi-stage builds, layer caching - SQL: normalization, foreign keys - YAML: anchors, merge keys - Terraform: state management, modules **Step 2: Commit** ```bash git add understand-anything-plugin/skills/understand/tour-builder-prompt.md git commit -m "feat(agents): extend tour builder for non-code file stops" ``` --- ## Task 12: Update Agent Prompts — Graph Reviewer **Files:** - Modify: `understand-anything-plugin/skills/understand/graph-reviewer-prompt.md` **Step 1: Update validation for new node/edge types** Key changes: 1. Add new node types to the valid type list in the validation script 2. Add new edge types to the valid type list 3. Add quality checks for non-code nodes: - Config nodes should have `configures` edges - Document nodes should have `documents` edges - Service nodes should have `deploys` edges - Table nodes should reference columns **Step 2: Commit** ```bash git add understand-anything-plugin/skills/understand/graph-reviewer-prompt.md git commit -m "feat(agents): update graph reviewer for new node/edge types" ``` --- ## Task 13: Add Language Context Snippets **Files:** - Create: `understand-anything-plugin/skills/understand/languages/markdown.md` - Create: `understand-anything-plugin/skills/understand/languages/yaml.md` - Create: `understand-anything-plugin/skills/understand/languages/json.md` - Create: `understand-anything-plugin/skills/understand/languages/sql.md` - Create: `understand-anything-plugin/skills/understand/languages/dockerfile.md` - Create: `understand-anything-plugin/skills/understand/languages/terraform.md` - Create: `understand-anything-plugin/skills/understand/languages/graphql.md` - Create: `understand-anything-plugin/skills/understand/languages/protobuf.md` - Create: `understand-anything-plugin/skills/understand/languages/shell.md` - Create: `understand-anything-plugin/skills/understand/languages/html.md` - Create: `understand-anything-plugin/skills/understand/languages/css.md` Each snippet follows the pattern of existing `typescript.md` / `python.md`: ```markdown # Markdown ## Key Concepts - Heading hierarchy (# through ######) - Front matter (YAML metadata between --- delimiters) - Code blocks (fenced with ``` or indented) - Reference-style links - Tables (pipe-delimited) ## Notable File Patterns - `README.md` — Project overview (high-value entry point) - `CONTRIBUTING.md` — Contribution guidelines - `CHANGELOG.md` — Version history - `docs/**/*.md` — Documentation directory ## Edge Patterns - Markdown files `documents` the code components they describe - Links to other .md files create `related` edges - Code block references may imply `depends_on` edges ## Summary Style > "Comprehensive guide document with N sections covering [topics]" ``` **Step 1: Create all 11 language snippets** **Step 2: Commit** ```bash git add understand-anything-plugin/skills/understand/languages/ git commit -m "feat(agents): add language context snippets for 11 non-code file types" ``` --- ## Task 14: Update SKILL.md — Main Pipeline **Files:** - Modify: `understand-anything-plugin/skills/understand/SKILL.md` **Step 1: Update the pipeline to handle non-code files** Key changes: 1. **Phase 1 (SCAN)**: Update file batching to include non-code files. Add `fileCategory` to batch metadata. 2. **Phase 2 (ANALYZE)**: Update batch construction to group related non-code files together (e.g., Dockerfile + docker-compose.yml). Pass `fileCategory` to file-analyzer prompt. 3. **Phase 4 (ARCHITECTURE)**: Inject non-code language snippets for detected non-code languages. 4. **Phase 5 (TOUR)**: Include non-code nodes in tour candidate pool. 5. **Phase 7 (SAVE)**: No changes needed (schema handles new types). 6. **Node/Edge reference table**: Add the 8 new node types and 8 new edge types. **Step 2: Commit** ```bash git add understand-anything-plugin/skills/understand/SKILL.md git commit -m "feat(pipeline): update main skill pipeline for non-code file analysis" ``` --- ## Task 15: Dashboard — Add Node Type Colors to Theme Presets **Files:** - Modify: `understand-anything-plugin/packages/dashboard/src/themes/presets.ts:1-143` **Step 1: Add 8 new node type colors to all 5 presets** Add these color entries to each preset's `colors` object: For dark presets: ```typescript "node-config": "#5eead4", // Teal "node-document": "#7dd3fc", // Sky blue "node-service": "#a78bfa", // Violet "node-table": "#6ee7b7", // Emerald "node-endpoint": "#fdba74", // Orange "node-pipeline": "#fda4af", // Rose "node-schema": "#fcd34d", // Amber "node-resource": "#a5b4fc", // Indigo ``` For light preset, use slightly darker versions: ```typescript "node-config": "#14b8a6", "node-document": "#38bdf8", "node-service": "#8b5cf6", "node-table": "#34d399", "node-endpoint": "#fb923c", "node-pipeline": "#fb7185", "node-schema": "#facc15", "node-resource": "#818cf8", ``` **Step 2: Commit** ```bash git add understand-anything-plugin/packages/dashboard/src/themes/presets.ts git commit -m "feat(dashboard): add 8 new node type colors to all theme presets" ``` --- ## Task 16: Dashboard — Update CustomNode Component **Files:** - Modify: `understand-anything-plugin/packages/dashboard/src/components/CustomNode.tsx:1-137` **Step 1: Add new entries to typeColors and typeTextColors maps** ```typescript const typeColors: Record = { file: "var(--color-node-file)", function: "var(--color-node-function)", class: "var(--color-node-class)", module: "var(--color-node-module)", concept: "var(--color-node-concept)", config: "var(--color-node-config)", document: "var(--color-node-document)", service: "var(--color-node-service)", table: "var(--color-node-table)", endpoint: "var(--color-node-endpoint)", pipeline: "var(--color-node-pipeline)", schema: "var(--color-node-schema)", resource: "var(--color-node-resource)", }; const typeTextColors: Record = { file: "text-node-file", function: "text-node-function", class: "text-node-class", module: "text-node-module", concept: "text-node-concept", config: "text-node-config", document: "text-node-document", service: "text-node-service", table: "text-node-table", endpoint: "text-node-endpoint", pipeline: "text-node-pipeline", schema: "text-node-schema", resource: "text-node-resource", }; ``` **Step 2: Commit** ```bash git add understand-anything-plugin/packages/dashboard/src/components/CustomNode.tsx git commit -m "feat(dashboard): add new node type colors to CustomNode" ``` --- ## Task 17: Dashboard — Update NodeInfo Sidebar **Files:** - Modify: `understand-anything-plugin/packages/dashboard/src/components/NodeInfo.tsx:1-312` **Step 1: Add badge colors for new node types** Add to `typeBadgeColors`: ```typescript config: "text-node-config border border-node-config/30 bg-node-config/10", document: "text-node-document border border-node-document/30 bg-node-document/10", service: "text-node-service border border-node-service/30 bg-node-service/10", table: "text-node-table border border-node-table/30 bg-node-table/10", endpoint: "text-node-endpoint border border-node-endpoint/30 bg-node-endpoint/10", pipeline: "text-node-pipeline border border-node-pipeline/30 bg-node-pipeline/10", schema: "text-node-schema border border-node-schema/30 bg-node-schema/10", resource: "text-node-resource border border-node-resource/30 bg-node-resource/10", ``` **Step 2: Add directional labels for new edge types** Add to `getDirectionalLabel()`: ```typescript case "deploys": return isSource ? "deploys" : "deployed by"; case "serves": return isSource ? "serves" : "served by"; case "migrates": return isSource ? "migrates" : "migrated by"; case "documents": return isSource ? "documents" : "documented by"; case "provisions": return isSource ? "provisions" : "provisioned by"; case "routes": return isSource ? "routes to" : "routed from"; case "defines_schema": return isSource ? "defines schema for" : "schema defined by"; case "triggers": return isSource ? "triggers" : "triggered by"; ``` **Step 3: Commit** ```bash git add understand-anything-plugin/packages/dashboard/src/components/NodeInfo.tsx git commit -m "feat(dashboard): add new node/edge type support to NodeInfo sidebar" ``` --- ## Task 18: Dashboard — Update ProjectOverview with File Type Breakdown **Files:** - Modify: `understand-anything-plugin/packages/dashboard/src/components/ProjectOverview.tsx` **Step 1: Add file type distribution** Add a "File Types" section after the stats grid that shows count per node type category: - Code: file + function + class - Config: config - Docs: document - Infra: service + resource + pipeline - Data: table + endpoint + schema Use colored dots matching the node type colors. **Step 2: Commit** ```bash git add understand-anything-plugin/packages/dashboard/src/components/ProjectOverview.tsx git commit -m "feat(dashboard): add file type breakdown to ProjectOverview" ``` --- ## Task 19: Dashboard — Add Filter Controls **Files:** - Modify: `understand-anything-plugin/packages/dashboard/src/store.ts` - Modify: `understand-anything-plugin/packages/dashboard/src/components/GraphView.tsx` - Modify: `understand-anything-plugin/packages/dashboard/src/App.tsx` **Step 1: Add filter state to store** Add to the Zustand store: ```typescript nodeTypeFilters: Record; // { code: true, config: true, docs: true, infra: true, data: true } toggleNodeTypeFilter: (category: string) => void; ``` Default all categories to `true` (visible). **Step 2: Apply filters in GraphView topology computation** In `useLayerDetailTopology`, filter nodes based on `nodeTypeFilters` before layout. **Step 3: Add filter checkboxes to App.tsx header** Add small checkbox toggles next to the layer legend for each category. **Step 4: Commit** ```bash git add understand-anything-plugin/packages/dashboard/src/store.ts understand-anything-plugin/packages/dashboard/src/components/GraphView.tsx understand-anything-plugin/packages/dashboard/src/App.tsx git commit -m "feat(dashboard): add node type category filter controls" ``` --- ## Task 20: Dashboard Build Verification **Step 1: Build the dashboard** Run: `pnpm --filter @understand-anything/dashboard build` Expected: Success, no TypeScript errors **Step 2: Build the core package** Run: `pnpm --filter @understand-anything/core build` Expected: Success **Step 3: Run all core tests** Run: `pnpm --filter @understand-anything/core test` Expected: All tests pass **Step 4: Run lint** Run: `pnpm lint` Expected: No errors **Step 5: Commit any lint fixes** ```bash git add -A git commit -m "fix: lint and build fixes for universal file type support" ``` --- ## Task 21: Integration Test — End-to-End Verification **Step 1: Dev server smoke test** Run: `pnpm dev:dashboard` - Load a knowledge graph that includes non-code nodes - Verify new node types render with correct colors - Verify NodeInfo sidebar shows new edge labels - Verify filter controls work **Step 2: Generate test graph with non-code nodes** Update `scripts/generate-large-graph.mjs` to include non-code node types in the random generation, then generate a test graph and load it in the dashboard. **Step 3: Commit** ```bash git add scripts/generate-large-graph.mjs git commit -m "feat(scripts): include non-code node types in test graph generator" ``` --- ## Task 22: Version Bump & Final Commit **Files:** - Modify: `understand-anything-plugin/package.json` → bump version - Modify: `.claude-plugin/marketplace.json` → bump version - Modify: `.claude-plugin/plugin.json` → bump version - Modify: `.cursor-plugin/plugin.json` → bump version **Step 1: Bump version in all 4 files** (e.g., 1.3.0 → 1.4.0) **Step 2: Final commit** ```bash git add understand-anything-plugin/package.json .claude-plugin/marketplace.json .claude-plugin/plugin.json .cursor-plugin/plugin.json git commit -m "chore: bump version to 1.4.0 for universal file type support" ``` --- ## Summary of All Tasks | # | Task | Files | Depends On | |---|------|-------|------------| | 1 | Extend core types | types.ts | — | | 2 | Extend schema validation | schema.ts | 1 | | 3 | Update PluginRegistry | registry.ts | 1 | | 4 | Add 26 language configs | languages/configs/ | 1 | | 5 | Build 12 custom parsers | plugins/parsers/ | 1, 3 | | 6 | Update GraphBuilder | graph-builder.ts | 1 | | 7 | Update core exports | index.ts | 1-6 | | 8 | Update project-scanner prompt | project-scanner-prompt.md | — | | 9 | Update file-analyzer prompt | file-analyzer-prompt.md | — | | 10 | Update architecture-analyzer prompt | architecture-analyzer-prompt.md | — | | 11 | Update tour-builder prompt | tour-builder-prompt.md | — | | 12 | Update graph-reviewer prompt | graph-reviewer-prompt.md | — | | 13 | Add language context snippets | languages/*.md | — | | 14 | Update SKILL.md pipeline | SKILL.md | 8-13 | | 15 | Dashboard theme colors | presets.ts | — | | 16 | Dashboard CustomNode | CustomNode.tsx | 15 | | 17 | Dashboard NodeInfo | NodeInfo.tsx | 15 | | 18 | Dashboard ProjectOverview | ProjectOverview.tsx | 15 | | 19 | Dashboard filter controls | store.ts, GraphView.tsx, App.tsx | 15-18 | | 20 | Build verification | — | 1-19 | | 21 | Integration test | — | 20 | | 22 | Version bump | package.json × 4 | 21 | **Parallelizable groups:** - Tasks 1-7 (core) are sequential - Tasks 8-14 (agent prompts) can run in parallel with each other, and in parallel with Tasks 15-19 (dashboard) - Tasks 20-22 are sequential and depend on all prior tasks