@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.
Files changed (335) hide show
  1. package/README.md +46 -16
  2. package/dist/analysis/relationship-classifier.js +2 -9
  3. package/dist/analysis/relationship-classifier.js.map +2 -2
  4. package/dist/analyzers/active-analyzer.js +62 -0
  5. package/dist/analyzers/active-analyzer.js.map +7 -0
  6. package/dist/analyzers/call-graph-utils.js +2 -2
  7. package/dist/analyzers/call-graph-utils.js.map +2 -2
  8. package/dist/analyzers/cards/build.js +191 -0
  9. package/dist/analyzers/cards/build.js.map +7 -0
  10. package/dist/analyzers/cards/classify.js +42 -0
  11. package/dist/analyzers/cards/classify.js.map +7 -0
  12. package/dist/analyzers/cards/edge-index.js +44 -0
  13. package/dist/analyzers/cards/edge-index.js.map +7 -0
  14. package/dist/analyzers/cards/extract.js +138 -0
  15. package/dist/analyzers/cards/extract.js.map +7 -0
  16. package/dist/analyzers/cards/facts.js +46 -0
  17. package/dist/analyzers/cards/facts.js.map +7 -0
  18. package/dist/analyzers/cards/graph.js +42 -0
  19. package/dist/analyzers/cards/graph.js.map +7 -0
  20. package/dist/analyzers/cards/index.js +8 -0
  21. package/dist/analyzers/cards/index.js.map +7 -0
  22. package/dist/analyzers/cards/routes.js +96 -0
  23. package/dist/analyzers/cards/routes.js.map +7 -0
  24. package/dist/analyzers/cards/tier0.js +18 -0
  25. package/dist/analyzers/cards/tier0.js.map +7 -0
  26. package/dist/analyzers/cards/types.js +1 -0
  27. package/dist/analyzers/cards/types.js.map +7 -0
  28. package/dist/analyzers/cbm-analyzer.js +270 -174
  29. package/dist/analyzers/cbm-analyzer.js.map +2 -2
  30. package/dist/analyzers/cbm-responses.js +342 -0
  31. package/dist/analyzers/cbm-responses.js.map +7 -0
  32. package/dist/analyzers/code-changes.js +159 -0
  33. package/dist/analyzers/code-changes.js.map +7 -0
  34. package/dist/analyzers/edge-relationships.js +49 -0
  35. package/dist/analyzers/edge-relationships.js.map +7 -0
  36. package/dist/analyzers/extraction-plan.js +541 -0
  37. package/dist/analyzers/extraction-plan.js.map +7 -0
  38. package/dist/analyzers/index-job.js +229 -0
  39. package/dist/analyzers/index-job.js.map +7 -0
  40. package/dist/analyzers/mapping-loader.js +9 -0
  41. package/dist/analyzers/mapping-loader.js.map +2 -2
  42. package/dist/analyzers/tier0-rules.js +153 -0
  43. package/dist/analyzers/tier0-rules.js.map +7 -0
  44. package/dist/analyzers/types.js.map +1 -1
  45. package/dist/audit/relationships/ai/prompts.js +10 -10
  46. package/dist/audit/relationships/ai/prompts.js.map +2 -2
  47. package/dist/audit/relationships/analysis/layer-templates.js +52 -52
  48. package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
  49. package/dist/cli.js +23 -11
  50. package/dist/cli.js.map +2 -2
  51. package/dist/coding-agents/default-permissions.js +31 -1
  52. package/dist/coding-agents/default-permissions.js.map +2 -2
  53. package/dist/coding-agents/drbot-mcp.js +269 -0
  54. package/dist/coding-agents/drbot-mcp.js.map +7 -0
  55. package/dist/commands/add.js +7 -4
  56. package/dist/commands/add.js.map +2 -2
  57. package/dist/commands/analyzer.js +143 -40
  58. package/dist/commands/analyzer.js.map +2 -2
  59. package/dist/commands/changeset-verify.js +63 -0
  60. package/dist/commands/changeset-verify.js.map +7 -0
  61. package/dist/commands/changeset.js +80 -29
  62. package/dist/commands/changeset.js.map +2 -2
  63. package/dist/commands/delete.js +10 -4
  64. package/dist/commands/delete.js.map +2 -2
  65. package/dist/commands/farm.js +176 -60
  66. package/dist/commands/farm.js.map +2 -2
  67. package/dist/commands/init.js +9 -26
  68. package/dist/commands/init.js.map +2 -2
  69. package/dist/commands/mcp.js +40 -21
  70. package/dist/commands/mcp.js.map +3 -3
  71. package/dist/commands/relationship.js +208 -37
  72. package/dist/commands/relationship.js.map +2 -2
  73. package/dist/commands/reports.js +3 -3
  74. package/dist/commands/reports.js.map +2 -2
  75. package/dist/commands/update.js +52 -32
  76. package/dist/commands/update.js.map +2 -2
  77. package/dist/commands/upgrade.js +99 -103
  78. package/dist/commands/upgrade.js.map +3 -3
  79. package/dist/commands/validate.js +19 -3
  80. package/dist/commands/validate.js.map +2 -2
  81. package/dist/commands/version.js +1 -1
  82. package/dist/commands/visualize.js +34 -15
  83. package/dist/commands/visualize.js.map +2 -2
  84. package/dist/core/annotation-store.js +15 -5
  85. package/dist/core/annotation-store.js.map +2 -2
  86. package/dist/core/catalog-migration.js +34 -0
  87. package/dist/core/catalog-migration.js.map +7 -0
  88. package/dist/core/changeset-analysis.js +421 -0
  89. package/dist/core/changeset-analysis.js.map +7 -0
  90. package/dist/core/changeset-base-index.js +160 -0
  91. package/dist/core/changeset-base-index.js.map +7 -0
  92. package/dist/core/changeset-brief-compact.js +256 -0
  93. package/dist/core/changeset-brief-compact.js.map +7 -0
  94. package/dist/core/changeset-brief-delta.js +102 -0
  95. package/dist/core/changeset-brief-delta.js.map +7 -0
  96. package/dist/core/changeset-graph.js +281 -0
  97. package/dist/core/changeset-graph.js.map +7 -0
  98. package/dist/core/changeset-only-guard.js +32 -0
  99. package/dist/core/changeset-only-guard.js.map +7 -0
  100. package/dist/core/changeset-summary.js +68 -0
  101. package/dist/core/changeset-summary.js.map +7 -0
  102. package/dist/core/changeset-validator.js +66 -20
  103. package/dist/core/changeset-validator.js.map +2 -2
  104. package/dist/core/changeset-verify.js +848 -0
  105. package/dist/core/changeset-verify.js.map +7 -0
  106. package/dist/core/changeset.js +56 -9
  107. package/dist/core/changeset.js.map +2 -2
  108. package/dist/core/element-type-migration.js +145 -0
  109. package/dist/core/element-type-migration.js.map +7 -0
  110. package/dist/core/extraction-observability.js +161 -0
  111. package/dist/core/extraction-observability.js.map +7 -0
  112. package/dist/core/farm-manifest.js +12 -6
  113. package/dist/core/farm-manifest.js.map +2 -2
  114. package/dist/core/farm-sync-engine.js +1 -1
  115. package/dist/core/farm-sync-engine.js.map +2 -2
  116. package/dist/core/farm-sync-state.js +10 -2
  117. package/dist/core/farm-sync-state.js.map +2 -2
  118. package/dist/core/migration-registry.js +88 -47
  119. package/dist/core/migration-registry.js.map +2 -2
  120. package/dist/core/model-upgrade.js +102 -0
  121. package/dist/core/model-upgrade.js.map +7 -0
  122. package/dist/core/model.js +82 -30
  123. package/dist/core/model.js.map +2 -2
  124. package/dist/core/mutation-handler.js +71 -6
  125. package/dist/core/mutation-handler.js.map +2 -2
  126. package/dist/core/project-init.js +53 -0
  127. package/dist/core/project-init.js.map +7 -0
  128. package/dist/core/relationship-migration-table.js +6639 -0
  129. package/dist/core/relationship-migration-table.js.map +7 -0
  130. package/dist/core/relationship-migration.js +272 -0
  131. package/dist/core/relationship-migration.js.map +7 -0
  132. package/dist/core/relationship-prune.js +49 -0
  133. package/dist/core/relationship-prune.js.map +7 -0
  134. package/dist/core/relationship-staging.js +161 -0
  135. package/dist/core/relationship-staging.js.map +7 -0
  136. package/dist/core/relationships.js +26 -4
  137. package/dist/core/relationships.js.map +2 -2
  138. package/dist/core/report-data-model.js +7 -13
  139. package/dist/core/report-data-model.js.map +2 -2
  140. package/dist/core/staged-changeset-storage.js +145 -18
  141. package/dist/core/staged-changeset-storage.js.map +2 -2
  142. package/dist/core/staged-source-reference.js +28 -0
  143. package/dist/core/staged-source-reference.js.map +7 -0
  144. package/dist/core/staging-area.js +166 -24
  145. package/dist/core/staging-area.js.map +2 -2
  146. package/dist/core/upgrade-plan.js +117 -0
  147. package/dist/core/upgrade-plan.js.map +7 -0
  148. package/dist/core/virtual-projection.js +13 -5
  149. package/dist/core/virtual-projection.js.map +2 -2
  150. package/dist/export/archimate-exporter.js +1 -0
  151. package/dist/export/archimate-exporter.js.map +2 -2
  152. package/dist/generated/compiled-validators.js +2 -2
  153. package/dist/generated/compiled-validators.js.map +2 -2
  154. package/dist/generated/layer-registry.js +16 -16
  155. package/dist/generated/layer-registry.js.map +2 -2
  156. package/dist/generated/node-types.js +186 -168
  157. package/dist/generated/node-types.js.map +2 -2
  158. package/dist/generated/relationship-index.js +2468 -7913
  159. package/dist/generated/relationship-index.js.map +2 -2
  160. package/dist/integrations/claude_code/.claude-plugin/plugin.json +24 -0
  161. package/dist/integrations/claude_code/agents/dr-architect.md +30 -3
  162. package/dist/integrations/claude_code/agents/dr-extractor.md +8 -2
  163. package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
  164. package/dist/integrations/claude_code/commands/dr-changeset.md +2 -1
  165. package/dist/integrations/claude_code/commands/dr-map.md +20 -1
  166. package/dist/integrations/claude_code/commands/dr-plan.md +66 -0
  167. package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
  168. package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
  169. package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
  170. package/dist/integrations/claude_code/docs/MCP_SERVER.md +47 -26
  171. package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
  172. package/dist/integrations/claude_code/docs/README.md +68 -2
  173. package/dist/integrations/claude_code/plugin-agents/dr-advisor.md +255 -0
  174. package/dist/integrations/claude_code/plugin-agents/dr-architect.md +306 -0
  175. package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
  176. package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
  177. package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
  178. package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
  179. package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
  180. package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
  181. package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
  182. package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
  183. package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
  184. package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
  185. package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
  186. package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
  187. package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +95 -15
  188. package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +178 -0
  189. package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +8 -0
  190. package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +6 -1
  191. package/dist/integrations/github_copilot/agents/dr-architect.md +3 -1
  192. package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
  193. package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
  194. package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
  195. package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
  196. package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
  197. package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
  198. package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
  199. package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
  200. package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
  201. package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
  202. package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
  203. package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
  204. package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +225 -102
  205. package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +177 -0
  206. package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
  207. package/dist/integrations/hash-utils.js.map +2 -2
  208. package/dist/mcp/api-key-manager.js +14 -1
  209. package/dist/mcp/api-key-manager.js.map +2 -2
  210. package/dist/mcp/changeset-only.js +45 -0
  211. package/dist/mcp/changeset-only.js.map +7 -0
  212. package/dist/mcp/project-root.js +85 -0
  213. package/dist/mcp/project-root.js.map +7 -0
  214. package/dist/mcp/server-instructions.js +27 -0
  215. package/dist/mcp/server-instructions.js.map +7 -0
  216. package/dist/mcp/strict-schema.js +52 -0
  217. package/dist/mcp/strict-schema.js.map +7 -0
  218. package/dist/mcp/tool-registry.js +55 -5
  219. package/dist/mcp/tool-registry.js.map +2 -2
  220. package/dist/mcp/tools/changeset-analysis-tools.js +98 -0
  221. package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
  222. package/dist/mcp/tools/changeset-commit.js +224 -0
  223. package/dist/mcp/tools/changeset-commit.js.map +7 -0
  224. package/dist/mcp/tools/changeset-editing.js +260 -0
  225. package/dist/mcp/tools/changeset-editing.js.map +7 -0
  226. package/dist/mcp/tools/changeset-lifecycle.js +83 -0
  227. package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
  228. package/dist/mcp/tools/changeset-shared.js +31 -0
  229. package/dist/mcp/tools/changeset-shared.js.map +7 -0
  230. package/dist/mcp/tools/changeset-show.js +17 -1
  231. package/dist/mcp/tools/changeset-show.js.map +2 -2
  232. package/dist/mcp/tools/changeset-verify.js +49 -0
  233. package/dist/mcp/tools/changeset-verify.js.map +7 -0
  234. package/dist/mcp/tools/codebase-extract.js +836 -0
  235. package/dist/mcp/tools/codebase-extract.js.map +7 -0
  236. package/dist/mcp/tools/codebase-index.js +125 -0
  237. package/dist/mcp/tools/codebase-index.js.map +7 -0
  238. package/dist/mcp/tools/codebase-shared.js +265 -0
  239. package/dist/mcp/tools/codebase-shared.js.map +7 -0
  240. package/dist/mcp/tools/codebase-verify.js +48 -0
  241. package/dist/mcp/tools/codebase-verify.js.map +7 -0
  242. package/dist/mcp/tools/index.js +34 -1
  243. package/dist/mcp/tools/index.js.map +2 -2
  244. package/dist/mcp/tools/model-add.js +191 -74
  245. package/dist/mcp/tools/model-add.js.map +2 -2
  246. package/dist/mcp/tools/model-delete.js +2 -2
  247. package/dist/mcp/tools/model-delete.js.map +2 -2
  248. package/dist/mcp/tools/model-search.js +14 -0
  249. package/dist/mcp/tools/model-search.js.map +2 -2
  250. package/dist/mcp/tools/model-show.js +29 -2
  251. package/dist/mcp/tools/model-show.js.map +2 -2
  252. package/dist/mcp/tools/model-trace.js +93 -30
  253. package/dist/mcp/tools/model-trace.js.map +2 -2
  254. package/dist/mcp/tools/model-update.js +46 -26
  255. package/dist/mcp/tools/model-update.js.map +2 -2
  256. package/dist/mcp/tools/model-validate.js +46 -4
  257. package/dist/mcp/tools/model-validate.js.map +2 -2
  258. package/dist/mcp/tools/project-status-collectors.js +381 -0
  259. package/dist/mcp/tools/project-status-collectors.js.map +7 -0
  260. package/dist/mcp/tools/project-status.js +237 -0
  261. package/dist/mcp/tools/project-status.js.map +7 -0
  262. package/dist/mcp/tools/project-tools.js +505 -0
  263. package/dist/mcp/tools/project-tools.js.map +7 -0
  264. package/dist/mcp/tools/relationship-tools.js +167 -0
  265. package/dist/mcp/tools/relationship-tools.js.map +7 -0
  266. package/dist/mcp/tools/review-open.js +210 -0
  267. package/dist/mcp/tools/review-open.js.map +7 -0
  268. package/dist/mcp/tools/shared.js +35 -4
  269. package/dist/mcp/tools/shared.js.map +2 -2
  270. package/dist/mcp/tools/spec-type.js +90 -0
  271. package/dist/mcp/tools/spec-type.js.map +7 -0
  272. package/dist/reports/model-report-orchestrator.js +31 -2
  273. package/dist/reports/model-report-orchestrator.js.map +2 -2
  274. package/dist/schemas/bundled/analyzers/cbm.json +1200 -70
  275. package/dist/schemas/bundled/analyzers/manifest.json +2 -2
  276. package/dist/schemas/bundled/api.json +1029 -1658
  277. package/dist/schemas/bundled/apm.json +499 -734
  278. package/dist/schemas/bundled/application.json +735 -371
  279. package/dist/schemas/bundled/base.json +3 -220
  280. package/dist/schemas/bundled/business.json +452 -366
  281. package/dist/schemas/bundled/data-model.json +395 -411
  282. package/dist/schemas/bundled/data-store.json +334 -558
  283. package/dist/schemas/bundled/manifest.json +18 -18
  284. package/dist/schemas/bundled/motivation.json +349 -368
  285. package/dist/schemas/bundled/navigation.json +415 -731
  286. package/dist/schemas/bundled/product.json +325 -159
  287. package/dist/schemas/bundled/security.json +864 -1232
  288. package/dist/schemas/bundled/technology.json +574 -703
  289. package/dist/schemas/bundled/testing.json +865 -1646
  290. package/dist/schemas/bundled/ux.json +739 -1352
  291. package/dist/server/schemas.js +8 -0
  292. package/dist/server/schemas.js.map +2 -2
  293. package/dist/server/server.js +686 -231
  294. package/dist/server/server.js.map +3 -3
  295. package/dist/server/viewer-registry.js +264 -0
  296. package/dist/server/viewer-registry.js.map +7 -0
  297. package/dist/server-entry.js +2 -1
  298. package/dist/server-entry.js.map +2 -2
  299. package/dist/telemetry/index.js +1 -1
  300. package/dist/utils/ansi-suppressor.js +6 -8
  301. package/dist/utils/ansi-suppressor.js.map +2 -2
  302. package/dist/utils/attribute-patch.js +41 -0
  303. package/dist/utils/attribute-patch.js.map +7 -0
  304. package/dist/utils/error-hints.js +29 -0
  305. package/dist/utils/error-hints.js.map +7 -0
  306. package/dist/utils/errors.js +9 -3
  307. package/dist/utils/errors.js.map +2 -2
  308. package/dist/utils/id-generator.js +5 -2
  309. package/dist/utils/id-generator.js.map +2 -2
  310. package/dist/utils/project-paths.js +26 -1
  311. package/dist/utils/project-paths.js.map +2 -2
  312. package/dist/utils/source-reference.js +64 -31
  313. package/dist/utils/source-reference.js.map +2 -2
  314. package/dist/utils/spec-version.js +2 -2
  315. package/dist/utils/spec-version.js.map +1 -1
  316. package/dist/validators/composed-reference-validator.js +5 -27
  317. package/dist/validators/composed-reference-validator.js.map +2 -2
  318. package/dist/validators/model-warnings.js +28 -0
  319. package/dist/validators/model-warnings.js.map +7 -0
  320. package/dist/validators/reference-validator.js +0 -7
  321. package/dist/validators/reference-validator.js.map +2 -2
  322. package/dist/validators/relationship-schema-validator.js +3 -3
  323. package/dist/validators/relationship-schema-validator.js.map +2 -2
  324. package/dist/validators/schema-validator.js +27 -9
  325. package/dist/validators/schema-validator.js.map +2 -2
  326. package/dist/validators/types.js.map +1 -1
  327. package/dist/viewer/README.md +6 -6
  328. package/dist/viewer/assets/main-CUOQGGRA.css +1 -0
  329. package/dist/viewer/assets/main-DvH3gYrI.js +84 -0
  330. package/dist/viewer/index.html +2 -2
  331. package/dist/viewer/manifest.json +10 -10
  332. package/dist/viewer/version.json +1 -1
  333. package/package.json +2 -1
  334. package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
  335. package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
@@ -0,0 +1,237 @@
1
+ import path from "node:path";
2
+ import { findProjectRoot } from "../../utils/project-paths.js";
3
+ import { fileExists } from "../../utils/file-io.js";
4
+ import { getErrorMessage } from "../../utils/errors.js";
5
+ import { currentProjectRoot, whenProjectRootSettled } from "../project-root.js";
6
+ import { readdir, stat } from "node:fs/promises";
7
+ import { jsonResult, loadModel, reloadModel, rootPathSchema, runTool } from "./shared.js";
8
+ import { collectChangesets, collectCodeDrift, collectCodeIndex, collectIndexing, collectModel, collectSpec, collectViewer, runGit } from "./project-status-collectors.js";
9
+ const inputSchema = {
10
+ rootPath: rootPathSchema
11
+ }, COLLECTORS = {
12
+ model: collectModel,
13
+ spec: collectSpec,
14
+ changesets: collectChangesets,
15
+ codeIndex: collectCodeIndex,
16
+ codeDrift: collectCodeDrift,
17
+ indexing: collectIndexing,
18
+ viewer: collectViewer
19
+ }, RESOLVED_BY = {
20
+ env: "DR_MCP_ROOT_PATH",
21
+ "client-roots": "mcp-roots",
22
+ cwd: "cwd"
23
+ };
24
+ async function projectStatus(args, options = {}) {
25
+ let root, resolvedBy;
26
+ if (args.rootPath)
27
+ root = path.resolve(args.rootPath), resolvedBy = "rootPath";
28
+ else {
29
+ await whenProjectRootSettled();
30
+ const current = currentProjectRoot();
31
+ root = current.root, resolvedBy = RESOLVED_BY[current.source];
32
+ }
33
+ const projectRoot = await findProjectRoot(root), manifest = projectRoot ? path.join(projectRoot, "documentation-robotics", "model", "manifest.yaml") : null, modelDir = manifest && await fileExists(manifest) ? path.dirname(manifest) : null;
34
+ let modelPromise;
35
+ const ctx = {
36
+ root,
37
+ resolvedBy,
38
+ projectRoot,
39
+ modelDir,
40
+ model: () => modelPromise ??= freshModel(args.rootPath, modelDir),
41
+ git: options.git ?? runGit
42
+ }, entries = await Promise.all(Object.entries(COLLECTORS).map(async ([key, collect]) => {
43
+ try {
44
+ return [key, await collect(ctx)];
45
+ } catch (error) {
46
+ return [key, { status: "error", error: getErrorMessage(error) }];
47
+ }
48
+ })), sections = Object.fromEntries(entries);
49
+ return {
50
+ project: { root, resolvedBy, projectRoot },
51
+ ...sections,
52
+ nextStep: suggestNextStep(sections, { root, rootPath: args.rootPath })
53
+ };
54
+ }
55
+ const lastSignature = /* @__PURE__ */ new Map();
56
+ function clearProjectStatusSignatures() {
57
+ lastSignature.clear();
58
+ }
59
+ async function freshModel(rootPath, modelDir) {
60
+ const key = rootPath ?? "", signature = modelDir ? await filesSignature(modelDir) : null;
61
+ if (signature !== null && lastSignature.get(key) === signature)
62
+ return loadModel(rootPath);
63
+ const model = await reloadModel(rootPath);
64
+ return signature !== null && lastSignature.set(key, signature), model;
65
+ }
66
+ async function filesSignature(dir) {
67
+ try {
68
+ const entries = await readdir(dir, { recursive: !0, withFileTypes: !0 }), stats = await Promise.all(entries.filter((entry) => entry.isFile()).map((entry) => stat(path.join(entry.parentPath, entry.name))));
69
+ let mtimes = 0, sizes = 0;
70
+ for (const s of stats)
71
+ mtimes += s.mtimeMs, sizes += s.size;
72
+ return `${stats.length}:${mtimes}:${sizes}`;
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+ function suggestNextStep(s, ctx) {
78
+ const step = withIndexNote(whileIndexing(pickNextStep(s, ctx.root), s), s);
79
+ if (!ctx.rootPath)
80
+ return step;
81
+ const withRoot = (args) => ({ ...args, rootPath: ctx.rootPath });
82
+ return {
83
+ ...step,
84
+ ...step.tool ? { args: withRoot(step.args) } : {},
85
+ ...step.then ? { then: { ...step.then, args: withRoot(step.then.args) } } : {},
86
+ ...step.also ? { also: { ...step.also, args: withRoot(step.also.args) } } : {}
87
+ };
88
+ }
89
+ const WAIT_ARGS = { status: !0, wait: 30 };
90
+ function withIndexNote(step, s) {
91
+ if (step.tool === "codebase_index")
92
+ return step;
93
+ let also;
94
+ return s.indexing?.status === "running" ? also = {
95
+ summary: `The code is being indexed (started ${s.indexing.startedAt}); until it is done, codebase tools read the old index. Call codebase_index with status: true and wait: 30 to wait for it.`,
96
+ tool: "codebase_index",
97
+ args: WAIT_ARGS
98
+ } : s.changesets?.status === "ok" && s.changesets.active && (s.codeIndex?.status === "fresh-with-uncommitted-edits" || s.codeIndex?.status === "stale") && (also = {
99
+ summary: `${s.codeIndex.status === "stale" ? `The code index is stale${s.codeIndex.reason ? `: ${s.codeIndex.reason}` : ""}.` : `The code index predates uncommitted edits${s.codeIndex.reason ? `: ${s.codeIndex.reason}` : ""}.`} Refresh it with codebase_index before extracting or verifying against the code.`,
100
+ tool: "codebase_index",
101
+ args: INDEX_ARGS
102
+ }), also ? step.also ? { ...step, summary: `${step.summary} Also: ${also.summary}` } : { ...step, summary: `${step.summary} Also: ${also.summary}`, also } : step;
103
+ }
104
+ function whileIndexing(step, s) {
105
+ return step.tool !== "codebase_index" || s.indexing?.status !== "running" ? step : {
106
+ summary: `The code is being indexed (started ${s.indexing.startedAt}). Call codebase_index with status: true and wait: 30 until it is done.`,
107
+ tool: "codebase_index",
108
+ args: { status: !0, wait: 30 },
109
+ ...step.then ? { then: step.then } : {}
110
+ };
111
+ }
112
+ const INDEX_ARGS = { wait: 30 };
113
+ function pickNextStep(s, root) {
114
+ const ctx = { root }, { model, spec, changesets, codeDrift, codeIndex } = s;
115
+ if (model.status === "absent")
116
+ return {
117
+ summary: `There is no DR model in ${ctx.root}. Create one with project_init.`,
118
+ tool: "project_init"
119
+ };
120
+ if (model.status === "error")
121
+ return { summary: `The model could not be read: ${model.error}`, tool: null };
122
+ if (spec.status === "behind") {
123
+ const how = spec.migration?.available ? "Preview and apply the migration with project_upgrade." : "The CLI has no migration path between them; project_upgrade reports the options.";
124
+ return {
125
+ summary: `The model is on spec ${spec.model}; this CLI carries ${spec.cli}. ${how}`,
126
+ tool: "project_upgrade"
127
+ };
128
+ }
129
+ if (spec.status === "ahead")
130
+ return {
131
+ summary: `The model is on spec ${spec.model}, newer than this CLI's ${spec.cli}. Update the dr CLI before changing the model.`,
132
+ tool: null
133
+ };
134
+ if (model.loadError)
135
+ return {
136
+ summary: `The model could not be loaded: ${model.loadError}. Fix the files under documentation-robotics/model/.`,
137
+ tool: null
138
+ };
139
+ if (changesets.status === "ok" && changesets.active?.asBuilt)
140
+ return asBuiltStep(changesets.active, changesets.staged);
141
+ if (changesets.status === "ok" && changesets.active) {
142
+ const { name, changes, baseDrifted } = changesets.active, drifted = baseDrifted ? " Its base model has changed since it was opened." : "";
143
+ return {
144
+ summary: `Changeset "${name}" is active with ${changes.total} staged change${changes.total === 1 ? "" : "s"}.${drifted} Read its brief with changeset_brief to pick up the plan.`,
145
+ tool: "changeset_brief"
146
+ };
147
+ }
148
+ if (codeDrift.status === "drift") {
149
+ const files = codeDrift.changedSourceFiles.length + codeDrift.uncommittedSourceFiles.length, sha = codeDrift.modelCommit.sha, drift = `${files} source file${files === 1 ? "" : "s"} the model references changed since the model was last updated, not counting spec migrations (${sha.slice(0, 7)}, ${codeDrift.commitsSince} commit${codeDrift.commitsSince === 1 ? "" : "s"} ago).`;
150
+ if (codeIndex.status !== "fresh") {
151
+ const index = codeIndex.status === "stale" ? "The code index is stale" : codeIndex.status === "fresh-with-uncommitted-edits" ? "Source files were edited after the code index was taken" : "The code has no usable index";
152
+ return {
153
+ summary: `${drift} ${index}: rebuild it with codebase_index, then check the API layer with codebase_verify and model the changes with codebase_extract since ${sha.slice(0, 7)}.`,
154
+ tool: "codebase_index",
155
+ args: INDEX_ARGS,
156
+ then: { tool: "codebase_verify" }
157
+ };
158
+ }
159
+ return {
160
+ summary: `${drift} Check the API layer with codebase_verify, then model the changes with codebase_extract since ${sha.slice(0, 7)}.`,
161
+ tool: "codebase_verify",
162
+ then: { tool: "codebase_extract", args: { since: sha } }
163
+ };
164
+ }
165
+ if (codeIndex.status === "absent")
166
+ return {
167
+ summary: "The code has no index. Build one with codebase_index.",
168
+ tool: "codebase_index",
169
+ args: INDEX_ARGS
170
+ };
171
+ if (codeIndex.status === "stale")
172
+ return {
173
+ summary: `The code index is stale: ${codeIndex.reason ?? `it was built at ${codeIndex.indexedCommit.slice(0, 7)}`}. Refresh it with codebase_index.`,
174
+ tool: "codebase_index",
175
+ args: INDEX_ARGS
176
+ };
177
+ if (codeIndex.status === "fresh-with-uncommitted-edits")
178
+ return {
179
+ summary: `The code index predates uncommitted edits: ${codeIndex.reason}. Refresh it with codebase_index.`,
180
+ tool: "codebase_index",
181
+ args: INDEX_ARGS
182
+ };
183
+ if (changesets.status === "ok" && changesets.staged.length > 0) {
184
+ const names = changesets.staged.map((changeset) => `"${changeset.name}"`).join(", ");
185
+ return {
186
+ summary: `No changeset is active; ${changesets.staged.length} staged: ${names}. Activate one with changeset_activate to continue it, or plan a new change with changeset_create.`,
187
+ tool: "changeset_activate"
188
+ };
189
+ }
190
+ return {
191
+ summary: "The model is current and in step with the code. To plan a change, start with changeset_create.",
192
+ tool: "changeset_create"
193
+ };
194
+ }
195
+ function asBuiltStep(asBuilt, staged) {
196
+ const changes = `${asBuilt.changes.total} staged change${asBuilt.changes.total === 1 ? "" : "s"}`, intro = `Changeset "${asBuilt.name}" is active, with ${changes}: it is the as-built changeset codebase_extract staged from the code, not a plan. Don't build from it or edit it as a plan.`, plans = staged.filter((entry) => entry.id !== asBuilt.id && !entry.asBuilt), plan = (asBuilt.previousActive ? plans.find((entry) => entry.id === asBuilt.previousActive.id) : void 0) ?? (plans.length === 1 ? plans[0] : void 0);
197
+ if (plan)
198
+ return {
199
+ summary: `${intro} It is the as-built side of a verify against the plan "${plan.name}": compare them with changeset_verify (planned: "${plan.name}", against: {changesetId: "${asBuilt.id}"}), and reactivate the plan with changeset_activate before any edits.`,
200
+ tool: "changeset_verify",
201
+ args: { planned: plan.id, against: { changesetId: asBuilt.id } },
202
+ also: {
203
+ summary: `Reactivate the plan "${plan.name}" with changeset_activate before editing anything, so changes stage into it.`,
204
+ tool: "changeset_activate",
205
+ args: { changesetId: plan.id }
206
+ }
207
+ };
208
+ if (plans.length > 1) {
209
+ const names = plans.map((entry) => `"${entry.name}"`).join(", ");
210
+ return {
211
+ summary: `${intro} ${plans.length} plans are staged (${names}), and nothing records which one this build is for. Ask the user, then call changeset_verify with planned: <that plan> and against: {changesetId: "${asBuilt.id}"}, and reactivate the plan with changeset_activate before any edits.`,
212
+ tool: null
213
+ };
214
+ }
215
+ return {
216
+ summary: `${intro} No plan is staged, so it is a keep-as-built catch-up: it holds what was built and is reviewed and landed as itself. Show it to the user with review_open, and land it with changeset_commit when they ask.`,
217
+ tool: "review_open",
218
+ args: { changeset: asBuilt.id }
219
+ };
220
+ }
221
+ async function projectStatusHandler(args) {
222
+ return runTool(async () => jsonResult(await projectStatus(args), { compact: !0 }));
223
+ }
224
+ const projectStatusTool = {
225
+ name: "project_status",
226
+ description: "Where this repo stands with DR, and what to do next: the project root and how it was found, whether a model exists, its spec version against this CLI's, the active and staged changesets, whether the code index exists and is fresh (and any indexing run in progress), code changed since the model last changed (from git), and the viewer running for the project with its link. Ends with nextStep: a sentence and the tool to call. Reads local files and git only. Call it first in a session.",
227
+ inputSchema,
228
+ handler: projectStatusHandler
229
+ };
230
+ export {
231
+ clearProjectStatusSignatures,
232
+ projectStatus,
233
+ projectStatusHandler,
234
+ projectStatusTool,
235
+ suggestNextStep
236
+ };
237
+ //# sourceMappingURL=project-status.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/mcp/tools/project-status.ts"],
4
+ "sourcesContent": ["/**\n * project_status \u2014 where this repo stands with DR, and what to do next. The first call an agent\n * makes in a session.\n *\n * It reads local files and git only: no network, and it never starts the code analyzer. Each\n * section comes from its own collector (project-status-collectors.ts), so one that fails reports\n * an error in its section and the others still answer.\n */\n\nimport path from \"node:path\";\nimport type { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Model } from \"../../core/model.js\";\nimport { findProjectRoot } from \"../../utils/project-paths.js\";\nimport { fileExists } from \"../../utils/file-io.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport { currentProjectRoot, whenProjectRootSettled, type ProjectRootSource } from \"../project-root.js\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { jsonResult, loadModel, reloadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\nimport {\n collectChangesets,\n collectCodeDrift,\n collectCodeIndex,\n collectIndexing,\n collectModel,\n collectSpec,\n collectViewer,\n runGit,\n type ChangesetEntry,\n type ErrorSection,\n type GitRunner,\n type RootResolution,\n type StatusContext,\n} from \"./project-status-collectors.js\";\n\nconst inputSchema = {\n rootPath: rootPathSchema,\n};\n\nexport type ProjectStatusArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\n/** The sections, one collector each. A new section is one more entry here. */\nconst COLLECTORS = {\n model: collectModel,\n spec: collectSpec,\n changesets: collectChangesets,\n codeIndex: collectCodeIndex,\n codeDrift: collectCodeDrift,\n indexing: collectIndexing,\n viewer: collectViewer,\n} as const;\n\ntype Sections = {\n [K in keyof typeof COLLECTORS]: Awaited<ReturnType<(typeof COLLECTORS)[K]>> | ErrorSection;\n};\n\nexport interface NextStep {\n summary: string;\n /** The tool to call, or null when the step is outside DR (update the CLI, fix a file). */\n tool: string | null;\n args?: Record<string, unknown>;\n /** A second call that follows the first. */\n then?: { tool: string; args?: Record<string, unknown> };\n /**\n * Something else that needs doing alongside this step, not after it: an index run in progress,\n * or an index that hasn't seen the latest code, while a changeset is active.\n */\n also?: { summary: string; tool: string; args?: Record<string, unknown> };\n}\n\nexport interface ProjectStatus extends Sections {\n project: { root: string; resolvedBy: RootResolution; projectRoot: string | null };\n nextStep: NextStep;\n}\n\nconst RESOLVED_BY: Record<ProjectRootSource, RootResolution> = {\n env: \"DR_MCP_ROOT_PATH\",\n \"client-roots\": \"mcp-roots\",\n cwd: \"cwd\",\n};\n\n/** Collects every section and picks the next step. `git` is injectable for tests. */\nexport async function projectStatus(\n args: ProjectStatusArgs,\n options: { git?: GitRunner } = {}\n): Promise<ProjectStatus> {\n let root: string;\n let resolvedBy: RootResolution;\n if (args.rootPath) {\n root = path.resolve(args.rootPath);\n resolvedBy = \"rootPath\";\n } else {\n await whenProjectRootSettled();\n const current = currentProjectRoot();\n root = current.root;\n resolvedBy = RESOLVED_BY[current.source];\n }\n\n const projectRoot = await findProjectRoot(root);\n const manifest = projectRoot ? path.join(projectRoot, \"documentation-robotics\", \"model\", \"manifest.yaml\") : null;\n const modelDir = manifest && (await fileExists(manifest)) ? path.dirname(manifest) : null;\n\n let modelPromise: Promise<Model> | undefined;\n const ctx: StatusContext = {\n root,\n resolvedBy,\n projectRoot,\n modelDir,\n model: () => (modelPromise ??= freshModel(args.rootPath, modelDir)),\n git: options.git ?? runGit,\n };\n\n const entries = await Promise.all(\n Object.entries(COLLECTORS).map(async ([key, collect]) => {\n try {\n return [key, await collect(ctx)] as const;\n } catch (error) {\n return [key, { status: \"error\", error: getErrorMessage(error) } satisfies ErrorSection] as const;\n }\n })\n );\n const sections = Object.fromEntries(entries) as Sections;\n\n return {\n project: { root, resolvedBy, projectRoot },\n ...sections,\n nextStep: suggestNextStep(sections, { root, rootPath: args.rootPath }),\n };\n}\n\n/** The model files' signature when this tool last read the model, per rootPath cache key. */\nconst lastSignature = new Map<string, string>();\n\n/** Test-only: forget the recorded signatures. */\nexport function clearProjectStatusSignatures(): void {\n lastSignature.clear();\n}\n\n/**\n * The model as it is on disk now. The server's cached model can be stale after a CLI command, a\n * pull or a hand edit, while git and changesets are read fresh. So the model files are stat'ed\n * (cheap), and the model is reloaded into the shared cache when they changed since this tool last\n * read it, or when this tool has not read it yet.\n */\nasync function freshModel(rootPath: string | undefined, modelDir: string | null): Promise<Model> {\n const key = rootPath ?? \"\";\n const signature = modelDir ? await filesSignature(modelDir) : null;\n if (signature !== null && lastSignature.get(key) === signature) return loadModel(rootPath);\n const model = await reloadModel(rootPath);\n if (signature !== null) lastSignature.set(key, signature);\n return model;\n}\n\n/** File count, summed mtimes and summed sizes of every file under `dir`. */\nasync function filesSignature(dir: string): Promise<string | null> {\n try {\n const entries = await readdir(dir, { recursive: true, withFileTypes: true });\n const stats = await Promise.all(\n entries.filter((entry) => entry.isFile()).map((entry) => stat(path.join(entry.parentPath, entry.name)))\n );\n let mtimes = 0;\n let sizes = 0;\n for (const s of stats) {\n mtimes += s.mtimeMs;\n sizes += s.size;\n }\n return `${stats.length}:${mtimes}:${sizes}`;\n } catch {\n return null;\n }\n}\n\n/**\n * The one thing to do next, in order: create a model, upgrade it, continue the active changeset,\n * index the code when drift needs a fresh index, catch the model up with the code, index the code.\n */\nexport function suggestNextStep(s: Sections, ctx: { root: string; rootPath?: string }): NextStep {\n const step = withIndexNote(whileIndexing(pickNextStep(s, ctx.root), s), s);\n if (!ctx.rootPath) return step;\n // A call that named its project passes it on, so the next call serves the same one.\n const withRoot = (args?: Record<string, unknown>) => ({ ...args, rootPath: ctx.rootPath });\n return {\n ...step,\n ...(step.tool ? { args: withRoot(step.args) } : {}),\n ...(step.then ? { then: { ...step.then, args: withRoot(step.then.args) } } : {}),\n ...(step.also ? { also: { ...step.also, args: withRoot(step.also.args) } } : {}),\n };\n}\n\n/** The call that waits for an index run already going. */\nconst WAIT_ARGS = { status: true, wait: 30 };\n\n/**\n * A step that isn't about the index still says when the index needs attention, so the agent\n * doesn't take an index run in progress, or one that hasn't seen the latest code, as settled.\n * The step itself stands: an active changeset is still the thing to pick up. The index call goes\n * in `also` unless the step already uses it, and in the summary either way.\n */\nfunction withIndexNote(step: NextStep, s: Sections): NextStep {\n if (step.tool === \"codebase_index\") return step;\n let also: NextStep[\"also\"];\n if (s.indexing?.status === \"running\") {\n also = {\n summary: `The code is being indexed (started ${s.indexing.startedAt}); until it is done, codebase tools read the old index. Call codebase_index with status: true and wait: 30 to wait for it.`,\n tool: \"codebase_index\",\n args: WAIT_ARGS,\n };\n } else if (s.changesets?.status === \"ok\" && s.changesets.active) {\n // Without an active changeset, pickNextStep already sends a stale index to codebase_index.\n if (s.codeIndex?.status === \"fresh-with-uncommitted-edits\" || s.codeIndex?.status === \"stale\") {\n const why =\n s.codeIndex.status === \"stale\"\n ? `The code index is stale${s.codeIndex.reason ? `: ${s.codeIndex.reason}` : \"\"}.`\n : `The code index predates uncommitted edits${s.codeIndex.reason ? `: ${s.codeIndex.reason}` : \"\"}.`;\n also = {\n summary: `${why} Refresh it with codebase_index before extracting or verifying against the code.`,\n tool: \"codebase_index\",\n args: INDEX_ARGS,\n };\n }\n }\n if (!also) return step;\n // A step that already has its own `also` (the as-built step's changeset_activate) keeps it; the\n // index still gets said, in the summary.\n if (step.also) return { ...step, summary: `${step.summary} Also: ${also.summary}` };\n return { ...step, summary: `${step.summary} Also: ${also.summary}`, also };\n}\n\n/** A step that would start an index run waits for the one already running instead. */\nfunction whileIndexing(step: NextStep, s: Sections): NextStep {\n if (step.tool !== \"codebase_index\" || s.indexing?.status !== \"running\") return step;\n return {\n summary: `The code is being indexed (started ${s.indexing.startedAt}). Call codebase_index with status: true and wait: 30 until it is done.`,\n tool: \"codebase_index\",\n args: { status: true, wait: 30 },\n ...(step.then ? { then: step.then } : {}),\n };\n}\n\n/** Starting an index run: block up to 30 s for it rather than poll. */\nconst INDEX_ARGS = { wait: 30 };\n\nfunction pickNextStep(s: Sections, root: string): NextStep {\n const ctx = { root };\n const { model, spec, changesets, codeDrift, codeIndex } = s;\n\n if (model.status === \"absent\") {\n return {\n summary: `There is no DR model in ${ctx.root}. Create one with project_init.`,\n tool: \"project_init\",\n };\n }\n if (model.status === \"error\") {\n return { summary: `The model could not be read: ${model.error}`, tool: null };\n }\n\n if (spec.status === \"behind\") {\n const how = spec.migration?.available\n ? \"Preview and apply the migration with project_upgrade.\"\n : \"The CLI has no migration path between them; project_upgrade reports the options.\";\n return {\n summary: `The model is on spec ${spec.model}; this CLI carries ${spec.cli}. ${how}`,\n tool: \"project_upgrade\",\n };\n }\n if (spec.status === \"ahead\") {\n return {\n summary: `The model is on spec ${spec.model}, newer than this CLI's ${spec.cli}. Update the dr CLI before changing the model.`,\n tool: null,\n };\n }\n\n if (model.loadError) {\n return {\n summary: `The model could not be loaded: ${model.loadError}. Fix the files under documentation-robotics/model/.`,\n tool: null,\n };\n }\n\n if (changesets.status === \"ok\" && changesets.active?.asBuilt) {\n return asBuiltStep(changesets.active, changesets.staged);\n }\n\n if (changesets.status === \"ok\" && changesets.active) {\n const { name, changes, baseDrifted } = changesets.active;\n const drifted = baseDrifted ? \" Its base model has changed since it was opened.\" : \"\";\n return {\n summary: `Changeset \"${name}\" is active with ${changes.total} staged change${changes.total === 1 ? \"\" : \"s\"}.${drifted} Read its brief with changeset_brief to pick up the plan.`,\n tool: \"changeset_brief\",\n };\n }\n\n if (codeDrift.status === \"drift\") {\n const files = codeDrift.changedSourceFiles.length + codeDrift.uncommittedSourceFiles.length;\n const sha = codeDrift.modelCommit.sha;\n const drift =\n `${files} source file${files === 1 ? \"\" : \"s\"} the model references changed since the model was last updated, ` +\n `not counting spec migrations (${sha.slice(0, 7)}, ${codeDrift.commitsSince} commit${codeDrift.commitsSince === 1 ? \"\" : \"s\"} ago).`;\n // codebase_verify refuses without a fresh index, so build or refresh it first.\n if (codeIndex.status !== \"fresh\") {\n const index =\n codeIndex.status === \"stale\"\n ? \"The code index is stale\"\n : codeIndex.status === \"fresh-with-uncommitted-edits\"\n ? \"Source files were edited after the code index was taken\"\n : \"The code has no usable index\";\n return {\n summary:\n `${drift} ${index}: rebuild it with codebase_index, then check the API layer with codebase_verify ` +\n `and model the changes with codebase_extract since ${sha.slice(0, 7)}.`,\n tool: \"codebase_index\",\n args: INDEX_ARGS,\n then: { tool: \"codebase_verify\" },\n };\n }\n return {\n summary: `${drift} Check the API layer with codebase_verify, then model the changes with codebase_extract since ${sha.slice(0, 7)}.`,\n tool: \"codebase_verify\",\n then: { tool: \"codebase_extract\", args: { since: sha } },\n };\n }\n\n if (codeIndex.status === \"absent\") {\n return {\n summary: \"The code has no index. Build one with codebase_index.\",\n tool: \"codebase_index\",\n args: INDEX_ARGS,\n };\n }\n if (codeIndex.status === \"stale\") {\n return {\n summary: `The code index is stale: ${codeIndex.reason ?? `it was built at ${codeIndex.indexedCommit.slice(0, 7)}`}. Refresh it with codebase_index.`,\n tool: \"codebase_index\",\n args: INDEX_ARGS,\n };\n }\n if (codeIndex.status === \"fresh-with-uncommitted-edits\") {\n return {\n summary: `The code index predates uncommitted edits: ${codeIndex.reason}. Refresh it with codebase_index.`,\n tool: \"codebase_index\",\n args: INDEX_ARGS,\n };\n }\n\n if (changesets.status === \"ok\" && changesets.staged.length > 0) {\n const names = changesets.staged.map((changeset) => `\"${changeset.name}\"`).join(\", \");\n return {\n summary: `No changeset is active; ${changesets.staged.length} staged: ${names}. Activate one with changeset_activate to continue it, or plan a new change with changeset_create.`,\n tool: \"changeset_activate\",\n };\n }\n\n return {\n summary: \"The model is current and in step with the code. To plan a change, start with changeset_create.\",\n tool: \"changeset_create\",\n };\n}\n\n/**\n * The step for an active as-built changeset (one codebase_extract staged): it holds what was\n * built, not a plan, so it is never \"the plan to pick up\". With a plan staged it is the as-built\n * side of a verify, and the plan is reactivated before any edits; with none, it is a\n * keep-as-built catch-up, reviewed and landed as itself.\n */\nfunction asBuiltStep(asBuilt: ChangesetEntry, staged: ChangesetEntry[]): NextStep {\n const changes = `${asBuilt.changes.total} staged change${asBuilt.changes.total === 1 ? \"\" : \"s\"}`;\n const intro =\n `Changeset \"${asBuilt.name}\" is active, with ${changes}: it is the as-built changeset codebase_extract staged ` +\n \"from the code, not a plan. Don't build from it or edit it as a plan.\";\n const plans = staged.filter((entry) => entry.id !== asBuilt.id && !entry.asBuilt);\n const fromRecord = asBuilt.previousActive ? plans.find((entry) => entry.id === asBuilt.previousActive!.id) : undefined;\n const plan = fromRecord ?? (plans.length === 1 ? plans[0] : undefined);\n\n if (plan) {\n return {\n summary:\n `${intro} It is the as-built side of a verify against the plan \"${plan.name}\": compare them with ` +\n `changeset_verify (planned: \"${plan.name}\", against: {changesetId: \"${asBuilt.id}\"}), and reactivate the plan ` +\n \"with changeset_activate before any edits.\",\n tool: \"changeset_verify\",\n args: { planned: plan.id, against: { changesetId: asBuilt.id } },\n also: {\n summary: `Reactivate the plan \"${plan.name}\" with changeset_activate before editing anything, so changes stage into it.`,\n tool: \"changeset_activate\",\n args: { changesetId: plan.id },\n },\n };\n }\n if (plans.length > 1) {\n const names = plans.map((entry) => `\"${entry.name}\"`).join(\", \");\n return {\n summary:\n `${intro} ${plans.length} plans are staged (${names}), and nothing records which one this build is for. ` +\n `Ask the user, then call changeset_verify with planned: <that plan> and against: {changesetId: \"${asBuilt.id}\"}, ` +\n \"and reactivate the plan with changeset_activate before any edits.\",\n tool: null,\n };\n }\n return {\n summary:\n `${intro} No plan is staged, so it is a keep-as-built catch-up: it holds what was built and is reviewed and ` +\n \"landed as itself. Show it to the user with review_open, and land it with changeset_commit when they ask.\",\n tool: \"review_open\",\n args: { changeset: asBuilt.id },\n };\n}\n\nexport async function projectStatusHandler(args: ProjectStatusArgs): Promise<CallToolResult> {\n return runTool(async () => jsonResult(await projectStatus(args), { compact: true }));\n}\n\nexport const projectStatusTool: McpToolDefinition<typeof inputSchema> = {\n name: \"project_status\",\n description:\n \"Where this repo stands with DR, and what to do next: the project root and how it was found, whether a model exists, its spec version against this CLI's, the active and staged changesets, whether the code index exists and is fresh (and any indexing run in progress), code changed since the model last changed (from git), and the viewer running for the project with its link. Ends with nextStep: a sentence and the tool to call. Reads local files and git only. Call it first in a session.\",\n inputSchema,\n handler: projectStatusHandler,\n};\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }