ctxr-cli 0.33.0 → 0.35.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 (378) hide show
  1. package/README.md +40 -6
  2. package/dist/commands/archive.d.ts +5 -4
  3. package/dist/commands/archive.d.ts.map +1 -1
  4. package/dist/commands/archive.js +7 -7
  5. package/dist/commands/archive.js.map +1 -1
  6. package/dist/commands/catalog-show.d.ts +8 -0
  7. package/dist/commands/catalog-show.d.ts.map +1 -1
  8. package/dist/commands/catalog-show.js +29 -2
  9. package/dist/commands/catalog-show.js.map +1 -1
  10. package/dist/commands/context-gather.d.ts.map +1 -1
  11. package/dist/commands/context-gather.js +3 -2
  12. package/dist/commands/context-gather.js.map +1 -1
  13. package/dist/commands/doctor.d.ts +5 -1
  14. package/dist/commands/doctor.d.ts.map +1 -1
  15. package/dist/commands/doctor.js +4 -0
  16. package/dist/commands/doctor.js.map +1 -1
  17. package/dist/commands/graph-build.d.ts +4 -1
  18. package/dist/commands/graph-build.d.ts.map +1 -1
  19. package/dist/commands/graph-build.js +14 -5
  20. package/dist/commands/graph-build.js.map +1 -1
  21. package/dist/commands/land.d.ts +27 -7
  22. package/dist/commands/land.d.ts.map +1 -1
  23. package/dist/commands/land.js +307 -32
  24. package/dist/commands/land.js.map +1 -1
  25. package/dist/commands/plugin-build.d.ts +33 -0
  26. package/dist/commands/plugin-build.d.ts.map +1 -0
  27. package/dist/commands/plugin-build.js +51 -0
  28. package/dist/commands/plugin-build.js.map +1 -0
  29. package/dist/commands/publish-check.d.ts.map +1 -1
  30. package/dist/commands/publish-check.js +35 -4
  31. package/dist/commands/publish-check.js.map +1 -1
  32. package/dist/commands/publish-gather.d.ts.map +1 -1
  33. package/dist/commands/publish-gather.js +2 -3
  34. package/dist/commands/publish-gather.js.map +1 -1
  35. package/dist/commands/review-list.d.ts +19 -5
  36. package/dist/commands/review-list.d.ts.map +1 -1
  37. package/dist/commands/review-list.js +55 -6
  38. package/dist/commands/review-list.js.map +1 -1
  39. package/dist/commands/rollup-gather.d.ts.map +1 -1
  40. package/dist/commands/rollup-gather.js +2 -3
  41. package/dist/commands/rollup-gather.js.map +1 -1
  42. package/dist/commands/second-opinion.d.ts +33 -0
  43. package/dist/commands/second-opinion.d.ts.map +1 -0
  44. package/dist/commands/second-opinion.js +56 -0
  45. package/dist/commands/second-opinion.js.map +1 -0
  46. package/dist/commands/serve.d.ts.map +1 -1
  47. package/dist/commands/serve.js +14 -2
  48. package/dist/commands/serve.js.map +1 -1
  49. package/dist/commands/session-discard.d.ts +18 -0
  50. package/dist/commands/session-discard.d.ts.map +1 -0
  51. package/dist/commands/session-discard.js +31 -0
  52. package/dist/commands/session-discard.js.map +1 -0
  53. package/dist/commands/session-list.d.ts +17 -6
  54. package/dist/commands/session-list.d.ts.map +1 -1
  55. package/dist/commands/session-list.js +31 -11
  56. package/dist/commands/session-list.js.map +1 -1
  57. package/dist/commands/session-rebase.d.ts +18 -0
  58. package/dist/commands/session-rebase.d.ts.map +1 -0
  59. package/dist/commands/session-rebase.js +43 -0
  60. package/dist/commands/session-rebase.js.map +1 -0
  61. package/dist/commands/session-start.d.ts +8 -0
  62. package/dist/commands/session-start.d.ts.map +1 -1
  63. package/dist/commands/session-start.js +52 -38
  64. package/dist/commands/session-start.js.map +1 -1
  65. package/dist/commands/session-status.d.ts +17 -0
  66. package/dist/commands/session-status.d.ts.map +1 -0
  67. package/dist/commands/session-status.js +38 -0
  68. package/dist/commands/session-status.js.map +1 -0
  69. package/dist/commands/session-submit.d.ts +23 -0
  70. package/dist/commands/session-submit.d.ts.map +1 -0
  71. package/dist/commands/session-submit.js +42 -0
  72. package/dist/commands/session-submit.js.map +1 -0
  73. package/dist/commands/shared-stores-status.d.ts +24 -0
  74. package/dist/commands/shared-stores-status.d.ts.map +1 -0
  75. package/dist/commands/shared-stores-status.js +51 -0
  76. package/dist/commands/shared-stores-status.js.map +1 -0
  77. package/dist/commands/shared-stores-sync.d.ts +27 -0
  78. package/dist/commands/shared-stores-sync.d.ts.map +1 -0
  79. package/dist/commands/shared-stores-sync.js +115 -0
  80. package/dist/commands/shared-stores-sync.js.map +1 -0
  81. package/dist/commands/verify.d.ts.map +1 -1
  82. package/dist/commands/verify.js +2 -4
  83. package/dist/commands/verify.js.map +1 -1
  84. package/dist/config/schema.d.ts +16 -0
  85. package/dist/config/schema.d.ts.map +1 -1
  86. package/dist/config/schema.js +32 -0
  87. package/dist/config/schema.js.map +1 -1
  88. package/dist/core/agents-doc.d.ts +10 -0
  89. package/dist/core/agents-doc.d.ts.map +1 -1
  90. package/dist/core/agents-doc.js +26 -1
  91. package/dist/core/agents-doc.js.map +1 -1
  92. package/dist/core/approval/decision.d.ts +39 -1
  93. package/dist/core/approval/decision.d.ts.map +1 -1
  94. package/dist/core/approval/decision.js +53 -6
  95. package/dist/core/approval/decision.js.map +1 -1
  96. package/dist/core/approval/session-group.d.ts +156 -0
  97. package/dist/core/approval/session-group.d.ts.map +1 -0
  98. package/dist/core/approval/session-group.js +359 -0
  99. package/dist/core/approval/session-group.js.map +1 -0
  100. package/dist/core/approval/session-marker.d.ts +79 -0
  101. package/dist/core/approval/session-marker.d.ts.map +1 -0
  102. package/dist/core/approval/session-marker.js +146 -0
  103. package/dist/core/approval/session-marker.js.map +1 -0
  104. package/dist/core/approval/store-forges.d.ts +15 -0
  105. package/dist/core/approval/store-forges.d.ts.map +1 -0
  106. package/dist/core/approval/store-forges.js +33 -0
  107. package/dist/core/approval/store-forges.js.map +1 -0
  108. package/dist/core/browse/approve.d.ts +8 -0
  109. package/dist/core/browse/approve.d.ts.map +1 -1
  110. package/dist/core/browse/approve.js +366 -48
  111. package/dist/core/browse/approve.js.map +1 -1
  112. package/dist/core/browse/link-resolver.d.ts +9 -4
  113. package/dist/core/browse/link-resolver.d.ts.map +1 -1
  114. package/dist/core/browse/link-resolver.js +12 -7
  115. package/dist/core/browse/link-resolver.js.map +1 -1
  116. package/dist/core/browse/review.d.ts +5 -0
  117. package/dist/core/browse/review.d.ts.map +1 -1
  118. package/dist/core/browse/review.js +8 -0
  119. package/dist/core/browse/review.js.map +1 -1
  120. package/dist/core/checks/integrity-checks.d.ts.map +1 -1
  121. package/dist/core/checks/integrity-checks.js +7 -1
  122. package/dist/core/checks/integrity-checks.js.map +1 -1
  123. package/dist/core/checks/manifest.d.ts.map +1 -1
  124. package/dist/core/checks/manifest.js +2 -0
  125. package/dist/core/checks/manifest.js.map +1 -1
  126. package/dist/core/checks/shared-stores-checks.d.ts +17 -0
  127. package/dist/core/checks/shared-stores-checks.d.ts.map +1 -0
  128. package/dist/core/checks/shared-stores-checks.js +84 -0
  129. package/dist/core/checks/shared-stores-checks.js.map +1 -0
  130. package/dist/core/errors.d.ts +17 -0
  131. package/dist/core/errors.d.ts.map +1 -1
  132. package/dist/core/errors.js +21 -0
  133. package/dist/core/errors.js.map +1 -1
  134. package/dist/core/forge/github.d.ts +14 -0
  135. package/dist/core/forge/github.d.ts.map +1 -1
  136. package/dist/core/forge/github.js +17 -0
  137. package/dist/core/forge/github.js.map +1 -1
  138. package/dist/core/fs/atomic.d.ts +3 -2
  139. package/dist/core/fs/atomic.d.ts.map +1 -1
  140. package/dist/core/fs/atomic.js +3 -2
  141. package/dist/core/fs/atomic.js.map +1 -1
  142. package/dist/core/git/fast-forward.d.ts +23 -0
  143. package/dist/core/git/fast-forward.d.ts.map +1 -0
  144. package/dist/core/git/fast-forward.js +38 -0
  145. package/dist/core/git/fast-forward.js.map +1 -0
  146. package/dist/core/git/repo.d.ts +11 -0
  147. package/dist/core/git/repo.d.ts.map +1 -1
  148. package/dist/core/git/repo.js +25 -0
  149. package/dist/core/git/repo.js.map +1 -1
  150. package/dist/core/graph/model.d.ts +27 -0
  151. package/dist/core/graph/model.d.ts.map +1 -1
  152. package/dist/core/graph/model.js +68 -2
  153. package/dist/core/graph/model.js.map +1 -1
  154. package/dist/core/graph/persist.d.ts.map +1 -1
  155. package/dist/core/graph/persist.js +3 -2
  156. package/dist/core/graph/persist.js.map +1 -1
  157. package/dist/core/mcp/cli-runner.d.ts +41 -0
  158. package/dist/core/mcp/cli-runner.d.ts.map +1 -0
  159. package/dist/core/mcp/cli-runner.js +81 -0
  160. package/dist/core/mcp/cli-runner.js.map +1 -0
  161. package/dist/core/mcp/jsonrpc.d.ts +13 -1
  162. package/dist/core/mcp/jsonrpc.d.ts.map +1 -1
  163. package/dist/core/mcp/jsonrpc.js +1 -1
  164. package/dist/core/mcp/jsonrpc.js.map +1 -1
  165. package/dist/core/mcp/member-sessions.d.ts +48 -0
  166. package/dist/core/mcp/member-sessions.d.ts.map +1 -0
  167. package/dist/core/mcp/member-sessions.js +85 -0
  168. package/dist/core/mcp/member-sessions.js.map +1 -0
  169. package/dist/core/mcp/ownership.d.ts +51 -0
  170. package/dist/core/mcp/ownership.d.ts.map +1 -0
  171. package/dist/core/mcp/ownership.js +101 -0
  172. package/dist/core/mcp/ownership.js.map +1 -0
  173. package/dist/core/mcp/paths.d.ts +48 -0
  174. package/dist/core/mcp/paths.d.ts.map +1 -0
  175. package/dist/core/mcp/paths.js +111 -0
  176. package/dist/core/mcp/paths.js.map +1 -0
  177. package/dist/core/mcp/sessions.d.ts +25 -50
  178. package/dist/core/mcp/sessions.d.ts.map +1 -1
  179. package/dist/core/mcp/sessions.js +31 -123
  180. package/dist/core/mcp/sessions.js.map +1 -1
  181. package/dist/core/mcp/tool-map.d.ts +94 -0
  182. package/dist/core/mcp/tool-map.d.ts.map +1 -0
  183. package/dist/core/mcp/tool-map.js +211 -0
  184. package/dist/core/mcp/tool-map.js.map +1 -0
  185. package/dist/core/mcp/tools/capture.d.ts +7 -2
  186. package/dist/core/mcp/tools/capture.d.ts.map +1 -1
  187. package/dist/core/mcp/tools/capture.js +69 -18
  188. package/dist/core/mcp/tools/capture.js.map +1 -1
  189. package/dist/core/mcp/tools/cli.d.ts +97 -0
  190. package/dist/core/mcp/tools/cli.d.ts.map +1 -0
  191. package/dist/core/mcp/tools/cli.js +271 -0
  192. package/dist/core/mcp/tools/cli.js.map +1 -0
  193. package/dist/core/mcp/tools/edit.d.ts +62 -28
  194. package/dist/core/mcp/tools/edit.d.ts.map +1 -1
  195. package/dist/core/mcp/tools/edit.js +182 -153
  196. package/dist/core/mcp/tools/edit.js.map +1 -1
  197. package/dist/core/mcp/tools/files.d.ts +37 -11
  198. package/dist/core/mcp/tools/files.d.ts.map +1 -1
  199. package/dist/core/mcp/tools/files.js +122 -100
  200. package/dist/core/mcp/tools/files.js.map +1 -1
  201. package/dist/core/mcp/tools/index.d.ts +12 -3
  202. package/dist/core/mcp/tools/index.d.ts.map +1 -1
  203. package/dist/core/mcp/tools/index.js +161 -58
  204. package/dist/core/mcp/tools/index.js.map +1 -1
  205. package/dist/core/mcp/tools/sessions.d.ts +145 -0
  206. package/dist/core/mcp/tools/sessions.d.ts.map +1 -0
  207. package/dist/core/mcp/tools/sessions.js +226 -0
  208. package/dist/core/mcp/tools/sessions.js.map +1 -0
  209. package/dist/core/notes/list.d.ts.map +1 -1
  210. package/dist/core/notes/list.js +5 -0
  211. package/dist/core/notes/list.js.map +1 -1
  212. package/dist/core/plugin/build.d.ts +70 -0
  213. package/dist/core/plugin/build.d.ts.map +1 -0
  214. package/dist/core/plugin/build.js +159 -0
  215. package/dist/core/plugin/build.js.map +1 -0
  216. package/dist/core/plugin/routes.d.ts +35 -0
  217. package/dist/core/plugin/routes.d.ts.map +1 -0
  218. package/dist/core/plugin/routes.js +77 -0
  219. package/dist/core/plugin/routes.js.map +1 -0
  220. package/dist/core/plugin/zip.d.ts +17 -0
  221. package/dist/core/plugin/zip.d.ts.map +1 -0
  222. package/dist/core/plugin/zip.js +75 -0
  223. package/dist/core/plugin/zip.js.map +1 -0
  224. package/dist/core/reconcile.d.ts.map +1 -1
  225. package/dist/core/reconcile.js +2 -1
  226. package/dist/core/reconcile.js.map +1 -1
  227. package/dist/core/retrieval/pass.d.ts.map +1 -1
  228. package/dist/core/retrieval/pass.js +5 -4
  229. package/dist/core/retrieval/pass.js.map +1 -1
  230. package/dist/core/rollup.d.ts.map +1 -1
  231. package/dist/core/rollup.js +2 -3
  232. package/dist/core/rollup.js.map +1 -1
  233. package/dist/core/root.d.ts.map +1 -1
  234. package/dist/core/root.js +33 -2
  235. package/dist/core/root.js.map +1 -1
  236. package/dist/core/second-opinion/environment.d.ts +21 -0
  237. package/dist/core/second-opinion/environment.d.ts.map +1 -0
  238. package/dist/core/second-opinion/environment.js +70 -0
  239. package/dist/core/second-opinion/environment.js.map +1 -0
  240. package/dist/core/second-opinion/judge.d.ts +29 -0
  241. package/dist/core/second-opinion/judge.d.ts.map +1 -0
  242. package/dist/core/second-opinion/judge.js +55 -0
  243. package/dist/core/second-opinion/judge.js.map +1 -0
  244. package/dist/core/second-opinion/launch.d.ts +16 -0
  245. package/dist/core/second-opinion/launch.d.ts.map +1 -0
  246. package/dist/core/second-opinion/launch.js +75 -0
  247. package/dist/core/second-opinion/launch.js.map +1 -0
  248. package/dist/core/second-opinion/lineup.d.ts +82 -0
  249. package/dist/core/second-opinion/lineup.d.ts.map +1 -0
  250. package/dist/core/second-opinion/lineup.js +113 -0
  251. package/dist/core/second-opinion/lineup.js.map +1 -0
  252. package/dist/core/second-opinion/modes.d.ts +98 -0
  253. package/dist/core/second-opinion/modes.d.ts.map +1 -0
  254. package/dist/core/second-opinion/modes.js +224 -0
  255. package/dist/core/second-opinion/modes.js.map +1 -0
  256. package/dist/core/second-opinion/prompts.d.ts +18 -0
  257. package/dist/core/second-opinion/prompts.d.ts.map +1 -0
  258. package/dist/core/second-opinion/prompts.js +65 -0
  259. package/dist/core/second-opinion/prompts.js.map +1 -0
  260. package/dist/core/session/commit.d.ts +29 -0
  261. package/dist/core/session/commit.d.ts.map +1 -0
  262. package/dist/core/session/commit.js +22 -0
  263. package/dist/core/session/commit.js.map +1 -0
  264. package/dist/core/session/discard.d.ts +24 -0
  265. package/dist/core/session/discard.d.ts.map +1 -0
  266. package/dist/core/session/discard.js +68 -0
  267. package/dist/core/session/discard.js.map +1 -0
  268. package/dist/core/session/list.d.ts +48 -0
  269. package/dist/core/session/list.d.ts.map +1 -0
  270. package/dist/core/session/list.js +55 -0
  271. package/dist/core/session/list.js.map +1 -0
  272. package/dist/core/session/rebase.d.ts +34 -0
  273. package/dist/core/session/rebase.d.ts.map +1 -0
  274. package/dist/core/session/rebase.js +87 -0
  275. package/dist/core/session/rebase.js.map +1 -0
  276. package/dist/core/session/remote.d.ts +80 -0
  277. package/dist/core/session/remote.d.ts.map +1 -0
  278. package/dist/core/session/remote.js +102 -0
  279. package/dist/core/session/remote.js.map +1 -0
  280. package/dist/core/session/resolve.d.ts +41 -0
  281. package/dist/core/session/resolve.d.ts.map +1 -0
  282. package/dist/core/session/resolve.js +109 -0
  283. package/dist/core/session/resolve.js.map +1 -0
  284. package/dist/core/session/start.d.ts +46 -0
  285. package/dist/core/session/start.d.ts.map +1 -0
  286. package/dist/core/session/start.js +33 -0
  287. package/dist/core/session/start.js.map +1 -0
  288. package/dist/core/session/status.d.ts +47 -0
  289. package/dist/core/session/status.d.ts.map +1 -0
  290. package/dist/core/session/status.js +55 -0
  291. package/dist/core/session/status.js.map +1 -0
  292. package/dist/core/session/submit.d.ts +67 -0
  293. package/dist/core/session/submit.d.ts.map +1 -0
  294. package/dist/core/session/submit.js +254 -0
  295. package/dist/core/session/submit.js.map +1 -0
  296. package/dist/core/shared-stores-location.d.ts +17 -0
  297. package/dist/core/shared-stores-location.d.ts.map +1 -0
  298. package/dist/core/shared-stores-location.js +22 -0
  299. package/dist/core/shared-stores-location.js.map +1 -0
  300. package/dist/core/shared-stores.d.ts +69 -0
  301. package/dist/core/shared-stores.d.ts.map +1 -0
  302. package/dist/core/shared-stores.js +100 -0
  303. package/dist/core/shared-stores.js.map +1 -0
  304. package/dist/core/skills.d.ts +20 -2
  305. package/dist/core/skills.d.ts.map +1 -1
  306. package/dist/core/skills.js +70 -13
  307. package/dist/core/skills.js.map +1 -1
  308. package/dist/run.d.ts +12 -0
  309. package/dist/run.d.ts.map +1 -1
  310. package/dist/run.js +194 -55
  311. package/dist/run.js.map +1 -1
  312. package/dist/version.d.ts +1 -1
  313. package/dist/version.js +1 -1
  314. package/package.json +1 -1
  315. package/templates/agents/shared-stores.md +11 -0
  316. package/templates/approve/copies-missing.md +1 -0
  317. package/templates/approve/elsewhere-heading.md +1 -0
  318. package/templates/approve/elsewhere-intro.md +1 -0
  319. package/templates/approve/homed-elsewhere.md +1 -0
  320. package/templates/approve/not-decider.md +1 -0
  321. package/templates/approve/part-heading.md +1 -0
  322. package/templates/approve/parts-changed.md +1 -0
  323. package/templates/approve/session-decision-note.md +1 -0
  324. package/templates/approve/session-intro.md +1 -0
  325. package/templates/approve/session-no-decision.md +1 -0
  326. package/templates/approve/store-unreachable.md +1 -0
  327. package/templates/land/resolver.md +2 -0
  328. package/templates/mcp/Delete.md +6 -0
  329. package/templates/mcp/Edit.md +6 -5
  330. package/templates/mcp/Glob.md +2 -2
  331. package/templates/mcp/Grep.md +2 -1
  332. package/templates/mcp/Move.md +7 -0
  333. package/templates/mcp/Read.md +4 -4
  334. package/templates/mcp/Write.md +4 -4
  335. package/templates/mcp/ctxr.md +7 -0
  336. package/templates/mcp/ctxr_write.md +8 -0
  337. package/templates/mcp/server-instructions.md +11 -3
  338. package/templates/mcp/session_discard.md +4 -0
  339. package/templates/mcp/session_list.md +7 -0
  340. package/templates/mcp/session_rebase.md +5 -0
  341. package/templates/mcp/session_start.md +7 -0
  342. package/templates/mcp/session_status.md +3 -0
  343. package/templates/mcp/session_submit.md +8 -0
  344. package/templates/plugin/README.md +13 -0
  345. package/templates/plugin/chatgpt-mcp.json +19 -0
  346. package/templates/plugin/chatgpt-plugin.json +13 -0
  347. package/templates/plugin/claude-mcp.json +8 -0
  348. package/templates/plugin/claude-plugin.json +6 -0
  349. package/templates/plugin/page.html +47 -0
  350. package/templates/second-opinion/poll-answer.md +7 -0
  351. package/templates/second-opinion/taste-panel.md +14 -0
  352. package/templates/session/pages/bare-route.md +2 -0
  353. package/templates/session/pages/block.md +8 -0
  354. package/templates/session/pages/condition-preview.md +1 -0
  355. package/templates/session/pages/condition.md +1 -0
  356. package/templates/session/pages/moved.md +1 -0
  357. package/templates/session/pages/stops-working.md +1 -0
  358. package/templates/session/pages/table-head-preview.md +2 -0
  359. package/templates/session/pages/table-head.md +2 -0
  360. package/templates/skills/ctxr-connection-finding.md +4 -1
  361. package/templates/skills/ctxr-land.md +26 -7
  362. package/templates/skills/ctxr-placement.md +10 -0
  363. package/templates/skills/ctxr-publish.md +2 -1
  364. package/templates/skills/ctxr-rollup.md +3 -0
  365. package/templates/skills/ctxr-second-opinion.md +52 -36
  366. package/templates/skills/ctxr-session-lifecycle.md +60 -33
  367. package/templates/skills/ctxr-submit.md +65 -56
  368. package/templates/skills/mcp/_preamble.md +44 -0
  369. package/dist/core/mcp/drafts.d.ts +0 -30
  370. package/dist/core/mcp/drafts.d.ts.map +0 -1
  371. package/dist/core/mcp/drafts.js +0 -52
  372. package/dist/core/mcp/drafts.js.map +0 -1
  373. package/templates/skills/ctxr-second-opinion/run.mjs +0 -542
  374. /package/templates/{skills/ctxr-second-opinion → second-opinion}/critic-contract.md +0 -0
  375. /package/templates/{skills/ctxr-second-opinion → second-opinion}/lenses.md +0 -0
  376. /package/templates/{skills/ctxr-second-opinion → second-opinion}/personas/architect.md +0 -0
  377. /package/templates/{skills/ctxr-second-opinion → second-opinion}/personas/pragmatist.md +0 -0
  378. /package/templates/{skills/ctxr-second-opinion → second-opinion}/personas/skeptic.md +0 -0
package/dist/run.js CHANGED
@@ -19,9 +19,17 @@ import * as publishCheckCommand from './commands/publish-check.js';
19
19
  import * as publishUrlsCommand from './commands/publish-urls.js';
20
20
  import * as publishNewCommand from './commands/publish-new.js';
21
21
  import * as publishStampCommand from './commands/publish-stamp.js';
22
+ import * as pluginBuildCommand from './commands/plugin-build.js';
22
23
  import * as reviewListCommand from './commands/review-list.js';
24
+ import * as secondOpinionCommand from './commands/second-opinion.js';
25
+ import * as sharedStoresStatusCommand from './commands/shared-stores-status.js';
26
+ import * as sharedStoresSyncCommand from './commands/shared-stores-sync.js';
23
27
  import * as sessionCaptureCommand from './commands/session-capture.js';
28
+ import * as sessionDiscardCommand from './commands/session-discard.js';
24
29
  import * as sessionListCommand from './commands/session-list.js';
30
+ import * as sessionRebaseCommand from './commands/session-rebase.js';
31
+ import * as sessionStatusCommand from './commands/session-status.js';
32
+ import * as sessionSubmitCommand from './commands/session-submit.js';
25
33
  import * as serveCommand from './commands/serve.js';
26
34
  import * as sessionStartCommand from './commands/session-start.js';
27
35
  import * as rollupGatherCommand from './commands/rollup-gather.js';
@@ -161,12 +169,12 @@ function commandPathFor(program, argv) {
161
169
  function collect(value, previous) {
162
170
  return [...previous, value];
163
171
  }
164
- export async function run(argv, env) {
165
- if (isGlobalVersionRequest(argv)) {
166
- const jsonMode = argv.includes('--json');
167
- const runEnv = { ...env, noInput: env.noInput || argv.includes('--no-input') || jsonMode };
168
- return runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv));
169
- }
172
+ /**
173
+ * The command tree, built once per invocation. Exported so the MCP surface's
174
+ * tool/command alignment check (serve-the-session-lifecycle-to-chat-apps D9)
175
+ * reads the CLI's real command registry rather than a copy of it.
176
+ */
177
+ export function buildProgram(env) {
170
178
  const program = new Command();
171
179
  program
172
180
  .name('ctxr')
@@ -178,7 +186,7 @@ export async function run(argv, env) {
178
186
  .option('--root <path>', 'store root (overrides CONTEXTURE_STORE_ROOT)')
179
187
  .option('--json', 'emit machine-readable output')
180
188
  .option('--no-input', 'never prompt; fail loud instead of blocking');
181
- let result = ExitCode.Ok;
189
+ const state = { result: ExitCode.Ok };
182
190
  program
183
191
  .command('init')
184
192
  .description('create a new context store, or reconcile an existing one')
@@ -187,7 +195,7 @@ export async function run(argv, env) {
187
195
  .option('--harness <ids>', `comma-separated harness-generation adapters to target (${initCommand.SELECTABLE_HARNESS_IDS.join(', ')}), or "none"`)
188
196
  .action(async (cmdOpts, cmd) => {
189
197
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
190
- result = await runCommand('init', runEnv, jsonMode, () => initCommand.execute(runEnv, { root, profile: cmdOpts.profile, taxonomy: cmdOpts.taxonomy, harness: cmdOpts.harness }));
198
+ state.result = await runCommand('init', runEnv, jsonMode, () => initCommand.execute(runEnv, { root, profile: cmdOpts.profile, taxonomy: cmdOpts.taxonomy, harness: cmdOpts.harness }));
191
199
  });
192
200
  program
193
201
  .command('doctor')
@@ -195,7 +203,7 @@ export async function run(argv, env) {
195
203
  .option('--staged', 'check staged changes only (used by the pre-commit hook)')
196
204
  .action(async (cmdOpts, cmd) => {
197
205
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
198
- result = await runCommand('doctor', runEnv, jsonMode, async () => {
206
+ state.result = await runCommand('doctor', runEnv, jsonMode, async () => {
199
207
  const store = await openStore(runEnv, { root });
200
208
  return doctorCommand.execute(runEnv, store, { staged: cmdOpts.staged });
201
209
  });
@@ -208,7 +216,7 @@ export async function run(argv, env) {
208
216
  .requiredOption('--text <text>', 'the line to append')
209
217
  .action(async (notePath, cmdOpts, cmd) => {
210
218
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
211
- result = await runCommand('entry.append', runEnv, jsonMode, async () => {
219
+ state.result = await runCommand('entry.append', runEnv, jsonMode, async () => {
212
220
  const store = await openStore(runEnv, { root });
213
221
  return entryAppendCommand.execute(runEnv, store, { path: notePath, region: cmdOpts.region, text: cmdOpts.text });
214
222
  });
@@ -219,7 +227,7 @@ export async function run(argv, env) {
219
227
  .description('regenerate every catalog section, preserving authored glosses')
220
228
  .action(async (_cmdOpts, cmd) => {
221
229
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
222
- result = await runCommand('catalog.build', runEnv, jsonMode, async () => {
230
+ state.result = await runCommand('catalog.build', runEnv, jsonMode, async () => {
223
231
  const store = await openStore(runEnv, { root });
224
232
  return catalogBuildCommand.execute(store);
225
233
  });
@@ -230,7 +238,7 @@ export async function run(argv, env) {
230
238
  .option('--stale', 'also report entries whose note has changed since the gloss was confirmed')
231
239
  .action(async (cmdOpts, cmd) => {
232
240
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
233
- result = await runCommand('catalog.check', runEnv, jsonMode, async () => {
241
+ state.result = await runCommand('catalog.check', runEnv, jsonMode, async () => {
234
242
  const store = await openStore(runEnv, { root });
235
243
  return catalogCheckCommand.execute(store, { stale: cmdOpts.stale });
236
244
  });
@@ -241,7 +249,7 @@ export async function run(argv, env) {
241
249
  .requiredOption('--section <id>', 'the section id to print')
242
250
  .action(async (cmdOpts, cmd) => {
243
251
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
244
- result = await runCommand('catalog.show', runEnv, jsonMode, async () => {
252
+ state.result = await runCommand('catalog.show', runEnv, jsonMode, async () => {
245
253
  const store = await openStore(runEnv, { root });
246
254
  return catalogShowCommand.execute(store, { section: cmdOpts.section });
247
255
  });
@@ -260,7 +268,7 @@ export async function run(argv, env) {
260
268
  .option('--max-notes <n>', 'cap the returned set; truncation is reported, never silent', (v) => Number.parseInt(v, 10))
261
269
  .action(async (cmdOpts, cmd) => {
262
270
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
263
- result = await runCommand('context.gather', runEnv, jsonMode, async () => {
271
+ state.result = await runCommand('context.gather', runEnv, jsonMode, async () => {
264
272
  const store = await openStore(runEnv, { root });
265
273
  return contextGatherCommand.execute(store, {
266
274
  seed: cmdOpts.seed,
@@ -281,7 +289,7 @@ export async function run(argv, env) {
281
289
  .option('--emit-records', 'also emit a stable per-note record list {id, path, gloss, hash}')
282
290
  .action(async (cmdOpts, cmd) => {
283
291
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
284
- result = await runCommand('graph.build', runEnv, jsonMode, async () => {
292
+ state.result = await runCommand('graph.build', runEnv, jsonMode, async () => {
285
293
  const store = await openStore(runEnv, { root });
286
294
  return graphBuildCommand.execute(store, { emitRecords: cmdOpts.emitRecords });
287
295
  });
@@ -297,7 +305,7 @@ export async function run(argv, env) {
297
305
  const flags = { since: cmdOpts.since, until: cmdOpts.until, format: cmdOpts.format };
298
306
  // review-the-knowledge-diff (D9): `--format markdown` is the whole stdout — the
299
307
  // block rides as the human summary, which the reporter writes verbatim and alone.
300
- result = await runCommand('graph.diff', runEnv, jsonMode, async () => {
308
+ state.result = await runCommand('graph.diff', runEnv, jsonMode, async () => {
301
309
  graphDiffCommand.checkFlags(flags, jsonMode);
302
310
  const store = await openStore(runEnv, { root });
303
311
  return graphDiffCommand.execute(store, flags, jsonMode);
@@ -312,7 +320,7 @@ export async function run(argv, env) {
312
320
  .option('--type <name>', 'follow only edges of this type (a configured relation name, or link)')
313
321
  .action(async (node, cmdOpts, cmd) => {
314
322
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
315
- result = await runCommand('graph.query.neighbors', runEnv, jsonMode, async () => {
323
+ state.result = await runCommand('graph.query.neighbors', runEnv, jsonMode, async () => {
316
324
  const store = await openStore(runEnv, { root });
317
325
  return graphQueryCommand.executeNeighbors(store, {
318
326
  node,
@@ -327,7 +335,7 @@ export async function run(argv, env) {
327
335
  .description('shortest path between two nodes, if one exists')
328
336
  .action(async (from, to, _cmdOpts, cmd) => {
329
337
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
330
- result = await runCommand('graph.query.path', runEnv, jsonMode, async () => {
338
+ state.result = await runCommand('graph.query.path', runEnv, jsonMode, async () => {
331
339
  const store = await openStore(runEnv, { root });
332
340
  return graphQueryCommand.executePath(store, { from, to });
333
341
  });
@@ -337,7 +345,7 @@ export async function run(argv, env) {
337
345
  .description('the induced subgraph over the given node ids')
338
346
  .action(async (ids, _cmdOpts, cmd) => {
339
347
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
340
- result = await runCommand('graph.query.subgraph', runEnv, jsonMode, async () => {
348
+ state.result = await runCommand('graph.query.subgraph', runEnv, jsonMode, async () => {
341
349
  const store = await openStore(runEnv, { root });
342
350
  return graphQueryCommand.executeSubgraph(store, { ids });
343
351
  });
@@ -348,7 +356,7 @@ export async function run(argv, env) {
348
356
  .option('--top <n>', 'how many to list', (v) => Number.parseInt(v, 10), 10)
349
357
  .action(async (cmdOpts, cmd) => {
350
358
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
351
- result = await runCommand('graph.query.hubs', runEnv, jsonMode, async () => {
359
+ state.result = await runCommand('graph.query.hubs', runEnv, jsonMode, async () => {
352
360
  const store = await openStore(runEnv, { root });
353
361
  return graphQueryCommand.executeHubs(store, { top: cmdOpts.top });
354
362
  });
@@ -358,7 +366,7 @@ export async function run(argv, env) {
358
366
  .description('every positional cluster with its note count')
359
367
  .action(async (_cmdOpts, cmd) => {
360
368
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
361
- result = await runCommand('graph.query.clusters', runEnv, jsonMode, async () => {
369
+ state.result = await runCommand('graph.query.clusters', runEnv, jsonMode, async () => {
362
370
  const store = await openStore(runEnv, { root });
363
371
  return graphQueryCommand.executeClusters(store, {});
364
372
  });
@@ -369,7 +377,7 @@ export async function run(argv, env) {
369
377
  .option('--top <n>', 'how many to list (default: the configured bridge limit)', (v) => Number.parseInt(v, 10))
370
378
  .action(async (cmdOpts, cmd) => {
371
379
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
372
- result = await runCommand('graph.query.bridges', runEnv, jsonMode, async () => {
380
+ state.result = await runCommand('graph.query.bridges', runEnv, jsonMode, async () => {
373
381
  const store = await openStore(runEnv, { root });
374
382
  return graphQueryCommand.executeBridges(store, { top: cmdOpts.top });
375
383
  });
@@ -379,7 +387,7 @@ export async function run(argv, env) {
379
387
  .description('nodes with no links in or out')
380
388
  .action(async (_cmdOpts, cmd) => {
381
389
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
382
- result = await runCommand('graph.query.orphans', runEnv, jsonMode, async () => {
390
+ state.result = await runCommand('graph.query.orphans', runEnv, jsonMode, async () => {
383
391
  const store = await openStore(runEnv, { root });
384
392
  return graphQueryCommand.executeOrphans(store, {});
385
393
  });
@@ -392,7 +400,7 @@ export async function run(argv, env) {
392
400
  .requiredOption('--source-id <id>', 'a stable identifier for this specific source')
393
401
  .action(async (capturePath, cmdOpts, cmd) => {
394
402
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
395
- result = await runCommand('ingest', runEnv, jsonMode, async () => {
403
+ state.result = await runCommand('ingest', runEnv, jsonMode, async () => {
396
404
  const store = await openStore(runEnv, { root });
397
405
  return ingestCommand.execute(runEnv, store, {
398
406
  path: capturePath,
@@ -408,7 +416,7 @@ export async function run(argv, env) {
408
416
  .description('the canonicalized-content hash of a file')
409
417
  .action(async (notePath, _cmdOpts, cmd) => {
410
418
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
411
- result = await runCommand('source.hash', runEnv, jsonMode, async () => {
419
+ state.result = await runCommand('source.hash', runEnv, jsonMode, async () => {
412
420
  const store = await openStore(runEnv, { root });
413
421
  return sourceHashCommand.execute(runEnv, store, { path: notePath });
414
422
  });
@@ -419,7 +427,7 @@ export async function run(argv, env) {
419
427
  .requiredOption('--source-id <id>', "the candidate material's source identifier")
420
428
  .action(async (notePath, cmdOpts, cmd) => {
421
429
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
422
- result = await runCommand('source.check', runEnv, jsonMode, async () => {
430
+ state.result = await runCommand('source.check', runEnv, jsonMode, async () => {
423
431
  const store = await openStore(runEnv, { root });
424
432
  return sourceCheckCommand.execute(runEnv, store, { path: notePath, sourceId: cmdOpts.sourceId });
425
433
  });
@@ -431,7 +439,7 @@ export async function run(argv, env) {
431
439
  .option('--hash <hash>', 'the content hash to record (default: computed from the note\'s current body)')
432
440
  .action(async (notePath, cmdOpts, cmd) => {
433
441
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
434
- result = await runCommand('source.stamp', runEnv, jsonMode, async () => {
442
+ state.result = await runCommand('source.stamp', runEnv, jsonMode, async () => {
435
443
  const store = await openStore(runEnv, { root });
436
444
  return sourceStampCommand.execute(runEnv, store, { path: notePath, id: cmdOpts.id, hash: cmdOpts.hash });
437
445
  });
@@ -442,7 +450,7 @@ export async function run(argv, env) {
442
450
  .requiredOption('--id <id>', 'the alternative source identifier')
443
451
  .action(async (notePath, cmdOpts, cmd) => {
444
452
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
445
- result = await runCommand('source.add-alt', runEnv, jsonMode, async () => {
453
+ state.result = await runCommand('source.add-alt', runEnv, jsonMode, async () => {
446
454
  const store = await openStore(runEnv, { root });
447
455
  return sourceAddAltCommand.execute(runEnv, store, { path: notePath, id: cmdOpts.id });
448
456
  });
@@ -452,7 +460,7 @@ export async function run(argv, env) {
452
460
  .description('health observations that never fail the run: orphans, broken links, uningested inbox material, catalog gaps')
453
461
  .action(async (_cmdOpts, cmd) => {
454
462
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
455
- result = await runCommand('lint', runEnv, jsonMode, async () => {
463
+ state.result = await runCommand('lint', runEnv, jsonMode, async () => {
456
464
  const store = await openStore(runEnv, { root });
457
465
  return lintCommand.execute(runEnv, store);
458
466
  });
@@ -462,7 +470,7 @@ export async function run(argv, env) {
462
470
  .description('retire a note, or a folder of notes whole, to its same path beneath the archive destination via a single tracked rename, reporting every note that links to it')
463
471
  .action(async (notePath, _cmdOpts, cmd) => {
464
472
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
465
- result = await runCommand('archive', runEnv, jsonMode, async () => {
473
+ state.result = await runCommand('archive', runEnv, jsonMode, async () => {
466
474
  const store = await openStore(runEnv, { root });
467
475
  return archiveCommand.execute(runEnv, store, { path: notePath });
468
476
  });
@@ -473,7 +481,7 @@ export async function run(argv, env) {
473
481
  .description('enumerate candidate source notes (notes linking to <entity>) for a rollup')
474
482
  .action(async (entity, _cmdOpts, cmd) => {
475
483
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
476
- result = await runCommand('rollup.gather', runEnv, jsonMode, async () => {
484
+ state.result = await runCommand('rollup.gather', runEnv, jsonMode, async () => {
477
485
  const store = await openStore(runEnv, { root });
478
486
  return rollupGatherCommand.execute(runEnv, store, { entity });
479
487
  });
@@ -484,7 +492,7 @@ export async function run(argv, env) {
484
492
  .requiredOption('--content-file <path>', 'a file containing the rollup text to write')
485
493
  .action(async (entity, cmdOpts, cmd) => {
486
494
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
487
- result = await runCommand('rollup.write', runEnv, jsonMode, async () => {
495
+ state.result = await runCommand('rollup.write', runEnv, jsonMode, async () => {
488
496
  const store = await openStore(runEnv, { root });
489
497
  return rollupWriteCommand.execute(runEnv, store, { entity, contentFile: cmdOpts.contentFile });
490
498
  });
@@ -495,7 +503,7 @@ export async function run(argv, env) {
495
503
  .option('--for <entity>', 'check only this entity')
496
504
  .action(async (cmdOpts, cmd) => {
497
505
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
498
- result = await runCommand('rollup.stale', runEnv, jsonMode, async () => {
506
+ state.result = await runCommand('rollup.stale', runEnv, jsonMode, async () => {
499
507
  const store = await openStore(runEnv, { root });
500
508
  return rollupStaleCommand.execute(runEnv, store, { for: cmdOpts.for });
501
509
  });
@@ -509,7 +517,7 @@ export async function run(argv, env) {
509
517
  .option('--entity <name>', 'every note linking to this entity (same enumeration as rollup gather)')
510
518
  .action(async (cmdOpts, cmd) => {
511
519
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
512
- result = await runCommand('publish.gather', runEnv, jsonMode, async () => {
520
+ state.result = await runCommand('publish.gather', runEnv, jsonMode, async () => {
513
521
  const store = await openStore(runEnv, { root });
514
522
  return publishGatherCommand.execute(runEnv, store, {
515
523
  under: cmdOpts.under,
@@ -524,7 +532,7 @@ export async function run(argv, env) {
524
532
  .option('--disposable', 'scaffold a disposable page at disposable/<YYYY-MM-DD>-<slug>, dated today by the command (two-kinds-of-published-page)')
525
533
  .action(async (slug, cmdOpts, cmd) => {
526
534
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
527
- result = await runCommand('publish.new', runEnv, jsonMode, async () => {
535
+ state.result = await runCommand('publish.new', runEnv, jsonMode, async () => {
528
536
  const store = await openStore(runEnv, { root });
529
537
  return publishNewCommand.execute(store, { slug, disposable: cmdOpts.disposable === true });
530
538
  });
@@ -534,7 +542,7 @@ export async function run(argv, env) {
534
542
  .description("record the hash of the note a permanent page represents (its README's lead link) as a marker on that line — once; never overwrites a marker, and refuses a disposable page")
535
543
  .action(async (pagePath, _cmdOpts, cmd) => {
536
544
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
537
- result = await runCommand('publish.stamp', runEnv, jsonMode, async () => {
545
+ state.result = await runCommand('publish.stamp', runEnv, jsonMode, async () => {
538
546
  const store = await openStore(runEnv, { root });
539
547
  return publishStampCommand.execute(store, { path: pagePath });
540
548
  });
@@ -544,7 +552,7 @@ export async function run(argv, env) {
544
552
  .description("the mechanized structural checks a published page must pass (no external references, viewport meta, print rule, provenance, sibling README, script syntax; a disposable page's shape; a permanent page's represented note and its hash), and the page's address and lifespan")
545
553
  .action(async (pagePath, _cmdOpts, cmd) => {
546
554
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
547
- result = await runCommand('publish.check', runEnv, jsonMode, async () => {
555
+ state.result = await runCommand('publish.check', runEnv, jsonMode, async () => {
548
556
  const store = await openStore(runEnv, { root });
549
557
  return publishCheckCommand.execute(store, { path: pagePath });
550
558
  });
@@ -556,7 +564,7 @@ export async function run(argv, env) {
556
564
  .option('--since <ref>', 'the changes since this ref, as a pull request against it would show')
557
565
  .action(async (cmdOpts, cmd) => {
558
566
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
559
- result = await runCommand('publish.urls', runEnv, jsonMode, async () => {
567
+ state.result = await runCommand('publish.urls', runEnv, jsonMode, async () => {
560
568
  const store = await openStore(runEnv, { root });
561
569
  return publishUrlsCommand.execute(store, { staged: cmdOpts.staged === true, since: cmdOpts.since });
562
570
  });
@@ -567,7 +575,7 @@ export async function run(argv, env) {
567
575
  .description('(re)generate every configured harness-generation adapter\'s output')
568
576
  .action(async (_cmdOpts, cmd) => {
569
577
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
570
- result = await runCommand('adapters.generate', runEnv, jsonMode, async () => {
578
+ state.result = await runCommand('adapters.generate', runEnv, jsonMode, async () => {
571
579
  const store = await openStore(runEnv, { root });
572
580
  return adaptersGenerateCommand.execute(runEnv, store);
573
581
  });
@@ -579,7 +587,7 @@ export async function run(argv, env) {
579
587
  .option('--host <address>', 'address to bind — widening beyond the default exposes the server, with no requester filtering of its own, to whatever can reach that address', serveCommand.DEFAULT_HOST)
580
588
  .action(async (cmdOpts, cmd) => {
581
589
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
582
- result = await runCommand('serve', runEnv, jsonMode, async () => {
590
+ state.result = await runCommand('serve', runEnv, jsonMode, async () => {
583
591
  const store = await openStore(runEnv, { root });
584
592
  return serveCommand.execute(runEnv, store, { port: cmdOpts.port, host: cmdOpts.host });
585
593
  });
@@ -590,7 +598,7 @@ export async function run(argv, env) {
590
598
  .option('--check', 'resolve the latest published release and compare it against the installed one')
591
599
  .action(async (cmdOpts, cmd) => {
592
600
  const { runEnv, jsonMode } = deriveRunEnv(env, cmd);
593
- result = await runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv, { check: cmdOpts.check }));
601
+ state.result = await runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv, { check: cmdOpts.check }));
594
602
  });
595
603
  program
596
604
  .command('update')
@@ -598,7 +606,7 @@ export async function run(argv, env) {
598
606
  .option('--worktree', 'work in a new worktree on a branch named for this release, never in this checkout; commits nothing')
599
607
  .action(async (cmdOpts, cmd) => {
600
608
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
601
- result = await runCommand('update', runEnv, jsonMode, async () => {
609
+ state.result = await runCommand('update', runEnv, jsonMode, async () => {
602
610
  // The one command allowed past the schema gate on an older store (migrate-stores-on-update).
603
611
  const store = await openStoreMigrating(runEnv, { root });
604
612
  return cmdOpts.worktree
@@ -612,7 +620,7 @@ export async function run(argv, env) {
612
620
  .option('--portable', "verify the store's recorded commit in a disposable checkout, in a child process with no harness state reachable")
613
621
  .action(async (cmdOpts, cmd) => {
614
622
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
615
- result = await runCommand('verify', runEnv, jsonMode, async () => {
623
+ state.result = await runCommand('verify', runEnv, jsonMode, async () => {
616
624
  const store = await openStore(runEnv, { root });
617
625
  return verifyCommand.execute(runEnv, store, { portable: cmdOpts.portable });
618
626
  });
@@ -623,11 +631,25 @@ export async function run(argv, env) {
623
631
  .argument('[pr]', 'the pull request number to land', (v) => Number.parseInt(v, 10))
624
632
  .option('--pending', 'land every open session pull request whose current head carries an approval from the approval page')
625
633
  .option('--confirm', 'the caller already has an explicit go for this pull request; land it without a recorded approval')
634
+ .option('--session <session>', 'with --confirm: land every pull request of a session homed here (worktree name or branch), parts in mounted stores first, stopping at the first that does not land')
626
635
  .action(async (pr, cmdOpts, cmd) => {
627
636
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
628
- result = await runCommand('land', runEnv, jsonMode, async () => {
637
+ state.result = await runCommand('land', runEnv, jsonMode, async () => {
629
638
  const store = await openStore(runEnv, { root });
630
- return landCommand.execute(runEnv, store, { pr, pending: Boolean(cmdOpts.pending), confirm: Boolean(cmdOpts.confirm) });
639
+ return landCommand.execute(runEnv, store, { pr, pending: Boolean(cmdOpts.pending), confirm: Boolean(cmdOpts.confirm), session: cmdOpts.session });
640
+ });
641
+ });
642
+ // serve-the-session-lifecycle-to-chat-apps D7: the chat-app plugins, built from the MCP render of the owned skills.
643
+ const pluginCommand = program.command('plugin').description("build the store's Claude and ChatGPT plugins: its skills and its MCP server");
644
+ pluginCommand
645
+ .command('build')
646
+ .description('write the Claude and ChatGPT plugins, each as a directory and a zip archive, from the MCP render of the owned skills and serve.base_url')
647
+ .option('--out <dir>', 'where to write them (default: .contexture/cache/plugin/ under the store root)')
648
+ .action(async (cmdOpts, cmd) => {
649
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
650
+ state.result = await runCommand('plugin.build', runEnv, jsonMode, async () => {
651
+ const store = await openStore(runEnv, { root });
652
+ return pluginBuildCommand.execute(runEnv, store, { out: cmdOpts.out });
631
653
  });
632
654
  });
633
655
  const reviewCommand = program.command('review').description('read the decisions people made on session pull requests from the approval page');
@@ -636,21 +658,73 @@ export async function run(argv, env) {
636
658
  .description('report each open session pull request with its decision state: awaiting, approved, changes-requested, needs-reapproval or blocked')
637
659
  .action(async (_cmdOpts, cmd) => {
638
660
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
639
- result = await runCommand('review.list', runEnv, jsonMode, async () => {
661
+ state.result = await runCommand('review.list', runEnv, jsonMode, async () => {
640
662
  const store = await openStore(runEnv, { root });
641
663
  return reviewListCommand.execute(runEnv, store);
642
664
  });
643
665
  });
666
+ // run-the-second-opinion-from-the-cli D1: the one command group that invokes a model CLI. Its options are
667
+ // contexture's own; the model CLIs' flags stay inside src/core/second-opinion/. It opens no store.
668
+ const secondOpinionGroup = program
669
+ .command('second-opinion')
670
+ .description('a cross-model second opinion: the same plan or question sent to three model families\' command-line tools in parallel');
671
+ const commonSecondOpinionOptions = (sub) => sub
672
+ .option('--tier <tier>', 'strong (each family\'s frontier model, the default) or fast (each family\'s workhorse)')
673
+ .option('--only <clis>', 'comma-separated model CLIs to use (claude, codex, agy); a critique or poll needs at least two')
674
+ .option('--timeout <seconds>', 'per-CLI time limit in seconds (default 600)');
675
+ commonSecondOpinionOptions(secondOpinionGroup.command('preflight').description('check each model CLI answers, at the tier the run will use, and still accepts the flags this command passes')).action(async (cmdOpts, cmd) => {
676
+ const { runEnv, jsonMode } = deriveRunEnv(env, cmd);
677
+ state.result = await runCommand('second-opinion.preflight', runEnv, jsonMode, () => secondOpinionCommand.executePreflight(runEnv, cmdOpts));
678
+ });
679
+ commonSecondOpinionOptions(secondOpinionGroup.command('critique').description('send a written plan to three critic roles, each on a different model family, and write anonymised letters and a manifest'))
680
+ .option('--plan-file <path>', 'the plan to critique (default: read from stdin)')
681
+ .option('--out <dir>', 'where to write the critiques and the manifest (default: a new temporary directory)')
682
+ .option('--seed <n>', 'seed the letter assignment, for a reproducible mapping')
683
+ .action(async (cmdOpts, cmd) => {
684
+ const { runEnv, jsonMode } = deriveRunEnv(env, cmd);
685
+ state.result = await runCommand('second-opinion.critique', runEnv, jsonMode, () => secondOpinionCommand.executeCritique(runEnv, cmdOpts));
686
+ });
687
+ commonSecondOpinionOptions(secondOpinionGroup.command('poll').description('send one question to the same model families, optionally answered through two or three taste lenses'))
688
+ .option('--prompt-file <path>', 'the question and its options (default: read from stdin)')
689
+ .option('--out <dir>', 'where to write the answers and the manifest (default: a new temporary directory)')
690
+ .option('--lens <lenses>', 'two or three comma-separated taste lenses: built-in names or Name:description')
691
+ .option('--no-wrap', 'send the question as written, without the answer scaffold')
692
+ .action(async (cmdOpts, cmd) => {
693
+ const { runEnv, jsonMode } = deriveRunEnv(env, cmd);
694
+ state.result = await runCommand('second-opinion.poll', runEnv, jsonMode, () => secondOpinionCommand.executePoll(runEnv, cmdOpts));
695
+ });
696
+ const sharedStoresCommand = program.command('shared-stores').description('the stores this store mounts under shared/');
697
+ sharedStoresCommand
698
+ .command('sync')
699
+ .description('clone each declared mount that is missing and fast-forward the others, leaving any with local work alone')
700
+ .action(async (_cmdOpts, cmd) => {
701
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
702
+ state.result = await runCommand('shared-stores.sync', runEnv, jsonMode, async () => {
703
+ const store = await openStore(runEnv, { root });
704
+ return sharedStoresSyncCommand.execute(runEnv, store);
705
+ });
706
+ });
707
+ sharedStoresCommand
708
+ .command('status')
709
+ .description('report each declared mount: present, a store, branch, commit, uncommitted changes — no writes, no network')
710
+ .action(async (_cmdOpts, cmd) => {
711
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
712
+ state.result = await runCommand('shared-stores.status', runEnv, jsonMode, async () => {
713
+ const store = await openStore(runEnv, { root });
714
+ return sharedStoresStatusCommand.execute(runEnv, store);
715
+ });
716
+ });
644
717
  const sessionCommand = program.command('session').description('manage session worktrees');
645
718
  sessionCommand
646
719
  .command('start')
647
720
  .description('create a new session worktree off a freshly fetched default branch')
648
721
  .argument('[label]', 'a short name for what the session is for — becomes part of the branch and worktree name')
649
- .action(async (label, _cmdOpts, cmd) => {
722
+ .option('--joins <session>', 'run inside a mounted store: start a session that belongs to this live session of the store that mounts it (worktree name or branch)')
723
+ .action(async (label, cmdOpts, cmd) => {
650
724
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
651
- result = await runCommand('session.start', runEnv, jsonMode, async () => {
725
+ state.result = await runCommand('session.start', runEnv, jsonMode, async () => {
652
726
  const store = await openStore(runEnv, { root });
653
- return sessionStartCommand.execute(runEnv, store, { label });
727
+ return sessionStartCommand.execute(runEnv, store, { label, ...(cmdOpts.joins === undefined ? {} : { joins: cmdOpts.joins }) });
654
728
  });
655
729
  });
656
730
  sessionCommand
@@ -659,21 +733,86 @@ export async function run(argv, env) {
659
733
  .requiredOption('--proposal <path>', 'a YAML file of approved note items')
660
734
  .action(async (cmdOpts, cmd) => {
661
735
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
662
- result = await runCommand('session.capture', runEnv, jsonMode, async () => {
736
+ state.result = await runCommand('session.capture', runEnv, jsonMode, async () => {
663
737
  const store = await openStore(runEnv, { root });
664
738
  return sessionCaptureCommand.execute(store, cmdOpts);
665
739
  });
666
740
  });
667
741
  sessionCommand
668
742
  .command('list')
669
- .description('list active session worktrees')
670
- .action(async (_cmdOpts, cmd) => {
743
+ .description("list active session worktrees, each with its uncommitted state and commits ahead, read locally")
744
+ .option('--review', "also read each session's open pull request and, when the store declares change_approval, its decision state from the forge")
745
+ .action(async (cmdOpts, cmd) => {
746
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
747
+ state.result = await runCommand('session.list', runEnv, jsonMode, async () => {
748
+ const store = await openStore(runEnv, { root });
749
+ return sessionListCommand.execute(runEnv, store, { review: Boolean(cmdOpts.review) });
750
+ });
751
+ });
752
+ // bring-the-session-lifecycle-into-the-cli D3: the lifecycle's mechanical steps, shared with the MCP surface.
753
+ sessionCommand
754
+ .command('status')
755
+ .description('re-scan a session: its uncommitted changes, the diff stat of committed and uncommitted work, and its commits ahead of the default branch')
756
+ .argument('[session]', 'the session worktree\'s directory name, as `session list` prints it (default: the session containing the working directory)')
757
+ .option('--diff', 'also print the unified diff of uncommitted work')
758
+ .action(async (session, cmdOpts, cmd) => {
759
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
760
+ state.result = await runCommand('session.status', runEnv, jsonMode, async () => {
761
+ const store = await openStore(runEnv, { root });
762
+ return sessionStatusCommand.execute(runEnv, store, { session, diff: Boolean(cmdOpts.diff) });
763
+ });
764
+ });
765
+ sessionCommand
766
+ .command('submit')
767
+ .description('stage a session\'s changes outside derived paths, gate on doctor, commit, name the branch, push, and open or update its pull request with the Pages and Knowledge changes sections appended')
768
+ .argument('<session>', 'the session worktree\'s directory name, as `session list` prints it')
769
+ .requiredOption('--branch <name>', 'the branch name the pull request carries; the session\'s branch is renamed to it')
770
+ .requiredOption('--message <msg>', 'the commit message')
771
+ .requiredOption('--title <title>', 'the pull request title')
772
+ .option('--body <body>', 'the pull request body: why, what changed, route, verification and follow-ups')
773
+ .option('--body-file <path>', 'read the pull request body from a file instead')
774
+ .action(async (session, cmdOpts, cmd) => {
775
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
776
+ state.result = await runCommand('session.submit', runEnv, jsonMode, async () => {
777
+ const store = await openStore(runEnv, { root });
778
+ return sessionSubmitCommand.execute(runEnv, store, { session, ...cmdOpts });
779
+ });
780
+ });
781
+ sessionCommand
782
+ .command('rebase')
783
+ .description('fetch the default branch and rebase a session onto it, reporting each conflicting path with both sides')
784
+ .argument('<session>', 'the session worktree\'s directory name, as `session list` prints it')
785
+ .option('--continue', 'stage the resolved paths and continue the rebase')
786
+ .option('--abort', 'abort the rebase and restore the session as it was')
787
+ .action(async (session, cmdOpts, cmd) => {
788
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
789
+ state.result = await runCommand('session.rebase', runEnv, jsonMode, async () => {
790
+ const store = await openStore(runEnv, { root });
791
+ return sessionRebaseCommand.execute(runEnv, store, { session, continue: cmdOpts.continue, abort: cmdOpts.abort });
792
+ });
793
+ });
794
+ sessionCommand
795
+ .command('discard')
796
+ .description('remove a session worktree and its local branch, refusing uncommitted or unpushed work unless forced')
797
+ .argument('<session>', 'the session worktree\'s directory name, as `session list` prints it')
798
+ .option('--force', 'discard uncommitted changes and commits the remote branch lacks')
799
+ .option('--close-pull-request', 'also close the session\'s open pull request')
800
+ .action(async (session, cmdOpts, cmd) => {
671
801
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
672
- result = await runCommand('session.list', runEnv, jsonMode, async () => {
802
+ state.result = await runCommand('session.discard', runEnv, jsonMode, async () => {
673
803
  const store = await openStore(runEnv, { root });
674
- return sessionListCommand.execute(runEnv, store);
804
+ return sessionDiscardCommand.execute(runEnv, store, { session, force: cmdOpts.force, closePullRequest: cmdOpts.closePullRequest });
675
805
  });
676
806
  });
807
+ return { program, state };
808
+ }
809
+ export async function run(argv, env) {
810
+ if (isGlobalVersionRequest(argv)) {
811
+ const jsonMode = argv.includes('--json');
812
+ const runEnv = { ...env, noInput: env.noInput || argv.includes('--no-input') || jsonMode };
813
+ return runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv));
814
+ }
815
+ const { program, state } = buildProgram(env);
677
816
  try {
678
817
  await program.parseAsync(argv, { from: 'user' });
679
818
  }
@@ -711,6 +850,6 @@ export async function run(argv, env) {
711
850
  }
712
851
  throw err;
713
852
  }
714
- return result;
853
+ return state.result;
715
854
  }
716
855
  //# sourceMappingURL=run.js.map