forge-server 0.1.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/.claude/hooks/worktree-create.sh +64 -0
- package/.claude/hooks/worktree-remove.sh +57 -0
- package/.claude/settings.local.json +29 -0
- package/.forge/knowledge/conventions.yaml +1 -0
- package/.forge/knowledge/decisions.yaml +1 -0
- package/.forge/knowledge/gotchas.yaml +1 -0
- package/.forge/knowledge/patterns.yaml +1 -0
- package/.forge/manifest.yaml +6 -0
- package/CLAUDE.md +144 -0
- package/bin/setup-forge.sh +132 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +553 -0
- package/dist/cli.js.map +1 -0
- package/dist/context/codebase.d.ts +57 -0
- package/dist/context/codebase.d.ts.map +1 -0
- package/dist/context/codebase.js +301 -0
- package/dist/context/codebase.js.map +1 -0
- package/dist/context/injector.d.ts +147 -0
- package/dist/context/injector.d.ts.map +1 -0
- package/dist/context/injector.js +533 -0
- package/dist/context/injector.js.map +1 -0
- package/dist/context/memory.d.ts +32 -0
- package/dist/context/memory.d.ts.map +1 -0
- package/dist/context/memory.js +140 -0
- package/dist/context/memory.js.map +1 -0
- package/dist/context/session-index.d.ts +54 -0
- package/dist/context/session-index.d.ts.map +1 -0
- package/dist/context/session-index.js +265 -0
- package/dist/context/session-index.js.map +1 -0
- package/dist/context/session.d.ts +42 -0
- package/dist/context/session.d.ts.map +1 -0
- package/dist/context/session.js +121 -0
- package/dist/context/session.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/ingestion/chunker.d.ts +19 -0
- package/dist/ingestion/chunker.d.ts.map +1 -0
- package/dist/ingestion/chunker.js +189 -0
- package/dist/ingestion/chunker.js.map +1 -0
- package/dist/ingestion/embedder.d.ts +45 -0
- package/dist/ingestion/embedder.d.ts.map +1 -0
- package/dist/ingestion/embedder.js +152 -0
- package/dist/ingestion/embedder.js.map +1 -0
- package/dist/ingestion/git-analyzer.d.ts +77 -0
- package/dist/ingestion/git-analyzer.d.ts.map +1 -0
- package/dist/ingestion/git-analyzer.js +437 -0
- package/dist/ingestion/git-analyzer.js.map +1 -0
- package/dist/ingestion/indexer.d.ts +79 -0
- package/dist/ingestion/indexer.d.ts.map +1 -0
- package/dist/ingestion/indexer.js +766 -0
- package/dist/ingestion/indexer.js.map +1 -0
- package/dist/ingestion/markdown-chunker.d.ts +19 -0
- package/dist/ingestion/markdown-chunker.d.ts.map +1 -0
- package/dist/ingestion/markdown-chunker.js +243 -0
- package/dist/ingestion/markdown-chunker.js.map +1 -0
- package/dist/ingestion/markdown-knowledge.d.ts +21 -0
- package/dist/ingestion/markdown-knowledge.d.ts.map +1 -0
- package/dist/ingestion/markdown-knowledge.js +129 -0
- package/dist/ingestion/markdown-knowledge.js.map +1 -0
- package/dist/ingestion/parser.d.ts +20 -0
- package/dist/ingestion/parser.d.ts.map +1 -0
- package/dist/ingestion/parser.js +429 -0
- package/dist/ingestion/parser.js.map +1 -0
- package/dist/ingestion/watcher.d.ts +28 -0
- package/dist/ingestion/watcher.d.ts.map +1 -0
- package/dist/ingestion/watcher.js +147 -0
- package/dist/ingestion/watcher.js.map +1 -0
- package/dist/knowledge/hydrator.d.ts +37 -0
- package/dist/knowledge/hydrator.d.ts.map +1 -0
- package/dist/knowledge/hydrator.js +220 -0
- package/dist/knowledge/hydrator.js.map +1 -0
- package/dist/knowledge/registry.d.ts +129 -0
- package/dist/knowledge/registry.d.ts.map +1 -0
- package/dist/knowledge/registry.js +361 -0
- package/dist/knowledge/registry.js.map +1 -0
- package/dist/knowledge/search.d.ts +114 -0
- package/dist/knowledge/search.d.ts.map +1 -0
- package/dist/knowledge/search.js +428 -0
- package/dist/knowledge/search.js.map +1 -0
- package/dist/knowledge/store.d.ts +76 -0
- package/dist/knowledge/store.d.ts.map +1 -0
- package/dist/knowledge/store.js +230 -0
- package/dist/knowledge/store.js.map +1 -0
- package/dist/learning/confidence.d.ts +30 -0
- package/dist/learning/confidence.d.ts.map +1 -0
- package/dist/learning/confidence.js +165 -0
- package/dist/learning/confidence.js.map +1 -0
- package/dist/learning/patterns.d.ts +52 -0
- package/dist/learning/patterns.d.ts.map +1 -0
- package/dist/learning/patterns.js +290 -0
- package/dist/learning/patterns.js.map +1 -0
- package/dist/learning/trajectory.d.ts +55 -0
- package/dist/learning/trajectory.d.ts.map +1 -0
- package/dist/learning/trajectory.js +200 -0
- package/dist/learning/trajectory.js.map +1 -0
- package/dist/memory/memory-compat.d.ts +100 -0
- package/dist/memory/memory-compat.d.ts.map +1 -0
- package/dist/memory/memory-compat.js +146 -0
- package/dist/memory/memory-compat.js.map +1 -0
- package/dist/memory/observation-store.d.ts +57 -0
- package/dist/memory/observation-store.d.ts.map +1 -0
- package/dist/memory/observation-store.js +154 -0
- package/dist/memory/observation-store.js.map +1 -0
- package/dist/memory/session-tracker.d.ts +81 -0
- package/dist/memory/session-tracker.d.ts.map +1 -0
- package/dist/memory/session-tracker.js +262 -0
- package/dist/memory/session-tracker.js.map +1 -0
- package/dist/pipeline/engine.d.ts +179 -0
- package/dist/pipeline/engine.d.ts.map +1 -0
- package/dist/pipeline/engine.js +691 -0
- package/dist/pipeline/engine.js.map +1 -0
- package/dist/pipeline/events.d.ts +54 -0
- package/dist/pipeline/events.d.ts.map +1 -0
- package/dist/pipeline/events.js +157 -0
- package/dist/pipeline/events.js.map +1 -0
- package/dist/pipeline/parallel.d.ts +83 -0
- package/dist/pipeline/parallel.d.ts.map +1 -0
- package/dist/pipeline/parallel.js +277 -0
- package/dist/pipeline/parallel.js.map +1 -0
- package/dist/pipeline/state-machine.d.ts +65 -0
- package/dist/pipeline/state-machine.d.ts.map +1 -0
- package/dist/pipeline/state-machine.js +176 -0
- package/dist/pipeline/state-machine.js.map +1 -0
- package/dist/query/graph-queries.d.ts +84 -0
- package/dist/query/graph-queries.d.ts.map +1 -0
- package/dist/query/graph-queries.js +216 -0
- package/dist/query/graph-queries.js.map +1 -0
- package/dist/query/hybrid-search.d.ts +34 -0
- package/dist/query/hybrid-search.d.ts.map +1 -0
- package/dist/query/hybrid-search.js +263 -0
- package/dist/query/hybrid-search.js.map +1 -0
- package/dist/query/intent-detector.d.ts +35 -0
- package/dist/query/intent-detector.d.ts.map +1 -0
- package/dist/query/intent-detector.js +115 -0
- package/dist/query/intent-detector.js.map +1 -0
- package/dist/query/ranking.d.ts +57 -0
- package/dist/query/ranking.d.ts.map +1 -0
- package/dist/query/ranking.js +109 -0
- package/dist/query/ranking.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +291 -0
- package/dist/server.js.map +1 -0
- package/dist/storage/falkordb-store.d.ts +73 -0
- package/dist/storage/falkordb-store.d.ts.map +1 -0
- package/dist/storage/falkordb-store.js +346 -0
- package/dist/storage/falkordb-store.js.map +1 -0
- package/dist/storage/file-cache.d.ts +32 -0
- package/dist/storage/file-cache.d.ts.map +1 -0
- package/dist/storage/file-cache.js +115 -0
- package/dist/storage/file-cache.js.map +1 -0
- package/dist/storage/interfaces.d.ts +151 -0
- package/dist/storage/interfaces.d.ts.map +1 -0
- package/dist/storage/interfaces.js +7 -0
- package/dist/storage/interfaces.js.map +1 -0
- package/dist/storage/qdrant-store.d.ts +110 -0
- package/dist/storage/qdrant-store.d.ts.map +1 -0
- package/dist/storage/qdrant-store.js +467 -0
- package/dist/storage/qdrant-store.js.map +1 -0
- package/dist/storage/schema.d.ts +4 -0
- package/dist/storage/schema.d.ts.map +1 -0
- package/dist/storage/schema.js +136 -0
- package/dist/storage/schema.js.map +1 -0
- package/dist/storage/sqlite.d.ts +35 -0
- package/dist/storage/sqlite.d.ts.map +1 -0
- package/dist/storage/sqlite.js +132 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/tools/collaboration-tools.d.ts +111 -0
- package/dist/tools/collaboration-tools.d.ts.map +1 -0
- package/dist/tools/collaboration-tools.js +174 -0
- package/dist/tools/collaboration-tools.js.map +1 -0
- package/dist/tools/context-tools.d.ts +293 -0
- package/dist/tools/context-tools.d.ts.map +1 -0
- package/dist/tools/context-tools.js +437 -0
- package/dist/tools/context-tools.js.map +1 -0
- package/dist/tools/graph-tools.d.ts +129 -0
- package/dist/tools/graph-tools.d.ts.map +1 -0
- package/dist/tools/graph-tools.js +237 -0
- package/dist/tools/graph-tools.js.map +1 -0
- package/dist/tools/ingestion-tools.d.ts +96 -0
- package/dist/tools/ingestion-tools.d.ts.map +1 -0
- package/dist/tools/ingestion-tools.js +90 -0
- package/dist/tools/ingestion-tools.js.map +1 -0
- package/dist/tools/learning-tools.d.ts +168 -0
- package/dist/tools/learning-tools.d.ts.map +1 -0
- package/dist/tools/learning-tools.js +158 -0
- package/dist/tools/learning-tools.js.map +1 -0
- package/dist/tools/memory-tools.d.ts +183 -0
- package/dist/tools/memory-tools.d.ts.map +1 -0
- package/dist/tools/memory-tools.js +197 -0
- package/dist/tools/memory-tools.js.map +1 -0
- package/dist/tools/phase-tools.d.ts +954 -0
- package/dist/tools/phase-tools.d.ts.map +1 -0
- package/dist/tools/phase-tools.js +1215 -0
- package/dist/tools/phase-tools.js.map +1 -0
- package/dist/tools/pipeline-tools.d.ts +140 -0
- package/dist/tools/pipeline-tools.d.ts.map +1 -0
- package/dist/tools/pipeline-tools.js +162 -0
- package/dist/tools/pipeline-tools.js.map +1 -0
- package/dist/tools/registration-tools.d.ts +220 -0
- package/dist/tools/registration-tools.d.ts.map +1 -0
- package/dist/tools/registration-tools.js +391 -0
- package/dist/tools/registration-tools.js.map +1 -0
- package/dist/util/circuit-breaker.d.ts +75 -0
- package/dist/util/circuit-breaker.d.ts.map +1 -0
- package/dist/util/circuit-breaker.js +159 -0
- package/dist/util/circuit-breaker.js.map +1 -0
- package/dist/util/config.d.ts +23 -0
- package/dist/util/config.d.ts.map +1 -0
- package/dist/util/config.js +164 -0
- package/dist/util/config.js.map +1 -0
- package/dist/util/logger.d.ts +13 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +45 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/util/token-counter.d.ts +24 -0
- package/dist/util/token-counter.d.ts.map +1 -0
- package/dist/util/token-counter.js +48 -0
- package/dist/util/token-counter.js.map +1 -0
- package/dist/util/types.d.ts +525 -0
- package/dist/util/types.d.ts.map +1 -0
- package/dist/util/types.js +5 -0
- package/dist/util/types.js.map +1 -0
- package/docker-compose.yml +20 -0
- package/docs/plans/2026-02-27-swarm-coordination/architecture.md +203 -0
- package/docs/plans/2026-02-27-swarm-coordination/vision.md +57 -0
- package/docs/plans/completed/2026-02-26-forge-plugin-bundling/architecture.md +1 -0
- package/docs/plans/completed/2026-02-26-forge-plugin-bundling/vision.md +300 -0
- package/docs/plans/completed/2026-02-27-forge-swarm-learning/architecture.md +480 -0
- package/docs/plans/completed/2026-02-27-forge-swarm-learning/verification-checklist.md +462 -0
- package/docs/plans/completed/2026-02-27-git-history-atlassian/git-jira-plan.md +181 -0
- package/package.json +39 -0
- package/plugin/.claude-plugin/plugin.json +8 -0
- package/plugin/.mcp.json +15 -0
- package/plugin/README.md +134 -0
- package/plugin/agents/architect.md +367 -0
- package/plugin/agents/backend-specialist.md +263 -0
- package/plugin/agents/brainstormer.md +122 -0
- package/plugin/agents/data-specialist.md +266 -0
- package/plugin/agents/designer.md +408 -0
- package/plugin/agents/frontend-specialist.md +241 -0
- package/plugin/agents/inspector.md +406 -0
- package/plugin/agents/knowledge-keeper.md +443 -0
- package/plugin/agents/platform-engineer.md +326 -0
- package/plugin/agents/product-manager.md +268 -0
- package/plugin/agents/product-owner.md +438 -0
- package/plugin/agents/pulse-checker.md +73 -0
- package/plugin/agents/qa-strategist.md +500 -0
- package/plugin/agents/self-improver.md +310 -0
- package/plugin/agents/strategist.md +360 -0
- package/plugin/agents/supervisor.md +380 -0
- package/plugin/commands/brainstorm.md +25 -0
- package/plugin/commands/forge.md +88 -0
- package/plugin/docs/atlassian-integration.md +110 -0
- package/plugin/docs/workflow.md +126 -0
- package/plugin/skills/agent-development/.skillfish.json +10 -0
- package/plugin/skills/agent-development/SKILL.md +415 -0
- package/plugin/skills/agent-development/examples/agent-creation-prompt.md +238 -0
- package/plugin/skills/agent-development/examples/complete-agent-examples.md +427 -0
- package/plugin/skills/agent-development/references/agent-creation-system-prompt.md +207 -0
- package/plugin/skills/agent-development/references/system-prompt-design.md +411 -0
- package/plugin/skills/agent-development/references/triggering-examples.md +491 -0
- package/plugin/skills/agent-development/scripts/validate-agent.sh +217 -0
- package/plugin/skills/agent-handoff/SKILL.md +335 -0
- package/plugin/skills/anti-stub/SKILL.md +317 -0
- package/plugin/skills/brainstorm/SKILL.md +31 -0
- package/plugin/skills/debugging/SKILL.md +276 -0
- package/plugin/skills/fix/SKILL.md +62 -0
- package/plugin/skills/frontend-design/.skillfish.json +10 -0
- package/plugin/skills/frontend-design/SKILL.md +42 -0
- package/plugin/skills/gotchas/SKILL.md +61 -0
- package/plugin/skills/graph-orchestrator/SKILL.md +38 -0
- package/plugin/skills/history/SKILL.md +58 -0
- package/plugin/skills/impact/SKILL.md +59 -0
- package/plugin/skills/implementation-execution/SKILL.md +291 -0
- package/plugin/skills/index-repo/SKILL.md +55 -0
- package/plugin/skills/interviewing/SKILL.md +225 -0
- package/plugin/skills/knowledge-curation/SKILL.md +393 -0
- package/plugin/skills/learn/SKILL.md +69 -0
- package/plugin/skills/mcp-integration/.skillfish.json +10 -0
- package/plugin/skills/mcp-integration/SKILL.md +554 -0
- package/plugin/skills/mcp-integration/examples/http-server.json +20 -0
- package/plugin/skills/mcp-integration/examples/sse-server.json +19 -0
- package/plugin/skills/mcp-integration/examples/stdio-server.json +26 -0
- package/plugin/skills/mcp-integration/references/authentication.md +549 -0
- package/plugin/skills/mcp-integration/references/server-types.md +536 -0
- package/plugin/skills/mcp-integration/references/tool-usage.md +538 -0
- package/plugin/skills/nestjs/.skillfish.json +10 -0
- package/plugin/skills/nestjs/SKILL.md +669 -0
- package/plugin/skills/nestjs/drizzle-reference.md +1894 -0
- package/plugin/skills/nestjs/reference.md +1447 -0
- package/plugin/skills/nestjs/workflow-optimization.md +229 -0
- package/plugin/skills/parallel-dispatch/SKILL.md +308 -0
- package/plugin/skills/project-discovery/SKILL.md +304 -0
- package/plugin/skills/search/SKILL.md +56 -0
- package/plugin/skills/security-audit/SKILL.md +362 -0
- package/plugin/skills/skill-development/.skillfish.json +10 -0
- package/plugin/skills/skill-development/SKILL.md +637 -0
- package/plugin/skills/skill-development/references/skill-creator-original.md +209 -0
- package/plugin/skills/tdd/SKILL.md +273 -0
- package/plugin/skills/terminal-presentation/SKILL.md +395 -0
- package/plugin/skills/test-strategy/SKILL.md +365 -0
- package/plugin/skills/verification-protocol/SKILL.md +256 -0
- package/plugin/skills/visual-explainer/CHANGELOG.md +97 -0
- package/plugin/skills/visual-explainer/LICENSE +21 -0
- package/plugin/skills/visual-explainer/README.md +137 -0
- package/plugin/skills/visual-explainer/SKILL.md +352 -0
- package/plugin/skills/visual-explainer/banner.png +0 -0
- package/plugin/skills/visual-explainer/package.json +11 -0
- package/plugin/skills/visual-explainer/prompts/diff-review.md +68 -0
- package/plugin/skills/visual-explainer/prompts/fact-check.md +63 -0
- package/plugin/skills/visual-explainer/prompts/generate-slides.md +18 -0
- package/plugin/skills/visual-explainer/prompts/generate-web-diagram.md +10 -0
- package/plugin/skills/visual-explainer/prompts/plan-review.md +86 -0
- package/plugin/skills/visual-explainer/prompts/project-recap.md +61 -0
- package/plugin/skills/visual-explainer/references/css-patterns.md +1188 -0
- package/plugin/skills/visual-explainer/references/libraries.md +470 -0
- package/plugin/skills/visual-explainer/references/responsive-nav.md +212 -0
- package/plugin/skills/visual-explainer/references/slide-patterns.md +1403 -0
- package/plugin/skills/visual-explainer/templates/architecture.html +596 -0
- package/plugin/skills/visual-explainer/templates/data-table.html +540 -0
- package/plugin/skills/visual-explainer/templates/mermaid-flowchart.html +435 -0
- package/plugin/skills/visual-explainer/templates/slide-deck.html +913 -0
- package/src/cli.ts +655 -0
- package/src/context/.gitkeep +0 -0
- package/src/context/codebase.ts +393 -0
- package/src/context/injector.ts +797 -0
- package/src/context/memory.ts +187 -0
- package/src/context/session-index.ts +327 -0
- package/src/context/session.ts +152 -0
- package/src/index.ts +47 -0
- package/src/ingestion/.gitkeep +0 -0
- package/src/ingestion/chunker.ts +277 -0
- package/src/ingestion/embedder.ts +167 -0
- package/src/ingestion/git-analyzer.ts +545 -0
- package/src/ingestion/indexer.ts +984 -0
- package/src/ingestion/markdown-chunker.ts +337 -0
- package/src/ingestion/markdown-knowledge.ts +175 -0
- package/src/ingestion/parser.ts +475 -0
- package/src/ingestion/watcher.ts +182 -0
- package/src/knowledge/.gitkeep +0 -0
- package/src/knowledge/hydrator.ts +246 -0
- package/src/knowledge/registry.ts +463 -0
- package/src/knowledge/search.ts +565 -0
- package/src/knowledge/store.ts +262 -0
- package/src/learning/.gitkeep +0 -0
- package/src/learning/confidence.ts +193 -0
- package/src/learning/patterns.ts +360 -0
- package/src/learning/trajectory.ts +268 -0
- package/src/memory/.gitkeep +0 -0
- package/src/memory/memory-compat.ts +233 -0
- package/src/memory/observation-store.ts +224 -0
- package/src/memory/session-tracker.ts +332 -0
- package/src/pipeline/.gitkeep +0 -0
- package/src/pipeline/engine.ts +1139 -0
- package/src/pipeline/events.ts +253 -0
- package/src/pipeline/parallel.ts +394 -0
- package/src/pipeline/state-machine.ts +199 -0
- package/src/query/.gitkeep +0 -0
- package/src/query/graph-queries.ts +262 -0
- package/src/query/hybrid-search.ts +337 -0
- package/src/query/intent-detector.ts +131 -0
- package/src/query/ranking.ts +161 -0
- package/src/server.ts +352 -0
- package/src/storage/.gitkeep +0 -0
- package/src/storage/falkordb-store.ts +388 -0
- package/src/storage/file-cache.ts +141 -0
- package/src/storage/interfaces.ts +201 -0
- package/src/storage/qdrant-store.ts +557 -0
- package/src/storage/schema.ts +139 -0
- package/src/storage/sqlite.ts +168 -0
- package/src/tools/.gitkeep +0 -0
- package/src/tools/collaboration-tools.ts +208 -0
- package/src/tools/context-tools.ts +493 -0
- package/src/tools/graph-tools.ts +295 -0
- package/src/tools/ingestion-tools.ts +122 -0
- package/src/tools/learning-tools.ts +181 -0
- package/src/tools/memory-tools.ts +234 -0
- package/src/tools/phase-tools.ts +1452 -0
- package/src/tools/pipeline-tools.ts +188 -0
- package/src/tools/registration-tools.ts +450 -0
- package/src/util/.gitkeep +0 -0
- package/src/util/circuit-breaker.ts +193 -0
- package/src/util/config.ts +177 -0
- package/src/util/logger.ts +53 -0
- package/src/util/token-counter.ts +52 -0
- package/src/util/types.ts +710 -0
- package/tests/context/.gitkeep +0 -0
- package/tests/integration/.gitkeep +0 -0
- package/tests/knowledge/.gitkeep +0 -0
- package/tests/learning/.gitkeep +0 -0
- package/tests/pipeline/.gitkeep +0 -0
- package/tests/tools/.gitkeep +0 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +10 -0
- package/vscode-extension/.vscodeignore +7 -0
- package/vscode-extension/README.md +43 -0
- package/vscode-extension/out/edge-collector.js +274 -0
- package/vscode-extension/out/edge-collector.js.map +1 -0
- package/vscode-extension/out/extension.js +264 -0
- package/vscode-extension/out/extension.js.map +1 -0
- package/vscode-extension/out/forge-client.js +318 -0
- package/vscode-extension/out/forge-client.js.map +1 -0
- package/vscode-extension/package-lock.json +59 -0
- package/vscode-extension/package.json +71 -0
- package/vscode-extension/src/edge-collector.ts +320 -0
- package/vscode-extension/src/extension.ts +269 -0
- package/vscode-extension/src/forge-client.ts +364 -0
- package/vscode-extension/tsconfig.json +19 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// Pipeline state machine: transition table, validation, and cycle tracking.
|
|
2
|
+
//
|
|
3
|
+
// Design notes:
|
|
4
|
+
// - The Phase type from types.ts uses the forge-graph-rag naming convention
|
|
5
|
+
// ('idle', 'interview', 'requirements', 'architecture', 'design', 'qa_strategy',
|
|
6
|
+
// 'implementation', 'inspection', 'knowledge_collection', 'completed').
|
|
7
|
+
// - PipelineTier determines which edges are legal.
|
|
8
|
+
// - Cycle edges (inspection -> implementation, requirements -> architecture) are
|
|
9
|
+
// separate from the forward table so callers can track iteration counts.
|
|
10
|
+
|
|
11
|
+
import type { Phase, PipelineTier } from '../util/types.js';
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Transition table: maps each (Phase, PipelineTier) pair to the set of phases
|
|
15
|
+
// that may legally be transitioned to.
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
// For 'full' and 'abbreviated' tiers we share the same edge set — abbreviated
|
|
19
|
+
// is full minus the interview/requirements/design/qa phases, so we model it as
|
|
20
|
+
// a separate entry below.
|
|
21
|
+
const FULL_FORWARD_TRANSITIONS: Readonly<Record<Phase, readonly Phase[]>> = {
|
|
22
|
+
idle: ['interview'],
|
|
23
|
+
interview: ['architecture'],
|
|
24
|
+
requirements: ['architecture'],
|
|
25
|
+
architecture: ['design', 'qa_strategy', 'implementation'],
|
|
26
|
+
design: ['qa_strategy', 'implementation'],
|
|
27
|
+
qa_strategy: ['implementation'],
|
|
28
|
+
implementation: ['inspection'],
|
|
29
|
+
inspection: ['knowledge_collection', 'implementation'],
|
|
30
|
+
knowledge_collection: ['completed'],
|
|
31
|
+
completed: [],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Bug-fix (abbreviated) pipeline: idle -> architecture -> implementation ->
|
|
35
|
+
// inspection -> (completed | implementation). No interview/requirements/design/qa.
|
|
36
|
+
const BUG_FIX_FORWARD_TRANSITIONS: Readonly<Record<Phase, readonly Phase[]>> = {
|
|
37
|
+
idle: ['architecture'],
|
|
38
|
+
interview: [],
|
|
39
|
+
requirements: ['architecture'],
|
|
40
|
+
architecture: ['implementation'],
|
|
41
|
+
design: [],
|
|
42
|
+
qa_strategy: [],
|
|
43
|
+
implementation: ['inspection'],
|
|
44
|
+
inspection: ['implementation', 'completed'],
|
|
45
|
+
knowledge_collection: [],
|
|
46
|
+
completed: [],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Trivial: idle -> completed directly.
|
|
50
|
+
const TRIVIAL_FORWARD_TRANSITIONS: Readonly<Record<Phase, readonly Phase[]>> = {
|
|
51
|
+
idle: ['completed'],
|
|
52
|
+
interview: [],
|
|
53
|
+
requirements: [],
|
|
54
|
+
architecture: [],
|
|
55
|
+
design: [],
|
|
56
|
+
qa_strategy: [],
|
|
57
|
+
implementation: [],
|
|
58
|
+
inspection: [],
|
|
59
|
+
knowledge_collection: [],
|
|
60
|
+
completed: [],
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Internal lookup by tier.
|
|
64
|
+
function getTable(tier: PipelineTier): Readonly<Record<Phase, readonly Phase[]>> {
|
|
65
|
+
switch (tier) {
|
|
66
|
+
case 'full':
|
|
67
|
+
return FULL_FORWARD_TRANSITIONS;
|
|
68
|
+
case 'abbreviated':
|
|
69
|
+
return BUG_FIX_FORWARD_TRANSITIONS;
|
|
70
|
+
case 'trivial':
|
|
71
|
+
return TRIVIAL_FORWARD_TRANSITIONS;
|
|
72
|
+
default: {
|
|
73
|
+
// Exhaustiveness guard — TypeScript will catch unhandled tiers at
|
|
74
|
+
// compile time, but the runtime guard prevents silent misbehaviour.
|
|
75
|
+
const _exhaustive: never = tier;
|
|
76
|
+
throw new Error(`Unknown PipelineTier: ${_exhaustive}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Public API
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Returns true when the requested phase transition is legal for the given tier.
|
|
87
|
+
*
|
|
88
|
+
* Rules:
|
|
89
|
+
* - A phase may always transition to itself (idempotent re-start is handled
|
|
90
|
+
* at the engine layer, but the state machine permits it).
|
|
91
|
+
* - Otherwise the transition must appear in the table for the given tier.
|
|
92
|
+
*
|
|
93
|
+
* Note: cycle limit enforcement is NOT done here — call `canCycle()` in
|
|
94
|
+
* addition when the engine detects a backward edge.
|
|
95
|
+
*/
|
|
96
|
+
export function isValidTransition(
|
|
97
|
+
from: Phase,
|
|
98
|
+
to: Phase,
|
|
99
|
+
tier: PipelineTier,
|
|
100
|
+
): boolean {
|
|
101
|
+
if (from === to) {
|
|
102
|
+
// Re-entering the same phase is permitted (e.g., retrying a failed start).
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
const table = getTable(tier);
|
|
106
|
+
const legalTargets = table[from];
|
|
107
|
+
return legalTargets !== undefined && (legalTargets as readonly Phase[]).includes(to);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Returns the set of phases that are legal next steps from `phase` for the
|
|
112
|
+
* given tier. This is used to populate `available_transitions` in API
|
|
113
|
+
* responses so callers know what actions are currently available.
|
|
114
|
+
*/
|
|
115
|
+
export function getAvailableTransitions(phase: Phase, tier: PipelineTier): Phase[] {
|
|
116
|
+
const table = getTable(tier);
|
|
117
|
+
return [...(table[phase] ?? [])];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
// Cycle limits
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Maximum number of times each backward edge may be traversed before the
|
|
126
|
+
* engine forces a forward skip.
|
|
127
|
+
*
|
|
128
|
+
* Key format: '<from>_to_<to>'.
|
|
129
|
+
*/
|
|
130
|
+
export const MAX_CYCLES: Readonly<Record<string, number>> = {
|
|
131
|
+
inspection_to_implementation: 3,
|
|
132
|
+
requirements_to_architecture: 2,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Returns true if the backward (cycle) edge from -> to may be traversed given
|
|
137
|
+
* the current number of times it has already been traversed for this project.
|
|
138
|
+
*
|
|
139
|
+
* When the limit is exceeded the engine should force-advance to the next
|
|
140
|
+
* forward phase instead of looping.
|
|
141
|
+
*
|
|
142
|
+
* For transitions that are not tracked as cycles (i.e., not in MAX_CYCLES),
|
|
143
|
+
* this returns true unconditionally — those are ordinary forward transitions
|
|
144
|
+
* and cycle tracking does not apply.
|
|
145
|
+
*/
|
|
146
|
+
export function canCycle(
|
|
147
|
+
from: Phase,
|
|
148
|
+
to: Phase,
|
|
149
|
+
currentCycleCount: number,
|
|
150
|
+
): boolean {
|
|
151
|
+
const key = `${from}_to_${to}`;
|
|
152
|
+
const max = MAX_CYCLES[key];
|
|
153
|
+
if (max === undefined) {
|
|
154
|
+
// Not a tracked cycle edge — no limit applies.
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
return currentCycleCount < max;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Derives the cycle key used in the engine's cycle-count map for a given
|
|
162
|
+
* backward transition pair.
|
|
163
|
+
*
|
|
164
|
+
* Returns null when the pair is not a recognised cycle edge.
|
|
165
|
+
*/
|
|
166
|
+
export function getCycleKey(from: Phase, to: Phase): string | null {
|
|
167
|
+
const key = `${from}_to_${to}`;
|
|
168
|
+
return key in MAX_CYCLES ? key : null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Determines whether a transition is a backward (cycle) edge, as opposed to a
|
|
173
|
+
* forward progression edge. This is needed by the engine to know when to
|
|
174
|
+
* increment the cycle counter.
|
|
175
|
+
*
|
|
176
|
+
* A transition is considered a cycle when:
|
|
177
|
+
* - The `to` phase appears earlier in the canonical phase order than `from`.
|
|
178
|
+
* - AND the key is present in MAX_CYCLES (meaning it is a recognised loop).
|
|
179
|
+
*/
|
|
180
|
+
export function isCycleTransition(from: Phase, to: Phase): boolean {
|
|
181
|
+
return getCycleKey(from, to) !== null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Returns the phase the engine should force-advance to when a cycle limit is
|
|
186
|
+
* exceeded.
|
|
187
|
+
*
|
|
188
|
+
* Per the architecture spec:
|
|
189
|
+
* - inspection -> implementation exceeded: force to knowledge_collection
|
|
190
|
+
* - requirements -> architecture exceeded: force to implementation
|
|
191
|
+
*/
|
|
192
|
+
export function getForcedAdvancePhase(from: Phase, to: Phase): Phase | null {
|
|
193
|
+
const key = `${from}_to_${to}`;
|
|
194
|
+
const forced: Record<string, Phase> = {
|
|
195
|
+
inspection_to_implementation: 'knowledge_collection',
|
|
196
|
+
requirements_to_architecture: 'implementation',
|
|
197
|
+
};
|
|
198
|
+
return forced[key] ?? null;
|
|
199
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cypher query templates for FalkorDB graph operations.
|
|
3
|
+
* Centralizes all graph query patterns used by tools.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ============================================================
|
|
7
|
+
// Index Creation Queries
|
|
8
|
+
// ============================================================
|
|
9
|
+
|
|
10
|
+
export const INDEX_QUERIES = [
|
|
11
|
+
'CREATE INDEX ON :File(path, repo_id)',
|
|
12
|
+
'CREATE INDEX ON :Function(name, repo_id)',
|
|
13
|
+
'CREATE INDEX ON :Class(name, repo_id)',
|
|
14
|
+
'CREATE INDEX ON :Interface(name, repo_id)',
|
|
15
|
+
'CREATE INDEX ON :Module(name, repo_id)',
|
|
16
|
+
'CREATE INDEX ON :Observation(id)',
|
|
17
|
+
'CREATE INDEX ON :Observation(session_id)',
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
// ============================================================
|
|
21
|
+
// Node Count Queries
|
|
22
|
+
// ============================================================
|
|
23
|
+
|
|
24
|
+
export const QUERY_TOTAL_NODES = 'MATCH (n) RETURN count(n) as cnt';
|
|
25
|
+
export const QUERY_TOTAL_EDGES = 'MATCH ()-[r]->() RETURN count(r) as cnt';
|
|
26
|
+
|
|
27
|
+
export const QUERY_NODES_BY_LABEL = (label: string) =>
|
|
28
|
+
`MATCH (n:${label}) RETURN count(n) as cnt`;
|
|
29
|
+
|
|
30
|
+
// ============================================================
|
|
31
|
+
// File Queries
|
|
32
|
+
// ============================================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get all entities contained in a file.
|
|
36
|
+
*/
|
|
37
|
+
export const QUERY_FILE_ENTITIES = (filePath: string, repoId: string) => `
|
|
38
|
+
MATCH (f:File {path: "${esc(filePath)}", repo_id: "${esc(repoId)}"})-[:CONTAINS]->(s)
|
|
39
|
+
RETURN s, labels(s) as label
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get all files in a repo.
|
|
44
|
+
*/
|
|
45
|
+
export const QUERY_REPO_FILES = (repoId: string) => `
|
|
46
|
+
MATCH (f:File {repo_id: "${esc(repoId)}"})
|
|
47
|
+
RETURN f.path as path, f.content_hash as hash, f.last_indexed as indexed_at
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get files in a directory.
|
|
52
|
+
*/
|
|
53
|
+
export const QUERY_DIRECTORY_FILES = (dirPath: string, repoId: string) => `
|
|
54
|
+
MATCH (f:File {repo_id: "${esc(repoId)}"})
|
|
55
|
+
WHERE f.path STARTS WITH "${esc(dirPath)}"
|
|
56
|
+
RETURN f.path as path, f.language as language
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
// ============================================================
|
|
60
|
+
// Impact Graph Queries
|
|
61
|
+
// ============================================================
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Inbound: who calls/imports/uses this symbol?
|
|
65
|
+
*/
|
|
66
|
+
export const QUERY_INBOUND_IMPACT = (symbolName: string, repoId: string, depth: number) => `
|
|
67
|
+
MATCH (center {name: "${esc(symbolName)}", repo_id: "${esc(repoId)}"})
|
|
68
|
+
MATCH path = (caller)-[r*1..${depth}]->(center)
|
|
69
|
+
RETURN caller, r, length(path) as depth
|
|
70
|
+
LIMIT 50
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Outbound: what does this symbol depend on?
|
|
75
|
+
*/
|
|
76
|
+
export const QUERY_OUTBOUND_IMPACT = (symbolName: string, repoId: string, depth: number) => `
|
|
77
|
+
MATCH (center {name: "${esc(symbolName)}", repo_id: "${esc(repoId)}"})
|
|
78
|
+
MATCH path = (center)-[r*1..${depth}]->(dep)
|
|
79
|
+
RETURN dep, r, length(path) as depth
|
|
80
|
+
LIMIT 50
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
// ============================================================
|
|
84
|
+
// Logic Flow Queries
|
|
85
|
+
// ============================================================
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Shortest path between two symbols in the call graph.
|
|
89
|
+
*/
|
|
90
|
+
export const QUERY_SHORTEST_PATH = (fromSymbol: string, toSymbol: string, repoId: string, maxDepth: number) => `
|
|
91
|
+
MATCH (a {name: "${esc(fromSymbol)}", repo_id: "${esc(repoId)}"}),
|
|
92
|
+
(b {name: "${esc(toSymbol)}", repo_id: "${esc(repoId)}"})
|
|
93
|
+
MATCH path = shortestPath((a)-[*..${maxDepth}]->(b))
|
|
94
|
+
RETURN path
|
|
95
|
+
LIMIT 3
|
|
96
|
+
`;
|
|
97
|
+
|
|
98
|
+
// ============================================================
|
|
99
|
+
// Graph Neighbor Queries (for hybrid search boost)
|
|
100
|
+
// ============================================================
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get graph neighbors of a file (imports, tests, co-modified).
|
|
104
|
+
* Used to boost vector search results with graph connectivity.
|
|
105
|
+
*/
|
|
106
|
+
export const QUERY_FILE_NEIGHBORS = (filePath: string, repoId: string, depth: number) => `
|
|
107
|
+
MATCH (f:File {path: "${esc(filePath)}", repo_id: "${esc(repoId)}"})
|
|
108
|
+
MATCH (f)-[r*1..${depth}]-(neighbor:File)
|
|
109
|
+
RETURN neighbor.path as path, type(r[0]) as rel_type, length(r) as depth
|
|
110
|
+
LIMIT 20
|
|
111
|
+
`;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get import graph for a file.
|
|
115
|
+
*/
|
|
116
|
+
export const QUERY_FILE_IMPORTS = (filePath: string, repoId: string) => `
|
|
117
|
+
MATCH (f:File {path: "${esc(filePath)}", repo_id: "${esc(repoId)}"})-[:IMPORTS]->(dep:File)
|
|
118
|
+
RETURN dep.path as path
|
|
119
|
+
`;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get test files for a source file.
|
|
123
|
+
*/
|
|
124
|
+
export const QUERY_FILE_TESTS = (filePath: string, repoId: string) => `
|
|
125
|
+
MATCH (test:File)-[:TESTS]->(src:File {path: "${esc(filePath)}", repo_id: "${esc(repoId)}"})
|
|
126
|
+
RETURN test.path as path
|
|
127
|
+
`;
|
|
128
|
+
|
|
129
|
+
// ============================================================
|
|
130
|
+
// Observation Queries
|
|
131
|
+
// ============================================================
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Create or update an Observation node.
|
|
135
|
+
*/
|
|
136
|
+
export const UPSERT_OBSERVATION = (
|
|
137
|
+
id: string,
|
|
138
|
+
content: string,
|
|
139
|
+
sessionId: string,
|
|
140
|
+
importance: number
|
|
141
|
+
) => `
|
|
142
|
+
MERGE (o:Observation {id: "${esc(id)}"})
|
|
143
|
+
SET o.content = "${esc(content)}",
|
|
144
|
+
o.session_id = "${esc(sessionId)}",
|
|
145
|
+
o.importance = ${importance},
|
|
146
|
+
o.is_stale = false,
|
|
147
|
+
o.created_at = ${Date.now()}
|
|
148
|
+
`;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Link an observation to a code symbol via REFERENCES edge.
|
|
152
|
+
*/
|
|
153
|
+
export const LINK_OBSERVATION_TO_SYMBOL = (observationId: string, symbolName: string, repoId: string) => `
|
|
154
|
+
MATCH (o:Observation {id: "${esc(observationId)}"})
|
|
155
|
+
MATCH (s {name: "${esc(symbolName)}", repo_id: "${esc(repoId)}"})
|
|
156
|
+
MERGE (o)-[:REFERENCES]->(s)
|
|
157
|
+
`;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get recent observations by session.
|
|
161
|
+
*/
|
|
162
|
+
export const QUERY_SESSION_OBSERVATIONS = (sessionId: string, limit: number) => `
|
|
163
|
+
MATCH (o:Observation {session_id: "${esc(sessionId)}"})
|
|
164
|
+
RETURN o ORDER BY o.created_at DESC LIMIT ${limit}
|
|
165
|
+
`;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Mark observations as stale when a symbol changes.
|
|
169
|
+
*/
|
|
170
|
+
export const MARK_SYMBOL_OBSERVATIONS_STALE = (symbolName: string, repoId: string) => `
|
|
171
|
+
MATCH (o:Observation)-[:REFERENCES]->(s {name: "${esc(symbolName)}", repo_id: "${esc(repoId)}"})
|
|
172
|
+
SET o.is_stale = true
|
|
173
|
+
`;
|
|
174
|
+
|
|
175
|
+
// ============================================================
|
|
176
|
+
// File Hotspot Queries (Phase 3 - git enrichment)
|
|
177
|
+
// ============================================================
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get top files by commit_count (change hotspots) for a repo.
|
|
181
|
+
* Requires File nodes to have commit_count property set by git enrichment.
|
|
182
|
+
*/
|
|
183
|
+
export const QUERY_FILE_HOTSPOTS = (repoId: string, limit: number = 100) => `
|
|
184
|
+
MATCH (f:File {repo_id: "${esc(repoId)}"})
|
|
185
|
+
WHERE f.commit_count IS NOT NULL AND f.commit_count > 0
|
|
186
|
+
RETURN f.path as path, f.commit_count as commit_count, f.stability_score as stability_score, f.change_velocity as change_velocity
|
|
187
|
+
ORDER BY f.commit_count DESC
|
|
188
|
+
LIMIT ${limit}
|
|
189
|
+
`;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Get git stats for a single file.
|
|
193
|
+
*/
|
|
194
|
+
export const QUERY_FILE_STATS = (filePath: string, repoId: string) => `
|
|
195
|
+
MATCH (f:File {path: "${esc(filePath)}", repo_id: "${esc(repoId)}"})
|
|
196
|
+
RETURN f.path as path, f.commit_count as commit_count, f.stability_score as stability_score, f.change_velocity as change_velocity, f.last_commit_hash as last_commit_hash, f.last_commit_ts as last_commit_ts
|
|
197
|
+
`;
|
|
198
|
+
|
|
199
|
+
// ============================================================
|
|
200
|
+
// Co-modification Queries
|
|
201
|
+
// ============================================================
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Upsert a co-modification relationship between two files.
|
|
205
|
+
*/
|
|
206
|
+
export const UPSERT_CO_MODIFIED = (fileA: string, fileB: string, repoId: string, count: number, lastCommit: string) => `
|
|
207
|
+
MATCH (a:File {path: "${esc(fileA)}", repo_id: "${esc(repoId)}"})
|
|
208
|
+
MATCH (b:File {path: "${esc(fileB)}", repo_id: "${esc(repoId)}"})
|
|
209
|
+
MERGE (a)-[r:CO_MODIFIED]-(b)
|
|
210
|
+
SET r.count = ${count}, r.last_commit = "${esc(lastCommit)}"
|
|
211
|
+
`;
|
|
212
|
+
|
|
213
|
+
// ============================================================
|
|
214
|
+
// CALLS Edge Queries
|
|
215
|
+
// ============================================================
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Upsert a CALLS relationship between two functions.
|
|
219
|
+
* Uses MERGE to avoid duplicate edges.
|
|
220
|
+
*/
|
|
221
|
+
export const UPSERT_CALLS = (
|
|
222
|
+
callerName: string,
|
|
223
|
+
callerFilePath: string,
|
|
224
|
+
calleeName: string,
|
|
225
|
+
calleeFilePath: string,
|
|
226
|
+
repoId: string,
|
|
227
|
+
callCount: number
|
|
228
|
+
) => `
|
|
229
|
+
MATCH (caller:Function {name: "${esc(callerName)}", file_path: "${esc(callerFilePath)}", repo_id: "${esc(repoId)}"})
|
|
230
|
+
MATCH (callee:Function {name: "${esc(calleeName)}", file_path: "${esc(calleeFilePath)}", repo_id: "${esc(repoId)}"})
|
|
231
|
+
MERGE (caller)-[r:CALLS]->(callee)
|
|
232
|
+
SET r.call_count = ${callCount}
|
|
233
|
+
`;
|
|
234
|
+
|
|
235
|
+
// ============================================================
|
|
236
|
+
// TESTS Edge Queries
|
|
237
|
+
// ============================================================
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Upsert a TESTS relationship from a test file to its source file.
|
|
241
|
+
*/
|
|
242
|
+
export const UPSERT_TESTS = (testFilePath: string, sourceFilePath: string, repoId: string) => `
|
|
243
|
+
MATCH (test:File {path: "${esc(testFilePath)}", repo_id: "${esc(repoId)}"})
|
|
244
|
+
MATCH (src:File {path: "${esc(sourceFilePath)}", repo_id: "${esc(repoId)}"})
|
|
245
|
+
MERGE (test)-[:TESTS]->(src)
|
|
246
|
+
`;
|
|
247
|
+
|
|
248
|
+
// ============================================================
|
|
249
|
+
// Utility
|
|
250
|
+
// ============================================================
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Escape a string for safe embedding in Cypher queries.
|
|
254
|
+
* FalkorDB uses double-quoted strings.
|
|
255
|
+
*/
|
|
256
|
+
function esc(s: string): string {
|
|
257
|
+
return s
|
|
258
|
+
.replace(/\\/g, '\\\\')
|
|
259
|
+
.replace(/"/g, '\\"')
|
|
260
|
+
.replace(/\n/g, '\\n')
|
|
261
|
+
.replace(/\r/g, '');
|
|
262
|
+
}
|