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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/core/session/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { ForgeCredentials } from '../forge/credentials.js';
2
+ import { type SessionRef } from './resolve.js';
3
+ import { type StatusDeps } from './status.js';
4
+ /**
5
+ * write-lifecycle spec (*`ctxr session rebase` brings a session onto the
6
+ * default branch*): the conflict playbook's mechanics. The judgment — reading
7
+ * both sides and writing a version that keeps both meanings — stays the
8
+ * agent's; this fetches, rebases, reports each conflict with both sides, and
9
+ * stages and continues once the agent has resolved them
10
+ * (bring-the-session-lifecycle-into-the-cli D3).
11
+ */
12
+ export interface Conflict {
13
+ /** Relative to the worktree's top level. */
14
+ path: string;
15
+ /** The default branch's version, with the session's commits applied so far; null when that side deleted the file. */
16
+ default_branch: string | null;
17
+ /** The version in the session commit being replayed; null when it deleted the file. */
18
+ session: string | null;
19
+ }
20
+ export type RebaseOutcome = 'rebased' | 'up-to-date' | 'conflict' | 'aborted';
21
+ export interface RebaseResult {
22
+ session: string;
23
+ branch: string;
24
+ onto: string;
25
+ fetched: boolean;
26
+ outcome: RebaseOutcome;
27
+ head: string;
28
+ conflicts: Conflict[];
29
+ }
30
+ export type RebaseMode = 'start' | 'continue' | 'abort';
31
+ export declare function rebaseSession(deps: StatusDeps & {
32
+ credentials: ForgeCredentials;
33
+ }, session: SessionRef, mode: RebaseMode): Promise<RebaseResult>;
34
+ //# sourceMappingURL=rebase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebase.d.ts","sourceRoot":"","sources":["../../../src/core/session/rebase.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAElE;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,qHAAqH;IACrH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,uFAAuF;IACvF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;AAE9E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AA0BxD,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG;IAAE,WAAW,EAAE,gBAAgB,CAAA;CAAE,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAsDtJ"}
@@ -0,0 +1,87 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { baseRef } from '../approval/sessions.js';
4
+ import { SessionRefusedError } from '../errors.js';
5
+ import { ExitCode } from '../exit-codes.js';
6
+ import { rebaseInProgress, workingChanges } from './resolve.js';
7
+ import { fetchDefaultBranch } from './status.js';
8
+ const MARKER = /^(<{7}|>{7})( |$)/m;
9
+ async function stageContent(git, cwd, stage, file) {
10
+ const shown = await git.run(['show', `:${stage}:${file}`], { cwd, allowFailure: true });
11
+ return shown.exitCode === 0 ? shown.stdout : null;
12
+ }
13
+ async function conflictedPaths(git, cwd) {
14
+ const { stdout } = await git.run(['diff', '--name-only', '--diff-filter=U', '-z'], { cwd, allowFailure: true });
15
+ return stdout.split('\0').filter((p) => p !== '');
16
+ }
17
+ async function conflicts(git, cwd) {
18
+ const found = [];
19
+ for (const file of await conflictedPaths(git, cwd)) {
20
+ found.push({ path: file, default_branch: await stageContent(git, cwd, 2, file), session: await stageContent(git, cwd, 3, file) });
21
+ }
22
+ return found;
23
+ }
24
+ async function head(git, cwd) {
25
+ return (await git.run(['rev-parse', 'HEAD'], { cwd })).stdout.trim();
26
+ }
27
+ export async function rebaseSession(deps, session, mode) {
28
+ const { git } = deps;
29
+ const cwd = session.path;
30
+ const inProgress = await rebaseInProgress(git, cwd);
31
+ const result = async (outcome, onto, fetched) => ({
32
+ session: session.name,
33
+ branch: session.branch,
34
+ onto,
35
+ fetched,
36
+ outcome,
37
+ head: await head(git, cwd),
38
+ conflicts: outcome === 'conflict' ? await conflicts(git, cwd) : [],
39
+ });
40
+ const onto = await baseRef(git, cwd, deps.config.git.default_branch);
41
+ // A rebase replays commits, so its editor must never wait on a person.
42
+ const rebase = (args) => git.run(['-c', 'core.editor=true', 'rebase', ...args], { cwd, allowFailure: true, env: { ...deps.env, GIT_EDITOR: 'true' } });
43
+ if (mode === 'abort') {
44
+ if (!inProgress)
45
+ throw new SessionRefusedError(ExitCode.Usage, 'no_rebase', `No rebase is in progress in "${session.name}", so there is nothing to abort.`, { session: session.name });
46
+ await rebase(['--abort']);
47
+ return result('aborted', onto, false);
48
+ }
49
+ if (mode === 'continue') {
50
+ if (!inProgress)
51
+ throw new SessionRefusedError(ExitCode.Usage, 'no_rebase', `No rebase is in progress in "${session.name}", so there is nothing to continue.`, { session: session.name });
52
+ const unresolved = [];
53
+ for (const file of await conflictedPaths(git, cwd)) {
54
+ const working = await readFile(path.join(cwd, file), 'utf8').catch(() => null);
55
+ if (working !== null && MARKER.test(working))
56
+ unresolved.push(file);
57
+ }
58
+ if (unresolved.length > 0) {
59
+ throw new SessionRefusedError(ExitCode.CheckFailed, 'conflict_unresolved', `Conflict markers remain in ${unresolved.map((f) => `"${f}"`).join(', ')}; resolve them before continuing.`, { session: session.name, paths: unresolved });
60
+ }
61
+ for (const file of await conflictedPaths(git, cwd))
62
+ await git.run(['add', '-A', '--', file], { cwd, allowFailure: true });
63
+ const continued = await rebase(['--continue']);
64
+ if (continued.exitCode === 0)
65
+ return result('rebased', onto, false);
66
+ if (await rebaseInProgress(git, cwd))
67
+ return result('conflict', onto, false);
68
+ throw new SessionRefusedError(ExitCode.CheckFailed, 'rebase_failed', `The rebase could not continue: ${continued.stderr.trim() || continued.stdout.trim()}`, { session: session.name });
69
+ }
70
+ if (inProgress) {
71
+ throw new SessionRefusedError(ExitCode.Usage, 'rebase_in_progress', `A rebase is already in progress in "${session.name}"; finish it with \`ctxr session rebase ${session.name} --continue\` or undo it with \`--abort\`.`, { session: session.name });
72
+ }
73
+ const dirty = await workingChanges(git, cwd);
74
+ if (dirty.length > 0) {
75
+ throw new SessionRefusedError(ExitCode.CheckFailed, 'uncommitted_changes', `"${session.name}" has uncommitted changes (${dirty.map((c) => c.path).join(', ')}); submit or set them aside before rebasing.`, { session: session.name, paths: dirty.map((c) => c.path) });
76
+ }
77
+ const fetched = await fetchDefaultBranch(deps, cwd);
78
+ const base = await baseRef(git, cwd, deps.config.git.default_branch);
79
+ const before = await head(git, cwd);
80
+ const rebased = await rebase(['--quiet', base]);
81
+ if (rebased.exitCode === 0)
82
+ return result((await head(git, cwd)) === before ? 'up-to-date' : 'rebased', base, fetched);
83
+ if (await rebaseInProgress(git, cwd))
84
+ return result('conflict', base, fetched);
85
+ throw new SessionRefusedError(ExitCode.CheckFailed, 'rebase_failed', `The rebase could not start: ${rebased.stderr.trim() || rebased.stdout.trim()}`, { session: session.name });
86
+ }
87
+ //# sourceMappingURL=rebase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebase.js","sourceRoot":"","sources":["../../../src/core/session/rebase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import type { StoreConfig } from '../../config/schema.js';
2
+ import { type ForgeCredentials } from '../forge/credentials.js';
3
+ import type { ForgeClient, PullRequest } from '../forge/github.js';
4
+ import type { GitRunner } from '../git/exec.js';
5
+ /**
6
+ * bring-the-session-lifecycle-into-the-cli (design.md Migration Plan, step 2):
7
+ * the session's remote side — push, publish (push plus the pull request, found
8
+ * by head before one is opened) and remove — moved here from the MCP surface's
9
+ * `sessions.ts`, so `ctxr session submit`, `discard` and the MCP tools run one
10
+ * implementation. Failures are thrown as `SessionRemoteError`, naming the step,
11
+ * and each caller words them for its own surface.
12
+ */
13
+ export interface RemoteDeps {
14
+ git: GitRunner;
15
+ config: StoreConfig;
16
+ credentials: ForgeCredentials;
17
+ forge: ForgeClient;
18
+ env: Readonly<Record<string, string | undefined>>;
19
+ }
20
+ /** The worktree and branch a remote step acts on. */
21
+ export interface SessionTarget {
22
+ path: string;
23
+ branch: string;
24
+ }
25
+ export type PullState = {
26
+ kind: 'open';
27
+ pull: PullRequest;
28
+ } | {
29
+ kind: 'merged';
30
+ } | {
31
+ kind: 'closed-unmerged';
32
+ } | {
33
+ kind: 'none';
34
+ };
35
+ export type RemoteStep = 'push' | 'pull_request';
36
+ /** A push or forge call that did not succeed; everything before it stays in place, so the same call can be retried. */
37
+ export declare class SessionRemoteError extends Error {
38
+ readonly step: RemoteStep;
39
+ readonly detail: string;
40
+ constructor(step: RemoteStep, detail: string);
41
+ }
42
+ export declare function firstLines(text: string, count?: number): string;
43
+ /** What the forge says about the pull requests for `branch`: the open one, else merged, else closed, else none. */
44
+ export declare function pullStateFor(forge: ForgeClient, branch: string): Promise<PullState>;
45
+ /** The remote branch's tip, or null when the remote has no such branch. Throws when the remote cannot be read at all. */
46
+ export declare function remoteTip(deps: RemoteDeps, cwd: string, branch: string): Promise<string | null>;
47
+ export type PushOutcome = 'up-to-date' | 'pushed' | 'pushed-with-lease';
48
+ /**
49
+ * Pushes the session's HEAD to its branch when the remote lacks it. Read
50
+ * first, so a retry after a push whose response was lost pushes nothing. A
51
+ * fast-forward is a plain push. A rewritten history (after `ctxr session
52
+ * rebase`) is pushed with a lease on the remote-tracking ref this clone last
53
+ * saw — never on the tip just read, which would overwrite a push made by
54
+ * someone else since (bring-the-session-lifecycle-into-the-cli D3).
55
+ */
56
+ export declare function pushSession(deps: RemoteDeps, session: SessionTarget): Promise<PushOutcome>;
57
+ export interface PublishResult {
58
+ pull: PullRequest;
59
+ push: PushOutcome;
60
+ /** `created` when this call opened it, `updated` when it rewrote an open one's title or body, else `found`. */
61
+ pullRequest: 'created' | 'updated' | 'found';
62
+ }
63
+ /**
64
+ * Publishes whatever the session holds that the forge does not: its branch,
65
+ * pushed when the remote lacks the local tip, and a pull request, found by
66
+ * head before one is opened. Idempotent, so a retry after any partial failure
67
+ * converges on exactly one pull request (serve-the-store-over-mcp D9, D13).
68
+ * With `update`, an open pull request whose title or body differs is rewritten
69
+ * to the given ones — how a resubmitted session answers requested changes on
70
+ * the same pull request (bring-the-session-lifecycle-into-the-cli D3).
71
+ */
72
+ export declare function publishSession(deps: RemoteDeps, session: SessionTarget, pull: {
73
+ title: string;
74
+ body: string;
75
+ }, opts?: {
76
+ update?: boolean;
77
+ }): Promise<PublishResult>;
78
+ /** Removes a session: its worktree and its local branch. The remote branch and any pull request are left as they are. */
79
+ export declare function removeSession(git: GitRunner, canonicalRoot: string, session: SessionTarget): Promise<void>;
80
+ //# sourceMappingURL=remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../../src/core/session/remote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD;;;;;;;GAOG;AAEH,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,KAAK,EAAE,WAAW,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;CACnD;AAED,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAElI,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,cAAc,CAAC;AAEjD,uHAAuH;AACvH,qBAAa,kBAAmB,SAAQ,KAAK;IAEzC,QAAQ,CAAC,IAAI,EAAE,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM;IAFzB,YACW,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EAIxB;CACF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,CAE1D;AAED,mHAAmH;AACnH,wBAAsB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAOzF;AAED,yHAAyH;AACzH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKrG;AAED,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,QAAQ,GAAG,mBAAmB,CAAC;AAMxE;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAqBhG;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;IAClB,+GAA+G;IAC/G,WAAW,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAc7K;AAED,yHAAyH;AACzH,wBAAsB,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhH"}
@@ -0,0 +1,102 @@
1
+ import { runRemoteGit } from '../forge/credentials.js';
2
+ import { removeWorktree } from '../git/worktree.js';
3
+ /** A push or forge call that did not succeed; everything before it stays in place, so the same call can be retried. */
4
+ export class SessionRemoteError extends Error {
5
+ step;
6
+ detail;
7
+ constructor(step, detail) {
8
+ super(`${step === 'push' ? 'push' : 'pull request'} failed: ${detail}`);
9
+ this.step = step;
10
+ this.detail = detail;
11
+ this.name = 'SessionRemoteError';
12
+ }
13
+ }
14
+ export function firstLines(text, count = 6) {
15
+ return text.trim().split('\n').slice(0, count).join('\n');
16
+ }
17
+ /** What the forge says about the pull requests for `branch`: the open one, else merged, else closed, else none. */
18
+ export async function pullStateFor(forge, branch) {
19
+ const pulls = await forge.pullsForHead(branch);
20
+ const open = pulls.find((p) => p.state === 'open');
21
+ if (open !== undefined)
22
+ return { kind: 'open', pull: open };
23
+ if (pulls.some((p) => p.merged))
24
+ return { kind: 'merged' };
25
+ if (pulls.length > 0)
26
+ return { kind: 'closed-unmerged' };
27
+ return { kind: 'none' };
28
+ }
29
+ /** The remote branch's tip, or null when the remote has no such branch. Throws when the remote cannot be read at all. */
30
+ export async function remoteTip(deps, cwd, branch) {
31
+ const listed = await runRemoteGit(deps.git, deps.credentials, deps.env, ['ls-remote', 'origin', `refs/heads/${branch}`], { cwd, allowFailure: true });
32
+ if (listed.exitCode !== 0)
33
+ throw new SessionRemoteError('push', firstLines(listed.stderr, 2));
34
+ const sha = listed.stdout.split(/\s/)[0] ?? '';
35
+ return sha === '' ? null : sha;
36
+ }
37
+ async function isAncestor(git, cwd, ancestor, descendant) {
38
+ return (await git.run(['merge-base', '--is-ancestor', ancestor, descendant], { cwd, allowFailure: true })).exitCode === 0;
39
+ }
40
+ /**
41
+ * Pushes the session's HEAD to its branch when the remote lacks it. Read
42
+ * first, so a retry after a push whose response was lost pushes nothing. A
43
+ * fast-forward is a plain push. A rewritten history (after `ctxr session
44
+ * rebase`) is pushed with a lease on the remote-tracking ref this clone last
45
+ * saw — never on the tip just read, which would overwrite a push made by
46
+ * someone else since (bring-the-session-lifecycle-into-the-cli D3).
47
+ */
48
+ export async function pushSession(deps, session) {
49
+ const tip = (await deps.git.run(['rev-parse', 'HEAD'], { cwd: session.path })).stdout.trim();
50
+ const remote = await remoteTip(deps, session.path, session.branch);
51
+ if (remote === tip)
52
+ return 'up-to-date';
53
+ const args = ['push', '--quiet', 'origin', `HEAD:refs/heads/${session.branch}`];
54
+ let outcome = 'pushed';
55
+ if (remote !== null && !(await isAncestor(deps.git, session.path, remote, tip))) {
56
+ const seen = await deps.git.run(['rev-parse', '--verify', '--quiet', `refs/remotes/origin/${session.branch}`], { cwd: session.path, allowFailure: true });
57
+ const expected = seen.exitCode === 0 ? seen.stdout.trim() : '';
58
+ if (expected !== remote) {
59
+ throw new SessionRemoteError('push', `the remote branch "${session.branch}" is at ${remote.slice(0, 7)}, which this session has not seen; fetch it and rebase before pushing`);
60
+ }
61
+ args.splice(2, 0, `--force-with-lease=refs/heads/${session.branch}:${expected}`);
62
+ outcome = 'pushed-with-lease';
63
+ }
64
+ const pushed = await runRemoteGit(deps.git, deps.credentials, deps.env, args, { cwd: session.path, allowFailure: true });
65
+ if (pushed.exitCode !== 0)
66
+ throw new SessionRemoteError('push', firstLines(pushed.stderr, 2));
67
+ // Recorded as seen, so a later leased push leases on what this clone itself pushed.
68
+ await deps.git.run(['update-ref', `refs/remotes/origin/${session.branch}`, tip], { cwd: session.path, allowFailure: true });
69
+ return outcome;
70
+ }
71
+ /**
72
+ * Publishes whatever the session holds that the forge does not: its branch,
73
+ * pushed when the remote lacks the local tip, and a pull request, found by
74
+ * head before one is opened. Idempotent, so a retry after any partial failure
75
+ * converges on exactly one pull request (serve-the-store-over-mcp D9, D13).
76
+ * With `update`, an open pull request whose title or body differs is rewritten
77
+ * to the given ones — how a resubmitted session answers requested changes on
78
+ * the same pull request (bring-the-session-lifecycle-into-the-cli D3).
79
+ */
80
+ export async function publishSession(deps, session, pull, opts = {}) {
81
+ const push = await pushSession(deps, session);
82
+ let state;
83
+ try {
84
+ state = await pullStateFor(deps.forge, session.branch);
85
+ if (state.kind === 'open') {
86
+ const open = state.pull;
87
+ if (opts.update !== true || (open.title === pull.title && open.body === pull.body))
88
+ return { pull: open, push, pullRequest: 'found' };
89
+ return { pull: await deps.forge.updatePull(open.number, { title: pull.title, body: pull.body }), push, pullRequest: 'updated' };
90
+ }
91
+ return { pull: await deps.forge.createPull({ head: session.branch, base: deps.config.git.default_branch, title: pull.title, body: pull.body }), push, pullRequest: 'created' };
92
+ }
93
+ catch (err) {
94
+ throw new SessionRemoteError('pull_request', err instanceof Error ? firstLines(err.message, 2) : String(err));
95
+ }
96
+ }
97
+ /** Removes a session: its worktree and its local branch. The remote branch and any pull request are left as they are. */
98
+ export async function removeSession(git, canonicalRoot, session) {
99
+ await removeWorktree(git, canonicalRoot, session.path);
100
+ await git.run(['branch', '-D', session.branch], { cwd: canonicalRoot, allowFailure: true });
101
+ }
102
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../../src/core/session/remote.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { StoreConfig } from '../../config/schema.js';
2
+ import type { GitRunner } from '../git/exec.js';
3
+ /**
4
+ * bring-the-session-lifecycle-into-the-cli D3: a session argument is the
5
+ * worktree's directory name, as `ctxr session list` prints it. The session
6
+ * commands act only on a linked worktree directly under the canonical clone's
7
+ * configured worktrees path, checked out on a branch — the guard #31 found
8
+ * missing from `abandon` (D1, point 4), applied to every session command.
9
+ */
10
+ export interface SessionRef {
11
+ /** The worktree's directory name. */
12
+ name: string;
13
+ /** The worktree's top level. */
14
+ path: string;
15
+ branch: string;
16
+ /** The store root inside the worktree: `path` plus the store's prefix in its repository. */
17
+ storeRoot: string;
18
+ /** The canonical clone's top level — the repository's main worktree. */
19
+ canonical: string;
20
+ }
21
+ /**
22
+ * Resolves `arg` — a directory name, or a path when it carries a separator — to
23
+ * a session, or with no `arg` the session containing `cwd`. Refused with the
24
+ * usage code for anything that is not a session: the canonical clone, a
25
+ * worktree outside the worktrees path, a detached checkout, a name no worktree
26
+ * carries.
27
+ */
28
+ export declare function resolveSession(git: GitRunner, storeRoot: string, config: StoreConfig, arg: string | undefined, cwd: string): Promise<SessionRef>;
29
+ /** Whether `cwd`'s checkout is partway through a rebase. */
30
+ export declare function rebaseInProgress(git: GitRunner, cwd: string): Promise<boolean>;
31
+ export interface WorkingChange {
32
+ /** Relative to the worktree's top level. */
33
+ path: string;
34
+ /** git's two-letter short status (`M `, ` M`, `??`, `UU`, …). */
35
+ status: string;
36
+ }
37
+ /** The worktree's uncommitted changes, untracked files included, as `git status --short` lists them. */
38
+ export declare function workingChanges(git: GitRunner, cwd: string): Promise<WorkingChange[]>;
39
+ /** The number of commits HEAD carries that `base` lacks. */
40
+ export declare function commitsAhead(git: GitRunner, cwd: string, base: string): Promise<number>;
41
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/core/session/resolve.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIhD;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA2CtJ;AAYD,4DAA4D;AAC5D,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMpF;AAED,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wGAAwG;AACxG,wBAAsB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAa1F;AAED,4DAA4D;AAC5D,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7F"}
@@ -0,0 +1,109 @@
1
+ import { readFile, realpath, stat } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { SessionRefusedError } from '../errors.js';
4
+ import { ExitCode } from '../exit-codes.js';
5
+ import { listWorktrees } from '../git/worktree.js';
6
+ import { storePrefix } from '../graph/tree.js';
7
+ async function real(p) {
8
+ try {
9
+ return await realpath(p);
10
+ }
11
+ catch {
12
+ return path.resolve(p);
13
+ }
14
+ }
15
+ /**
16
+ * Resolves `arg` — a directory name, or a path when it carries a separator — to
17
+ * a session, or with no `arg` the session containing `cwd`. Refused with the
18
+ * usage code for anything that is not a session: the canonical clone, a
19
+ * worktree outside the worktrees path, a detached checkout, a name no worktree
20
+ * carries.
21
+ */
22
+ export async function resolveSession(git, storeRoot, config, arg, cwd) {
23
+ const worktrees = await listWorktrees(git, storeRoot);
24
+ const canonical = worktrees[0]?.path ?? storeRoot;
25
+ const prefix = await storePrefix(git, storeRoot);
26
+ const worktreesDir = await real(path.join(canonical, prefix, config.session.worktrees_path));
27
+ let target;
28
+ if (arg === undefined) {
29
+ const top = await git.run(['rev-parse', '--show-toplevel'], { cwd, allowFailure: true });
30
+ target = top.stdout.trim();
31
+ if (top.exitCode !== 0 || target === '' || (await real(target)) === (await real(canonical))) {
32
+ throw new SessionRefusedError(ExitCode.Usage, 'not_in_session', `"${cwd}" is not inside a session worktree; name the session, as \`ctxr session list\` prints it.`, { cwd });
33
+ }
34
+ }
35
+ else if (arg.includes('/') || arg.includes(path.sep) || arg === '.' || arg === '..') {
36
+ target = path.resolve(cwd, arg);
37
+ }
38
+ else {
39
+ const named = worktrees.find((w) => path.basename(w.path) === arg);
40
+ if (named === undefined) {
41
+ throw new SessionRefusedError(ExitCode.Usage, 'not_found', `No session worktree is named "${arg}"; \`ctxr session list\` names them.`, { session: arg }, arg);
42
+ }
43
+ target = named.path;
44
+ }
45
+ const realTarget = await real(target);
46
+ const worktree = await (async () => {
47
+ for (const w of worktrees)
48
+ if ((await real(w.path)) === realTarget)
49
+ return w;
50
+ return undefined;
51
+ })();
52
+ const shown = arg ?? target;
53
+ if (worktree === undefined || (await stat(realTarget).catch(() => null)) === null) {
54
+ throw new SessionRefusedError(ExitCode.Usage, 'not_a_session', `"${shown}" is not a worktree of this store's repository.`, { session: shown }, shown);
55
+ }
56
+ if (worktree === worktrees[0]) {
57
+ throw new SessionRefusedError(ExitCode.Usage, 'not_a_session', `"${shown}" is the canonical clone, not a session.`, { session: shown, worktree: worktree.path }, shown);
58
+ }
59
+ if (path.dirname(realTarget) !== worktreesDir) {
60
+ throw new SessionRefusedError(ExitCode.Usage, 'not_a_session', `"${shown}" is not under the configured worktrees path (${config.session.worktrees_path}), so it is not a session.`, { session: shown, worktree: worktree.path }, shown);
61
+ }
62
+ const branch = worktree.branch ?? (await rebasingBranch(git, worktree.path));
63
+ if (branch === null) {
64
+ throw new SessionRefusedError(ExitCode.Usage, 'not_a_session', `"${shown}" is not checked out on a branch, so it is not a session.`, { session: shown, worktree: worktree.path }, shown);
65
+ }
66
+ return { name: path.basename(worktree.path), path: worktree.path, branch, storeRoot: path.join(worktree.path, prefix), canonical };
67
+ }
68
+ /** The branch a rebase in progress will move, which git lists as a detached checkout until the rebase ends; null when none is. */
69
+ async function rebasingBranch(git, cwd) {
70
+ for (const name of ['rebase-merge', 'rebase-apply']) {
71
+ const gitPath = (await git.run(['rev-parse', '--git-path', `${name}/head-name`], { cwd, allowFailure: true })).stdout.trim();
72
+ const headName = await readFile(path.resolve(cwd, gitPath), 'utf8').catch(() => null);
73
+ if (headName !== null && headName.startsWith('refs/heads/'))
74
+ return headName.trim().slice('refs/heads/'.length);
75
+ }
76
+ return null;
77
+ }
78
+ /** Whether `cwd`'s checkout is partway through a rebase. */
79
+ export async function rebaseInProgress(git, cwd) {
80
+ for (const name of ['rebase-merge', 'rebase-apply']) {
81
+ const gitPath = (await git.run(['rev-parse', '--git-path', name], { cwd })).stdout.trim();
82
+ if ((await stat(path.resolve(cwd, gitPath)).catch(() => null)) !== null)
83
+ return true;
84
+ }
85
+ return false;
86
+ }
87
+ /** The worktree's uncommitted changes, untracked files included, as `git status --short` lists them. */
88
+ export async function workingChanges(git, cwd) {
89
+ const { stdout } = await git.run(['status', '--porcelain=v1', '-z', '--untracked-files=all'], { cwd });
90
+ const fields = stdout.split('\0');
91
+ const changes = [];
92
+ for (let i = 0; i < fields.length; i++) {
93
+ const field = fields[i];
94
+ if (field.length < 4)
95
+ continue;
96
+ const status = field.slice(0, 2);
97
+ changes.push({ path: field.slice(3), status });
98
+ // A rename or copy is followed by its source path, which is not a change of its own.
99
+ if (status.startsWith('R') || status.startsWith('C'))
100
+ i += 1;
101
+ }
102
+ return changes;
103
+ }
104
+ /** The number of commits HEAD carries that `base` lacks. */
105
+ export async function commitsAhead(git, cwd, base) {
106
+ const counted = await git.run(['rev-list', '--count', `${base}..HEAD`], { cwd, allowFailure: true });
107
+ return counted.exitCode === 0 ? Number.parseInt(counted.stdout.trim(), 10) || 0 : 0;
108
+ }
109
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/core/session/resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { StoreConfig } from '../../config/schema.js';
2
+ import type { GitRunner } from '../git/exec.js';
3
+ /**
4
+ * write-lifecycle spec (*session start*): a new session worktree off a freshly
5
+ * fetched default branch, shared by `ctxr session start` and the MCP surface's
6
+ * `session_start` and `capture` (serve-the-session-lifecycle-to-chat-apps D3),
7
+ * so the two surfaces name, place and refuse a session identically. Each
8
+ * surface brings its own fetch: the CLI's plain `git fetch`, the server's
9
+ * through its forge credential.
10
+ */
11
+ export interface StartDeps {
12
+ git: GitRunner;
13
+ config: StoreConfig;
14
+ /** Fetches the default branch into `origin/<default>`; false when there is no remote or it cannot be reached. */
15
+ fetch(cwd: string): Promise<boolean>;
16
+ now(): Date;
17
+ /**
18
+ * Whether a generated branch name is already taken, when the caller can say
19
+ * (the server, whose captures can start twice in one second): a taken name
20
+ * is stepped past one second at a time. Omitted, the first name is used and
21
+ * git refuses a collision.
22
+ */
23
+ branchTaken?(branch: string): Promise<boolean>;
24
+ }
25
+ export interface StartedSession {
26
+ /** The worktree's directory name: what the other session commands take. */
27
+ name: string;
28
+ worktree: string;
29
+ branch: string;
30
+ startPoint: string;
31
+ fetched: boolean;
32
+ /** The normalized label this session was named with, or null when none was given. */
33
+ label: string | null;
34
+ }
35
+ /**
36
+ * approve-sessions-across-stores: a session joined to one in the store that
37
+ * mounts this one takes its branch and worktree name from that session, never
38
+ * from a label or the clock. Only `ctxr session start --joins` passes it; the
39
+ * MCP surface keeps no mounts.
40
+ */
41
+ export interface JoinedName {
42
+ branch: string;
43
+ worktreeName: string;
44
+ }
45
+ export declare function startSession(deps: StartDeps, storeRoot: string, label?: string, joined?: JoinedName): Promise<StartedSession>;
46
+ //# sourceMappingURL=start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/core/session/start.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIhD;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,iHAAiH;IACjH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,GAAG,IAAI,IAAI,CAAC;IACZ;;;;;OAKG;IACH,WAAW,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,qFAAqF;IACrF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CA0BnI"}
@@ -0,0 +1,33 @@
1
+ import path from 'node:path';
2
+ import { SessionLabelUnusableError, SessionNameExistsError, SessionWorktreeRefusedError } from '../errors.js';
3
+ import { addWorktree } from '../git/worktree.js';
4
+ import { findSessionWorktreeByLabel, generateSessionBranchName, sessionLabelSlug, worktreePathFor } from '../session.js';
5
+ export async function startSession(deps, storeRoot, label, joined) {
6
+ // Ahead of the fetch, so a label that can never work costs no network round trip and leaves nothing behind.
7
+ let labelSlug = null;
8
+ if (label !== undefined) {
9
+ labelSlug = sessionLabelSlug(label);
10
+ if (labelSlug === '')
11
+ throw new SessionLabelUnusableError(label);
12
+ // A label identifies at most one session at a time, checked against the sessions on disk (name-the-session-at-start D4).
13
+ const existing = await findSessionWorktreeByLabel(storeRoot, deps.config, labelSlug);
14
+ if (existing !== null)
15
+ throw new SessionNameExistsError(labelSlug, existing);
16
+ }
17
+ const defaultBranch = deps.config.git.default_branch;
18
+ const fetched = await deps.fetch(storeRoot);
19
+ // The local branch both with no remote at all and with a remote that lacks the branch: honest, expected states.
20
+ const startPoint = fetched ? `origin/${defaultBranch}` : defaultBranch;
21
+ let branch = joined?.branch ?? generateSessionBranchName(deps.config, deps.now(), labelSlug ?? undefined);
22
+ if (joined === undefined && deps.branchTaken !== undefined) {
23
+ for (let step = 1; step <= 60 && (await deps.branchTaken(branch)); step += 1) {
24
+ branch = generateSessionBranchName(deps.config, new Date(deps.now().getTime() + step * 1000), labelSlug ?? undefined);
25
+ }
26
+ }
27
+ const worktree = joined === undefined ? worktreePathFor({ root: storeRoot, config: deps.config }, branch) : path.join(storeRoot, deps.config.session.worktrees_path, joined.worktreeName);
28
+ const added = await addWorktree(deps.git, storeRoot, worktree, branch, startPoint, { allowFailure: true });
29
+ if (added.exitCode !== 0)
30
+ throw new SessionWorktreeRefusedError(branch, worktree, added.stderr);
31
+ return { name: path.basename(worktree), worktree, branch, startPoint, fetched, label: labelSlug };
32
+ }
33
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/core/session/start.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAE9G,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AA+CzH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAe,EAAE,SAAiB,EAAE,KAAc,EAAE,MAAmB;IACxG,4GAA4G;IAC5G,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,SAAS,KAAK,EAAE;YAAE,MAAM,IAAI,yBAAyB,CAAC,KAAK,CAAC,CAAC;QACjE,yHAAyH;QACzH,MAAM,QAAQ,GAAG,MAAM,0BAA0B,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACrF,IAAI,QAAQ,KAAK,IAAI;YAAE,MAAM,IAAI,sBAAsB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;IACrD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC5C,gHAAgH;IAChH,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,UAAU,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;IAEvE,IAAI,MAAM,GAAG,MAAM,EAAE,MAAM,IAAI,yBAAyB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,IAAI,SAAS,CAAC,CAAC;IAC1G,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QAC3D,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;YAC7E,MAAM,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,EAAE,SAAS,IAAI,SAAS,CAAC,CAAC;QACxH,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1L,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3G,IAAI,KAAK,CAAC,QAAQ,KAAK,CAAC;QAAE,MAAM,IAAI,2BAA2B,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAChG,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AACpG,CAAC"}