homegraph 1.2.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -11
- package/dist/bin/homegraph.js +298 -72
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +117 -11
- package/dist/context/index.js.map +1 -1
- package/dist/db/index.d.ts +207 -6
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +461 -20
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +19 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts +157 -3
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +426 -9
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.sql +32 -1
- package/dist/db/sqlite-adapter.d.ts +24 -17
- package/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/dist/db/sqlite-adapter.js +292 -36
- package/dist/db/sqlite-adapter.js.map +1 -1
- package/dist/db/wal-valve.d.ts +119 -0
- package/dist/db/wal-valve.d.ts.map +1 -0
- package/dist/db/wal-valve.js +290 -0
- package/dist/db/wal-valve.js.map +1 -0
- package/dist/directory.d.ts +9 -5
- package/dist/directory.d.ts.map +1 -1
- package/dist/directory.js +210 -19
- package/dist/directory.js.map +1 -1
- package/dist/extraction/arkts-batch-worker.js +3 -2
- package/dist/extraction/arkts-batch-worker.js.map +1 -1
- package/dist/extraction/cfml-extractor.d.ts +107 -0
- package/dist/extraction/cfml-extractor.d.ts.map +1 -0
- package/dist/extraction/cfml-extractor.js +494 -0
- package/dist/extraction/cfml-extractor.js.map +1 -0
- package/dist/extraction/default-ignore.d.ts +39 -0
- package/dist/extraction/default-ignore.d.ts.map +1 -0
- package/dist/extraction/default-ignore.js +221 -0
- package/dist/extraction/default-ignore.js.map +1 -0
- package/dist/extraction/grammars.d.ts +25 -1
- package/dist/extraction/grammars.d.ts.map +1 -1
- package/dist/extraction/grammars.js +177 -24
- package/dist/extraction/grammars.js.map +1 -1
- package/dist/extraction/index.d.ts +52 -14
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +521 -314
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/arkts.d.ts +90 -6
- package/dist/extraction/languages/arkts.d.ts.map +1 -1
- package/dist/extraction/languages/arkts.js +1579 -128
- package/dist/extraction/languages/arkts.js.map +1 -1
- package/dist/extraction/languages/c-cpp.d.ts +42 -0
- package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/dist/extraction/languages/c-cpp.js +369 -4
- package/dist/extraction/languages/c-cpp.js.map +1 -1
- package/dist/extraction/languages/cfquery.d.ts +12 -0
- package/dist/extraction/languages/cfquery.d.ts.map +1 -0
- package/dist/extraction/languages/cfquery.js +28 -0
- package/dist/extraction/languages/cfquery.js.map +1 -0
- package/dist/extraction/languages/cfscript.d.ts +3 -0
- package/dist/extraction/languages/cfscript.d.ts.map +1 -0
- package/dist/extraction/languages/cfscript.js +73 -0
- package/dist/extraction/languages/cfscript.js.map +1 -0
- package/dist/extraction/languages/cobol.d.ts +33 -0
- package/dist/extraction/languages/cobol.d.ts.map +1 -0
- package/dist/extraction/languages/cobol.js +499 -0
- package/dist/extraction/languages/cobol.js.map +1 -0
- package/dist/extraction/languages/erlang.d.ts +3 -0
- package/dist/extraction/languages/erlang.d.ts.map +1 -0
- package/dist/extraction/languages/erlang.js +350 -0
- package/dist/extraction/languages/erlang.js.map +1 -0
- package/dist/extraction/languages/index.d.ts.map +1 -1
- package/dist/extraction/languages/index.js +16 -0
- package/dist/extraction/languages/index.js.map +1 -1
- package/dist/extraction/languages/nix.d.ts +3 -0
- package/dist/extraction/languages/nix.d.ts.map +1 -0
- package/dist/extraction/languages/nix.js +294 -0
- package/dist/extraction/languages/nix.js.map +1 -0
- package/dist/extraction/languages/solidity.d.ts +3 -0
- package/dist/extraction/languages/solidity.d.ts.map +1 -0
- package/dist/extraction/languages/solidity.js +293 -0
- package/dist/extraction/languages/solidity.js.map +1 -0
- package/dist/extraction/languages/terraform.d.ts +3 -0
- package/dist/extraction/languages/terraform.d.ts.map +1 -0
- package/dist/extraction/languages/terraform.js +641 -0
- package/dist/extraction/languages/terraform.js.map +1 -0
- package/dist/extraction/languages/vbnet.d.ts +11 -0
- package/dist/extraction/languages/vbnet.d.ts.map +1 -0
- package/dist/extraction/languages/vbnet.js +141 -0
- package/dist/extraction/languages/vbnet.js.map +1 -0
- package/dist/extraction/mybatis-extractor.d.ts +30 -10
- package/dist/extraction/mybatis-extractor.d.ts.map +1 -1
- package/dist/extraction/mybatis-extractor.js +140 -38
- package/dist/extraction/mybatis-extractor.js.map +1 -1
- package/dist/extraction/parse-pool.d.ts +27 -1
- package/dist/extraction/parse-pool.d.ts.map +1 -1
- package/dist/extraction/parse-pool.js +75 -7
- package/dist/extraction/parse-pool.js.map +1 -1
- package/dist/extraction/parse-worker.js +9 -2
- package/dist/extraction/parse-worker.js.map +1 -1
- package/dist/extraction/store-worker.d.ts +20 -0
- package/dist/extraction/store-worker.d.ts.map +1 -0
- package/dist/extraction/store-worker.js +102 -0
- package/dist/extraction/store-worker.js.map +1 -0
- package/dist/extraction/store-writer.d.ts +48 -0
- package/dist/extraction/store-writer.d.ts.map +1 -0
- package/dist/extraction/store-writer.js +167 -0
- package/dist/extraction/store-writer.js.map +1 -0
- package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
- package/dist/extraction/tree-sitter-helpers.js +1 -0
- package/dist/extraction/tree-sitter-helpers.js.map +1 -1
- package/dist/extraction/tree-sitter-types.d.ts +3 -1
- package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.d.ts +38 -0
- package/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.js +801 -10
- package/dist/extraction/tree-sitter.js.map +1 -1
- package/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
- package/dist/extraction/wasm-runtime-flags.d.ts +14 -4
- package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
- package/dist/extraction/wasm-runtime-flags.js +55 -7
- package/dist/extraction/wasm-runtime-flags.js.map +1 -1
- package/dist/graph/traversal.d.ts.map +1 -1
- package/dist/graph/traversal.js +1 -1
- package/dist/graph/traversal.js.map +1 -1
- package/dist/index.d.ts +74 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +436 -55
- package/dist/index.js.map +1 -1
- package/dist/installer/index.d.ts +42 -0
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +97 -2
- package/dist/installer/index.js.map +1 -1
- package/dist/mcp/daemon.d.ts +25 -3
- package/dist/mcp/daemon.d.ts.map +1 -1
- package/dist/mcp/daemon.js +62 -8
- package/dist/mcp/daemon.js.map +1 -1
- package/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
- package/dist/mcp/dynamic-boundaries.js +2 -1
- package/dist/mcp/dynamic-boundaries.js.map +1 -1
- package/dist/mcp/early-ppid.d.ts +26 -0
- package/dist/mcp/early-ppid.d.ts.map +1 -0
- package/dist/mcp/early-ppid.js +29 -0
- package/dist/mcp/early-ppid.js.map +1 -0
- package/dist/mcp/engine.d.ts +4 -5
- package/dist/mcp/engine.d.ts.map +1 -1
- package/dist/mcp/engine.js +27 -1
- package/dist/mcp/engine.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +41 -6
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/liveness-watchdog.d.ts +18 -1
- package/dist/mcp/liveness-watchdog.d.ts.map +1 -1
- package/dist/mcp/liveness-watchdog.js +73 -13
- package/dist/mcp/liveness-watchdog.js.map +1 -1
- package/dist/mcp/memory-budget.d.ts +30 -0
- package/dist/mcp/memory-budget.d.ts.map +1 -0
- package/dist/mcp/memory-budget.js +123 -0
- package/dist/mcp/memory-budget.js.map +1 -0
- package/dist/mcp/proxy.d.ts.map +1 -1
- package/dist/mcp/proxy.js +88 -4
- package/dist/mcp/proxy.js.map +1 -1
- package/dist/mcp/query-cache.d.ts +35 -4
- package/dist/mcp/query-cache.d.ts.map +1 -1
- package/dist/mcp/query-cache.js +89 -19
- package/dist/mcp/query-cache.js.map +1 -1
- package/dist/mcp/query-pool.d.ts +46 -12
- package/dist/mcp/query-pool.d.ts.map +1 -1
- package/dist/mcp/query-pool.js +100 -23
- package/dist/mcp/query-pool.js.map +1 -1
- package/dist/mcp/query-worker.d.ts +2 -2
- package/dist/mcp/query-worker.js +2 -2
- package/dist/mcp/server-instructions.d.ts +4 -27
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +39 -84
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/session.d.ts +14 -0
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +28 -1
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/startup-handshake.d.ts +44 -0
- package/dist/mcp/startup-handshake.d.ts.map +1 -0
- package/dist/mcp/startup-handshake.js +73 -0
- package/dist/mcp/startup-handshake.js.map +1 -0
- package/dist/mcp/tools.d.ts +104 -4
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +2432 -217
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/transport.d.ts.map +1 -1
- package/dist/mcp/transport.js +18 -0
- package/dist/mcp/transport.js.map +1 -1
- package/dist/project-config.d.ts +38 -0
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +101 -2
- package/dist/project-config.js.map +1 -1
- package/dist/resolution/c-fnptr-synthesizer.d.ts +2 -1
- package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
- package/dist/resolution/c-fnptr-synthesizer.js +178 -146
- package/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
- package/dist/resolution/callback-synthesizer.d.ts +54 -10
- package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/dist/resolution/callback-synthesizer.js +1299 -257
- package/dist/resolution/callback-synthesizer.js.map +1 -1
- package/dist/resolution/cooperative-yield.d.ts +10 -2
- package/dist/resolution/cooperative-yield.d.ts.map +1 -1
- package/dist/resolution/cooperative-yield.js +6 -4
- package/dist/resolution/cooperative-yield.js.map +1 -1
- package/dist/resolution/frameworks/cics.d.ts +20 -0
- package/dist/resolution/frameworks/cics.d.ts.map +1 -0
- package/dist/resolution/frameworks/cics.js +90 -0
- package/dist/resolution/frameworks/cics.js.map +1 -0
- package/dist/resolution/frameworks/go.d.ts.map +1 -1
- package/dist/resolution/frameworks/go.js +29 -6
- package/dist/resolution/frameworks/go.js.map +1 -1
- package/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/dist/resolution/frameworks/index.js +3 -0
- package/dist/resolution/frameworks/index.js.map +1 -1
- package/dist/resolution/frameworks/java.d.ts.map +1 -1
- package/dist/resolution/frameworks/java.js +14 -6
- package/dist/resolution/frameworks/java.js.map +1 -1
- package/dist/resolution/frameworks/terraform.d.ts +38 -0
- package/dist/resolution/frameworks/terraform.d.ts.map +1 -0
- package/dist/resolution/frameworks/terraform.js +277 -0
- package/dist/resolution/frameworks/terraform.js.map +1 -0
- package/dist/resolution/goframe-synthesizer.d.ts +2 -1
- package/dist/resolution/goframe-synthesizer.d.ts.map +1 -1
- package/dist/resolution/goframe-synthesizer.js +8 -3
- package/dist/resolution/goframe-synthesizer.js.map +1 -1
- package/dist/resolution/import-resolver.d.ts +9 -3
- package/dist/resolution/import-resolver.d.ts.map +1 -1
- package/dist/resolution/import-resolver.js +295 -11
- package/dist/resolution/import-resolver.js.map +1 -1
- package/dist/resolution/index.d.ts +146 -8
- package/dist/resolution/index.d.ts.map +1 -1
- package/dist/resolution/index.js +1089 -131
- package/dist/resolution/index.js.map +1 -1
- package/dist/resolution/memory-budget.d.ts +48 -0
- package/dist/resolution/memory-budget.d.ts.map +1 -0
- package/dist/resolution/memory-budget.js +162 -0
- package/dist/resolution/memory-budget.js.map +1 -0
- package/dist/resolution/name-matcher.d.ts +12 -4
- package/dist/resolution/name-matcher.d.ts.map +1 -1
- package/dist/resolution/name-matcher.js +793 -130
- package/dist/resolution/name-matcher.js.map +1 -1
- package/dist/resolution/resolver-pool.d.ts +106 -0
- package/dist/resolution/resolver-pool.d.ts.map +1 -0
- package/dist/resolution/resolver-pool.js +344 -0
- package/dist/resolution/resolver-pool.js.map +1 -0
- package/dist/resolution/resolver-worker.d.ts +17 -0
- package/dist/resolution/resolver-worker.d.ts.map +1 -0
- package/dist/resolution/resolver-worker.js +141 -0
- package/dist/resolution/resolver-worker.js.map +1 -0
- package/dist/resolution/strip-comments.d.ts +1 -1
- package/dist/resolution/strip-comments.d.ts.map +1 -1
- package/dist/resolution/strip-comments.js +49 -0
- package/dist/resolution/strip-comments.js.map +1 -1
- package/dist/resolution/types.d.ts +32 -0
- package/dist/resolution/types.d.ts.map +1 -1
- package/dist/resolution/workspace-packages.d.ts +10 -0
- package/dist/resolution/workspace-packages.d.ts.map +1 -1
- package/dist/resolution/workspace-packages.js +142 -4
- package/dist/resolution/workspace-packages.js.map +1 -1
- package/dist/search/identifier-segments.d.ts +60 -0
- package/dist/search/identifier-segments.d.ts.map +1 -0
- package/dist/search/identifier-segments.js +176 -0
- package/dist/search/identifier-segments.js.map +1 -0
- package/dist/search/query-utils.d.ts +201 -0
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +919 -2
- package/dist/search/query-utils.js.map +1 -1
- package/dist/spec/build/diff-parser.d.ts +55 -0
- package/dist/spec/build/diff-parser.d.ts.map +1 -0
- package/dist/spec/build/diff-parser.js +205 -0
- package/dist/spec/build/diff-parser.js.map +1 -0
- package/dist/spec/build/git-scanner.d.ts +93 -0
- package/dist/spec/build/git-scanner.d.ts.map +1 -0
- package/dist/spec/build/git-scanner.js +254 -0
- package/dist/spec/build/git-scanner.js.map +1 -0
- package/dist/spec/build/pipeline.d.ts +54 -0
- package/dist/spec/build/pipeline.d.ts.map +1 -0
- package/dist/spec/build/pipeline.js +170 -0
- package/dist/spec/build/pipeline.js.map +1 -0
- package/dist/spec/build/scan.d.ts +48 -0
- package/dist/spec/build/scan.d.ts.map +1 -0
- package/dist/spec/build/scan.js +89 -0
- package/dist/spec/build/scan.js.map +1 -0
- package/dist/spec/build/scope-resolver.d.ts +50 -0
- package/dist/spec/build/scope-resolver.d.ts.map +1 -0
- package/dist/spec/build/scope-resolver.js +105 -0
- package/dist/spec/build/scope-resolver.js.map +1 -0
- package/dist/spec/build/spec-extractor.d.ts +74 -0
- package/dist/spec/build/spec-extractor.d.ts.map +1 -0
- package/dist/spec/build/spec-extractor.js +344 -0
- package/dist/spec/build/spec-extractor.js.map +1 -0
- package/dist/spec/config.d.ts +35 -1
- package/dist/spec/config.d.ts.map +1 -1
- package/dist/spec/config.js +30 -5
- package/dist/spec/config.js.map +1 -1
- package/dist/spec/db/fts.d.ts.map +1 -1
- package/dist/spec/db/fts.js +19 -50
- package/dist/spec/db/fts.js.map +1 -1
- package/dist/spec/db/index.d.ts +5 -3
- package/dist/spec/db/index.d.ts.map +1 -1
- package/dist/spec/db/index.js +16 -1
- package/dist/spec/db/index.js.map +1 -1
- package/dist/spec/db/persist.d.ts +45 -0
- package/dist/spec/db/persist.d.ts.map +1 -0
- package/dist/spec/db/persist.js +66 -0
- package/dist/spec/db/persist.js.map +1 -0
- package/dist/spec/db/relations.d.ts +80 -1
- package/dist/spec/db/relations.d.ts.map +1 -1
- package/dist/spec/db/relations.js +175 -4
- package/dist/spec/db/relations.js.map +1 -1
- package/dist/spec/db/schema.d.ts +4 -0
- package/dist/spec/db/schema.d.ts.map +1 -1
- package/dist/spec/db/schema.js +4 -0
- package/dist/spec/db/schema.js.map +1 -1
- package/dist/spec/db/schema.sql +5 -1
- package/dist/spec/db/spec-node.d.ts +5 -0
- package/dist/spec/db/spec-node.d.ts.map +1 -1
- package/dist/spec/db/spec-node.js +11 -5
- package/dist/spec/db/spec-node.js.map +1 -1
- package/dist/spec/db/sql-utils.d.ts +11 -0
- package/dist/spec/db/sql-utils.d.ts.map +1 -0
- package/dist/spec/db/sql-utils.js +19 -0
- package/dist/spec/db/sql-utils.js.map +1 -0
- package/dist/spec/evolve/cluster-context.d.ts +30 -0
- package/dist/spec/evolve/cluster-context.d.ts.map +1 -0
- package/dist/spec/evolve/cluster-context.js +78 -0
- package/dist/spec/evolve/cluster-context.js.map +1 -0
- package/dist/spec/evolve/commit-spec-analyzer.d.ts +51 -0
- package/dist/spec/evolve/commit-spec-analyzer.d.ts.map +1 -0
- package/dist/spec/evolve/commit-spec-analyzer.js +88 -0
- package/dist/spec/evolve/commit-spec-analyzer.js.map +1 -0
- package/dist/spec/evolve/commit-spec-persister.d.ts +53 -0
- package/dist/spec/evolve/commit-spec-persister.d.ts.map +1 -0
- package/dist/spec/evolve/commit-spec-persister.js +93 -0
- package/dist/spec/evolve/commit-spec-persister.js.map +1 -0
- package/dist/spec/evolve/impact-locator.d.ts +23 -7
- package/dist/spec/evolve/impact-locator.d.ts.map +1 -1
- package/dist/spec/evolve/impact-locator.js +58 -14
- package/dist/spec/evolve/impact-locator.js.map +1 -1
- package/dist/spec/evolve/pipeline.d.ts +62 -25
- package/dist/spec/evolve/pipeline.d.ts.map +1 -1
- package/dist/spec/evolve/pipeline.js +436 -457
- package/dist/spec/evolve/pipeline.js.map +1 -1
- package/dist/spec/evolve/spec-rewriter.d.ts +13 -13
- package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -1
- package/dist/spec/evolve/spec-rewriter.js +45 -45
- package/dist/spec/evolve/spec-rewriter.js.map +1 -1
- package/dist/spec/git/commits.d.ts +85 -0
- package/dist/spec/git/commits.d.ts.map +1 -0
- package/dist/spec/git/commits.js +218 -0
- package/dist/spec/git/commits.js.map +1 -0
- package/dist/spec/git/exec.d.ts +13 -0
- package/dist/spec/git/exec.d.ts.map +1 -0
- package/dist/spec/git/exec.js +19 -0
- package/dist/spec/git/exec.js.map +1 -0
- package/dist/spec/git/index.d.ts +9 -0
- package/dist/spec/git/index.d.ts.map +1 -0
- package/dist/spec/git/index.js +22 -0
- package/dist/spec/git/index.js.map +1 -0
- package/dist/spec/git-utils.d.ts +8 -0
- package/dist/spec/git-utils.d.ts.map +1 -0
- package/dist/spec/git-utils.js +14 -0
- package/dist/spec/git-utils.js.map +1 -0
- package/dist/spec/graph/index.d.ts +8 -0
- package/dist/spec/graph/index.d.ts.map +1 -0
- package/dist/spec/graph/index.js +17 -0
- package/dist/spec/graph/index.js.map +1 -0
- package/dist/spec/graph/queries.d.ts +6 -35
- package/dist/spec/graph/queries.d.ts.map +1 -1
- package/dist/spec/graph/queries.js +71 -248
- package/dist/spec/graph/queries.js.map +1 -1
- package/dist/spec/llm/agent-client.d.ts +59 -0
- package/dist/spec/llm/agent-client.d.ts.map +1 -0
- package/dist/spec/llm/agent-client.js +213 -0
- package/dist/spec/llm/agent-client.js.map +1 -0
- package/dist/spec/llm/agents/claude-code.d.ts +32 -0
- package/dist/spec/llm/agents/claude-code.d.ts.map +1 -0
- package/dist/spec/llm/agents/claude-code.js +125 -0
- package/dist/spec/llm/agents/claude-code.js.map +1 -0
- package/dist/spec/llm/agents/codex.d.ts +32 -0
- package/dist/spec/llm/agents/codex.d.ts.map +1 -0
- package/dist/spec/llm/agents/codex.js +145 -0
- package/dist/spec/llm/agents/codex.js.map +1 -0
- package/dist/spec/llm/agents/detect-utils.d.ts +28 -0
- package/dist/spec/llm/agents/detect-utils.d.ts.map +1 -0
- package/dist/spec/llm/agents/detect-utils.js +91 -0
- package/dist/spec/llm/agents/detect-utils.js.map +1 -0
- package/dist/spec/llm/agents/deveco-code.d.ts +33 -0
- package/dist/spec/llm/agents/deveco-code.d.ts.map +1 -0
- package/dist/spec/llm/agents/deveco-code.js +165 -0
- package/dist/spec/llm/agents/deveco-code.js.map +1 -0
- package/dist/spec/llm/agents/index.d.ts +31 -0
- package/dist/spec/llm/agents/index.d.ts.map +1 -0
- package/dist/spec/llm/agents/index.js +65 -0
- package/dist/spec/llm/agents/index.js.map +1 -0
- package/dist/spec/llm/agents/types.d.ts +76 -0
- package/dist/spec/llm/agents/types.d.ts.map +1 -0
- package/dist/spec/llm/agents/types.js +15 -0
- package/dist/spec/llm/agents/types.js.map +1 -0
- package/dist/spec/llm/client.d.ts +31 -11
- package/dist/spec/llm/client.d.ts.map +1 -1
- package/dist/spec/llm/client.js +143 -81
- package/dist/spec/llm/client.js.map +1 -1
- package/dist/spec/llm/factory.d.ts +41 -0
- package/dist/spec/llm/factory.d.ts.map +1 -0
- package/dist/spec/llm/factory.js +80 -0
- package/dist/spec/llm/factory.js.map +1 -0
- package/dist/spec/llm/prompts.d.ts +24 -8
- package/dist/spec/llm/prompts.d.ts.map +1 -1
- package/dist/spec/llm/prompts.js +100 -50
- package/dist/spec/llm/prompts.js.map +1 -1
- package/dist/spec/llm/retry.d.ts +53 -0
- package/dist/spec/llm/retry.d.ts.map +1 -0
- package/dist/spec/llm/retry.js +153 -0
- package/dist/spec/llm/retry.js.map +1 -0
- package/dist/spec/mine/clusterer.d.ts +63 -0
- package/dist/spec/mine/clusterer.d.ts.map +1 -0
- package/dist/spec/mine/clusterer.js +904 -0
- package/dist/spec/mine/clusterer.js.map +1 -0
- package/dist/spec/mine/clustering/features.d.ts +38 -0
- package/dist/spec/mine/clustering/features.d.ts.map +1 -0
- package/dist/spec/mine/clustering/features.js +108 -0
- package/dist/spec/mine/clustering/features.js.map +1 -0
- package/dist/spec/mine/clustering/index.d.ts +62 -0
- package/dist/spec/mine/clustering/index.d.ts.map +1 -0
- package/dist/spec/mine/clustering/index.js +259 -0
- package/dist/spec/mine/clustering/index.js.map +1 -0
- package/dist/spec/mine/clustering/leiden.d.ts +61 -0
- package/dist/spec/mine/clustering/leiden.d.ts.map +1 -0
- package/dist/spec/mine/clustering/leiden.js +489 -0
- package/dist/spec/mine/clustering/leiden.js.map +1 -0
- package/dist/spec/mine/clustering/text-similarity.d.ts +22 -0
- package/dist/spec/mine/clustering/text-similarity.d.ts.map +1 -0
- package/dist/spec/mine/clustering/text-similarity.js +98 -0
- package/dist/spec/mine/clustering/text-similarity.js.map +1 -0
- package/dist/spec/mine/generator.d.ts +54 -0
- package/dist/spec/mine/generator.d.ts.map +1 -0
- package/dist/spec/mine/generator.js +267 -0
- package/dist/spec/mine/generator.js.map +1 -0
- package/dist/spec/mine/persist.d.ts +37 -0
- package/dist/spec/mine/persist.d.ts.map +1 -0
- package/dist/spec/mine/persist.js +170 -0
- package/dist/spec/mine/persist.js.map +1 -0
- package/dist/spec/mine/pipeline.d.ts +41 -0
- package/dist/spec/mine/pipeline.d.ts.map +1 -0
- package/dist/spec/mine/pipeline.js +236 -0
- package/dist/spec/mine/pipeline.js.map +1 -0
- package/dist/spec/mine/progress-handler.d.ts +22 -0
- package/dist/spec/mine/progress-handler.d.ts.map +1 -0
- package/dist/spec/mine/progress-handler.js +108 -0
- package/dist/spec/mine/progress-handler.js.map +1 -0
- package/dist/spec/mine/progress.d.ts +23 -0
- package/dist/spec/mine/progress.d.ts.map +1 -0
- package/dist/spec/mine/progress.js +12 -0
- package/dist/spec/mine/progress.js.map +1 -0
- package/dist/spec/mine/scanner.d.ts +59 -0
- package/dist/spec/mine/scanner.d.ts.map +1 -0
- package/dist/spec/mine/scanner.js +383 -0
- package/dist/spec/mine/scanner.js.map +1 -0
- package/dist/spec/types.d.ts +32 -0
- package/dist/spec/types.d.ts.map +1 -1
- package/dist/spec/ui/index.d.ts +9 -0
- package/dist/spec/ui/index.d.ts.map +1 -0
- package/dist/spec/ui/index.js +16 -0
- package/dist/spec/ui/index.js.map +1 -0
- package/dist/spec/ui/progress-handler.d.ts +33 -0
- package/dist/spec/ui/progress-handler.d.ts.map +1 -0
- package/dist/spec/ui/progress-handler.js +132 -0
- package/dist/spec/ui/progress-handler.js.map +1 -0
- package/dist/spec/ui/progress.d.ts +24 -0
- package/dist/spec/ui/progress.d.ts.map +1 -0
- package/dist/spec/ui/progress.js +13 -0
- package/dist/spec/ui/progress.js.map +1 -0
- package/dist/spec/utils/fs.d.ts +45 -0
- package/dist/spec/utils/fs.d.ts.map +1 -0
- package/dist/spec/utils/fs.js +163 -0
- package/dist/spec/utils/fs.js.map +1 -0
- package/dist/spec/utils/index.d.ts +12 -0
- package/dist/spec/utils/index.d.ts.map +1 -0
- package/dist/spec/utils/index.js +26 -0
- package/dist/spec/utils/index.js.map +1 -0
- package/dist/spec/utils/meta.d.ts +32 -0
- package/dist/spec/utils/meta.d.ts.map +1 -0
- package/dist/spec/utils/meta.js +122 -0
- package/dist/spec/utils/meta.js.map +1 -0
- package/dist/spec/utils/truncate.d.ts +86 -0
- package/dist/spec/utils/truncate.d.ts.map +1 -0
- package/dist/spec/utils/truncate.js +172 -0
- package/dist/spec/utils/truncate.js.map +1 -0
- package/dist/spec/utils.d.ts +4 -16
- package/dist/spec/utils.d.ts.map +1 -1
- package/dist/spec/utils.js +6 -58
- package/dist/spec/utils.js.map +1 -1
- package/dist/sync/git-hooks.d.ts.map +1 -1
- package/dist/sync/git-hooks.js +2 -0
- package/dist/sync/git-hooks.js.map +1 -1
- package/dist/sync/watcher.d.ts +35 -6
- package/dist/sync/watcher.d.ts.map +1 -1
- package/dist/sync/watcher.js +127 -17
- package/dist/sync/watcher.js.map +1 -1
- package/dist/sync/worktree.d.ts.map +1 -1
- package/dist/sync/worktree.js +5 -0
- package/dist/sync/worktree.js.map +1 -1
- package/dist/telemetry/index.js +3 -3
- package/dist/telemetry/index.js.map +1 -1
- package/dist/types.d.ts +22 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -1
- package/dist/upgrade/index.d.ts +32 -0
- package/dist/upgrade/index.d.ts.map +1 -1
- package/dist/upgrade/index.js +162 -14
- package/dist/upgrade/index.js.map +1 -1
- package/dist/upgrade/remove-binary.d.ts +87 -0
- package/dist/upgrade/remove-binary.d.ts.map +1 -0
- package/dist/upgrade/remove-binary.js +289 -0
- package/dist/upgrade/remove-binary.js.map +1 -0
- package/dist/upgrade/update-check.d.ts +92 -0
- package/dist/upgrade/update-check.d.ts.map +1 -0
- package/dist/upgrade/update-check.js +258 -0
- package/dist/upgrade/update-check.js.map +1 -0
- package/package.json +6 -2
- package/scripts/agent-eval/run-all.sh +6 -0
- package/scripts/build-bundle.sh +5 -0
- package/scripts/npm-shim.js +8 -1
- package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/data/agents.json +0 -109
- package/scripts/exp_boundary_eval/data/experiments.json +0 -140
- package/scripts/qa_eval/README.md +0 -407
- package/scripts/qa_eval/_test_deveco_probe.py +0 -41
- package/scripts/qa_eval/agent_runner.py +0 -526
- package/scripts/qa_eval/data/.gitignore +0 -4
- package/scripts/qa_eval/data/test-set.jsonl +0 -2
- package/scripts/qa_eval/eval_metrics.py +0 -274
- package/scripts/qa_eval/external_agent.py +0 -976
- package/scripts/qa_eval/llm_config.py +0 -92
- package/scripts/qa_eval/memory_monitor.py +0 -132
- package/scripts/qa_eval/my_answer_accuracy.py +0 -187
- package/scripts/qa_eval/requirements.txt +0 -2
- package/scripts/qa_eval/run_pipeline.py +0 -804
- package/scripts/qa_eval/stats_efficiency.py +0 -279
- package/scripts/qa_eval/stats_scores.py +0 -207
|
@@ -33,535 +33,514 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
36
|
+
exports.runEvolvePipeline = runEvolvePipeline;
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
38
|
+
* Batch spec evolve pipeline — replaces the old per-commit approach with
|
|
39
|
+
* a unified batch pipeline optimised for the post-commit hook's cumulative
|
|
40
|
+
* commit threshold trigger.
|
|
40
41
|
*
|
|
41
|
-
*
|
|
42
|
+
* Flow:
|
|
43
|
+
* 0. Prep (meta, lock, schema, discover specs)
|
|
44
|
+
* 1a. Batch analysis (scope + metadata + diff, no DB writes)
|
|
45
|
+
* 1b. Per-commit persistence (independent transactions)
|
|
46
|
+
* 2. Impact location (find old specs affected by new commits)
|
|
47
|
+
* 3. LLM evaluation per spec cluster (only if LLM configured)
|
|
48
|
+
* ↓ or: mine-style fallback (if phase 1 produced zero matches)
|
|
49
|
+
* 4. Advance meta.json to last phase-1 success
|
|
42
50
|
*
|
|
43
51
|
* @module spec/evolve/pipeline
|
|
44
52
|
*/
|
|
45
53
|
const path = __importStar(require("path"));
|
|
46
54
|
const fs = __importStar(require("fs"));
|
|
47
|
-
const child_process_1 = require("child_process");
|
|
48
55
|
const config_1 = require("../config");
|
|
49
56
|
const utils_1 = require("../utils");
|
|
50
57
|
const schema_1 = require("../db/schema");
|
|
51
58
|
const spec_node_1 = require("../db/spec-node");
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const scope_resolver_1 = require("../mining/scope-resolver");
|
|
57
|
-
const spec_extractor_1 = require("../mining/spec-extractor");
|
|
58
|
-
const diff_parser_1 = require("../mining/diff-parser");
|
|
59
|
-
const client_1 = require("../llm/client");
|
|
60
|
-
const logic_checker_1 = require("./logic-checker");
|
|
59
|
+
const git_1 = require("../git");
|
|
60
|
+
const factory_1 = require("../llm/factory");
|
|
61
|
+
const commit_spec_analyzer_1 = require("./commit-spec-analyzer");
|
|
62
|
+
const commit_spec_persister_1 = require("./commit-spec-persister");
|
|
61
63
|
const impact_locator_1 = require("./impact-locator");
|
|
64
|
+
const cluster_context_1 = require("./cluster-context");
|
|
62
65
|
const spec_rewriter_1 = require("./spec-rewriter");
|
|
66
|
+
const pipeline_1 = require("../mine/pipeline");
|
|
63
67
|
const errors_1 = require("../../errors");
|
|
68
|
+
const utils_2 = require("../utils");
|
|
69
|
+
// =============================================================================
|
|
70
|
+
// Constants
|
|
71
|
+
// =============================================================================
|
|
72
|
+
const LOCK_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
64
73
|
// =============================================================================
|
|
65
74
|
// Helpers
|
|
66
75
|
// =============================================================================
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const node = (0, spec_node_1.findSpecById)(db, specId);
|
|
73
|
-
if (node) {
|
|
74
|
-
return { version: node.version, filePath: node.filePath };
|
|
76
|
+
/** Resolve HEAD hash (throws when it cannot be resolved). */
|
|
77
|
+
function resolveHead(repoPath) {
|
|
78
|
+
const head = (0, git_1.getHeadHash)(repoPath);
|
|
79
|
+
if (!head) {
|
|
80
|
+
throw new Error('Failed to resolve HEAD. Not a valid git repository?');
|
|
75
81
|
}
|
|
76
|
-
return
|
|
82
|
+
return head;
|
|
77
83
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
* specs and evaluate each one.
|
|
95
|
-
* 5. If neither Path A nor Path B produced candidates, return early.
|
|
96
|
-
* 6. Persist everything in a single DB transaction.
|
|
97
|
-
*
|
|
98
|
-
* @param repoPath - Absolute path to the git repository.
|
|
99
|
-
* @param db - Active SQLite database handle (schema already initialised).
|
|
100
|
-
* @param specStoragePath - Path to the spec storage directory (from meta.json).
|
|
101
|
-
* @param commitHash - Commit hash to process.
|
|
102
|
-
* @param llmConfig - Optional LLM config override; falls back to spec config.
|
|
103
|
-
*/
|
|
104
|
-
async function runEvolvePipeline(repoPath, db, specStoragePath, commitHash, llmConfig) {
|
|
105
|
-
// ------------------------------------------------------------------
|
|
106
|
-
// 1. Context loading
|
|
107
|
-
// ------------------------------------------------------------------
|
|
108
|
-
// meta.json and schema already handled by runBatchEvolvePipeline
|
|
109
|
-
// Resolve commit hash
|
|
110
|
-
const resolvedHash = commitHash ||
|
|
111
|
-
(() => {
|
|
112
|
-
try {
|
|
113
|
-
return (0, child_process_1.execFileSync)('git', ['rev-parse', 'HEAD'], {
|
|
114
|
-
cwd: repoPath,
|
|
115
|
-
encoding: 'utf8',
|
|
116
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
117
|
-
windowsHide: true,
|
|
118
|
-
}).trim();
|
|
84
|
+
/** Validate that lastEvolved is an ancestor of HEAD (detect rebase). */
|
|
85
|
+
function validateAncestry(repoPath, lastEvolved, headHash) {
|
|
86
|
+
if (!(0, git_1.isAncestor)(repoPath, lastEvolved, headHash)) {
|
|
87
|
+
throw new Error(`The last evolved commit (${lastEvolved.slice(0, 7)}) is not an ancestor of ` +
|
|
88
|
+
`HEAD (${headHash.slice(0, 7)}). This usually happens after a rebase ` +
|
|
89
|
+
`or force-push. Please re-run 'homegraph spec build' to rebuild the ` +
|
|
90
|
+
`knowledge graph, then run evolve again.`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Acquire a file-based advisory lock. */
|
|
94
|
+
function acquireEvolveLock(lockFile) {
|
|
95
|
+
try {
|
|
96
|
+
if (fs.existsSync(lockFile)) {
|
|
97
|
+
const stat = fs.statSync(lockFile);
|
|
98
|
+
if (Date.now() - stat.mtimeMs > LOCK_TIMEOUT_MS) {
|
|
99
|
+
fs.unlinkSync(lockFile);
|
|
119
100
|
}
|
|
120
|
-
|
|
121
|
-
return
|
|
101
|
+
else {
|
|
102
|
+
return false;
|
|
122
103
|
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
// Get commit info and diff
|
|
128
|
-
const commitInfo = (0, git_scanner_1.getCommitInfo)(repoPath, resolvedHash);
|
|
129
|
-
if (!commitInfo) {
|
|
130
|
-
throw new Error(`Commit ${resolvedHash} not found in repository.`);
|
|
131
|
-
}
|
|
132
|
-
const diff = (0, git_scanner_1.getCommitDiff)(repoPath, resolvedHash);
|
|
133
|
-
// Parse diff into fragments once — reused for file paths and persistence.
|
|
134
|
-
const diffFragments = (0, diff_parser_1.analyzeCommitDiff)(repoPath, resolvedHash, diff);
|
|
135
|
-
// Load spec config and optionally create LLM client.
|
|
136
|
-
// When LLM is not available we still run Path A (scope-based GENERATE).
|
|
137
|
-
const specConfig = (0, config_1.loadSpecConfig)(repoPath);
|
|
138
|
-
const resolvedLLMConfig = llmConfig || specConfig.llm;
|
|
139
|
-
const client = resolvedLLMConfig
|
|
140
|
-
? new client_1.OpenAiLlmClient(resolvedLLMConfig)
|
|
141
|
-
: undefined;
|
|
142
|
-
// ------------------------------------------------------------------
|
|
143
|
-
// 2. Path A (GENERATE) — commit message scope resolution
|
|
144
|
-
// ------------------------------------------------------------------
|
|
145
|
-
const pathASpecId = (0, scope_resolver_1.resolveScopeToSpec)(commitInfo.message, specStoragePath, specConfig);
|
|
146
|
-
let pathASpecMetadata = null;
|
|
147
|
-
if (pathASpecId) {
|
|
148
|
-
pathASpecMetadata = (0, spec_extractor_1.extractSpecMetadata)(specStoragePath, pathASpecId, specConfig);
|
|
104
|
+
}
|
|
105
|
+
fs.writeFileSync(lockFile, String(process.pid));
|
|
106
|
+
return true;
|
|
149
107
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// Non-Path-A commits cannot be processed without LLM for logic
|
|
153
|
-
// checking and spec evaluation.
|
|
154
|
-
// ------------------------------------------------------------------
|
|
155
|
-
if (!pathASpecId && !client) {
|
|
156
|
-
(0, errors_1.logWarn)('Skipping commit — no LLM configured and commit does not match Path A', {
|
|
157
|
-
commitHash: resolvedHash.slice(0, 7),
|
|
158
|
-
});
|
|
159
|
-
return {
|
|
160
|
-
commitHash: resolvedHash,
|
|
161
|
-
generateRelationCreated: false,
|
|
162
|
-
isLogicChange: false,
|
|
163
|
-
logicCheckReason: '',
|
|
164
|
-
affectedSpecCount: 0,
|
|
165
|
-
evolvedSpecs: [],
|
|
166
|
-
fragmentsCount: 0,
|
|
167
|
-
relationsCreated: 0,
|
|
168
|
-
persisted: false,
|
|
169
|
-
skipped: true,
|
|
170
|
-
skipReason: 'LLM not configured — commit message does not contain a spec scope (Path A)',
|
|
171
|
-
};
|
|
108
|
+
catch {
|
|
109
|
+
return false;
|
|
172
110
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
111
|
+
}
|
|
112
|
+
/** Build an empty BatchEvolveResult for no-op runs. */
|
|
113
|
+
function emptyBatchResult(fromCommit, toCommit, commitsScanned) {
|
|
114
|
+
return {
|
|
115
|
+
fromCommit,
|
|
116
|
+
toCommit,
|
|
117
|
+
commitsScanned,
|
|
118
|
+
phaseOneMatched: 0,
|
|
119
|
+
phaseOneSkipped: 0,
|
|
120
|
+
phaseOneFailures: 0,
|
|
121
|
+
historicalSpecsEvaluated: 0,
|
|
122
|
+
specsUpdated: 0,
|
|
123
|
+
specsDeprecated: 0,
|
|
124
|
+
specsUnchanged: 0,
|
|
125
|
+
perCommitResults: [],
|
|
126
|
+
metaUpdated: false,
|
|
127
|
+
skipped: false,
|
|
128
|
+
mineFallback: false,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function runPhaseOne(repoPath, db, specStoragePath, commits, config) {
|
|
132
|
+
// ---- Stage 1a: Batch analysis ----
|
|
133
|
+
const analyses = (0, commit_spec_analyzer_1.analyzeIncrementalCommits)(repoPath, specStoragePath, commits, config);
|
|
134
|
+
// ---- Stage 1b: Per-commit persistence ----
|
|
135
|
+
const phaseOneResults = new Map();
|
|
136
|
+
const phaseOneSpecIds = new Set();
|
|
137
|
+
const commitFilePaths = new Map();
|
|
138
|
+
let lastPhaseOneSuccess = null;
|
|
139
|
+
for (const analysis of analyses) {
|
|
140
|
+
if (!analysis.matched) {
|
|
141
|
+
phaseOneResults.set(analysis.commit.hash, {
|
|
142
|
+
skipped: true,
|
|
143
|
+
reason: analysis.skipReason ?? 'Scope not matched',
|
|
144
|
+
});
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
178
147
|
try {
|
|
179
|
-
|
|
148
|
+
const result = (0, commit_spec_persister_1.persistCommitSpecGraph)(db, analysis);
|
|
149
|
+
phaseOneResults.set(analysis.commit.hash, result);
|
|
150
|
+
phaseOneSpecIds.add(result.specId);
|
|
151
|
+
commitFilePaths.set(analysis.commit.hash, result.filePaths);
|
|
152
|
+
lastPhaseOneSuccess = analysis.commit.hash;
|
|
180
153
|
}
|
|
181
154
|
catch {
|
|
182
|
-
|
|
183
|
-
|
|
155
|
+
// Persistence failed — stop advancing but don't roll back prior commits
|
|
156
|
+
phaseOneResults.set(analysis.commit.hash, {
|
|
157
|
+
skipped: true,
|
|
158
|
+
reason: 'Persistence transaction failed',
|
|
184
159
|
});
|
|
185
|
-
|
|
160
|
+
break;
|
|
186
161
|
}
|
|
187
162
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const activeRows = db
|
|
201
|
-
.prepare(`SELECT id FROM spec_nodes WHERE status = 'active' AND id IN (${placeholders})`)
|
|
202
|
-
.all(...affectedSpecIds);
|
|
203
|
-
pathBSpecIds = activeRows.map((r) => r.id);
|
|
204
|
-
// Remove Path A spec from Path B list (if present)
|
|
205
|
-
if (pathASpecId) {
|
|
206
|
-
pathBSpecIds = pathBSpecIds.filter((id) => id !== pathASpecId);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
(0, errors_1.logDebug)('Path B: affected active specs', {
|
|
210
|
-
count: pathBSpecIds.length,
|
|
211
|
-
specIds: pathBSpecIds,
|
|
212
|
-
});
|
|
163
|
+
return { phaseOneResults, phaseOneSpecIds, commitFilePaths, lastPhaseOneSuccess, analyses };
|
|
164
|
+
}
|
|
165
|
+
// =============================================================================
|
|
166
|
+
// processSingleCommit — fallback for first-ever evolve (no meta.json anchor)
|
|
167
|
+
// =============================================================================
|
|
168
|
+
async function processSingleCommit(repoPath, db, specStoragePath, headHash, config) {
|
|
169
|
+
(0, errors_1.logDebug)('runEvolvePipeline: no currentCommitID in meta.json — processing HEAD only', {
|
|
170
|
+
headHash: headHash.slice(0, 7),
|
|
171
|
+
});
|
|
172
|
+
const info = (0, git_1.getCommitInfo)(repoPath, headHash);
|
|
173
|
+
if (!info) {
|
|
174
|
+
throw new Error(`Commit ${headHash.slice(0, 7)} not found.`);
|
|
213
175
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const hasPathB = pathBSpecIds.length > 0;
|
|
219
|
-
if (!hasPathA && !hasPathB) {
|
|
220
|
-
(0, errors_1.logDebug)('runEvolvePipeline: no relevant spec found, returning early', {
|
|
221
|
-
commitHash: resolvedHash.slice(0, 7),
|
|
222
|
-
});
|
|
223
|
-
return {
|
|
224
|
-
commitHash: resolvedHash,
|
|
225
|
-
generateRelationCreated: false,
|
|
226
|
-
isLogicChange: logicResult.isLogic,
|
|
227
|
-
logicCheckReason: logicResult.reason,
|
|
228
|
-
affectedSpecCount: 0,
|
|
229
|
-
evolvedSpecs: [],
|
|
230
|
-
fragmentsCount: 0,
|
|
231
|
-
relationsCreated: 0,
|
|
232
|
-
persisted: false,
|
|
233
|
-
skipped: false,
|
|
234
|
-
};
|
|
176
|
+
const { phaseOneResults, phaseOneSpecIds, commitFilePaths, lastPhaseOneSuccess, analyses } = runPhaseOne(repoPath, db, specStoragePath, [info], config);
|
|
177
|
+
const metaUpdated = !!(lastPhaseOneSuccess);
|
|
178
|
+
if (metaUpdated) {
|
|
179
|
+
(0, utils_1.writeMeta)(repoPath, specStoragePath, lastPhaseOneSuccess);
|
|
235
180
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const { version, filePath } = getSpecPathInfo(db, specStoragePath, specId);
|
|
241
|
-
const decision = await (0, spec_rewriter_1.evaluateSpec)(specId, specStoragePath, filePath, commitInfo.message, diff, scheduleNextSpecs, client);
|
|
242
|
-
pendingDecisions.push({ specId, decision, version, filePath });
|
|
181
|
+
// Phase 2 — only if phase 1 matched something
|
|
182
|
+
let affectedEntries = [];
|
|
183
|
+
if (phaseOneSpecIds.size > 0) {
|
|
184
|
+
affectedEntries = (0, impact_locator_1.locateAffectedSpecsWithCommits)(db, commitFilePaths, phaseOneSpecIds);
|
|
243
185
|
}
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
186
|
+
// Phase 3
|
|
187
|
+
const client = (0, factory_1.createSpecLlmClient)(config.llm);
|
|
188
|
+
const evolvedSpecsByCommit = await evaluateAndApply(db, repoPath, affectedEntries, phaseOneResults, client);
|
|
189
|
+
return buildBatchResult({
|
|
190
|
+
fromCommit: null,
|
|
191
|
+
toCommit: headHash,
|
|
192
|
+
commitsScanned: 1,
|
|
193
|
+
analyses,
|
|
194
|
+
phaseOneResults,
|
|
195
|
+
affectedEntries,
|
|
196
|
+
evolvedSpecs: evolvedSpecsByCommit,
|
|
197
|
+
metaUpdated,
|
|
198
|
+
mineFallback: false,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// =============================================================================
|
|
202
|
+
// evaluateAndApply — phase 3: evaluate each affected spec + apply decisions
|
|
203
|
+
// =============================================================================
|
|
204
|
+
async function evaluateAndApply(db, repoPath, affectedEntries, phaseOneResults, client) {
|
|
205
|
+
const evolvedSpecsByCommit = new Map();
|
|
206
|
+
if (!client || affectedEntries.length === 0) {
|
|
207
|
+
return evolvedSpecsByCommit;
|
|
208
|
+
}
|
|
209
|
+
for (const entry of affectedEntries) {
|
|
210
|
+
// Get spec info from DB
|
|
211
|
+
const specNode = (0, spec_node_1.findSpecById)(db, entry.specId);
|
|
212
|
+
if (!specNode)
|
|
213
|
+
continue;
|
|
214
|
+
// Collect affecting PersistResults
|
|
215
|
+
const affectingResults = entry.affectingCommits
|
|
216
|
+
.map((h) => phaseOneResults.get(h))
|
|
217
|
+
.filter((r) => r !== undefined && 'filePaths' in r);
|
|
218
|
+
if (affectingResults.length === 0)
|
|
219
|
+
continue;
|
|
220
|
+
// Build CommitContextInput list
|
|
221
|
+
const commitInputs = [];
|
|
222
|
+
for (const pr of affectingResults) {
|
|
223
|
+
let message = pr.commitHash.slice(0, 7);
|
|
224
|
+
try {
|
|
225
|
+
const info = (0, git_1.getCommitInfo)(repoPath, pr.commitHash);
|
|
226
|
+
if (info)
|
|
227
|
+
message = info.message;
|
|
228
|
+
}
|
|
229
|
+
catch { /* use short hash */ }
|
|
230
|
+
commitInputs.push({
|
|
231
|
+
commitHash: pr.commitHash,
|
|
232
|
+
message,
|
|
233
|
+
filePaths: pr.filePaths,
|
|
280
234
|
});
|
|
281
|
-
(0, relations_1.insertSpecCommitRelation)(db, pathASpecMetadata.specId, commitInfo.hash, 'GENERATE');
|
|
282
|
-
evolveResult.generateRelationCreated = true;
|
|
283
|
-
evolveResult.relationsCreated++;
|
|
284
235
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
236
|
+
// Build cluster context
|
|
237
|
+
const clusterCtx = (0, cluster_context_1.buildClusterContext)(commitInputs);
|
|
238
|
+
// Populate actual diffs into cluster context
|
|
239
|
+
for (const cs of clusterCtx.commitSummaries) {
|
|
240
|
+
try {
|
|
241
|
+
const diff = (0, git_1.getCommitDiff)(repoPath, cs.fullHash);
|
|
242
|
+
cs.truncatedDiff = (0, utils_2.truncateText)(diff, 16000);
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
cs.truncatedDiff = '(diff unavailable)';
|
|
246
|
+
}
|
|
289
247
|
}
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
248
|
+
// LLM evaluation (outside transaction)
|
|
249
|
+
let decision;
|
|
250
|
+
try {
|
|
251
|
+
decision = await (0, spec_rewriter_1.evaluateSpecWithCluster)(entry.specId, specNode.filePath, clusterCtx, client);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
decision = { action: 'UNCHANGED' };
|
|
255
|
+
}
|
|
256
|
+
// The last commit in affectingCommits is the one that triggered this evaluation.
|
|
257
|
+
const lastAffectingCommit = entry.affectingCommits[entry.affectingCommits.length - 1];
|
|
258
|
+
// Apply decision (inside transaction)
|
|
259
|
+
db.exec('BEGIN');
|
|
260
|
+
try {
|
|
294
261
|
if (decision.action === 'UPDATE') {
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
specId,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
262
|
+
const result = (0, spec_rewriter_1.applyUpdate)(db, entry.specId, specNode.filePath, specNode.version, decision, lastAffectingCommit);
|
|
263
|
+
const evolved = {
|
|
264
|
+
specId: entry.specId, action: 'UPDATE',
|
|
265
|
+
newVersion: result.newVersion, newSpecId: result.newSpecId,
|
|
266
|
+
};
|
|
267
|
+
if (!evolvedSpecsByCommit.has(lastAffectingCommit)) {
|
|
268
|
+
evolvedSpecsByCommit.set(lastAffectingCommit, []);
|
|
269
|
+
}
|
|
270
|
+
evolvedSpecsByCommit.get(lastAffectingCommit).push(evolved);
|
|
303
271
|
}
|
|
304
272
|
else if (decision.action === 'DEPRECATE') {
|
|
305
|
-
(0, spec_rewriter_1.applyDeprecate)(db, specId);
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
evolveResult.relationsCreated += 1;
|
|
273
|
+
(0, spec_rewriter_1.applyDeprecate)(db, entry.specId);
|
|
274
|
+
const evolved = { specId: entry.specId, action: 'DEPRECATE' };
|
|
275
|
+
if (!evolvedSpecsByCommit.has(lastAffectingCommit)) {
|
|
276
|
+
evolvedSpecsByCommit.set(lastAffectingCommit, []);
|
|
277
|
+
}
|
|
278
|
+
evolvedSpecsByCommit.get(lastAffectingCommit).push(evolved);
|
|
312
279
|
}
|
|
313
280
|
else {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
281
|
+
const evolved = { specId: entry.specId, action: 'UNCHANGED' };
|
|
282
|
+
if (!evolvedSpecsByCommit.has(lastAffectingCommit)) {
|
|
283
|
+
evolvedSpecsByCommit.set(lastAffectingCommit, []);
|
|
284
|
+
}
|
|
285
|
+
evolvedSpecsByCommit.get(lastAffectingCommit).push(evolved);
|
|
319
286
|
}
|
|
287
|
+
db.exec('COMMIT');
|
|
288
|
+
}
|
|
289
|
+
catch (e) {
|
|
290
|
+
db.exec('ROLLBACK');
|
|
291
|
+
(0, errors_1.logWarn)('evaluateAndApply: apply failed', {
|
|
292
|
+
specId: entry.specId,
|
|
293
|
+
error: e instanceof Error ? e.message : String(e),
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return evolvedSpecsByCommit;
|
|
298
|
+
}
|
|
299
|
+
// =============================================================================
|
|
300
|
+
// mineStyleFallback
|
|
301
|
+
// =============================================================================
|
|
302
|
+
async function mineStyleFallback(repoPath, db, specStoragePath, newCommits, lastEvolved, headHash, llmConfig) {
|
|
303
|
+
const client = (0, factory_1.createSpecLlmClient)(llmConfig ?? null);
|
|
304
|
+
if (!client) {
|
|
305
|
+
(0, errors_1.logWarn)('Phase 1 produced no spec matches and no LLM is available ' +
|
|
306
|
+
'(no coding agent detected, no LLM configured). ' +
|
|
307
|
+
'No evolution can be performed. ' +
|
|
308
|
+
'Consider running "homegraph spec build/mine" first, ' +
|
|
309
|
+
'or configure an LLM in .homegraph/commit4spec/configs.json.');
|
|
310
|
+
return {
|
|
311
|
+
...emptyBatchResult(lastEvolved, headHash, newCommits.length),
|
|
312
|
+
phaseOneSkipped: newCommits.length,
|
|
313
|
+
skipped: true,
|
|
314
|
+
skipReason: 'Phase 1 produced no matches and no LLM available (no coding agent detected, no LLM configured)',
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
// Invoke mine pipeline for the unmatched commit range
|
|
318
|
+
(0, errors_1.logWarn)('Phase 1 produced no spec matches. Falling back to mine-style spec generation ' +
|
|
319
|
+
`for ${newCommits.length} commit(s).`);
|
|
320
|
+
try {
|
|
321
|
+
const mineConfig = (0, config_1.createMineConfig)({
|
|
322
|
+
limit: 200,
|
|
323
|
+
threshold: 0.25,
|
|
324
|
+
maxCluster: 10,
|
|
325
|
+
outputDir: specStoragePath,
|
|
326
|
+
skipLlm: false,
|
|
327
|
+
}, true);
|
|
328
|
+
const mineResult = await (0, pipeline_1.runMinePipeline)(repoPath, mineConfig, llmConfig ?? null, db);
|
|
329
|
+
// runMinePipeline already writes to meta.json and the same DB
|
|
330
|
+
(0, errors_1.logDebug)('mineStyleFallback: mine pipeline completed', { ...mineResult });
|
|
331
|
+
const hadResults = mineResult.specsGenerated > 0 || mineResult.specsWritten > 0;
|
|
332
|
+
return {
|
|
333
|
+
...emptyBatchResult(lastEvolved, headHash, newCommits.length),
|
|
334
|
+
phaseOneSkipped: newCommits.length,
|
|
335
|
+
metaUpdated: hadResults,
|
|
336
|
+
skipped: !hadResults,
|
|
337
|
+
skipReason: hadResults ? undefined : 'Mine pipeline produced no specs',
|
|
338
|
+
mineFallback: true,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
catch (err) {
|
|
342
|
+
(0, errors_1.logWarn)('mineStyleFallback: mine pipeline failed', {
|
|
343
|
+
error: err instanceof Error ? err.message : String(err),
|
|
344
|
+
});
|
|
345
|
+
return {
|
|
346
|
+
...emptyBatchResult(lastEvolved, headHash, newCommits.length),
|
|
347
|
+
phaseOneSkipped: newCommits.length,
|
|
348
|
+
skipped: true,
|
|
349
|
+
skipReason: `Mine pipeline failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
350
|
+
mineFallback: true,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// =============================================================================
|
|
355
|
+
// buildBatchResult — assemble the final BatchEvolveResult
|
|
356
|
+
// =============================================================================
|
|
357
|
+
function buildBatchResult(params) {
|
|
358
|
+
const { fromCommit, toCommit, commitsScanned, analyses, phaseOneResults, affectedEntries, evolvedSpecs, metaUpdated, mineFallback } = params;
|
|
359
|
+
let phaseOneMatched = 0;
|
|
360
|
+
let phaseOneSkipped = 0;
|
|
361
|
+
let phaseOneFailures = 0;
|
|
362
|
+
const perCommitResults = [];
|
|
363
|
+
for (const analysis of analyses) {
|
|
364
|
+
const pr = phaseOneResults.get(analysis.commit.hash);
|
|
365
|
+
if (!pr) {
|
|
366
|
+
// Should not happen, but defensive
|
|
367
|
+
perCommitResults.push({
|
|
368
|
+
commitHash: analysis.commit.hash,
|
|
369
|
+
matched: false,
|
|
370
|
+
phaseOneSkipped: true,
|
|
371
|
+
phaseOneSkipReason: 'Result not found',
|
|
372
|
+
evolvedSpecs: [],
|
|
373
|
+
fragmentsInserted: 0,
|
|
374
|
+
relationsCreated: 0,
|
|
375
|
+
});
|
|
376
|
+
phaseOneSkipped++;
|
|
377
|
+
continue;
|
|
320
378
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
379
|
+
if ('skipped' in pr) {
|
|
380
|
+
perCommitResults.push({
|
|
381
|
+
commitHash: analysis.commit.hash,
|
|
382
|
+
matched: false,
|
|
383
|
+
phaseOneSkipped: true,
|
|
384
|
+
phaseOneSkipReason: pr.reason,
|
|
385
|
+
evolvedSpecs: [],
|
|
386
|
+
fragmentsInserted: 0,
|
|
387
|
+
relationsCreated: 0,
|
|
388
|
+
});
|
|
389
|
+
analysis.matched ? phaseOneFailures++ : phaseOneSkipped++;
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
perCommitResults.push({
|
|
393
|
+
commitHash: analysis.commit.hash,
|
|
394
|
+
matched: true,
|
|
395
|
+
matchedSpecId: pr.specId,
|
|
396
|
+
phaseOneSkipped: false,
|
|
397
|
+
evolvedSpecs: evolvedSpecs.get(analysis.commit.hash) || [],
|
|
398
|
+
fragmentsInserted: pr.stats.fragmentsInserted,
|
|
399
|
+
relationsCreated: pr.stats.relationsCreated,
|
|
331
400
|
});
|
|
332
|
-
|
|
333
|
-
(0, relations_1.insertCommitFragmentRelation)(db, commitInfo.hash, inserted.id);
|
|
334
|
-
evolveResult.relationsCreated++;
|
|
401
|
+
phaseOneMatched++;
|
|
335
402
|
}
|
|
336
|
-
db.exec('COMMIT');
|
|
337
403
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
404
|
+
// Count phase 3 results
|
|
405
|
+
let specsUpdated = 0;
|
|
406
|
+
let specsDeprecated = 0;
|
|
407
|
+
let specsUnchanged = 0;
|
|
408
|
+
for (const [, specs] of evolvedSpecs) {
|
|
409
|
+
for (const es of specs) {
|
|
410
|
+
if (es.action === 'UPDATE')
|
|
411
|
+
specsUpdated++;
|
|
412
|
+
else if (es.action === 'DEPRECATE')
|
|
413
|
+
specsDeprecated++;
|
|
414
|
+
else
|
|
415
|
+
specsUnchanged++;
|
|
416
|
+
}
|
|
341
417
|
}
|
|
342
|
-
return
|
|
418
|
+
return {
|
|
419
|
+
fromCommit,
|
|
420
|
+
toCommit,
|
|
421
|
+
commitsScanned,
|
|
422
|
+
phaseOneMatched,
|
|
423
|
+
phaseOneSkipped,
|
|
424
|
+
phaseOneFailures,
|
|
425
|
+
historicalSpecsEvaluated: affectedEntries.length,
|
|
426
|
+
specsUpdated,
|
|
427
|
+
specsDeprecated,
|
|
428
|
+
specsUnchanged,
|
|
429
|
+
perCommitResults,
|
|
430
|
+
metaUpdated,
|
|
431
|
+
skipped: !metaUpdated && !mineFallback && phaseOneMatched === 0,
|
|
432
|
+
skipReason: !metaUpdated && !mineFallback && phaseOneMatched === 0
|
|
433
|
+
? 'All phase-1 persistence failed'
|
|
434
|
+
: undefined,
|
|
435
|
+
mineFallback,
|
|
436
|
+
};
|
|
343
437
|
}
|
|
344
438
|
// =============================================================================
|
|
345
|
-
//
|
|
439
|
+
// Public API — runEvolvePipeline
|
|
346
440
|
// =============================================================================
|
|
347
441
|
/**
|
|
348
|
-
* Run the self-evolve pipeline for all
|
|
349
|
-
*
|
|
350
|
-
* Reads `currentCommitID` from `meta.json` and processes every commit between
|
|
351
|
-
* that hash and `HEAD` in chronological order. Each commit is independently
|
|
352
|
-
* evolved via `runEvolvePipeline`. On full success, `meta.json` is refreshed
|
|
353
|
-
* with the new HEAD as `currentCommitID` and `updatedAt` set to now.
|
|
442
|
+
* Run the spec self-evolve pipeline for all new commits since the last evolve.
|
|
354
443
|
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
444
|
+
* This is the ONLY public entry point. It replaces both the old
|
|
445
|
+
* ``runEvolvePipeline`` (per-commit) and ``runBatchEvolvePipeline`` (batch
|
|
446
|
+
* wrapper) with a unified batch pipeline that aligns with the post-commit
|
|
447
|
+
* hook's cumulative commit threshold trigger.
|
|
357
448
|
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
449
|
+
* Flow:
|
|
450
|
+
* 0. Prep: meta.json → lock → schema → resolve HEAD + range.
|
|
451
|
+
* 1a. Batch analysis of all incremental commits (no DB writes).
|
|
452
|
+
* 1b. Per-commit persistence with independent transactions.
|
|
453
|
+
* 2. Impact location: find old specs affected by new commits.
|
|
454
|
+
* 3. LLM evaluation per spec cluster (only if LLM configured).
|
|
455
|
+
* ↓ or: mine-style fallback (if phase 1 produced zero matches + LLM).
|
|
456
|
+
* 4. Advance meta.json to last phase-1 success.
|
|
362
457
|
*
|
|
363
|
-
*
|
|
364
|
-
* -
|
|
365
|
-
* -
|
|
366
|
-
*
|
|
367
|
-
*/
|
|
368
|
-
const LOCK_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
369
|
-
/**
|
|
370
|
-
* Acquire a file-based advisory lock to prevent concurrent evolve runs.
|
|
371
|
-
* Returns true if the lock was acquired (or the existing lock is stale).
|
|
372
|
-
* Returns false if another evolve instance holds the lock.
|
|
458
|
+
* @param repoPath - Absolute path to the git repository.
|
|
459
|
+
* @param db - Active SQLite database handle.
|
|
460
|
+
* @param config - Spec configuration (loaded from configs.json); when config.llm is absent, phase 3 is skipped
|
|
461
|
+
* (phase 1 graph construction still runs).
|
|
373
462
|
*/
|
|
374
|
-
function
|
|
375
|
-
|
|
376
|
-
if (fs.existsSync(lockFile)) {
|
|
377
|
-
const stat = fs.statSync(lockFile);
|
|
378
|
-
if (Date.now() - stat.mtimeMs > LOCK_TIMEOUT_MS) {
|
|
379
|
-
// Stale lock — previous process may have crashed
|
|
380
|
-
fs.unlinkSync(lockFile);
|
|
381
|
-
}
|
|
382
|
-
else {
|
|
383
|
-
return false;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
fs.writeFileSync(lockFile, String(process.pid));
|
|
387
|
-
return true;
|
|
388
|
-
}
|
|
389
|
-
catch {
|
|
390
|
-
return false;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
async function runBatchEvolvePipeline(repoPath, db, llmConfig) {
|
|
463
|
+
async function runEvolvePipeline(repoPath, db, config) {
|
|
464
|
+
// ---- Stage 0: Preparation ----
|
|
394
465
|
const meta = (0, utils_1.readMeta)(repoPath);
|
|
395
466
|
if (!meta) {
|
|
396
|
-
throw new Error("No meta.json found. Run 'homegraph spec
|
|
467
|
+
throw new Error("No meta.json found. Run 'homegraph spec build' first.");
|
|
397
468
|
}
|
|
398
|
-
//
|
|
399
|
-
// fire multiple times in quick succession).
|
|
469
|
+
// File lock
|
|
400
470
|
const lockFile = path.join(repoPath, utils_1.SPEC_DATA_DIR, 'logs', 'evolve.lock');
|
|
401
471
|
fs.mkdirSync(path.dirname(lockFile), { recursive: true });
|
|
402
472
|
if (!acquireEvolveLock(lockFile)) {
|
|
403
|
-
(0, errors_1.logDebug)('
|
|
404
|
-
return
|
|
405
|
-
fromCommit: meta.currentCommitID || null,
|
|
406
|
-
toCommit: '',
|
|
407
|
-
commitsProcessed: 0,
|
|
408
|
-
perCommitResults: [],
|
|
409
|
-
metaUpdated: false,
|
|
410
|
-
skippedCommits: 0,
|
|
411
|
-
failures: 0,
|
|
412
|
-
};
|
|
473
|
+
(0, errors_1.logDebug)('runEvolvePipeline: another instance is running, skipping');
|
|
474
|
+
return emptyBatchResult(meta.currentCommitID || null, '', 0);
|
|
413
475
|
}
|
|
414
476
|
(0, schema_1.initSpecSchema)(db);
|
|
415
477
|
try {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
478
|
+
// Resolve HEAD and commit range
|
|
479
|
+
const headHash = resolveHead(repoPath);
|
|
480
|
+
const lastEvolved = meta.currentCommitID || null;
|
|
481
|
+
// No currentCommitID → process HEAD only
|
|
482
|
+
if (!lastEvolved) {
|
|
483
|
+
return await processSingleCommit(repoPath, db, meta.specStoragePath, headHash, config);
|
|
421
484
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
*/
|
|
429
|
-
async function runBatchEvolvePipelineImpl(repoPath, db, meta, llmConfig) {
|
|
430
|
-
// Resolve HEAD
|
|
431
|
-
let headHash;
|
|
432
|
-
try {
|
|
433
|
-
headHash = (0, child_process_1.execFileSync)('git', ['rev-parse', 'HEAD'], {
|
|
434
|
-
cwd: repoPath,
|
|
435
|
-
encoding: 'utf8',
|
|
436
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
437
|
-
windowsHide: true,
|
|
438
|
-
}).trim();
|
|
439
|
-
}
|
|
440
|
-
catch {
|
|
441
|
-
throw new Error('Failed to resolve HEAD. Not a valid git repository?');
|
|
442
|
-
}
|
|
443
|
-
if (!headHash) {
|
|
444
|
-
throw new Error('No commits found in repository.');
|
|
445
|
-
}
|
|
446
|
-
const lastEvolved = meta.currentCommitID || null;
|
|
447
|
-
// Fallback: no currentCommitID → process just HEAD
|
|
448
|
-
if (!lastEvolved) {
|
|
449
|
-
(0, errors_1.logDebug)('runBatchEvolvePipeline: no currentCommitID in meta.json — processing HEAD only', {
|
|
450
|
-
headHash: headHash.slice(0, 7),
|
|
451
|
-
});
|
|
452
|
-
const result = await runEvolvePipeline(repoPath, db, meta.specStoragePath, headHash, llmConfig);
|
|
453
|
-
// Only refresh meta.json when the commit was actually processed (not skipped).
|
|
454
|
-
const metaUpdated = !result.skipped;
|
|
455
|
-
if (metaUpdated) {
|
|
456
|
-
(0, utils_1.writeMeta)(repoPath, meta.specStoragePath, headHash);
|
|
485
|
+
// No new commits
|
|
486
|
+
if (lastEvolved === headHash) {
|
|
487
|
+
(0, errors_1.logDebug)('runEvolvePipeline: no new commits to evolve', {
|
|
488
|
+
currentCommitID: lastEvolved.slice(0, 7),
|
|
489
|
+
});
|
|
490
|
+
return emptyBatchResult(lastEvolved, headHash, 0);
|
|
457
491
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
// No new commits
|
|
469
|
-
if (lastEvolved === headHash) {
|
|
470
|
-
(0, errors_1.logDebug)('runBatchEvolvePipeline: no new commits to evolve', {
|
|
471
|
-
currentCommitID: lastEvolved.slice(0, 7),
|
|
472
|
-
});
|
|
473
|
-
return {
|
|
474
|
-
fromCommit: lastEvolved,
|
|
475
|
-
toCommit: headHash,
|
|
476
|
-
commitsProcessed: 0,
|
|
477
|
-
perCommitResults: [],
|
|
478
|
-
metaUpdated: false,
|
|
479
|
-
skippedCommits: 0,
|
|
480
|
-
failures: 0,
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
// Validate ancestry: lastEvolved must be an ancestor of HEAD
|
|
484
|
-
try {
|
|
485
|
-
(0, child_process_1.execFileSync)('git', ['merge-base', '--is-ancestor', lastEvolved, headHash], {
|
|
486
|
-
cwd: repoPath,
|
|
487
|
-
stdio: 'ignore',
|
|
488
|
-
windowsHide: true,
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
catch {
|
|
492
|
-
throw new Error(`The last evolved commit (${lastEvolved.slice(0, 7)}) is not an ancestor of ` +
|
|
493
|
-
`HEAD (${headHash.slice(0, 7)}). This usually happens after a rebase ` +
|
|
494
|
-
`or force-push. Please re-run 'homegraph spec mine' to rebuild the ` +
|
|
495
|
-
`knowledge graph, then run 'homegraph spec evolve' again.`);
|
|
496
|
-
}
|
|
497
|
-
// Get commit range in chronological order (oldest first)
|
|
498
|
-
const commits = (0, git_scanner_1.getCommitRange)(repoPath, lastEvolved, headHash);
|
|
499
|
-
if (commits.length === 0) {
|
|
500
|
-
(0, errors_1.logDebug)('runBatchEvolvePipeline: range query returned 0 commits', {
|
|
492
|
+
// Rebase detection
|
|
493
|
+
validateAncestry(repoPath, lastEvolved, headHash);
|
|
494
|
+
// Get commit range in chronological order
|
|
495
|
+
const newCommits = (0, git_1.getCommitRange)(repoPath, lastEvolved, headHash);
|
|
496
|
+
if (newCommits.length === 0) {
|
|
497
|
+
return emptyBatchResult(lastEvolved, headHash, 0);
|
|
498
|
+
}
|
|
499
|
+
(0, errors_1.logDebug)('runEvolvePipeline: processing commit range', {
|
|
500
|
+
count: newCommits.length,
|
|
501
501
|
from: lastEvolved.slice(0, 7),
|
|
502
502
|
to: headHash.slice(0, 7),
|
|
503
503
|
});
|
|
504
|
-
|
|
504
|
+
// ---- Stage 1a + 1b: Batch analysis + per-commit persistence ----
|
|
505
|
+
(0, errors_1.logDebug)('runEvolvePipeline: phase 1 — batch analysis + persistence', {
|
|
506
|
+
commitCount: newCommits.length,
|
|
507
|
+
});
|
|
508
|
+
const { phaseOneResults, phaseOneSpecIds, commitFilePaths, lastPhaseOneSuccess, analyses } = runPhaseOne(repoPath, db, meta.specStoragePath, newCommits, config);
|
|
509
|
+
// ---- Decision: phase 1 produced matches? ----
|
|
510
|
+
if (phaseOneSpecIds.size === 0) {
|
|
511
|
+
return await mineStyleFallback(repoPath, db, meta.specStoragePath, newCommits, lastEvolved, headHash, config.llm ?? undefined);
|
|
512
|
+
}
|
|
513
|
+
// ---- Stage 2: Impact location ----
|
|
514
|
+
const affectedEntries = (0, impact_locator_1.locateAffectedSpecsWithCommits)(db, commitFilePaths, phaseOneSpecIds);
|
|
515
|
+
(0, errors_1.logDebug)('runEvolvePipeline: phase 2 — impact location', {
|
|
516
|
+
affectedSpecs: affectedEntries.length,
|
|
517
|
+
});
|
|
518
|
+
// ---- Stage 3: LLM evaluation + apply ----
|
|
519
|
+
const client = (0, factory_1.createSpecLlmClient)(config.llm);
|
|
520
|
+
const evolvedSpecsByCommit = await evaluateAndApply(db, repoPath, affectedEntries, phaseOneResults, client);
|
|
521
|
+
// ---- Stage 4: Advance meta.json ----
|
|
522
|
+
const metaUpdated = lastPhaseOneSuccess !== null;
|
|
523
|
+
if (metaUpdated) {
|
|
524
|
+
(0, utils_1.writeMeta)(repoPath, meta.specStoragePath, lastPhaseOneSuccess);
|
|
525
|
+
}
|
|
526
|
+
const result = buildBatchResult({
|
|
505
527
|
fromCommit: lastEvolved,
|
|
506
|
-
toCommit: headHash,
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
528
|
+
toCommit: lastPhaseOneSuccess || headHash,
|
|
529
|
+
commitsScanned: newCommits.length,
|
|
530
|
+
analyses,
|
|
531
|
+
phaseOneResults,
|
|
532
|
+
affectedEntries,
|
|
533
|
+
evolvedSpecs: evolvedSpecsByCommit,
|
|
534
|
+
metaUpdated,
|
|
535
|
+
mineFallback: false,
|
|
536
|
+
});
|
|
537
|
+
return result;
|
|
513
538
|
}
|
|
514
|
-
|
|
515
|
-
count: commits.length,
|
|
516
|
-
from: lastEvolved.slice(0, 7),
|
|
517
|
-
to: headHash.slice(0, 7),
|
|
518
|
-
});
|
|
519
|
-
// Process each commit independently
|
|
520
|
-
const perCommitResults = [];
|
|
521
|
-
let failures = 0;
|
|
522
|
-
let skippedCount = 0;
|
|
523
|
-
for (const commit of commits) {
|
|
539
|
+
finally {
|
|
524
540
|
try {
|
|
525
|
-
|
|
526
|
-
perCommitResults.push(result);
|
|
527
|
-
if (result.skipped)
|
|
528
|
-
skippedCount++;
|
|
529
|
-
}
|
|
530
|
-
catch (err) {
|
|
531
|
-
failures++;
|
|
532
|
-
(0, errors_1.logWarn)('runBatchEvolvePipeline: commit evolve failed, continuing', {
|
|
533
|
-
commitHash: commit.hash.slice(0, 7),
|
|
534
|
-
error: err instanceof Error ? err.message : String(err),
|
|
535
|
-
});
|
|
536
|
-
perCommitResults.push({
|
|
537
|
-
commitHash: commit.hash,
|
|
538
|
-
generateRelationCreated: false,
|
|
539
|
-
isLogicChange: false,
|
|
540
|
-
logicCheckReason: `Evolve failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
541
|
-
affectedSpecCount: 0,
|
|
542
|
-
evolvedSpecs: [],
|
|
543
|
-
fragmentsCount: 0,
|
|
544
|
-
relationsCreated: 0,
|
|
545
|
-
persisted: false,
|
|
546
|
-
skipped: false,
|
|
547
|
-
});
|
|
541
|
+
fs.unlinkSync(lockFile);
|
|
548
542
|
}
|
|
543
|
+
catch { /* may already be deleted */ }
|
|
549
544
|
}
|
|
550
|
-
// Refresh meta.json as long as at least one commit was actually
|
|
551
|
-
// processed (neither skipped nor failed).
|
|
552
|
-
const processedCount = commits.length - failures - skippedCount;
|
|
553
|
-
const metaUpdated = processedCount > 0;
|
|
554
|
-
if (metaUpdated) {
|
|
555
|
-
(0, utils_1.writeMeta)(repoPath, meta.specStoragePath, headHash);
|
|
556
|
-
}
|
|
557
|
-
return {
|
|
558
|
-
fromCommit: lastEvolved,
|
|
559
|
-
toCommit: headHash,
|
|
560
|
-
commitsProcessed: commits.length,
|
|
561
|
-
perCommitResults,
|
|
562
|
-
metaUpdated,
|
|
563
|
-
skippedCommits: skippedCount,
|
|
564
|
-
failures,
|
|
565
|
-
};
|
|
566
545
|
}
|
|
567
546
|
//# sourceMappingURL=pipeline.js.map
|