@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.
- package/CHANGELOG.md +44 -0
- package/README.md +120 -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/invocation-card.d.ts +77 -0
- package/dist/agent/invocation-card.js +169 -0
- package/dist/agent/plan-prompt.d.ts +7 -0
- package/dist/agent/plan-prompt.js +2 -1
- package/dist/agent/prompt-options.d.ts +6 -0
- package/dist/agent/queued-messages.d.ts +3 -0
- package/dist/agent/queued-messages.js +4 -1
- package/dist/agent/reducer.d.ts +38 -1
- package/dist/agent/reducer.js +57 -12
- 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 +22 -4
- package/dist/commands/governance-command.d.ts +35 -0
- package/dist/commands/governance-command.js +304 -0
- package/dist/commands/governance-runs-table.d.ts +40 -0
- package/dist/commands/governance-runs-table.js +130 -0
- package/dist/commands/index-build.d.ts +8 -0
- package/dist/commands/index-build.js +11 -0
- package/dist/commands/registry.d.ts +35 -0
- package/dist/commands/registry.js +20 -7
- package/dist/commands/skills.js +36 -2
- package/dist/commands/subagent-command.js +3 -1
- package/dist/commands/team-command.d.ts +6 -0
- package/dist/commands/team-command.js +40 -3
- 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/persist.js +10 -0
- package/dist/session/validate-session.js +36 -3
- package/dist/team/forced-mode.d.ts +19 -0
- package/dist/team/forced-mode.js +42 -20
- 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 +170 -31
- 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 +7 -1
- package/dist/ui/entries/GovernanceCard.d.ts +30 -0
- package/dist/ui/entries/GovernanceCard.js +32 -0
- package/dist/ui/entries/InvocationCard.d.ts +20 -0
- package/dist/ui/entries/InvocationCard.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/invocation-card.d.ts +41 -0
- package/dist/ui/layout/invocation-card.js +91 -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 +22 -1
- 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 +13 -1
- package/dist/ui/use-wheel-routing.js +3 -1
- package/package.json +2 -2
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governance-mode configuration (governance-mode sections 11.1 / 13.2).
|
|
3
|
+
*
|
|
4
|
+
* LIVES IN ITS OWN FILE, NOT IN `schema.ts`: that file is far past the repo's
|
|
5
|
+
* 1000-line limit, and a section whose clamp depends on nothing else in it has no
|
|
6
|
+
* reason to grow it. `schema.ts` imports and re-exports everything below, so every
|
|
7
|
+
* importer still reaches the section through `config/schema.js`.
|
|
8
|
+
*
|
|
9
|
+
* SELF-CONTAINED ON PURPOSE. The integer/boolean helpers in `schema.ts` are private,
|
|
10
|
+
* and importing back from it would make a cycle (`schema.ts` re-exports this file).
|
|
11
|
+
* The two helpers here are four lines each.
|
|
12
|
+
*
|
|
13
|
+
* ASCII ONLY: `src/config/**` is inside the glyph scanner's scope.
|
|
14
|
+
*/
|
|
15
|
+
import process from 'node:process';
|
|
16
|
+
import { GOV_LIMITS } from '../governance/limits.js';
|
|
17
|
+
import { PROFILE_IDS } from '../governance/types.js';
|
|
18
|
+
export const DEFAULT_GOVERNANCE_CONFIG = {
|
|
19
|
+
enabled: true,
|
|
20
|
+
shiftTab: true,
|
|
21
|
+
panel: true,
|
|
22
|
+
profile: 'general',
|
|
23
|
+
maxWorkPackages: 4,
|
|
24
|
+
maxPhases: 3,
|
|
25
|
+
maxRework: 3,
|
|
26
|
+
maxFixCycles: 3,
|
|
27
|
+
minAskRounds: 2,
|
|
28
|
+
budgetTokens: 0,
|
|
29
|
+
confirmCharter: false,
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Inclusive range per numeric key. The upper bounds of the four structural keys are
|
|
33
|
+
* `GOV_LIMITS.hardMax*` (NOT repeated here), so the clamp and the engine can never
|
|
34
|
+
* disagree: a hand-edited `config.json` cannot exceed what the engine enforces.
|
|
35
|
+
*/
|
|
36
|
+
const NUMERIC_RANGES = {
|
|
37
|
+
maxWorkPackages: { min: 1, max: GOV_LIMITS.hardMaxWorkPackages },
|
|
38
|
+
maxPhases: { min: 1, max: GOV_LIMITS.hardMaxPhases },
|
|
39
|
+
maxRework: { min: 1, max: GOV_LIMITS.hardMaxRework },
|
|
40
|
+
maxFixCycles: { min: 1, max: GOV_LIMITS.hardMaxFixCycles },
|
|
41
|
+
minAskRounds: { min: 0, max: 5 },
|
|
42
|
+
budgetTokens: { min: 0, max: 1_000_000_000 },
|
|
43
|
+
};
|
|
44
|
+
/** The numeric keys, in display order; shared with the settings and `config` surfaces. */
|
|
45
|
+
export const GOVERNANCE_NUMERIC_KEYS = Object.keys(NUMERIC_RANGES);
|
|
46
|
+
/** The inclusive range a numeric key is clamped to. */
|
|
47
|
+
export function governanceRangeOf(key) {
|
|
48
|
+
return NUMERIC_RANGES[key];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Only a real, finite INTEGER survives. A float, NaN, a string ("2") or null is
|
|
52
|
+
* REPAIRED TO THE DEFAULT, not rounded or coerced: a hand-edited `maxRework: 2.5` has no
|
|
53
|
+
* defensible reading, and "typo changes nothing" is the discipline every sibling clamp
|
|
54
|
+
* follows. Out-of-range integers are clamped, not rejected.
|
|
55
|
+
*/
|
|
56
|
+
function clampRangedInt(value, key) {
|
|
57
|
+
const range = NUMERIC_RANGES[key];
|
|
58
|
+
const fallback = DEFAULT_GOVERNANCE_CONFIG[key];
|
|
59
|
+
if (typeof value !== 'number' || !Number.isInteger(value))
|
|
60
|
+
return fallback;
|
|
61
|
+
return Math.min(range.max, Math.max(range.min, value));
|
|
62
|
+
}
|
|
63
|
+
function pickBool(value, fallback) {
|
|
64
|
+
return typeof value === 'boolean' ? value : fallback;
|
|
65
|
+
}
|
|
66
|
+
function pickProfile(value) {
|
|
67
|
+
return typeof value === 'string' && PROFILE_IDS.includes(value)
|
|
68
|
+
? value
|
|
69
|
+
: DEFAULT_GOVERNANCE_CONFIG.profile;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* THE single gate for every governance-config read AND write, mirroring
|
|
73
|
+
* `clampTeamConfig` for the reason that one records: hardening only the read path
|
|
74
|
+
* leaves a bad value on disk that the read path then rewrites on every launch, which
|
|
75
|
+
* presents to the user as "my setting won't stick". Unknown keys are dropped.
|
|
76
|
+
*/
|
|
77
|
+
export function clampGovernanceConfig(raw) {
|
|
78
|
+
const src = (raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {});
|
|
79
|
+
const defaults = DEFAULT_GOVERNANCE_CONFIG;
|
|
80
|
+
return {
|
|
81
|
+
enabled: pickBool(src.enabled, defaults.enabled),
|
|
82
|
+
shiftTab: pickBool(src.shiftTab, defaults.shiftTab),
|
|
83
|
+
panel: pickBool(src.panel, defaults.panel),
|
|
84
|
+
profile: pickProfile(src.profile),
|
|
85
|
+
maxWorkPackages: clampRangedInt(src.maxWorkPackages, 'maxWorkPackages'),
|
|
86
|
+
maxPhases: clampRangedInt(src.maxPhases, 'maxPhases'),
|
|
87
|
+
maxRework: clampRangedInt(src.maxRework, 'maxRework'),
|
|
88
|
+
maxFixCycles: clampRangedInt(src.maxFixCycles, 'maxFixCycles'),
|
|
89
|
+
minAskRounds: clampRangedInt(src.minAskRounds, 'minAskRounds'),
|
|
90
|
+
budgetTokens: clampRangedInt(src.budgetTokens, 'budgetTokens'),
|
|
91
|
+
confirmCharter: pickBool(src.confirmCharter, defaults.confirmCharter),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Environment kill switch + availability (config-level part)
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
/** The spellings of "off" the kill switch accepts, matching the other ARAGON_* switches. */
|
|
98
|
+
const ENV_OFF_VALUES = new Set(['0', 'false', 'off', 'no']);
|
|
99
|
+
/**
|
|
100
|
+
* `ARAGON_GOVERNANCE=0` is a KILL switch, not a toggle: it can only disable. Any other
|
|
101
|
+
* value (including `1`) is ignored, so an environment can never switch a feature ON that
|
|
102
|
+
* the user's config or a `--no-governance` flag turned off.
|
|
103
|
+
*
|
|
104
|
+
* Takes the env as a parameter so tests and `doctor` do not touch `process.env`.
|
|
105
|
+
*/
|
|
106
|
+
export function isGovernanceEnvDisabled(env = process.env) {
|
|
107
|
+
const value = env.ARAGON_GOVERNANCE?.trim().toLowerCase();
|
|
108
|
+
return value !== undefined && ENV_OFF_VALUES.has(value);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Config-only availability, in precedence order: the environment kill switch first (it is
|
|
112
|
+
* the strongest), then the config key, then the team dependency. Pure: no I/O.
|
|
113
|
+
*/
|
|
114
|
+
export function describeGovernanceConfigAvailability(config, env = process.env) {
|
|
115
|
+
if (isGovernanceEnvDisabled(env))
|
|
116
|
+
return { ok: false, reason: 'disabled_env' };
|
|
117
|
+
if (config.governance?.enabled === false)
|
|
118
|
+
return { ok: false, reason: 'disabled_config' };
|
|
119
|
+
if (!config.team.enabled)
|
|
120
|
+
return { ok: false, reason: 'team_off' };
|
|
121
|
+
return { ok: true };
|
|
122
|
+
}
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// Launch resolution (load.ts calls these; kept here so load.ts barely grows)
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
/**
|
|
127
|
+
* Merge the `governance` section across the layers (defaults > file > env > flag).
|
|
128
|
+
*
|
|
129
|
+
* The environment and `--no-governance` layers can ONLY switch `enabled` off (they are kill
|
|
130
|
+
* switches), and they are applied last so nothing in the file can outvote them. The flag is a
|
|
131
|
+
* launch-only override: it is resolved here into the in-memory config and never reaches the
|
|
132
|
+
* store, which is what "not persisted" means.
|
|
133
|
+
*/
|
|
134
|
+
export function resolveGovernanceConfig(layers) {
|
|
135
|
+
return clampGovernanceConfig({
|
|
136
|
+
...DEFAULT_GOVERNANCE_CONFIG,
|
|
137
|
+
...(isPlainObject(layers.file) ? layers.file : {}),
|
|
138
|
+
...(isPlainObject(layers.env) ? layers.env : {}),
|
|
139
|
+
...(layers.disableForLaunch === true ? { enabled: false } : {}),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function isPlainObject(value) {
|
|
143
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The posture the session starts in. Governance flags win over `--plan` / `planModeDefault`
|
|
147
|
+
* (a user who asked for a governed run did not ask for a plain one); when governance is
|
|
148
|
+
* unavailable at the CONFIG level the request degrades to the classic posture the same launch
|
|
149
|
+
* would have had, and the reason is returned so the caller can say so instead of silently
|
|
150
|
+
* dropping the flag. Without a governance flag this is exactly `startInPlanMode ? 'plan' :
|
|
151
|
+
* 'build'`, so `--plan` behaviour is untouched.
|
|
152
|
+
*/
|
|
153
|
+
export function resolveInitialPosture(input, env = process.env) {
|
|
154
|
+
const classic = input.startInPlanMode ? 'plan' : 'build';
|
|
155
|
+
const requested = input.planGovern === true
|
|
156
|
+
? 'plan_govern'
|
|
157
|
+
: input.govern === true ? 'govern' : null;
|
|
158
|
+
if (requested === null)
|
|
159
|
+
return { posture: classic };
|
|
160
|
+
const availability = describeGovernanceConfigAvailability({ governance: input.governance, team: { enabled: input.teamEnabled } }, env);
|
|
161
|
+
return availability.ok
|
|
162
|
+
? { posture: requested }
|
|
163
|
+
: { posture: classic, degradedReason: availability.reason };
|
|
164
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command-line validation for the governance flags (governance-mode 11.2).
|
|
3
|
+
*
|
|
4
|
+
* PURE, AND OUT OF `cli.tsx` ON PURPOSE: that file is far past the size limit, and these four
|
|
5
|
+
* rules are exactly the kind that regress silently (a missing one lets `-p --govern` start a
|
|
6
|
+
* run that can never reach a human). `cli.tsx` only gathers the facts and prints the message.
|
|
7
|
+
*
|
|
8
|
+
* ASCII ONLY: `src/config/**` is inside the glyph scanner's scope.
|
|
9
|
+
*/
|
|
10
|
+
export interface GovernanceLaunchInput {
|
|
11
|
+
/** `--govern`. */
|
|
12
|
+
govern?: boolean;
|
|
13
|
+
/** `--plan-govern`. */
|
|
14
|
+
planGovern?: boolean;
|
|
15
|
+
/** `--plan` (`true` only when passed; `--no-plan` and silence are both falsy here). */
|
|
16
|
+
plan?: boolean;
|
|
17
|
+
/** `--no-team`. */
|
|
18
|
+
noTeam?: boolean;
|
|
19
|
+
/** `--no-governance`. */
|
|
20
|
+
noGovernance?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The run cannot reach a human: `-p/--print`, the `exec` subcommand, piped stdin or a
|
|
23
|
+
* non-TTY stdout. Governance needs `ask_user` and the review overlays, which headless
|
|
24
|
+
* runs deny wholesale.
|
|
25
|
+
*/
|
|
26
|
+
headless: boolean;
|
|
27
|
+
}
|
|
28
|
+
export type GovernanceLaunchCheck = {
|
|
29
|
+
ok: true;
|
|
30
|
+
} | {
|
|
31
|
+
ok: false;
|
|
32
|
+
message: string;
|
|
33
|
+
};
|
|
34
|
+
export declare const GOVERNANCE_EXCLUSIVE_MESSAGE = "--govern, --plan-govern and --plan are mutually exclusive. Pass only one of them.";
|
|
35
|
+
export declare const GOVERNANCE_HEADLESS_MESSAGE: string;
|
|
36
|
+
export declare const GOVERNANCE_NO_TEAM_MESSAGE: string;
|
|
37
|
+
export declare const GOVERNANCE_NO_GOVERNANCE_MESSAGE: string;
|
|
38
|
+
/**
|
|
39
|
+
* The first violated rule, or `{ ok: true }`. ORDER IS THE CONTRACT: the exclusivity error
|
|
40
|
+
* is the one a user typing three flags needs to see first, and the headless rule outranks
|
|
41
|
+
* `--no-team` because it is the one that cannot be fixed by dropping a second flag.
|
|
42
|
+
* Nothing is checked unless a governance posture was actually requested.
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateGovernanceLaunch(input: GovernanceLaunchInput): GovernanceLaunchCheck;
|
|
45
|
+
/** The root-level options the rules read, as commander materialises them. */
|
|
46
|
+
export interface GovernanceRootOptions {
|
|
47
|
+
govern?: boolean;
|
|
48
|
+
planGovern?: boolean;
|
|
49
|
+
plan?: boolean;
|
|
50
|
+
/** `--team` / `--no-team`: only an explicit `false` is a refusal. */
|
|
51
|
+
team?: boolean;
|
|
52
|
+
/** `--no-governance` is declared alone, so this is `true` when absent and `false` when given. */
|
|
53
|
+
governance?: boolean;
|
|
54
|
+
print?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface GovernanceCommandContext {
|
|
57
|
+
/** The command about to run: `exec`, `config`, or the root command's own name. */
|
|
58
|
+
commandName: string;
|
|
59
|
+
/** `true` for the root command's own action (the TUI / `-p` entry), not a subcommand. */
|
|
60
|
+
isRootAction: boolean;
|
|
61
|
+
stdinIsTty: boolean;
|
|
62
|
+
stdoutIsTty: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The `preAction` hook's decision. `exec` is always headless; the root action is headless
|
|
66
|
+
* when `-p` was given or either stream is not a terminal (the TUI would refuse to start
|
|
67
|
+
* anyway, but it would do so AFTER a governance run had been promised). Other subcommands
|
|
68
|
+
* (`config`, `logs`, ...) never start a governed run, so only the flag-combination rules
|
|
69
|
+
* apply to them.
|
|
70
|
+
*/
|
|
71
|
+
export declare function checkGovernanceCommandLine(options: GovernanceRootOptions, context: GovernanceCommandContext): GovernanceLaunchCheck;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command-line validation for the governance flags (governance-mode 11.2).
|
|
3
|
+
*
|
|
4
|
+
* PURE, AND OUT OF `cli.tsx` ON PURPOSE: that file is far past the size limit, and these four
|
|
5
|
+
* rules are exactly the kind that regress silently (a missing one lets `-p --govern` start a
|
|
6
|
+
* run that can never reach a human). `cli.tsx` only gathers the facts and prints the message.
|
|
7
|
+
*
|
|
8
|
+
* ASCII ONLY: `src/config/**` is inside the glyph scanner's scope.
|
|
9
|
+
*/
|
|
10
|
+
export const GOVERNANCE_EXCLUSIVE_MESSAGE = '--govern, --plan-govern and --plan are mutually exclusive. Pass only one of them.';
|
|
11
|
+
export const GOVERNANCE_HEADLESS_MESSAGE = 'Governance mode needs an interactive terminal. It cannot be combined with -p/--print, '
|
|
12
|
+
+ 'the exec subcommand or piped input.';
|
|
13
|
+
export const GOVERNANCE_NO_TEAM_MESSAGE = '--govern and --plan-govern run their roles as team subagents, so they cannot be '
|
|
14
|
+
+ 'combined with --no-team. Remove --no-team to use governance mode.';
|
|
15
|
+
export const GOVERNANCE_NO_GOVERNANCE_MESSAGE = '--no-governance disables governance mode for this launch, so it cannot be combined with '
|
|
16
|
+
+ '--govern or --plan-govern.';
|
|
17
|
+
/**
|
|
18
|
+
* The first violated rule, or `{ ok: true }`. ORDER IS THE CONTRACT: the exclusivity error
|
|
19
|
+
* is the one a user typing three flags needs to see first, and the headless rule outranks
|
|
20
|
+
* `--no-team` because it is the one that cannot be fixed by dropping a second flag.
|
|
21
|
+
* Nothing is checked unless a governance posture was actually requested.
|
|
22
|
+
*/
|
|
23
|
+
export function validateGovernanceLaunch(input) {
|
|
24
|
+
const requested = input.govern === true || input.planGovern === true;
|
|
25
|
+
const exclusive = [input.govern === true, input.planGovern === true, input.plan === true];
|
|
26
|
+
if (exclusive.filter(Boolean).length > 1) {
|
|
27
|
+
return { ok: false, message: GOVERNANCE_EXCLUSIVE_MESSAGE };
|
|
28
|
+
}
|
|
29
|
+
if (!requested)
|
|
30
|
+
return { ok: true };
|
|
31
|
+
if (input.noGovernance === true)
|
|
32
|
+
return { ok: false, message: GOVERNANCE_NO_GOVERNANCE_MESSAGE };
|
|
33
|
+
if (input.headless)
|
|
34
|
+
return { ok: false, message: GOVERNANCE_HEADLESS_MESSAGE };
|
|
35
|
+
if (input.noTeam === true)
|
|
36
|
+
return { ok: false, message: GOVERNANCE_NO_TEAM_MESSAGE };
|
|
37
|
+
return { ok: true };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The `preAction` hook's decision. `exec` is always headless; the root action is headless
|
|
41
|
+
* when `-p` was given or either stream is not a terminal (the TUI would refuse to start
|
|
42
|
+
* anyway, but it would do so AFTER a governance run had been promised). Other subcommands
|
|
43
|
+
* (`config`, `logs`, ...) never start a governed run, so only the flag-combination rules
|
|
44
|
+
* apply to them.
|
|
45
|
+
*/
|
|
46
|
+
export function checkGovernanceCommandLine(options, context) {
|
|
47
|
+
const headless = context.commandName === 'exec'
|
|
48
|
+
|| (context.isRootAction
|
|
49
|
+
&& (options.print === true || !context.stdinIsTty || !context.stdoutIsTty));
|
|
50
|
+
return validateGovernanceLaunch({
|
|
51
|
+
govern: options.govern,
|
|
52
|
+
planGovern: options.planGovern,
|
|
53
|
+
plan: options.plan,
|
|
54
|
+
noTeam: options.team === false,
|
|
55
|
+
noGovernance: options.governance === false,
|
|
56
|
+
headless,
|
|
57
|
+
});
|
|
58
|
+
}
|
package/dist/config/load.d.ts
CHANGED
|
@@ -240,6 +240,21 @@ export interface CliFlags {
|
|
|
240
240
|
compaction?: boolean;
|
|
241
241
|
/** `--compaction-threshold <0..1|N%>` — session override for `threshold`. */
|
|
242
242
|
compactionThreshold?: string;
|
|
243
|
+
/**
|
|
244
|
+
* `--govern` / `--plan-govern` (governance-mode 11.2). Plain booleans: they only ever ask
|
|
245
|
+
* for a starting posture and are persisted nowhere, so unlike the pairs above there is no
|
|
246
|
+
* stored value for a commander default to overwrite. `cli.tsx` rejects the combinations
|
|
247
|
+
* (mutually exclusive, headless, `--no-team`) before this layer sees them.
|
|
248
|
+
*/
|
|
249
|
+
govern?: boolean;
|
|
250
|
+
planGovern?: boolean;
|
|
251
|
+
/**
|
|
252
|
+
* `--no-governance`, carried as `false` ONLY. A lone negative flag makes commander default
|
|
253
|
+
* its option to `true`, so `cli.tsx` forwards `undefined` for that case and nothing here can
|
|
254
|
+
* mistake silence for an override. Launch-only: it lands in the resolved `CliConfig` and is
|
|
255
|
+
* never written to the store.
|
|
256
|
+
*/
|
|
257
|
+
governance?: boolean;
|
|
243
258
|
/**
|
|
244
259
|
* `--resume <id|path>` - continue a saved session under a NEW id
|
|
245
260
|
* (tui-session-id-resume 4).
|
package/dist/config/load.js
CHANGED
|
@@ -15,6 +15,7 @@ import { getConfigPath } from './app-paths.js';
|
|
|
15
15
|
import { setHistoryEnabled } from './prompt-history.js';
|
|
16
16
|
import { setEntryRetain } from '../agent/entry-limits.js';
|
|
17
17
|
import { readSubmitCount } from './ui-state.js';
|
|
18
|
+
import { resolveGovernanceConfig, resolveInitialPosture } from './governance-config.js';
|
|
18
19
|
import { getLogger } from '../logging/logger.js';
|
|
19
20
|
import { registerSecret, registerSecretsFrom } from '../logging/secret-registry.js';
|
|
20
21
|
import { detectCapabilities, resolveTuiCapabilities } from '../ui/capabilities.js';
|
|
@@ -710,6 +711,28 @@ export function loadConfig(flags = {}, options = {}) {
|
|
|
710
711
|
// `viewReducer` is pure and takes no config, so the resolved ring cap reaches
|
|
711
712
|
// it through the same module-singleton channel `setHistoryEnabled` uses.
|
|
712
713
|
setEntryRetain(transcriptRetain);
|
|
714
|
+
// Governance: file < env (kill switch) < `--no-governance`, clamped like every section. The
|
|
715
|
+
// initial posture is resolved against the SAME team value the config carries, and a request
|
|
716
|
+
// that cannot be honoured degrades to the classic posture with a log record, never silently.
|
|
717
|
+
const governance = resolveGovernanceConfig({
|
|
718
|
+
file: file.governance,
|
|
719
|
+
env: env.partial.governance,
|
|
720
|
+
disableForLaunch: flags.governance === false,
|
|
721
|
+
});
|
|
722
|
+
const team = resolveTeamConfig(flags, env.partial, file);
|
|
723
|
+
const posture = resolveInitialPosture({
|
|
724
|
+
govern: flags.govern,
|
|
725
|
+
planGovern: flags.planGovern,
|
|
726
|
+
startInPlanMode,
|
|
727
|
+
governance,
|
|
728
|
+
teamEnabled: team.enabled,
|
|
729
|
+
});
|
|
730
|
+
const initialPosture = posture.posture;
|
|
731
|
+
if (posture.degradedReason !== undefined) {
|
|
732
|
+
getLogger().warn('config', 'governance_initial_posture_degraded', {
|
|
733
|
+
reason: posture.degradedReason,
|
|
734
|
+
});
|
|
735
|
+
}
|
|
713
736
|
const config = {
|
|
714
737
|
modelProfiles: projection.issues.length ? undefined : file.modelProfiles,
|
|
715
738
|
provider,
|
|
@@ -768,7 +791,7 @@ export function loadConfig(flags = {}, options = {}) {
|
|
|
768
791
|
: {}),
|
|
769
792
|
},
|
|
770
793
|
log: resolveLogConfig(flags, env.partial, file),
|
|
771
|
-
team
|
|
794
|
+
team,
|
|
772
795
|
todo: resolveTodoConfig(flags, env.partial, file),
|
|
773
796
|
retry: resolveRetryConfig(flags, env.partial, file),
|
|
774
797
|
fast: resolveFastConfig(flags, env.partial, file),
|
|
@@ -790,6 +813,8 @@ export function loadConfig(flags = {}, options = {}) {
|
|
|
790
813
|
// `taskSummary.enabled: false` cannot arrive as two different shapes.
|
|
791
814
|
taskSummary: clampTaskSummaryConfig({ ...DEFAULT_CONFIG.taskSummary,
|
|
792
815
|
...(env.partial.taskSummary ?? {}), ...(file.taskSummary ?? {}) }),
|
|
816
|
+
governance,
|
|
817
|
+
initialPosture,
|
|
793
818
|
cwd,
|
|
794
819
|
color,
|
|
795
820
|
colorLevel,
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { type ModelProfilesConfig, type ModelRole, type ProfileValidationIssue } from './model-profiles.js';
|
|
2
2
|
import type { SessionKitState } from './model-kits.js';
|
|
3
|
-
import type { CliConfig, CompactionConfig, FastConfig, LogConfig, PersistedConfig, TeamConfig } from './schema.js';
|
|
4
|
-
export interface ModelSettingsPatch extends Partial<Omit<PersistedConfig, 'modelProfiles' | 'fast' | 'compaction' | 'log' | 'team'>> {
|
|
3
|
+
import type { CliConfig, CompactionConfig, FastConfig, GovernanceConfig, LogConfig, PersistedConfig, TeamConfig } from './schema.js';
|
|
4
|
+
export interface ModelSettingsPatch extends Partial<Omit<PersistedConfig, 'modelProfiles' | 'fast' | 'compaction' | 'log' | 'team' | 'governance'>> {
|
|
5
5
|
fast?: Partial<FastConfig>;
|
|
6
6
|
compaction?: Partial<CompactionConfig>;
|
|
7
7
|
log?: Partial<LogConfig>;
|
|
8
8
|
/** The subagent-model picker writes here (subagent-model D-5/I-5): draft-only until Save. */
|
|
9
9
|
team?: Partial<TeamConfig>;
|
|
10
|
+
/** Governance writers (`config set`, `/gov budget`) send single keys; the store clamps. */
|
|
11
|
+
governance?: Partial<GovernanceConfig>;
|
|
10
12
|
}
|
|
11
13
|
export interface ModelSettingsDraft {
|
|
12
14
|
profiles?: ModelProfilesConfig;
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { type RetryPolicy, type ThinkingLevel } from '@aragon-agent/core';
|
|
9
9
|
import { type LogLevelName } from '../logging/levels.js';
|
|
10
|
+
import { type GovernanceConfig } from './governance-config.js';
|
|
11
|
+
import type { Posture } from '../governance/posture.js';
|
|
10
12
|
import type { FollowThroughMode } from '../todo/types.js';
|
|
13
|
+
export { clampGovernanceConfig, DEFAULT_GOVERNANCE_CONFIG, type GovernanceConfig, } from './governance-config.js';
|
|
11
14
|
/**
|
|
12
15
|
* `ModelRegistry` seeds builtin lists for five providers, but `initProviders()`
|
|
13
16
|
* registers only three adapters. Running a model whose provider has no adapter
|
|
@@ -1146,6 +1149,8 @@ export interface PersistedConfig {
|
|
|
1146
1149
|
prompts: PromptsConfig;
|
|
1147
1150
|
/** The header task label. The THIRTEENTH; two scalars (see TaskSummaryConfig). */
|
|
1148
1151
|
taskSummary: TaskSummaryConfig;
|
|
1152
|
+
/** Governance mode. The FOURTEENTH; scalars only (see GovernanceConfig). */
|
|
1153
|
+
governance: GovernanceConfig;
|
|
1149
1154
|
}
|
|
1150
1155
|
export declare const DEFAULT_CONFIG: PersistedConfig;
|
|
1151
1156
|
/**
|
|
@@ -1534,6 +1539,23 @@ export interface CliConfig {
|
|
|
1534
1539
|
* switched-off feature.
|
|
1535
1540
|
*/
|
|
1536
1541
|
taskSummary?: TaskSummaryConfig;
|
|
1542
|
+
/**
|
|
1543
|
+
* Governance mode (governance-mode 11.1). The FOURTEENTH nested object; scalars only.
|
|
1544
|
+
*
|
|
1545
|
+
* OPTIONAL HERE FOR THE SAME REASON AS `prompts` / `taskSummary` ABOVE: `CliConfig` is built
|
|
1546
|
+
* by hand in many fixtures, `loadConfig` always fills it, and readers treat a missing
|
|
1547
|
+
* section as the documented defaults. `enabled` here (after env kill switch and
|
|
1548
|
+
* `--no-governance`) decides whether governance tools are REGISTERED, once at construction.
|
|
1549
|
+
*/
|
|
1550
|
+
governance?: GovernanceConfig;
|
|
1551
|
+
/**
|
|
1552
|
+
* The posture the session starts in (governance-mode 11.2): `--plan` / `planModeDefault`
|
|
1553
|
+
* still decide `startInPlanMode` exactly as before, and `--govern` / `--plan-govern` win over
|
|
1554
|
+
* them when governance is available. Optional on this shape for the fixture reason above;
|
|
1555
|
+
* `loadConfig` always fills it. Without a governance flag it is `'plan'` when
|
|
1556
|
+
* `startInPlanMode`, else `'build'`.
|
|
1557
|
+
*/
|
|
1558
|
+
initialPosture?: Posture;
|
|
1537
1559
|
/**
|
|
1538
1560
|
* Lifetime submit count driving the composer hint fade (`HINT_FADE_AFTER`).
|
|
1539
1561
|
*
|
package/dist/config/schema.js
CHANGED
|
@@ -9,6 +9,9 @@ import { isAbsolute } from 'node:path';
|
|
|
9
9
|
import { ABSOLUTE_MAX_OUTPUT_TOKENS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_RETRY_POLICY, MIN_MAX_OUTPUT_TOKENS, RETRY_LIMITS, } from '@aragon-agent/core';
|
|
10
10
|
import { clampLogLevel } from '../logging/levels.js';
|
|
11
11
|
import { TEAM_LIMITS } from '../team/limits.js';
|
|
12
|
+
import { DEFAULT_GOVERNANCE_CONFIG } from './governance-config.js';
|
|
13
|
+
// Governance mode (governance-mode 11.1): defined in its own file so this one does not grow.
|
|
14
|
+
export { clampGovernanceConfig, DEFAULT_GOVERNANCE_CONFIG, } from './governance-config.js';
|
|
12
15
|
// ---------------------------------------------------------------------------
|
|
13
16
|
// Provider set — only the adapter-backed providers are usable at run time (R5).
|
|
14
17
|
// ---------------------------------------------------------------------------
|
|
@@ -1194,6 +1197,9 @@ export const DEFAULT_CONFIG = {
|
|
|
1194
1197
|
// `config list`, so the file would report a section it never wrote. One line
|
|
1195
1198
|
// here, like the seven above it.
|
|
1196
1199
|
taskSummary: DEFAULT_TASK_SUMMARY_CONFIG,
|
|
1200
|
+
// And one section later again. Without this line a `config.json` predating governance
|
|
1201
|
+
// resolves `governance` to `undefined`; every reader would then disagree with `config list`.
|
|
1202
|
+
governance: DEFAULT_GOVERNANCE_CONFIG,
|
|
1197
1203
|
};
|
|
1198
1204
|
/**
|
|
1199
1205
|
* Runtime state that used to be stored in `config.json` by mistake
|
package/dist/config/store.js
CHANGED
|
@@ -17,7 +17,7 @@ import { getConfigPath, getSessionsDir } from './app-paths.js';
|
|
|
17
17
|
import { registerProfileSecrets, registerSecretsFrom } from '../logging/secret-registry.js';
|
|
18
18
|
import { adaptLegacyConnectionPatch, ModelProfileConfigError, readModelSettingsDisk } from './model-profile-store.js';
|
|
19
19
|
import { normalizeModelProfiles } from './model-profiles.js';
|
|
20
|
-
import { clampBashConfig, clampJobsConfig, clampPromptsConfig, clampTaskSummaryConfig, CONFIG_VERSION, DEFAULT_CONFIG, clampCompactionConfig, clampFastConfig, clampLogConfig, clampMaxTokens, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampContextWindow, clampUpdateConfig, isAutoToken, stripLegacyStateKeys, stripRetiredConfigKeys, } from './schema.js';
|
|
20
|
+
import { clampBashConfig, clampJobsConfig, clampPromptsConfig, clampTaskSummaryConfig, CONFIG_VERSION, DEFAULT_CONFIG, clampCompactionConfig, clampFastConfig, clampGovernanceConfig, clampLogConfig, clampMaxTokens, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampContextWindow, clampUpdateConfig, isAutoToken, stripLegacyStateKeys, stripRetiredConfigKeys, } from './schema.js';
|
|
21
21
|
/**
|
|
22
22
|
* Normalize `maxTokens` for both directions of the config file.
|
|
23
23
|
*
|
|
@@ -213,6 +213,13 @@ export function normalizePersistedConfig(input) {
|
|
|
213
213
|
...DEFAULT_CONFIG.taskSummary,
|
|
214
214
|
...(partial.taskSummary ?? {}),
|
|
215
215
|
}),
|
|
216
|
+
// And the fourteenth. The READ half supplies a whole section to every user whose
|
|
217
|
+
// `config.json` predates governance, and clamps a hand-edited one: the file cannot
|
|
218
|
+
// carry a `maxRework` the engine would refuse.
|
|
219
|
+
governance: clampGovernanceConfig({
|
|
220
|
+
...DEFAULT_CONFIG.governance,
|
|
221
|
+
...(partial.governance ?? {}),
|
|
222
|
+
}),
|
|
216
223
|
};
|
|
217
224
|
}
|
|
218
225
|
/**
|
|
@@ -334,6 +341,12 @@ export function mergePersistedConfig(current, patch) {
|
|
|
334
341
|
// that must never happen is a FAILED summary call landing on "show nothing"
|
|
335
342
|
// because a switch the user never touched defaulted away.
|
|
336
343
|
taskSummary: clampTaskSummaryConfig({ ...current.taskSummary, ...(patch.taskSummary ?? {}) }),
|
|
344
|
+
// The fourteenth section, and the ninth time this file records the same trap.
|
|
345
|
+
// `aragon config set governance.maxRework 9` sends `{ governance: { maxRework: 9 } }`;
|
|
346
|
+
// without this merge the shallow spread REPLACES the section and `enabled` is written
|
|
347
|
+
// absent, and without the clamp 9 reaches the disk and the engine's ceiling is the
|
|
348
|
+
// only thing that stops it. The WRITE half of the two-direction gate.
|
|
349
|
+
governance: clampGovernanceConfig({ ...current.governance, ...(patch.governance ?? {}) }),
|
|
337
350
|
};
|
|
338
351
|
return merged;
|
|
339
352
|
}
|
|
@@ -105,6 +105,14 @@ export interface UiState {
|
|
|
105
105
|
* and a boolean could only ever say "shown", never "shown WHAT".
|
|
106
106
|
*/
|
|
107
107
|
promptKeyNoticeVersion: number;
|
|
108
|
+
/**
|
|
109
|
+
* Whether the one-time GOVERN explainer has been shown (governance-mode 4.3). A boolean is
|
|
110
|
+
* enough here, unlike the notices above: the sentence has never been reworded, so there is
|
|
111
|
+
* no audience of "already shown the OLD text" to reach. Like them it is a new scalar rather
|
|
112
|
+
* than a schema bump (which would reset every user's `submitCount`), and an older file reads
|
|
113
|
+
* it as `false`, which is exactly the first-run behaviour wanted.
|
|
114
|
+
*/
|
|
115
|
+
governanceIntroSeen: boolean;
|
|
108
116
|
}
|
|
109
117
|
/** Read the state, caching it for the life of the process. Never throws. */
|
|
110
118
|
export declare function loadUiState(): UiState;
|
|
@@ -125,6 +133,9 @@ export declare function setScrollModeNoticeVersion(version: number): void;
|
|
|
125
133
|
/** `0` on a file written before the field existed; see the field's comment. */
|
|
126
134
|
export declare function getPromptKeyNoticeVersion(): number;
|
|
127
135
|
export declare function setPromptKeyNoticeVersion(version: number): void;
|
|
136
|
+
/** `false` until the one-time GOVERN explainer has been shown; persisted across launches. */
|
|
137
|
+
export declare function getGovernanceIntroSeen(): boolean;
|
|
138
|
+
export declare function setGovernanceIntroSeen(seen: boolean): void;
|
|
128
139
|
/**
|
|
129
140
|
* Migration-only: fill in fields that are still at their default, and never
|
|
130
141
|
* overwrite a value already here. A second import — after a half-finished
|
package/dist/config/ui-state.js
CHANGED
|
@@ -39,6 +39,7 @@ const DEFAULT_UI_STATE = {
|
|
|
39
39
|
vtInputNoticeVersion: 0,
|
|
40
40
|
scrollModeNoticeVersion: 0,
|
|
41
41
|
promptKeyNoticeVersion: 0,
|
|
42
|
+
governanceIntroSeen: false,
|
|
42
43
|
};
|
|
43
44
|
let memory = null;
|
|
44
45
|
/** Non-negative integer or `fallback`; shared by both numeric fields. */
|
|
@@ -73,6 +74,9 @@ function readFromDisk() {
|
|
|
73
74
|
vtInputNoticeVersion: coerceCount(parsed.vtInputNoticeVersion, DEFAULT_UI_STATE.vtInputNoticeVersion),
|
|
74
75
|
scrollModeNoticeVersion: coerceCount(parsed.scrollModeNoticeVersion, DEFAULT_UI_STATE.scrollModeNoticeVersion),
|
|
75
76
|
promptKeyNoticeVersion: coerceCount(parsed.promptKeyNoticeVersion, DEFAULT_UI_STATE.promptKeyNoticeVersion),
|
|
77
|
+
governanceIntroSeen: typeof parsed.governanceIntroSeen === 'boolean'
|
|
78
|
+
? parsed.governanceIntroSeen
|
|
79
|
+
: DEFAULT_UI_STATE.governanceIntroSeen,
|
|
76
80
|
};
|
|
77
81
|
}
|
|
78
82
|
catch {
|
|
@@ -160,6 +164,13 @@ export function getPromptKeyNoticeVersion() {
|
|
|
160
164
|
export function setPromptKeyNoticeVersion(version) {
|
|
161
165
|
update({ promptKeyNoticeVersion: version });
|
|
162
166
|
}
|
|
167
|
+
/** `false` until the one-time GOVERN explainer has been shown; persisted across launches. */
|
|
168
|
+
export function getGovernanceIntroSeen() {
|
|
169
|
+
return loadUiState().governanceIntroSeen;
|
|
170
|
+
}
|
|
171
|
+
export function setGovernanceIntroSeen(seen) {
|
|
172
|
+
update({ governanceIntroSeen: seen });
|
|
173
|
+
}
|
|
163
174
|
/**
|
|
164
175
|
* Migration-only: fill in fields that are still at their default, and never
|
|
165
176
|
* overwrite a value already here. A second import — after a half-finished
|
|
@@ -16,6 +16,8 @@ import process from 'node:process';
|
|
|
16
16
|
import { initProviders, ModelRegistry } from '@aragon-agent/core';
|
|
17
17
|
import { getHomeResolutionWarning, getSessionsDir, getUserDataDir } from '../config/app-paths.js';
|
|
18
18
|
import { readConfigFile } from '../config/store.js';
|
|
19
|
+
import { describeGovernanceConfigAvailability, } from '../config/governance-config.js';
|
|
20
|
+
import { unavailableReasonText } from '../governance/copy.js';
|
|
19
21
|
import { loadConfig, makeGetApiKey } from '../config/load.js';
|
|
20
22
|
import { isAdapterProvider, toRetryPolicy } from '../config/schema.js';
|
|
21
23
|
import { MODE_TOGGLE_KEYS } from '../agent/agent-mode.js';
|
|
@@ -28,6 +30,7 @@ export async function runDoctorChecks(flags, opts = {}) {
|
|
|
28
30
|
checks.push(checkModel(config));
|
|
29
31
|
checks.push(checkSessionsDir());
|
|
30
32
|
checks.push(checkValidationStrength());
|
|
33
|
+
checks.push(checkGovernance(config));
|
|
31
34
|
if (opts.probe)
|
|
32
35
|
checks.push(await probeProvider(config));
|
|
33
36
|
return { ok: checks.every((c) => c.verdict !== 'fail'), checks };
|
|
@@ -64,6 +67,23 @@ function checkValidationStrength() {
|
|
|
64
67
|
return pass('ajv', 'absent: required/properties/items/additionalProperties are still enforced by the ' +
|
|
65
68
|
'built-in validator; pattern/format/multipleOf are not');
|
|
66
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* `governance: ready | unavailable (<reason>)` (governance-mode 13.2) - a `pass` either way.
|
|
72
|
+
*
|
|
73
|
+
* An unavailable feature is a CHOICE (a config key, `ARAGON_GOVERNANCE=0`, team mode off),
|
|
74
|
+
* not a defect, so it must not warn or move the exit code; the row exists so "why does
|
|
75
|
+
* Shift+Tab not reach GOVERN" has an answer next to the other install facts. Config-level
|
|
76
|
+
* reasons only: a missing API key is already reported by the `api-key` row, and the runtime
|
|
77
|
+
* reasons (`headless`, `restart_required`) are not properties of an installation.
|
|
78
|
+
* The sentences come from `governance/copy.ts`, the one definition `/gov` and the settings
|
|
79
|
+
* screen share.
|
|
80
|
+
*/
|
|
81
|
+
function checkGovernance(config) {
|
|
82
|
+
const availability = describeGovernanceConfigAvailability(config, process.env);
|
|
83
|
+
if (availability.ok)
|
|
84
|
+
return pass('governance', 'ready');
|
|
85
|
+
return pass('governance', `unavailable (${unavailableReasonText(availability.reason)})`);
|
|
86
|
+
}
|
|
67
87
|
function pass(name, detail) {
|
|
68
88
|
return { name, verdict: 'pass', detail, remedy: '' };
|
|
69
89
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `normalizeGovernanceCard` - turn an untrusted value (a session file, a hand-edited
|
|
3
|
+
* `entries` array) into a renderable `GovernanceCardData`, or `null` (section 10.4).
|
|
4
|
+
*
|
|
5
|
+
* Pure: no React, no I/O. ASCII ONLY.
|
|
6
|
+
*
|
|
7
|
+
* LENIENT BY DESIGN. A governance card is HISTORY: a resume that refuses because one row
|
|
8
|
+
* carried a string where a number belongs would throw away a conversation to protect a
|
|
9
|
+
* footnote (`validate-session.ts` makes the same argument for the todo card). So:
|
|
10
|
+
* unknown fields are dropped, a malformed ROW is dropped, a missing text field degrades
|
|
11
|
+
* to an empty string, and only a value that is not a card at all (not an object, no
|
|
12
|
+
* recognisable variant, nothing left to draw) returns `null` - which the caller turns into
|
|
13
|
+
* a one-line text entry.
|
|
14
|
+
*/
|
|
15
|
+
import type { GovernanceCardData } from './types.js';
|
|
16
|
+
/** The one line a card degrades to when nothing of it can be drawn. */
|
|
17
|
+
export declare const GOVERNANCE_CARD_FALLBACK_TEXT = "Governance card unavailable";
|
|
18
|
+
/** Bounds so a corrupt file cannot make a card taller than the transcript can hold. */
|
|
19
|
+
export declare const CARD_LIMITS: {
|
|
20
|
+
readonly rows: 24;
|
|
21
|
+
readonly notes: 12;
|
|
22
|
+
readonly textChars: 400;
|
|
23
|
+
};
|
|
24
|
+
export declare function normalizeGovernanceCard(value: unknown): GovernanceCardData | null;
|