@aragon-agent/cli 0.6.44 → 0.6.45
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.
- package/CHANGELOG.md +44 -0
- package/README.md +69 -2
- package/dist/agent/controller.d.ts +69 -0
- package/dist/agent/controller.js +224 -11
- package/dist/agent/governance-view.d.ts +40 -0
- package/dist/agent/governance-view.js +40 -0
- package/dist/agent/governance-wiring.d.ts +162 -0
- package/dist/agent/governance-wiring.js +470 -0
- package/dist/agent/plan-prompt.d.ts +7 -0
- package/dist/agent/plan-prompt.js +2 -1
- package/dist/agent/reducer.d.ts +33 -1
- package/dist/agent/reducer.js +45 -9
- package/dist/agent/system-prompt.d.ts +19 -0
- package/dist/agent/system-prompt.js +9 -1
- package/dist/cli.js +45 -1
- package/dist/commands/builtins.js +10 -4
- package/dist/commands/governance-command.d.ts +35 -0
- package/dist/commands/governance-command.js +292 -0
- package/dist/commands/governance-runs-table.d.ts +40 -0
- package/dist/commands/governance-runs-table.js +130 -0
- package/dist/commands/registry.d.ts +12 -0
- package/dist/config/app-paths.d.ts +10 -0
- package/dist/config/app-paths.js +12 -0
- package/dist/config/cli-commands.d.ts +18 -0
- package/dist/config/cli-commands.js +47 -1
- package/dist/config/env.d.ts +2 -1
- package/dist/config/env.js +10 -1
- package/dist/config/governance-config.d.ts +125 -0
- package/dist/config/governance-config.js +164 -0
- package/dist/config/governance-launch.d.ts +71 -0
- package/dist/config/governance-launch.js +58 -0
- package/dist/config/load.d.ts +15 -0
- package/dist/config/load.js +26 -1
- package/dist/config/model-profile-store.d.ts +4 -2
- package/dist/config/schema.d.ts +22 -0
- package/dist/config/schema.js +6 -0
- package/dist/config/store.js +14 -1
- package/dist/config/ui-state.d.ts +11 -0
- package/dist/config/ui-state.js +11 -0
- package/dist/diagnostics/doctor.js +20 -0
- package/dist/governance/card-normalize.d.ts +24 -0
- package/dist/governance/card-normalize.js +76 -0
- package/dist/governance/copy.d.ts +109 -0
- package/dist/governance/copy.js +223 -0
- package/dist/governance/engine/aftermath.d.ts +49 -0
- package/dist/governance/engine/aftermath.js +134 -0
- package/dist/governance/engine/artifact-persist.d.ts +35 -0
- package/dist/governance/engine/artifact-persist.js +86 -0
- package/dist/governance/engine/budget.d.ts +52 -0
- package/dist/governance/engine/budget.js +112 -0
- package/dist/governance/engine/cards.d.ts +18 -0
- package/dist/governance/engine/cards.js +186 -0
- package/dist/governance/engine/digest.d.ts +32 -0
- package/dist/governance/engine/digest.js +63 -0
- package/dist/governance/engine/engine-core.d.ts +219 -0
- package/dist/governance/engine/engine-core.js +562 -0
- package/dist/governance/engine/engine.d.ts +68 -0
- package/dist/governance/engine/engine.js +314 -0
- package/dist/governance/engine/estimate.d.ts +38 -0
- package/dist/governance/engine/estimate.js +46 -0
- package/dist/governance/engine/inspector.d.ts +16 -0
- package/dist/governance/engine/inspector.js +396 -0
- package/dist/governance/engine/integration.d.ts +35 -0
- package/dist/governance/engine/integration.js +220 -0
- package/dist/governance/engine/lifecycle.d.ts +29 -0
- package/dist/governance/engine/lifecycle.js +656 -0
- package/dist/governance/engine/pause.d.ts +56 -0
- package/dist/governance/engine/pause.js +107 -0
- package/dist/governance/engine/phase-members.d.ts +15 -0
- package/dist/governance/engine/phase-members.js +34 -0
- package/dist/governance/engine/phase-planner.d.ts +53 -0
- package/dist/governance/engine/phase-planner.js +282 -0
- package/dist/governance/engine/rebuild.d.ts +27 -0
- package/dist/governance/engine/rebuild.js +57 -0
- package/dist/governance/engine/report.d.ts +66 -0
- package/dist/governance/engine/report.js +220 -0
- package/dist/governance/engine/run-digest.d.ts +20 -0
- package/dist/governance/engine/run-digest.js +42 -0
- package/dist/governance/engine/spec-builder.d.ts +117 -0
- package/dist/governance/engine/spec-builder.js +321 -0
- package/dist/governance/engine/stage-runner.d.ts +22 -0
- package/dist/governance/engine/stage-runner.js +664 -0
- package/dist/governance/engine/start-input.d.ts +19 -0
- package/dist/governance/engine/start-input.js +111 -0
- package/dist/governance/engine/state-machine.d.ts +101 -0
- package/dist/governance/engine/state-machine.js +586 -0
- package/dist/governance/engine/submission-queries.d.ts +42 -0
- package/dist/governance/engine/submission-queries.js +97 -0
- package/dist/governance/engine/submission-render.d.ts +12 -0
- package/dist/governance/engine/submission-render.js +92 -0
- package/dist/governance/engine/submissions.d.ts +27 -0
- package/dist/governance/engine/submissions.js +455 -0
- package/dist/governance/engine/visibility.d.ts +104 -0
- package/dist/governance/engine/visibility.js +223 -0
- package/dist/governance/governed-dispatch.d.ts +19 -0
- package/dist/governance/governed-dispatch.js +17 -0
- package/dist/governance/limits.d.ts +107 -0
- package/dist/governance/limits.js +131 -0
- package/dist/governance/posture-transition.d.ts +38 -0
- package/dist/governance/posture-transition.js +44 -0
- package/dist/governance/posture.d.ts +35 -0
- package/dist/governance/posture.js +59 -0
- package/dist/governance/profiles.d.ts +48 -0
- package/dist/governance/profiles.js +140 -0
- package/dist/governance/prompts/orchestrator-block.d.ts +40 -0
- package/dist/governance/prompts/orchestrator-block.js +128 -0
- package/dist/governance/prompts/plan-addendum.d.ts +22 -0
- package/dist/governance/prompts/plan-addendum.js +60 -0
- package/dist/governance/prompts/refusals.d.ts +48 -0
- package/dist/governance/prompts/refusals.js +82 -0
- package/dist/governance/prompts/role-blocks.d.ts +40 -0
- package/dist/governance/prompts/role-blocks.js +255 -0
- package/dist/governance/report-reader.d.ts +31 -0
- package/dist/governance/report-reader.js +57 -0
- package/dist/governance/roles.d.ts +83 -0
- package/dist/governance/roles.js +142 -0
- package/dist/governance/rules/claims.d.ts +83 -0
- package/dist/governance/rules/claims.js +250 -0
- package/dist/governance/rules/elimination.d.ts +66 -0
- package/dist/governance/rules/elimination.js +105 -0
- package/dist/governance/rules/events-table.d.ts +46 -0
- package/dist/governance/rules/events-table.js +94 -0
- package/dist/governance/rules/failure-analysis.d.ts +28 -0
- package/dist/governance/rules/failure-analysis.js +93 -0
- package/dist/governance/rules/ledger-replay.d.ts +53 -0
- package/dist/governance/rules/ledger-replay.js +53 -0
- package/dist/governance/rules/ledger-state.d.ts +85 -0
- package/dist/governance/rules/ledger-state.js +175 -0
- package/dist/governance/rules/ledger.d.ts +228 -0
- package/dist/governance/rules/ledger.js +560 -0
- package/dist/governance/rules/rca.d.ts +68 -0
- package/dist/governance/rules/rca.js +220 -0
- package/dist/governance/rules/settlement.d.ts +129 -0
- package/dist/governance/rules/settlement.js +363 -0
- package/dist/governance/rules/suspicion.d.ts +66 -0
- package/dist/governance/rules/suspicion.js +169 -0
- package/dist/governance/store/artifacts.d.ts +81 -0
- package/dist/governance/store/artifacts.js +173 -0
- package/dist/governance/store/atomic.d.ts +79 -0
- package/dist/governance/store/atomic.js +119 -0
- package/dist/governance/store/events-log.d.ts +35 -0
- package/dist/governance/store/events-log.js +86 -0
- package/dist/governance/store/run-lock.d.ts +51 -0
- package/dist/governance/store/run-lock.js +122 -0
- package/dist/governance/store/run-store.d.ts +229 -0
- package/dist/governance/store/run-store.js +644 -0
- package/dist/governance/store/scoreboard-export.d.ts +53 -0
- package/dist/governance/store/scoreboard-export.js +65 -0
- package/dist/governance/tools/child-tools.d.ts +31 -0
- package/dist/governance/tools/child-tools.js +65 -0
- package/dist/governance/tools/guard.d.ts +71 -0
- package/dist/governance/tools/guard.js +194 -0
- package/dist/governance/tools/inspector-tools.d.ts +63 -0
- package/dist/governance/tools/inspector-tools.js +424 -0
- package/dist/governance/tools/lead-tools.d.ts +42 -0
- package/dist/governance/tools/lead-tools.js +226 -0
- package/dist/governance/tools/normalize-util.d.ts +101 -0
- package/dist/governance/tools/normalize-util.js +230 -0
- package/dist/governance/tools/scan-incomplete.d.ts +79 -0
- package/dist/governance/tools/scan-incomplete.js +486 -0
- package/dist/governance/tools/shared-tools.d.ts +44 -0
- package/dist/governance/tools/shared-tools.js +125 -0
- package/dist/governance/tools/submit-normalizers.d.ts +28 -0
- package/dist/governance/tools/submit-normalizers.js +474 -0
- package/dist/governance/tools/submit-tools.d.ts +26 -0
- package/dist/governance/tools/submit-tools.js +171 -0
- package/dist/governance/types.d.ts +661 -0
- package/dist/governance/types.js +27 -0
- package/dist/session/validate-session.js +32 -1
- package/dist/team/runtime.d.ts +8 -0
- package/dist/team/runtime.js +9 -0
- package/dist/team/subagent.d.ts +23 -0
- package/dist/team/subagent.js +14 -3
- package/dist/team/types.d.ts +6 -0
- package/dist/tools/index.d.ts +30 -7
- package/dist/tools/index.js +14 -0
- package/dist/tools/plan-tools.d.ts +14 -2
- package/dist/tools/plan-tools.js +5 -2
- package/dist/ui/App.js +145 -25
- package/dist/ui/BottomStatusRow.js +1 -1
- package/dist/ui/Composer.d.ts +7 -1
- package/dist/ui/Composer.js +9 -6
- package/dist/ui/GovernancePanel.d.ts +50 -0
- package/dist/ui/GovernancePanel.js +77 -0
- package/dist/ui/GovernanceRun.d.ts +18 -0
- package/dist/ui/GovernanceRun.js +11 -0
- package/dist/ui/StatusBar.d.ts +15 -2
- package/dist/ui/StatusBar.js +10 -4
- package/dist/ui/Transcript.js +3 -0
- package/dist/ui/entries/GovernanceCard.d.ts +30 -0
- package/dist/ui/entries/GovernanceCard.js +32 -0
- package/dist/ui/governance-copy.d.ts +69 -0
- package/dist/ui/governance-copy.js +104 -0
- package/dist/ui/governance-status.d.ts +145 -0
- package/dist/ui/governance-status.js +326 -0
- package/dist/ui/interaction-copy.d.ts +4 -0
- package/dist/ui/interaction-copy.js +5 -0
- package/dist/ui/interaction-hints.d.ts +17 -0
- package/dist/ui/interaction-hints.js +14 -2
- package/dist/ui/layout/governance-board.d.ts +121 -0
- package/dist/ui/layout/governance-board.js +382 -0
- package/dist/ui/layout/governance-card.d.ts +53 -0
- package/dist/ui/layout/governance-card.js +134 -0
- package/dist/ui/layout/governance-chip.d.ts +38 -0
- package/dist/ui/layout/governance-chip.js +64 -0
- package/dist/ui/layout/governance-panel.d.ts +85 -0
- package/dist/ui/layout/governance-panel.js +358 -0
- package/dist/ui/layout/governance-roster.d.ts +65 -0
- package/dist/ui/layout/governance-roster.js +275 -0
- package/dist/ui/layout/status-detail-layout.js +3 -3
- package/dist/ui/layout/status-layout.d.ts +5 -2
- package/dist/ui/layout/status-layout.js +10 -6
- package/dist/ui/layout/virtual-window.js +11 -0
- package/dist/ui/overlays/GovernanceBoardOverlay.d.ts +41 -0
- package/dist/ui/overlays/GovernanceBoardOverlay.js +76 -0
- package/dist/ui/overlays/GovernanceSettingsPage.d.ts +48 -0
- package/dist/ui/overlays/GovernanceSettingsPage.js +93 -0
- package/dist/ui/overlays/HelpOverlay.js +4 -3
- package/dist/ui/overlays/QuestionOverlay.d.ts +9 -1
- package/dist/ui/overlays/QuestionOverlay.js +4 -2
- package/dist/ui/overlays/SettingsScreen.d.ts +7 -0
- package/dist/ui/overlays/SettingsScreen.js +21 -1
- package/dist/ui/overlays/governance-settings.d.ts +79 -0
- package/dist/ui/overlays/governance-settings.js +140 -0
- package/dist/ui/overlays/model-profile-state.d.ts +6 -1
- package/dist/ui/overlays/model-profile-state.js +10 -0
- package/dist/ui/palettes.d.ts +17 -0
- package/dist/ui/palettes.js +9 -0
- package/dist/ui/scrollback/live-preview.js +2 -0
- package/dist/ui/scrollback/settled-boundary.js +3 -0
- package/dist/ui/shortcuts.js +2 -2
- package/dist/ui/theme.d.ts +7 -0
- package/dist/ui/theme.js +1 -0
- package/dist/ui/transcript-text.js +9 -0
- package/dist/ui/use-wheel-routing.js +3 -1
- package/package.json +2 -2
|
@@ -0,0 +1,292 @@
|
|
|
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), { userInitiated: false });
|
|
202
|
+
}
|
|
203
|
+
function abort(ctx) {
|
|
204
|
+
if (!ctx.controller.isGovernanceStageRunning()) {
|
|
205
|
+
ctx.notify('info', GOV_NO_STAGE_NOTICE);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
ctx.controller.abortGovernanceStage();
|
|
209
|
+
ctx.notify('info', GOV_ABORTED_NOTICE);
|
|
210
|
+
}
|
|
211
|
+
/** `500`, `500k`, `2m`, `off`/`0`. NaN when unparseable. */
|
|
212
|
+
export function parseBudgetTokens(raw) {
|
|
213
|
+
const text = raw.trim().toLowerCase();
|
|
214
|
+
if (text === 'off' || text === '0')
|
|
215
|
+
return 0;
|
|
216
|
+
const match = /^(\d+(?:\.\d+)?)([km]?)$/.exec(text);
|
|
217
|
+
if (!match)
|
|
218
|
+
return Number.NaN;
|
|
219
|
+
const scale = match[2] === 'm' ? 1_000_000 : match[2] === 'k' ? 1_000 : 1;
|
|
220
|
+
return Math.floor(Number(match[1]) * scale);
|
|
221
|
+
}
|
|
222
|
+
function setBudget(ctx) {
|
|
223
|
+
const raw = ctx.args.trim().split(/\s+/)[1];
|
|
224
|
+
if (raw === undefined) {
|
|
225
|
+
ctx.notify('info', GOV_BUDGET_USAGE);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const tokens = parseBudgetTokens(raw);
|
|
229
|
+
if (!Number.isFinite(tokens) || tokens < 0) {
|
|
230
|
+
ctx.notify('warn', GOV_BUDGET_USAGE);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
// BOTH CALLS, AND NEITHER MAY BE DROPPED (the `/fast` rule): the setter makes the running
|
|
234
|
+
// session honour it and re-renders the prompt; persisting alone changes nothing until
|
|
235
|
+
// relaunch, and the setter alone is forgotten by morning.
|
|
236
|
+
const adopted = ctx.controller.setGovernanceConfig({ budgetTokens: tokens });
|
|
237
|
+
ctx.persistConfig({ governance: adopted });
|
|
238
|
+
ctx.notify('info', adopted.budgetTokens === 0 ? GOV_BUDGET_OFF_NOTICE : govBudgetSetNotice(adopted.budgetTokens));
|
|
239
|
+
}
|
|
240
|
+
/** The command body; `registerGovernanceCommand` is the only registration site. */
|
|
241
|
+
export async function runGovernanceCommand(ctx) {
|
|
242
|
+
const verb = (ctx.args.trim().split(/\s+/)[0] ?? '').toLowerCase();
|
|
243
|
+
switch (verb) {
|
|
244
|
+
case '':
|
|
245
|
+
case 'status':
|
|
246
|
+
reportStatus(ctx);
|
|
247
|
+
return;
|
|
248
|
+
case 'help':
|
|
249
|
+
ctx.notify('info', buildGovHelpText(ctx.controller.getGovernanceConfig().minAskRounds));
|
|
250
|
+
return;
|
|
251
|
+
case 'runs':
|
|
252
|
+
await reportRuns(ctx);
|
|
253
|
+
return;
|
|
254
|
+
case 'report':
|
|
255
|
+
await report(ctx);
|
|
256
|
+
return;
|
|
257
|
+
case 'board':
|
|
258
|
+
ctx.setOverlay('governance');
|
|
259
|
+
return;
|
|
260
|
+
case 'off':
|
|
261
|
+
leave(ctx);
|
|
262
|
+
return;
|
|
263
|
+
case 'on':
|
|
264
|
+
enter(ctx, 'govern');
|
|
265
|
+
return;
|
|
266
|
+
case 'plan':
|
|
267
|
+
enter(ctx, 'plan_govern');
|
|
268
|
+
return;
|
|
269
|
+
case 'resume':
|
|
270
|
+
await resume(ctx);
|
|
271
|
+
return;
|
|
272
|
+
case 'pause':
|
|
273
|
+
await pause(ctx);
|
|
274
|
+
return;
|
|
275
|
+
case 'abort':
|
|
276
|
+
abort(ctx);
|
|
277
|
+
return;
|
|
278
|
+
case 'budget':
|
|
279
|
+
setBudget(ctx);
|
|
280
|
+
return;
|
|
281
|
+
default:
|
|
282
|
+
ctx.notify('warn', `Unknown argument "${verb}". ${USAGE}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/** Registered from `builtins.ts` with one line, next to every other subsystem. */
|
|
286
|
+
export function registerGovernanceCommand(registry) {
|
|
287
|
+
registry.register({
|
|
288
|
+
name: 'gov',
|
|
289
|
+
description: GOV_COMMAND_SUMMARY,
|
|
290
|
+
run: (ctx) => runGovernanceCommand(ctx),
|
|
291
|
+
});
|
|
292
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -6,6 +6,7 @@ import type { SubmitMessageOptions } from '../agent/prompt-options.js';
|
|
|
6
6
|
import type { CopyRequest, CopyRequestResult } from '../ui/clipboard-task.js';
|
|
7
7
|
import type { AgentController } from '../agent/controller.js';
|
|
8
8
|
import type { AgentMode } from '../agent/agent-mode.js';
|
|
9
|
+
import type { Posture } from '../governance/posture.js';
|
|
9
10
|
import type { Entry, NoticeLevel, Overlay, ToastLevel, ViewAction, ViewState } from '../agent/reducer.js';
|
|
10
11
|
import type { PersistedConfig } from '../config/schema.js';
|
|
11
12
|
import type { FollowThroughBudget } from '../todo/follow-through.js';
|
|
@@ -92,6 +93,17 @@ export interface CommandContext {
|
|
|
92
93
|
effective: AgentMode;
|
|
93
94
|
pending: AgentMode | null;
|
|
94
95
|
};
|
|
96
|
+
/**
|
|
97
|
+
* The same single write path, widened to the four postures (governance-mode 4.2).
|
|
98
|
+
* OPTIONAL so the many fixtures that build this context by literal need no change; the
|
|
99
|
+
* App always supplies it, and `/gov` reports "unavailable" when it is absent.
|
|
100
|
+
*/
|
|
101
|
+
applyPosture?: (next: Posture, opts?: {
|
|
102
|
+
force?: boolean;
|
|
103
|
+
}) => {
|
|
104
|
+
effective: Posture;
|
|
105
|
+
pending: Posture | null;
|
|
106
|
+
};
|
|
95
107
|
/**
|
|
96
108
|
* Mouse capture, for `/mouse` (tui-selection-and-scroll-follow §6.2 / G3).
|
|
97
109
|
*
|
|
@@ -151,6 +151,16 @@ export declare function getSessionsDir(): string;
|
|
|
151
151
|
* a per-process run id and why retention is two-tier (§3.5.2 / RV-6).
|
|
152
152
|
*/
|
|
153
153
|
export declare function getCompactionArchiveDir(): string;
|
|
154
|
+
/**
|
|
155
|
+
* `<home>/governance` - governance-mode run records (governance-mode 11.1 / 12.1).
|
|
156
|
+
*
|
|
157
|
+
* ITS OWN ROOT, for the reason `getCompactionArchiveDir` above records: `logs/`, `sessions/`
|
|
158
|
+
* and `skills/` are scan roots, and every extra directory inside one is another thing each
|
|
159
|
+
* walk has to recognise and skip. Derived from the same `resolution.root`, so the
|
|
160
|
+
* `ARAGON_HOME` / VITEST isolation contract at the top of this file covers it too.
|
|
161
|
+
* The caller creates it (0700 on POSIX); this function only names it.
|
|
162
|
+
*/
|
|
163
|
+
export declare function getGovernanceDir(): string;
|
|
154
164
|
/** `<home>` — parent of `skills/`, and where sidecar state such as usage lives. */
|
|
155
165
|
export declare function getUserDataDir(): string;
|
|
156
166
|
export declare function getUserSkillsDir(): string;
|
package/dist/config/app-paths.js
CHANGED
|
@@ -242,6 +242,18 @@ export function getSessionsDir() {
|
|
|
242
242
|
export function getCompactionArchiveDir() {
|
|
243
243
|
return join(resolution.root, 'compaction');
|
|
244
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* `<home>/governance` - governance-mode run records (governance-mode 11.1 / 12.1).
|
|
247
|
+
*
|
|
248
|
+
* ITS OWN ROOT, for the reason `getCompactionArchiveDir` above records: `logs/`, `sessions/`
|
|
249
|
+
* and `skills/` are scan roots, and every extra directory inside one is another thing each
|
|
250
|
+
* walk has to recognise and skip. Derived from the same `resolution.root`, so the
|
|
251
|
+
* `ARAGON_HOME` / VITEST isolation contract at the top of this file covers it too.
|
|
252
|
+
* The caller creates it (0700 on POSIX); this function only names it.
|
|
253
|
+
*/
|
|
254
|
+
export function getGovernanceDir() {
|
|
255
|
+
return join(resolution.root, 'governance');
|
|
256
|
+
}
|
|
245
257
|
/** `<home>` — parent of `skills/`, and where sidecar state such as usage lives. */
|
|
246
258
|
export function getUserDataDir() {
|
|
247
259
|
return resolution.root;
|
|
@@ -96,6 +96,11 @@ export declare const UPDATE_CONFIG_SET_KEYS: readonly ["update.mode", "update.ch
|
|
|
96
96
|
* persisted-off-survives-a-flagless-run check — runs exactly that command.
|
|
97
97
|
*/
|
|
98
98
|
export declare const COMPACTION_CONFIG_SET_KEYS: readonly ["compaction.enabled", "compaction.threshold", "compaction.warnThreshold", "compaction.keepRecentTurns", "compaction.useFastTier", "compaction.onFailure", "compaction.subagents", "compaction.archive"];
|
|
99
|
+
/**
|
|
100
|
+
* Config keys under `governance.` that `aragon config set` accepts (governance-mode 11.1).
|
|
101
|
+
* Every key is writable and ONE level deep, so `runConfigGet`'s single-dot split resolves it.
|
|
102
|
+
*/
|
|
103
|
+
export declare const GOVERNANCE_CONFIG_SET_KEYS: readonly ["governance.enabled", "governance.shiftTab", "governance.panel", "governance.profile", "governance.maxWorkPackages", "governance.maxPhases", "governance.maxRework", "governance.maxFixCycles", "governance.minAskRounds", "governance.budgetTokens", "governance.confirmCharter"];
|
|
99
104
|
/**
|
|
100
105
|
* Translate a `log.*` dotted key into a patch, or `null` for anything else.
|
|
101
106
|
*
|
|
@@ -131,6 +136,19 @@ export declare function applyJobsConfigSet(key: string, value: string): Partial<
|
|
|
131
136
|
* rather than silently mean `false`.
|
|
132
137
|
*/
|
|
133
138
|
export declare function applyTaskSummaryConfigSet(key: string, value: string): Partial<PersistedConfig> | null;
|
|
139
|
+
/**
|
|
140
|
+
* Translate a `governance.*` dotted key into a patch, or `null` for anything else.
|
|
141
|
+
*
|
|
142
|
+
* EVERY KEY ROUTES THROUGH `clampGovernanceConfig`, so `config set governance.maxRework 9`
|
|
143
|
+
* stores 5 (the engine's `hardMaxRework`) and the caller echoes the STORED value. The string
|
|
144
|
+
* is turned into a number HERE, because the clamp deliberately repairs a string to the
|
|
145
|
+
* default (a hand-edited `"2"` has no defensible reading); an unparseable argument becomes
|
|
146
|
+
* `NaN`, which the clamp repairs to the default - the "typo changes nothing" rule.
|
|
147
|
+
*
|
|
148
|
+
* The patch is a PARTIAL section, safe only because `updatePersistedConfig` deep-merges
|
|
149
|
+
* `governance` (the ninth time that trap is recorded in `store.ts`).
|
|
150
|
+
*/
|
|
151
|
+
export declare function applyGovernanceConfigSet(key: string, value: string): Partial<PersistedConfig> | null;
|
|
134
152
|
/**
|
|
135
153
|
* Translate a `team.*` dotted key into a patch, or `null` for anything else.
|
|
136
154
|
*
|
|
@@ -14,7 +14,7 @@ import { getConfigBackupPath, getConfigPath, getHomeRoot, getLogsDir, getPromptH
|
|
|
14
14
|
import { getHomeMigrationBreadcrumbPath } from './migrate-home.js';
|
|
15
15
|
import { loadPersistedConfig, updatePersistedConfig } from './store.js';
|
|
16
16
|
import { normalizeModelProfiles, validateModelProfiles } from './model-profiles.js';
|
|
17
|
-
import { clampFastConfig, clampRetryConfig, clampCompactionConfig, clampTeamConfig, parseThresholdInput, clampUpdateConfig, coercePositiveInt, maskSecret, DEFAULT_FAST_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TEAM_CONFIG, DEFAULT_COMPACTION_CONFIG, DEFAULT_UPDATE_CONFIG, DEFAULT_JOBS_CONFIG, clampJobsConfig, } from './schema.js';
|
|
17
|
+
import { clampFastConfig, clampRetryConfig, clampCompactionConfig, clampTeamConfig, parseThresholdInput, clampUpdateConfig, coercePositiveInt, maskSecret, DEFAULT_FAST_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TEAM_CONFIG, DEFAULT_COMPACTION_CONFIG, DEFAULT_UPDATE_CONFIG, DEFAULT_JOBS_CONFIG, clampJobsConfig, clampGovernanceConfig, DEFAULT_GOVERNANCE_CONFIG, } from './schema.js';
|
|
18
18
|
import { clampLogLevel } from '../logging/levels.js';
|
|
19
19
|
/** Config keys under `log.` that `aragon config set` accepts. */
|
|
20
20
|
export const LOG_CONFIG_SET_KEYS = [
|
|
@@ -167,6 +167,23 @@ export const COMPACTION_CONFIG_SET_KEYS = [
|
|
|
167
167
|
'compaction.subagents',
|
|
168
168
|
'compaction.archive',
|
|
169
169
|
];
|
|
170
|
+
/**
|
|
171
|
+
* Config keys under `governance.` that `aragon config set` accepts (governance-mode 11.1).
|
|
172
|
+
* Every key is writable and ONE level deep, so `runConfigGet`'s single-dot split resolves it.
|
|
173
|
+
*/
|
|
174
|
+
export const GOVERNANCE_CONFIG_SET_KEYS = [
|
|
175
|
+
'governance.enabled',
|
|
176
|
+
'governance.shiftTab',
|
|
177
|
+
'governance.panel',
|
|
178
|
+
'governance.profile',
|
|
179
|
+
'governance.maxWorkPackages',
|
|
180
|
+
'governance.maxPhases',
|
|
181
|
+
'governance.maxRework',
|
|
182
|
+
'governance.maxFixCycles',
|
|
183
|
+
'governance.minAskRounds',
|
|
184
|
+
'governance.budgetTokens',
|
|
185
|
+
'governance.confirmCharter',
|
|
186
|
+
];
|
|
170
187
|
function isTrue(value) {
|
|
171
188
|
return value === 'true' || value === '1';
|
|
172
189
|
}
|
|
@@ -255,6 +272,35 @@ export function applyTaskSummaryConfigSet(key, value) {
|
|
|
255
272
|
return null;
|
|
256
273
|
}
|
|
257
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* Translate a `governance.*` dotted key into a patch, or `null` for anything else.
|
|
277
|
+
*
|
|
278
|
+
* EVERY KEY ROUTES THROUGH `clampGovernanceConfig`, so `config set governance.maxRework 9`
|
|
279
|
+
* stores 5 (the engine's `hardMaxRework`) and the caller echoes the STORED value. The string
|
|
280
|
+
* is turned into a number HERE, because the clamp deliberately repairs a string to the
|
|
281
|
+
* default (a hand-edited `"2"` has no defensible reading); an unparseable argument becomes
|
|
282
|
+
* `NaN`, which the clamp repairs to the default - the "typo changes nothing" rule.
|
|
283
|
+
*
|
|
284
|
+
* The patch is a PARTIAL section, safe only because `updatePersistedConfig` deep-merges
|
|
285
|
+
* `governance` (the ninth time that trap is recorded in `store.ts`).
|
|
286
|
+
*/
|
|
287
|
+
export function applyGovernanceConfigSet(key, value) {
|
|
288
|
+
if (!GOVERNANCE_CONFIG_SET_KEYS.includes(key))
|
|
289
|
+
return null;
|
|
290
|
+
const field = key.slice('governance.'.length);
|
|
291
|
+
const typed = parseGovernanceArgument(field, value);
|
|
292
|
+
const clamped = clampGovernanceConfig({ ...DEFAULT_GOVERNANCE_CONFIG, [field]: typed });
|
|
293
|
+
return { governance: { [field]: clamped[field] } };
|
|
294
|
+
}
|
|
295
|
+
function parseGovernanceArgument(field, value) {
|
|
296
|
+
const kind = typeof DEFAULT_GOVERNANCE_CONFIG[field];
|
|
297
|
+
const trimmed = value.trim();
|
|
298
|
+
if (kind === 'boolean')
|
|
299
|
+
return isTrue(trimmed);
|
|
300
|
+
if (kind === 'number')
|
|
301
|
+
return trimmed === '' ? Number.NaN : Number(trimmed);
|
|
302
|
+
return trimmed;
|
|
303
|
+
}
|
|
258
304
|
/**
|
|
259
305
|
* Translate a `team.*` dotted key into a patch, or `null` for anything else.
|
|
260
306
|
*
|
package/dist/config/env.d.ts
CHANGED
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
* ARAGON_COMPACTION_ARCHIVE,
|
|
22
22
|
* ARAGON_JOBS_ENABLED, ARAGON_JOBS_WAIT_SECONDS, ARAGON_JOBS_STALL_SECONDS,
|
|
23
23
|
* ARAGON_JOBS_PERSIST_LOG, ARAGON_JOBS_NOTICE_STEER,
|
|
24
|
-
* ARAGON_PROMPTS (the quick-prompt library's `enabled` switch, and only that)
|
|
24
|
+
* ARAGON_PROMPTS (the quick-prompt library's `enabled` switch, and only that),
|
|
25
|
+
* ARAGON_GOVERNANCE (a KILL switch: `0` disables governance mode, nothing enables it).
|
|
25
26
|
*
|
|
26
27
|
* READ ELSEWHERE, ON PURPOSE: `ARAGON_UPDATE_REGISTRY` and `npm_config_registry`
|
|
27
28
|
* are resolved by `update/registry.ts::resolveRegistryUrl`, NOT here, because
|