@documentation-robotics/cli 0.2.0 → 0.4.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 +46 -16
- package/dist/analysis/relationship-classifier.js +2 -9
- package/dist/analysis/relationship-classifier.js.map +2 -2
- package/dist/analyzers/active-analyzer.js +62 -0
- package/dist/analyzers/active-analyzer.js.map +7 -0
- package/dist/analyzers/call-graph-utils.js +2 -2
- package/dist/analyzers/call-graph-utils.js.map +2 -2
- package/dist/analyzers/cards/build.js +191 -0
- package/dist/analyzers/cards/build.js.map +7 -0
- package/dist/analyzers/cards/classify.js +42 -0
- package/dist/analyzers/cards/classify.js.map +7 -0
- package/dist/analyzers/cards/edge-index.js +44 -0
- package/dist/analyzers/cards/edge-index.js.map +7 -0
- package/dist/analyzers/cards/extract.js +138 -0
- package/dist/analyzers/cards/extract.js.map +7 -0
- package/dist/analyzers/cards/facts.js +46 -0
- package/dist/analyzers/cards/facts.js.map +7 -0
- package/dist/analyzers/cards/graph.js +42 -0
- package/dist/analyzers/cards/graph.js.map +7 -0
- package/dist/analyzers/cards/index.js +8 -0
- package/dist/analyzers/cards/index.js.map +7 -0
- package/dist/analyzers/cards/routes.js +96 -0
- package/dist/analyzers/cards/routes.js.map +7 -0
- package/dist/analyzers/cards/tier0.js +18 -0
- package/dist/analyzers/cards/tier0.js.map +7 -0
- package/dist/analyzers/cards/types.js +1 -0
- package/dist/analyzers/cards/types.js.map +7 -0
- package/dist/analyzers/cbm-analyzer.js +270 -174
- package/dist/analyzers/cbm-analyzer.js.map +2 -2
- package/dist/analyzers/cbm-responses.js +342 -0
- package/dist/analyzers/cbm-responses.js.map +7 -0
- package/dist/analyzers/code-changes.js +159 -0
- package/dist/analyzers/code-changes.js.map +7 -0
- package/dist/analyzers/edge-relationships.js +49 -0
- package/dist/analyzers/edge-relationships.js.map +7 -0
- package/dist/analyzers/extraction-plan.js +541 -0
- package/dist/analyzers/extraction-plan.js.map +7 -0
- package/dist/analyzers/index-job.js +229 -0
- package/dist/analyzers/index-job.js.map +7 -0
- package/dist/analyzers/mapping-loader.js +9 -0
- package/dist/analyzers/mapping-loader.js.map +2 -2
- package/dist/analyzers/tier0-rules.js +153 -0
- package/dist/analyzers/tier0-rules.js.map +7 -0
- package/dist/analyzers/types.js.map +1 -1
- package/dist/audit/relationships/ai/prompts.js +10 -10
- package/dist/audit/relationships/ai/prompts.js.map +2 -2
- package/dist/audit/relationships/analysis/layer-templates.js +52 -52
- package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
- package/dist/cli.js +23 -11
- package/dist/cli.js.map +2 -2
- package/dist/coding-agents/default-permissions.js +31 -1
- package/dist/coding-agents/default-permissions.js.map +2 -2
- package/dist/coding-agents/drbot-mcp.js +269 -0
- package/dist/coding-agents/drbot-mcp.js.map +7 -0
- package/dist/commands/add.js +7 -4
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +143 -40
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/changeset-verify.js +63 -0
- package/dist/commands/changeset-verify.js.map +7 -0
- package/dist/commands/changeset.js +80 -29
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/delete.js +10 -4
- package/dist/commands/delete.js.map +2 -2
- package/dist/commands/farm.js +176 -60
- package/dist/commands/farm.js.map +2 -2
- package/dist/commands/init.js +9 -26
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/mcp.js +40 -21
- package/dist/commands/mcp.js.map +3 -3
- package/dist/commands/relationship.js +208 -37
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/reports.js +3 -3
- package/dist/commands/reports.js.map +2 -2
- package/dist/commands/update.js +52 -32
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +99 -103
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/validate.js +19 -3
- package/dist/commands/validate.js.map +2 -2
- package/dist/commands/version.js +1 -1
- package/dist/commands/visualize.js +34 -15
- package/dist/commands/visualize.js.map +2 -2
- package/dist/core/annotation-store.js +15 -5
- package/dist/core/annotation-store.js.map +2 -2
- package/dist/core/catalog-migration.js +34 -0
- package/dist/core/catalog-migration.js.map +7 -0
- package/dist/core/changeset-analysis.js +421 -0
- package/dist/core/changeset-analysis.js.map +7 -0
- package/dist/core/changeset-base-index.js +160 -0
- package/dist/core/changeset-base-index.js.map +7 -0
- package/dist/core/changeset-brief-compact.js +256 -0
- package/dist/core/changeset-brief-compact.js.map +7 -0
- package/dist/core/changeset-brief-delta.js +102 -0
- package/dist/core/changeset-brief-delta.js.map +7 -0
- package/dist/core/changeset-graph.js +281 -0
- package/dist/core/changeset-graph.js.map +7 -0
- package/dist/core/changeset-only-guard.js +32 -0
- package/dist/core/changeset-only-guard.js.map +7 -0
- package/dist/core/changeset-summary.js +68 -0
- package/dist/core/changeset-summary.js.map +7 -0
- package/dist/core/changeset-validator.js +66 -20
- package/dist/core/changeset-validator.js.map +2 -2
- package/dist/core/changeset-verify.js +848 -0
- package/dist/core/changeset-verify.js.map +7 -0
- package/dist/core/changeset.js +56 -9
- package/dist/core/changeset.js.map +2 -2
- package/dist/core/element-type-migration.js +145 -0
- package/dist/core/element-type-migration.js.map +7 -0
- package/dist/core/extraction-observability.js +161 -0
- package/dist/core/extraction-observability.js.map +7 -0
- package/dist/core/farm-manifest.js +12 -6
- package/dist/core/farm-manifest.js.map +2 -2
- package/dist/core/farm-sync-engine.js +1 -1
- package/dist/core/farm-sync-engine.js.map +2 -2
- package/dist/core/farm-sync-state.js +10 -2
- package/dist/core/farm-sync-state.js.map +2 -2
- package/dist/core/migration-registry.js +88 -47
- package/dist/core/migration-registry.js.map +2 -2
- package/dist/core/model-upgrade.js +102 -0
- package/dist/core/model-upgrade.js.map +7 -0
- package/dist/core/model.js +82 -30
- package/dist/core/model.js.map +2 -2
- package/dist/core/mutation-handler.js +71 -6
- package/dist/core/mutation-handler.js.map +2 -2
- package/dist/core/project-init.js +53 -0
- package/dist/core/project-init.js.map +7 -0
- package/dist/core/relationship-migration-table.js +6639 -0
- package/dist/core/relationship-migration-table.js.map +7 -0
- package/dist/core/relationship-migration.js +272 -0
- package/dist/core/relationship-migration.js.map +7 -0
- package/dist/core/relationship-prune.js +49 -0
- package/dist/core/relationship-prune.js.map +7 -0
- package/dist/core/relationship-staging.js +161 -0
- package/dist/core/relationship-staging.js.map +7 -0
- package/dist/core/relationships.js +26 -4
- package/dist/core/relationships.js.map +2 -2
- package/dist/core/report-data-model.js +7 -13
- package/dist/core/report-data-model.js.map +2 -2
- package/dist/core/staged-changeset-storage.js +145 -18
- package/dist/core/staged-changeset-storage.js.map +2 -2
- package/dist/core/staged-source-reference.js +28 -0
- package/dist/core/staged-source-reference.js.map +7 -0
- package/dist/core/staging-area.js +166 -24
- package/dist/core/staging-area.js.map +2 -2
- package/dist/core/upgrade-plan.js +117 -0
- package/dist/core/upgrade-plan.js.map +7 -0
- package/dist/core/virtual-projection.js +13 -5
- package/dist/core/virtual-projection.js.map +2 -2
- package/dist/export/archimate-exporter.js +1 -0
- package/dist/export/archimate-exporter.js.map +2 -2
- package/dist/generated/compiled-validators.js +2 -2
- package/dist/generated/compiled-validators.js.map +2 -2
- package/dist/generated/layer-registry.js +16 -16
- package/dist/generated/layer-registry.js.map +2 -2
- package/dist/generated/node-types.js +186 -168
- package/dist/generated/node-types.js.map +2 -2
- package/dist/generated/relationship-index.js +2468 -7913
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/.claude-plugin/plugin.json +24 -0
- package/dist/integrations/claude_code/agents/dr-architect.md +30 -3
- package/dist/integrations/claude_code/agents/dr-extractor.md +8 -2
- package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
- package/dist/integrations/claude_code/commands/dr-changeset.md +2 -1
- package/dist/integrations/claude_code/commands/dr-map.md +20 -1
- package/dist/integrations/claude_code/commands/dr-plan.md +66 -0
- package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
- package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
- package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
- package/dist/integrations/claude_code/docs/MCP_SERVER.md +47 -26
- package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
- package/dist/integrations/claude_code/docs/README.md +68 -2
- package/dist/integrations/claude_code/plugin-agents/dr-advisor.md +255 -0
- package/dist/integrations/claude_code/plugin-agents/dr-architect.md +306 -0
- package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
- package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
- package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
- package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
- package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
- package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
- package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
- package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
- package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
- package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
- package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
- package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
- package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +95 -15
- package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +178 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +8 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +6 -1
- package/dist/integrations/github_copilot/agents/dr-architect.md +3 -1
- package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
- package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
- package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
- package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
- package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
- package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
- package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
- package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
- package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
- package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
- package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
- package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
- package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +225 -102
- package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +177 -0
- package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/hash-utils.js.map +2 -2
- package/dist/mcp/api-key-manager.js +14 -1
- package/dist/mcp/api-key-manager.js.map +2 -2
- package/dist/mcp/changeset-only.js +45 -0
- package/dist/mcp/changeset-only.js.map +7 -0
- package/dist/mcp/project-root.js +85 -0
- package/dist/mcp/project-root.js.map +7 -0
- package/dist/mcp/server-instructions.js +27 -0
- package/dist/mcp/server-instructions.js.map +7 -0
- package/dist/mcp/strict-schema.js +52 -0
- package/dist/mcp/strict-schema.js.map +7 -0
- package/dist/mcp/tool-registry.js +55 -5
- package/dist/mcp/tool-registry.js.map +2 -2
- package/dist/mcp/tools/changeset-analysis-tools.js +98 -0
- package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
- package/dist/mcp/tools/changeset-commit.js +224 -0
- package/dist/mcp/tools/changeset-commit.js.map +7 -0
- package/dist/mcp/tools/changeset-editing.js +260 -0
- package/dist/mcp/tools/changeset-editing.js.map +7 -0
- package/dist/mcp/tools/changeset-lifecycle.js +83 -0
- package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
- package/dist/mcp/tools/changeset-shared.js +31 -0
- package/dist/mcp/tools/changeset-shared.js.map +7 -0
- package/dist/mcp/tools/changeset-show.js +17 -1
- package/dist/mcp/tools/changeset-show.js.map +2 -2
- package/dist/mcp/tools/changeset-verify.js +49 -0
- package/dist/mcp/tools/changeset-verify.js.map +7 -0
- package/dist/mcp/tools/codebase-extract.js +836 -0
- package/dist/mcp/tools/codebase-extract.js.map +7 -0
- package/dist/mcp/tools/codebase-index.js +125 -0
- package/dist/mcp/tools/codebase-index.js.map +7 -0
- package/dist/mcp/tools/codebase-shared.js +265 -0
- package/dist/mcp/tools/codebase-shared.js.map +7 -0
- package/dist/mcp/tools/codebase-verify.js +48 -0
- package/dist/mcp/tools/codebase-verify.js.map +7 -0
- package/dist/mcp/tools/index.js +34 -1
- package/dist/mcp/tools/index.js.map +2 -2
- package/dist/mcp/tools/model-add.js +191 -74
- package/dist/mcp/tools/model-add.js.map +2 -2
- package/dist/mcp/tools/model-delete.js +2 -2
- package/dist/mcp/tools/model-delete.js.map +2 -2
- package/dist/mcp/tools/model-search.js +14 -0
- package/dist/mcp/tools/model-search.js.map +2 -2
- package/dist/mcp/tools/model-show.js +29 -2
- package/dist/mcp/tools/model-show.js.map +2 -2
- package/dist/mcp/tools/model-trace.js +93 -30
- package/dist/mcp/tools/model-trace.js.map +2 -2
- package/dist/mcp/tools/model-update.js +46 -26
- package/dist/mcp/tools/model-update.js.map +2 -2
- package/dist/mcp/tools/model-validate.js +46 -4
- package/dist/mcp/tools/model-validate.js.map +2 -2
- package/dist/mcp/tools/project-status-collectors.js +381 -0
- package/dist/mcp/tools/project-status-collectors.js.map +7 -0
- package/dist/mcp/tools/project-status.js +237 -0
- package/dist/mcp/tools/project-status.js.map +7 -0
- package/dist/mcp/tools/project-tools.js +505 -0
- package/dist/mcp/tools/project-tools.js.map +7 -0
- package/dist/mcp/tools/relationship-tools.js +167 -0
- package/dist/mcp/tools/relationship-tools.js.map +7 -0
- package/dist/mcp/tools/review-open.js +210 -0
- package/dist/mcp/tools/review-open.js.map +7 -0
- package/dist/mcp/tools/shared.js +35 -4
- package/dist/mcp/tools/shared.js.map +2 -2
- package/dist/mcp/tools/spec-type.js +90 -0
- package/dist/mcp/tools/spec-type.js.map +7 -0
- package/dist/reports/model-report-orchestrator.js +31 -2
- package/dist/reports/model-report-orchestrator.js.map +2 -2
- package/dist/schemas/bundled/analyzers/cbm.json +1200 -70
- package/dist/schemas/bundled/analyzers/manifest.json +2 -2
- package/dist/schemas/bundled/api.json +1029 -1658
- package/dist/schemas/bundled/apm.json +499 -734
- package/dist/schemas/bundled/application.json +735 -371
- package/dist/schemas/bundled/base.json +3 -220
- package/dist/schemas/bundled/business.json +452 -366
- package/dist/schemas/bundled/data-model.json +395 -411
- package/dist/schemas/bundled/data-store.json +334 -558
- package/dist/schemas/bundled/manifest.json +18 -18
- package/dist/schemas/bundled/motivation.json +349 -368
- package/dist/schemas/bundled/navigation.json +415 -731
- package/dist/schemas/bundled/product.json +325 -159
- package/dist/schemas/bundled/security.json +864 -1232
- package/dist/schemas/bundled/technology.json +574 -703
- package/dist/schemas/bundled/testing.json +865 -1646
- package/dist/schemas/bundled/ux.json +739 -1352
- package/dist/server/schemas.js +8 -0
- package/dist/server/schemas.js.map +2 -2
- package/dist/server/server.js +686 -231
- package/dist/server/server.js.map +3 -3
- package/dist/server/viewer-registry.js +264 -0
- package/dist/server/viewer-registry.js.map +7 -0
- package/dist/server-entry.js +2 -1
- package/dist/server-entry.js.map +2 -2
- package/dist/telemetry/index.js +1 -1
- package/dist/utils/ansi-suppressor.js +6 -8
- package/dist/utils/ansi-suppressor.js.map +2 -2
- package/dist/utils/attribute-patch.js +41 -0
- package/dist/utils/attribute-patch.js.map +7 -0
- package/dist/utils/error-hints.js +29 -0
- package/dist/utils/error-hints.js.map +7 -0
- package/dist/utils/errors.js +9 -3
- package/dist/utils/errors.js.map +2 -2
- package/dist/utils/id-generator.js +5 -2
- package/dist/utils/id-generator.js.map +2 -2
- package/dist/utils/project-paths.js +26 -1
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/source-reference.js +64 -31
- package/dist/utils/source-reference.js.map +2 -2
- package/dist/utils/spec-version.js +2 -2
- package/dist/utils/spec-version.js.map +1 -1
- package/dist/validators/composed-reference-validator.js +5 -27
- package/dist/validators/composed-reference-validator.js.map +2 -2
- package/dist/validators/model-warnings.js +28 -0
- package/dist/validators/model-warnings.js.map +7 -0
- package/dist/validators/reference-validator.js +0 -7
- package/dist/validators/reference-validator.js.map +2 -2
- package/dist/validators/relationship-schema-validator.js +3 -3
- package/dist/validators/relationship-schema-validator.js.map +2 -2
- package/dist/validators/schema-validator.js +27 -9
- package/dist/validators/schema-validator.js.map +2 -2
- package/dist/validators/types.js.map +1 -1
- package/dist/viewer/README.md +6 -6
- package/dist/viewer/assets/main-CUOQGGRA.css +1 -0
- package/dist/viewer/assets/main-DvH3gYrI.js +84 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer/manifest.json +10 -10
- package/dist/viewer/version.json +1 -1
- package/package.json +2 -1
- package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
- package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/codebase-extract.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * codebase_extract \u2014 run the extraction cascade over the indexed code and stage what it finds in\n * an as-built changeset. It never writes the base model and never commits.\n *\n * The cascade (docs/analyzers/CASCADE_DESIGN.md):\n * 1. Tier 0 rules decide what they can; a CBM route is an `api.operation` by the node mapping.\n * Those decisions are staged, with the relationships the edge mapping gives them.\n * 2. Tier 1 (a decision model) is not wired until the per-project opt-in is settled\n * (docs/EXTRACTION_STRATEGY.md, B6); it would decide cards between steps 1 and 3.\n * 3. The calling agent gets the rest as cards, paged, and stages its own decisions with model_add.\n *\n * Only what differs from the model is staged (src/analyzers/extraction-plan.ts): existing elements\n * are matched by source file and symbol; a changed match is an update, no match is an add, and an\n * element whose code is gone is listed as a candidate delete, never staged. Re-running on unchanged\n * code stages nothing. `since` limits the run to files changed since a git ref, which is how the\n * verify workflow extracts a branch's build for changeset_verify.\n *\n * It runs inline: on this repository (4,800 cards, 25,000 mapped edges) a run takes a few seconds.\n * The extraction changeset is active afterwards, so the agent's model_add calls stage into it;\n * the one active before is returned as previousActive. A run that stages nothing creates and\n * activates no changeset: its cards wait in pending.json for the changeset the agent creates.\n *\n * \"Not an element\" decisions are kept per project (.dr/analyzers/extract/decisions.json), by file\n * and symbol: a card or staged symbol the agent rejects (`reject`, which unstages what is still\n * staged for it), and an element this tool staged that the agent then unstaged. Later runs leave\n * those symbols out, and say how many; `clearRejected` forgets them.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { strictItem } from \"../strict-schema.js\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { codeChangesSince, inDirs, scopeChanges, type CodeChangesResult } from \"../../analyzers/code-changes.js\";\nimport { SOURCE_EXT, VENDOR_EXCLUDE } from \"../../analyzers/cards/build.js\";\nimport { ExtractionTimeoutError, type ExtractionGraph } from \"../../analyzers/cards/extract.js\";\nimport {\n attributeChangedLines,\n decisionKey,\n needsAttributesCard,\n planElements,\n planRelationships,\n sortUndecided,\n sourceSymbolOf,\n type ElementPlan,\n type PlannedElement,\n type PlannedRelationship,\n type PlannedUpdate,\n type UndecidedCard,\n type UndecidedKind,\n} from \"../../analyzers/extraction-plan.js\";\nimport { Changeset, type StagedChange } from \"../../core/changeset.js\";\nimport { ChangesetGraph } from \"../../core/changeset-graph.js\";\nimport { Element } from \"../../core/element.js\";\nimport { Layer } from \"../../core/layer.js\";\nimport type { Model } from \"../../core/model.js\";\nimport { setStagedSourceReference, stagedSourceReference } from \"../../core/staged-source-reference.js\";\nimport { StagingAreaManager } from \"../../core/staging-area.js\";\nimport { getAllLayerIds, isValidLayer } from \"../../generated/layer-registry.js\";\nimport { getValidRelationships } from \"../../generated/relationship-index.js\";\nimport type { SourceReference } from \"../../types/source-reference.js\";\nimport { generateUUID } from \"../../utils/id-generator.js\";\nimport { CLIError, ErrorCategory, formatValidOptions } from \"../../utils/errors.js\";\nimport { FileLock } from \"../../utils/file-lock.js\";\nimport { SchemaValidator } from \"../../validators/schema-validator.js\";\nimport { compactJson, jsonResult, loadModel, reloadModel, rootPathSchema, runTool, type McpToolContext, type McpToolDefinition } from \"./shared.js\";\nimport { changesetUnstageHandler } from \"./changeset-editing.js\";\nimport {\n analyzerNotFoundError,\n canonicalRoots,\n defaultCodebaseToolDeps,\n describeIndex,\n requireFreshIndex,\n type CodebaseToolDeps,\n} from \"./codebase-shared.js\";\n\nconst DEFAULT_PAGE_SIZE = 25;\n/** The most cards a page holds, whatever pageSize asks: more than this rarely fits the response budget. */\nconst MAX_PAGE_SIZE = 50;\n/**\n * The size a response with cards aims to stay under. Clients save larger tool results to a file\n * (Claude Code does above about 25-30 KB), which the agent then has to search.\n */\nconst RESPONSE_BUDGET_BYTES = 28 * 1024;\nconst MAX_LISTED = 100;\n\nconst inputSchema = {\n changeset: z\n .string()\n .min(1)\n .optional()\n .describe(\n \"Name (or id) of the as-built changeset to stage into. Created when absent, reused when it is staged. \" +\n \"Default: extract-<short git HEAD>, or extract-<since base>..<HEAD> with since.\"\n ),\n since: z\n .string()\n .min(1)\n .optional()\n .describe(\n \"A git ref (branch, tag or commit). Extract only the files changed since its merge base with HEAD, plus \" +\n \"uncommitted ones. To verify a branch's build, pass the branch it started from.\"\n ),\n layers: z.array(z.string()).optional().describe(\"Only these layers (canonical names). Default: every layer.\"),\n pageSize: z\n .number()\n .int()\n .min(1)\n .max(200)\n .optional()\n .describe(\n `Undecided cards per page (default ${DEFAULT_PAGE_SIZE}, at most ${MAX_PAGE_SIZE}). A page that would make the response larger than about ` +\n `${RESPONSE_BUDGET_BYTES / 1024} KB has its cards shortened, and says so.`\n ),\n page: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\n \"Page of undecided cards (default 1). Page 2 and later read the last run's cards, with its since and layers: nothing is extracted or staged.\"\n ),\n reject: z\n .array(\n strictItem(\"A reject[] item\", {\n card: z\n .string()\n .min(1)\n .describe(\"The card's cardId, its symbol (or file#symbol), or the id of an element this extraction staged.\"),\n reason: z.string().min(1).describe(\"Why it is not a model element, in a few words.\"),\n })\n )\n .optional()\n .describe(\n \"Code that is not a model element: a card of this extraction (cardId, or a symbol only one card has), a symbol it \" +\n \"staged (Tier 0 decided it), or the id of an element staged from it. Recorded for the project until cleared, so \" +\n \"later runs leave them out; an element still staged in the changeset for it is unstaged, with its relationships. \" +\n \"A call with only reject or clearRejected records and runs nothing.\"\n ),\n clearRejected: z\n .union([z.literal(true), z.array(z.string().min(1))])\n .optional()\n .describe(\"Forget not-an-element decisions: true for all, or a list of symbols (or file#symbol) as notElements lists them.\"),\n rootPath: rootPathSchema,\n};\n\nexport type CodebaseExtractArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\n/**\n * The last run on a changeset: its undecided cards, for paging, the arguments and model they came\n * from, and the changeset that was active before the first run.\n */\ninterface StoredCards {\n changesetId: string;\n changesetName: string;\n gitHead: string;\n since: string | null;\n layers: string[] | null;\n /** The base model's manifest timestamp when the cards were read. */\n baseModified?: string;\n previousActive?: { id: string; name: string } | null;\n createdAt: string;\n cards: UndecidedCard[];\n /** The elements extraction staged into this changeset, by the symbol they came from. */\n staged?: StagedBySymbol[];\n /**\n * Cards earlier runs returned that are no longer undecided (the agent modelled them), so a\n * `reject` can still name them by cardId, e.g. after unstaging the element it added for one.\n */\n earlierCards?: EarlierCard[];\n /**\n * A run that staged nothing and so made no changeset (`changesetId` is empty): its cards, kept\n * in {@link PENDING_FILE} for paging and `reject`, and adopted by the changeset of that name\n * once it exists.\n */\n pending?: true;\n /**\n * Updates extraction itself staged into this changeset, with the fields it changed (an update\n * folded into an add this changeset stages included), accumulated across runs. An entry goes\n * when its change is unstaged or the element is rejected.\n */\n updated?: Array<{\n id: string;\n fields: string[];\n /**\n * The value extraction wrote for each field, keyed as in `fields`: a top-level field by its\n * on-disk name (`description`, `name`, `source_reference`), an attribute as\n * `attributes.<key>` (`attributes.http_path`). The latest run's value wins.\n */\n values?: Record<string, unknown>;\n }>;\n /** Ids extraction listed as candidate deletes for this changeset, accumulated across runs. */\n candidateDeletes?: string[];\n}\n\n/** A card of an earlier run, as the card was (older records kept only the identifying fields). */\ntype EarlierCard = Pick<UndecidedCard, \"cardId\" | \"file\" | \"symbol\" | \"label\" | \"qualifiedName\"> & Partial<UndecidedCard>;\n\ninterface StagedBySymbol {\n id: string;\n file: string | null;\n symbol: string;\n label: string;\n /** The element name it was staged with. */\n name?: string;\n /** The attributes it was staged with, when it had any. */\n attributes?: Record<string, unknown>;\n}\n\n/** An element's name and attributes for its {@link StagedBySymbol} entry. */\nfunction stagedAs(name: string | undefined, attributes: Record<string, unknown> | undefined): Pick<StagedBySymbol, \"name\" | \"attributes\"> {\n return { ...(name ? { name } : {}), ...(attributes && Object.keys(attributes).length ? { attributes: structuredClone(attributes) } : {}) };\n}\n\n/** Descriptions extraction wrote from docstrings, by element id (see PlanOptions.extractedDescriptions). */\nconst DESCRIPTIONS_FILE = \"descriptions.json\";\n\n/** \"Not an element\" decisions, by {@link decisionKey}. */\nconst DECISIONS_FILE = \"decisions.json\";\n\ninterface NotElementDecision {\n file: string | null;\n symbol: string;\n label?: string;\n reason: string;\n /** `rejected`: the agent passed it in `reject`. `unstaged`: extraction staged it and it was unstaged. */\n how: \"rejected\" | \"unstaged\";\n changeset: string;\n /**\n * The changeset it came from. An `unstaged` decision lasts only while that changeset is staged\n * (discarding or landing it drops the decision); a `rejected` one lasts until cleared.\n */\n changesetId?: string;\n at: string;\n}\n\ninterface DecisionsFile {\n version: 1;\n notElements: Record<string, NotElementDecision>;\n}\n\n/** The cards of the last run that staged nothing, so made no changeset ({@link StoredCards.pending}). */\nconst PENDING_FILE = \"pending.json\";\n\nconst KEEP_FILES = new Set([DESCRIPTIONS_FILE, DECISIONS_FILE, PENDING_FILE]);\n\nfunction extractDir(projectRoot: string): string {\n return path.join(projectRoot, \".dr\", \"analyzers\", \"extract\");\n}\n\nfunction cardsPath(projectRoot: string, changesetId: string): string {\n return path.join(extractDir(projectRoot), `${changesetId.replace(/[^\\w.-]/g, \"_\")}.json`);\n}\n\n/**\n * Whether a changeset is one codebase_extract stages into: it has the extraction's record (its\n * cards file, which a run or a reject writes, adopted waiting cards included), or, given its name,\n * it is the changeset the waiting cards of a run that staged nothing name.\n */\nexport async function isExtractionChangeset(projectRoot: string, changesetId: string, changesetName?: string): Promise<boolean> {\n const stored = await readJson<StoredCards>(cardsPath(projectRoot, changesetId));\n if (stored && !stored.pending && stored.changesetId === changesetId) return true;\n if (!changesetName) return false;\n const pending = await readJson<StoredCards>(path.join(extractDir(projectRoot), PENDING_FILE));\n return !!pending?.pending && pending.changesetName === changesetName;\n}\n\n/** A catalog check by triple id (`layer.type.predicate.layer.type`). */\nfunction hasTriple(id: string): boolean {\n const parts = id.split(\".\");\n if (parts.length !== 5) return false;\n return getValidRelationships(`${parts[0]}.${parts[1]}`, parts[2], `${parts[3]}.${parts[4]}`).length > 0;\n}\n\nfunction emptyChangeset(): Changeset {\n const now = new Date().toISOString();\n return new Changeset({ id: \"extract-preview\", name: \"extract\", created: now, modified: now, status: \"staged\", baseSnapshot: \"\", changes: [] });\n}\n\nfunction page<T>(items: T[], pageNumber: number, pageSize: number) {\n const pages = Math.ceil(items.length / pageSize);\n return {\n total: items.length,\n page: pageNumber,\n pageSize,\n pages,\n items: items.slice((pageNumber - 1) * pageSize, pageNumber * pageSize),\n };\n}\n\nfunction capped<T>(items: T[], limit = MAX_LISTED): { total: number; items: T[]; truncated?: true } {\n return items.length > limit ? { total: items.length, items: items.slice(0, limit), truncated: true } : { total: items.length, items };\n}\n\n/** How much of each card a page shows: all of it, shortened, or only what deciding needs. */\ntype CardDetail = \"full\" | \"shortened\" | \"compact\";\n\n/** Kinds whose reason is the same sentence on every card of the kind. */\nconst GENERIC_REASON: ReadonlySet<UndecidedKind> = new Set([\"no-rule\", \"narrowed\"]);\n\nfunction clip(text: string | undefined, max: number): string | undefined {\n if (!text) return text;\n return text.length > max ? `${text.slice(0, max - 3)}...` : text;\n}\n\nfunction cardAt<T extends UndecidedCard>(card: T, detail: CardDetail): Partial<T> {\n if (detail === \"full\") return card;\n const { reason, docstring, signature, decorators, candidates, qualifiedName, ...rest } = card;\n const open = candidates.length ? { candidates } : {};\n if (detail === \"shortened\") {\n return {\n ...rest,\n qualifiedName,\n ...open,\n ...(signature ? { signature: clip(signature, 80) } : {}),\n ...(docstring ? { docstring: clip(docstring, 120) } : {}),\n ...(decorators ? { decorators } : {}),\n ...(GENERIC_REASON.has(card.kind) ? {} : { reason }),\n } as Partial<T>;\n }\n return { ...rest, ...open, ...(card.kind === \"ambiguous\" || card.kind === \"needs-attributes\" ? { reason: clip(reason, 200) } : {}) } as Partial<T>;\n}\n\nconst PAGE_NOTES: Record<Exclude<CardDetail, \"full\">, string> = {\n shortened:\n \"Docstrings and signatures are shortened, and empty candidates and reasons that only name the card's kind left out, to keep this response small.\",\n compact: \"Docstrings, signatures, decorators, qualified names, empty candidates and most reasons are left out, to keep this response small.\",\n};\n\n/** How a response was fitted under the budget. */\ninterface PageFit {\n /** The cards' detail, when less than full, with a note saying what was left out. */\n detail?: Exclude<CardDetail, \"full\">;\n note?: string;\n /** The page was cut to its first `shown` cards; `readOn` says how to read the ones after. */\n shown?: number;\n readOn?: string;\n /** The lists other than the cards (candidate deletes, updates, retyped, recorded decisions) show at most this many items. */\n listLimit?: number;\n /** Nothing fitted: even this, the smallest response, is over the budget. */\n overBudget?: true;\n}\n\ntype CardPage = ReturnType<typeof page<UndecidedCard>>;\n\n/** How many items the other lists show, largest first, when they alone would fill the budget. */\nconst LIST_LIMITS = [MAX_LISTED, 20, 5, 0];\n\n/** The paging call that continues after a page cut to its first `shown` cards. */\nfunction cutInstruction(p: CardPage, shown: number): string {\n const next = (p.page - 1) * p.pageSize + shown;\n return (\n `call codebase_extract with page: ${Math.floor(next / shown) + 1} and pageSize: ${shown}` +\n `${next % shown ? \" (its first cards may repeat ones you have)\" : \"\"}`\n );\n}\n\n/**\n * The response with a page of cards, at the most detail that keeps it under the budget. The other\n * lists come first: when they alone would fill it, they are shortened (`listLimit`). Then the\n * cards: shortened, then compact, then the page cut short (`shown`, with `readOn`). When even one\n * compact card and empty lists don't fit, the smallest response is returned with `overBudget`.\n * `render` builds the whole response from the page's cards and how it fitted them.\n */\nfunction fitCards(cards: UndecidedCard[], p: CardPage, render: (items: Array<Partial<UndecidedCard>>, fit: PageFit) => Record<string, unknown>): Record<string, unknown> {\n const fits = (result: Record<string, unknown>) => Buffer.byteLength(compactJson(result), \"utf-8\") <= RESPONSE_BUDGET_BYTES;\n let lists: PageFit = {};\n let listsFit = false;\n for (const limit of LIST_LIMITS) {\n lists = limit < MAX_LISTED ? { listLimit: limit } : {};\n if (fits(render([], lists))) {\n listsFit = true;\n break;\n }\n }\n const compact = cards.map((c) => cardAt(c, \"compact\"));\n const smallest = (): Record<string, unknown> =>\n render(compact.slice(0, 1), {\n ...lists,\n ...(cards.length ? { detail: \"compact\", note: PAGE_NOTES.compact } : {}),\n ...(cards.length > 1 ? { shown: 1, readOn: cutInstruction(p, 1) } : {}),\n overBudget: true,\n });\n if (!listsFit) return smallest();\n let result = render(cards, lists);\n if (fits(result)) return result;\n for (const detail of [\"shortened\", \"compact\"] as const) {\n result = render(\n cards.map((c) => cardAt(c, detail)),\n { ...lists, detail, note: PAGE_NOTES[detail] }\n );\n if (fits(result)) return result;\n }\n for (let shown = compact.length - 1; shown >= 1; shown--) {\n result = render(compact.slice(0, shown), { ...lists, detail: \"compact\", note: PAGE_NOTES.compact, shown, readOn: cutInstruction(p, shown) });\n if (fits(result)) return result;\n }\n return smallest();\n}\n\n/** The response's notes on what fitting it left out, at its top level. */\nfunction fitNotes(fit: PageFit): Record<string, unknown> {\n return {\n ...(fit.listLimit !== undefined\n ? {\n listsShortened:\n `candidateDeletes, staged.updated, retyped and notElements.recorded list at most ${fit.listLimit} item(s) here, to keep the response small; ` +\n \"each total is the full count. Narrow the run with layers or since to list the rest.\",\n }\n : {}),\n ...(fit.overBudget ? { overBudget: `Even shortened, this response is over about ${RESPONSE_BUDGET_BYTES / 1024} KB.` } : {}),\n };\n}\n\n/** The undecided section of a response: the page, how it was fitted, and how to read on. */\nfunction undecidedSection(p: CardPage, items: Array<Partial<UndecidedCard>>, fit: PageFit, requestedPageSize: number, extra: Record<string, unknown> = {}): Record<string, unknown> {\n return {\n ...p,\n items,\n ...extra,\n ...(requestedPageSize > p.pageSize ? { pageSizeCapped: `pageSize ${requestedPageSize} was capped at ${p.pageSize}; use page: 2 and on for more.` } : {}),\n ...(fit.detail ? { detail: fit.detail, detailNote: `${fit.note} A smaller pageSize gives full cards.` } : {}),\n ...(fit.shown !== undefined\n ? { cut: `This page was cut to its first ${fit.shown} of ${p.items.length} cards to keep the response small. For the rest, ${fit.readOn}.` }\n : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Staging\n// ---------------------------------------------------------------------------\n\nfunction elementOfAdd(add: PlannedElement, now: string): Element {\n const element = new Element({\n id: generateUUID(),\n path: add.id,\n spec_node_id: `${add.layer}.${add.type}`,\n layer_id: add.layer,\n type: add.type,\n name: add.name,\n description: add.description,\n attributes: add.attributes,\n metadata: { created_at: now, updated_at: now, version: 1 },\n layer: add.layer,\n });\n if (add.sourceReference) element.setSourceReference(add.sourceReference);\n return element;\n}\n\n/** Adds whose attributes validate, and the rest as cards with what they lack. */\nasync function validateAdds(adds: PlannedElement[], project: string, now: string, hunks?: CodeChangesResult[\"hunks\"]) {\n const valid: Array<{ add: PlannedElement; element: Element }> = [];\n const invalid: UndecidedCard[] = [];\n const validator = new SchemaValidator();\n const byLayer = new Map<string, Array<{ add: PlannedElement; element: Element }>>();\n for (const add of adds) {\n const list = byLayer.get(add.layer) ?? byLayer.set(add.layer, []).get(add.layer)!;\n list.push({ add, element: elementOfAdd(add, now) });\n }\n for (const [layerName, items] of byLayer) {\n const layer = new Layer(layerName);\n for (const item of items) layer.addElement(item.element);\n const result = await validator.validateLayer(layer);\n const errors = new Map<string, string[]>();\n for (const e of result.errors) {\n if (!e.elementId) continue;\n (errors.get(e.elementId) ?? errors.set(e.elementId, []).get(e.elementId)!).push(e.message);\n }\n for (const item of items) {\n const errs = errors.get(item.add.id);\n if (errs?.length) invalid.push(needsAttributesCard(item.add, project, errs, hunks));\n else valid.push(item);\n }\n }\n return { valid, invalid };\n}\n\n/** The element as the changeset currently has it, in the on-disk shape. */\nasync function currentSnapshot(model: Model, graph: ChangesetGraph, changeset: Changeset, id: string, layer: string) {\n const element = graph.getElement(id);\n if (element && element.status !== \"unchanged\") {\n const changes = (changeset.changes as StagedChange[]).filter(\n (c) => (c.type === \"add\" || c.type === \"update\") && c.after && graph.resolve(c.elementId) === id\n );\n const last = changes[changes.length - 1];\n if (last?.after) return { snapshot: structuredClone(last.after), stagedAdd: element.status === \"added\" ? changes.find((c) => c.type === \"add\") : undefined };\n }\n const base = (await model.getBaseLayer(layer))?.getElement(id);\n return base ? { snapshot: structuredClone(base.toJSON() as unknown as Record<string, unknown>), stagedAdd: undefined } : null;\n}\n\nfunction patched(snapshot: Record<string, unknown>, update: PlannedUpdate, now: string): Record<string, unknown> {\n const after = structuredClone(snapshot);\n for (const [field, value] of Object.entries(update.fields)) {\n if (field === \"source_reference\") setStagedSourceReference(after, value as SourceReference);\n else if (field.startsWith(\"attributes.\")) {\n after.attributes = { ...((after.attributes as Record<string, unknown>) ?? {}), [field.slice(\"attributes.\".length)]: value };\n } else after[field] = value;\n }\n const metadata = after.metadata as Record<string, unknown> | undefined;\n if (metadata) after.metadata = { ...metadata, updated_at: now };\n return after;\n}\n\nfunction relationshipChange(r: PlannedRelationship): Omit<StagedChange, \"sequenceNumber\"> {\n return {\n type: \"relationship-add\",\n elementId: `${r.source}::${r.predicate}::${r.target}`,\n layerName: r.sourceLayer,\n after: {\n source: r.source,\n target: r.target,\n predicate: r.predicate,\n layer: r.sourceLayer,\n ...(r.targetLayer !== r.sourceLayer ? { targetLayer: r.targetLayer } : {}),\n category: \"structural\",\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Result\n// ---------------------------------------------------------------------------\n\nfunction byLayer(adds: PlannedElement[], updates: PlannedUpdate[], relationships: PlannedRelationship[]) {\n const out: Record<string, { adds: number; updates: number; relationships: number }> = {};\n const at = (layer: string) => (out[layer] ??= { adds: 0, updates: 0, relationships: 0 });\n for (const a of adds) at(a.layer).adds++;\n for (const u of updates) at(u.layer).updates++;\n for (const r of relationships) at(r.sourceLayer).relationships++;\n return Object.fromEntries(Object.entries(out).sort(([a], [b]) => a.localeCompare(b)));\n}\n\nfunction notElementsResult(\n decisions: DecisionsFile,\n skipped: number,\n recorded: Array<{ symbol: string; file: string | null; how: NotElementDecision[\"how\"] }>,\n cleared: number,\n listLimit = MAX_LISTED\n) {\n const total = Object.keys(decisions.notElements).length;\n if (!total && !skipped && !recorded.length && !cleared) return {};\n return {\n notElements: {\n total,\n skipped,\n ...(recorded.length ? { recorded: capped(recorded, listLimit) } : {}),\n ...(cleared ? { cleared } : {}),\n note: \"Symbols decided not to be elements (rejected, or unstaged after this tool staged them). Runs leave them out; clearRejected forgets them.\",\n },\n };\n}\n\n/** Verify mode, the card step: stage cards as the code names them, never as the plan does. */\nfunction verifyCardStep(undecidedPages: number, readOn?: string): string {\n return (\n \"Stage the element cards with model_add, named after the card's symbol (the card's name when it has one), never the plan's element, and never copy plan elements here: \" +\n 'a layer and type from its candidates or hint, sourceFile = file, sourceSymbol = symbol, sourceProvenance: \"extracted\". ' +\n `Ask the user about cards you can't place, in one short list. ${readFurther(undecidedPages, readOn)}`\n );\n}\n\n/** Verify mode, after verify: the plan lands, not the as-built changeset. */\nfunction verifyLandStep(plan: { id: string; name: string }, why = \"\"): string {\n return (\n `After verify, the plan '${plan.name}' lands (changeset_commit when the user asks), not this changeset: discard this one or keep it as a record. ` +\n `Landing it first drifts the plan's base, so the plan would need force. Call changeset_activate with \"${plan.id}\" to resume the plan${why}.`\n );\n}\n\n/**\n * Verify mode with nothing to stage or decide: no as-built changeset exists, so the plan is\n * verified against the model, with extraction's blind spots applied.\n */\nfunction verifyNothingSteps(plan: { id: string; name: string }, since: string): string[] {\n return [\n `Nothing in the range since ${since} is observable to extraction or differs from the model, so no as-built changeset was created: there is none to verify against. '${plan.name}' is still active.`,\n `Call changeset_verify with planned: \"${plan.id}\" and against: {base: true, extracted: true}: it compares the plan with the model, and what extraction can't see is unverifiable rather than missing.`,\n ];\n}\n\n/** How to read the cards after this page: the cut's paging call when the page was cut. */\nfunction readFurther(undecidedPages: number, readOn?: string): string {\n return readOn\n ? `This page was cut to keep the response small: for the cards after it, ${readOn}, and page on with that pageSize.`\n : `Read further pages with page: 2 and on (${undecidedPages} in all).`;\n}\n\nfunction nextSteps(\n changeset: { id: string; name: string },\n previous: { id: string; name: string } | null,\n undecidedPages: number,\n plan: Pick<ElementPlan, \"candidateDeletes\" | \"retyped\">,\n changedCards = 0,\n since?: string,\n readOn?: string\n): string[] {\n const steps = [\n `The as-built changeset '${changeset.name}' is active: model_add, model_update, model_delete and relationship_add stage into it. Nothing reaches the base model until the user lands it.`,\n ];\n if (changedCards > 0) {\n steps.push(\n `${changedCards} card(s) have changedInRange: their lines are new or changed in the range, so they come first. The rest are symbols in the same files that the range didn't touch.`\n );\n }\n // A since run with a plan active before it is the verify workflow: this changeset is the\n // as-built side the plan is checked against, not a change to land.\n const verify = !!since && !!previous;\n const rerun = `codebase_extract again with changeset: \"${changeset.name}\"${since ? `, since: \"${since}\"` : \"\"}`;\n if (undecidedPages > 0) {\n steps.push(\n verify\n ? verifyCardStep(undecidedPages, readOn)\n : \"Decide the undecided cards: for each one that is a model element, call model_add with a layer and type from its candidates \" +\n \"(or its hint; spec_type says what a type needs), a name (the card's name when it has one), sourceFile = file, sourceSymbol = symbol and sourceProvenance: \\\"extracted\\\". \" +\n readFurther(undecidedPages, readOn),\n \"For cards that are not elements, call codebase_extract with reject: [{card: cardId, reason}] so later runs leave them out.\",\n verify\n ? `Call ${rerun} for their relationships.`\n : `Then call ${rerun} (it keeps that run's since and layers). It finds your elements by their source reference and stages the relationships the edge mapping gives them.`\n );\n }\n if (plan.candidateDeletes.length) {\n steps.push(\n \"Check candidateDeletes: call model_delete only for elements whose code is really gone (replacedBy names the element staged for a renamed file). \" +\n \"reference-never-matched means the element's reference was wrong before the range: the range removed nothing, so fix or delete the element without blaming the range.\"\n );\n }\n if (plan.retyped.length) {\n steps.push(\"retyped lists elements whose type the rules now decide differently. Leave them unless the rule is right; changing a type means adding the new element and deleting the old.\");\n }\n if (verify) {\n steps.push(\n `Then call changeset_verify with planned: \"${previous!.id}\" and against: {changesetId: \"${changeset.id}\"}.`,\n verifyLandStep(previous!)\n );\n return steps;\n }\n steps.push(\"Call changeset_brief to see what the changeset covers and its gaps, then review_open and give the user the link.\");\n if (previous) {\n steps.push(\n `'${previous.name}' was active before this call. To check it against this build, call changeset_verify with planned: \"${previous.id}\" and against: {changesetId: \"${changeset.id}\"}. Call changeset_activate with \"${previous.id}\" to resume it.`\n );\n } else {\n steps.push(\"The user lands the changeset with changeset_commit (they confirm in a dialog) or in the viewer.\");\n }\n return steps;\n}\n\n/**\n * Next steps for a run that staged nothing but left cards or candidate deletes: no changeset was\n * made, so the agent makes one before staging anything for them.\n */\nfunction pendingSteps(\n name: string,\n active: { id: string; name: string } | null,\n undecidedPages: number,\n plan: Pick<ElementPlan, \"candidateDeletes\">,\n changedCards: number,\n since?: string,\n readOn?: string\n): string[] {\n // A since run with a plan active is the verify workflow: the changeset to create is the\n // as-built side, and creating it deactivates the plan.\n const verify = !!since && !!active;\n const steps = [\n verify\n ? `Nothing was staged, so no as-built changeset was created and '${active!.name}' is still active. Before you stage a card or delete a candidate, call changeset_create with name: \"${name}\" ` +\n `(it becomes active, so model_add and model_delete stage into it and not into the plan).`\n : `Nothing was staged, so no changeset was created or activated. Before you model a card or delete a candidate, call changeset_create with name: \"${name}\" ` +\n `(it becomes active, and model_add and model_delete stage into it); without it they would ${active ? `stage into '${active.name}'` : \"write the base model\"}.`,\n ];\n if (changedCards > 0) {\n steps.push(`${changedCards} card(s) have changedInRange: their lines are new or changed in the range, so they come first. The rest are symbols in the same files that the range didn't touch.`);\n }\n if (undecidedPages > 0) {\n steps.push(\n verify\n ? verifyCardStep(undecidedPages, readOn)\n : \"For each card that is a model element, call model_add (into that changeset) with a layer and type from its candidates (or its hint), a name (the card's name when it has one), \" +\n `sourceFile = file, sourceSymbol = symbol and sourceProvenance: \"extracted\". ${readFurther(undecidedPages, readOn)}`,\n \"For cards that are not elements, call codebase_extract with reject: [{card: cardId, reason}] so later runs leave them out; that needs no changeset.\",\n verify\n ? `Call codebase_extract again with changeset: \"${name}\", since: \"${since}\" for their relationships.`\n : `After adding elements, call codebase_extract with changeset: \"${name}\"${since ? `, since: \"${since}\"` : \"\"}: it keeps this run's since and layers, and stages the relationships the edge mapping gives them.`\n );\n }\n if (plan.candidateDeletes.length) {\n steps.push(\n \"Check candidateDeletes: call model_delete (into that changeset) only for elements whose code is really gone. \" +\n \"reference-never-matched means the element's reference was wrong before the range: the range removed nothing.\"\n );\n }\n if (verify) {\n steps.push(\n `Then call changeset_verify with planned: \"${active!.id}\" and against: {changesetId: \"${name}\"}.`,\n verifyLandStep(active!, \" (changeset_create deactivated it)\"),\n `If no card is an element and nothing is deleted, there is no as-built changeset to verify against: call changeset_verify with planned: \"${active!.id}\" and against: {base: true, extracted: true} instead.`\n );\n return steps;\n }\n steps.push(\"If none of these need modelling now, there is nothing to land and nothing to clean up.\");\n return steps;\n}\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_BUDGET_MS = 100_000;\nconst NARROW = \"Narrow the run with layers, or with since (a git ref), and call codebase_extract again\";\n\nfunction sameLayers(a: string[] | null, b: string[] | null): boolean {\n return JSON.stringify([...(a ?? [])].sort()) === JSON.stringify([...(b ?? [])].sort());\n}\n\nasync function readJson<T>(file: string): Promise<T | null> {\n try {\n return JSON.parse(await readFile(file, \"utf-8\")) as T;\n } catch {\n return null;\n }\n}\n\n/** Drop the cards files of changesets that are no longer staged. */\nasync function pruneCardFiles(projectRoot: string, manager: StagingAreaManager): Promise<void> {\n const dir = extractDir(projectRoot);\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n return;\n }\n const staged = new Set((await manager.list()).filter((c) => c.status === \"staged\").map((c) => c.id));\n for (const entry of entries) {\n if (!entry.endsWith(\".json\") || KEEP_FILES.has(entry)) continue;\n const stored = await readJson<StoredCards>(path.join(dir, entry));\n if (!stored || !staged.has(stored.changesetId)) await rm(path.join(dir, entry), { force: true });\n }\n}\n\n/** The staged changesets with an extraction run at this commit. */\nasync function runsAt(projectRoot: string, manager: StagingAreaManager, head: string): Promise<Changeset[]> {\n let entries: string[];\n try {\n entries = await readdir(extractDir(projectRoot));\n } catch {\n return [];\n }\n const out: Changeset[] = [];\n for (const entry of entries) {\n if (!entry.endsWith(\".json\") || KEEP_FILES.has(entry)) continue;\n const stored = await readJson<StoredCards>(path.join(extractDir(projectRoot), entry));\n if (!stored || stored.pending || stored.gitHead !== head || !stored.changesetId) continue;\n const changeset = await manager.load(stored.changesetId);\n if (changeset?.status === \"staged\") out.push(changeset);\n }\n return out;\n}\n\nasync function readDecisions(projectRoot: string): Promise<DecisionsFile> {\n const stored = await readJson<DecisionsFile>(path.join(extractDir(projectRoot), DECISIONS_FILE));\n return { version: 1, notElements: stored?.notElements && typeof stored.notElements === \"object\" ? stored.notElements : {} };\n}\n\nasync function writeDecisions(projectRoot: string, decisions: DecisionsFile): Promise<void> {\n await mkdir(extractDir(projectRoot), { recursive: true });\n await writeFile(path.join(extractDir(projectRoot), DECISIONS_FILE), JSON.stringify(decisions, null, 2), \"utf-8\");\n}\n\n/**\n * A piece of code a `reject` may name: a card of this extraction (this run's or an earlier one's),\n * a symbol it staged, or an element of its changeset that names code (staged now, or unstaged).\n */\ninterface Rejectable {\n file: string | null;\n symbol: string;\n label?: string;\n cardId?: string;\n qualifiedName?: string;\n elementId?: string;\n}\n\nfunction normFile(file: string | null | undefined): string | null {\n return file ? file.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\") : null;\n}\n\n/**\n * The code an extraction changeset's own extracted elements name: its staged adds, and the adds\n * unstaged from it. Only `extracted` provenance: an element someone wrote by hand (a planned one,\n * with a manual reference) is never a rejection target.\n */\nfunction changesetRejectables(changeset: Changeset | null, graph: ChangesetGraph | null): Rejectable[] {\n const out: Rejectable[] = [];\n for (const e of graph?.elements.values() ?? []) {\n if (e.status !== \"added\" || e.sourceReference?.provenance !== \"extracted\") continue;\n for (const l of e.sourceReference.locations ?? []) {\n if (l.symbol) out.push({ file: normFile(l.file), symbol: l.symbol, elementId: e.id });\n }\n }\n for (const t of changeset?.unstaged ?? []) {\n if (t.rewritten || t.change.type !== \"add\") continue;\n const ref = stagedSourceReference(t.change.after as Record<string, unknown> | undefined);\n if (ref?.provenance !== \"extracted\") continue;\n for (const l of ref.locations ?? []) {\n if (l.symbol) out.push({ file: normFile(l.file), symbol: l.symbol, elementId: t.change.elementId });\n }\n }\n return out;\n}\n\n/**\n * What a `reject` names, one symbol per entry, or a CLIError naming the entries it can't place.\n * An entry may be a cardId (of the last run, or an earlier run's card the agent has modelled\n * since), an element id the extraction staged, or a symbol (bare, file#symbol or qualified name)\n * that only one of those has.\n */\nfunction cardsToReject(\n stored: StoredCards | null,\n fromChangeset: Rejectable[],\n changesetName: string,\n refs: Array<{ card: string; reason: string }>\n): Array<{ file: string | null; symbol: string; label?: string; reason: string }> {\n const known: Rejectable[] = [\n ...(stored?.cards ?? []).map((c) => ({ file: c.file, symbol: c.symbol, label: c.label, cardId: c.cardId, qualifiedName: c.qualifiedName })),\n ...(stored?.earlierCards ?? []).map((c) => ({ file: c.file, symbol: c.symbol, label: c.label, cardId: c.cardId, qualifiedName: c.qualifiedName })),\n ...(stored?.staged ?? []).map((s) => ({ file: s.file, symbol: s.symbol, label: s.label, elementId: s.id })),\n ...fromChangeset,\n ];\n if (!known.length) {\n throw new CLIError(`No cards recorded for '${changesetName}' to reject from`, ErrorCategory.USER, [\n \"Call codebase_extract first, then pass the cardId (or symbol) of each card that is not an element\",\n ]);\n }\n const found: Array<{ file: string | null; symbol: string; label?: string; reason: string }> = [];\n const unknown: string[] = [];\n const ambiguous: string[] = [];\n // The same symbol can be known several ways (a card, then the element staged for it).\n const distinctSymbols = (matches: Rejectable[]): Rejectable[] => {\n const bySymbol = new Map<string, Rejectable>();\n for (const m of matches) {\n const key = decisionKey(m.file, m.symbol);\n const seen = bySymbol.get(key);\n if (!seen || (!seen.label && m.label)) bySymbol.set(key, m);\n }\n return [...bySymbol.values()];\n };\n for (const ref of refs) {\n // An element id names the element: every symbol it names (one per source location).\n const ofElement = known.filter((k) => k.elementId === ref.card);\n if (ofElement.length) {\n for (const d of distinctSymbols(ofElement)) found.push({ file: d.file, symbol: d.symbol, label: d.label, reason: ref.reason });\n continue;\n }\n const byCard = known.filter((k) => k.cardId === ref.card);\n const matches = byCard.length\n ? byCard\n : known.filter((k) => k.symbol === ref.card || `${k.file ?? \"\"}#${k.symbol}` === ref.card || k.qualifiedName === ref.card);\n const distinct = distinctSymbols(matches);\n if (distinct.length === 1) found.push({ file: distinct[0].file, symbol: distinct[0].symbol, label: distinct[0].label, reason: ref.reason });\n else if (distinct.length > 1) {\n ambiguous.push(`${ref.card} (${distinct.map((d) => d.cardId ?? `${d.file ?? \"\"}#${d.symbol}`).join(\", \")})`);\n } else unknown.push(ref.card);\n }\n if (unknown.length || ambiguous.length) {\n const parts = [\n ...(unknown.length ? [`not among the cards or staged symbols of '${changesetName}': ${unknown.join(\", \")}`] : []),\n ...(ambiguous.length ? [`names more than one card: ${ambiguous.join(\"; \")}`] : []),\n ];\n throw new CLIError(`Can't reject: ${parts.join(\"; \")}. Nothing was recorded`, ErrorCategory.USER, [\n \"Pass the cardId (or file#symbol) of a card, or the id of an element this extraction staged\",\n ]);\n }\n return found;\n}\n\n/** Drop decisions: all, or those whose key, symbol or file#symbol is listed. Returns how many. */\nfunction clearDecisions(decisions: DecisionsFile, which: true | string[]): number {\n let n = 0;\n for (const [key, d] of Object.entries(decisions.notElements)) {\n if (which === true || which.some((w) => w === key || w === d.symbol || w === `${d.file ?? \"\"}#${d.symbol}`)) {\n delete decisions.notElements[key];\n n++;\n }\n }\n return n;\n}\n\nexport function createCodebaseExtractHandler(deps: CodebaseToolDeps = defaultCodebaseToolDeps) {\n return async function codebaseExtractHandler(args: CodebaseExtractArgs, context?: McpToolContext): Promise<CallToolResult> {\n return runTool(async () => {\n const startedAt = Date.now();\n const deadline = startedAt + (deps.budgetMs ?? DEFAULT_BUDGET_MS);\n const model = await loadModel(args.rootPath);\n const { projectRoot, codebaseRoot } = await canonicalRoots(model);\n\n const argLayers = args.layers?.length ? [...new Set(args.layers)] : undefined;\n const unknownLayers = (argLayers ?? []).filter((l) => !isValidLayer(l));\n if (unknownLayers.length) {\n throw new CLIError(`Unknown layer${unknownLayers.length > 1 ? \"s\" : \"\"}: ${unknownLayers.join(\", \")}`, ErrorCategory.USER, [\n `Use canonical layer names: ${formatValidOptions(getAllLayerIds())}`,\n ]);\n }\n\n const { analyzer, freshness, index: indexJudgement } = await requireFreshIndex(projectRoot, codebaseRoot, deps, \"codebase_extract\", {\n uncommittedEdits: true,\n });\n const head = freshness.currentGitHead;\n\n const manager = new StagingAreaManager(model.rootPath, model);\n const pageSize = args.pageSize ?? DEFAULT_PAGE_SIZE;\n const effectivePageSize = Math.min(pageSize, MAX_PAGE_SIZE);\n const baseModified = model.manifest.modified;\n const paging = (args.page ?? 1) > 1;\n // A call that only rejects cards or clears decisions records them and runs nothing.\n const decisionsOnly = !paging && (!!args.reject?.length || args.clearRejected !== undefined);\n\n // The changeset: the one named; else, for a page or decisions call, the active extraction\n // changeset (it has a cards file); else the default name for this commit (and range).\n let name = args.changeset ?? \"\";\n let changeset: Changeset | null = args.changeset ? await manager.load(args.changeset) : null;\n if (!args.changeset && (paging || decisionsOnly)) {\n const activeId = await manager.getActiveId();\n const active = activeId ? await manager.load(activeId) : null;\n if (active?.status === \"staged\" && existsSync(cardsPath(projectRoot, active.id!))) {\n changeset = active;\n name = active.name;\n } else {\n // The extraction changeset isn't the active one (the agent switched back to its plan):\n // the run at this commit into a staged changeset, when there is only one. With several,\n // guessing could reject (and unstage) from the wrong one, so the call is refused.\n const runs = await runsAt(projectRoot, manager, head);\n if (runs.length === 1) {\n changeset = runs[0];\n name = runs[0].name;\n } else if (runs.length > 1) {\n throw new CLIError(\n `Several extraction changesets have runs at this commit (${runs.map((r) => `'${r.name}'`).sort().join(\", \")}), and none is active`,\n ErrorCategory.USER,\n [\"Pass changeset with the name of the one you mean\"]\n );\n }\n }\n }\n // The last run that staged nothing made no changeset; its cards wait under its name until\n // that changeset exists (the agent creates it to stage its decisions), which adopts them.\n // Cards read at another commit are stale: not adopted (their since would be another run's),\n // and removed under the lock below.\n const pendingRecord = await readJson<StoredCards>(path.join(extractDir(projectRoot), PENDING_FILE));\n const pending = pendingRecord?.pending && pendingRecord.gitHead === head ? pendingRecord : null;\n const stalePending = !!pendingRecord?.pending && pendingRecord.gitHead !== head;\n const pendingFor = (n: string | undefined) => (pending && n && pending.changesetName === n ? pending : null);\n let stored = changeset ? await readJson<StoredCards>(cardsPath(projectRoot, changeset.id!)) : null;\n stored ??= pendingFor(changeset?.name ?? args.changeset);\n if (\n !args.changeset &&\n (paging || decisionsOnly) &&\n pending &&\n (!changeset || !stored || stored.createdAt < pending.createdAt)\n ) {\n // A page or decisions call after a run that made no changeset (later than the active\n // extraction changeset's last run): that run's cards, in the changeset of its name once the\n // agent has created it.\n const named = await manager.load(pending.changesetName);\n changeset = named?.status === \"staged\" ? named : null;\n name = pending.changesetName;\n stored = pending;\n }\n\n // A run or page into an extraction changeset (or the cards waiting for it) keeps its run's\n // since and layers; a call that names others is refused.\n let since = args.since;\n let layers = argLayers;\n if (stored && (changeset ? changeset.status === \"staged\" : !!stored.pending) && !decisionsOnly) {\n const conflicts: string[] = [];\n if (args.since !== undefined && args.since !== (stored.since ?? undefined)) {\n conflicts.push(`since: ${args.since} (its run had since: ${stored.since ?? \"none\"})`);\n }\n if (argLayers && !sameLayers(stored.layers, argLayers)) {\n conflicts.push(`layers: ${argLayers.join(\", \")} (its run had layers: ${stored.layers?.join(\", \") ?? \"all\"})`);\n }\n if (conflicts.length) {\n throw new CLIError(`'${stored.changesetName}' holds another run's extraction: this call names ${conflicts.join(\" and \")}`, ErrorCategory.USER, [\n \"Leave since and layers out to use that run's\",\n \"Or pass another changeset name for a run with these arguments\",\n ]);\n }\n since = stored.since ?? undefined;\n layers = stored.layers ?? undefined;\n }\n\n // The scope: every file, or the files changed since a ref (a run, or a default name to find).\n let changes: CodeChangesResult | null = null;\n if (since && (!(paging || decisionsOnly) || (!changeset && !stored))) changes = await (deps.codeChanges ?? codeChangesSince)(codebaseRoot, since);\n\n if (!changeset && !args.changeset && !stored?.pending) {\n // A whole-codebase run and a `since` run at the same commit are different changesets. A\n // range with no commits (only uncommitted edits) is named for the working tree.\n const defaultName = !changes\n ? `extract-${head.slice(0, 7)}`\n : changes.base === head\n ? `extract-${head.slice(0, 7)}+worktree`\n : `extract-${changes.base.slice(0, 7)}..${head.slice(0, 7)}`;\n name = defaultName;\n changeset = await manager.load(name);\n // A default name already landed (or discarded) at this commit: take the next free one.\n for (let n = 2; changeset && changeset.status !== \"staged\"; n++) {\n name = `${defaultName}-${n}`;\n changeset = await manager.load(name);\n }\n stored = (changeset ? await readJson<StoredCards>(cardsPath(projectRoot, changeset.id!)) : null) ?? pendingFor(name);\n }\n if (changeset && changeset.status !== \"staged\") {\n throw new CLIError(`Changeset '${changeset.name}' is ${changeset.status} and can't take the extraction`, ErrorCategory.USER, [\n \"Pass another name in changeset\",\n ]);\n }\n\n const backend = paging || decisionsOnly ? null : await deps.getAnalyzer(analyzer);\n if (!paging && !decisionsOnly) {\n if (!backend) throw analyzerNotFoundError(analyzer);\n if (!backend.extract) {\n throw new CLIError(`The ${analyzer} analyzer can't extract (it has no Tier-0 rules)`, ErrorCategory.USER);\n }\n }\n\n // One call per project at a time, from reading the decisions and the model to staging.\n await mkdir(extractDir(projectRoot), { recursive: true });\n const lock = new FileLock(path.join(extractDir(projectRoot), \"run\"));\n try {\n await lock.acquire({ timeout: 2000, staleLockThreshold: (deps.budgetMs ?? DEFAULT_BUDGET_MS) + 60_000 });\n } catch {\n throw new CLIError(\"Another codebase_extract run is in progress for this project\", ErrorCategory.USER, [\n \"Wait for it to finish, then call codebase_extract again\",\n ]);\n }\n try {\n // Decisions, read under the lock: drop inferred ones whose changeset is gone, then what\n // this call clears, then what it rejects.\n if (stalePending) {\n const again = await readJson<StoredCards>(path.join(extractDir(projectRoot), PENDING_FILE));\n if (again?.pending && again.gitHead !== head) await rm(path.join(extractDir(projectRoot), PENDING_FILE), { force: true });\n }\n const decisions = await readDecisions(projectRoot);\n const stagedIds = new Set((await manager.list()).filter((c) => c.status === \"staged\").map((c) => c.id));\n let pruned = false;\n for (const [key, d] of Object.entries(decisions.notElements)) {\n if (d.how === \"unstaged\" && !(d.changesetId && stagedIds.has(d.changesetId))) {\n delete decisions.notElements[key];\n pruned = true;\n }\n }\n const recordedNow: Array<{ symbol: string; file: string | null; how: NotElementDecision[\"how\"] }> = [];\n let cleared = 0;\n if (args.clearRejected) cleared = clearDecisions(decisions, args.clearRejected);\n // What a reject names that is staged in the extraction changeset now: unstaged below, after\n // recording. Only a changeset this extraction stages into (it has cards, or adopted the\n // waiting ones) is touched, and in it only extracted elements.\n const toUnstage = new Map<string, string>();\n const inBase: string[] = [];\n const keptElements: Array<{ id: string; alsoNames: string[] }> = [];\n if (args.reject?.length) {\n const now = new Date().toISOString();\n const extractionChangeset = changeset && stored ? changeset : null;\n const graph = extractionChangeset ? await ChangesetGraph.build(model, extractionChangeset) : null;\n const rejected = cardsToReject(stored, changesetRejectables(extractionChangeset, graph), changeset?.name ?? stored?.changesetName ?? name, args.reject);\n const rejectedKeys = new Map<string, string>();\n for (const card of rejected) {\n const key = decisionKey(card.file, card.symbol);\n rejectedKeys.set(key, card.symbol);\n decisions.notElements[key] = {\n file: card.file,\n symbol: card.symbol,\n ...(card.label ? { label: card.label } : {}),\n reason: card.reason,\n how: \"rejected\",\n changeset: changeset?.name ?? stored?.changesetName ?? name,\n ...(changeset ? { changesetId: changeset.id! } : {}),\n at: now,\n };\n recordedNow.push({ symbol: card.symbol, file: card.file, how: \"rejected\" });\n }\n // Elements that name a rejected symbol. One the changeset adds is unstaged when every\n // symbol it names is rejected; one that also names other code stays, and is listed. One\n // the base model has stays (rejecting is about what extraction stages, not what the\n // model says).\n const stagedByExtraction = new Map<string, string>();\n for (const st of stored?.staged ?? []) {\n const key = decisionKey(st.file, st.symbol);\n if (rejectedKeys.has(key)) stagedByExtraction.set(st.id, key);\n }\n for (const e of graph?.elements.values() ?? []) {\n if (e.status === \"deleted\") continue;\n const keys = new Set(\n (e.sourceReference?.locations ?? []).filter((l) => l.symbol).map((l) => decisionKey(normFile(l.file), l.symbol!))\n );\n const hit = stagedByExtraction.get(e.id) ?? [...keys].find((k) => rejectedKeys.has(k));\n if (!hit) continue;\n if (!stagedByExtraction.has(e.id) && e.sourceReference?.provenance !== \"extracted\") continue;\n if (e.status !== \"added\" || e.alreadyInBase) {\n inBase.push(e.id);\n continue;\n }\n const others = [...keys].filter((k) => !rejectedKeys.has(k));\n if (others.length) keptElements.push({ id: e.id, alsoNames: others });\n else toUnstage.set(e.id, rejectedKeys.get(hit)!);\n }\n }\n if (pruned || cleared || recordedNow.length) await writeDecisions(projectRoot, decisions);\n const notElementKeys = new Set(Object.keys(decisions.notElements));\n\n // Unstage what was rejected while staged, with the relationships staged for it, so the\n // decision holds now and not only once the changeset lands.\n const unstaged: Array<{ id: string; symbol: string; changes: number }> = [];\n const unstageFailed: Array<{ id: string; error: string }> = [];\n for (const [id, symbol] of toUnstage) {\n const result = await changesetUnstageHandler({ elementId: id, changesetId: changeset!.id!, rootPath: args.rootPath });\n const body = JSON.parse((result.content[0] as { text: string }).text) as { unstaged?: unknown[]; error?: string; message?: string };\n if (result.isError) unstageFailed.push({ id, error: body.error ?? body.message ?? \"unstage failed\" });\n else if (body.unstaged?.length) unstaged.push({ id, symbol, changes: body.unstaged.length });\n }\n if (unstaged.length && stored && changeset) {\n // The record of what extraction staged no longer holds what was unstaged. Waiting cards\n // become this changeset's record here (adopted, as a run would adopt them).\n const gone = new Set(unstaged.map((u) => u.id));\n const { pending: wasPending, ...rest } = stored;\n const updated = (stored.updated ?? []).filter((u) => !gone.has(u.id));\n stored = {\n ...rest,\n changesetId: changeset.id!,\n changesetName: changeset.name,\n staged: (stored.staged ?? []).filter((s) => !gone.has(s.id)),\n ...(updated.length ? { updated } : { updated: undefined }),\n };\n await writeFile(cardsPath(projectRoot, changeset.id!), JSON.stringify(stored), \"utf-8\");\n if (wasPending) await rm(path.join(extractDir(projectRoot), PENDING_FILE), { force: true });\n }\n if (unstaged.length) await reloadModel(args.rootPath);\n const rejectResult = {\n ...(unstaged.length\n ? {\n unstaged: {\n items: unstaged,\n note: `Rejected while staged: unstaged from '${changeset!.name}', with the relationships staged for them (changes counts both).`,\n },\n }\n : {}),\n ...(unstageFailed.length ? { unstageFailed } : {}),\n ...(inBase.length\n ? { inModel: { ids: [...new Set(inBase)], note: \"Already in the base model: rejecting doesn't remove them. model_delete them if they should go.\" } }\n : {}),\n ...(keptElements.length\n ? {\n kept: {\n items: keptElements,\n note: \"Still staged: each also names code that wasn't rejected (alsoNames). Unstage it with changeset_unstage, or drop the rejected location with model_update, if it should change.\",\n },\n }\n : {}),\n };\n\n if (decisionsOnly) {\n const rerunName = changeset?.name ?? stored?.changesetName;\n const rerun = rerunName ? `changeset: \"${rerunName}\"` : \"the arguments of the last run\";\n return jsonResult(\n {\n changeset: changeset ? { id: changeset.id, name: changeset.name } : null,\n ...notElementsResult(decisions, 0, recordedNow, cleared),\n ...rejectResult,\n message: unstaged.length\n ? `Recorded, and unstaged ${unstaged.length} element(s) it had staged; nothing was extracted.`\n : \"Recorded; nothing was extracted or staged.\",\n next: [`Call codebase_extract with ${rerun} to refresh the cards: it leaves out what is recorded, and says how many.`],\n },\n { compact: true }\n );\n }\n\n // Later pages: the last run's cards, marking any the agent has modelled since.\n if (paging) {\n if (!stored) {\n throw new CLIError(\n changeset ? `No cards recorded for '${changeset.name}'` : `No extraction changeset '${name}' yet`,\n ErrorCategory.USER,\n [\"Call codebase_extract without page first\"]\n );\n }\n const runName = changeset?.name ?? stored.changesetName;\n if (stored.gitHead !== head) {\n throw new CLIError(`The cards for '${runName}' were read at ${stored.gitHead.slice(0, 7)}; the code is now at ${head.slice(0, 7)}`, ErrorCategory.USER, [\n \"Call codebase_extract without page to extract again\",\n ]);\n }\n const graph = await ChangesetGraph.build(model, changeset ?? emptyChangeset());\n const modelledAt = new Map<string, string>();\n for (const e of graph.elements.values()) {\n if (e.status === \"deleted\") continue;\n for (const l of e.sourceReference?.locations ?? []) if (l.symbol) modelledAt.set(`${l.file}#${l.symbol}`, e.id);\n }\n const cards = stored.cards\n .filter((c) => !notElementKeys.has(decisionKey(c.file, c.symbol)))\n .map((c) => {\n const modelled = c.file ? modelledAt.get(`${c.file}#${c.symbol}`) : undefined;\n return modelled ? { ...c, modelled } : c;\n });\n const p = page(cards, args.page!, effectivePageSize);\n return jsonResult(\n fitCards(p.items, p, (items, fit) => ({\n changeset: changeset ? { id: changeset.id, name: changeset.name } : null,\n ...(changeset ? {} : { pending: `No changeset yet: the run that read these cards staged nothing. Call changeset_create with name: \"${runName}\" before staging.` }),\n ...fitNotes(fit),\n scope: { since: stored!.since, layers: stored!.layers ?? \"all\" },\n undecided: undecidedSection(p, items, fit, pageSize),\n ...notElementsResult(decisions, stored!.cards.length - cards.length, recordedNow, cleared, fit.listLimit),\n ...rejectResult,\n ...(stored!.baseModified !== baseModified\n ? { warning: \"The base model changed since these cards were read; call codebase_extract without page to refresh them.\" }\n : {}),\n ...(fit.readOn\n ? { next: `This page was cut to keep the response small: for the cards after it, ${fit.readOn}.` }\n : args.page! < p.pages\n ? { next: `Call codebase_extract with page: ${args.page! + 1} for the next cards.` }\n : {}),\n })),\n { compact: true }\n );\n }\n // Uncommitted source edits, deletes and renames the index hasn't seen, from the shared\n // freshness rule (judgeIndex, which honours deps.sourceEdits).\n const edited = indexJudgement.editedSince;\n\n // What the model has: the base, plus the extraction changeset's own changes when it exists.\n const before = await ChangesetGraph.build(model, changeset ?? emptyChangeset());\n const referenced = new Set<string>();\n const liveKeys = new Set<string>();\n const liveIds = new Set<string>();\n // The elements this changeset adds, by the symbols they name: a card the agent staged.\n const addedAt = new Map<string, string>();\n for (const e of before.elements.values()) {\n if (e.status === \"deleted\") continue;\n liveIds.add(e.id);\n for (const l of e.sourceReference?.locations ?? []) {\n const file = l.file?.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\");\n if (file) referenced.add(file);\n if (!l.symbol) continue;\n const key = decisionKey(file || null, l.symbol);\n liveKeys.add(key);\n if (e.status === \"added\" && !e.alreadyInBase && !addedAt.has(key)) addedAt.set(key, e.id);\n }\n }\n\n // Elements this tool staged into the changeset that the agent unstaged from it (the\n // changeset keeps a tombstone of the unstaged add): not elements, while it stays staged.\n const storedBefore = stored;\n const unstagedAdds = new Set(\n (changeset?.unstaged ?? []).filter((t) => !t.rewritten && t.change.type === \"add\").map((t) => t.change.elementId)\n );\n const stillStaged: StagedBySymbol[] = [];\n for (const st of storedBefore?.staged ?? []) {\n const key = decisionKey(st.file, st.symbol);\n if (liveIds.has(st.id) || liveKeys.has(key)) {\n stillStaged.push(st);\n } else if (unstagedAdds.has(st.id) && !decisions.notElements[key]) {\n decisions.notElements[key] = {\n file: st.file,\n symbol: st.symbol,\n label: st.label,\n reason: `${st.id} was staged by codebase_extract and then unstaged`,\n how: \"unstaged\",\n changeset: changeset!.name,\n changesetId: changeset!.id!,\n at: new Date().toISOString(),\n };\n notElementKeys.add(key);\n recordedNow.push({ symbol: st.symbol, file: st.file, how: \"unstaged\" });\n }\n }\n // Cards of earlier runs the agent has staged since (model_add with the card's file and\n // symbol): recorded with the element staged for them, so the record of what extraction\n // staged covers what came from its cards too (changeset_verify reads it).\n const recorded = new Set(stillStaged.map((st) => `${st.id} ${decisionKey(st.file, st.symbol)}`));\n for (const c of [...(storedBefore?.cards ?? []), ...(storedBefore?.earlierCards ?? [])]) {\n const key = decisionKey(c.file, c.symbol);\n const id = addedAt.get(key);\n if (!id || recorded.has(`${id} ${key}`)) continue;\n recorded.add(`${id} ${key}`);\n const element = before.getElement(id);\n stillStaged.push({ id, file: c.file, symbol: c.symbol, label: c.label, ...stagedAs(element?.name, element?.attributes) });\n }\n if (recordedNow.some((r) => r.how === \"unstaged\")) await writeDecisions(projectRoot, decisions);\n\n // With since: only code. DR's own folders are out already; leave out files that are not\n // source and that no element names (configs, docs, lockfiles).\n if (changes) {\n const drDirs = [path.join(projectRoot, \"documentation-robotics\"), path.join(projectRoot, \".dr\")]\n .map((d) => path.relative(codebaseRoot, d).split(path.sep).join(\"/\"))\n .filter((d) => d && !d.startsWith(\"..\"));\n changes = scopeChanges(changes, (f) => !inDirs(f, drDirs) && ((SOURCE_EXT.test(f) && !VENDOR_EXCLUDE.test(f)) || referenced.has(f)));\n }\n\n const checkFiles = new Set<string>();\n for (const e of before.elements.values()) {\n if (e.status === \"deleted\" || (layers && !layers.includes(e.layer))) continue;\n for (const l of e.sourceReference?.locations ?? []) {\n const file = l.file?.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\");\n if (file && l.symbol && (!changes || changes.changed.has(file))) checkFiles.add(file);\n }\n }\n\n let extraction: ExtractionGraph;\n try {\n extraction = await backend!.extract!(projectRoot, {\n codebaseRoot,\n ...(changes ? { files: changes.changed } : {}),\n checkFiles: [...checkFiles],\n deadline,\n });\n } catch (error) {\n if (error instanceof ExtractionTimeoutError) {\n throw new CLIError(`codebase_extract ran past its ${Math.round((deadline - startedAt) / 1000)} s budget ${error.stage}; nothing was staged`, ErrorCategory.USER, [NARROW]);\n }\n throw error;\n }\n\n const descriptionsFile = path.join(extractDir(projectRoot), DESCRIPTIONS_FILE);\n const extractedDescriptions = (await readJson<Record<string, string>>(descriptionsFile)) ?? {};\n const plan = planElements(extraction, before, {\n layers,\n changes,\n extractedDescriptions,\n notElements: notElementKeys,\n fileExists: (file) => existsSync(path.join(codebaseRoot, file)),\n fileText: (file) => {\n try {\n return readFileSync(path.join(codebaseRoot, file), \"utf-8\");\n } catch {\n return null;\n }\n },\n });\n\n const now = new Date().toISOString();\n const { valid, invalid } = await validateAdds(plan.adds, extraction.project, now, changes?.hunks);\n const adds = valid.map((v) => v.add);\n const undecided = sortUndecided(attributeChangedLines([...plan.undecided, ...invalid], changes?.hunks));\n const kept = new Set(adds);\n for (const add of plan.adds) {\n if (!kept.has(add)) {\n plan.elementOf.delete(add.symbol.qualifiedName);\n delete plan.descriptions[add.id];\n }\n }\n\n const elements = new Map<string, { layer: string; type: string }>();\n for (const e of before.elements.values()) if (e.status !== \"deleted\") elements.set(e.id, { layer: e.layer, type: e.type });\n for (const a of adds) elements.set(a.id, { layer: a.layer, type: a.type });\n const { relationships, alreadyPresent } = planRelationships(extraction, before, plan.elementOf, elements, hasTriple, layers);\n\n // Everything staged in one write: adds, updates (an update of an element this changeset\n // adds rewrites the add in place), relationships.\n const batch: Array<Omit<StagedChange, \"sequenceNumber\">> = [];\n const rewrites: Array<{ elementId: string; change: Omit<StagedChange, \"sequenceNumber\"> }> = [];\n for (const { add, element } of valid) {\n batch.push({ type: \"add\", elementId: add.id, layerName: add.layer, after: element.toJSON() as unknown as Record<string, unknown> });\n }\n const stagedUpdates: PlannedUpdate[] = [];\n for (const update of plan.updates) {\n const current = await currentSnapshot(model, before, changeset ?? emptyChangeset(), update.id, update.layer);\n if (!current) continue;\n const after = patched(current.snapshot, update, now);\n if (current.stagedAdd) {\n rewrites.push({\n elementId: current.stagedAdd.elementId,\n change: {\n type: \"add\",\n elementId: current.stagedAdd.elementId,\n layerName: current.stagedAdd.layerName,\n ...(current.stagedAdd.before !== undefined ? { before: current.stagedAdd.before } : {}),\n after,\n },\n });\n } else {\n batch.push({ type: \"update\", elementId: update.id, layerName: update.layer, before: current.snapshot, after });\n }\n stagedUpdates.push(update);\n }\n for (const r of relationships) batch.push(relationshipChange(r));\n\n const summary = {\n adds: adds.length,\n updates: stagedUpdates.length,\n relationships: relationships.length,\n cards: undecided.length,\n candidateDeletes: plan.candidateDeletes.length,\n };\n if (Date.now() > deadline) {\n throw new CLIError(\n `codebase_extract ran past its ${Math.round((deadline - startedAt) / 1000)} s budget before staging. It had planned ${summary.adds} adds, ` +\n `${summary.updates} updates and ${summary.relationships} relationships, with ${summary.cards} cards; nothing was staged`,\n ErrorCategory.USER,\n [NARROW]\n );\n }\n if (context?.signal?.aborted) {\n throw new CLIError(\"codebase_extract was cancelled before staging; nothing was staged\", ErrorCategory.USER);\n }\n\n // The changeset active before: the one active now, or (on a later run, when the extraction\n // changeset is already active) the one the first run replaced, while it is still staged.\n const activeId = await manager.getActiveId();\n let previousActive: { id: string; name: string } | null = null;\n if (activeId && activeId !== changeset?.id) {\n const prev = await manager.load(activeId);\n previousActive = { id: activeId, name: prev?.name ?? activeId };\n } else if (storedBefore?.previousActive) {\n const prev = await manager.load(storedBefore.previousActive.id);\n if (prev?.status === \"staged\") previousActive = { id: prev.id!, name: prev.name };\n }\n // The record keeps the plan the first run replaced: that is the plan this as-built side\n // verifies, even when a later run happens while another changeset is active. The next\n // steps verify against it too; the result's previousActive still says what this run replaced.\n let recordedPrevious = previousActive;\n if (storedBefore?.previousActive && storedBefore.previousActive.id !== previousActive?.id) {\n const first = await manager.load(storedBefore.previousActive.id);\n if (first?.status === \"staged\") recordedPrevious = { id: first.id!, name: first.name };\n }\n\n // A run makes a changeset only to stage into it: a run that stages nothing leaves its cards\n // and candidate deletes for the agent without creating or activating an empty changeset\n // (which would then sit in project_status as the next thing to resume).\n const stages = batch.length > 0 || rewrites.length > 0;\n const hasWork = stages || undecided.length > 0 || plan.candidateDeletes.length > 0;\n let created = false;\n let active = !!changeset && activeId === changeset.id;\n if (changeset ? hasWork : stages) {\n if (!changeset) {\n changeset = await manager.create(\n name,\n `As-built extraction of the code at ${head.slice(0, 7)}${since ? `, files changed since ${since}` : \"\"}. Staged by codebase_extract.`\n );\n created = true;\n }\n try {\n await manager.stageMany(changeset.id!, batch, rewrites);\n } catch (error) {\n // A changeset this run made and couldn't fill is not left behind.\n if (created) await manager.delete(changeset.id!).catch(() => undefined);\n throw error;\n }\n // Activate last, once staging has succeeded.\n if (activeId !== changeset.id) await manager.setActive(changeset.id!);\n active = true;\n await reloadModel(args.rootPath);\n if (Object.keys(plan.descriptions).length) {\n await writeFile(descriptionsFile, JSON.stringify({ ...extractedDescriptions, ...plan.descriptions }), \"utf-8\");\n }\n }\n // Cards earlier runs returned that this one doesn't (the agent modelled them), so reject\n // can still name them.\n const nowCards = new Set(undecided.map((c) => c.cardId));\n const earlierCards = new Map<string, EarlierCard>();\n for (const c of [...(storedBefore?.earlierCards ?? []), ...(storedBefore?.cards ?? [])]) {\n // The whole card (candidates, name, proposed), so verify can check type and name against it.\n if (!nowCards.has(c.cardId)) earlierCards.set(c.cardId, c);\n }\n // Updates extraction staged: earlier runs' while their change is still staged, merged with\n // this run's, one entry per element with the union of its fields and the value extraction\n // wrote for each (this run's wins), so verify can tell a later hand edit from it.\n const updatedFields = new Map<string, Map<string, unknown>>();\n for (const u of storedBefore?.updated ?? []) {\n const status = before.getElement(u.id)?.status;\n if (status !== \"updated\" && status !== \"added\") continue;\n updatedFields.set(u.id, new Map(u.fields.map((f) => [f, u.values && Object.prototype.hasOwnProperty.call(u.values, f) ? u.values[f] : undefined])));\n }\n for (const u of stagedUpdates) {\n const fields = updatedFields.get(u.id) ?? updatedFields.set(u.id, new Map()).get(u.id)!;\n for (const [f, value] of Object.entries(u.fields)) fields.set(f, structuredClone(value));\n }\n const updatedRecord = [...updatedFields].map(([id, fields]) => {\n const names = [...fields.keys()].sort();\n const values = Object.fromEntries(names.filter((f) => fields.get(f) !== undefined).map((f) => [f, fields.get(f)]));\n return { id, fields: names, ...(Object.keys(values).length ? { values } : {}) };\n });\n const candidateDeleteIds = [...new Set([...(storedBefore?.candidateDeletes ?? []), ...plan.candidateDeletes.map((d) => d.id)])];\n const accumulated = {\n ...(updatedRecord.length ? { updated: updatedRecord } : {}),\n ...(candidateDeleteIds.length ? { candidateDeletes: candidateDeleteIds } : {}),\n };\n const pendingPath = path.join(extractDir(projectRoot), PENDING_FILE);\n if (changeset) {\n const staged = [...stillStaged];\n for (const a of adds) {\n staged.push({\n id: a.id,\n file: a.symbol.card.file_path,\n symbol: sourceSymbolOf(a.symbol, extraction.project),\n label: a.symbol.card.label,\n ...stagedAs(a.name, a.attributes),\n });\n }\n const record: StoredCards = {\n changesetId: changeset.id!,\n changesetName: changeset.name,\n gitHead: head,\n since: since ?? null,\n layers: layers ?? null,\n baseModified,\n previousActive: recordedPrevious,\n createdAt: now,\n cards: undecided,\n staged,\n ...(earlierCards.size ? { earlierCards: [...earlierCards.values()] } : {}),\n ...accumulated,\n };\n await writeFile(cardsPath(projectRoot, changeset.id!), JSON.stringify(record), \"utf-8\");\n // Waiting cards this changeset now holds.\n if (pending?.changesetName === changeset.name) await rm(pendingPath, { force: true });\n } else if (undecided.length || plan.candidateDeletes.length) {\n const record: StoredCards = {\n changesetId: \"\",\n changesetName: name,\n gitHead: head,\n since: since ?? null,\n layers: layers ?? null,\n baseModified,\n previousActive,\n createdAt: now,\n cards: undecided,\n staged: [],\n ...(earlierCards.size ? { earlierCards: [...earlierCards.values()] } : {}),\n ...accumulated,\n pending: true,\n };\n await writeFile(pendingPath, JSON.stringify(record), \"utf-8\");\n } else if (pending?.changesetName === name) {\n await rm(pendingPath, { force: true });\n }\n await pruneCardFiles(projectRoot, manager);\n\n const cards = page(undecided, 1, effectivePageSize);\n const changedCards = undecided.filter((c) => c.changedInRange).length;\n const changesetRef = changeset ? { id: changeset.id!, name: changeset.name } : null;\n const verifyMode = !!since && !!recordedPrevious;\n const message = !hasWork\n ? verifyMode && !changeset\n ? `Nothing to stage: nothing in the range is observable to extraction or differs from the model. No as-built changeset was created; ${previousActive ? `'${previousActive.name}' is still active.` : `the plan is '${recordedPrevious!.name}'.`}`\n : changeset\n ? `Nothing more to stage: '${changeset.name}' already says what this code says.`\n : \"Nothing to stage: the model already says what this code says. No changeset was created or activated.\"\n : !changeset\n ? `Nothing to stage, so no changeset was created or activated. ${undecided.length} card(s)` +\n `${changedCards ? ` (${changedCards} changed in the range)` : \"\"} and ${plan.candidateDeletes.length} candidate delete(s) are left for you to decide; ` +\n `to stage any, first call changeset_create with name: \"${name}\".`\n : undefined;\n return jsonResult(\n fitCards(cards.items, cards, (items, fit) => ({\n changeset: changesetRef ? { ...changesetRef, created, active } : null,\n previousActive,\n ...(message ? { message } : {}),\n ...fitNotes(fit),\n ...(edited.length\n ? {\n warning:\n `${edited.length} source file(s) have uncommitted edits made after the index was taken, which this run may not have seen ` +\n `(${edited.slice(0, 5).join(\", \")}${edited.length > 5 ? \", ...\" : \"\"}). Re-index with codebase_index, then call codebase_extract again.`,\n }\n : {}),\n ...(changes?.hunksError\n ? {\n hunksWarning: `The range's changed lines couldn't be read (${changes.hunksError}), so no card says changedInRange; the cards are those of every changed file.`,\n }\n : {}),\n analyzer,\n // The shared judgement: `fresh-with-uncommitted-edits` when the warning above is given.\n index: describeIndex(freshness, indexJudgement),\n scope: {\n since: since ?? null,\n ...(changes ? { base: changes.base, changedFiles: changes.changed.size, deletedFiles: changes.deleted.size } : { files: \"all\" }),\n layers: layers ?? \"all\",\n },\n cards: { ...extraction.summary, needsAttributes: invalid.length },\n staged: {\n adds: adds.length,\n updates: stagedUpdates.length,\n relationships: relationships.length,\n byLayer: byLayer(adds, stagedUpdates, relationships),\n ...(stagedUpdates.length ? { updated: capped(stagedUpdates.map((u) => ({ id: u.id, fields: Object.keys(u.fields) })), fit.listLimit) } : {}),\n },\n unchanged: {\n elements: plan.unchanged,\n modelled: plan.modelled,\n relationships: alreadyPresent,\n rejected: plan.rejected,\n ...(plan.outsideLayers ? { outsideLayers: plan.outsideLayers } : {}),\n },\n candidateDeletes: {\n ...capped(plan.candidateDeletes, fit.listLimit),\n note: \"Not staged: deleting is left to you. Each has its evidence.\",\n },\n ...(plan.retyped.length ? { retyped: capped(plan.retyped, fit.listLimit) } : {}),\n ...notElementsResult(decisions, plan.skipped, recordedNow, cleared, fit.listLimit),\n undecided: undecidedSection(cards, items, fit, pageSize, changes ? { changedInRange: changedCards } : {}),\n tier1: \"not wired: cards Tier 0 can't decide come to you (docs/EXTRACTION_STRATEGY.md, B6)\",\n durationMs: Date.now() - startedAt,\n next: !hasWork\n ? verifyMode\n ? changesetRef\n ? nextSteps(changesetRef, recordedPrevious, 0, plan, 0, since)\n : verifyNothingSteps(recordedPrevious!, since!)\n : []\n : changesetRef\n ? nextSteps(changesetRef, recordedPrevious, cards.pages, plan, changedCards, since, fit.readOn)\n : pendingSteps(name, recordedPrevious, cards.pages, plan, changedCards, since, fit.readOn),\n })),\n { compact: true }\n );\n } finally {\n await lock.release().catch(() => undefined);\n }\n });\n };\n}\n\nexport const codebaseExtractHandler = createCodebaseExtractHandler();\n\nexport const codebaseExtractTool: McpToolDefinition<typeof inputSchema> = {\n name: \"codebase_extract\",\n description:\n \"Model the indexed code as an as-built changeset: Tier-0 rules decide what they can and those elements and \" +\n \"their relationships are staged; the rest come back as undecided cards (paged) for you to stage with model_add. \" +\n \"Stages only what differs from the model (matched by source file and symbol): new symbols are adds, changed ones \" +\n \"updates; elements whose code is gone are listed as candidateDeletes, not staged. since (a git ref) limits it to \" +\n \"files changed since then, for verifying a branch; cards whose lines the range changed say changedInRange and come first. \" +\n \"Code that is not an element goes in reject (with a reason): a card, or a symbol or element it staged, which is then \" +\n \"unstaged; kept until clearRejected, later runs leave them out. An element \" +\n \"it staged that you unstage from a changeset is also left out, but only while that changeset is staged: discarding or \" +\n \"landing it forgets that. A run or page into an extraction changeset keeps that run's since and layers. \" +\n \"The changeset (default extract-<sha>) is created and made active only when the run stages something; a run that only \" +\n \"leaves cards or candidate deletes creates nothing and says which changeset to create first. previousActive is the one \" +\n \"active before the first run. Needs a fresh index (codebase_index). Never writes the base model or commits.\",\n inputSchema,\n handler: codebaseExtractHandler,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["result", "byLayer", "now", "cards"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readIndexJob, startIndexJob } from "../../analyzers/index-job.js";
|
|
3
|
+
import { readSession, writeSession } from "../../analyzers/session-state.js";
|
|
4
|
+
import { CLIError, ErrorCategory } from "../../utils/errors.js";
|
|
5
|
+
import { jsonResult, loadModel, rootPathSchema, runTool } from "./shared.js";
|
|
6
|
+
import { analyzerNotFoundError, assessIndex, canonicalRoots, defaultCodebaseToolDeps, describeIndex, installSuggestions, notInstalledError, takeWorktreeSnapshot, WAIT_FOR_INDEX, writeWorktreeSnapshot } from "./codebase-shared.js";
|
|
7
|
+
const MAX_WAIT_SECONDS = 50, inputSchema = {
|
|
8
|
+
status: z.boolean().optional().describe("Only report the current or last run and the index's freshness; start nothing."),
|
|
9
|
+
wait: z.number().min(0).optional().describe(`Seconds to block until the run finishes (at most ${MAX_WAIT_SECONDS}; larger values are capped). Returns early when the run ends. Pass 30 when starting and when polling.`),
|
|
10
|
+
force: z.boolean().optional().describe("Re-index even when the index is fresh. Also stops a run in flight and starts over (for a stuck run)."),
|
|
11
|
+
rootPath: rootPathSchema
|
|
12
|
+
}, POLL = `Indexing is still running. ${WAIT_FOR_INDEX} or failed; do other work between calls if you have any.`;
|
|
13
|
+
function nextStep(job, freshness, judgement) {
|
|
14
|
+
if (job?.state === "running")
|
|
15
|
+
return POLL;
|
|
16
|
+
const state = judgement?.state ?? "stale";
|
|
17
|
+
return job?.state === "failed" && state !== "fresh" ? "The last run failed: see job.error and the log at job.logPath. Fix the cause, then call codebase_index again." : freshness.indexed ? state === "fresh" ? "The index is fresh. codebase_extract models the code; codebase_verify checks the API layer's operations against the code's routes." : state === "fresh-with-uncommitted-edits" ? "Source files were edited after the index was taken (index.uncommittedEdits). Call codebase_index with wait: 30 to re-index them." : "The code has changed since the last index. Call codebase_index with wait: 30 to re-index." : "The code is not indexed. Call codebase_index with wait: 30 to index it.";
|
|
18
|
+
}
|
|
19
|
+
const sleep = (ms, signal) => new Promise((resolve) => {
|
|
20
|
+
const timer = setTimeout(done, ms);
|
|
21
|
+
function done() {
|
|
22
|
+
clearTimeout(timer), signal?.removeEventListener("abort", done), resolve();
|
|
23
|
+
}
|
|
24
|
+
signal?.addEventListener("abort", done, { once: !0 });
|
|
25
|
+
}), REPORT_RESERVE_MS = 2e3;
|
|
26
|
+
async function waitForJob(projectRoot, job, deadline, deps, signal) {
|
|
27
|
+
const interval = deps.pollIntervalMs ?? 1e3;
|
|
28
|
+
let current = job;
|
|
29
|
+
for (; current?.state === "running" && Date.now() < deadline && !signal?.aborted; )
|
|
30
|
+
await sleep(Math.max(1, Math.min(interval, deadline - Date.now())), signal), current = await readIndexJob(projectRoot, { isAlive: deps.isAlive });
|
|
31
|
+
return current;
|
|
32
|
+
}
|
|
33
|
+
function createCodebaseIndexHandler(deps = defaultCodebaseToolDeps) {
|
|
34
|
+
return async function(args, context) {
|
|
35
|
+
const deadline = Date.now() + Math.min((args.wait ?? 0) * 1e3, MAX_WAIT_SECONDS * 1e3 - REPORT_RESERVE_MS);
|
|
36
|
+
return runTool(async () => {
|
|
37
|
+
const model = await loadModel(args.rootPath), { projectRoot, codebaseRoot } = await canonicalRoots(model), job = await readIndexJob(projectRoot, { isAlive: deps.isAlive }), session = await readSession(projectRoot), report = async (analyzer2, started2, current2, extra = {}) => {
|
|
38
|
+
const waited = args.wait && args.wait > 0 && current2?.state === "running", startedWaiting = Date.now(), settled = waited ? await waitForJob(projectRoot, current2, deadline, deps, context?.signal) : current2, { freshness, judgement } = analyzer2 ? await assessIndex(projectRoot, analyzer2, codebaseRoot, deps) : { freshness: { indexed: !1, fresh: !1 }, judgement: null };
|
|
39
|
+
return jsonResult({
|
|
40
|
+
projectRoot,
|
|
41
|
+
analyzer: analyzer2,
|
|
42
|
+
started: started2,
|
|
43
|
+
job: settled,
|
|
44
|
+
...waited ? { waitedSeconds: Math.round((Date.now() - startedWaiting) / 1e3) } : {},
|
|
45
|
+
index: describeIndex(freshness, judgement),
|
|
46
|
+
next: nextStep(settled, freshness, judgement),
|
|
47
|
+
...extra
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
if (args.status)
|
|
51
|
+
return report(session?.active_analyzer || job?.analyzer || null, !1, job);
|
|
52
|
+
if (job?.state === "running" && !args.force)
|
|
53
|
+
return report(job.analyzer, !1, job);
|
|
54
|
+
let analyzer = session?.active_analyzer, discovered = !1;
|
|
55
|
+
if (!analyzer) {
|
|
56
|
+
const discovery = await deps.discover();
|
|
57
|
+
if (!discovery.selected) {
|
|
58
|
+
const name = discovery.found[0]?.name ?? "cbm";
|
|
59
|
+
throw new CLIError("No code analyzer is installed", ErrorCategory.USER, await installSuggestions(name));
|
|
60
|
+
}
|
|
61
|
+
analyzer = discovery.selected, discovered = !0, await writeSession({ active_analyzer: analyzer, selected_at: (/* @__PURE__ */ new Date()).toISOString() }, projectRoot);
|
|
62
|
+
}
|
|
63
|
+
const backend = await deps.getAnalyzer(analyzer);
|
|
64
|
+
if (!backend)
|
|
65
|
+
throw analyzerNotFoundError(analyzer);
|
|
66
|
+
if (!discovered && !(await backend.detect(projectRoot)).installed)
|
|
67
|
+
throw await notInstalledError(analyzer);
|
|
68
|
+
let editedSinceIndex = !1;
|
|
69
|
+
if (!args.force) {
|
|
70
|
+
const { judgement } = await assessIndex(projectRoot, analyzer, codebaseRoot, deps);
|
|
71
|
+
if (judgement?.state === "fresh")
|
|
72
|
+
return report(analyzer, !1, job, {
|
|
73
|
+
...discovered ? { discovered: !0 } : {},
|
|
74
|
+
message: "The index is fresh; nothing to do. Pass force: true to re-index anyway."
|
|
75
|
+
});
|
|
76
|
+
editedSinceIndex = judgement?.state === "fresh-with-uncommitted-edits";
|
|
77
|
+
}
|
|
78
|
+
const ignoreFile = analyzer === "cbm" ? await cbmIgnoreFile(codebaseRoot, projectRoot) : void 0, snapshot = await takeWorktreeSnapshot(codebaseRoot), { started, job: current, replaced } = await startIndexJob({
|
|
79
|
+
projectRoot,
|
|
80
|
+
codebaseRoot,
|
|
81
|
+
analyzer,
|
|
82
|
+
// The child skips an index taken at the current HEAD unless forced; uncommitted edits need the run.
|
|
83
|
+
force: args.force || editedSinceIndex,
|
|
84
|
+
replaceRunning: args.force,
|
|
85
|
+
spawn: deps.spawn,
|
|
86
|
+
kill: deps.kill,
|
|
87
|
+
drCommand: deps.drCommand,
|
|
88
|
+
isAlive: deps.isAlive
|
|
89
|
+
});
|
|
90
|
+
return started && snapshot && await writeWorktreeSnapshot(projectRoot, analyzer, { ...snapshot, jobId: current.jobId }).catch(() => {
|
|
91
|
+
}), report(analyzer, started, current, {
|
|
92
|
+
...discovered ? { discovered: !0 } : {},
|
|
93
|
+
...replaced ? { replaced } : {},
|
|
94
|
+
// Said only with a run that started (and will read it), not beside a run that did not.
|
|
95
|
+
...ignoreFile && started ? { ignoreFile } : {}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async function cbmIgnoreFile(codebaseRoot, projectRoot) {
|
|
101
|
+
try {
|
|
102
|
+
const { ensureCbmIgnore } = await import("../../analyzers/cbm-analyzer.js"), result = await ensureCbmIgnore(codebaseRoot, projectRoot);
|
|
103
|
+
return result.added.length === 0 ? void 0 : {
|
|
104
|
+
path: result.path,
|
|
105
|
+
created: result.created,
|
|
106
|
+
added: result.added,
|
|
107
|
+
note: "codebase-memory-mcp indexes every file it isn't told to skip; this keeps DR's model, changesets and analyzer state out of the index. Commit the file with the code."
|
|
108
|
+
};
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return { error: `Could not update .cbmignore, so DR's own files may be indexed: ${error instanceof Error ? error.message : String(error)}` };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const codebaseIndexHandler = createCodebaseIndexHandler(), codebaseIndexTool = {
|
|
114
|
+
name: "codebase_index",
|
|
115
|
+
description: `Index the project's code with the code analyzer (codebase-memory-mcp) in the background. Returns the job ({state: running|done|failed, startedAt, finishedAt, error, progress, logPath}) and the index's freshness (index.state: fresh, fresh-with-uncommitted-edits or stale). With wait (seconds, at most ${MAX_WAIT_SECONDS}) it blocks until the run ends or the wait does; without it, it returns at once. Start with wait: 30, then call it with status: true, wait: 30 until job.state is done or failed. A call while a run is in flight returns that run; force: true stops it and starts over. Skips a fresh index unless force: true. Selects an installed analyzer if none is. Writes .dr/analyzers/, and for codebase-memory-mcp a .cbmignore at the codebase root that keeps documentation-robotics/ and .dr/ out of the index (ignoreFile says when it changed it); never the model.`,
|
|
116
|
+
inputSchema,
|
|
117
|
+
handler: codebaseIndexHandler
|
|
118
|
+
};
|
|
119
|
+
export {
|
|
120
|
+
MAX_WAIT_SECONDS,
|
|
121
|
+
codebaseIndexHandler,
|
|
122
|
+
codebaseIndexTool,
|
|
123
|
+
createCodebaseIndexHandler
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=codebase-index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/codebase-index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * codebase_index \u2014 index the project's code with the analyzer (codebase-memory-mcp), in the\n * background.\n *\n * It starts `dr analyzer index` in a detached process. Without `wait` it returns at once; with\n * `wait` (seconds, capped at MAX_WAIT_SECONDS) it blocks until the run ends or the wait does, then\n * returns the job. The agent repeats `status: true, wait: 30` until the job is done or failed.\n * Indexing a large codebase outlasts an MCP call, and a client that moves a long call to the\n * background (Claude Code after 2 minutes) loses its result under `claude -p`, so a single call\n * never waits longer than about 50 seconds. The job record is `.dr/analyzers/index-job.json`\n * (analyzers/index-job.ts). Writes no model files.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { readIndexJob, startIndexJob, type IndexJob } from \"../../analyzers/index-job.js\";\nimport { readSession, writeSession } from \"../../analyzers/session-state.js\";\nimport type { IndexFreshness } from \"../../analyzers/active-analyzer.js\";\nimport { CLIError, ErrorCategory } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, rootPathSchema, runTool, type McpToolContext, type McpToolDefinition } from \"./shared.js\";\nimport {\n analyzerNotFoundError,\n assessIndex,\n canonicalRoots,\n defaultCodebaseToolDeps,\n describeIndex,\n installSuggestions,\n notInstalledError,\n takeWorktreeSnapshot,\n WAIT_FOR_INDEX,\n writeWorktreeSnapshot,\n type CodebaseToolDeps,\n type IndexJudgement,\n} from \"./codebase-shared.js\";\n\n/** The longest one call blocks: under the point where a client moves a call to the background. */\nexport const MAX_WAIT_SECONDS = 50;\n\nconst inputSchema = {\n status: z\n .boolean()\n .optional()\n .describe(\"Only report the current or last run and the index's freshness; start nothing.\"),\n wait: z\n .number()\n .min(0)\n .optional()\n .describe(\n `Seconds to block until the run finishes (at most ${MAX_WAIT_SECONDS}; larger values are capped). Returns early when the run ends. Pass 30 when starting and when polling.`\n ),\n force: z\n .boolean()\n .optional()\n .describe(\"Re-index even when the index is fresh. Also stops a run in flight and starts over (for a stuck run).\"),\n rootPath: rootPathSchema,\n};\n\nexport type CodebaseIndexArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nconst POLL = `Indexing is still running. ${WAIT_FOR_INDEX} or failed; do other work between calls if you have any.`;\n\n/** What the agent should do next, given the job and the index. */\nfunction nextStep(job: IndexJob | null, freshness: IndexFreshness, judgement: IndexJudgement | null): string {\n if (job?.state === \"running\") return POLL;\n const state = judgement?.state ?? \"stale\";\n if (job?.state === \"failed\" && state !== \"fresh\") {\n return \"The last run failed: see job.error and the log at job.logPath. Fix the cause, then call codebase_index again.\";\n }\n if (!freshness.indexed) return \"The code is not indexed. Call codebase_index with wait: 30 to index it.\";\n if (state === \"fresh\") {\n return \"The index is fresh. codebase_extract models the code; codebase_verify checks the API layer's operations against the code's routes.\";\n }\n if (state === \"fresh-with-uncommitted-edits\") {\n return \"Source files were edited after the index was taken (index.uncommittedEdits). Call codebase_index with wait: 30 to re-index them.\";\n }\n return \"The code has changed since the last index. Call codebase_index with wait: 30 to re-index.\";\n}\n\n/** Sleeps `ms`, or less when `signal` aborts. */\nconst sleep = (ms: number, signal?: AbortSignal) =>\n new Promise<void>((resolve) => {\n const timer = setTimeout(done, ms);\n function done() {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", done);\n resolve();\n }\n signal?.addEventListener(\"abort\", done, { once: true });\n });\n\n/** Blocks until the run is no longer running or `seconds` pass, and returns the job as it is then. */\n/** Time kept back from the wait for the last read of the index, so the whole call fits the cap. */\nconst REPORT_RESERVE_MS = 2000;\n\n/**\n * Blocks until the run is no longer running, `deadline` passes, or the request is cancelled, and\n * returns the job as it is then.\n */\nasync function waitForJob(\n projectRoot: string,\n job: IndexJob | null,\n deadline: number,\n deps: CodebaseToolDeps,\n signal?: AbortSignal\n): Promise<IndexJob | null> {\n const interval = deps.pollIntervalMs ?? 1000;\n let current = job;\n while (current?.state === \"running\" && Date.now() < deadline && !signal?.aborted) {\n await sleep(Math.max(1, Math.min(interval, deadline - Date.now())), signal);\n current = await readIndexJob(projectRoot, { isAlive: deps.isAlive });\n }\n return current;\n}\n\nexport function createCodebaseIndexHandler(deps: CodebaseToolDeps = defaultCodebaseToolDeps) {\n return async function codebaseIndexHandler(args: CodebaseIndexArgs, context?: McpToolContext): Promise<CallToolResult> {\n // The wait counts from the call's start: loading the model and running git use it up too.\n const deadline = Date.now() + Math.min((args.wait ?? 0) * 1000, MAX_WAIT_SECONDS * 1000 - REPORT_RESERVE_MS);\n return runTool(async () => {\n // The project comes from rootPath or the client's roots (loadModel waits for them).\n const model = await loadModel(args.rootPath);\n // One spelling of each root for this call and the child it starts (see canonicalRoots).\n const { projectRoot, codebaseRoot } = await canonicalRoots(model);\n const job = await readIndexJob(projectRoot, { isAlive: deps.isAlive });\n const session = await readSession(projectRoot);\n\n const report = async (analyzer: string | null, started: boolean, current: IndexJob | null, extra = {}) => {\n const waited = args.wait && args.wait > 0 && current?.state === \"running\";\n const startedWaiting = Date.now();\n const settled = waited ? await waitForJob(projectRoot, current, deadline, deps, context?.signal) : current;\n const { freshness, judgement } = analyzer\n ? await assessIndex(projectRoot, analyzer, codebaseRoot, deps)\n : { freshness: { indexed: false, fresh: false } as const, judgement: null };\n return jsonResult({\n projectRoot,\n analyzer,\n started,\n job: settled,\n ...(waited ? { waitedSeconds: Math.round((Date.now() - startedWaiting) / 1000) } : {}),\n index: describeIndex(freshness, judgement),\n next: nextStep(settled, freshness, judgement),\n ...extra,\n });\n };\n\n if (args.status) {\n return report(session?.active_analyzer || job?.analyzer || null, false, job);\n }\n\n // One run at a time: a call while one is in flight reports that run. force replaces it.\n if (job?.state === \"running\" && !args.force) {\n return report(job.analyzer, false, job);\n }\n\n // Pick the analyzer, discovering one when none is selected yet.\n let analyzer = session?.active_analyzer;\n let discovered = false;\n if (!analyzer) {\n const discovery = await deps.discover();\n if (!discovery.selected) {\n const name = discovery.found[0]?.name ?? \"cbm\";\n throw new CLIError(\"No code analyzer is installed\", ErrorCategory.USER, await installSuggestions(name));\n }\n analyzer = discovery.selected;\n discovered = true;\n await writeSession({ active_analyzer: analyzer, selected_at: new Date().toISOString() }, projectRoot);\n }\n\n const backend = await deps.getAnalyzer(analyzer);\n if (!backend) throw analyzerNotFoundError(analyzer);\n // Discovery has just checked it; otherwise check before starting a run that would fail.\n if (!discovered) {\n const detection = await backend.detect(projectRoot);\n if (!detection.installed) throw await notInstalledError(analyzer);\n }\n\n let editedSinceIndex = false;\n if (!args.force) {\n const { judgement } = await assessIndex(projectRoot, analyzer, codebaseRoot, deps);\n if (judgement?.state === \"fresh\") {\n return report(analyzer, false, job, {\n ...(discovered ? { discovered: true } : {}),\n message: \"The index is fresh; nothing to do. Pass force: true to re-index anyway.\",\n });\n }\n editedSinceIndex = judgement?.state === \"fresh-with-uncommitted-edits\";\n }\n\n // codebase-memory-mcp indexes every file it isn't told to skip, DR's changesets and analyzer\n // state included; the run writes .cbmignore too, but doing it here lets the result say so.\n const ignoreFile = analyzer === \"cbm\" ? await cbmIgnoreFile(codebaseRoot, projectRoot) : undefined;\n\n // The uncommitted source files as the run starts, so a later check sees any change to them.\n const snapshot = await takeWorktreeSnapshot(codebaseRoot);\n const { started, job: current, replaced } = await startIndexJob({\n projectRoot,\n codebaseRoot,\n analyzer,\n // The child skips an index taken at the current HEAD unless forced; uncommitted edits need the run.\n force: args.force || editedSinceIndex,\n replaceRunning: args.force,\n spawn: deps.spawn,\n kill: deps.kill,\n drCommand: deps.drCommand,\n isAlive: deps.isAlive,\n });\n if (started && snapshot) {\n await writeWorktreeSnapshot(projectRoot, analyzer, { ...snapshot, jobId: current.jobId }).catch(() => undefined);\n }\n return report(analyzer, started, current, {\n ...(discovered ? { discovered: true } : {}),\n ...(replaced ? { replaced } : {}),\n // Said only with a run that started (and will read it), not beside a run that did not.\n ...(ignoreFile && started ? { ignoreFile } : {}),\n });\n });\n };\n}\n\n/**\n * Adds DR's own folders to the codebase's .cbmignore (cbm-analyzer.ts ensureCbmIgnore), and says\n * what it did when it changed the file, so the agent can tell the developer about a new file to\n * commit. Undefined when nothing changed; a failure is reported, not thrown: the run still works.\n */\nasync function cbmIgnoreFile(codebaseRoot: string, projectRoot: string): Promise<Record<string, unknown> | undefined> {\n try {\n const { ensureCbmIgnore } = await import(\"../../analyzers/cbm-analyzer.js\");\n const result = await ensureCbmIgnore(codebaseRoot, projectRoot);\n if (result.added.length === 0) return undefined;\n return {\n path: result.path,\n created: result.created,\n added: result.added,\n note:\n \"codebase-memory-mcp indexes every file it isn't told to skip; this keeps DR's model, changesets and analyzer state out of the index. Commit the file with the code.\",\n };\n } catch (error) {\n return { error: `Could not update .cbmignore, so DR's own files may be indexed: ${error instanceof Error ? error.message : String(error)}` };\n }\n}\n\nexport const codebaseIndexHandler = createCodebaseIndexHandler();\n\nexport const codebaseIndexTool: McpToolDefinition<typeof inputSchema> = {\n name: \"codebase_index\",\n description:\n \"Index the project's code with the code analyzer (codebase-memory-mcp) in the background. Returns the job \" +\n \"({state: running|done|failed, startedAt, finishedAt, error, progress, logPath}) and the index's freshness \" +\n \"(index.state: fresh, fresh-with-uncommitted-edits or stale). With wait (seconds, at most \" +\n `${MAX_WAIT_SECONDS}) it blocks until the run ends or the wait does; without it, it returns at once. Start with ` +\n \"wait: 30, then call it with status: true, wait: 30 until job.state is done or failed. A call while a run \" +\n \"is in flight returns that run; force: true stops it and starts over. Skips a fresh index unless force: true. \" +\n \"Selects an installed analyzer if none is. Writes .dr/analyzers/, and for codebase-memory-mcp a .cbmignore at \" +\n \"the codebase root that keeps documentation-robotics/ and .dr/ out of the index (ignoreFile says when it changed \" +\n \"it); never the model.\",\n inputSchema,\n handler: codebaseIndexHandler,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["analyzer", "started", "current"]
|
|
7
|
+
}
|