@aragon-agent/cli 0.6.44 → 0.6.46

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 (255) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +120 -2
  3. package/dist/agent/controller.d.ts +69 -0
  4. package/dist/agent/controller.js +224 -11
  5. package/dist/agent/governance-view.d.ts +40 -0
  6. package/dist/agent/governance-view.js +40 -0
  7. package/dist/agent/governance-wiring.d.ts +162 -0
  8. package/dist/agent/governance-wiring.js +470 -0
  9. package/dist/agent/invocation-card.d.ts +77 -0
  10. package/dist/agent/invocation-card.js +169 -0
  11. package/dist/agent/plan-prompt.d.ts +7 -0
  12. package/dist/agent/plan-prompt.js +2 -1
  13. package/dist/agent/prompt-options.d.ts +6 -0
  14. package/dist/agent/queued-messages.d.ts +3 -0
  15. package/dist/agent/queued-messages.js +4 -1
  16. package/dist/agent/reducer.d.ts +38 -1
  17. package/dist/agent/reducer.js +57 -12
  18. package/dist/agent/system-prompt.d.ts +19 -0
  19. package/dist/agent/system-prompt.js +9 -1
  20. package/dist/cli.js +45 -1
  21. package/dist/commands/builtins.js +22 -4
  22. package/dist/commands/governance-command.d.ts +35 -0
  23. package/dist/commands/governance-command.js +304 -0
  24. package/dist/commands/governance-runs-table.d.ts +40 -0
  25. package/dist/commands/governance-runs-table.js +130 -0
  26. package/dist/commands/index-build.d.ts +8 -0
  27. package/dist/commands/index-build.js +11 -0
  28. package/dist/commands/registry.d.ts +35 -0
  29. package/dist/commands/registry.js +20 -7
  30. package/dist/commands/skills.js +36 -2
  31. package/dist/commands/subagent-command.js +3 -1
  32. package/dist/commands/team-command.d.ts +6 -0
  33. package/dist/commands/team-command.js +40 -3
  34. package/dist/config/app-paths.d.ts +10 -0
  35. package/dist/config/app-paths.js +12 -0
  36. package/dist/config/cli-commands.d.ts +18 -0
  37. package/dist/config/cli-commands.js +47 -1
  38. package/dist/config/env.d.ts +2 -1
  39. package/dist/config/env.js +10 -1
  40. package/dist/config/governance-config.d.ts +125 -0
  41. package/dist/config/governance-config.js +164 -0
  42. package/dist/config/governance-launch.d.ts +71 -0
  43. package/dist/config/governance-launch.js +58 -0
  44. package/dist/config/load.d.ts +15 -0
  45. package/dist/config/load.js +26 -1
  46. package/dist/config/model-profile-store.d.ts +4 -2
  47. package/dist/config/schema.d.ts +22 -0
  48. package/dist/config/schema.js +6 -0
  49. package/dist/config/store.js +14 -1
  50. package/dist/config/ui-state.d.ts +11 -0
  51. package/dist/config/ui-state.js +11 -0
  52. package/dist/diagnostics/doctor.js +20 -0
  53. package/dist/governance/card-normalize.d.ts +24 -0
  54. package/dist/governance/card-normalize.js +76 -0
  55. package/dist/governance/copy.d.ts +109 -0
  56. package/dist/governance/copy.js +223 -0
  57. package/dist/governance/engine/aftermath.d.ts +49 -0
  58. package/dist/governance/engine/aftermath.js +134 -0
  59. package/dist/governance/engine/artifact-persist.d.ts +35 -0
  60. package/dist/governance/engine/artifact-persist.js +86 -0
  61. package/dist/governance/engine/budget.d.ts +52 -0
  62. package/dist/governance/engine/budget.js +112 -0
  63. package/dist/governance/engine/cards.d.ts +18 -0
  64. package/dist/governance/engine/cards.js +186 -0
  65. package/dist/governance/engine/digest.d.ts +32 -0
  66. package/dist/governance/engine/digest.js +63 -0
  67. package/dist/governance/engine/engine-core.d.ts +219 -0
  68. package/dist/governance/engine/engine-core.js +562 -0
  69. package/dist/governance/engine/engine.d.ts +68 -0
  70. package/dist/governance/engine/engine.js +314 -0
  71. package/dist/governance/engine/estimate.d.ts +38 -0
  72. package/dist/governance/engine/estimate.js +46 -0
  73. package/dist/governance/engine/inspector.d.ts +16 -0
  74. package/dist/governance/engine/inspector.js +396 -0
  75. package/dist/governance/engine/integration.d.ts +35 -0
  76. package/dist/governance/engine/integration.js +220 -0
  77. package/dist/governance/engine/lifecycle.d.ts +29 -0
  78. package/dist/governance/engine/lifecycle.js +656 -0
  79. package/dist/governance/engine/pause.d.ts +56 -0
  80. package/dist/governance/engine/pause.js +107 -0
  81. package/dist/governance/engine/phase-members.d.ts +15 -0
  82. package/dist/governance/engine/phase-members.js +34 -0
  83. package/dist/governance/engine/phase-planner.d.ts +53 -0
  84. package/dist/governance/engine/phase-planner.js +282 -0
  85. package/dist/governance/engine/rebuild.d.ts +27 -0
  86. package/dist/governance/engine/rebuild.js +57 -0
  87. package/dist/governance/engine/report.d.ts +66 -0
  88. package/dist/governance/engine/report.js +220 -0
  89. package/dist/governance/engine/run-digest.d.ts +20 -0
  90. package/dist/governance/engine/run-digest.js +42 -0
  91. package/dist/governance/engine/spec-builder.d.ts +117 -0
  92. package/dist/governance/engine/spec-builder.js +321 -0
  93. package/dist/governance/engine/stage-runner.d.ts +22 -0
  94. package/dist/governance/engine/stage-runner.js +664 -0
  95. package/dist/governance/engine/start-input.d.ts +19 -0
  96. package/dist/governance/engine/start-input.js +111 -0
  97. package/dist/governance/engine/state-machine.d.ts +101 -0
  98. package/dist/governance/engine/state-machine.js +586 -0
  99. package/dist/governance/engine/submission-queries.d.ts +42 -0
  100. package/dist/governance/engine/submission-queries.js +97 -0
  101. package/dist/governance/engine/submission-render.d.ts +12 -0
  102. package/dist/governance/engine/submission-render.js +92 -0
  103. package/dist/governance/engine/submissions.d.ts +27 -0
  104. package/dist/governance/engine/submissions.js +455 -0
  105. package/dist/governance/engine/visibility.d.ts +104 -0
  106. package/dist/governance/engine/visibility.js +223 -0
  107. package/dist/governance/governed-dispatch.d.ts +19 -0
  108. package/dist/governance/governed-dispatch.js +17 -0
  109. package/dist/governance/limits.d.ts +107 -0
  110. package/dist/governance/limits.js +131 -0
  111. package/dist/governance/posture-transition.d.ts +38 -0
  112. package/dist/governance/posture-transition.js +44 -0
  113. package/dist/governance/posture.d.ts +35 -0
  114. package/dist/governance/posture.js +59 -0
  115. package/dist/governance/profiles.d.ts +48 -0
  116. package/dist/governance/profiles.js +140 -0
  117. package/dist/governance/prompts/orchestrator-block.d.ts +40 -0
  118. package/dist/governance/prompts/orchestrator-block.js +128 -0
  119. package/dist/governance/prompts/plan-addendum.d.ts +22 -0
  120. package/dist/governance/prompts/plan-addendum.js +60 -0
  121. package/dist/governance/prompts/refusals.d.ts +48 -0
  122. package/dist/governance/prompts/refusals.js +82 -0
  123. package/dist/governance/prompts/role-blocks.d.ts +40 -0
  124. package/dist/governance/prompts/role-blocks.js +255 -0
  125. package/dist/governance/report-reader.d.ts +31 -0
  126. package/dist/governance/report-reader.js +57 -0
  127. package/dist/governance/roles.d.ts +83 -0
  128. package/dist/governance/roles.js +142 -0
  129. package/dist/governance/rules/claims.d.ts +83 -0
  130. package/dist/governance/rules/claims.js +250 -0
  131. package/dist/governance/rules/elimination.d.ts +66 -0
  132. package/dist/governance/rules/elimination.js +105 -0
  133. package/dist/governance/rules/events-table.d.ts +46 -0
  134. package/dist/governance/rules/events-table.js +94 -0
  135. package/dist/governance/rules/failure-analysis.d.ts +28 -0
  136. package/dist/governance/rules/failure-analysis.js +93 -0
  137. package/dist/governance/rules/ledger-replay.d.ts +53 -0
  138. package/dist/governance/rules/ledger-replay.js +53 -0
  139. package/dist/governance/rules/ledger-state.d.ts +85 -0
  140. package/dist/governance/rules/ledger-state.js +175 -0
  141. package/dist/governance/rules/ledger.d.ts +228 -0
  142. package/dist/governance/rules/ledger.js +560 -0
  143. package/dist/governance/rules/rca.d.ts +68 -0
  144. package/dist/governance/rules/rca.js +220 -0
  145. package/dist/governance/rules/settlement.d.ts +129 -0
  146. package/dist/governance/rules/settlement.js +363 -0
  147. package/dist/governance/rules/suspicion.d.ts +66 -0
  148. package/dist/governance/rules/suspicion.js +169 -0
  149. package/dist/governance/store/artifacts.d.ts +81 -0
  150. package/dist/governance/store/artifacts.js +173 -0
  151. package/dist/governance/store/atomic.d.ts +79 -0
  152. package/dist/governance/store/atomic.js +119 -0
  153. package/dist/governance/store/events-log.d.ts +35 -0
  154. package/dist/governance/store/events-log.js +86 -0
  155. package/dist/governance/store/run-lock.d.ts +51 -0
  156. package/dist/governance/store/run-lock.js +122 -0
  157. package/dist/governance/store/run-store.d.ts +229 -0
  158. package/dist/governance/store/run-store.js +644 -0
  159. package/dist/governance/store/scoreboard-export.d.ts +53 -0
  160. package/dist/governance/store/scoreboard-export.js +65 -0
  161. package/dist/governance/tools/child-tools.d.ts +31 -0
  162. package/dist/governance/tools/child-tools.js +65 -0
  163. package/dist/governance/tools/guard.d.ts +71 -0
  164. package/dist/governance/tools/guard.js +194 -0
  165. package/dist/governance/tools/inspector-tools.d.ts +63 -0
  166. package/dist/governance/tools/inspector-tools.js +424 -0
  167. package/dist/governance/tools/lead-tools.d.ts +42 -0
  168. package/dist/governance/tools/lead-tools.js +226 -0
  169. package/dist/governance/tools/normalize-util.d.ts +101 -0
  170. package/dist/governance/tools/normalize-util.js +230 -0
  171. package/dist/governance/tools/scan-incomplete.d.ts +79 -0
  172. package/dist/governance/tools/scan-incomplete.js +486 -0
  173. package/dist/governance/tools/shared-tools.d.ts +44 -0
  174. package/dist/governance/tools/shared-tools.js +125 -0
  175. package/dist/governance/tools/submit-normalizers.d.ts +28 -0
  176. package/dist/governance/tools/submit-normalizers.js +474 -0
  177. package/dist/governance/tools/submit-tools.d.ts +26 -0
  178. package/dist/governance/tools/submit-tools.js +171 -0
  179. package/dist/governance/types.d.ts +661 -0
  180. package/dist/governance/types.js +27 -0
  181. package/dist/session/persist.js +10 -0
  182. package/dist/session/validate-session.js +36 -3
  183. package/dist/team/forced-mode.d.ts +19 -0
  184. package/dist/team/forced-mode.js +42 -20
  185. package/dist/team/runtime.d.ts +8 -0
  186. package/dist/team/runtime.js +9 -0
  187. package/dist/team/subagent.d.ts +23 -0
  188. package/dist/team/subagent.js +14 -3
  189. package/dist/team/types.d.ts +6 -0
  190. package/dist/tools/index.d.ts +30 -7
  191. package/dist/tools/index.js +14 -0
  192. package/dist/tools/plan-tools.d.ts +14 -2
  193. package/dist/tools/plan-tools.js +5 -2
  194. package/dist/ui/App.js +170 -31
  195. package/dist/ui/BottomStatusRow.js +1 -1
  196. package/dist/ui/Composer.d.ts +7 -1
  197. package/dist/ui/Composer.js +9 -6
  198. package/dist/ui/GovernancePanel.d.ts +50 -0
  199. package/dist/ui/GovernancePanel.js +77 -0
  200. package/dist/ui/GovernanceRun.d.ts +18 -0
  201. package/dist/ui/GovernanceRun.js +11 -0
  202. package/dist/ui/StatusBar.d.ts +15 -2
  203. package/dist/ui/StatusBar.js +10 -4
  204. package/dist/ui/Transcript.js +7 -1
  205. package/dist/ui/entries/GovernanceCard.d.ts +30 -0
  206. package/dist/ui/entries/GovernanceCard.js +32 -0
  207. package/dist/ui/entries/InvocationCard.d.ts +20 -0
  208. package/dist/ui/entries/InvocationCard.js +32 -0
  209. package/dist/ui/governance-copy.d.ts +69 -0
  210. package/dist/ui/governance-copy.js +104 -0
  211. package/dist/ui/governance-status.d.ts +145 -0
  212. package/dist/ui/governance-status.js +326 -0
  213. package/dist/ui/interaction-copy.d.ts +4 -0
  214. package/dist/ui/interaction-copy.js +5 -0
  215. package/dist/ui/interaction-hints.d.ts +17 -0
  216. package/dist/ui/interaction-hints.js +14 -2
  217. package/dist/ui/layout/governance-board.d.ts +121 -0
  218. package/dist/ui/layout/governance-board.js +382 -0
  219. package/dist/ui/layout/governance-card.d.ts +53 -0
  220. package/dist/ui/layout/governance-card.js +134 -0
  221. package/dist/ui/layout/governance-chip.d.ts +38 -0
  222. package/dist/ui/layout/governance-chip.js +64 -0
  223. package/dist/ui/layout/governance-panel.d.ts +85 -0
  224. package/dist/ui/layout/governance-panel.js +358 -0
  225. package/dist/ui/layout/governance-roster.d.ts +65 -0
  226. package/dist/ui/layout/governance-roster.js +275 -0
  227. package/dist/ui/layout/invocation-card.d.ts +41 -0
  228. package/dist/ui/layout/invocation-card.js +91 -0
  229. package/dist/ui/layout/status-detail-layout.js +3 -3
  230. package/dist/ui/layout/status-layout.d.ts +5 -2
  231. package/dist/ui/layout/status-layout.js +10 -6
  232. package/dist/ui/layout/virtual-window.js +22 -1
  233. package/dist/ui/overlays/GovernanceBoardOverlay.d.ts +41 -0
  234. package/dist/ui/overlays/GovernanceBoardOverlay.js +76 -0
  235. package/dist/ui/overlays/GovernanceSettingsPage.d.ts +48 -0
  236. package/dist/ui/overlays/GovernanceSettingsPage.js +93 -0
  237. package/dist/ui/overlays/HelpOverlay.js +4 -3
  238. package/dist/ui/overlays/QuestionOverlay.d.ts +9 -1
  239. package/dist/ui/overlays/QuestionOverlay.js +4 -2
  240. package/dist/ui/overlays/SettingsScreen.d.ts +7 -0
  241. package/dist/ui/overlays/SettingsScreen.js +21 -1
  242. package/dist/ui/overlays/governance-settings.d.ts +79 -0
  243. package/dist/ui/overlays/governance-settings.js +140 -0
  244. package/dist/ui/overlays/model-profile-state.d.ts +6 -1
  245. package/dist/ui/overlays/model-profile-state.js +10 -0
  246. package/dist/ui/palettes.d.ts +17 -0
  247. package/dist/ui/palettes.js +9 -0
  248. package/dist/ui/scrollback/live-preview.js +2 -0
  249. package/dist/ui/scrollback/settled-boundary.js +3 -0
  250. package/dist/ui/shortcuts.js +2 -2
  251. package/dist/ui/theme.d.ts +7 -0
  252. package/dist/ui/theme.js +1 -0
  253. package/dist/ui/transcript-text.js +13 -1
  254. package/dist/ui/use-wheel-routing.js +3 -1
  255. package/package.json +2 -2
@@ -15,7 +15,9 @@ import { mergePendingEntries } from '../agent/queued-messages.js';
15
15
  import { TODO_FOLLOW_LIMITS } from '../todo/limits.js';
16
16
  import { buildContinuationMessage } from '../todo/follow-through.js';
17
17
  import { planIsResolved } from '../todo/acceptance.js';
18
- import { MODE_LABEL, nextMode } from '../agent/agent-mode.js';
18
+ import { nextMode } from '../agent/agent-mode.js';
19
+ import { POSTURE_LABEL } from '../governance/posture.js';
20
+ import { registerGovernanceCommand } from './governance-command.js';
19
21
  import { loadSession, resolveSessionPath, saveSession } from '../session/persist.js';
20
22
  import { applyRestoredSession } from '../session/startup-session.js';
21
23
  import { runSessionCommand } from './session-command.js';
@@ -353,12 +355,13 @@ const COMMANDS = [
353
355
  run: (ctx) => {
354
356
  const arg = ctx.args.trim().toLowerCase();
355
357
  if (arg === 'status') {
356
- const s = ctx.controller.getPlanStatus();
357
- const pending = s.pending ? ` (pending ${MODE_LABEL[s.pending]} after this run)` : '';
358
+ // The full posture (GOVERN / PLAN+GOVERN included), not just the gate mode.
359
+ const s = ctx.controller.getPostureState();
360
+ const pending = s.pending ? ` (pending ${POSTURE_LABEL[s.pending]} after this run)` : '';
358
361
  // NO ROUND COUNT. The old line ended with `Ask rounds used: 3/4.`, which
359
362
  // told the user their agent was rationing questions - a limit that no
360
363
  // longer exists. Nothing replaced it: "0 of unlimited" is noise.
361
- ctx.notify('info', `Mode: ${MODE_LABEL[s.effective]}${pending}.`);
364
+ ctx.notify('info', `Mode: ${POSTURE_LABEL[s.effective]}${pending}.`);
362
365
  return;
363
366
  }
364
367
  if (arg.length > 0 && arg !== 'on' && arg !== 'off') {
@@ -618,6 +621,8 @@ const COMMANDS = [
618
621
  },
619
622
  {
620
623
  name: 'todo',
624
+ // Same verb parse as `run` below, so the echo is suppressed exactly when a card can appear (I-8).
625
+ rendersInvocationCard: (args) => args.trim().toLowerCase().split(/\s+/)[0] === 'continue',
621
626
  description: 'Todo planning: status | on | off | panel on|off | follow <mode> | ' +
622
627
  'acceptance [on|off|reset] | clear | continue',
623
628
  /**
@@ -779,6 +784,16 @@ const COMMANDS = [
779
784
  // the more verbose of the two forms (AC-17).
780
785
  ctx.submit(buildContinuationMessage(snapshot), {
781
786
  userInitiated: false, todoPolicy: 'continue',
787
+ // The transcript shows a card instead of the canned paragraph; the payload above
788
+ // is unchanged (tui-invocation-cards I-1).
789
+ ...(ctx.invocationCards === false ? {} : {
790
+ invocation: {
791
+ variant: 'todo',
792
+ name: 'continue',
793
+ commandLine: '/todo continue',
794
+ facts: [`${Math.max(0, snapshot.total - snapshot.doneCount)} of ${snapshot.total} steps left`],
795
+ },
796
+ }),
782
797
  });
783
798
  return;
784
799
  }
@@ -1346,6 +1361,9 @@ export function registerBuiltinCommands(registry) {
1346
1361
  // now live in the settings screen, and this command is the ACT: arm forced mode
1347
1362
  // and start work. Unconditional, for the reason `/subagent` above records.
1348
1363
  registerTeamCommand(registry);
1364
+ // `/gov` (governance-mode 11.3). Unconditional, like `/team` and for the same reason: the
1365
+ // session where governance cannot run is exactly where a user asks the command why.
1366
+ registerGovernanceCommand(registry);
1349
1367
  // The keyboard drawer (`Ctrl+G` / `/keys`) and the task label (`/task`). Two
1350
1368
  // registrations, no new mechanism: `/keys` sets the panel's pre-filter and opens
1351
1369
  // the same overlay `Ctrl+G` opens, and `/task` reports what the header cell says.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `/gov`: enter, leave and inspect governance mode (governance-mode 11.3).
3
+ *
4
+ * ASCII ONLY: `src/commands/**` is inside `glyphs.test.ts::inScope`.
5
+ *
6
+ * THE GUARD ORDER IS A CONTRACT, and it is the order `/team` uses (and for the same
7
+ * reasons), not an alphabetical one:
8
+ *
9
+ * status / help / runs / report / board
10
+ * - questions, answerable in ANY session, including the
11
+ * ones where governance cannot run (that is where users
12
+ * ask why). `report` only READS files already on disk.
13
+ * off - leaving is always possible, even mid-stage.
14
+ * available? - `on` / `plan` / `resume` / `pause` name the exact reason.
15
+ * not busy - half a team dispatch under one posture and half under
16
+ * another leaves a result nothing can explain.
17
+ * act - switch posture / submit the resume turn / abort.
18
+ *
19
+ * `pause` sits BETWEEN `available?` and `not busy` and never takes the busy refusal: a stage
20
+ * running is exactly when someone wants to pause, and the request is cooperative (nothing is
21
+ * stopped), unlike `abort`.
22
+ *
23
+ * EVERY POSTURE CHANGE BELOW IS FOLLOWED BY A NOTICE OR TOAST IN THE SAME BRANCH: a
24
+ * posture change produces no `AgentEvent`, so without one the badge would wait for an
25
+ * unrelated state change to repaint (the lesson of team-command-forced-dispatch P1-6).
26
+ */
27
+ import type { CommandContext, CommandRegistry } from './registry.js';
28
+ /** The fixed English turn that makes the orchestrator call `gov_run resume` (11.3). */
29
+ export declare function resumeTurnText(runId: string): string;
30
+ /** `500`, `500k`, `2m`, `off`/`0`. NaN when unparseable. */
31
+ export declare function parseBudgetTokens(raw: string): number;
32
+ /** The command body; `registerGovernanceCommand` is the only registration site. */
33
+ export declare function runGovernanceCommand(ctx: CommandContext): Promise<void>;
34
+ /** Registered from `builtins.ts` with one line, next to every other subsystem. */
35
+ export declare function registerGovernanceCommand(registry: CommandRegistry): void;
@@ -0,0 +1,304 @@
1
+ /**
2
+ * `/gov`: enter, leave and inspect governance mode (governance-mode 11.3).
3
+ *
4
+ * ASCII ONLY: `src/commands/**` is inside `glyphs.test.ts::inScope`.
5
+ *
6
+ * THE GUARD ORDER IS A CONTRACT, and it is the order `/team` uses (and for the same
7
+ * reasons), not an alphabetical one:
8
+ *
9
+ * status / help / runs / report / board
10
+ * - questions, answerable in ANY session, including the
11
+ * ones where governance cannot run (that is where users
12
+ * ask why). `report` only READS files already on disk.
13
+ * off - leaving is always possible, even mid-stage.
14
+ * available? - `on` / `plan` / `resume` / `pause` name the exact reason.
15
+ * not busy - half a team dispatch under one posture and half under
16
+ * another leaves a result nothing can explain.
17
+ * act - switch posture / submit the resume turn / abort.
18
+ *
19
+ * `pause` sits BETWEEN `available?` and `not busy` and never takes the busy refusal: a stage
20
+ * running is exactly when someone wants to pause, and the request is cooperative (nothing is
21
+ * stopped), unlike `abort`.
22
+ *
23
+ * EVERY POSTURE CHANGE BELOW IS FOLLOWED BY A NOTICE OR TOAST IN THE SAME BRANCH: a
24
+ * posture change produces no `AgentEvent`, so without one the badge would wait for an
25
+ * unrelated state change to repaint (the lesson of team-command-forced-dispatch P1-6).
26
+ */
27
+ import { GOV_ABORTED_NOTICE, GOV_BUDGET_OFF_NOTICE, GOV_BUDGET_USAGE, GOV_COMMAND_SUMMARY, GOV_NO_RUN_NOTICE, GOV_NO_RUNS_NOTICE, GOV_NO_STAGE_NOTICE, GOV_OFF_NOTICE, GOV_OFF_WITH_RUN_NOTICE, GOV_PAUSE_ALREADY_NOTICE, GOV_PAUSE_CANCELLED_TOAST, GOV_PAUSE_ESCALATED_NOTICE, GOV_PAUSE_NONE_PENDING_NOTICE, GOV_PAUSE_NO_RUN_NOTICE, GOV_REPORT_NO_RUN_NOTICE, GOV_STAGE_BUSY_NOTICE, buildGovHelpText, formatGovStatus, govBudgetSetNotice, govPausePendingToast, govPausedNowToast, govReportBadIdNotice, govReportMissingNotice, govUnavailableNotice, posturePendingToast, postureAppliedToast, stageRunningToast, RESTART_REQUIRED_TEXT, } from '../governance/copy.js';
28
+ import { RUN_ID_PATTERN } from '../governance/limits.js';
29
+ import { isGovernancePosture } from '../governance/posture.js';
30
+ import { formatReportNotice, formatRunsTable } from './governance-runs-table.js';
31
+ const USAGE = 'Usage: /gov [status|on|plan|off|board|runs|report [runId]|resume [runId]|pause [cancel]' +
32
+ '|abort|budget <n|off>|help]';
33
+ /** The fixed English turn that makes the orchestrator call `gov_run resume` (11.3). */
34
+ export function resumeTurnText(runId) {
35
+ return `Resume governance run ${runId}.`;
36
+ }
37
+ function unavailableText(ctx) {
38
+ const availability = ctx.controller.isGovernanceAvailable();
39
+ if (availability.ok)
40
+ return null;
41
+ return availability.reason === 'restart_required'
42
+ ? RESTART_REQUIRED_TEXT
43
+ : govUnavailableNotice(availability.reason);
44
+ }
45
+ function reportStatus(ctx) {
46
+ const snapshot = ctx.controller.getGovernanceSnapshot();
47
+ ctx.notify('info', formatGovStatus({
48
+ posture: ctx.controller.getPosture(),
49
+ availability: ctx.controller.isGovernanceAvailable(),
50
+ run: snapshot
51
+ ? {
52
+ runId: snapshot.runId,
53
+ phase: snapshot.phase,
54
+ phaseCount: snapshot.phaseCount,
55
+ stage: snapshot.stage,
56
+ status: snapshot.status,
57
+ health: snapshot.health,
58
+ pauseRequested: snapshot.pauseRequested === true,
59
+ }
60
+ : null,
61
+ dispatchPlan: snapshot ? ctx.controller.getGovernanceDispatchPlan() : null,
62
+ }));
63
+ }
64
+ async function reportRuns(ctx) {
65
+ const runs = await ctx.controller.listGovernanceRuns();
66
+ if (runs.length === 0) {
67
+ ctx.notify('info', GOV_NO_RUNS_NOTICE);
68
+ return;
69
+ }
70
+ // Two columns less than the terminal: the transcript indents notices.
71
+ ctx.notify('info', formatRunsTable(runs, (process.stdout.columns ?? 80) - 2));
72
+ }
73
+ /** `/gov report [runId]`: a stored report as one transcript notice (read-only). */
74
+ async function report(ctx) {
75
+ const raw = ctx.args.trim().split(/\s+/)[1] ?? '';
76
+ // Checked HERE as well as in the reader: a malformed id never reaches the controller,
77
+ // let alone the file system (it would become a path segment).
78
+ if (raw !== '' && !RUN_ID_PATTERN.test(raw)) {
79
+ ctx.notify('warn', govReportBadIdNotice(raw));
80
+ return;
81
+ }
82
+ const result = await ctx.controller.readGovernanceReport(raw === '' ? undefined : raw);
83
+ switch (result.kind) {
84
+ case 'ok':
85
+ ctx.notify('info', formatReportNotice(result));
86
+ return;
87
+ case 'missing':
88
+ ctx.notify('info', govReportMissingNotice(result.runId));
89
+ return;
90
+ case 'bad_id':
91
+ ctx.notify('warn', govReportBadIdNotice(raw));
92
+ return;
93
+ case 'no_run':
94
+ ctx.notify('info', GOV_REPORT_NO_RUN_NOTICE);
95
+ }
96
+ }
97
+ /** `/gov pause [cancel]`: stop at the next clean stage boundary; nothing is killed. */
98
+ async function pause(ctx) {
99
+ const unavailable = unavailableText(ctx);
100
+ if (unavailable !== null) {
101
+ ctx.notify('warn', unavailable);
102
+ return;
103
+ }
104
+ const arg = (ctx.args.trim().split(/\s+/)[1] ?? '').toLowerCase();
105
+ if (arg === 'cancel') {
106
+ if (ctx.controller.cancelGovernancePause())
107
+ ctx.toast('info', GOV_PAUSE_CANCELLED_TOAST);
108
+ else
109
+ ctx.notify('info', GOV_PAUSE_NONE_PENDING_NOTICE);
110
+ return;
111
+ }
112
+ if (arg !== '') {
113
+ ctx.notify('warn', `Unknown argument "${arg}". Usage: /gov pause [cancel]`);
114
+ return;
115
+ }
116
+ const outcome = await ctx.controller.requestGovernancePause();
117
+ const snapshot = ctx.controller.getGovernanceSnapshot();
118
+ switch (outcome) {
119
+ case 'pending':
120
+ ctx.toast('info', govPausePendingToast(snapshot?.stage ?? null));
121
+ return;
122
+ case 'paused_now':
123
+ ctx.toast('info', govPausedNowToast(snapshot?.runId ?? ''));
124
+ return;
125
+ case 'already_paused':
126
+ ctx.notify('info', GOV_PAUSE_ALREADY_NOTICE);
127
+ return;
128
+ case 'escalated':
129
+ ctx.notify('info', GOV_PAUSE_ESCALATED_NOTICE);
130
+ return;
131
+ case 'no_run':
132
+ ctx.notify('info', GOV_PAUSE_NO_RUN_NOTICE);
133
+ }
134
+ }
135
+ /** Switch posture through the App's single write path and report what was ADOPTED. */
136
+ function switchPosture(ctx, target) {
137
+ if (ctx.applyPosture === undefined) {
138
+ ctx.notify('warn', 'Governance is unavailable here: this surface cannot change posture.');
139
+ return null;
140
+ }
141
+ const applied = ctx.applyPosture(target);
142
+ if (applied.pending !== null) {
143
+ ctx.toast('info', ctx.controller.isGovernanceStageRunning()
144
+ ? stageRunningToast(applied.pending)
145
+ : posturePendingToast(applied.pending));
146
+ }
147
+ else {
148
+ ctx.toast('info', postureAppliedToast(applied.effective));
149
+ }
150
+ return applied;
151
+ }
152
+ function leave(ctx) {
153
+ const wasGoverned = isGovernancePosture(ctx.controller.getPosture());
154
+ const snapshot = ctx.controller.getGovernanceSnapshot();
155
+ if (!wasGoverned && ctx.controller.getPostureState().pending === null) {
156
+ ctx.notify('info', GOV_OFF_NOTICE);
157
+ return;
158
+ }
159
+ const applied = switchPosture(ctx, 'build');
160
+ // A deferred change (a stage is running) already said so in its toast.
161
+ if (applied === null || applied.pending !== null)
162
+ return;
163
+ // Leaving never kills an in-flight stage; the run is left resumable.
164
+ const hasRun = snapshot !== null && snapshot.status !== 'closed' && snapshot.status !== 'abandoned';
165
+ ctx.notify('info', hasRun ? GOV_OFF_WITH_RUN_NOTICE : GOV_OFF_NOTICE);
166
+ }
167
+ function enter(ctx, target) {
168
+ const unavailable = unavailableText(ctx);
169
+ if (unavailable !== null) {
170
+ ctx.notify('warn', unavailable);
171
+ return;
172
+ }
173
+ if (ctx.controller.isTeamBusy()) {
174
+ ctx.notify('warn', ctx.controller.isGovernanceStageRunning()
175
+ ? GOV_STAGE_BUSY_NOTICE
176
+ : 'Cannot change posture while a team dispatch is running.');
177
+ return;
178
+ }
179
+ switchPosture(ctx, target);
180
+ }
181
+ async function resume(ctx) {
182
+ const unavailable = unavailableText(ctx);
183
+ if (unavailable !== null) {
184
+ ctx.notify('warn', unavailable);
185
+ return;
186
+ }
187
+ if (ctx.controller.isTeamBusy()) {
188
+ ctx.notify('warn', GOV_STAGE_BUSY_NOTICE);
189
+ return;
190
+ }
191
+ const requested = ctx.args.trim().split(/\s+/)[1] ?? '';
192
+ const runId = await ctx.controller.findResumableGovernanceRun(requested);
193
+ if (runId === null) {
194
+ ctx.notify('info', GOV_NO_RUN_NOTICE);
195
+ return;
196
+ }
197
+ if (ctx.controller.getPosture() !== 'govern' && switchPosture(ctx, 'govern') === null)
198
+ return;
199
+ // `userInitiated: false` keeps the canned turn out of the prompt history, exactly like
200
+ // `/todo continue` (todo-plan-followthrough C-12).
201
+ ctx.submit(resumeTurnText(runId), {
202
+ userInitiated: false,
203
+ ...(ctx.invocationCards === false ? {} : {
204
+ invocation: {
205
+ variant: 'govern',
206
+ name: 'resume',
207
+ commandLine: requested === '' ? '/gov resume' : `/gov resume ${requested}`,
208
+ facts: [`run ${runId.slice(0, 8)}`],
209
+ },
210
+ }),
211
+ });
212
+ }
213
+ function abort(ctx) {
214
+ if (!ctx.controller.isGovernanceStageRunning()) {
215
+ ctx.notify('info', GOV_NO_STAGE_NOTICE);
216
+ return;
217
+ }
218
+ ctx.controller.abortGovernanceStage();
219
+ ctx.notify('info', GOV_ABORTED_NOTICE);
220
+ }
221
+ /** `500`, `500k`, `2m`, `off`/`0`. NaN when unparseable. */
222
+ export function parseBudgetTokens(raw) {
223
+ const text = raw.trim().toLowerCase();
224
+ if (text === 'off' || text === '0')
225
+ return 0;
226
+ const match = /^(\d+(?:\.\d+)?)([km]?)$/.exec(text);
227
+ if (!match)
228
+ return Number.NaN;
229
+ const scale = match[2] === 'm' ? 1_000_000 : match[2] === 'k' ? 1_000 : 1;
230
+ return Math.floor(Number(match[1]) * scale);
231
+ }
232
+ function setBudget(ctx) {
233
+ const raw = ctx.args.trim().split(/\s+/)[1];
234
+ if (raw === undefined) {
235
+ ctx.notify('info', GOV_BUDGET_USAGE);
236
+ return;
237
+ }
238
+ const tokens = parseBudgetTokens(raw);
239
+ if (!Number.isFinite(tokens) || tokens < 0) {
240
+ ctx.notify('warn', GOV_BUDGET_USAGE);
241
+ return;
242
+ }
243
+ // BOTH CALLS, AND NEITHER MAY BE DROPPED (the `/fast` rule): the setter makes the running
244
+ // session honour it and re-renders the prompt; persisting alone changes nothing until
245
+ // relaunch, and the setter alone is forgotten by morning.
246
+ const adopted = ctx.controller.setGovernanceConfig({ budgetTokens: tokens });
247
+ ctx.persistConfig({ governance: adopted });
248
+ ctx.notify('info', adopted.budgetTokens === 0 ? GOV_BUDGET_OFF_NOTICE : govBudgetSetNotice(adopted.budgetTokens));
249
+ }
250
+ /** The command body; `registerGovernanceCommand` is the only registration site. */
251
+ export async function runGovernanceCommand(ctx) {
252
+ const verb = (ctx.args.trim().split(/\s+/)[0] ?? '').toLowerCase();
253
+ switch (verb) {
254
+ case '':
255
+ case 'status':
256
+ reportStatus(ctx);
257
+ return;
258
+ case 'help':
259
+ ctx.notify('info', buildGovHelpText(ctx.controller.getGovernanceConfig().minAskRounds));
260
+ return;
261
+ case 'runs':
262
+ await reportRuns(ctx);
263
+ return;
264
+ case 'report':
265
+ await report(ctx);
266
+ return;
267
+ case 'board':
268
+ ctx.setOverlay('governance');
269
+ return;
270
+ case 'off':
271
+ leave(ctx);
272
+ return;
273
+ case 'on':
274
+ enter(ctx, 'govern');
275
+ return;
276
+ case 'plan':
277
+ enter(ctx, 'plan_govern');
278
+ return;
279
+ case 'resume':
280
+ await resume(ctx);
281
+ return;
282
+ case 'pause':
283
+ await pause(ctx);
284
+ return;
285
+ case 'abort':
286
+ abort(ctx);
287
+ return;
288
+ case 'budget':
289
+ setBudget(ctx);
290
+ return;
291
+ default:
292
+ ctx.notify('warn', `Unknown argument "${verb}". ${USAGE}`);
293
+ }
294
+ }
295
+ /** Registered from `builtins.ts` with one line, next to every other subsystem. */
296
+ export function registerGovernanceCommand(registry) {
297
+ registry.register({
298
+ name: 'gov',
299
+ // Same verb parse as `runGovernanceCommand`, so the echo is suppressed exactly when a card can appear (I-8).
300
+ rendersInvocationCard: (args) => (args.trim().split(/\s+/)[0] ?? '').toLowerCase() === 'resume',
301
+ description: GOV_COMMAND_SUMMARY,
302
+ run: (ctx) => runGovernanceCommand(ctx),
303
+ });
304
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The `/gov runs` table and the `/gov report` notice text (governance-mode-v1-1 7.1, 7.2).
3
+ *
4
+ * ASCII ONLY: `src/commands/**` is inside `glyphs.test.ts::inScope`. Everything this module
5
+ * ADDS is ASCII (column rules, the `...` cut mark, `n/a`); the only non-ASCII that can pass
6
+ * through is the user's own goal text, which is measured and cut in terminal CELLS
7
+ * (`ui/layout/cells.ts`), never in code units, so a CJK goal cannot push a row past the edge.
8
+ *
9
+ * PURE. The command hands in rows and a width; nothing here reads the terminal or the clock
10
+ * except through arguments, which is what lets the width matrix be tested.
11
+ *
12
+ * THE COLUMNS DEGRADE BY WIDTH, in the order of how much each one is missed: first
13
+ * HEALTH and COST go (they are the cheapest to look up again in `/gov board`), then UPDATED
14
+ * and TOKENS, and at the narrowest only `RUN STATUS PHASE GOAL` remain. The goal gets
15
+ * whatever is left and is cut with `...`.
16
+ */
17
+ import type { GovernanceRunRow } from '../agent/governance-wiring.js';
18
+ interface Column {
19
+ key: 'run' | 'status' | 'phase' | 'health' | 'tokens' | 'cost' | 'updated' | 'updatedShort';
20
+ title: string;
21
+ width: number;
22
+ }
23
+ /** `184k`, `2.1M`, `950`. */
24
+ export declare function formatTokensCompact(tokens: number): string;
25
+ /** `$1.42`; unknown pricing is `n/a`, never `$0.00` (v1 8.5 / C-11). */
26
+ export declare function formatCostCell(costUsd: number | null): string;
27
+ /** `2026-10-24 14:02` in local time. */
28
+ export declare function formatStamp(ms: number): string;
29
+ /** One row of the table, already cut to `cols` cells. */
30
+ export declare function formatRunRow(row: GovernanceRunRow, keys: ReadonlyArray<Column['key']>, cols: number): string;
31
+ /** The whole `/gov runs` notice for `cols` terminal columns. */
32
+ export declare function formatRunsTable(runs: readonly GovernanceRunRow[], cols: number): string;
33
+ /** The transcript text for a found report: header, body capped by lines, full path. */
34
+ export declare function formatReportNotice(input: {
35
+ runId: string;
36
+ file: string;
37
+ text: string;
38
+ path: string;
39
+ }): string;
40
+ export {};
@@ -0,0 +1,130 @@
1
+ /**
2
+ * The `/gov runs` table and the `/gov report` notice text (governance-mode-v1-1 7.1, 7.2).
3
+ *
4
+ * ASCII ONLY: `src/commands/**` is inside `glyphs.test.ts::inScope`. Everything this module
5
+ * ADDS is ASCII (column rules, the `...` cut mark, `n/a`); the only non-ASCII that can pass
6
+ * through is the user's own goal text, which is measured and cut in terminal CELLS
7
+ * (`ui/layout/cells.ts`), never in code units, so a CJK goal cannot push a row past the edge.
8
+ *
9
+ * PURE. The command hands in rows and a width; nothing here reads the terminal or the clock
10
+ * except through arguments, which is what lets the width matrix be tested.
11
+ *
12
+ * THE COLUMNS DEGRADE BY WIDTH, in the order of how much each one is missed: first
13
+ * HEALTH and COST go (they are the cheapest to look up again in `/gov board`), then UPDATED
14
+ * and TOKENS, and at the narrowest only `RUN STATUS PHASE GOAL` remain. The goal gets
15
+ * whatever is left and is cut with `...`.
16
+ */
17
+ import { GOV_REPORT_MAX_LINES } from '../governance/copy.js';
18
+ import { cellWidth, fitCells, padCells } from '../ui/layout/cells.js';
19
+ const UNFINISHED = new Set(['executing', 'paused', 'escalated']);
20
+ const MIN_GOAL_CELLS = 8;
21
+ const GAP = ' ';
22
+ const COLUMNS = {
23
+ run: { key: 'run', title: 'RUN', width: 13 },
24
+ status: { key: 'status', title: 'STATUS', width: 9 },
25
+ phase: { key: 'phase', title: 'PHASE', width: 5 },
26
+ health: { key: 'health', title: 'HEALTH', width: 6 },
27
+ tokens: { key: 'tokens', title: 'TOKENS', width: 7 },
28
+ cost: { key: 'cost', title: 'COST', width: 8 },
29
+ updated: { key: 'updated', title: 'UPDATED', width: 16 },
30
+ // The same column without the year, for widths where the goal text is worth more.
31
+ updatedShort: { key: 'updatedShort', title: 'UPDATED', width: 11 },
32
+ };
33
+ /** Column sets from widest to narrowest; the first whose goal still gets room wins. */
34
+ const TIERS = [
35
+ ['run', 'status', 'phase', 'health', 'tokens', 'cost', 'updated'],
36
+ ['run', 'status', 'phase', 'tokens', 'updatedShort'],
37
+ ['run', 'status', 'phase', 'tokens'],
38
+ ['run', 'status', 'phase'],
39
+ ];
40
+ /** `184k`, `2.1M`, `950`. */
41
+ export function formatTokensCompact(tokens) {
42
+ if (tokens >= 1_000_000)
43
+ return `${(tokens / 1_000_000).toFixed(1)}M`;
44
+ if (tokens >= 10_000)
45
+ return `${Math.round(tokens / 1_000)}k`;
46
+ if (tokens >= 1_000)
47
+ return `${(tokens / 1_000).toFixed(1)}k`;
48
+ return String(Math.max(0, Math.round(tokens)));
49
+ }
50
+ /** `$1.42`; unknown pricing is `n/a`, never `$0.00` (v1 8.5 / C-11). */
51
+ export function formatCostCell(costUsd) {
52
+ if (costUsd === null)
53
+ return 'n/a';
54
+ return costUsd < 0.01 && costUsd > 0 ? '<$0.01' : `$${costUsd.toFixed(2)}`;
55
+ }
56
+ function two(n) {
57
+ return String(n).padStart(2, '0');
58
+ }
59
+ /** `2026-10-24 14:02` in local time. */
60
+ export function formatStamp(ms) {
61
+ const d = new Date(ms);
62
+ if (Number.isNaN(d.getTime()))
63
+ return '-';
64
+ const date = `${d.getFullYear()}-${two(d.getMonth() + 1)}-${two(d.getDate())}`;
65
+ return `${date} ${two(d.getHours())}:${two(d.getMinutes())}`;
66
+ }
67
+ function cellFor(key, row, digest) {
68
+ switch (key) {
69
+ case 'run':
70
+ return row.runId;
71
+ case 'status':
72
+ return row.status;
73
+ case 'phase':
74
+ return digest === undefined ? '-' : `${digest.phase}/${digest.phaseCount}`;
75
+ case 'health':
76
+ return digest?.health == null ? '-' : String(digest.health);
77
+ case 'tokens':
78
+ return digest === undefined ? '-' : formatTokensCompact(digest.tokens);
79
+ case 'cost':
80
+ return digest === undefined ? '-' : formatCostCell(digest.costUsd);
81
+ case 'updated':
82
+ return formatStamp(row.updatedAt);
83
+ case 'updatedShort': {
84
+ const stamp = formatStamp(row.updatedAt);
85
+ return stamp === '-' ? stamp : stamp.slice(5);
86
+ }
87
+ }
88
+ }
89
+ function prefixWidth(keys) {
90
+ const widths = keys.reduce((sum, key) => sum + COLUMNS[key].width, 0);
91
+ return 2 + widths + GAP.length * keys.length;
92
+ }
93
+ function pickTier(cols) {
94
+ const last = TIERS[TIERS.length - 1];
95
+ return (TIERS.find((keys) => cols - prefixWidth(keys) - 2 >= MIN_GOAL_CELLS + 4) ?? last);
96
+ }
97
+ /** One row of the table, already cut to `cols` cells. */
98
+ export function formatRunRow(row, keys, cols) {
99
+ const cells = keys.map((key) => padCells(cellFor(key, row, row.digest), COLUMNS[key].width));
100
+ const star = UNFINISHED.has(row.status) ? ' *' : '';
101
+ const goalRoom = cols - prefixWidth(keys) - star.length;
102
+ const goal = goalRoom >= 4 ? fitCells(row.goal.replace(/\s+/g, ' '), goalRoom) : '';
103
+ const line = ` ${cells.join(GAP)}${GAP}${goal}${star}`.trimEnd();
104
+ return cellWidth(line) <= cols ? line : fitCells(line, cols);
105
+ }
106
+ /** The whole `/gov runs` notice for `cols` terminal columns. */
107
+ export function formatRunsTable(runs, cols) {
108
+ const width = Number.isFinite(cols) ? Math.max(20, Math.floor(cols)) : 80;
109
+ const keys = pickTier(width);
110
+ const header = ` ${keys.map((k) => padCells(COLUMNS[k].title, COLUMNS[k].width)).join(GAP)}`;
111
+ const lines = ['Governed runs (newest first):', header.trimEnd()];
112
+ for (const run of runs)
113
+ lines.push(formatRunRow(run, keys, width));
114
+ if (runs.some((run) => UNFINISHED.has(run.status))) {
115
+ lines.push('* unfinished: /gov resume <runId>');
116
+ }
117
+ return lines.join('\n');
118
+ }
119
+ /** The transcript text for a found report: header, body capped by lines, full path. */
120
+ export function formatReportNotice(input) {
121
+ const body = input.text.replace(/\r\n/g, '\n').trimEnd().split('\n');
122
+ const shown = body.slice(0, GOV_REPORT_MAX_LINES);
123
+ const more = body.length - shown.length;
124
+ return [
125
+ `Report for run ${input.runId} (${input.file}):`,
126
+ ...shown,
127
+ ...(more > 0 ? [`... (${more} more lines; see the file below)`] : []),
128
+ `Full file: ${input.path}`,
129
+ ].join('\n');
130
+ }
@@ -26,6 +26,14 @@ export declare function hasProjectIndex(cwd: string): boolean;
26
26
  * second time (the skill's own edge-case list says exactly that).
27
27
  */
28
28
  export declare function indexBuildInvocationArgs(hasExistingIndex: boolean): string;
29
+ /**
30
+ * True when `args` is one of the two machine-written sentences above. The invocation
31
+ * card uses this to NOT present them as something the user said (tui-invocation-cards
32
+ * RV-3): it shows a `ctrl+i` fact instead. Same file as the generator so the two cannot
33
+ * drift - a reworded sentence that stops matching would silently put machine words
34
+ * back on the card.
35
+ */
36
+ export declare function isIndexBuildArgs(args: string): boolean;
29
37
  export interface IndexConfirmInput {
30
38
  cwd: string;
31
39
  /** True when `.claude-index/index.md` already exists (rebuild, not first build). */
@@ -40,6 +40,17 @@ export function indexBuildInvocationArgs(hasExistingIndex) {
40
40
  ? 'The user pressed Ctrl+I and confirmed. Rebuild the project index for this workspace now, reusing the existing .claude-index/config.md preferences.'
41
41
  : 'The user pressed Ctrl+I and confirmed. Build the project index for this workspace now, asking the configuration questions first.';
42
42
  }
43
+ /**
44
+ * True when `args` is one of the two machine-written sentences above. The invocation
45
+ * card uses this to NOT present them as something the user said (tui-invocation-cards
46
+ * RV-3): it shows a `ctrl+i` fact instead. Same file as the generator so the two cannot
47
+ * drift - a reworded sentence that stops matching would silently put machine words
48
+ * back on the card.
49
+ */
50
+ export function isIndexBuildArgs(args) {
51
+ const text = args.trim();
52
+ return text === indexBuildInvocationArgs(true) || text === indexBuildInvocationArgs(false);
53
+ }
43
54
  /**
44
55
  * The Yes/No dialog body. It names WHAT WILL BE WRITTEN - an index run is a
45
56
  * batch of file writes the user never typed, and the one question a confirm