@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,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Roster geometry and cell text for the legion panel (governance-mode section 10.3).
|
|
3
|
+
*
|
|
4
|
+
* Pure and total: no Ink, no clock, no terminal. ASCII ONLY.
|
|
5
|
+
*
|
|
6
|
+
* WHY COMPUTED FIXED-WIDTH COLUMNS. Same lesson as `team-row.ts`, whose header records
|
|
7
|
+
* it at length: a fixed-height parent makes Yoga size a flex column to its widest CHILD,
|
|
8
|
+
* so a row placed by `flexGrow` stops short of the terminal and the cells to its right
|
|
9
|
+
* lose their absolute offsets. Every column below therefore has a COMPUTED integer width
|
|
10
|
+
* and exactly ONE column is elastic; it sits between the fixed cluster on its left and
|
|
11
|
+
* the fixed `delta` cell on its right, so the score change always lands in the row's
|
|
12
|
+
* last column whatever the activity text says.
|
|
13
|
+
*
|
|
14
|
+
* `columnPlan` is TOTAL: for any width (including 0 and 400) the widths never sum past
|
|
15
|
+
* the width it was given. `governance-panel-layout.test.ts` runs it for every width.
|
|
16
|
+
*/
|
|
17
|
+
import { statusMarkerCell, statusMarkerWidth } from '../team-status.js';
|
|
18
|
+
import { GAUGE_CELLS, deltaCell, gaugeFilledCells, govChildStatus, labelTag, scoreText, scoreToneKey, segment, statusTone, } from '../governance-status.js';
|
|
19
|
+
import { NOT_SCORED, ROLE_LABEL, STATE_WORD, WORKING_VERB, replacedByText, } from '../governance-copy.js';
|
|
20
|
+
import { cellWidth, fitCells } from './cells.js';
|
|
21
|
+
/** The elastic column keeps at least this many columns, else it is dropped (activity) or kept (wp). */
|
|
22
|
+
const ELASTIC_MIN_CELLS = { activity: 12, wp: 6 };
|
|
23
|
+
/** One leading margin column, drawn by the component. */
|
|
24
|
+
export const PANEL_MARGIN_CELLS = 1;
|
|
25
|
+
function columnSpecs(tier, markerCells) {
|
|
26
|
+
const marker = { key: 'marker', width: markerCells };
|
|
27
|
+
const delta = { key: 'delta', width: 7, align: 'right', drop: 2 };
|
|
28
|
+
switch (tier) {
|
|
29
|
+
case 'full':
|
|
30
|
+
return [
|
|
31
|
+
marker,
|
|
32
|
+
{ key: 'id', width: 8 },
|
|
33
|
+
{ key: 'role', width: 6, drop: 3 },
|
|
34
|
+
{ key: 'state', width: 12 },
|
|
35
|
+
{ key: 'gauge', width: GAUGE_CELLS + 1, drop: 5 },
|
|
36
|
+
{ key: 'score', width: 5, align: 'right' },
|
|
37
|
+
{ key: 'prov', width: 7, drop: 4 },
|
|
38
|
+
{ key: 'tag', width: 8, drop: 6 },
|
|
39
|
+
{ key: 'wp', width: 11 },
|
|
40
|
+
{ key: 'activity', width: 0, elastic: true },
|
|
41
|
+
delta,
|
|
42
|
+
];
|
|
43
|
+
case 'standard':
|
|
44
|
+
return [
|
|
45
|
+
marker,
|
|
46
|
+
{ key: 'id', width: 8 },
|
|
47
|
+
{ key: 'role', width: 6, drop: 3 },
|
|
48
|
+
{ key: 'state', width: 12 },
|
|
49
|
+
{ key: 'gauge', width: GAUGE_CELLS + 1, drop: 5 },
|
|
50
|
+
{ key: 'score', width: 5, align: 'right' },
|
|
51
|
+
{ key: 'prov', width: 7, drop: 4 },
|
|
52
|
+
{ key: 'tag', width: 8, drop: 6 },
|
|
53
|
+
{ key: 'wp', width: 0, elastic: true },
|
|
54
|
+
delta,
|
|
55
|
+
];
|
|
56
|
+
default:
|
|
57
|
+
return [
|
|
58
|
+
marker,
|
|
59
|
+
{ key: 'id', width: 8 },
|
|
60
|
+
{ key: 'state', width: 12, drop: 3 },
|
|
61
|
+
{ key: 'score', width: 5, align: 'right' },
|
|
62
|
+
{ key: 'wp', width: 0, elastic: true },
|
|
63
|
+
delta,
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function fixedSum(specs) {
|
|
68
|
+
return specs.reduce((sum, spec) => sum + (spec.elastic ? 0 : spec.width), 0);
|
|
69
|
+
}
|
|
70
|
+
/** The column that gives way first: the highest `drop` rank, or -1 when none can. */
|
|
71
|
+
function dropVictim(specs) {
|
|
72
|
+
let victim = -1;
|
|
73
|
+
let rank = 0;
|
|
74
|
+
specs.forEach((spec, index) => {
|
|
75
|
+
if (spec.drop !== undefined && spec.drop > rank) {
|
|
76
|
+
rank = spec.drop;
|
|
77
|
+
victim = index;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return victim;
|
|
81
|
+
}
|
|
82
|
+
/** Last-resort squeeze so the sum NEVER exceeds `inner`, from the right edge inward. */
|
|
83
|
+
function squeeze(columns, inner) {
|
|
84
|
+
let over = columns.reduce((sum, column) => sum + column.width, 0) - inner;
|
|
85
|
+
for (let index = columns.length - 1; index >= 0 && over > 0; index -= 1) {
|
|
86
|
+
const column = columns[index];
|
|
87
|
+
const cut = Math.min(column.width, over);
|
|
88
|
+
column.width -= cut;
|
|
89
|
+
over -= cut;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Give the activity column up and make the work-package cell the elastic one, which turns
|
|
94
|
+
* a `full` row into a `standard` one without losing the single-elastic-column invariant.
|
|
95
|
+
*/
|
|
96
|
+
function promoteWorkPackage(specs) {
|
|
97
|
+
return specs
|
|
98
|
+
.filter((spec) => spec.key !== 'activity')
|
|
99
|
+
.map((spec) => (spec.key === 'wp' ? { key: 'wp', width: 0, elastic: true } : spec));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The row's columns for a tier at `inner` columns (the terminal width minus the margin).
|
|
103
|
+
*
|
|
104
|
+
* THE DROP LADDER IS THE SPECIFICATION, in the order the cells give way: the activity
|
|
105
|
+
* text first (the only column whose loss costs nothing structural - the work-package cell
|
|
106
|
+
* becomes the elastic one), then the tag, gauge, provisional, role and delta cells. The
|
|
107
|
+
* elastic column keeps at least its floor; when even the fixed cluster does not fit,
|
|
108
|
+
* `squeeze` trims from the right so the sum stays inside `inner` for any input.
|
|
109
|
+
*/
|
|
110
|
+
export function columnPlan(tier, inner, markerCells) {
|
|
111
|
+
const width = Number.isFinite(inner) ? Math.max(0, Math.floor(inner)) : 0;
|
|
112
|
+
let specs = columnSpecs(tier, markerCells);
|
|
113
|
+
const floorOf = (spec) => spec?.key === 'activity' ? ELASTIC_MIN_CELLS.activity : ELASTIC_MIN_CELLS.wp;
|
|
114
|
+
for (;;) {
|
|
115
|
+
const elastic = specs.find((spec) => spec.elastic === true);
|
|
116
|
+
if (fixedSum(specs) + floorOf(elastic) <= width)
|
|
117
|
+
break;
|
|
118
|
+
if (elastic?.key === 'activity') {
|
|
119
|
+
specs = promoteWorkPackage(specs);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const victim = dropVictim(specs);
|
|
123
|
+
if (victim < 0)
|
|
124
|
+
break;
|
|
125
|
+
specs = specs.filter((_, index) => index !== victim);
|
|
126
|
+
}
|
|
127
|
+
const remaining = Math.max(0, width - fixedSum(specs));
|
|
128
|
+
const columns = specs.map((spec) => ({
|
|
129
|
+
key: spec.key,
|
|
130
|
+
width: spec.elastic ? remaining : spec.width,
|
|
131
|
+
elastic: spec.elastic === true,
|
|
132
|
+
align: spec.align ?? 'left',
|
|
133
|
+
}));
|
|
134
|
+
squeeze(columns, width);
|
|
135
|
+
return columns;
|
|
136
|
+
}
|
|
137
|
+
export function columnsWidth(columns) {
|
|
138
|
+
return columns.reduce((sum, column) => sum + column.width, 0);
|
|
139
|
+
}
|
|
140
|
+
const BLANK_TONE = 'muted';
|
|
141
|
+
function textCell(column, text, tone, ellipsis, bold = false) {
|
|
142
|
+
const clipped = column.width === 0 ? '' : fitCells(text, column.width, ellipsis);
|
|
143
|
+
return {
|
|
144
|
+
key: column.key,
|
|
145
|
+
width: column.width,
|
|
146
|
+
elastic: column.elastic,
|
|
147
|
+
align: column.align,
|
|
148
|
+
segments: clipped === '' ? [] : [segment(clipped, tone, bold)],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function leading(text) {
|
|
152
|
+
return text === '' ? '' : ` ${text}`;
|
|
153
|
+
}
|
|
154
|
+
/** `not scored` replaces the gauge for the inspector (spec 5.1: never scored). */
|
|
155
|
+
function gaugeCell(column, row, glyphs) {
|
|
156
|
+
if (row.confirmed === null)
|
|
157
|
+
return textCell(column, NOT_SCORED, 'muted', glyphs.ellipsis);
|
|
158
|
+
const filled = gaugeFilledCells(row.confirmed);
|
|
159
|
+
const bar = [
|
|
160
|
+
segment(glyphs.gaugeFull.repeat(filled), scoreToneKey(row.label)),
|
|
161
|
+
segment(glyphs.gaugeEmpty.repeat(GAUGE_CELLS - filled), 'border'),
|
|
162
|
+
].filter((part) => part.text !== '');
|
|
163
|
+
return {
|
|
164
|
+
key: column.key,
|
|
165
|
+
width: column.width,
|
|
166
|
+
elastic: false,
|
|
167
|
+
align: 'left',
|
|
168
|
+
segments: bar,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function stateText(row) {
|
|
172
|
+
return row.state === 'working' ? WORKING_VERB[row.role] : STATE_WORD[row.state];
|
|
173
|
+
}
|
|
174
|
+
function rightAligned(column, text) {
|
|
175
|
+
return ' '.repeat(Math.max(0, column.width - cellWidth(text))) + text;
|
|
176
|
+
}
|
|
177
|
+
function scoreCell(column, row, ctx) {
|
|
178
|
+
const ell = ctx.glyphs.ellipsis;
|
|
179
|
+
if (row.confirmed === null)
|
|
180
|
+
return textCell(column, '', BLANK_TONE, ell);
|
|
181
|
+
const text = rightAligned(column, scoreText(row.confirmed));
|
|
182
|
+
return textCell(column, text, scoreToneKey(row.label), ell);
|
|
183
|
+
}
|
|
184
|
+
function deltaColumnCell(column, row, ctx) {
|
|
185
|
+
const delta = deltaCell(row, ctx.now, ctx.reducedMotion);
|
|
186
|
+
const text = delta.text === '' ? '' : rightAligned(column, delta.text);
|
|
187
|
+
return textCell(column, text, delta.tone, ctx.glyphs.ellipsis, delta.bold);
|
|
188
|
+
}
|
|
189
|
+
/** One builder per column: a table, so adding a column cannot raise a function's complexity. */
|
|
190
|
+
const CELL_BUILDERS = {
|
|
191
|
+
marker: (column, row, ctx) => {
|
|
192
|
+
const status = govChildStatus(row.state);
|
|
193
|
+
const text = ` ${statusMarkerCell(status, ctx.glyphs)} `;
|
|
194
|
+
return textCell(column, text, statusTone(status), ctx.glyphs.ellipsis);
|
|
195
|
+
},
|
|
196
|
+
id: (column, row, ctx) => textCell(column, row.id, 'primary', ctx.glyphs.ellipsis),
|
|
197
|
+
role: (column, row, ctx) => textCell(column, ROLE_LABEL[row.role], 'muted', ctx.glyphs.ellipsis),
|
|
198
|
+
state: (column, row, ctx) => {
|
|
199
|
+
const tone = statusTone(govChildStatus(row.state));
|
|
200
|
+
return textCell(column, stateText(row), tone, ctx.glyphs.ellipsis);
|
|
201
|
+
},
|
|
202
|
+
gauge: (column, row, ctx) => gaugeCell(column, row, ctx.glyphs),
|
|
203
|
+
score: scoreCell,
|
|
204
|
+
prov: (column, row, ctx) => {
|
|
205
|
+
const text = row.provisional > 0 ? leading(`+${row.provisional}P`) : '';
|
|
206
|
+
return textCell(column, text, 'muted', ctx.glyphs.ellipsis);
|
|
207
|
+
},
|
|
208
|
+
tag: (column, row, ctx) => {
|
|
209
|
+
const text = leading(labelTag(row.label));
|
|
210
|
+
return textCell(column, text, scoreToneKey(row.label), ctx.glyphs.ellipsis, true);
|
|
211
|
+
},
|
|
212
|
+
wp: (column, row, ctx) => textCell(column, leading(row.wpId ?? '-'), 'text', ctx.glyphs.ellipsis),
|
|
213
|
+
activity: (column, row, ctx) => {
|
|
214
|
+
const text = leading(row.activity.replace(/\s+/g, ' ').trim());
|
|
215
|
+
return textCell(column, text, 'muted', ctx.glyphs.ellipsis);
|
|
216
|
+
},
|
|
217
|
+
delta: deltaColumnCell,
|
|
218
|
+
note: (column, _row, ctx) => textCell(column, '', BLANK_TONE, ctx.glyphs.ellipsis),
|
|
219
|
+
};
|
|
220
|
+
function cellFor(column, row, ctx) {
|
|
221
|
+
return CELL_BUILDERS[column.key](column, row, ctx);
|
|
222
|
+
}
|
|
223
|
+
/** Columns a replaced member's one-line note spans. */
|
|
224
|
+
const NOTE_SPAN = new Set(['state', 'gauge', 'score', 'prov', 'tag']);
|
|
225
|
+
/**
|
|
226
|
+
* A replaced member: marker, id and role stay (so the row is recognisable), and one
|
|
227
|
+
* muted note spans the state-through-tag cells. The note NAMES the successor, which is the
|
|
228
|
+
* information the member's vanishing from the panel next phase would otherwise erase.
|
|
229
|
+
*/
|
|
230
|
+
function eliminatedCells(columns, row, ctx) {
|
|
231
|
+
const cells = [];
|
|
232
|
+
let spanned = 0;
|
|
233
|
+
let spanColumn = null;
|
|
234
|
+
const flush = () => {
|
|
235
|
+
if (spanColumn === null)
|
|
236
|
+
return;
|
|
237
|
+
const merged = { ...spanColumn, key: 'note', width: spanned, align: 'left' };
|
|
238
|
+
const text = ` ${replacedByText(row.replacedBy)}`;
|
|
239
|
+
cells.push(textCell(merged, text, 'muted', ctx.glyphs.ellipsis));
|
|
240
|
+
spanColumn = null;
|
|
241
|
+
spanned = 0;
|
|
242
|
+
};
|
|
243
|
+
for (const column of columns) {
|
|
244
|
+
if (NOTE_SPAN.has(column.key)) {
|
|
245
|
+
spanColumn ??= column;
|
|
246
|
+
spanned += column.width;
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
flush();
|
|
250
|
+
const cell = cellFor(column, row, ctx);
|
|
251
|
+
const quiet = column.key === 'id' || column.key === 'role' || column.key === 'marker';
|
|
252
|
+
cells.push(quiet ? mute(cell) : blank(cell));
|
|
253
|
+
}
|
|
254
|
+
flush();
|
|
255
|
+
return cells;
|
|
256
|
+
}
|
|
257
|
+
function mute(cell) {
|
|
258
|
+
return { ...cell, segments: cell.segments.map((part) => ({ ...part, tone: 'muted' })) };
|
|
259
|
+
}
|
|
260
|
+
function blank(cell) {
|
|
261
|
+
return { ...cell, segments: [] };
|
|
262
|
+
}
|
|
263
|
+
/** One roster row's cells, text already clamped to its cell. */
|
|
264
|
+
export function buildRosterLine(input) {
|
|
265
|
+
const { columns, row, glyphs, now, reducedMotion } = input;
|
|
266
|
+
const ctx = { glyphs, now, reducedMotion };
|
|
267
|
+
if (row.state === 'eliminated') {
|
|
268
|
+
return { key: row.id, kind: 'eliminated', cells: eliminatedCells(columns, row, ctx) };
|
|
269
|
+
}
|
|
270
|
+
return { key: row.id, kind: 'agent', cells: columns.map((column) => cellFor(column, row, ctx)) };
|
|
271
|
+
}
|
|
272
|
+
/** The marker cell's width in the current glyph tier: 1 + widest marker + 1. */
|
|
273
|
+
export function markerCells(glyphs) {
|
|
274
|
+
return 1 + statusMarkerWidth(glyphs) + 1;
|
|
275
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invocation card layout (tui-invocation-cards section 3.7): what a `user` entry that
|
|
3
|
+
* carries an `invocation` says, as pure data. No Ink, no React. ASCII ONLY.
|
|
4
|
+
*
|
|
5
|
+
* THE CARD'S HEIGHT IS A FUNCTION OF ITS DATA AND THE USABLE WIDTH (I-4).
|
|
6
|
+
* `InvocationCard.tsx` renders exactly the rows `invocationCardRows` counts, and both
|
|
7
|
+
* read `INVOCATION_LIMITS` plus the one `invocationInputText` below - an estimate that
|
|
8
|
+
* disagrees with the painter is permanent, because an over-estimated entry is never
|
|
9
|
+
* mounted and so never measured (see `virtual-window.ts`).
|
|
10
|
+
*/
|
|
11
|
+
import type { InvocationCard } from '../../agent/invocation-card.js';
|
|
12
|
+
import type { Glyphs } from '../glyphs.js';
|
|
13
|
+
/** Colour slots the component maps onto the theme; kept local so this file needs no `Theme`. */
|
|
14
|
+
export type InvocationTone = 'label' | 'name' | 'muted';
|
|
15
|
+
export interface InvocationSegment {
|
|
16
|
+
text: string;
|
|
17
|
+
tone: InvocationTone;
|
|
18
|
+
bold: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The header row, already fitted to `usable` columns (RV-10). Narrow terminals drop
|
|
22
|
+
* facts from the right WHOLE before anything else is cut; only when the identity alone
|
|
23
|
+
* is too wide is the name shortened. Ink's `wrap="truncate"` stays on the row as a
|
|
24
|
+
* backstop, but it is never what produces the visible ellipsis.
|
|
25
|
+
*/
|
|
26
|
+
export declare function invocationHeaderSegments(card: InvocationCard, glyphs: Glyphs, usable: number): InvocationSegment[];
|
|
27
|
+
/** The text painted for `input`: tabs expanded per line, the same rule `UserEntry` follows. */
|
|
28
|
+
export declare function invocationInputText(card: InvocationCard): string;
|
|
29
|
+
/** Singular/plural for the hidden-characters tail. */
|
|
30
|
+
export declare function invocationHiddenText(card: InvocationCard, glyphs: Glyphs): string;
|
|
31
|
+
/**
|
|
32
|
+
* Rows the card occupies at `usable` columns. `wrappedRows` is injected by the caller
|
|
33
|
+
* (`virtual-window.ts` owns the one wrapping rule) so this file stays import-cycle free.
|
|
34
|
+
*/
|
|
35
|
+
export declare function invocationCardRows(card: InvocationCard, usable: number, wrappedRows: (text: string, usable: number) => number): number;
|
|
36
|
+
/**
|
|
37
|
+
* The lines the exit replay / export prints UNDER the command line (section 2.4):
|
|
38
|
+
* a bracketed fact line, and the disclosure note when there is one. Plain ASCII
|
|
39
|
+
* separators - the replay is pasted into issues and must survive any terminal.
|
|
40
|
+
*/
|
|
41
|
+
export declare function invocationCardLines(card: InvocationCard): string[];
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invocation card layout (tui-invocation-cards section 3.7): what a `user` entry that
|
|
3
|
+
* carries an `invocation` says, as pure data. No Ink, no React. ASCII ONLY.
|
|
4
|
+
*
|
|
5
|
+
* THE CARD'S HEIGHT IS A FUNCTION OF ITS DATA AND THE USABLE WIDTH (I-4).
|
|
6
|
+
* `InvocationCard.tsx` renders exactly the rows `invocationCardRows` counts, and both
|
|
7
|
+
* read `INVOCATION_LIMITS` plus the one `invocationInputText` below - an estimate that
|
|
8
|
+
* disagrees with the painter is permanent, because an over-estimated entry is never
|
|
9
|
+
* mounted and so never measured (see `virtual-window.ts`).
|
|
10
|
+
*/
|
|
11
|
+
import { expandTabs } from '../display-tab.js';
|
|
12
|
+
import { cellWidth, fitCells } from './cells.js';
|
|
13
|
+
/** Two spaces between the identity (`skill . pdf-forms`) and the facts. */
|
|
14
|
+
const FACT_GAP = ' ';
|
|
15
|
+
function seg(text, tone, bold = false) {
|
|
16
|
+
return { text, tone, bold };
|
|
17
|
+
}
|
|
18
|
+
function segmentsWidth(segments) {
|
|
19
|
+
return segments.reduce((sum, part) => sum + cellWidth(part.text), 0);
|
|
20
|
+
}
|
|
21
|
+
function identitySegments(card, glyphs, name) {
|
|
22
|
+
const parts = [seg(card.variant, 'label', true)];
|
|
23
|
+
if (name !== '')
|
|
24
|
+
parts.push(seg(` ${glyphs.midDot} `, 'muted'), seg(name, 'name', true));
|
|
25
|
+
return parts;
|
|
26
|
+
}
|
|
27
|
+
function factSegments(facts, glyphs) {
|
|
28
|
+
if (facts.length === 0)
|
|
29
|
+
return [];
|
|
30
|
+
const parts = [seg(FACT_GAP, 'muted')];
|
|
31
|
+
facts.forEach((fact, index) => {
|
|
32
|
+
if (index > 0)
|
|
33
|
+
parts.push(seg(` ${glyphs.midDot} `, 'muted'));
|
|
34
|
+
parts.push(seg(fact, 'muted'));
|
|
35
|
+
});
|
|
36
|
+
return parts;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The header row, already fitted to `usable` columns (RV-10). Narrow terminals drop
|
|
40
|
+
* facts from the right WHOLE before anything else is cut; only when the identity alone
|
|
41
|
+
* is too wide is the name shortened. Ink's `wrap="truncate"` stays on the row as a
|
|
42
|
+
* backstop, but it is never what produces the visible ellipsis.
|
|
43
|
+
*/
|
|
44
|
+
export function invocationHeaderSegments(card, glyphs, usable) {
|
|
45
|
+
const width = Math.max(1, Math.floor(usable));
|
|
46
|
+
for (let kept = card.facts.length; kept >= 0; kept -= 1) {
|
|
47
|
+
const candidate = [
|
|
48
|
+
...identitySegments(card, glyphs, card.name),
|
|
49
|
+
...factSegments(card.facts.slice(0, kept), glyphs),
|
|
50
|
+
];
|
|
51
|
+
if (segmentsWidth(candidate) <= width)
|
|
52
|
+
return candidate;
|
|
53
|
+
}
|
|
54
|
+
const head = identitySegments(card, glyphs, '');
|
|
55
|
+
const room = width - segmentsWidth(head) - cellWidth(` ${glyphs.midDot} `);
|
|
56
|
+
if (card.name !== '' && room > 1) {
|
|
57
|
+
return identitySegments(card, glyphs, fitCells(card.name, room, glyphs.ellipsis));
|
|
58
|
+
}
|
|
59
|
+
return [seg(fitCells(card.variant, width, glyphs.ellipsis), 'label', true)];
|
|
60
|
+
}
|
|
61
|
+
/** The text painted for `input`: tabs expanded per line, the same rule `UserEntry` follows. */
|
|
62
|
+
export function invocationInputText(card) {
|
|
63
|
+
return card.input.split('\n').map((line) => expandTabs(line)).join('\n');
|
|
64
|
+
}
|
|
65
|
+
/** Singular/plural for the hidden-characters tail. */
|
|
66
|
+
export function invocationHiddenText(card, glyphs) {
|
|
67
|
+
const unit = card.inputHidden === 1 ? 'char' : 'chars';
|
|
68
|
+
return `${glyphs.ellipsis} +${card.inputHidden} ${unit} not shown`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Rows the card occupies at `usable` columns. `wrappedRows` is injected by the caller
|
|
72
|
+
* (`virtual-window.ts` owns the one wrapping rule) so this file stays import-cycle free.
|
|
73
|
+
*/
|
|
74
|
+
export function invocationCardRows(card, usable, wrappedRows) {
|
|
75
|
+
const inputRows = card.input === '' ? 0 : wrappedRows(invocationInputText(card), usable);
|
|
76
|
+
return 1 + inputRows + (card.inputHidden > 0 ? 1 : 0) + (card.note ? 1 : 0);
|
|
77
|
+
}
|
|
78
|
+
const REPLAY_INDENT = ' ';
|
|
79
|
+
/**
|
|
80
|
+
* The lines the exit replay / export prints UNDER the command line (section 2.4):
|
|
81
|
+
* a bracketed fact line, and the disclosure note when there is one. Plain ASCII
|
|
82
|
+
* separators - the replay is pasted into issues and must survive any terminal.
|
|
83
|
+
*/
|
|
84
|
+
export function invocationCardLines(card) {
|
|
85
|
+
const identity = card.name === '' ? card.variant : `${card.variant} ${card.name}`;
|
|
86
|
+
const detail = card.facts.length === 0 ? identity : `${identity} ${card.facts.join(' - ')}`;
|
|
87
|
+
const lines = [`${REPLAY_INDENT}[${detail}]`];
|
|
88
|
+
if (card.note)
|
|
89
|
+
lines.push(`${REPLAY_INDENT}${card.note}`);
|
|
90
|
+
return lines;
|
|
91
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { formatCost, formatTokens, promptTokensOf } from '../../agent/usage.js';
|
|
2
2
|
import { actionCandidates, clipStatusText, escapeClause } from '../interaction-hints.js';
|
|
3
|
-
import {
|
|
3
|
+
import { isGovernedModeValue, modeWord } from '../governance-status.js';
|
|
4
4
|
import { statusField, statusLinePlan, validContext } from './status-layout.js';
|
|
5
5
|
/**
|
|
6
6
|
* Uppercase mode word for the details row, mirroring the primary row's field:
|
|
7
7
|
* same vocabulary (`MODE_LABEL`), same `CUR>PENDING` deferred-switch shape.
|
|
8
8
|
*/
|
|
9
9
|
function detailModeText(mode, pendingMode) {
|
|
10
|
-
const word = (value) =>
|
|
10
|
+
const word = (value) => modeWord(value, true) ?? value.toUpperCase();
|
|
11
11
|
if (pendingMode)
|
|
12
12
|
return `${word(mode || 'build')}>${word(pendingMode)}`;
|
|
13
13
|
return word(mode || 'build');
|
|
@@ -41,7 +41,7 @@ export function planStatusDetail(input) {
|
|
|
41
41
|
if (status.servicesActive?.live)
|
|
42
42
|
add(statusField('services', 'Svc' + status.servicesActive.live));
|
|
43
43
|
if (status.mode || status.pendingMode)
|
|
44
|
-
add(statusField('mode', detailModeText(status.mode, status.pendingMode), 'accent'));
|
|
44
|
+
add(statusField('mode', detailModeText(status.mode, status.pendingMode), isGovernedModeValue(status.mode) || isGovernedModeValue(status.pendingMode) ? 'govern' : 'accent'));
|
|
45
45
|
if (validContext(status.context)) {
|
|
46
46
|
const approximate = status.context.source === 'estimate' || status.context.deltaTokens > 0 ? '~' : '';
|
|
47
47
|
add(statusField('context', 'Context ' + approximate + formatTokens(status.context.occupied)
|
|
@@ -117,8 +117,11 @@ export interface StatusField {
|
|
|
117
117
|
id: string;
|
|
118
118
|
text: string;
|
|
119
119
|
cells: number;
|
|
120
|
-
/**
|
|
121
|
-
|
|
120
|
+
/**
|
|
121
|
+
* 'accent' carries the mode word - the row's one always-on emphasis. 'govern' is the
|
|
122
|
+
* same slot while the posture is GOVERN / PLAN+GOVERN (`governAccent`, its own hue).
|
|
123
|
+
*/
|
|
124
|
+
tone: 'normal' | 'muted' | 'warning' | 'error' | 'accent' | 'govern';
|
|
122
125
|
}
|
|
123
126
|
export interface StatusLinePlan {
|
|
124
127
|
fields: readonly StatusField[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import stringWidth from 'string-width';
|
|
2
2
|
import stripAnsi from 'strip-ansi';
|
|
3
3
|
import { formatDuration } from '../../agent/usage.js';
|
|
4
|
-
import {
|
|
4
|
+
import { isGovernedModeValue, modeWord } from '../governance-status.js';
|
|
5
5
|
import { interactionCopy as copy } from '../interaction-copy.js';
|
|
6
6
|
export function cleanStatusText(text) {
|
|
7
7
|
// eslint-disable-next-line no-control-regex
|
|
@@ -170,10 +170,12 @@ function modeFieldText(mode, pendingMode, full) {
|
|
|
170
170
|
if (!mode && !pendingMode)
|
|
171
171
|
return null;
|
|
172
172
|
const word = (value) => {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
173
|
+
// `build` / `plan` answer exactly as before; the two governed postures are the only
|
|
174
|
+
// other values `modeWord` knows (`PG` is the short form of PLAN+GOVERN, since `P` is PLAN).
|
|
175
|
+
const known = modeWord(value, full);
|
|
176
|
+
if (known !== undefined)
|
|
177
|
+
return known;
|
|
178
|
+
return full ? value.toUpperCase() : (value[0] ?? '?').toUpperCase();
|
|
177
179
|
};
|
|
178
180
|
const current = word(mode || 'build');
|
|
179
181
|
return pendingMode ? `${current}>${word(pendingMode)}` : current;
|
|
@@ -231,7 +233,9 @@ export function planPrimaryStatusFields(input) {
|
|
|
231
233
|
return statusLinePlan([
|
|
232
234
|
statusField('phase', glyph + (rung >= 5 ? '' : ' ') + label, phaseTone),
|
|
233
235
|
...(notice ? [statusField('feedback', notice, feedbackTone)] : []),
|
|
234
|
-
...(modeText
|
|
236
|
+
...(modeText
|
|
237
|
+
? [statusField('mode', modeText, isGovernedModeValue(input.mode) || isGovernedModeValue(input.pendingMode) ? 'govern' : 'accent')]
|
|
238
|
+
: []),
|
|
235
239
|
...(forcedText ? [statusField('forcedTeam', forcedText, 'accent')] : []),
|
|
236
240
|
statusField('context', (full ? 'Context ' : 'C') + pct
|
|
237
241
|
+ (input.compactionPaused === true ? pausedSuffix(full) : '')),
|
|
@@ -33,12 +33,14 @@
|
|
|
33
33
|
* through the mounted set and the measured heights back to the offset.
|
|
34
34
|
*/
|
|
35
35
|
import stringWidth from 'string-width';
|
|
36
|
+
import { governanceCardRows } from './governance-card.js';
|
|
36
37
|
import { FAST_LIMITS } from '../../fast/limits.js';
|
|
37
38
|
import { COMPACTION_LIMITS } from '../../compaction/limits.js';
|
|
38
39
|
import { GUTTER_WIDTH } from './Gutter.js';
|
|
39
40
|
import { expandTabs } from '../display-tab.js';
|
|
40
41
|
import { USER_ENTRY_MAX_ROWS } from '../composer-limits.js';
|
|
41
42
|
import { isLiveTeamCard } from '../team-status.js';
|
|
43
|
+
import { invocationCardRows } from './invocation-card.js';
|
|
42
44
|
export const VIRTUAL_LIMITS = {
|
|
43
45
|
/**
|
|
44
46
|
* Entries kept mounted on each side of the visible band.
|
|
@@ -67,8 +69,12 @@ export const VIRTUAL_LIMITS = {
|
|
|
67
69
|
*/
|
|
68
70
|
export function entryRevision(entry) {
|
|
69
71
|
switch (entry.kind) {
|
|
72
|
+
// A card's shape is fixed at creation; the suffix only tells "card" from "plain" (and
|
|
73
|
+
// the three row-bearing parts), which is what makes a `queued -> user` rewrite re-measure.
|
|
70
74
|
case 'user':
|
|
71
|
-
return
|
|
75
|
+
return entry.invocation
|
|
76
|
+
? `i${entry.invocation.input.length}.${entry.invocation.inputHidden > 0 ? 1 : 0}.${entry.invocation.note ? 1 : 0}`
|
|
77
|
+
: 'u';
|
|
72
78
|
case 'notice':
|
|
73
79
|
return 'n';
|
|
74
80
|
// `thinkingMs` is O(1) and it CHANGES THE ROW: sealing the clock turns
|
|
@@ -153,6 +159,11 @@ export function entryRevision(entry) {
|
|
|
153
159
|
*/
|
|
154
160
|
case 'service':
|
|
155
161
|
return `v${entry.status}.${entry.rowsSeen}.${entry.url ? 1 : 0}.${entry.exitCode ?? -1}.${entry.terminal ? 1 : 0}`;
|
|
162
|
+
// A governance card is IMMUTABLE once appended (it is a settled record), so its
|
|
163
|
+
// revision only has to tell two cards apart: the shape terms below are what decide
|
|
164
|
+
// its height (`governanceCardRows`), and they cannot change without a new entry.
|
|
165
|
+
case 'governance':
|
|
166
|
+
return `g${entry.card.rows.length}.${entry.card.notes.length}.${entry.card.headline.length}`;
|
|
156
167
|
default:
|
|
157
168
|
return 'x';
|
|
158
169
|
}
|
|
@@ -253,6 +264,11 @@ export function estimateEntryRows(entry, cols, density, expanded, thinkingVisibl
|
|
|
253
264
|
const separation = density === 'comfortable' ? 1 : 0;
|
|
254
265
|
switch (entry.kind) {
|
|
255
266
|
case 'user':
|
|
267
|
+
// A CARD HAS ITS OWN, BOUNDED HEIGHT (tui-invocation-cards I-4): the same
|
|
268
|
+
// `invocationCardRows` the painter is built from, never the command line's wrapped rows.
|
|
269
|
+
if (entry.invocation) {
|
|
270
|
+
return separation + invocationCardRows(entry.invocation, usable, wrappedRows);
|
|
271
|
+
}
|
|
256
272
|
// MIRRORS `UserEntry`'s RENDER CAP (+1 for the `... +N more lines` tail).
|
|
257
273
|
// THESE TWO NUMBERS ARE ONE NUMBER (I-13). Capping the renderer alone
|
|
258
274
|
// would leave this function believing a 5 000-line message is 5 000 rows
|
|
@@ -402,6 +418,11 @@ export function estimateEntryRows(entry, cols, density, expanded, thinkingVisibl
|
|
|
402
418
|
const progress = entry.progress || entry.stalled ? SERVICE_PROGRESS_ROWS : 0;
|
|
403
419
|
return separation + 1 + progress + url + tail;
|
|
404
420
|
}
|
|
421
|
+
// EXACT, not an upper bound: every line of the card is `wrap="truncate"`, so its
|
|
422
|
+
// height is a function of its data alone (`layout/governance-card.ts`). It has to
|
|
423
|
+
// be added to BOTH of this file's switches - one alone yields scroll drift.
|
|
424
|
+
case 'governance':
|
|
425
|
+
return separation + governanceCardRows(entry.card);
|
|
405
426
|
default:
|
|
406
427
|
return separation + 1;
|
|
407
428
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GovernanceBoardOverlay - the read-only `/gov board` overview
|
|
3
|
+
* (governance-mode section 10.5).
|
|
4
|
+
*
|
|
5
|
+
* ASCII ONLY: every symbol comes through `glyphs`.
|
|
6
|
+
*
|
|
7
|
+
* READ-ONLY IS THE SAFETY BOUNDARY, as for the Agents board: nothing here scores, rules
|
|
8
|
+
* or resolves anything. The only side effect is `e`, which asks the owner to copy the
|
|
9
|
+
* `board.md` path.
|
|
10
|
+
*
|
|
11
|
+
* `OverlayFrame` SELF-MANAGED MODE, with this file owning the window. The tab strip must
|
|
12
|
+
* stay put while the rows scroll, which the frame's controlled mode (it windows EVERY row
|
|
13
|
+
* it is given) cannot do; so the body is "one strip row + a window of rows" and the
|
|
14
|
+
* windowing is `sliceWindow` through `boardWindow`, the arithmetic the frame itself uses.
|
|
15
|
+
* `PgUp` / `PgDn` / the wheel arrive through `App`'s `controlled` overlay list as
|
|
16
|
+
* `scrollOffset`; Up/Down and Left/Right are this component's own keys, the same split the
|
|
17
|
+
* Agents board makes.
|
|
18
|
+
*
|
|
19
|
+
* NO `ink-spinner` and no motion prop (spinner-census): this is a reading surface.
|
|
20
|
+
*/
|
|
21
|
+
import React from 'react';
|
|
22
|
+
import type { Theme } from '../theme.js';
|
|
23
|
+
import type { TermCapabilities } from '../capabilities.js';
|
|
24
|
+
import { type BoardTab, type GovernanceBoardData } from '../layout/governance-board.js';
|
|
25
|
+
export interface GovernanceBoardOverlayProps {
|
|
26
|
+
/** The board's data, or null when there is no governed run to show. */
|
|
27
|
+
data: GovernanceBoardData | null;
|
|
28
|
+
/** The overlay's FRAME width (`App`'s `viewCols`). */
|
|
29
|
+
cols: number;
|
|
30
|
+
maxRows: number;
|
|
31
|
+
scrollOffset: number;
|
|
32
|
+
onScrollClamp: (offset: number) => void;
|
|
33
|
+
isActive: boolean;
|
|
34
|
+
theme: Theme;
|
|
35
|
+
caps: TermCapabilities;
|
|
36
|
+
/** `e`: copy the board file path. Absent = the key reports the path as unavailable. */
|
|
37
|
+
onCopyPath?: (path: string) => void;
|
|
38
|
+
onNotice?: (level: 'info' | 'warn', text: string) => void;
|
|
39
|
+
initialTab?: BoardTab;
|
|
40
|
+
}
|
|
41
|
+
export declare function GovernanceBoardOverlay({ data, cols, maxRows, scrollOffset, onScrollClamp, isActive, theme, caps, onCopyPath, onNotice, initialTab, }: GovernanceBoardOverlayProps): React.ReactElement;
|