@aragon-agent/cli 0.6.43 → 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/proc/kill-tree.d.ts +19 -1
- package/dist/proc/kill-tree.js +32 -5
- package/dist/proc/limits.d.ts +19 -0
- package/dist/proc/limits.js +19 -0
- package/dist/proc/supervisor.js +8 -1
- 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/bounded-spawn.d.ts +56 -0
- package/dist/tools/bounded-spawn.js +76 -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/tools/search-tools.js +52 -44
- 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/ScrollbackShell.d.ts +35 -7
- package/dist/ui/ScrollbackShell.js +1 -1
- 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/LiveTail.d.ts +3 -1
- package/dist/ui/scrollback/budget.d.ts +12 -6
- package/dist/ui/scrollback/budget.js +11 -4
- package/dist/ui/scrollback/live-preview.js +2 -0
- package/dist/ui/scrollback/settled-boundary.js +3 -0
- package/dist/ui/scrollback/tail-anchor.d.ts +5 -2
- package/dist/ui/scrollback/tail-anchor.js +3 -1
- 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
|
@@ -47,7 +47,7 @@ export function allKeyRows(times) {
|
|
|
47
47
|
// product's word for transcript line offset (the header chip and the row below),
|
|
48
48
|
// so abbreviating the mode fallback would put two meanings of `^` on one screen
|
|
49
49
|
// (quick-prompt-library D-1 / P1-7).
|
|
50
|
-
['Shift+Tab / Ctrl+N', '
|
|
50
|
+
['Shift+Tab / Ctrl+N', 'Cycle BUILD / PLAN / GOVERN / PLAN+GOVERN (/plan and /gov pick one)'],
|
|
51
51
|
['Ctrl+P', 'Quick prompt library: manage, create, reorder, pick'],
|
|
52
52
|
// The ladder clears a draft first (ctrl-c-clear-draft-exit):
|
|
53
53
|
// with a draft x2 clears the input and x3 exits; an empty input
|
|
@@ -117,7 +117,8 @@ const COMMANDS = [
|
|
|
117
117
|
['/task refresh', 'Regenerate the header task summary from the last prompt'],
|
|
118
118
|
['/model', 'Open the model picker'],
|
|
119
119
|
['/settings', 'Open the settings screen'],
|
|
120
|
-
['/plan [on|off|status]', 'Toggle plan mode (
|
|
120
|
+
['/plan [on|off|status]', 'Toggle plan mode (leaves GOVERN)'],
|
|
121
|
+
['/gov [on|plan|off|board|status]', 'Governed team: enter, leave, the board, the run status'],
|
|
121
122
|
['/theme <name>', 'auto | warm | cool | light'],
|
|
122
123
|
['/thinking <level>', 'Set thinking level'],
|
|
123
124
|
['/max-tokens [n|auto]', 'Output token cap; no argument reports the effective one'],
|
|
@@ -165,7 +166,7 @@ const SKILL_ROWS = [
|
|
|
165
166
|
['skill / skill_install', 'Tools the model uses to load and install skills'],
|
|
166
167
|
];
|
|
167
168
|
const PLAN_ROWS = [
|
|
168
|
-
['Shift+Tab / /plan', 'Switch
|
|
169
|
+
['Shift+Tab / /plan', 'Switch BUILD (do it now) and PLAN (research first); Shift+Tab also cycles GOVERN'],
|
|
169
170
|
// A ROW OF ITS OWN, not a third name on the line above: the reader who needs
|
|
170
171
|
// this one is the reader whose `Shift+Tab` does nothing, and what they need is
|
|
171
172
|
// the reason, not another synonym. Listing the key in both places instead just
|
|
@@ -26,6 +26,14 @@ interface QuestionOverlayProps {
|
|
|
26
26
|
theme: Theme;
|
|
27
27
|
caps: TermCapabilities;
|
|
28
28
|
onSubmit: (answers: Answer[]) => void;
|
|
29
|
+
/**
|
|
30
|
+
* PLAN+GOVERN interview progress (governance-mode 9 / 10.6). Present only in that
|
|
31
|
+
* posture; absent leaves the title byte-identical to the pre-governance overlay.
|
|
32
|
+
*/
|
|
33
|
+
interview?: {
|
|
34
|
+
round: number;
|
|
35
|
+
required: number;
|
|
36
|
+
};
|
|
29
37
|
}
|
|
30
|
-
export declare function QuestionOverlay({ isActive, questions, maxRows, cols, theme, caps, onSubmit, }: QuestionOverlayProps): React.ReactElement;
|
|
38
|
+
export declare function QuestionOverlay({ isActive, questions, maxRows, cols, theme, caps, onSubmit, interview, }: QuestionOverlayProps): React.ReactElement;
|
|
31
39
|
export {};
|
|
@@ -22,6 +22,7 @@ import { wrapToRows } from '../layout/wrap-rows.js';
|
|
|
22
22
|
import { OverlayFrame, overlayBodyRows } from '../layout/OverlayFrame.js';
|
|
23
23
|
import { stripPasteFrames } from '../paste-frames.js';
|
|
24
24
|
import { stripEnterFrames } from '../enter-frames.js';
|
|
25
|
+
import { interviewChipText } from '../governance-status.js';
|
|
25
26
|
/** Which option index each question starts on: the recommended one. */
|
|
26
27
|
function initialCursors(questions) {
|
|
27
28
|
return questions.map((q) => Math.max(0, q.options.findIndex((o) => o.recommended)));
|
|
@@ -32,7 +33,7 @@ function initialSelections(questions) {
|
|
|
32
33
|
return new Set(recommended >= 0 ? [recommended] : [0]);
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
|
-
export function QuestionOverlay({ isActive = true, questions, maxRows, cols, theme, caps, onSubmit, }) {
|
|
36
|
+
export function QuestionOverlay({ isActive = true, questions, maxRows, cols, theme, caps, onSubmit, interview, }) {
|
|
36
37
|
const glyphs = pickGlyphs(caps);
|
|
37
38
|
const [step, setStep] = useState(0);
|
|
38
39
|
const [phase, setPhase] = useState('choosing');
|
|
@@ -215,6 +216,7 @@ export function QuestionOverlay({ isActive = true, questions, maxRows, cols, the
|
|
|
215
216
|
});
|
|
216
217
|
const title = phase === 'review' ? 'Review your answers' : 'Clarify the request';
|
|
217
218
|
const position = phase === 'review' ? '' : ` ${step + 1}/${questions.length}`;
|
|
219
|
+
const interviewChip = interview ? ` ${interviewChipText(interview.round, interview.required)}` : '';
|
|
218
220
|
const hint = phase === 'typingOther'
|
|
219
221
|
? `type your answer ${glyphs.midDot} ${glyphs.enterKey} commit ${glyphs.midDot} ${glyphs.arrowLeft} back ${glyphs.midDot} esc cancel`
|
|
220
222
|
: phase === 'review'
|
|
@@ -252,5 +254,5 @@ export function QuestionOverlay({ isActive = true, questions, maxRows, cols, the
|
|
|
252
254
|
const shortHint = phase === 'typingOther' ? 'Enter commit | Left back | Esc cancel'
|
|
253
255
|
: phase === 'review' ? 'Enter submit | Left back | Esc cancel'
|
|
254
256
|
: '^v choose Space select Enter next Esc';
|
|
255
|
-
return _jsx(OverlayFrame, { title: `${title}${position}`, hint: cols <= 48 ? shortHint : hint, maxRows: maxRows, cols: cols, theme: theme, caps: caps, rows: rowTexts.map((line, index) => _jsx(Text, { wrap: "truncate", children: line || ' ' }, index)), scrollOffset: offset, onScrollClamp: setOffset });
|
|
257
|
+
return _jsx(OverlayFrame, { title: `${title}${position}${interviewChip}`, hint: cols <= 48 ? shortHint : hint, maxRows: maxRows, cols: cols, theme: theme, caps: caps, rows: rowTexts.map((line, index) => _jsx(Text, { wrap: "truncate", children: line || ' ' }, index)), scrollOffset: offset, onScrollClamp: setOffset });
|
|
256
258
|
}
|
|
@@ -146,6 +146,13 @@ interface SettingsScreenProps {
|
|
|
146
146
|
* literal, and absent honestly means "unknown, so do not disclose".
|
|
147
147
|
*/
|
|
148
148
|
teamRegistered?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Whether the governance tools were registered when this session started
|
|
151
|
+
* (governance-mode-v1-1 5.2). Same contract as `teamRegistered`: a CONSTRUCTION-TIME
|
|
152
|
+
* snapshot, OPTIONAL, and `undefined` means "not disclosed" so no note is shown. It is
|
|
153
|
+
* what lets the page say `applies next launch` when the draft's `enabled` disagrees.
|
|
154
|
+
*/
|
|
155
|
+
governanceRegistered?: boolean;
|
|
149
156
|
}
|
|
150
157
|
/**
|
|
151
158
|
* The derived, non-editable line under the five fast rows — the sibling of
|
|
@@ -29,6 +29,8 @@ import { KitEditor } from './KitEditor.js';
|
|
|
29
29
|
import { KitManager } from './KitManager.js';
|
|
30
30
|
import { TeamFanoutPage } from './TeamFanoutPage.js';
|
|
31
31
|
import { fanoutRows, teamFanoutValues, teamSummary } from './team-fanout-state.js';
|
|
32
|
+
import { GovernanceSettingsPage } from './GovernanceSettingsPage.js';
|
|
33
|
+
import { draftGovernance, governanceRestartNote, governanceSettingRows, governanceSummary, } from './governance-settings.js';
|
|
32
34
|
import { heldSlots, kitManagerRows, kitPackRow, kitReducer } from './kit-settings-state.js';
|
|
33
35
|
/**
|
|
34
36
|
* THE ROOT PAGE'S ROW INDEXES, AS NAMES (subagent-model V-5).
|
|
@@ -42,7 +44,7 @@ import { heldSlots, kitManagerRows, kitPackRow, kitReducer } from './kit-setting
|
|
|
42
44
|
* fifth of these and the "five offsets agreed by accident" defect does not need
|
|
43
45
|
* a sequel. Order here IS the render order.
|
|
44
46
|
*/
|
|
45
|
-
const ROOT_ROWS = ['main', 'fast', 'subagent', 'team', 'kit', 'manage'];
|
|
47
|
+
const ROOT_ROWS = ['main', 'fast', 'subagent', 'team', 'governance', 'kit', 'manage'];
|
|
46
48
|
const ROOT_MAIN = ROOT_ROWS.indexOf('main');
|
|
47
49
|
const ROOT_FAST = ROOT_ROWS.indexOf('fast');
|
|
48
50
|
const ROOT_SUBAGENT = ROOT_ROWS.indexOf('subagent');
|
|
@@ -51,6 +53,9 @@ const ROOT_SUBAGENT = ROOT_ROWS.indexOf('subagent');
|
|
|
51
53
|
// one decision, and splitting them across the page would make the pair harder to
|
|
52
54
|
// keep consistent than the pair of numbers inside it.
|
|
53
55
|
const ROOT_TEAM = ROOT_ROWS.indexOf('team');
|
|
56
|
+
// Governance (governance-mode-v1-1 5.2) sits right under Team: both decide the SHAPE of the
|
|
57
|
+
// team, and the row is an index into this list like every other, never a typed number.
|
|
58
|
+
const ROOT_GOVERNANCE = ROOT_ROWS.indexOf('governance');
|
|
54
59
|
const ROOT_KIT = ROOT_ROWS.indexOf('kit');
|
|
55
60
|
const ROOT_MANAGE = ROOT_ROWS.indexOf('manage');
|
|
56
61
|
const ROOT_FIRST_FIELD = ROOT_ROWS.length;
|
|
@@ -693,6 +698,12 @@ function activateRootSetting(props, view) {
|
|
|
693
698
|
// `team-fanout-page.test.tsx` asserts that Enter on this row saves nothing.
|
|
694
699
|
dispatch({ type: 'page', page: 'team' });
|
|
695
700
|
}
|
|
701
|
+
else if (index === ROOT_GOVERNANCE) {
|
|
702
|
+
// SAME RULE AS THE TEAM BRANCH ABOVE, and the same cost of getting it wrong: this MUST
|
|
703
|
+
// stay above the fallback `else`, which is `saveProfileSettings`. A misplaced branch
|
|
704
|
+
// compiles and silently commits the whole draft when Enter opens the page.
|
|
705
|
+
dispatch({ type: 'page', page: 'governance' });
|
|
706
|
+
}
|
|
696
707
|
else if (index === ROOT_KIT) {
|
|
697
708
|
// The fifth root row opens the manager, not a picker: kits are data the user
|
|
698
709
|
// owns here, and `ctrl+K` is where they are CONSUMED (agent-model-kits §4.5).
|
|
@@ -858,6 +869,14 @@ function renderProfileSubpage(props, view) {
|
|
|
858
869
|
rows: fanoutRows(teamFanoutValues(state.draft), props.teamRegistered),
|
|
859
870
|
error: state.error,
|
|
860
871
|
}, dispatch: dispatch, onBack: () => dispatch({ type: 'page', page: 'root' }) });
|
|
872
|
+
if (state.page === 'governance') {
|
|
873
|
+
const config = draftGovernance(state.draft);
|
|
874
|
+
return _jsx(GovernanceSettingsPage, { ...props, view: {
|
|
875
|
+
rows: governanceSettingRows(config),
|
|
876
|
+
error: state.error,
|
|
877
|
+
restartNote: governanceRestartNote(config.enabled, props.governanceRegistered),
|
|
878
|
+
}, dispatch: dispatch, onBack: () => dispatch({ type: 'page', page: 'root' }) });
|
|
879
|
+
}
|
|
861
880
|
// THE KIT PAGES (agent-model-kits §4.5). They are dispatched BEFORE the profile
|
|
862
881
|
// pages because `'kit-slot'` RENDERS a profile picker while belonging to the
|
|
863
882
|
// kit editor - the page name, not the component, decides where the user is.
|
|
@@ -982,6 +1001,7 @@ function buildRootSettingsRows(props, view) {
|
|
|
982
1001
|
// four values, only two of which are about fan-out width. `padEnd(18)` is
|
|
983
1002
|
// unchanged, so the value column still lines up with `Subagent model`.
|
|
984
1003
|
`Team ${summary}`,
|
|
1004
|
+
`Governance ${governanceSummary(draftGovernance(state.draft))}`,
|
|
985
1005
|
`Kit pack ${kitPackRow(state)}`,
|
|
986
1006
|
`Manage profiles ${library.entries.length} saved`,
|
|
987
1007
|
...fields.map((item) => `${item.label.padEnd(18)}${item.key === 'apiKey'
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings > Governance: the pure half of the page (governance-mode 11.1).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/ui/**` is inside `glyphs.test.ts::inScope`.
|
|
5
|
+
*
|
|
6
|
+
* FIELD DEFINITIONS AND THE ARROW-KEY STEP, NOTHING ELSE. `SettingsScreen.tsx` is far past
|
|
7
|
+
* the size limit, so the page lists its rows from here and adds wiring only, mirroring
|
|
8
|
+
* `team-fanout-state.ts`. Every value a step produces goes back through
|
|
9
|
+
* `clampGovernanceConfig`, so the page, `config set` and a hand-edited `config.json` can
|
|
10
|
+
* never disagree about a range.
|
|
11
|
+
*
|
|
12
|
+
* THE PAGE MAY WRITE THE ELEVEN POLICY KEYS AND NOTHING ELSE. The structural bounds
|
|
13
|
+
* (`GOV_LIMITS`) are not settings: a number a user can tune past what the store and the
|
|
14
|
+
* panel can carry is not a preference, it is a crash.
|
|
15
|
+
*/
|
|
16
|
+
import { type GovernanceConfig } from '../../config/governance-config.js';
|
|
17
|
+
import type { ModelSettingsDraft } from '../../config/model-profile-store.js';
|
|
18
|
+
export type GovernanceSettingKey = keyof GovernanceConfig;
|
|
19
|
+
export type GovernanceSettingKind = 'toggle' | 'number' | 'choice';
|
|
20
|
+
export interface GovernanceSettingDef {
|
|
21
|
+
key: GovernanceSettingKey;
|
|
22
|
+
/** At most 17 columns: the page pads labels to 18, like the Team page. */
|
|
23
|
+
label: string;
|
|
24
|
+
/** One line, at most 60 columns: WHY this setting, not a restatement of the label. */
|
|
25
|
+
description: string;
|
|
26
|
+
kind: GovernanceSettingKind;
|
|
27
|
+
/** Inclusive; numbers only. Read from the clamp, never repeated here. */
|
|
28
|
+
range?: {
|
|
29
|
+
min: number;
|
|
30
|
+
max: number;
|
|
31
|
+
};
|
|
32
|
+
/** Arrow-key increment; numbers only. */
|
|
33
|
+
step?: number;
|
|
34
|
+
/** Cycle order; choices only. */
|
|
35
|
+
choices?: readonly string[];
|
|
36
|
+
}
|
|
37
|
+
/** The rows in cursor order. The switch is first: the rest describe what it turns on. */
|
|
38
|
+
export declare const GOVERNANCE_SETTING_DEFS: readonly GovernanceSettingDef[];
|
|
39
|
+
export interface GovernanceSettingRow {
|
|
40
|
+
key: GovernanceSettingKey;
|
|
41
|
+
label: string;
|
|
42
|
+
/** The value as the page prints it (`'on'` / `'3'` / `'unlimited'`). */
|
|
43
|
+
value: string;
|
|
44
|
+
/** Description plus the range, one line. */
|
|
45
|
+
hint: string;
|
|
46
|
+
}
|
|
47
|
+
/** The page's rows for the CLAMPED section, so the screen shows what would be saved. */
|
|
48
|
+
export declare function governanceSettingRows(values: unknown): GovernanceSettingRow[];
|
|
49
|
+
/**
|
|
50
|
+
* The PATCH FRAGMENT for one arrow press, for a section the screen already shows
|
|
51
|
+
* (`current`). Exactly one key, so a step can never carry a second one into the draft.
|
|
52
|
+
* Toggles flip on either arrow, as on the Team page: a direction means nothing for two
|
|
53
|
+
* states. An unknown key yields an empty patch rather than throwing.
|
|
54
|
+
*/
|
|
55
|
+
export declare function stepGovernanceSetting(current: unknown, key: GovernanceSettingKey, delta: -1 | 1): Partial<GovernanceConfig>;
|
|
56
|
+
/**
|
|
57
|
+
* The governance section this draft would save: the patch over the disk baseline, then the
|
|
58
|
+
* clamp (governance-mode-v1-1 5.2). Same order as `teamFanoutValues`, and the clamp is not
|
|
59
|
+
* cosmetic: it is what makes the number on screen the number `Ctrl+S` writes, whatever a
|
|
60
|
+
* hand-edited `config.json` or an old patch carried.
|
|
61
|
+
*/
|
|
62
|
+
export declare function draftGovernance(draft: ModelSettingsDraft): GovernanceConfig;
|
|
63
|
+
/**
|
|
64
|
+
* The one-line summary the settings root row prints. A DERIVED row, never a control: the
|
|
65
|
+
* values change on the page Enter opens, so the root row cannot be moved by a stray arrow.
|
|
66
|
+
* `off` alone when the switch is off, because the numbers then describe a capability that
|
|
67
|
+
* is not there (the `teamSummary` rule).
|
|
68
|
+
*/
|
|
69
|
+
export declare function governanceSummary(config: GovernanceConfig): string;
|
|
70
|
+
export type GovernanceRestartNote = string | null;
|
|
71
|
+
/**
|
|
72
|
+
* Whether saving the `enabled` switch would not take effect in THIS session. The tool array
|
|
73
|
+
* is immutable after construction (v1 D-22), so a draft that disagrees with what was
|
|
74
|
+
* registered at launch only applies next launch, and the page says so rather than letting a
|
|
75
|
+
* user believe a toggle summoned `gov_run` into the running session. `undefined` means the
|
|
76
|
+
* host did not say, and the page then discloses nothing (every fixture builds props by
|
|
77
|
+
* literal).
|
|
78
|
+
*/
|
|
79
|
+
export declare function governanceRestartNote(enabledInDraft: boolean, registeredAtLaunch: boolean | undefined): GovernanceRestartNote;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings > Governance: the pure half of the page (governance-mode 11.1).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/ui/**` is inside `glyphs.test.ts::inScope`.
|
|
5
|
+
*
|
|
6
|
+
* FIELD DEFINITIONS AND THE ARROW-KEY STEP, NOTHING ELSE. `SettingsScreen.tsx` is far past
|
|
7
|
+
* the size limit, so the page lists its rows from here and adds wiring only, mirroring
|
|
8
|
+
* `team-fanout-state.ts`. Every value a step produces goes back through
|
|
9
|
+
* `clampGovernanceConfig`, so the page, `config set` and a hand-edited `config.json` can
|
|
10
|
+
* never disagree about a range.
|
|
11
|
+
*
|
|
12
|
+
* THE PAGE MAY WRITE THE ELEVEN POLICY KEYS AND NOTHING ELSE. The structural bounds
|
|
13
|
+
* (`GOV_LIMITS`) are not settings: a number a user can tune past what the store and the
|
|
14
|
+
* panel can carry is not a preference, it is a crash.
|
|
15
|
+
*/
|
|
16
|
+
import { clampGovernanceConfig, governanceRangeOf, } from '../../config/governance-config.js';
|
|
17
|
+
import { PROFILE_IDS } from '../../governance/types.js';
|
|
18
|
+
function numeric(key, label, description, step = 1) {
|
|
19
|
+
return { key, label, description, kind: 'number', range: governanceRangeOf(key), step };
|
|
20
|
+
}
|
|
21
|
+
/** The rows in cursor order. The switch is first: the rest describe what it turns on. */
|
|
22
|
+
export const GOVERNANCE_SETTING_DEFS = [
|
|
23
|
+
{ key: 'enabled', label: 'Governance', kind: 'toggle',
|
|
24
|
+
description: 'Off removes it entirely. Turning it on needs a restart.' },
|
|
25
|
+
{ key: 'shiftTab', label: 'Shift+Tab cycle', kind: 'toggle',
|
|
26
|
+
description: 'Off keeps Shift+Tab on BUILD/PLAN; /gov still works.' },
|
|
27
|
+
{ key: 'panel', label: 'Legion panel', kind: 'toggle',
|
|
28
|
+
description: 'Off shows the status chip only, no panel.' },
|
|
29
|
+
{ key: 'profile', label: 'Profile', kind: 'choice', choices: PROFILE_IDS,
|
|
30
|
+
description: 'Domain wording for the roles and their checklists.' },
|
|
31
|
+
numeric('maxWorkPackages', 'Work packages', 'Most work packages one run may define.'),
|
|
32
|
+
numeric('maxPhases', 'Phases', 'Most dev/review/test rounds one run may take.'),
|
|
33
|
+
numeric('maxRework', 'Rework rounds', 'Rework rounds per work package before escalation.'),
|
|
34
|
+
numeric('maxFixCycles', 'Fix cycles', 'Fix cycles per phase after integration fails.'),
|
|
35
|
+
numeric('minAskRounds', 'Ask rounds', 'Questions PLAN+GOVERN asks before a plan is allowed.'),
|
|
36
|
+
numeric('budgetTokens', 'Token budget', 'Per-run token ceiling; 0 means unlimited.', 100_000),
|
|
37
|
+
{ key: 'confirmCharter', label: 'Confirm charter', kind: 'toggle',
|
|
38
|
+
description: 'On asks you to approve the run plan before any dispatch.' },
|
|
39
|
+
];
|
|
40
|
+
function formatValue(def, config) {
|
|
41
|
+
const value = config[def.key];
|
|
42
|
+
if (def.kind === 'toggle')
|
|
43
|
+
return value ? 'on' : 'off';
|
|
44
|
+
if (def.key === 'budgetTokens')
|
|
45
|
+
return value === 0 ? 'unlimited' : String(value);
|
|
46
|
+
return String(value);
|
|
47
|
+
}
|
|
48
|
+
function formatHint(def) {
|
|
49
|
+
if (def.range === undefined)
|
|
50
|
+
return def.description;
|
|
51
|
+
return `${def.description} (${def.range.min}-${def.range.max})`;
|
|
52
|
+
}
|
|
53
|
+
/** The page's rows for the CLAMPED section, so the screen shows what would be saved. */
|
|
54
|
+
export function governanceSettingRows(values) {
|
|
55
|
+
const config = clampGovernanceConfig(values);
|
|
56
|
+
return GOVERNANCE_SETTING_DEFS.map((def) => ({
|
|
57
|
+
key: def.key,
|
|
58
|
+
label: def.label,
|
|
59
|
+
value: formatValue(def, config),
|
|
60
|
+
hint: formatHint(def),
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
function stepNumber(config, def, delta) {
|
|
64
|
+
const key = def.key;
|
|
65
|
+
// NO WRAPAROUND: a form control is not a ring, and Left at the floor jumping to the
|
|
66
|
+
// ceiling would be a way to raise a limit while trying to lower it. The clamp does it.
|
|
67
|
+
const next = clampGovernanceConfig({ ...config, [key]: config[key] + delta * (def.step ?? 1) });
|
|
68
|
+
return { [key]: next[key] };
|
|
69
|
+
}
|
|
70
|
+
function stepChoice(config, def, delta) {
|
|
71
|
+
const choices = def.choices ?? [];
|
|
72
|
+
const at = choices.indexOf(String(config[def.key]));
|
|
73
|
+
const next = choices[(at + delta + choices.length) % choices.length];
|
|
74
|
+
// Through the clamp, so a choice list that ever drifts from the clamp's vocabulary cannot
|
|
75
|
+
// write a value the read path would silently repair.
|
|
76
|
+
const stored = clampGovernanceConfig({ ...config, [def.key]: next })[def.key];
|
|
77
|
+
return { [def.key]: stored };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The PATCH FRAGMENT for one arrow press, for a section the screen already shows
|
|
81
|
+
* (`current`). Exactly one key, so a step can never carry a second one into the draft.
|
|
82
|
+
* Toggles flip on either arrow, as on the Team page: a direction means nothing for two
|
|
83
|
+
* states. An unknown key yields an empty patch rather than throwing.
|
|
84
|
+
*/
|
|
85
|
+
export function stepGovernanceSetting(current, key, delta) {
|
|
86
|
+
const config = clampGovernanceConfig(current);
|
|
87
|
+
const def = GOVERNANCE_SETTING_DEFS.find((candidate) => candidate.key === key);
|
|
88
|
+
if (def === undefined)
|
|
89
|
+
return {};
|
|
90
|
+
if (def.kind === 'toggle')
|
|
91
|
+
return { [key]: !config[key] };
|
|
92
|
+
return def.kind === 'number' ? stepNumber(config, def, delta) : stepChoice(config, def, delta);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The governance section this draft would save: the patch over the disk baseline, then the
|
|
96
|
+
* clamp (governance-mode-v1-1 5.2). Same order as `teamFanoutValues`, and the clamp is not
|
|
97
|
+
* cosmetic: it is what makes the number on screen the number `Ctrl+S` writes, whatever a
|
|
98
|
+
* hand-edited `config.json` or an old patch carried.
|
|
99
|
+
*/
|
|
100
|
+
export function draftGovernance(draft) {
|
|
101
|
+
return clampGovernanceConfig({ ...draft.baseline.governance, ...draft.patch.governance });
|
|
102
|
+
}
|
|
103
|
+
/** `0` is unlimited; otherwise a compact figure (`500k`, `1.2M`). */
|
|
104
|
+
function budgetText(tokens) {
|
|
105
|
+
if (tokens <= 0)
|
|
106
|
+
return 'unlimited';
|
|
107
|
+
if (tokens >= 1_000_000)
|
|
108
|
+
return `${Number((tokens / 1_000_000).toFixed(1))}M`;
|
|
109
|
+
return `${Math.round(tokens / 1_000)}k`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The one-line summary the settings root row prints. A DERIVED row, never a control: the
|
|
113
|
+
* values change on the page Enter opens, so the root row cannot be moved by a stray arrow.
|
|
114
|
+
* `off` alone when the switch is off, because the numbers then describe a capability that
|
|
115
|
+
* is not there (the `teamSummary` rule).
|
|
116
|
+
*/
|
|
117
|
+
export function governanceSummary(config) {
|
|
118
|
+
if (!config.enabled)
|
|
119
|
+
return 'off';
|
|
120
|
+
return [
|
|
121
|
+
'on',
|
|
122
|
+
`${config.maxWorkPackages} WP`,
|
|
123
|
+
`${config.maxPhases} phases`,
|
|
124
|
+
`rework ${config.maxRework}`,
|
|
125
|
+
`budget ${budgetText(config.budgetTokens)}`,
|
|
126
|
+
].join(' | ');
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Whether saving the `enabled` switch would not take effect in THIS session. The tool array
|
|
130
|
+
* is immutable after construction (v1 D-22), so a draft that disagrees with what was
|
|
131
|
+
* registered at launch only applies next launch, and the page says so rather than letting a
|
|
132
|
+
* user believe a toggle summoned `gov_run` into the running session. `undefined` means the
|
|
133
|
+
* host did not say, and the page then discloses nothing (every fixture builds props by
|
|
134
|
+
* literal).
|
|
135
|
+
*/
|
|
136
|
+
export function governanceRestartNote(enabledInDraft, registeredAtLaunch) {
|
|
137
|
+
if (registeredAtLaunch === undefined || enabledInDraft === registeredAtLaunch)
|
|
138
|
+
return null;
|
|
139
|
+
return 'Governance is registered at launch; this change applies next launch.';
|
|
140
|
+
}
|
|
@@ -4,7 +4,8 @@ import type { ModelSettingsDraft } from '../../config/model-profile-store.js';
|
|
|
4
4
|
import type { SubagentModelMode } from '../../team/model.js';
|
|
5
5
|
import type { KitDraft } from './kit-settings-state.js';
|
|
6
6
|
import { type TeamFanoutField } from './team-fanout-state.js';
|
|
7
|
-
|
|
7
|
+
import { type GovernanceSettingKey } from './governance-settings.js';
|
|
8
|
+
export type ProfilePage = 'root' | 'picker' | 'manager' | 'editor' | 'models' | 'delete-confirm' | 'discard-confirm' | 'kits' | 'kit-edit' | 'kit-slot' | 'kit-delete' | 'team' | 'governance';
|
|
8
9
|
/**
|
|
9
10
|
* `'team'` is the fan-out page (subagent-fanout D-5), and it is a PAGE rather
|
|
10
11
|
* than three more fields on the root page for a measurable reason: the root page
|
|
@@ -118,6 +119,10 @@ export type ModelProfileAction = {
|
|
|
118
119
|
type: 'team-fanout';
|
|
119
120
|
field: TeamFanoutField;
|
|
120
121
|
delta: -1 | 1;
|
|
122
|
+
} | {
|
|
123
|
+
type: 'governance-step';
|
|
124
|
+
key: GovernanceSettingKey;
|
|
125
|
+
delta: -1 | 1;
|
|
121
126
|
};
|
|
122
127
|
/** Keep the original secret separate from the empty replacement field. */
|
|
123
128
|
export declare function createProfileEditor(profile: ModelProfile): ProfileEditorDraft;
|
|
@@ -2,6 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { emptyModelProfiles, duplicateModelProfile, normalizeModelProfiles, validateModelProfiles } from '../../config/model-profiles.js';
|
|
3
3
|
import { parseContextWindowInput } from '../../config/schema.js';
|
|
4
4
|
import { stepFanoutValue, teamFanoutValues } from './team-fanout-state.js';
|
|
5
|
+
import { draftGovernance, stepGovernanceSetting } from './governance-settings.js';
|
|
5
6
|
/** The picker's built-in `Fast tier model` row; never a profile id on disk. */
|
|
6
7
|
export const SUBAGENT_FAST_ROW_ID = '__fast__';
|
|
7
8
|
/** Keep the original secret separate from the empty replacement field. */
|
|
@@ -233,6 +234,15 @@ export function modelProfileReducer(state, action) {
|
|
|
233
234
|
draft: { ...state.draft,
|
|
234
235
|
patch: { ...state.draft.patch, team: { ...state.draft.patch.team, ...step } } } };
|
|
235
236
|
}
|
|
237
|
+
case 'governance-step': {
|
|
238
|
+
// THE FRAGMENT IS THE ONLY THING WRITTEN, as for `team-fanout`: `stepGovernanceSetting`
|
|
239
|
+
// returns exactly one key, clamped, from the value the screen is showing
|
|
240
|
+
// (`draftGovernance`), so a step can never drag a second key into the patch.
|
|
241
|
+
const step = stepGovernanceSetting(draftGovernance(state.draft), action.key, action.delta);
|
|
242
|
+
return { ...state, dirty: true, error: undefined,
|
|
243
|
+
draft: { ...state.draft, patch: { ...state.draft.patch,
|
|
244
|
+
governance: { ...state.draft.patch.governance, ...step } } } };
|
|
245
|
+
}
|
|
236
246
|
case 'duplicate': {
|
|
237
247
|
if (library.entries.length >= 200)
|
|
238
248
|
return { ...state,
|
package/dist/ui/palettes.d.ts
CHANGED
|
@@ -71,6 +71,17 @@ export interface Palette {
|
|
|
71
71
|
fg: string;
|
|
72
72
|
bg: string;
|
|
73
73
|
};
|
|
74
|
+
/**
|
|
75
|
+
* The GOVERN / PLAN+GOVERN posture badge, the legion panel title and the status chip
|
|
76
|
+
* (governance-mode section 10.7).
|
|
77
|
+
*
|
|
78
|
+
* A hue of its own, pinned by `palettes.test.ts`: >= 4.5:1 against THIS palette's own
|
|
79
|
+
* surface and >= 30 degrees away from the six semantic hues it must never be confused
|
|
80
|
+
* with (`primary`, `accent`, `user`, `toolDone`, `noticeWarn`, `noticeError`) - the
|
|
81
|
+
* last four because governance score gains and losses are drawn in `toolDone` /
|
|
82
|
+
* `noticeError` right beside it. The numbers below are the measured starting points.
|
|
83
|
+
*/
|
|
84
|
+
governAccent: string;
|
|
74
85
|
}
|
|
75
86
|
/**
|
|
76
87
|
* The reference dark background these palettes are contrast-checked against.
|
|
@@ -79,6 +90,12 @@ export interface Palette {
|
|
|
79
90
|
* text unreadable.
|
|
80
91
|
*/
|
|
81
92
|
export declare const DARK_SURFACE = "#1c1917";
|
|
93
|
+
/**
|
|
94
|
+
* The reference background of the `LIGHT` palette. `LIGHT` text is dark-on-light, so
|
|
95
|
+
* contrast-checking it against `DARK_SURFACE` would pass a pair that is unreadable in
|
|
96
|
+
* the only place it is ever used (the same trap `selectionBg` documents).
|
|
97
|
+
*/
|
|
98
|
+
export declare const LIGHT_SURFACE = "#ffffff";
|
|
82
99
|
/** Terracotta + amber over warm neutrals — the v0.4.0 default. */
|
|
83
100
|
export declare const WARM: Palette;
|
|
84
101
|
/** The v0.3.0 palette, renamed. Reachable via `--theme cool` / `theme: "dark"`. */
|
package/dist/ui/palettes.js
CHANGED
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
* text unreadable.
|
|
19
19
|
*/
|
|
20
20
|
export const DARK_SURFACE = '#1c1917';
|
|
21
|
+
/**
|
|
22
|
+
* The reference background of the `LIGHT` palette. `LIGHT` text is dark-on-light, so
|
|
23
|
+
* contrast-checking it against `DARK_SURFACE` would pass a pair that is unreadable in
|
|
24
|
+
* the only place it is ever used (the same trap `selectionBg` documents).
|
|
25
|
+
*/
|
|
26
|
+
export const LIGHT_SURFACE = '#ffffff';
|
|
21
27
|
/** Terracotta + amber over warm neutrals — the v0.4.0 default. */
|
|
22
28
|
export const WARM = {
|
|
23
29
|
primary: '#d08c60',
|
|
@@ -46,6 +52,7 @@ export const WARM = {
|
|
|
46
52
|
diff: { add: '#7fb08a', remove: '#cf6b5c', meta: '#d08c60', context: '#a2968a' },
|
|
47
53
|
toast: { info: '#d08c60', warn: '#c9a227', error: '#cf6b5c', success: '#7fb08a' },
|
|
48
54
|
chip: { fg: '#1c1917', bg: '#d08c60' },
|
|
55
|
+
governAccent: '#B79CED',
|
|
49
56
|
};
|
|
50
57
|
/** The v0.3.0 palette, renamed. Reachable via `--theme cool` / `theme: "dark"`. */
|
|
51
58
|
export const COOL = {
|
|
@@ -75,6 +82,7 @@ export const COOL = {
|
|
|
75
82
|
diff: { add: '#9ece6a', remove: '#f7768e', meta: '#7aa2f7', context: '#7a86b8' },
|
|
76
83
|
toast: { info: '#7aa2f7', warn: '#e0af68', error: '#f7768e', success: '#9ece6a' },
|
|
77
84
|
chip: { fg: '#1a1b26', bg: '#7aa2f7' },
|
|
85
|
+
governAccent: '#73DACA',
|
|
78
86
|
};
|
|
79
87
|
export const LIGHT = {
|
|
80
88
|
primary: '#2959aa',
|
|
@@ -103,6 +111,7 @@ export const LIGHT = {
|
|
|
103
111
|
diff: { add: '#2e7d32', remove: '#c62828', meta: '#2959aa', context: '#6b7280' },
|
|
104
112
|
toast: { info: '#2959aa', warn: '#b5730f', error: '#c62828', success: '#2e7d32' },
|
|
105
113
|
chip: { fg: '#ffffff', bg: '#2959aa' },
|
|
114
|
+
governAccent: '#A8327A',
|
|
106
115
|
};
|
|
107
116
|
/**
|
|
108
117
|
* Resolve a theme name to its palette.
|
|
@@ -32,7 +32,9 @@
|
|
|
32
32
|
* so a four-row first turn was pushed against the composer and every unused row sat ABOVE
|
|
33
33
|
* the conversation. `tailAnchor` therefore sums the estimated height of exactly the
|
|
34
34
|
* entries this frame renders and asks for `flex-start` while they fit - the conversation
|
|
35
|
-
* is then written downwards from
|
|
35
|
+
* is then written downwards from the region's top row, the way a terminal writes. (That row
|
|
36
|
+
* belongs to the band: `tui-header-leaks-into-scrollback` moved the identity row below the
|
|
37
|
+
* composer, so nothing sits between the newest printed row and the first row of the tail.)
|
|
36
38
|
*
|
|
37
39
|
* THE OVERFLOW FRAME STAYS `flex-end`, AND THAT IS THE OTHER HALF OF THE FIX.
|
|
38
40
|
* `flex-start` PLUS `overflow="hidden"` clips the NEWEST rows (Ink's clip rectangle is
|
|
@@ -12,15 +12,20 @@
|
|
|
12
12
|
* and every row it did not ask for became `gap` - blank rows ABOVE the content, which
|
|
13
13
|
* is what the user reported as "the app starts halfway down the screen" and as "a big
|
|
14
14
|
* blank between the result and the running card". The band now takes the whole pool
|
|
15
|
-
* (`fill`), so the region is `[
|
|
15
|
+
* (`fill`), so the region is `[band][composer][identity][status]` top to bottom and
|
|
16
16
|
* `gap` cannot exist: `resolveCanvasLayout` is given `frameRows === capacity` and
|
|
17
17
|
* derives `gap = 0` (see the spec's §5.5 proof, which is why the writer needs no
|
|
18
18
|
* change at all).
|
|
19
19
|
*
|
|
20
20
|
* The composer, popup and status rows come from the SAME `buildFrameBudget` the
|
|
21
21
|
* full-screen layout uses, so the two modes cannot disagree about how tall the
|
|
22
|
-
* editor is. What differs is the top: the
|
|
23
|
-
* row it occupies is spent from the region, not from the printed transcript.
|
|
22
|
+
* editor is. What differs is the top: the identity row is a real slot here (D3), and
|
|
23
|
+
* the row it occupies is spent from the region, not from the printed transcript.
|
|
24
|
+
* THE COUNT IS ALL THIS MODULE OWNS, NOT THE POSITION: since
|
|
25
|
+
* `tui-header-leaks-into-scrollback` the identity row is drawn between the composer and
|
|
26
|
+
* the status group (`ScrollbackShell.tsx`), because region row 0 is necessarily the
|
|
27
|
+
* successor of the newest printed row and chrome there lands inside the conversation.
|
|
28
|
+
* Moving it changed no number below: it is still 1 row, still taken out of `remaining`.
|
|
24
29
|
*
|
|
25
30
|
* THIS IS THE ONLY CALL SITE OF `buildLiveBand` (I-8). `remaining` is computed here
|
|
26
31
|
* once and handed to the band; an `App` that computed its own copy would make
|
|
@@ -58,9 +63,10 @@ export interface ScrollbackBudget {
|
|
|
58
63
|
/** Terminal below the 40x12 floor: the region is a one-row placeholder. */
|
|
59
64
|
inactive: boolean;
|
|
60
65
|
/**
|
|
61
|
-
* The
|
|
62
|
-
*
|
|
63
|
-
* (I-F4) on exactly the frames `/perf` is
|
|
66
|
+
* The identity slot, a real row inside the region (D3), drawn between the composer and
|
|
67
|
+
* the status group. 0 on a degraded frame: the placeholder draws no header, and
|
|
68
|
+
* reporting 1 there would break the row identity (I-F4) on exactly the frames `/perf` is
|
|
69
|
+
* read to explain.
|
|
64
70
|
*/
|
|
65
71
|
headerRows: number;
|
|
66
72
|
statusRows: 0 | 1 | 2;
|
|
@@ -12,15 +12,20 @@
|
|
|
12
12
|
* and every row it did not ask for became `gap` - blank rows ABOVE the content, which
|
|
13
13
|
* is what the user reported as "the app starts halfway down the screen" and as "a big
|
|
14
14
|
* blank between the result and the running card". The band now takes the whole pool
|
|
15
|
-
* (`fill`), so the region is `[
|
|
15
|
+
* (`fill`), so the region is `[band][composer][identity][status]` top to bottom and
|
|
16
16
|
* `gap` cannot exist: `resolveCanvasLayout` is given `frameRows === capacity` and
|
|
17
17
|
* derives `gap = 0` (see the spec's §5.5 proof, which is why the writer needs no
|
|
18
18
|
* change at all).
|
|
19
19
|
*
|
|
20
20
|
* The composer, popup and status rows come from the SAME `buildFrameBudget` the
|
|
21
21
|
* full-screen layout uses, so the two modes cannot disagree about how tall the
|
|
22
|
-
* editor is. What differs is the top: the
|
|
23
|
-
* row it occupies is spent from the region, not from the printed transcript.
|
|
22
|
+
* editor is. What differs is the top: the identity row is a real slot here (D3), and
|
|
23
|
+
* the row it occupies is spent from the region, not from the printed transcript.
|
|
24
|
+
* THE COUNT IS ALL THIS MODULE OWNS, NOT THE POSITION: since
|
|
25
|
+
* `tui-header-leaks-into-scrollback` the identity row is drawn between the composer and
|
|
26
|
+
* the status group (`ScrollbackShell.tsx`), because region row 0 is necessarily the
|
|
27
|
+
* successor of the newest printed row and chrome there lands inside the conversation.
|
|
28
|
+
* Moving it changed no number below: it is still 1 row, still taken out of `remaining`.
|
|
24
29
|
*
|
|
25
30
|
* THIS IS THE ONLY CALL SITE OF `buildLiveBand` (I-8). `remaining` is computed here
|
|
26
31
|
* once and handed to the band; an `App` that computed its own copy would make
|
|
@@ -56,9 +61,11 @@ export function buildScrollbackBudget(input) {
|
|
|
56
61
|
}
|
|
57
62
|
// D1 · H = C. `frameRows` is `rows - 1` by construction (`layout/budget.ts`), so the
|
|
58
63
|
// region ends exactly on the row above the writer's parked cursor.
|
|
64
|
+
// The identity row is drawn at the BOTTOM now; it is still one row and still deducted
|
|
65
|
+
// here, which is why `liveRows`, `bandRows` and `previewRows` did not move with it.
|
|
59
66
|
const headerRows = 1;
|
|
60
67
|
const liveRows = Math.max(1, base.frameRows);
|
|
61
|
-
// The whole pool: everything
|
|
68
|
+
// The whole pool: everything above the composer slot. Two independent
|
|
62
69
|
// derivations put its floor at 1, so `max(0, ...)` is defensive only:
|
|
63
70
|
// 1. `composerSlotRows = 2 + clampDraftRows(rows, draftRows)` and
|
|
64
71
|
// `draftMaxRows(rows) = max(1, min(6, floor(rows / 4)))`, so on the narrowest
|
|
@@ -95,6 +95,8 @@ function entryRows(entry, input) {
|
|
|
95
95
|
return [fit(firstLine(entry.text), cols)];
|
|
96
96
|
case 'service':
|
|
97
97
|
return [];
|
|
98
|
+
case 'governance':
|
|
99
|
+
return [fit(`Governance: ${entry.card.title}`, cols)];
|
|
98
100
|
default: {
|
|
99
101
|
const exhaustive = entry;
|
|
100
102
|
return exhaustive;
|
|
@@ -61,6 +61,9 @@ export function isEntryStable(entry, runActive, isTail) {
|
|
|
61
61
|
case 'service':
|
|
62
62
|
// Only the terminal record is ever a candidate; `isExcluded` filters the rest.
|
|
63
63
|
return entry.terminal === true;
|
|
64
|
+
case 'governance':
|
|
65
|
+
// A settlement card is appended once, already complete.
|
|
66
|
+
return true;
|
|
64
67
|
default: {
|
|
65
68
|
const exhaustive = entry;
|
|
66
69
|
return exhaustive;
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* `justifyContent="flex-end"` therefore pushed those four rows against the composer and
|
|
8
8
|
* left every unused row ABOVE the conversation - the "the first reply starts at the
|
|
9
9
|
* bottom of the screen" report. The answer is conditional anchoring: top while the
|
|
10
|
-
* content fits, so the conversation is written downwards from
|
|
10
|
+
* content fits, so the conversation is written downwards from the region's top row
|
|
11
|
+
* (`tui-header-leaks-into-scrollback` took the identity row off that row and put it
|
|
12
|
+
* below the composer, so the first line of the band is now the first line of the screen).
|
|
11
13
|
*
|
|
12
14
|
* WHY THE FALLBACK IS `bottom` AND NOT THE OTHER WAY ROUND. `flex-start` inside an
|
|
13
15
|
* `overflow="hidden"` box clips the NEWEST rows (Ink's clip rectangle is the box's
|
|
@@ -26,7 +28,8 @@
|
|
|
26
28
|
* parameters and a unit test can drive it with any table it likes.
|
|
27
29
|
*/
|
|
28
30
|
import type { Entry } from '../../agent/reducer.js';
|
|
29
|
-
/** `top` = content grows down from the
|
|
31
|
+
/** `top` = content grows down from the region's top row; `bottom` = newest row hugs the
|
|
32
|
+
* composer. */
|
|
30
33
|
export type TailAnchor = 'top' | 'bottom';
|
|
31
34
|
/**
|
|
32
35
|
* Which alignment the live tail should use for the entries it is about to render.
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* `justifyContent="flex-end"` therefore pushed those four rows against the composer and
|
|
8
8
|
* left every unused row ABOVE the conversation - the "the first reply starts at the
|
|
9
9
|
* bottom of the screen" report. The answer is conditional anchoring: top while the
|
|
10
|
-
* content fits, so the conversation is written downwards from
|
|
10
|
+
* content fits, so the conversation is written downwards from the region's top row
|
|
11
|
+
* (`tui-header-leaks-into-scrollback` took the identity row off that row and put it
|
|
12
|
+
* below the composer, so the first line of the band is now the first line of the screen).
|
|
11
13
|
*
|
|
12
14
|
* WHY THE FALLBACK IS `bottom` AND NOT THE OTHER WAY ROUND. `flex-start` inside an
|
|
13
15
|
* `overflow="hidden"` box clips the NEWEST rows (Ink's clip rectangle is the box's
|