@aragon-agent/cli 0.6.35 → 0.6.36
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 +21 -0
- package/README.md +3173 -3071
- package/dist/agent/agent-mode.d.ts +20 -4
- package/dist/agent/agent-mode.js +20 -4
- package/dist/agent/controller.d.ts +38 -3
- package/dist/agent/controller.js +64 -4
- package/dist/agent/headless.js +31 -0
- package/dist/agent/reducer.d.ts +13 -2
- package/dist/agent/reducer.js +1 -0
- package/dist/cli.js +12 -0
- package/dist/commands/agents-command.d.ts +15 -0
- package/dist/commands/agents-command.js +27 -0
- package/dist/commands/builtins.js +131 -4
- package/dist/commands/perf.d.ts +11 -0
- package/dist/commands/perf.js +2 -1
- package/dist/commands/registry.d.ts +14 -0
- package/dist/config/app-paths.d.ts +15 -0
- package/dist/config/app-paths.js +33 -2
- package/dist/config/env.d.ts +4 -1
- package/dist/config/env.js +28 -2
- package/dist/config/load.d.ts +10 -0
- package/dist/config/load.js +8 -1
- package/dist/config/schema.d.ts +68 -0
- package/dist/config/schema.js +39 -0
- package/dist/config/store.js +12 -1
- package/dist/config/ui-state.d.ts +18 -0
- package/dist/config/ui-state.js +9 -0
- package/dist/exec/events.d.ts +25 -0
- package/dist/exec/events.js +4 -0
- package/dist/exec/index.js +16 -1
- package/dist/exec/runner.js +10 -0
- package/dist/proc/limits.d.ts +16 -0
- package/dist/proc/limits.js +16 -0
- package/dist/proc/supervisor.d.ts +20 -1
- package/dist/proc/supervisor.js +42 -14
- package/dist/prompts/command.d.ts +34 -0
- package/dist/prompts/command.js +237 -0
- package/dist/prompts/copy.d.ts +89 -0
- package/dist/prompts/copy.js +131 -0
- package/dist/prompts/fill.d.ts +51 -0
- package/dist/prompts/fill.js +46 -0
- package/dist/prompts/limits.d.ts +53 -0
- package/dist/prompts/limits.js +53 -0
- package/dist/prompts/normalize.d.ts +53 -0
- package/dist/prompts/normalize.js +190 -0
- package/dist/prompts/resolve.d.ts +31 -0
- package/dist/prompts/resolve.js +60 -0
- package/dist/prompts/search.d.ts +58 -0
- package/dist/prompts/search.js +146 -0
- package/dist/prompts/store.d.ts +86 -0
- package/dist/prompts/store.js +453 -0
- package/dist/prompts/types.d.ts +204 -0
- package/dist/prompts/types.js +13 -0
- package/dist/session/checkpoint.d.ts +8 -1
- package/dist/session/checkpoint.js +6 -0
- package/dist/session/persist.d.ts +19 -1
- package/dist/session/persist.js +13 -1
- package/dist/session/startup-session.d.ts +7 -2
- package/dist/session/startup-session.js +5 -2
- package/dist/session/store.js +3 -0
- package/dist/session/validate-session.js +64 -1
- package/dist/team/limits.d.ts +25 -0
- package/dist/team/limits.js +26 -0
- package/dist/team/runtime.js +27 -2
- package/dist/team/settled.d.ts +57 -0
- package/dist/team/settled.js +87 -0
- package/dist/team/subagent.js +48 -2
- package/dist/team/timeline.d.ts +74 -0
- package/dist/team/timeline.js +101 -0
- package/dist/team/types.d.ts +24 -1
- package/dist/todo/acceptance.d.ts +120 -0
- package/dist/todo/acceptance.js +399 -0
- package/dist/todo/follow-through.d.ts +48 -23
- package/dist/todo/follow-through.js +110 -44
- package/dist/todo/limits.d.ts +62 -1
- package/dist/todo/limits.js +62 -1
- package/dist/todo/panel-rows.d.ts +29 -39
- package/dist/todo/panel-rows.js +37 -83
- package/dist/todo/plan-sections.d.ts +60 -0
- package/dist/todo/plan-sections.js +108 -0
- package/dist/todo/prompt.d.ts +17 -12
- package/dist/todo/prompt.js +59 -40
- package/dist/todo/row-window.d.ts +51 -0
- package/dist/todo/row-window.js +107 -0
- package/dist/todo/store.d.ts +139 -31
- package/dist/todo/store.js +271 -73
- package/dist/todo/todo-tool.d.ts +33 -8
- package/dist/todo/todo-tool.js +186 -30
- package/dist/todo/types.d.ts +58 -0
- package/dist/ui/App.js +310 -46
- package/dist/ui/Composer.d.ts +6 -2
- package/dist/ui/Composer.js +2 -2
- package/dist/ui/Header.d.ts +9 -1
- package/dist/ui/Header.js +2 -2
- package/dist/ui/PromptInput.d.ts +21 -1
- package/dist/ui/PromptInput.js +21 -1
- package/dist/ui/ScrollbackShell.d.ts +19 -19
- package/dist/ui/ScrollbackShell.js +8 -1
- package/dist/ui/StatusBar.d.ts +5 -0
- package/dist/ui/StatusBar.js +1 -0
- package/dist/ui/TeamPanel.d.ts +26 -44
- package/dist/ui/TeamPanel.js +46 -135
- package/dist/ui/TodoPanel.d.ts +17 -14
- package/dist/ui/TodoPanel.js +146 -38
- package/dist/ui/Transcript.js +1 -1
- package/dist/ui/composer-input.d.ts +10 -0
- package/dist/ui/composer-input.js +57 -24
- package/dist/ui/entries/TodoCard.d.ts +26 -11
- package/dist/ui/entries/TodoCard.js +56 -15
- package/dist/ui/glyphs.d.ts +19 -0
- package/dist/ui/glyphs.js +4 -0
- package/dist/ui/layout/agents-board.d.ts +102 -0
- package/dist/ui/layout/agents-board.js +389 -0
- package/dist/ui/layout/cells.d.ts +61 -0
- package/dist/ui/layout/cells.js +156 -0
- package/dist/ui/layout/header-hints.d.ts +13 -3
- package/dist/ui/layout/header-hints.js +48 -14
- package/dist/ui/layout/status-detail-layout.js +9 -0
- package/dist/ui/layout/status-layout.d.ts +13 -0
- package/dist/ui/layout/team-row.d.ts +139 -0
- package/dist/ui/layout/team-row.js +246 -0
- package/dist/ui/layout/todo-layout.d.ts +38 -0
- package/dist/ui/layout/todo-layout.js +75 -0
- package/dist/ui/layout/virtual-window.js +23 -3
- package/dist/ui/overlays/AgentsBoardOverlay.d.ts +57 -0
- package/dist/ui/overlays/AgentsBoardOverlay.js +183 -0
- package/dist/ui/overlays/HelpOverlay.js +17 -2
- package/dist/ui/overlays/PromptEditorPage.d.ts +48 -0
- package/dist/ui/overlays/PromptEditorPage.js +227 -0
- package/dist/ui/overlays/PromptLibraryOverlay.d.ts +37 -0
- package/dist/ui/overlays/PromptLibraryOverlay.js +191 -0
- package/dist/ui/overlays/PromptPicker.d.ts +36 -0
- package/dist/ui/overlays/PromptPicker.js +129 -0
- package/dist/ui/overlays/PromptTextArea.d.ts +86 -0
- package/dist/ui/overlays/PromptTextArea.js +141 -0
- package/dist/ui/overlays/prompt-library-state.d.ts +162 -0
- package/dist/ui/overlays/prompt-library-state.js +335 -0
- package/dist/ui/overlays/prompt-picker-state.d.ts +71 -0
- package/dist/ui/overlays/prompt-picker-state.js +98 -0
- package/dist/ui/scrollback/band.js +14 -1
- package/dist/ui/team-status.d.ts +25 -0
- package/dist/ui/team-status.js +31 -3
- package/dist/ui/use-startup-notices.d.ts +35 -1
- package/dist/ui/use-startup-notices.js +29 -2
- package/dist/ui/use-wheel-routing.js +9 -1
- package/package.json +2 -2
package/dist/commands/perf.d.ts
CHANGED
|
@@ -94,6 +94,17 @@ export interface BandPerf {
|
|
|
94
94
|
* reply, which is exactly the state that used to be unrecoverable.
|
|
95
95
|
*/
|
|
96
96
|
headRows: number;
|
|
97
|
+
/**
|
|
98
|
+
* Which rung the acceptance section reached inside the rail
|
|
99
|
+
* (todo-acceptance-criteria §6.9.6): `visible` (header plus rows), `summary` (the
|
|
100
|
+
* one `AC 2/5` line) or `absent` (nothing - the count is on the status chip).
|
|
101
|
+
*
|
|
102
|
+
* `n/a` when there are no criteria at all, which is the same spelling `/perf` uses
|
|
103
|
+
* for the band outside native mode. It is reported on the EXISTING band line rather
|
|
104
|
+
* than as a new row, and it comes from `buildPlanSections` - the same function the
|
|
105
|
+
* rail rendered from, so this is a report and not a second opinion.
|
|
106
|
+
*/
|
|
107
|
+
acceptance?: 'visible' | 'summary' | 'absent' | 'n/a';
|
|
97
108
|
}
|
|
98
109
|
/**
|
|
99
110
|
* Why the right-edge scrollbar is or is not usable, in one record
|
package/dist/commands/perf.js
CHANGED
|
@@ -139,7 +139,8 @@ function formatBandLine(band) {
|
|
|
139
139
|
`tail=${band.previewRows} pool=${band.bandRows} ` +
|
|
140
140
|
`cols=${band.contentCols}/${band.previewCols} ` +
|
|
141
141
|
`reason=${band.reason} held=${band.heldRailRows}/${band.heldTeamRows} ` +
|
|
142
|
-
`window=${band.windowStart}/${band.windowEntries} head=${band.headRows}
|
|
142
|
+
`window=${band.windowStart}/${band.windowEntries} head=${band.headRows}` +
|
|
143
|
+
` acc=${band.acceptance ?? 'n/a'}`;
|
|
143
144
|
}
|
|
144
145
|
/**
|
|
145
146
|
* Format a snapshot as the seven-line block documented in §5.4 (plus the scrollbar
|
|
@@ -12,6 +12,7 @@ import type { FollowThroughBudget } from '../todo/follow-through.js';
|
|
|
12
12
|
import type { UpdateCommandPort } from '../update/types.js';
|
|
13
13
|
import type { SessionCommandPort } from './session-command.js';
|
|
14
14
|
import type { BranchCommandPort } from './branch-command.js';
|
|
15
|
+
import type { PromptCommandPort } from '../prompts/types.js';
|
|
15
16
|
export interface CommandContext {
|
|
16
17
|
/** App-owned shared lock and single feedback path for command and selection copies. */
|
|
17
18
|
requestCopy?: (request: CopyRequest) => Promise<CopyRequestResult>;
|
|
@@ -161,6 +162,19 @@ export interface CommandContext {
|
|
|
161
162
|
* value at run time.
|
|
162
163
|
*/
|
|
163
164
|
branch?: BranchCommandPort;
|
|
165
|
+
/**
|
|
166
|
+
* The quick-prompt library's three capabilities (`/prompts`, quick-prompt-library
|
|
167
|
+
* §4.3 / P1-3).
|
|
168
|
+
*
|
|
169
|
+
* OPTIONAL, and this is the fifth time this file records the same rule: every
|
|
170
|
+
* fixture in this package builds `CommandContext` by literal, so a REQUIRED field
|
|
171
|
+
* would fail to compile every one of them for a feature none of them is about
|
|
172
|
+
* (F-14). Absent means the build has no library, and `/prompts` says exactly that.
|
|
173
|
+
*
|
|
174
|
+
* TYPE-ONLY import, for the reason the `branch` note above records: the command
|
|
175
|
+
* needs the SHAPE of the port, never a value at run time.
|
|
176
|
+
*/
|
|
177
|
+
prompts?: PromptCommandPort;
|
|
164
178
|
}
|
|
165
179
|
/** What `/mouse` can see and do. Read at command time, never captured. */
|
|
166
180
|
export interface MouseCommandPort {
|
|
@@ -90,6 +90,21 @@ export declare function getModelWindowsPath(): string;
|
|
|
90
90
|
* recall (config-state-separation D-1).
|
|
91
91
|
*/
|
|
92
92
|
export declare function getPromptHistoryPath(): string;
|
|
93
|
+
/**
|
|
94
|
+
* `<home>/quick-prompts.json` — the user's own quick-prompt library
|
|
95
|
+
* (quick-prompt-library D-3).
|
|
96
|
+
*
|
|
97
|
+
* A DIRECT CHILD OF THE ROOT, and deliberately NOT a section of `config.json`.
|
|
98
|
+
* `ui-state.ts:5-13` already wrote the rule this follows: anything carrying USER
|
|
99
|
+
* CONTENT, and anything that GROWS with usage, opens its own file. A library of
|
|
100
|
+
* two hundred prompts is exactly that, and `config.json` is where an API key
|
|
101
|
+
* lives.
|
|
102
|
+
*
|
|
103
|
+
* THE APPLICATION WRITES IT, unlike `model-windows.json` above: it is the library's
|
|
104
|
+
* only truth, and the store creates it on the first `add` rather than at startup.
|
|
105
|
+
* Naming follows `getPromptHistoryPath` beside it.
|
|
106
|
+
*/
|
|
107
|
+
export declare function getQuickPromptsPath(): string;
|
|
93
108
|
/** `<home>/state.json` — UI bookkeeping scalars only; see `ui-state.ts`. */
|
|
94
109
|
export declare function getUiStatePath(): string;
|
|
95
110
|
/**
|
package/dist/config/app-paths.js
CHANGED
|
@@ -89,8 +89,22 @@ function isDirectory(path) {
|
|
|
89
89
|
* test that sets `ARAGON_HOME` to something bogus quietly gets the real one.
|
|
90
90
|
*/
|
|
91
91
|
function fallbackRoot() {
|
|
92
|
-
if (process.env.VITEST)
|
|
93
|
-
|
|
92
|
+
if (process.env.VITEST) {
|
|
93
|
+
// ONE DIRECTORY PER WORKER, NOT ONE PER PROCESS.
|
|
94
|
+
//
|
|
95
|
+
// The `threads` pool (vitest.config.ts) gives every worker the SAME
|
|
96
|
+
// `process.pid` - they are threads - so a pid-keyed root is shared by up to
|
|
97
|
+
// `maxWorkers` test files running at the same time. Two of them cleaning up
|
|
98
|
+
// (`rmSync(getSessionsDir())`) while a third writes is a race, and it reports
|
|
99
|
+
// itself as "the session was never written": a red full run whose two files
|
|
100
|
+
// both pass alone. `VITEST_POOL_ID` is the worker's own id and a worker runs
|
|
101
|
+
// one file at a time, so keying on it restores the isolation the contract
|
|
102
|
+
// above promises (measured: `session-store.test.ts` and
|
|
103
|
+
// `exec-text-parity.test.ts` failed together and passed separately).
|
|
104
|
+
const worker = process.env.VITEST_POOL_ID ?? '';
|
|
105
|
+
const suffix = worker.length > 0 ? `-${worker}` : '';
|
|
106
|
+
return join(tmpdir(), `aragon-agent-vitest-${process.pid}${suffix}`);
|
|
107
|
+
}
|
|
94
108
|
return join(homedir(), HOME_DIR_NAME);
|
|
95
109
|
}
|
|
96
110
|
function resolveHomeRoot() {
|
|
@@ -151,6 +165,23 @@ export function getModelWindowsPath() {
|
|
|
151
165
|
export function getPromptHistoryPath() {
|
|
152
166
|
return join(resolution.root, 'prompt-history.jsonl');
|
|
153
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* `<home>/quick-prompts.json` — the user's own quick-prompt library
|
|
170
|
+
* (quick-prompt-library D-3).
|
|
171
|
+
*
|
|
172
|
+
* A DIRECT CHILD OF THE ROOT, and deliberately NOT a section of `config.json`.
|
|
173
|
+
* `ui-state.ts:5-13` already wrote the rule this follows: anything carrying USER
|
|
174
|
+
* CONTENT, and anything that GROWS with usage, opens its own file. A library of
|
|
175
|
+
* two hundred prompts is exactly that, and `config.json` is where an API key
|
|
176
|
+
* lives.
|
|
177
|
+
*
|
|
178
|
+
* THE APPLICATION WRITES IT, unlike `model-windows.json` above: it is the library's
|
|
179
|
+
* only truth, and the store creates it on the first `add` rather than at startup.
|
|
180
|
+
* Naming follows `getPromptHistoryPath` beside it.
|
|
181
|
+
*/
|
|
182
|
+
export function getQuickPromptsPath() {
|
|
183
|
+
return join(resolution.root, 'quick-prompts.json');
|
|
184
|
+
}
|
|
154
185
|
/** `<home>/state.json` — UI bookkeeping scalars only; see `ui-state.ts`. */
|
|
155
186
|
export function getUiStatePath() {
|
|
156
187
|
return join(resolution.root, 'state.json');
|
package/dist/config/env.d.ts
CHANGED
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
* ARAGON_UPDATE,
|
|
19
19
|
* ARAGON_COMPACTION, ARAGON_COMPACTION_THRESHOLD,
|
|
20
20
|
* ARAGON_COMPACTION_KEEP_TURNS, ARAGON_COMPACTION_SUBAGENTS,
|
|
21
|
-
* ARAGON_COMPACTION_ARCHIVE
|
|
21
|
+
* ARAGON_COMPACTION_ARCHIVE,
|
|
22
|
+
* ARAGON_JOBS_ENABLED, ARAGON_JOBS_WAIT_SECONDS, ARAGON_JOBS_STALL_SECONDS,
|
|
23
|
+
* ARAGON_JOBS_PERSIST_LOG, ARAGON_JOBS_NOTICE_STEER,
|
|
24
|
+
* ARAGON_PROMPTS (the quick-prompt library's `enabled` switch, and only that).
|
|
22
25
|
*
|
|
23
26
|
* READ ELSEWHERE, ON PURPOSE: `ARAGON_UPDATE_REGISTRY` and `npm_config_registry`
|
|
24
27
|
* are resolved by `update/registry.ts::resolveRegistryUrl`, NOT here, because
|
package/dist/config/env.js
CHANGED
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
* ARAGON_UPDATE,
|
|
19
19
|
* ARAGON_COMPACTION, ARAGON_COMPACTION_THRESHOLD,
|
|
20
20
|
* ARAGON_COMPACTION_KEEP_TURNS, ARAGON_COMPACTION_SUBAGENTS,
|
|
21
|
-
* ARAGON_COMPACTION_ARCHIVE
|
|
21
|
+
* ARAGON_COMPACTION_ARCHIVE,
|
|
22
|
+
* ARAGON_JOBS_ENABLED, ARAGON_JOBS_WAIT_SECONDS, ARAGON_JOBS_STALL_SECONDS,
|
|
23
|
+
* ARAGON_JOBS_PERSIST_LOG, ARAGON_JOBS_NOTICE_STEER,
|
|
24
|
+
* ARAGON_PROMPTS (the quick-prompt library's `enabled` switch, and only that).
|
|
22
25
|
*
|
|
23
26
|
* READ ELSEWHERE, ON PURPOSE: `ARAGON_UPDATE_REGISTRY` and `npm_config_registry`
|
|
24
27
|
* are resolved by `update/registry.ts::resolveRegistryUrl`, NOT here, because
|
|
@@ -212,8 +215,10 @@ export function readEnvConfig() {
|
|
|
212
215
|
}
|
|
213
216
|
const todo = process.env.ARAGON_TODO?.trim().toLowerCase();
|
|
214
217
|
const todoFollow = process.env.ARAGON_TODO_FOLLOW?.trim().toLowerCase();
|
|
218
|
+
const todoAcceptance = process.env.ARAGON_TODO_ACCEPTANCE?.trim().toLowerCase();
|
|
215
219
|
if ((todo !== undefined && todo.length > 0) ||
|
|
216
|
-
(todoFollow !== undefined && todoFollow.length > 0)
|
|
220
|
+
(todoFollow !== undefined && todoFollow.length > 0) ||
|
|
221
|
+
(todoAcceptance !== undefined && todoAcceptance.length > 0)) {
|
|
217
222
|
// Keyed by `TodoConfig` but VALUED `unknown`, which is what lets the mode be
|
|
218
223
|
// written through unvalidated (below) while still failing to compile if a
|
|
219
224
|
// future key is misspelled.
|
|
@@ -227,6 +232,16 @@ export function readEnvConfig() {
|
|
|
227
232
|
if (todoFollow !== undefined && todoFollow.length > 0) {
|
|
228
233
|
section.followThrough = todoFollow;
|
|
229
234
|
}
|
|
235
|
+
// Same treatment as `enabled`: only the five affirmatives are true, anything
|
|
236
|
+
// else recognized-as-present is false, and an ABSENT variable leaves the key
|
|
237
|
+
// out entirely so the next layer's value survives.
|
|
238
|
+
if (todoAcceptance !== undefined && todoAcceptance.length > 0) {
|
|
239
|
+
section.acceptance =
|
|
240
|
+
todoAcceptance === '1' ||
|
|
241
|
+
todoAcceptance === 'true' ||
|
|
242
|
+
todoAcceptance === 'on' ||
|
|
243
|
+
todoAcceptance === 'yes';
|
|
244
|
+
}
|
|
230
245
|
// A PARTIAL section, safe only because every consumer deep-merges it — the
|
|
231
246
|
// same contract `partial.skills`, `partial.log` and `partial.team` rely on.
|
|
232
247
|
if (Object.keys(section).length > 0)
|
|
@@ -292,6 +307,17 @@ export function readEnvConfig() {
|
|
|
292
307
|
if (Object.keys(section).length > 0)
|
|
293
308
|
partial.jobs = section;
|
|
294
309
|
}
|
|
310
|
+
// ARAGON_PROMPTS=0 is the kill switch for the whole quick-prompt surface: no
|
|
311
|
+
// `Ctrl+P`, no header hint, and `/prompts` reports that the feature is off
|
|
312
|
+
// (D-19 / AC-31). ONLY `enabled` IS REACHABLE HERE. `insertMode` and `hint` are
|
|
313
|
+
// preferences a human sets once, and an environment variable that could silently
|
|
314
|
+
// flip a fill into "overwrite what you had typed" is not a kill switch.
|
|
315
|
+
const prompts = process.env.ARAGON_PROMPTS?.trim().toLowerCase();
|
|
316
|
+
if (prompts !== undefined && prompts.length > 0) {
|
|
317
|
+
partial.prompts = {
|
|
318
|
+
enabled: prompts === '1' || prompts === 'true' || prompts === 'on' || prompts === 'yes',
|
|
319
|
+
};
|
|
320
|
+
}
|
|
295
321
|
const retry = process.env.ARAGON_RETRY?.trim().toLowerCase();
|
|
296
322
|
const retryMax = process.env.ARAGON_RETRY_MAX?.trim();
|
|
297
323
|
if ((retry !== undefined && retry.length > 0) || (retryMax !== undefined && retryMax.length > 0)) {
|
package/dist/config/load.d.ts
CHANGED
|
@@ -118,6 +118,16 @@ export interface CliFlags {
|
|
|
118
118
|
* rejected, which is what every other key in this file does.
|
|
119
119
|
*/
|
|
120
120
|
todoFollow?: string;
|
|
121
|
+
/**
|
|
122
|
+
* `--todo-acceptance` => true, `--no-todo-acceptance` => false, absent =>
|
|
123
|
+
* undefined (todo-acceptance-criteria §6.8.2).
|
|
124
|
+
*
|
|
125
|
+
* DECLARED AS A PAIR, for the reason `--todo-panel` above records at length: it
|
|
126
|
+
* is a PERSISTED setting, so "not passed" has to stay distinguishable from
|
|
127
|
+
* `true`, or commander's lone-`--no-x` default would overwrite a config-file
|
|
128
|
+
* `acceptance: false` on every run that passes no flag at all.
|
|
129
|
+
*/
|
|
130
|
+
todoAcceptance?: boolean;
|
|
121
131
|
/** `--log-level <lv>` — this run only, never persisted. */
|
|
122
132
|
logLevel?: string;
|
|
123
133
|
/** `--log-file` ⇒ true, `--no-log-file` ⇒ false, absent ⇒ undefined. */
|
package/dist/config/load.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import process from 'node:process';
|
|
9
9
|
import { JOB_WAIT_MARGIN_MS } from '../proc/limits.js';
|
|
10
|
-
import { DEFAULT_CONFIG, DEFAULT_SCROLL_MODE, IDLE_TIMEOUT_MARGIN_MS, clampAskRounds, clampDensity, clampHumanTimeout, clampCompactionConfig, clampLogConfig, clampFastConfig, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampBashConfig, clampJobsConfig, clampUpdateConfig, clampTheme, clampThinkingLevel, clampContextWindow, clampMaxTokens, clampMaxRenderInterval, clampScrollMode, clampScrollResumeMs, clampTranscriptRetain, clampTranscriptWindow, coercePositiveInt, isAutoToken, isSkillsToolPolicyMode, legacyTeamCeilingPatch, parseThresholdInput, } from './schema.js';
|
|
10
|
+
import { DEFAULT_CONFIG, DEFAULT_SCROLL_MODE, IDLE_TIMEOUT_MARGIN_MS, clampAskRounds, clampDensity, clampHumanTimeout, clampCompactionConfig, clampLogConfig, clampFastConfig, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampBashConfig, clampJobsConfig, clampPromptsConfig, clampUpdateConfig, clampTheme, clampThinkingLevel, clampContextWindow, clampMaxTokens, clampMaxRenderInterval, clampScrollMode, clampScrollResumeMs, clampTranscriptRetain, clampTranscriptWindow, coercePositiveInt, isAutoToken, isSkillsToolPolicyMode, legacyTeamCeilingPatch, parseThresholdInput, } from './schema.js';
|
|
11
11
|
import { loadDotenv, readEnvConfig, readEnvDisabledSkills } from './env.js';
|
|
12
12
|
import { readConfigFile, updatePersistedConfig } from './store.js';
|
|
13
13
|
import { projectModelProfiles, resolveModelProfileState, resolveModelRoleKey, } from './model-profile-resolution.js';
|
|
@@ -159,6 +159,7 @@ function resolveTodoConfig(flags, env, file) {
|
|
|
159
159
|
...(env.todo ?? {}),
|
|
160
160
|
...(flags.todo !== undefined ? { enabled: flags.todo } : {}),
|
|
161
161
|
...(flags.todoPanel !== undefined ? { panel: flags.todoPanel } : {}),
|
|
162
|
+
...(flags.todoAcceptance !== undefined ? { acceptance: flags.todoAcceptance } : {}),
|
|
162
163
|
// `!== undefined` for the third time, though for a value flag the risk is
|
|
163
164
|
// milder: commander leaves `opts.todoFollow` absent unless it was passed.
|
|
164
165
|
// Written this way anyway so the three lines read as one rule.
|
|
@@ -731,6 +732,12 @@ export function loadConfig(flags = {}, options = {}) {
|
|
|
731
732
|
// NOT `resolveJobsConfig(...)` a second time: that would re-apply the
|
|
732
733
|
// un-converged `waitSeconds` and silently undo I-4.
|
|
733
734
|
jobs,
|
|
735
|
+
// The quick-prompt library's three policy scalars (quick-prompt-library D-19).
|
|
736
|
+
// Resolved through the SAME clamp the read and write paths use, so an env-only
|
|
737
|
+
// `ARAGON_PROMPTS=0` and a file-only `prompts.enabled: false` cannot arrive as
|
|
738
|
+
// two different shapes on `CliConfig`.
|
|
739
|
+
prompts: clampPromptsConfig({ ...DEFAULT_CONFIG.prompts, ...(env.partial.prompts ?? {}),
|
|
740
|
+
...(file.prompts ?? {}) }),
|
|
734
741
|
cwd,
|
|
735
742
|
color,
|
|
736
743
|
colorLevel,
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -489,6 +489,17 @@ export interface TodoConfig {
|
|
|
489
489
|
* be, and would mean replacing both merges first.
|
|
490
490
|
*/
|
|
491
491
|
followThrough: FollowThroughMode;
|
|
492
|
+
/**
|
|
493
|
+
* Must a plan also declare acceptance criteria, and does the UI show them
|
|
494
|
+
* (todo-acceptance-criteria §6.8.1). Default TRUE.
|
|
495
|
+
*
|
|
496
|
+
* THE FOURTH SCALAR, and it is a scalar for exactly the reason above: both
|
|
497
|
+
* hand-written merges in `config/store.ts` spread the whole `todo` object, so a
|
|
498
|
+
* new scalar key flows through them automatically. `clampTodoConfig` below is the
|
|
499
|
+
* only other place that has to know about it - a value that is missing THERE
|
|
500
|
+
* would silently keep the default and make `--no-todo-acceptance` look broken.
|
|
501
|
+
*/
|
|
502
|
+
acceptance: boolean;
|
|
492
503
|
}
|
|
493
504
|
export declare const DEFAULT_TODO_CONFIG: TodoConfig;
|
|
494
505
|
/**
|
|
@@ -851,6 +862,43 @@ export declare const DEFAULT_JOBS_CONFIG: JobsConfig;
|
|
|
851
862
|
* resolve to `undefined` and the setting would silently never apply.
|
|
852
863
|
*/
|
|
853
864
|
export declare function clampJobsConfig(raw: unknown): JobsConfig;
|
|
865
|
+
/**
|
|
866
|
+
* The quick-prompt library's three POLICY scalars (quick-prompt-library D-19).
|
|
867
|
+
*
|
|
868
|
+
* THE LIBRARY ITSELF IS NOT HERE (D-3). Two hundred prompts with bodies is user
|
|
869
|
+
* content that grows with usage, and `ui-state.ts:5-13` already wrote the rule:
|
|
870
|
+
* anything carrying user content opens its own file. `config.json` holds the three
|
|
871
|
+
* decisions that are about BEHAVIOUR - whether the key exists, what a fill does to
|
|
872
|
+
* a non-empty draft, and whether the header teaches the key.
|
|
873
|
+
*
|
|
874
|
+
* ONE LEVEL DEEP, like every section beside it: `runConfigGet` splits on a single
|
|
875
|
+
* dot, so `prompts.hint` resolves and `prompts.some.nested` would not.
|
|
876
|
+
*/
|
|
877
|
+
export interface PromptsConfig {
|
|
878
|
+
/**
|
|
879
|
+
* `false` stops `Ctrl+P` and the header hint; `/prompts` STAYS REGISTERED and
|
|
880
|
+
* reports that the feature is off (D-19 / AC-30). Removing the command as well
|
|
881
|
+
* would leave the one surface that can explain the switch unable to run.
|
|
882
|
+
*/
|
|
883
|
+
enabled: boolean;
|
|
884
|
+
/**
|
|
885
|
+
* What a fill does to a draft that already has text in it (D-6).
|
|
886
|
+
* `insert` keeps the user's words; `replace` overwrites them.
|
|
887
|
+
*/
|
|
888
|
+
insertMode: 'insert' | 'replace';
|
|
889
|
+
/** Whether the header's right-hand column may teach `^P prompts`. */
|
|
890
|
+
hint: boolean;
|
|
891
|
+
}
|
|
892
|
+
export declare const DEFAULT_PROMPTS_CONFIG: PromptsConfig;
|
|
893
|
+
/**
|
|
894
|
+
* THE single gate for every `prompts` read AND write, like the eleven sections
|
|
895
|
+
* above it.
|
|
896
|
+
*
|
|
897
|
+
* An unrecognized `insertMode` falls back to `insert` rather than to `replace`,
|
|
898
|
+
* and that direction is deliberate: a typo must never silently start DISCARDING
|
|
899
|
+
* what the user has already typed into the composer.
|
|
900
|
+
*/
|
|
901
|
+
export declare function clampPromptsConfig(raw: unknown): PromptsConfig;
|
|
854
902
|
/**
|
|
855
903
|
* Parse `0.9`, `90%` or `90` into a ratio, or `null` when it is neither.
|
|
856
904
|
*
|
|
@@ -1013,6 +1061,8 @@ export interface PersistedConfig {
|
|
|
1013
1061
|
bash: BashConfig;
|
|
1014
1062
|
/** Background jobs and bounded waiting. The ELEVENTH; scalars only (see JobsConfig). */
|
|
1015
1063
|
jobs: JobsConfig;
|
|
1064
|
+
/** Quick prompts. The TWELFTH; three scalars (see PromptsConfig). */
|
|
1065
|
+
prompts: PromptsConfig;
|
|
1016
1066
|
}
|
|
1017
1067
|
export declare const DEFAULT_CONFIG: PersistedConfig;
|
|
1018
1068
|
/**
|
|
@@ -1351,6 +1401,24 @@ export interface CliConfig {
|
|
|
1351
1401
|
* `undefined` and report an empty value for a setting that IS on disk.
|
|
1352
1402
|
*/
|
|
1353
1403
|
jobs: JobsConfig;
|
|
1404
|
+
/**
|
|
1405
|
+
* Quick prompts (quick-prompt-library D-19). The TWELFTH nested object; three
|
|
1406
|
+
* scalars, one level deep.
|
|
1407
|
+
*
|
|
1408
|
+
* ON `CliConfig` AS WELL AS `PersistedConfig`, for the reason every section above
|
|
1409
|
+
* records: `App` reads `cfg.prompts?.enabled` / `.hint` / `.insertMode` from a
|
|
1410
|
+
* `CliConfig`, so a key added to the persisted shape alone would round-trip
|
|
1411
|
+
* through the `config` commands, appear in `config list`, and change nothing.
|
|
1412
|
+
*
|
|
1413
|
+
* OPTIONAL ON THIS SHAPE ONLY, and `loadConfig` always fills it. The reason is the
|
|
1414
|
+
* one the `jobs` note above does not have to state: `CliConfig` is built by hand in
|
|
1415
|
+
* ~20 test fixtures, and a REQUIRED section turns every one of them into a compile
|
|
1416
|
+
* error for a feature none of them is about. The three readers then fall back to the
|
|
1417
|
+
* DOCUMENTED defaults (`enabled: true`, `insertMode: 'insert'`, `hint: true`), so a
|
|
1418
|
+
* missing section can only ever behave like a default session - never like a
|
|
1419
|
+
* disabled or destructive one.
|
|
1420
|
+
*/
|
|
1421
|
+
prompts?: PromptsConfig;
|
|
1354
1422
|
/**
|
|
1355
1423
|
* Lifetime submit count driving the composer hint fade (`HINT_FADE_AFTER`).
|
|
1356
1424
|
*
|
package/dist/config/schema.js
CHANGED
|
@@ -578,6 +578,7 @@ export const DEFAULT_TODO_CONFIG = {
|
|
|
578
578
|
enabled: true,
|
|
579
579
|
panel: true,
|
|
580
580
|
followThrough: 'notify',
|
|
581
|
+
acceptance: true,
|
|
581
582
|
};
|
|
582
583
|
/**
|
|
583
584
|
* There is no enum helper in this file, so this follows the `isThinkingLevel`
|
|
@@ -606,6 +607,10 @@ export function clampTodoConfig(raw) {
|
|
|
606
607
|
// `ARAGON_TODO_FOLLOW=garbage` therefore resolves to `'notify'` and throws
|
|
607
608
|
// nothing (AC-5).
|
|
608
609
|
followThrough: followMode(src.followThrough, DEFAULT_TODO_CONFIG.followThrough),
|
|
610
|
+
// The fourth key needs nothing beyond this line: no migration, because
|
|
611
|
+
// `CONFIG_VERSION` is only stamped and never branched, and an old file reaches
|
|
612
|
+
// the new default through `{ ...DEFAULT, ...partial } + clamp`.
|
|
613
|
+
acceptance: bool(src.acceptance, DEFAULT_TODO_CONFIG.acceptance),
|
|
609
614
|
};
|
|
610
615
|
}
|
|
611
616
|
export const DEFAULT_RETRY_CONFIG = {
|
|
@@ -958,6 +963,31 @@ export function clampJobsConfig(raw) {
|
|
|
958
963
|
noticeSteer: bool(src.noticeSteer, DEFAULT_JOBS_CONFIG.noticeSteer),
|
|
959
964
|
};
|
|
960
965
|
}
|
|
966
|
+
export const DEFAULT_PROMPTS_CONFIG = {
|
|
967
|
+
enabled: true,
|
|
968
|
+
insertMode: 'insert',
|
|
969
|
+
hint: true,
|
|
970
|
+
};
|
|
971
|
+
const PROMPT_INSERT_MODES = ['insert', 'replace'];
|
|
972
|
+
/**
|
|
973
|
+
* THE single gate for every `prompts` read AND write, like the eleven sections
|
|
974
|
+
* above it.
|
|
975
|
+
*
|
|
976
|
+
* An unrecognized `insertMode` falls back to `insert` rather than to `replace`,
|
|
977
|
+
* and that direction is deliberate: a typo must never silently start DISCARDING
|
|
978
|
+
* what the user has already typed into the composer.
|
|
979
|
+
*/
|
|
980
|
+
export function clampPromptsConfig(raw) {
|
|
981
|
+
const src = (raw && typeof raw === 'object' ? raw : {});
|
|
982
|
+
const mode = typeof src.insertMode === 'string' ? src.insertMode.trim().toLowerCase() : '';
|
|
983
|
+
return {
|
|
984
|
+
enabled: bool(src.enabled, DEFAULT_PROMPTS_CONFIG.enabled),
|
|
985
|
+
insertMode: PROMPT_INSERT_MODES.includes(mode)
|
|
986
|
+
? mode
|
|
987
|
+
: DEFAULT_PROMPTS_CONFIG.insertMode,
|
|
988
|
+
hint: bool(src.hint, DEFAULT_PROMPTS_CONFIG.hint),
|
|
989
|
+
};
|
|
990
|
+
}
|
|
961
991
|
/**
|
|
962
992
|
* Parse `0.9`, `90%` or `90` into a ratio, or `null` when it is neither.
|
|
963
993
|
*
|
|
@@ -1062,6 +1092,15 @@ export const DEFAULT_CONFIG = {
|
|
|
1062
1092
|
// to `undefined` would throw on `config.jobs.waitSeconds` at construction
|
|
1063
1093
|
// rather than quietly disabling something.
|
|
1064
1094
|
jobs: DEFAULT_JOBS_CONFIG,
|
|
1095
|
+
// And one section later again, for the seventh time, and this one has BOTH
|
|
1096
|
+
// failure directions at once: `prompts.enabled` and `prompts.hint` are `true` by
|
|
1097
|
+
// default, so a `config.json` predating this feature would resolve them to
|
|
1098
|
+
// `undefined` (falsy) and arrive with the key and its hint silently off - while
|
|
1099
|
+
// `prompts.insertMode` would be `undefined`, which is neither `'insert'` nor
|
|
1100
|
+
// `'replace'` and would make `planPromptFill` fall through to its `replace`
|
|
1101
|
+
// branch. That branch discards the user's own words, so the miss would be a data
|
|
1102
|
+
// loss rather than a missing hint.
|
|
1103
|
+
prompts: DEFAULT_PROMPTS_CONFIG,
|
|
1065
1104
|
};
|
|
1066
1105
|
/**
|
|
1067
1106
|
* Runtime state that used to be stored in `config.json` by mistake
|
package/dist/config/store.js
CHANGED
|
@@ -17,7 +17,7 @@ import { getConfigPath, getSessionsDir } from './app-paths.js';
|
|
|
17
17
|
import { registerProfileSecrets, registerSecretsFrom } from '../logging/secret-registry.js';
|
|
18
18
|
import { adaptLegacyConnectionPatch, ModelProfileConfigError, readModelSettingsDisk } from './model-profile-store.js';
|
|
19
19
|
import { normalizeModelProfiles } from './model-profiles.js';
|
|
20
|
-
import { clampBashConfig, clampJobsConfig, CONFIG_VERSION, DEFAULT_CONFIG, clampCompactionConfig, clampFastConfig, clampLogConfig, clampMaxTokens, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampContextWindow, clampUpdateConfig, isAutoToken, stripLegacyStateKeys, } from './schema.js';
|
|
20
|
+
import { clampBashConfig, clampJobsConfig, clampPromptsConfig, CONFIG_VERSION, DEFAULT_CONFIG, clampCompactionConfig, clampFastConfig, clampLogConfig, clampMaxTokens, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampContextWindow, clampUpdateConfig, isAutoToken, stripLegacyStateKeys, } from './schema.js';
|
|
21
21
|
/**
|
|
22
22
|
* Normalize `maxTokens` for both directions of the config file.
|
|
23
23
|
*
|
|
@@ -195,6 +195,11 @@ export function normalizePersistedConfig(input) {
|
|
|
195
195
|
// outright, which is a crash on the first `job_wait` rather than a silently
|
|
196
196
|
// wrong setting.
|
|
197
197
|
jobs: clampJobsConfig({ ...DEFAULT_CONFIG.jobs, ...(partial.jobs ?? {}) }),
|
|
198
|
+
// And the twelfth, on the same line and for the same reason - with one extra
|
|
199
|
+
// edge: without it `prompts.insertMode` reads `undefined`, which is neither
|
|
200
|
+
// `'insert'` nor `'replace'`, so a fill into a non-empty draft would take the
|
|
201
|
+
// branch that REPLACES what the user typed.
|
|
202
|
+
prompts: clampPromptsConfig({ ...DEFAULT_CONFIG.prompts, ...(partial.prompts ?? {}) }),
|
|
198
203
|
};
|
|
199
204
|
}
|
|
200
205
|
/**
|
|
@@ -302,6 +307,12 @@ export function mergePersistedConfig(current, patch) {
|
|
|
302
307
|
// absent — with `noticeSteer`'s default masking it on the next load, so the
|
|
303
308
|
// user would never learn that their privacy switch had been turned back on.
|
|
304
309
|
jobs: clampJobsConfig({ ...current.jobs, ...(patch.jobs ?? {}) }),
|
|
310
|
+
// The twelfth section, and the seventh time this file records the same trap.
|
|
311
|
+
// `aragon config set prompts.hint false` sends `{ prompts: { hint: false } }`;
|
|
312
|
+
// without this line the shallow top-level spread REPLACES the section and
|
|
313
|
+
// `insertMode` is written absent - which reads back as neither `'insert'` nor
|
|
314
|
+
// `'replace'`, i.e. the next fill overwrites the user's own draft.
|
|
315
|
+
prompts: clampPromptsConfig({ ...current.prompts, ...(patch.prompts ?? {}) }),
|
|
305
316
|
};
|
|
306
317
|
return merged;
|
|
307
318
|
}
|
|
@@ -90,6 +90,21 @@ export interface UiState {
|
|
|
90
90
|
* others for the same reasons the two above record, and NOT a schema bump.
|
|
91
91
|
*/
|
|
92
92
|
scrollModeNoticeVersion: number;
|
|
93
|
+
/**
|
|
94
|
+
* Which revision of the "Ctrl+P moved to the prompt library" notice this user has
|
|
95
|
+
* been shown (`0` = none; quick-prompt-library D-20).
|
|
96
|
+
*
|
|
97
|
+
* A VERSION BESIDE THE OTHERS AND NOT A SCHEMA BUMP, for the third time in this
|
|
98
|
+
* file: bumping `UI_STATE_SCHEMA` makes `readFromDisk` discard the whole object, so
|
|
99
|
+
* every user's `submitCount` resets and the composer hint un-fades - to re-show one
|
|
100
|
+
* line. A NEW field simply reads as its default on an older file, which is exactly
|
|
101
|
+
* the behaviour wanted here.
|
|
102
|
+
*
|
|
103
|
+
* IT EXISTS BECAUSE THE KEY MOVED. `Ctrl+P` now opens the prompt library and the
|
|
104
|
+
* mode fallback is `Ctrl+N`; the audience for that sentence is every existing user,
|
|
105
|
+
* and a boolean could only ever say "shown", never "shown WHAT".
|
|
106
|
+
*/
|
|
107
|
+
promptKeyNoticeVersion: number;
|
|
93
108
|
}
|
|
94
109
|
/** Read the state, caching it for the life of the process. Never throws. */
|
|
95
110
|
export declare function loadUiState(): UiState;
|
|
@@ -107,6 +122,9 @@ export declare function setVtInputNoticeVersion(version: number): void;
|
|
|
107
122
|
/** `0` on a file written before the field existed. */
|
|
108
123
|
export declare function getScrollModeNoticeVersion(): number;
|
|
109
124
|
export declare function setScrollModeNoticeVersion(version: number): void;
|
|
125
|
+
/** `0` on a file written before the field existed; see the field's comment. */
|
|
126
|
+
export declare function getPromptKeyNoticeVersion(): number;
|
|
127
|
+
export declare function setPromptKeyNoticeVersion(version: number): void;
|
|
110
128
|
/**
|
|
111
129
|
* Migration-only: fill in fields that are still at their default, and never
|
|
112
130
|
* overwrite a value already here. A second import — after a half-finished
|
package/dist/config/ui-state.js
CHANGED
|
@@ -38,6 +38,7 @@ const DEFAULT_UI_STATE = {
|
|
|
38
38
|
mouseNoticeVersion: 0,
|
|
39
39
|
vtInputNoticeVersion: 0,
|
|
40
40
|
scrollModeNoticeVersion: 0,
|
|
41
|
+
promptKeyNoticeVersion: 0,
|
|
41
42
|
};
|
|
42
43
|
let memory = null;
|
|
43
44
|
/** Non-negative integer or `fallback`; shared by both numeric fields. */
|
|
@@ -71,6 +72,7 @@ function readFromDisk() {
|
|
|
71
72
|
mouseNoticeVersion: coerceCount(parsed.mouseNoticeVersion, DEFAULT_UI_STATE.mouseNoticeVersion),
|
|
72
73
|
vtInputNoticeVersion: coerceCount(parsed.vtInputNoticeVersion, DEFAULT_UI_STATE.vtInputNoticeVersion),
|
|
73
74
|
scrollModeNoticeVersion: coerceCount(parsed.scrollModeNoticeVersion, DEFAULT_UI_STATE.scrollModeNoticeVersion),
|
|
75
|
+
promptKeyNoticeVersion: coerceCount(parsed.promptKeyNoticeVersion, DEFAULT_UI_STATE.promptKeyNoticeVersion),
|
|
74
76
|
};
|
|
75
77
|
}
|
|
76
78
|
catch {
|
|
@@ -151,6 +153,13 @@ export function getScrollModeNoticeVersion() {
|
|
|
151
153
|
export function setScrollModeNoticeVersion(version) {
|
|
152
154
|
update({ scrollModeNoticeVersion: version });
|
|
153
155
|
}
|
|
156
|
+
/** `0` on a file written before the field existed; see the field's comment. */
|
|
157
|
+
export function getPromptKeyNoticeVersion() {
|
|
158
|
+
return loadUiState().promptKeyNoticeVersion;
|
|
159
|
+
}
|
|
160
|
+
export function setPromptKeyNoticeVersion(version) {
|
|
161
|
+
update({ promptKeyNoticeVersion: version });
|
|
162
|
+
}
|
|
154
163
|
/**
|
|
155
164
|
* Migration-only: fill in fields that are still at their default, and never
|
|
156
165
|
* overwrite a value already here. A second import — after a half-finished
|
package/dist/exec/events.d.ts
CHANGED
|
@@ -192,6 +192,22 @@ export interface ExecTodoEvent {
|
|
|
192
192
|
content: string;
|
|
193
193
|
status: 'pending' | 'in_progress' | 'completed';
|
|
194
194
|
}[];
|
|
195
|
+
/**
|
|
196
|
+
* Acceptance counts (todo-acceptance-criteria §6.13.2). `null` when the capability
|
|
197
|
+
* is off or the plan has no criteria.
|
|
198
|
+
*
|
|
199
|
+
* REQUIRED BUT NULLABLE, not optional: `runner` is the only producer and can
|
|
200
|
+
* always answer, while for a consumer `null` and "field absent" mean the same
|
|
201
|
+
* thing under the forward-compatibility contract above. Per-criterion `evidence`
|
|
202
|
+
* never reaches this stream (I-8) - a machine consumer that needs it reads the
|
|
203
|
+
* session file.
|
|
204
|
+
*/
|
|
205
|
+
acceptance: {
|
|
206
|
+
total: number;
|
|
207
|
+
checked: number;
|
|
208
|
+
passed: number;
|
|
209
|
+
failed: number;
|
|
210
|
+
} | null;
|
|
195
211
|
}
|
|
196
212
|
export interface ExecTeamEvent {
|
|
197
213
|
type: 'team';
|
|
@@ -371,6 +387,15 @@ export interface ExecResultEvent {
|
|
|
371
387
|
id: string;
|
|
372
388
|
};
|
|
373
389
|
todos: ExecTodoCounts | null;
|
|
390
|
+
/**
|
|
391
|
+
* The acceptance tally for the run (todo-acceptance-criteria §6.13.2), on the same
|
|
392
|
+
* terms as `ExecTodoEvent.acceptance`: required but nullable, no evidence.
|
|
393
|
+
*/
|
|
394
|
+
acceptance: {
|
|
395
|
+
total: number;
|
|
396
|
+
passed: number;
|
|
397
|
+
failed: number;
|
|
398
|
+
} | null;
|
|
374
399
|
error: ExecErrorInfo | null;
|
|
375
400
|
}
|
|
376
401
|
/**
|
package/dist/exec/events.js
CHANGED
|
@@ -44,6 +44,10 @@ export const EXEC_CAPABILITIES = [
|
|
|
44
44
|
// Background job lifecycle events (long-task-jobs §4.10). A consumer that does
|
|
45
45
|
// not know the `job` type ignores it; this string is how it asks first.
|
|
46
46
|
'background-jobs',
|
|
47
|
+
// Acceptance counts on the todo event and the result event
|
|
48
|
+
// (todo-acceptance-criteria §6.13.2). APPEND-ONLY: a wrapper detects support by
|
|
49
|
+
// asking for this string, and an older wrapper never asks.
|
|
50
|
+
'todo-acceptance',
|
|
47
51
|
];
|
|
48
52
|
export function buildInitEvent(params) {
|
|
49
53
|
return {
|
package/dist/exec/index.js
CHANGED
|
@@ -112,7 +112,7 @@ async function execute(input) {
|
|
|
112
112
|
});
|
|
113
113
|
if (plan.saved) {
|
|
114
114
|
controller.replaceMessages(plan.saved.messages, plan.saved.compactionIdentity);
|
|
115
|
-
controller.restoreTodos(plan.saved.todos);
|
|
115
|
+
controller.restoreTodos(plan.saved.todos, plan.saved.acceptance);
|
|
116
116
|
}
|
|
117
117
|
const config = controller.getConfig();
|
|
118
118
|
emitter.init({
|
|
@@ -190,6 +190,14 @@ async function execute(input) {
|
|
|
190
190
|
cost: buildCost(controller, stats.usage, stats.compactionBilling),
|
|
191
191
|
model: { provider: config.provider, id: config.model },
|
|
192
192
|
todos: todo ? { total: todo.total, done: todo.doneCount } : null,
|
|
193
|
+
// The verdict tally for the run, with no per-criterion evidence (I-8).
|
|
194
|
+
acceptance: todo?.acceptance
|
|
195
|
+
? {
|
|
196
|
+
total: todo.acceptance.total,
|
|
197
|
+
passed: todo.acceptance.passedCount,
|
|
198
|
+
failed: todo.acceptance.failedCount,
|
|
199
|
+
}
|
|
200
|
+
: null,
|
|
193
201
|
error: stats.errorCode && stats.errorMessage
|
|
194
202
|
? { code: stats.errorCode, message: stats.errorMessage }
|
|
195
203
|
: null,
|
|
@@ -288,6 +296,7 @@ function failedResult(sessionId, config, message, code, durationMs) {
|
|
|
288
296
|
cost: { amount: 0, currency: 'USD', known: false },
|
|
289
297
|
model: { provider: config.provider, id: config.model },
|
|
290
298
|
todos: null,
|
|
299
|
+
acceptance: null,
|
|
291
300
|
error: { code, message },
|
|
292
301
|
};
|
|
293
302
|
}
|
|
@@ -479,6 +488,12 @@ function persist(plan, controller, turns, usage, cli, at) {
|
|
|
479
488
|
...(controller.getSessionSnapshot?.() ?? { messages: controller.getMessages() }),
|
|
480
489
|
entries: [],
|
|
481
490
|
todos: controller.getTodoSnapshot?.()?.items ?? [],
|
|
491
|
+
// From the STORE, not the render projection: a run whose capability is off
|
|
492
|
+
// must still persist the verdicts it already has. OPTIONAL CALL, like the line
|
|
493
|
+
// above: `ExecControllerFactory` is a port, and a caller whose controller
|
|
494
|
+
// predates this feature must keep saving sessions rather than fail on a method
|
|
495
|
+
// it never heard of - the failure mode would be a session silently not written.
|
|
496
|
+
acceptance: controller.getAcceptanceItems?.() ?? [],
|
|
482
497
|
},
|
|
483
498
|
meta,
|
|
484
499
|
});
|
package/dist/exec/runner.js
CHANGED
|
@@ -108,6 +108,16 @@ export class ExecRunner {
|
|
|
108
108
|
done: doneCount,
|
|
109
109
|
activeIndex,
|
|
110
110
|
items: items.map((item) => ({ content: item.content, status: item.status })),
|
|
111
|
+
// Counts only, never per-criterion evidence (I-8): this stream is a machine
|
|
112
|
+
// surface, and a criterion's evidence is written for a human to read.
|
|
113
|
+
acceptance: event.snapshot.acceptance
|
|
114
|
+
? {
|
|
115
|
+
total: event.snapshot.acceptance.total,
|
|
116
|
+
checked: event.snapshot.acceptance.checkedCount,
|
|
117
|
+
passed: event.snapshot.acceptance.passedCount,
|
|
118
|
+
failed: event.snapshot.acceptance.failedCount,
|
|
119
|
+
}
|
|
120
|
+
: null,
|
|
111
121
|
});
|
|
112
122
|
});
|
|
113
123
|
if (todos)
|
package/dist/proc/limits.d.ts
CHANGED
|
@@ -79,6 +79,22 @@ export declare const PROC_LIMITS: {
|
|
|
79
79
|
readonly outputCoalesceMs: 100;
|
|
80
80
|
/** `SIGTERM` -> `SIGKILL` escalation window for a graceful stop. */
|
|
81
81
|
readonly stopGraceMs: 3000;
|
|
82
|
+
/**
|
|
83
|
+
* How long to KEEP ASKING whether the `SIGKILL` actually landed before
|
|
84
|
+
* declaring the job `stopped`.
|
|
85
|
+
*
|
|
86
|
+
* THIS NUMBER IS NOT A GUESS ABOUT THE PLATFORM. `killTree` spawns `taskkill`,
|
|
87
|
+
* which is a process of its own: a Windows tree kill of a shell plus its node
|
|
88
|
+
* child measures ~0.8 s on the reference machine (while starting `cmd` costs
|
|
89
|
+
* 50 ms), so the fixed 250 ms this used to allow expired first and `stop()`
|
|
90
|
+
* reported `stopped` with the child still running - AC-18 caught exactly that.
|
|
91
|
+
* The wait stays BOUNDED against the opposite failure (a promise that never
|
|
92
|
+
* resolves); at this deadline the record keeps the honest `killIncomplete`
|
|
93
|
+
* flag instead.
|
|
94
|
+
*/
|
|
95
|
+
readonly killVerifyMs: 2000;
|
|
96
|
+
/** Liveness poll interval while waiting for a `SIGKILL` to land. */
|
|
97
|
+
readonly killVerifyPollMs: 50;
|
|
82
98
|
/** Below this many terminal columns the status chip degrades to `[N]`. */
|
|
83
99
|
readonly statusCompactCols: 92;
|
|
84
100
|
/**
|