ctxr-cli 0.34.0 → 0.36.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 (204) hide show
  1. package/README.md +50 -7
  2. package/dist/commands/land.d.ts +1 -1
  3. package/dist/commands/land.d.ts.map +1 -1
  4. package/dist/commands/land.js +8 -4
  5. package/dist/commands/land.js.map +1 -1
  6. package/dist/commands/plugin-build.d.ts +33 -0
  7. package/dist/commands/plugin-build.d.ts.map +1 -0
  8. package/dist/commands/plugin-build.js +51 -0
  9. package/dist/commands/plugin-build.js.map +1 -0
  10. package/dist/commands/publish-check.d.ts.map +1 -1
  11. package/dist/commands/publish-check.js +35 -4
  12. package/dist/commands/publish-check.js.map +1 -1
  13. package/dist/commands/serve.d.ts +3 -0
  14. package/dist/commands/serve.d.ts.map +1 -1
  15. package/dist/commands/serve.js +129 -23
  16. package/dist/commands/serve.js.map +1 -1
  17. package/dist/commands/session-start.d.ts.map +1 -1
  18. package/dist/commands/session-start.js +12 -38
  19. package/dist/commands/session-start.js.map +1 -1
  20. package/dist/commands/session-submit.d.ts.map +1 -1
  21. package/dist/commands/session-submit.js +2 -0
  22. package/dist/commands/session-submit.js.map +1 -1
  23. package/dist/commands/sync.d.ts +50 -0
  24. package/dist/commands/sync.d.ts.map +1 -0
  25. package/dist/commands/sync.js +186 -0
  26. package/dist/commands/sync.js.map +1 -0
  27. package/dist/commands/version.d.ts.map +1 -1
  28. package/dist/commands/version.js +6 -3
  29. package/dist/commands/version.js.map +1 -1
  30. package/dist/config/defaults.d.ts +13 -0
  31. package/dist/config/defaults.d.ts.map +1 -1
  32. package/dist/config/defaults.js +11 -0
  33. package/dist/config/defaults.js.map +1 -1
  34. package/dist/config/schema.d.ts +1 -0
  35. package/dist/config/schema.d.ts.map +1 -1
  36. package/dist/config/schema.js +7 -0
  37. package/dist/config/schema.js.map +1 -1
  38. package/dist/core/approval/sessions.d.ts.map +1 -1
  39. package/dist/core/approval/sessions.js +4 -2
  40. package/dist/core/approval/sessions.js.map +1 -1
  41. package/dist/core/browse/approve.d.ts.map +1 -1
  42. package/dist/core/browse/approve.js +12 -2
  43. package/dist/core/browse/approve.js.map +1 -1
  44. package/dist/core/browse/page-url.d.ts +13 -0
  45. package/dist/core/browse/page-url.d.ts.map +1 -1
  46. package/dist/core/browse/page-url.js +17 -0
  47. package/dist/core/browse/page-url.js.map +1 -1
  48. package/dist/core/browse/pull-preview.d.ts +67 -0
  49. package/dist/core/browse/pull-preview.d.ts.map +1 -0
  50. package/dist/core/browse/pull-preview.js +154 -0
  51. package/dist/core/browse/pull-preview.js.map +1 -0
  52. package/dist/core/browse/webhook.d.ts +38 -0
  53. package/dist/core/browse/webhook.d.ts.map +1 -0
  54. package/dist/core/browse/webhook.js +102 -0
  55. package/dist/core/browse/webhook.js.map +1 -0
  56. package/dist/core/errors.d.ts +16 -0
  57. package/dist/core/errors.d.ts.map +1 -1
  58. package/dist/core/errors.js +27 -0
  59. package/dist/core/errors.js.map +1 -1
  60. package/dist/core/fs/atomic.d.ts +3 -2
  61. package/dist/core/fs/atomic.d.ts.map +1 -1
  62. package/dist/core/fs/atomic.js +3 -2
  63. package/dist/core/fs/atomic.js.map +1 -1
  64. package/dist/core/git/exec.d.ts +16 -1
  65. package/dist/core/git/exec.d.ts.map +1 -1
  66. package/dist/core/git/exec.js +15 -4
  67. package/dist/core/git/exec.js.map +1 -1
  68. package/dist/core/git/fast-forward.d.ts +23 -0
  69. package/dist/core/git/fast-forward.d.ts.map +1 -1
  70. package/dist/core/git/fast-forward.js +24 -0
  71. package/dist/core/git/fast-forward.js.map +1 -1
  72. package/dist/core/git/hardened.d.ts +15 -0
  73. package/dist/core/git/hardened.d.ts.map +1 -0
  74. package/dist/core/git/hardened.js +123 -0
  75. package/dist/core/git/hardened.js.map +1 -0
  76. package/dist/core/install-kind.d.ts +10 -3
  77. package/dist/core/install-kind.d.ts.map +1 -1
  78. package/dist/core/install-kind.js +48 -14
  79. package/dist/core/install-kind.js.map +1 -1
  80. package/dist/core/mcp/cli-runner.d.ts +41 -0
  81. package/dist/core/mcp/cli-runner.d.ts.map +1 -0
  82. package/dist/core/mcp/cli-runner.js +81 -0
  83. package/dist/core/mcp/cli-runner.js.map +1 -0
  84. package/dist/core/mcp/jsonrpc.d.ts +13 -1
  85. package/dist/core/mcp/jsonrpc.d.ts.map +1 -1
  86. package/dist/core/mcp/jsonrpc.js +1 -1
  87. package/dist/core/mcp/jsonrpc.js.map +1 -1
  88. package/dist/core/mcp/member-sessions.d.ts +48 -0
  89. package/dist/core/mcp/member-sessions.d.ts.map +1 -0
  90. package/dist/core/mcp/member-sessions.js +85 -0
  91. package/dist/core/mcp/member-sessions.js.map +1 -0
  92. package/dist/core/mcp/ownership.d.ts +51 -0
  93. package/dist/core/mcp/ownership.d.ts.map +1 -0
  94. package/dist/core/mcp/ownership.js +101 -0
  95. package/dist/core/mcp/ownership.js.map +1 -0
  96. package/dist/core/mcp/paths.d.ts +48 -0
  97. package/dist/core/mcp/paths.d.ts.map +1 -0
  98. package/dist/core/mcp/paths.js +111 -0
  99. package/dist/core/mcp/paths.js.map +1 -0
  100. package/dist/core/mcp/sessions.d.ts +24 -46
  101. package/dist/core/mcp/sessions.d.ts.map +1 -1
  102. package/dist/core/mcp/sessions.js +31 -103
  103. package/dist/core/mcp/sessions.js.map +1 -1
  104. package/dist/core/mcp/tool-map.d.ts +94 -0
  105. package/dist/core/mcp/tool-map.d.ts.map +1 -0
  106. package/dist/core/mcp/tool-map.js +211 -0
  107. package/dist/core/mcp/tool-map.js.map +1 -0
  108. package/dist/core/mcp/tools/capture.d.ts +7 -2
  109. package/dist/core/mcp/tools/capture.d.ts.map +1 -1
  110. package/dist/core/mcp/tools/capture.js +69 -18
  111. package/dist/core/mcp/tools/capture.js.map +1 -1
  112. package/dist/core/mcp/tools/cli.d.ts +97 -0
  113. package/dist/core/mcp/tools/cli.d.ts.map +1 -0
  114. package/dist/core/mcp/tools/cli.js +271 -0
  115. package/dist/core/mcp/tools/cli.js.map +1 -0
  116. package/dist/core/mcp/tools/edit.d.ts +62 -28
  117. package/dist/core/mcp/tools/edit.d.ts.map +1 -1
  118. package/dist/core/mcp/tools/edit.js +182 -153
  119. package/dist/core/mcp/tools/edit.js.map +1 -1
  120. package/dist/core/mcp/tools/files.d.ts +37 -11
  121. package/dist/core/mcp/tools/files.d.ts.map +1 -1
  122. package/dist/core/mcp/tools/files.js +122 -100
  123. package/dist/core/mcp/tools/files.js.map +1 -1
  124. package/dist/core/mcp/tools/index.d.ts +12 -3
  125. package/dist/core/mcp/tools/index.d.ts.map +1 -1
  126. package/dist/core/mcp/tools/index.js +161 -58
  127. package/dist/core/mcp/tools/index.js.map +1 -1
  128. package/dist/core/mcp/tools/sessions.d.ts +145 -0
  129. package/dist/core/mcp/tools/sessions.d.ts.map +1 -0
  130. package/dist/core/mcp/tools/sessions.js +226 -0
  131. package/dist/core/mcp/tools/sessions.js.map +1 -0
  132. package/dist/core/npm-prefix.d.ts +10 -0
  133. package/dist/core/npm-prefix.d.ts.map +1 -0
  134. package/dist/core/npm-prefix.js +11 -0
  135. package/dist/core/npm-prefix.js.map +1 -0
  136. package/dist/core/plugin/build.d.ts +70 -0
  137. package/dist/core/plugin/build.d.ts.map +1 -0
  138. package/dist/core/plugin/build.js +159 -0
  139. package/dist/core/plugin/build.js.map +1 -0
  140. package/dist/core/plugin/routes.d.ts +35 -0
  141. package/dist/core/plugin/routes.d.ts.map +1 -0
  142. package/dist/core/plugin/routes.js +77 -0
  143. package/dist/core/plugin/routes.js.map +1 -0
  144. package/dist/core/plugin/zip.d.ts +17 -0
  145. package/dist/core/plugin/zip.d.ts.map +1 -0
  146. package/dist/core/plugin/zip.js +75 -0
  147. package/dist/core/plugin/zip.js.map +1 -0
  148. package/dist/core/session/start.d.ts +46 -0
  149. package/dist/core/session/start.d.ts.map +1 -0
  150. package/dist/core/session/start.js +33 -0
  151. package/dist/core/session/start.js.map +1 -0
  152. package/dist/core/session/submit.d.ts +7 -0
  153. package/dist/core/session/submit.d.ts.map +1 -1
  154. package/dist/core/session/submit.js +8 -0
  155. package/dist/core/session/submit.js.map +1 -1
  156. package/dist/core/skills.d.ts +20 -2
  157. package/dist/core/skills.d.ts.map +1 -1
  158. package/dist/core/skills.js +56 -3
  159. package/dist/core/skills.js.map +1 -1
  160. package/dist/core/store-update-runner.d.ts +57 -0
  161. package/dist/core/store-update-runner.d.ts.map +1 -0
  162. package/dist/core/{approval/lander.js → store-update-runner.js} +41 -17
  163. package/dist/core/store-update-runner.js.map +1 -0
  164. package/dist/run.d.ts +12 -0
  165. package/dist/run.d.ts.map +1 -1
  166. package/dist/run.js +93 -58
  167. package/dist/run.js.map +1 -1
  168. package/dist/version.d.ts +1 -1
  169. package/dist/version.js +1 -1
  170. package/package.json +1 -1
  171. package/templates/approve/pages-note-pull.md +1 -0
  172. package/templates/conventions/baseline-conventions.md +5 -0
  173. package/templates/mcp/Delete.md +6 -0
  174. package/templates/mcp/Edit.md +6 -5
  175. package/templates/mcp/Glob.md +2 -2
  176. package/templates/mcp/Grep.md +2 -1
  177. package/templates/mcp/Move.md +7 -0
  178. package/templates/mcp/Read.md +4 -4
  179. package/templates/mcp/Write.md +4 -4
  180. package/templates/mcp/ctxr.md +7 -0
  181. package/templates/mcp/ctxr_write.md +8 -0
  182. package/templates/mcp/server-instructions.md +11 -3
  183. package/templates/mcp/session_discard.md +4 -0
  184. package/templates/mcp/session_list.md +7 -0
  185. package/templates/mcp/session_rebase.md +5 -0
  186. package/templates/mcp/session_start.md +7 -0
  187. package/templates/mcp/session_status.md +3 -0
  188. package/templates/mcp/session_submit.md +8 -0
  189. package/templates/plugin/README.md +13 -0
  190. package/templates/plugin/chatgpt-mcp.json +19 -0
  191. package/templates/plugin/chatgpt-plugin.json +13 -0
  192. package/templates/plugin/claude-mcp.json +8 -0
  193. package/templates/plugin/claude-plugin.json +6 -0
  194. package/templates/plugin/page.html +47 -0
  195. package/templates/skills/ctxr-publish.md +2 -1
  196. package/templates/skills/ctxr-upgrade.md +5 -5
  197. package/templates/skills/mcp/_preamble.md +44 -0
  198. package/dist/core/approval/lander.d.ts +0 -38
  199. package/dist/core/approval/lander.d.ts.map +0 -1
  200. package/dist/core/approval/lander.js.map +0 -1
  201. package/dist/core/mcp/drafts.d.ts +0 -30
  202. package/dist/core/mcp/drafts.d.ts.map +0 -1
  203. package/dist/core/mcp/drafts.js +0 -52
  204. package/dist/core/mcp/drafts.js.map +0 -1
package/dist/run.js CHANGED
@@ -7,6 +7,7 @@ import * as archiveCommand from './commands/archive.js';
7
7
  import * as doctorCommand from './commands/doctor.js';
8
8
  import * as ingestCommand from './commands/ingest.js';
9
9
  import * as landCommand from './commands/land.js';
10
+ import * as syncCommand from './commands/sync.js';
10
11
  import * as lintCommand from './commands/lint.js';
11
12
  import * as contextGatherCommand from './commands/context-gather.js';
12
13
  import * as graphBuildCommand from './commands/graph-build.js';
@@ -19,6 +20,7 @@ import * as publishCheckCommand from './commands/publish-check.js';
19
20
  import * as publishUrlsCommand from './commands/publish-urls.js';
20
21
  import * as publishNewCommand from './commands/publish-new.js';
21
22
  import * as publishStampCommand from './commands/publish-stamp.js';
23
+ import * as pluginBuildCommand from './commands/plugin-build.js';
22
24
  import * as reviewListCommand from './commands/review-list.js';
23
25
  import * as secondOpinionCommand from './commands/second-opinion.js';
24
26
  import * as sharedStoresStatusCommand from './commands/shared-stores-status.js';
@@ -168,12 +170,12 @@ function commandPathFor(program, argv) {
168
170
  function collect(value, previous) {
169
171
  return [...previous, value];
170
172
  }
171
- export async function run(argv, env) {
172
- if (isGlobalVersionRequest(argv)) {
173
- const jsonMode = argv.includes('--json');
174
- const runEnv = { ...env, noInput: env.noInput || argv.includes('--no-input') || jsonMode };
175
- return runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv));
176
- }
173
+ /**
174
+ * The command tree, built once per invocation. Exported so the MCP surface's
175
+ * tool/command alignment check (serve-the-session-lifecycle-to-chat-apps D9)
176
+ * reads the CLI's real command registry rather than a copy of it.
177
+ */
178
+ export function buildProgram(env) {
177
179
  const program = new Command();
178
180
  program
179
181
  .name('ctxr')
@@ -185,7 +187,7 @@ export async function run(argv, env) {
185
187
  .option('--root <path>', 'store root (overrides CONTEXTURE_STORE_ROOT)')
186
188
  .option('--json', 'emit machine-readable output')
187
189
  .option('--no-input', 'never prompt; fail loud instead of blocking');
188
- let result = ExitCode.Ok;
190
+ const state = { result: ExitCode.Ok };
189
191
  program
190
192
  .command('init')
191
193
  .description('create a new context store, or reconcile an existing one')
@@ -194,7 +196,7 @@ export async function run(argv, env) {
194
196
  .option('--harness <ids>', `comma-separated harness-generation adapters to target (${initCommand.SELECTABLE_HARNESS_IDS.join(', ')}), or "none"`)
195
197
  .action(async (cmdOpts, cmd) => {
196
198
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
197
- result = await runCommand('init', runEnv, jsonMode, () => initCommand.execute(runEnv, { root, profile: cmdOpts.profile, taxonomy: cmdOpts.taxonomy, harness: cmdOpts.harness }));
199
+ state.result = await runCommand('init', runEnv, jsonMode, () => initCommand.execute(runEnv, { root, profile: cmdOpts.profile, taxonomy: cmdOpts.taxonomy, harness: cmdOpts.harness }));
198
200
  });
199
201
  program
200
202
  .command('doctor')
@@ -202,7 +204,7 @@ export async function run(argv, env) {
202
204
  .option('--staged', 'check staged changes only (used by the pre-commit hook)')
203
205
  .action(async (cmdOpts, cmd) => {
204
206
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
205
- result = await runCommand('doctor', runEnv, jsonMode, async () => {
207
+ state.result = await runCommand('doctor', runEnv, jsonMode, async () => {
206
208
  const store = await openStore(runEnv, { root });
207
209
  return doctorCommand.execute(runEnv, store, { staged: cmdOpts.staged });
208
210
  });
@@ -215,7 +217,7 @@ export async function run(argv, env) {
215
217
  .requiredOption('--text <text>', 'the line to append')
216
218
  .action(async (notePath, cmdOpts, cmd) => {
217
219
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
218
- result = await runCommand('entry.append', runEnv, jsonMode, async () => {
220
+ state.result = await runCommand('entry.append', runEnv, jsonMode, async () => {
219
221
  const store = await openStore(runEnv, { root });
220
222
  return entryAppendCommand.execute(runEnv, store, { path: notePath, region: cmdOpts.region, text: cmdOpts.text });
221
223
  });
@@ -226,7 +228,7 @@ export async function run(argv, env) {
226
228
  .description('regenerate every catalog section, preserving authored glosses')
227
229
  .action(async (_cmdOpts, cmd) => {
228
230
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
229
- result = await runCommand('catalog.build', runEnv, jsonMode, async () => {
231
+ state.result = await runCommand('catalog.build', runEnv, jsonMode, async () => {
230
232
  const store = await openStore(runEnv, { root });
231
233
  return catalogBuildCommand.execute(store);
232
234
  });
@@ -237,7 +239,7 @@ export async function run(argv, env) {
237
239
  .option('--stale', 'also report entries whose note has changed since the gloss was confirmed')
238
240
  .action(async (cmdOpts, cmd) => {
239
241
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
240
- result = await runCommand('catalog.check', runEnv, jsonMode, async () => {
242
+ state.result = await runCommand('catalog.check', runEnv, jsonMode, async () => {
241
243
  const store = await openStore(runEnv, { root });
242
244
  return catalogCheckCommand.execute(store, { stale: cmdOpts.stale });
243
245
  });
@@ -248,7 +250,7 @@ export async function run(argv, env) {
248
250
  .requiredOption('--section <id>', 'the section id to print')
249
251
  .action(async (cmdOpts, cmd) => {
250
252
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
251
- result = await runCommand('catalog.show', runEnv, jsonMode, async () => {
253
+ state.result = await runCommand('catalog.show', runEnv, jsonMode, async () => {
252
254
  const store = await openStore(runEnv, { root });
253
255
  return catalogShowCommand.execute(store, { section: cmdOpts.section });
254
256
  });
@@ -267,7 +269,7 @@ export async function run(argv, env) {
267
269
  .option('--max-notes <n>', 'cap the returned set; truncation is reported, never silent', (v) => Number.parseInt(v, 10))
268
270
  .action(async (cmdOpts, cmd) => {
269
271
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
270
- result = await runCommand('context.gather', runEnv, jsonMode, async () => {
272
+ state.result = await runCommand('context.gather', runEnv, jsonMode, async () => {
271
273
  const store = await openStore(runEnv, { root });
272
274
  return contextGatherCommand.execute(store, {
273
275
  seed: cmdOpts.seed,
@@ -288,7 +290,7 @@ export async function run(argv, env) {
288
290
  .option('--emit-records', 'also emit a stable per-note record list {id, path, gloss, hash}')
289
291
  .action(async (cmdOpts, cmd) => {
290
292
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
291
- result = await runCommand('graph.build', runEnv, jsonMode, async () => {
293
+ state.result = await runCommand('graph.build', runEnv, jsonMode, async () => {
292
294
  const store = await openStore(runEnv, { root });
293
295
  return graphBuildCommand.execute(store, { emitRecords: cmdOpts.emitRecords });
294
296
  });
@@ -304,7 +306,7 @@ export async function run(argv, env) {
304
306
  const flags = { since: cmdOpts.since, until: cmdOpts.until, format: cmdOpts.format };
305
307
  // review-the-knowledge-diff (D9): `--format markdown` is the whole stdout — the
306
308
  // block rides as the human summary, which the reporter writes verbatim and alone.
307
- result = await runCommand('graph.diff', runEnv, jsonMode, async () => {
309
+ state.result = await runCommand('graph.diff', runEnv, jsonMode, async () => {
308
310
  graphDiffCommand.checkFlags(flags, jsonMode);
309
311
  const store = await openStore(runEnv, { root });
310
312
  return graphDiffCommand.execute(store, flags, jsonMode);
@@ -319,7 +321,7 @@ export async function run(argv, env) {
319
321
  .option('--type <name>', 'follow only edges of this type (a configured relation name, or link)')
320
322
  .action(async (node, cmdOpts, cmd) => {
321
323
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
322
- result = await runCommand('graph.query.neighbors', runEnv, jsonMode, async () => {
324
+ state.result = await runCommand('graph.query.neighbors', runEnv, jsonMode, async () => {
323
325
  const store = await openStore(runEnv, { root });
324
326
  return graphQueryCommand.executeNeighbors(store, {
325
327
  node,
@@ -334,7 +336,7 @@ export async function run(argv, env) {
334
336
  .description('shortest path between two nodes, if one exists')
335
337
  .action(async (from, to, _cmdOpts, cmd) => {
336
338
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
337
- result = await runCommand('graph.query.path', runEnv, jsonMode, async () => {
339
+ state.result = await runCommand('graph.query.path', runEnv, jsonMode, async () => {
338
340
  const store = await openStore(runEnv, { root });
339
341
  return graphQueryCommand.executePath(store, { from, to });
340
342
  });
@@ -344,7 +346,7 @@ export async function run(argv, env) {
344
346
  .description('the induced subgraph over the given node ids')
345
347
  .action(async (ids, _cmdOpts, cmd) => {
346
348
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
347
- result = await runCommand('graph.query.subgraph', runEnv, jsonMode, async () => {
349
+ state.result = await runCommand('graph.query.subgraph', runEnv, jsonMode, async () => {
348
350
  const store = await openStore(runEnv, { root });
349
351
  return graphQueryCommand.executeSubgraph(store, { ids });
350
352
  });
@@ -355,7 +357,7 @@ export async function run(argv, env) {
355
357
  .option('--top <n>', 'how many to list', (v) => Number.parseInt(v, 10), 10)
356
358
  .action(async (cmdOpts, cmd) => {
357
359
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
358
- result = await runCommand('graph.query.hubs', runEnv, jsonMode, async () => {
360
+ state.result = await runCommand('graph.query.hubs', runEnv, jsonMode, async () => {
359
361
  const store = await openStore(runEnv, { root });
360
362
  return graphQueryCommand.executeHubs(store, { top: cmdOpts.top });
361
363
  });
@@ -365,7 +367,7 @@ export async function run(argv, env) {
365
367
  .description('every positional cluster with its note count')
366
368
  .action(async (_cmdOpts, cmd) => {
367
369
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
368
- result = await runCommand('graph.query.clusters', runEnv, jsonMode, async () => {
370
+ state.result = await runCommand('graph.query.clusters', runEnv, jsonMode, async () => {
369
371
  const store = await openStore(runEnv, { root });
370
372
  return graphQueryCommand.executeClusters(store, {});
371
373
  });
@@ -376,7 +378,7 @@ export async function run(argv, env) {
376
378
  .option('--top <n>', 'how many to list (default: the configured bridge limit)', (v) => Number.parseInt(v, 10))
377
379
  .action(async (cmdOpts, cmd) => {
378
380
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
379
- result = await runCommand('graph.query.bridges', runEnv, jsonMode, async () => {
381
+ state.result = await runCommand('graph.query.bridges', runEnv, jsonMode, async () => {
380
382
  const store = await openStore(runEnv, { root });
381
383
  return graphQueryCommand.executeBridges(store, { top: cmdOpts.top });
382
384
  });
@@ -386,7 +388,7 @@ export async function run(argv, env) {
386
388
  .description('nodes with no links in or out')
387
389
  .action(async (_cmdOpts, cmd) => {
388
390
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
389
- result = await runCommand('graph.query.orphans', runEnv, jsonMode, async () => {
391
+ state.result = await runCommand('graph.query.orphans', runEnv, jsonMode, async () => {
390
392
  const store = await openStore(runEnv, { root });
391
393
  return graphQueryCommand.executeOrphans(store, {});
392
394
  });
@@ -399,7 +401,7 @@ export async function run(argv, env) {
399
401
  .requiredOption('--source-id <id>', 'a stable identifier for this specific source')
400
402
  .action(async (capturePath, cmdOpts, cmd) => {
401
403
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
402
- result = await runCommand('ingest', runEnv, jsonMode, async () => {
404
+ state.result = await runCommand('ingest', runEnv, jsonMode, async () => {
403
405
  const store = await openStore(runEnv, { root });
404
406
  return ingestCommand.execute(runEnv, store, {
405
407
  path: capturePath,
@@ -415,7 +417,7 @@ export async function run(argv, env) {
415
417
  .description('the canonicalized-content hash of a file')
416
418
  .action(async (notePath, _cmdOpts, cmd) => {
417
419
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
418
- result = await runCommand('source.hash', runEnv, jsonMode, async () => {
420
+ state.result = await runCommand('source.hash', runEnv, jsonMode, async () => {
419
421
  const store = await openStore(runEnv, { root });
420
422
  return sourceHashCommand.execute(runEnv, store, { path: notePath });
421
423
  });
@@ -426,7 +428,7 @@ export async function run(argv, env) {
426
428
  .requiredOption('--source-id <id>', "the candidate material's source identifier")
427
429
  .action(async (notePath, cmdOpts, cmd) => {
428
430
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
429
- result = await runCommand('source.check', runEnv, jsonMode, async () => {
431
+ state.result = await runCommand('source.check', runEnv, jsonMode, async () => {
430
432
  const store = await openStore(runEnv, { root });
431
433
  return sourceCheckCommand.execute(runEnv, store, { path: notePath, sourceId: cmdOpts.sourceId });
432
434
  });
@@ -438,7 +440,7 @@ export async function run(argv, env) {
438
440
  .option('--hash <hash>', 'the content hash to record (default: computed from the note\'s current body)')
439
441
  .action(async (notePath, cmdOpts, cmd) => {
440
442
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
441
- result = await runCommand('source.stamp', runEnv, jsonMode, async () => {
443
+ state.result = await runCommand('source.stamp', runEnv, jsonMode, async () => {
442
444
  const store = await openStore(runEnv, { root });
443
445
  return sourceStampCommand.execute(runEnv, store, { path: notePath, id: cmdOpts.id, hash: cmdOpts.hash });
444
446
  });
@@ -449,7 +451,7 @@ export async function run(argv, env) {
449
451
  .requiredOption('--id <id>', 'the alternative source identifier')
450
452
  .action(async (notePath, cmdOpts, cmd) => {
451
453
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
452
- result = await runCommand('source.add-alt', runEnv, jsonMode, async () => {
454
+ state.result = await runCommand('source.add-alt', runEnv, jsonMode, async () => {
453
455
  const store = await openStore(runEnv, { root });
454
456
  return sourceAddAltCommand.execute(runEnv, store, { path: notePath, id: cmdOpts.id });
455
457
  });
@@ -459,7 +461,7 @@ export async function run(argv, env) {
459
461
  .description('health observations that never fail the run: orphans, broken links, uningested inbox material, catalog gaps')
460
462
  .action(async (_cmdOpts, cmd) => {
461
463
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
462
- result = await runCommand('lint', runEnv, jsonMode, async () => {
464
+ state.result = await runCommand('lint', runEnv, jsonMode, async () => {
463
465
  const store = await openStore(runEnv, { root });
464
466
  return lintCommand.execute(runEnv, store);
465
467
  });
@@ -469,7 +471,7 @@ export async function run(argv, env) {
469
471
  .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')
470
472
  .action(async (notePath, _cmdOpts, cmd) => {
471
473
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
472
- result = await runCommand('archive', runEnv, jsonMode, async () => {
474
+ state.result = await runCommand('archive', runEnv, jsonMode, async () => {
473
475
  const store = await openStore(runEnv, { root });
474
476
  return archiveCommand.execute(runEnv, store, { path: notePath });
475
477
  });
@@ -480,7 +482,7 @@ export async function run(argv, env) {
480
482
  .description('enumerate candidate source notes (notes linking to <entity>) for a rollup')
481
483
  .action(async (entity, _cmdOpts, cmd) => {
482
484
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
483
- result = await runCommand('rollup.gather', runEnv, jsonMode, async () => {
485
+ state.result = await runCommand('rollup.gather', runEnv, jsonMode, async () => {
484
486
  const store = await openStore(runEnv, { root });
485
487
  return rollupGatherCommand.execute(runEnv, store, { entity });
486
488
  });
@@ -491,7 +493,7 @@ export async function run(argv, env) {
491
493
  .requiredOption('--content-file <path>', 'a file containing the rollup text to write')
492
494
  .action(async (entity, cmdOpts, cmd) => {
493
495
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
494
- result = await runCommand('rollup.write', runEnv, jsonMode, async () => {
496
+ state.result = await runCommand('rollup.write', runEnv, jsonMode, async () => {
495
497
  const store = await openStore(runEnv, { root });
496
498
  return rollupWriteCommand.execute(runEnv, store, { entity, contentFile: cmdOpts.contentFile });
497
499
  });
@@ -502,7 +504,7 @@ export async function run(argv, env) {
502
504
  .option('--for <entity>', 'check only this entity')
503
505
  .action(async (cmdOpts, cmd) => {
504
506
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
505
- result = await runCommand('rollup.stale', runEnv, jsonMode, async () => {
507
+ state.result = await runCommand('rollup.stale', runEnv, jsonMode, async () => {
506
508
  const store = await openStore(runEnv, { root });
507
509
  return rollupStaleCommand.execute(runEnv, store, { for: cmdOpts.for });
508
510
  });
@@ -516,7 +518,7 @@ export async function run(argv, env) {
516
518
  .option('--entity <name>', 'every note linking to this entity (same enumeration as rollup gather)')
517
519
  .action(async (cmdOpts, cmd) => {
518
520
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
519
- result = await runCommand('publish.gather', runEnv, jsonMode, async () => {
521
+ state.result = await runCommand('publish.gather', runEnv, jsonMode, async () => {
520
522
  const store = await openStore(runEnv, { root });
521
523
  return publishGatherCommand.execute(runEnv, store, {
522
524
  under: cmdOpts.under,
@@ -531,7 +533,7 @@ export async function run(argv, env) {
531
533
  .option('--disposable', 'scaffold a disposable page at disposable/<YYYY-MM-DD>-<slug>, dated today by the command (two-kinds-of-published-page)')
532
534
  .action(async (slug, cmdOpts, cmd) => {
533
535
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
534
- result = await runCommand('publish.new', runEnv, jsonMode, async () => {
536
+ state.result = await runCommand('publish.new', runEnv, jsonMode, async () => {
535
537
  const store = await openStore(runEnv, { root });
536
538
  return publishNewCommand.execute(store, { slug, disposable: cmdOpts.disposable === true });
537
539
  });
@@ -541,7 +543,7 @@ export async function run(argv, env) {
541
543
  .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")
542
544
  .action(async (pagePath, _cmdOpts, cmd) => {
543
545
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
544
- result = await runCommand('publish.stamp', runEnv, jsonMode, async () => {
546
+ state.result = await runCommand('publish.stamp', runEnv, jsonMode, async () => {
545
547
  const store = await openStore(runEnv, { root });
546
548
  return publishStampCommand.execute(store, { path: pagePath });
547
549
  });
@@ -551,7 +553,7 @@ export async function run(argv, env) {
551
553
  .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")
552
554
  .action(async (pagePath, _cmdOpts, cmd) => {
553
555
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
554
- result = await runCommand('publish.check', runEnv, jsonMode, async () => {
556
+ state.result = await runCommand('publish.check', runEnv, jsonMode, async () => {
555
557
  const store = await openStore(runEnv, { root });
556
558
  return publishCheckCommand.execute(store, { path: pagePath });
557
559
  });
@@ -563,7 +565,7 @@ export async function run(argv, env) {
563
565
  .option('--since <ref>', 'the changes since this ref, as a pull request against it would show')
564
566
  .action(async (cmdOpts, cmd) => {
565
567
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
566
- result = await runCommand('publish.urls', runEnv, jsonMode, async () => {
568
+ state.result = await runCommand('publish.urls', runEnv, jsonMode, async () => {
567
569
  const store = await openStore(runEnv, { root });
568
570
  return publishUrlsCommand.execute(store, { staged: cmdOpts.staged === true, since: cmdOpts.since });
569
571
  });
@@ -574,7 +576,7 @@ export async function run(argv, env) {
574
576
  .description('(re)generate every configured harness-generation adapter\'s output')
575
577
  .action(async (_cmdOpts, cmd) => {
576
578
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
577
- result = await runCommand('adapters.generate', runEnv, jsonMode, async () => {
579
+ state.result = await runCommand('adapters.generate', runEnv, jsonMode, async () => {
578
580
  const store = await openStore(runEnv, { root });
579
581
  return adaptersGenerateCommand.execute(runEnv, store);
580
582
  });
@@ -586,7 +588,7 @@ export async function run(argv, env) {
586
588
  .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)
587
589
  .action(async (cmdOpts, cmd) => {
588
590
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
589
- result = await runCommand('serve', runEnv, jsonMode, async () => {
591
+ state.result = await runCommand('serve', runEnv, jsonMode, async () => {
590
592
  const store = await openStore(runEnv, { root });
591
593
  return serveCommand.execute(runEnv, store, { port: cmdOpts.port, host: cmdOpts.host });
592
594
  });
@@ -597,7 +599,7 @@ export async function run(argv, env) {
597
599
  .option('--check', 'resolve the latest published release and compare it against the installed one')
598
600
  .action(async (cmdOpts, cmd) => {
599
601
  const { runEnv, jsonMode } = deriveRunEnv(env, cmd);
600
- result = await runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv, { check: cmdOpts.check }));
602
+ state.result = await runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv, { check: cmdOpts.check }));
601
603
  });
602
604
  program
603
605
  .command('update')
@@ -605,7 +607,7 @@ export async function run(argv, env) {
605
607
  .option('--worktree', 'work in a new worktree on a branch named for this release, never in this checkout; commits nothing')
606
608
  .action(async (cmdOpts, cmd) => {
607
609
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
608
- result = await runCommand('update', runEnv, jsonMode, async () => {
610
+ state.result = await runCommand('update', runEnv, jsonMode, async () => {
609
611
  // The one command allowed past the schema gate on an older store (migrate-stores-on-update).
610
612
  const store = await openStoreMigrating(runEnv, { root });
611
613
  return cmdOpts.worktree
@@ -619,7 +621,7 @@ export async function run(argv, env) {
619
621
  .option('--portable', "verify the store's recorded commit in a disposable checkout, in a child process with no harness state reachable")
620
622
  .action(async (cmdOpts, cmd) => {
621
623
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
622
- result = await runCommand('verify', runEnv, jsonMode, async () => {
624
+ state.result = await runCommand('verify', runEnv, jsonMode, async () => {
623
625
  const store = await openStore(runEnv, { root });
624
626
  return verifyCommand.execute(runEnv, store, { portable: cmdOpts.portable });
625
627
  });
@@ -633,18 +635,42 @@ export async function run(argv, env) {
633
635
  .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')
634
636
  .action(async (pr, cmdOpts, cmd) => {
635
637
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
636
- result = await runCommand('land', runEnv, jsonMode, async () => {
638
+ state.result = await runCommand('land', runEnv, jsonMode, async () => {
637
639
  const store = await openStore(runEnv, { root });
638
640
  return landCommand.execute(runEnv, store, { pr, pending: Boolean(cmdOpts.pending), confirm: Boolean(cmdOpts.confirm), session: cmdOpts.session });
639
641
  });
640
642
  });
643
+ program
644
+ .command('sync')
645
+ .description("bring the canonical clone up to date with the forge's default branch by landing's fast-forward rule, leaving a clone with local work alone; with --every, keep doing so, mounts included")
646
+ .option('--every <minutes>', 'keep running: every this many whole minutes, sync the canonical clone and then refresh the mounts as `ctxr shared-stores sync` does', (v) => Number(v))
647
+ .action(async (cmdOpts, cmd) => {
648
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
649
+ state.result = await runCommand('sync', runEnv, jsonMode, async () => {
650
+ const store = await openStore(runEnv, { root });
651
+ return syncCommand.execute(runEnv, store, cmdOpts.every === undefined ? {} : { every: cmdOpts.every });
652
+ });
653
+ });
654
+ // serve-the-session-lifecycle-to-chat-apps D7: the chat-app plugins, built from the MCP render of the owned skills.
655
+ const pluginCommand = program.command('plugin').description("build the store's Claude and ChatGPT plugins: its skills and its MCP server");
656
+ pluginCommand
657
+ .command('build')
658
+ .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')
659
+ .option('--out <dir>', 'where to write them (default: .contexture/cache/plugin/ under the store root)')
660
+ .action(async (cmdOpts, cmd) => {
661
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
662
+ state.result = await runCommand('plugin.build', runEnv, jsonMode, async () => {
663
+ const store = await openStore(runEnv, { root });
664
+ return pluginBuildCommand.execute(runEnv, store, { out: cmdOpts.out });
665
+ });
666
+ });
641
667
  const reviewCommand = program.command('review').description('read the decisions people made on session pull requests from the approval page');
642
668
  reviewCommand
643
669
  .command('list')
644
670
  .description('report each open session pull request with its decision state: awaiting, approved, changes-requested, needs-reapproval or blocked')
645
671
  .action(async (_cmdOpts, cmd) => {
646
672
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
647
- result = await runCommand('review.list', runEnv, jsonMode, async () => {
673
+ state.result = await runCommand('review.list', runEnv, jsonMode, async () => {
648
674
  const store = await openStore(runEnv, { root });
649
675
  return reviewListCommand.execute(runEnv, store);
650
676
  });
@@ -660,7 +686,7 @@ export async function run(argv, env) {
660
686
  .option('--timeout <seconds>', 'per-CLI time limit in seconds (default 600)');
661
687
  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) => {
662
688
  const { runEnv, jsonMode } = deriveRunEnv(env, cmd);
663
- result = await runCommand('second-opinion.preflight', runEnv, jsonMode, () => secondOpinionCommand.executePreflight(runEnv, cmdOpts));
689
+ state.result = await runCommand('second-opinion.preflight', runEnv, jsonMode, () => secondOpinionCommand.executePreflight(runEnv, cmdOpts));
664
690
  });
665
691
  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'))
666
692
  .option('--plan-file <path>', 'the plan to critique (default: read from stdin)')
@@ -668,7 +694,7 @@ export async function run(argv, env) {
668
694
  .option('--seed <n>', 'seed the letter assignment, for a reproducible mapping')
669
695
  .action(async (cmdOpts, cmd) => {
670
696
  const { runEnv, jsonMode } = deriveRunEnv(env, cmd);
671
- result = await runCommand('second-opinion.critique', runEnv, jsonMode, () => secondOpinionCommand.executeCritique(runEnv, cmdOpts));
697
+ state.result = await runCommand('second-opinion.critique', runEnv, jsonMode, () => secondOpinionCommand.executeCritique(runEnv, cmdOpts));
672
698
  });
673
699
  commonSecondOpinionOptions(secondOpinionGroup.command('poll').description('send one question to the same model families, optionally answered through two or three taste lenses'))
674
700
  .option('--prompt-file <path>', 'the question and its options (default: read from stdin)')
@@ -677,7 +703,7 @@ export async function run(argv, env) {
677
703
  .option('--no-wrap', 'send the question as written, without the answer scaffold')
678
704
  .action(async (cmdOpts, cmd) => {
679
705
  const { runEnv, jsonMode } = deriveRunEnv(env, cmd);
680
- result = await runCommand('second-opinion.poll', runEnv, jsonMode, () => secondOpinionCommand.executePoll(runEnv, cmdOpts));
706
+ state.result = await runCommand('second-opinion.poll', runEnv, jsonMode, () => secondOpinionCommand.executePoll(runEnv, cmdOpts));
681
707
  });
682
708
  const sharedStoresCommand = program.command('shared-stores').description('the stores this store mounts under shared/');
683
709
  sharedStoresCommand
@@ -685,7 +711,7 @@ export async function run(argv, env) {
685
711
  .description('clone each declared mount that is missing and fast-forward the others, leaving any with local work alone')
686
712
  .action(async (_cmdOpts, cmd) => {
687
713
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
688
- result = await runCommand('shared-stores.sync', runEnv, jsonMode, async () => {
714
+ state.result = await runCommand('shared-stores.sync', runEnv, jsonMode, async () => {
689
715
  const store = await openStore(runEnv, { root });
690
716
  return sharedStoresSyncCommand.execute(runEnv, store);
691
717
  });
@@ -695,7 +721,7 @@ export async function run(argv, env) {
695
721
  .description('report each declared mount: present, a store, branch, commit, uncommitted changes — no writes, no network')
696
722
  .action(async (_cmdOpts, cmd) => {
697
723
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
698
- result = await runCommand('shared-stores.status', runEnv, jsonMode, async () => {
724
+ state.result = await runCommand('shared-stores.status', runEnv, jsonMode, async () => {
699
725
  const store = await openStore(runEnv, { root });
700
726
  return sharedStoresStatusCommand.execute(runEnv, store);
701
727
  });
@@ -708,7 +734,7 @@ export async function run(argv, env) {
708
734
  .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)')
709
735
  .action(async (label, cmdOpts, cmd) => {
710
736
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
711
- result = await runCommand('session.start', runEnv, jsonMode, async () => {
737
+ state.result = await runCommand('session.start', runEnv, jsonMode, async () => {
712
738
  const store = await openStore(runEnv, { root });
713
739
  return sessionStartCommand.execute(runEnv, store, { label, ...(cmdOpts.joins === undefined ? {} : { joins: cmdOpts.joins }) });
714
740
  });
@@ -719,7 +745,7 @@ export async function run(argv, env) {
719
745
  .requiredOption('--proposal <path>', 'a YAML file of approved note items')
720
746
  .action(async (cmdOpts, cmd) => {
721
747
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
722
- result = await runCommand('session.capture', runEnv, jsonMode, async () => {
748
+ state.result = await runCommand('session.capture', runEnv, jsonMode, async () => {
723
749
  const store = await openStore(runEnv, { root });
724
750
  return sessionCaptureCommand.execute(store, cmdOpts);
725
751
  });
@@ -730,7 +756,7 @@ export async function run(argv, env) {
730
756
  .option('--review', "also read each session's open pull request and, when the store declares change_approval, its decision state from the forge")
731
757
  .action(async (cmdOpts, cmd) => {
732
758
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
733
- result = await runCommand('session.list', runEnv, jsonMode, async () => {
759
+ state.result = await runCommand('session.list', runEnv, jsonMode, async () => {
734
760
  const store = await openStore(runEnv, { root });
735
761
  return sessionListCommand.execute(runEnv, store, { review: Boolean(cmdOpts.review) });
736
762
  });
@@ -743,7 +769,7 @@ export async function run(argv, env) {
743
769
  .option('--diff', 'also print the unified diff of uncommitted work')
744
770
  .action(async (session, cmdOpts, cmd) => {
745
771
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
746
- result = await runCommand('session.status', runEnv, jsonMode, async () => {
772
+ state.result = await runCommand('session.status', runEnv, jsonMode, async () => {
747
773
  const store = await openStore(runEnv, { root });
748
774
  return sessionStatusCommand.execute(runEnv, store, { session, diff: Boolean(cmdOpts.diff) });
749
775
  });
@@ -759,7 +785,7 @@ export async function run(argv, env) {
759
785
  .option('--body-file <path>', 'read the pull request body from a file instead')
760
786
  .action(async (session, cmdOpts, cmd) => {
761
787
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
762
- result = await runCommand('session.submit', runEnv, jsonMode, async () => {
788
+ state.result = await runCommand('session.submit', runEnv, jsonMode, async () => {
763
789
  const store = await openStore(runEnv, { root });
764
790
  return sessionSubmitCommand.execute(runEnv, store, { session, ...cmdOpts });
765
791
  });
@@ -772,7 +798,7 @@ export async function run(argv, env) {
772
798
  .option('--abort', 'abort the rebase and restore the session as it was')
773
799
  .action(async (session, cmdOpts, cmd) => {
774
800
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
775
- result = await runCommand('session.rebase', runEnv, jsonMode, async () => {
801
+ state.result = await runCommand('session.rebase', runEnv, jsonMode, async () => {
776
802
  const store = await openStore(runEnv, { root });
777
803
  return sessionRebaseCommand.execute(runEnv, store, { session, continue: cmdOpts.continue, abort: cmdOpts.abort });
778
804
  });
@@ -785,11 +811,20 @@ export async function run(argv, env) {
785
811
  .option('--close-pull-request', 'also close the session\'s open pull request')
786
812
  .action(async (session, cmdOpts, cmd) => {
787
813
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
788
- result = await runCommand('session.discard', runEnv, jsonMode, async () => {
814
+ state.result = await runCommand('session.discard', runEnv, jsonMode, async () => {
789
815
  const store = await openStore(runEnv, { root });
790
816
  return sessionDiscardCommand.execute(runEnv, store, { session, force: cmdOpts.force, closePullRequest: cmdOpts.closePullRequest });
791
817
  });
792
818
  });
819
+ return { program, state };
820
+ }
821
+ export async function run(argv, env) {
822
+ if (isGlobalVersionRequest(argv)) {
823
+ const jsonMode = argv.includes('--json');
824
+ const runEnv = { ...env, noInput: env.noInput || argv.includes('--no-input') || jsonMode };
825
+ return runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv));
826
+ }
827
+ const { program, state } = buildProgram(env);
793
828
  try {
794
829
  await program.parseAsync(argv, { from: 'user' });
795
830
  }
@@ -827,6 +862,6 @@ export async function run(argv, env) {
827
862
  }
828
863
  throw err;
829
864
  }
830
- return result;
865
+ return state.result;
831
866
  }
832
867
  //# sourceMappingURL=run.js.map