@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
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The quick-prompt library's data model (quick-prompt-library §6.1).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/prompts/**` is inside `glyphs.test.ts::inScope`. Chinese copy
|
|
5
|
+
* lives in `copy.ts` as `\uXXXX` escapes, never as literal text in this tree.
|
|
6
|
+
*
|
|
7
|
+
* THE DISK SHAPE IS THE ONLY TRUTH (D-3 / I-6). `App` holds a `PromptLibrary`
|
|
8
|
+
* snapshot for rendering, every mutation goes through `store.ts`, and the store
|
|
9
|
+
* hands the new snapshot back. No component computes an optimistic library of its
|
|
10
|
+
* own, because "the UI says it was added and the disk disagrees" is a failure
|
|
11
|
+
* mode with no error message.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* One entry.
|
|
15
|
+
*
|
|
16
|
+
* `useCount` / `createdAt` / `updatedAt` are ALWAYS present: a missing number
|
|
17
|
+
* would make every consumer write `?? 0` and one of them would eventually forget.
|
|
18
|
+
* `description` / `tags` / `favorite` / `lastUsedAt` are optional because "absent"
|
|
19
|
+
* is their honest state.
|
|
20
|
+
*/
|
|
21
|
+
export interface QuickPrompt {
|
|
22
|
+
/** `randomUUID()`. Never shown in full; the list uses an 8-character prefix. */
|
|
23
|
+
id: string;
|
|
24
|
+
/** 1..80 code points, trimmed, no control characters. Never empty (I-5). */
|
|
25
|
+
title: string;
|
|
26
|
+
/** 1..8000 code points. Original newlines preserved; `\r\n` normalised to `\n`. */
|
|
27
|
+
content: string;
|
|
28
|
+
/** 0..200 code points. */
|
|
29
|
+
description?: string;
|
|
30
|
+
/** 0..6 tags, each 0..24 code points. */
|
|
31
|
+
tags?: string[];
|
|
32
|
+
favorite?: boolean;
|
|
33
|
+
/** Monotonic per entry (I-4). */
|
|
34
|
+
useCount: number;
|
|
35
|
+
/** Epoch ms. */
|
|
36
|
+
createdAt: number;
|
|
37
|
+
updatedAt: number;
|
|
38
|
+
lastUsedAt?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The whole library.
|
|
42
|
+
*
|
|
43
|
+
* `prompts` IS the manual order (I-1): index 0 is what the list shows first and
|
|
44
|
+
* what `Ctrl+Up/Down` rearranges. There is no `order` field, because a second
|
|
45
|
+
* ordering authority is a second thing that can disagree with the first.
|
|
46
|
+
*/
|
|
47
|
+
export interface PromptLibrary {
|
|
48
|
+
schema: 1;
|
|
49
|
+
prompts: QuickPrompt[];
|
|
50
|
+
/** Epoch ms of the last successful write; strictly increasing (I-3). */
|
|
51
|
+
updatedAt: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The persistent re-orderings `/prompts sort <key>` can name (D-9).
|
|
55
|
+
*
|
|
56
|
+
* A WRITE key, not a view: `PromptSortView` is what the picker renders and never
|
|
57
|
+
* persists, this is what the user may ask to have rewritten on disk. They overlap by two
|
|
58
|
+
* words and are deliberately separate types, because "sort by recent" and "show me the
|
|
59
|
+
* recent order for a moment" are different promises.
|
|
60
|
+
*/
|
|
61
|
+
export type PromptSortKey = 'name' | 'recent' | 'favorite';
|
|
62
|
+
/** The picker's three presentations. A VIEW: never persisted (D-9). */
|
|
63
|
+
export type PromptSortView = 'manual' | 'recent' | 'favorite';
|
|
64
|
+
/**
|
|
65
|
+
* Why a write or a lookup failed. A stable code, never a sentence: the sentence
|
|
66
|
+
* comes from `copy.ts`, so the same failure has one wording on every surface.
|
|
67
|
+
*/
|
|
68
|
+
export type PromptWriteError = 'title_required' | 'content_required' | 'title_too_long' | 'content_too_long' | 'description_too_long' | 'tag_too_long' | 'too_many_tags' | 'too_many_prompts' | 'not_found' | 'ambiguous' | 'write_failed';
|
|
69
|
+
/**
|
|
70
|
+
* The result of one mutation.
|
|
71
|
+
*
|
|
72
|
+
* THE LIBRARY TRAVELS WITH THE FAILURE TOO, and that is deliberate: a
|
|
73
|
+
* `write_failed` still applied in memory (D-4), so the caller has to be able to
|
|
74
|
+
* render what the user just created rather than pretending nothing happened.
|
|
75
|
+
*/
|
|
76
|
+
export type PromptMutationResult = {
|
|
77
|
+
ok: true;
|
|
78
|
+
library: PromptLibrary;
|
|
79
|
+
id?: string;
|
|
80
|
+
} | {
|
|
81
|
+
ok: false;
|
|
82
|
+
code: PromptWriteError;
|
|
83
|
+
library: PromptLibrary;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* A one-shot hand-off into the manager overlay (D-21).
|
|
87
|
+
*
|
|
88
|
+
* `App` never edits the overlay's state directly; it hands over an intent, and the
|
|
89
|
+
* overlay consumes it exactly once by nonce. That is what makes `/prompts edit 2`
|
|
90
|
+
* land in the editor with a prefilled draft instead of on row 0 of the list.
|
|
91
|
+
*/
|
|
92
|
+
export type PromptLibraryEntry = {
|
|
93
|
+
kind: 'list';
|
|
94
|
+
focusId?: string;
|
|
95
|
+
} | {
|
|
96
|
+
kind: 'create';
|
|
97
|
+
seed?: {
|
|
98
|
+
title?: string;
|
|
99
|
+
content?: string;
|
|
100
|
+
};
|
|
101
|
+
} | {
|
|
102
|
+
kind: 'edit';
|
|
103
|
+
id: string;
|
|
104
|
+
} | {
|
|
105
|
+
kind: 'delete';
|
|
106
|
+
id: string;
|
|
107
|
+
};
|
|
108
|
+
/** `nonce` is monotonic; the same value is consumed at most once (I-8). */
|
|
109
|
+
export interface PromptLibraryIntent {
|
|
110
|
+
nonce: number;
|
|
111
|
+
entry: PromptLibraryEntry;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* `<n|title>` resolved to an entry (D-22).
|
|
115
|
+
*
|
|
116
|
+
* `ambiguous` CARRIES ITS CANDIDATES. Titles may repeat (I-2), and a lookup that
|
|
117
|
+
* failed without saying which entries matched would leave the user with nothing
|
|
118
|
+
* to type next - which is exactly how `/prompts rm <title>` deletes the wrong
|
|
119
|
+
* prompt, and there is no recycle bin (D-13).
|
|
120
|
+
*/
|
|
121
|
+
export type PromptRefResolution = {
|
|
122
|
+
ok: true;
|
|
123
|
+
prompt: QuickPrompt;
|
|
124
|
+
} | {
|
|
125
|
+
ok: false;
|
|
126
|
+
code: 'not_found';
|
|
127
|
+
} | {
|
|
128
|
+
ok: false;
|
|
129
|
+
code: 'ambiguous';
|
|
130
|
+
candidates: QuickPrompt[];
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* The editable form of one entry.
|
|
134
|
+
*
|
|
135
|
+
* `id: null` means "not saved yet". `tags` is the RAW field text: parsing it on
|
|
136
|
+
* every keystroke would rewrite what the user is typing as they type it.
|
|
137
|
+
*/
|
|
138
|
+
export interface PromptEditorDraft {
|
|
139
|
+
id: string | null;
|
|
140
|
+
title: string;
|
|
141
|
+
content: string;
|
|
142
|
+
description: string;
|
|
143
|
+
tags: string;
|
|
144
|
+
favorite: boolean;
|
|
145
|
+
}
|
|
146
|
+
/** The three things the manager overlay may ask the store to do (P2-1: idempotent). */
|
|
147
|
+
export type PromptLibraryMutation = {
|
|
148
|
+
kind: 'create';
|
|
149
|
+
draft: PromptEditorDraft;
|
|
150
|
+
} | {
|
|
151
|
+
kind: 'update';
|
|
152
|
+
id: string;
|
|
153
|
+
draft: PromptEditorDraft;
|
|
154
|
+
} | {
|
|
155
|
+
kind: 'delete';
|
|
156
|
+
id: string;
|
|
157
|
+
} | {
|
|
158
|
+
kind: 'move';
|
|
159
|
+
id: string;
|
|
160
|
+
delta: -1 | 1;
|
|
161
|
+
} | {
|
|
162
|
+
kind: 'favorite';
|
|
163
|
+
id: string;
|
|
164
|
+
favorite: boolean;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* What a command (or the picker) may ask the host to do (§6.3 / P1-3).
|
|
168
|
+
*
|
|
169
|
+
* THREE METHODS, and each one is something the command layer genuinely cannot do
|
|
170
|
+
* itself: open a surface, hand that surface a payload, or read the library through
|
|
171
|
+
* the same resolver the user's typing is interpreted with. Everything else
|
|
172
|
+
* (notifications, toasts, overlays in general) already exists on `CommandContext`
|
|
173
|
+
* and is not repeated here.
|
|
174
|
+
*/
|
|
175
|
+
export interface PromptCommandPort {
|
|
176
|
+
/** Open the picker (`overlay: 'prompt-pick'`). */
|
|
177
|
+
openPicker(): void;
|
|
178
|
+
/** Open the manager on a specific page, with an optional prefilled draft. */
|
|
179
|
+
openManager(entry: PromptLibraryEntry): void;
|
|
180
|
+
/** `<n|title>` -> entry, through `resolvePromptRef` (D-22). */
|
|
181
|
+
resolve(ref: string): PromptRefResolution;
|
|
182
|
+
}
|
|
183
|
+
/** A validated draft, ready for the store. Produced by `finishPromptEditor`. */
|
|
184
|
+
export interface PromptDraftInput {
|
|
185
|
+
title: string;
|
|
186
|
+
content: string;
|
|
187
|
+
description?: string;
|
|
188
|
+
tags?: string[];
|
|
189
|
+
favorite?: boolean;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The verdict of validating a draft (§4.4 / D-12).
|
|
193
|
+
*
|
|
194
|
+
* `field` is the row that should own focus after a refusal, so the editor can jump
|
|
195
|
+
* there instead of leaving the user staring at a footer with an error code in it.
|
|
196
|
+
*/
|
|
197
|
+
export type PromptDraftVerdict = {
|
|
198
|
+
ok: true;
|
|
199
|
+
input: PromptDraftInput;
|
|
200
|
+
} | {
|
|
201
|
+
ok: false;
|
|
202
|
+
code: PromptWriteError;
|
|
203
|
+
field: 'title' | 'content' | 'description' | 'tags';
|
|
204
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The quick-prompt library's data model (quick-prompt-library §6.1).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/prompts/**` is inside `glyphs.test.ts::inScope`. Chinese copy
|
|
5
|
+
* lives in `copy.ts` as `\uXXXX` escapes, never as literal text in this tree.
|
|
6
|
+
*
|
|
7
|
+
* THE DISK SHAPE IS THE ONLY TRUTH (D-3 / I-6). `App` holds a `PromptLibrary`
|
|
8
|
+
* snapshot for rendering, every mutation goes through `store.ts`, and the store
|
|
9
|
+
* hands the new snapshot back. No component computes an optimistic library of its
|
|
10
|
+
* own, because "the UI says it was added and the disk disagrees" is a failure
|
|
11
|
+
* mode with no error message.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
*/
|
|
32
32
|
import { type Message, type ModelRef } from '@aragon-agent/core';
|
|
33
33
|
import type { Entry, UsageTotal } from '../agent/reducer.js';
|
|
34
|
-
import type { TodoItem } from '../todo/types.js';
|
|
34
|
+
import type { AcceptanceItem, TodoItem } from '../todo/types.js';
|
|
35
35
|
import type { CompactionIdentity } from '../compaction/memory-identity.js';
|
|
36
36
|
import { type SessionLockHandle } from './store.js';
|
|
37
37
|
/**
|
|
@@ -58,6 +58,13 @@ export interface CheckpointDeps {
|
|
|
58
58
|
compactionIdentity?: CompactionIdentity;
|
|
59
59
|
};
|
|
60
60
|
readTodos(): TodoItem[];
|
|
61
|
+
/**
|
|
62
|
+
* The acceptance verdicts, for the same reason `readTodos` exists: a checkpoint
|
|
63
|
+
* must not lose the conclusions the user was just shown
|
|
64
|
+
* (todo-acceptance-criteria §6.12). OPTIONAL so a caller that has no table — and
|
|
65
|
+
* every existing test double — keeps compiling and writes no key.
|
|
66
|
+
*/
|
|
67
|
+
readAcceptance?(): AcceptanceItem[];
|
|
61
68
|
readModel(): ModelRef;
|
|
62
69
|
/** `meta.cwd`; read at every write because `/cwd` can change it. */
|
|
63
70
|
readCwd(): string;
|
|
@@ -322,6 +322,9 @@ export class SessionCheckpointWriter {
|
|
|
322
322
|
...(input.compactionIdentity ? { compactionIdentity: input.compactionIdentity } : {}),
|
|
323
323
|
entries: input.entries,
|
|
324
324
|
todos: this.deps.readTodos(),
|
|
325
|
+
...(this.deps.readAcceptance
|
|
326
|
+
? { acceptance: this.deps.readAcceptance() }
|
|
327
|
+
: {}),
|
|
325
328
|
meta: this.buildMeta(input),
|
|
326
329
|
};
|
|
327
330
|
try {
|
|
@@ -447,6 +450,9 @@ export class SessionCheckpointWriter {
|
|
|
447
450
|
view.entries.length,
|
|
448
451
|
lastEntry,
|
|
449
452
|
this.deps.readTodos().length,
|
|
453
|
+
// A verdict landing must force a checkpoint even when the step list is
|
|
454
|
+
// unchanged: that is the one transition a `todos.length` key cannot see.
|
|
455
|
+
this.deps.readAcceptance?.().filter((item) => item.status !== 'pending').length ?? 0,
|
|
450
456
|
this.pinned ? 'pin' : '-',
|
|
451
457
|
].join('|');
|
|
452
458
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Message, ModelRef } from '@aragon-agent/core';
|
|
9
9
|
import type { Entry } from '../agent/reducer.js';
|
|
10
|
-
import type { TodoItem } from '../todo/types.js';
|
|
10
|
+
import type { AcceptanceItem, TodoItem } from '../todo/types.js';
|
|
11
11
|
import { type CompactionIdentity } from '../compaction/memory-identity.js';
|
|
12
12
|
/**
|
|
13
13
|
* Bookkeeping `aragon exec` attaches to the sessions it owns
|
|
@@ -75,6 +75,19 @@ export interface SavedSession {
|
|
|
75
75
|
* right answer for a session that predates the feature (D-20 / D-22).
|
|
76
76
|
*/
|
|
77
77
|
todos?: TodoItem[];
|
|
78
|
+
/**
|
|
79
|
+
* The acceptance table's VERDICTS at save time (todo-acceptance-criteria §6.12).
|
|
80
|
+
*
|
|
81
|
+
* ADDITIVE AND OPTIONAL, exactly like `todos` above, so `SESSION_VERSION` stays 1
|
|
82
|
+
* and an older file simply yields `undefined` - which restores as "no criteria"
|
|
83
|
+
* and leaves the rail, the card and the chip exactly as they were (AC-30).
|
|
84
|
+
*
|
|
85
|
+
* `reopen` is consumed before anything is stored and `in_progress` is a derived
|
|
86
|
+
* state, so each entry on disk carries only `content` / `check` / `status`
|
|
87
|
+
* (three-valued here) / `evidence`; `restore` lets the store re-derive which
|
|
88
|
+
* criterion is being checked.
|
|
89
|
+
*/
|
|
90
|
+
acceptance?: AcceptanceItem[];
|
|
78
91
|
/**
|
|
79
92
|
* Written by `aragon exec` (cli-integration-surface §5.2 / D-10) AND by the
|
|
80
93
|
* TUI's session checkpoint (tui-session-id-resume §6.1).
|
|
@@ -109,6 +122,11 @@ export declare function saveSession(filePath: string, data: {
|
|
|
109
122
|
compactionIdentity?: CompactionIdentity;
|
|
110
123
|
entries: Entry[];
|
|
111
124
|
todos: TodoItem[];
|
|
125
|
+
/**
|
|
126
|
+
* The acceptance verdicts. OPTIONAL HERE, unlike `todos`, only to keep the field
|
|
127
|
+
* additive for callers that predate it; every writer in this package passes it.
|
|
128
|
+
*/
|
|
129
|
+
acceptance?: AcceptanceItem[];
|
|
112
130
|
meta?: SessionMeta;
|
|
113
131
|
}): void;
|
|
114
132
|
/**
|
package/dist/session/persist.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
9
9
|
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
10
10
|
import { getSessionsDir } from '../config/store.js';
|
|
11
|
+
import { stripEphemeralRuns } from '../team/settled.js';
|
|
11
12
|
import { validateSession } from './validate-session.js';
|
|
12
13
|
import { validateCompactionIdentity, verifyCompactionIdentity, } from '../compaction/memory-identity.js';
|
|
13
14
|
import { getLogger } from '../logging/logger.js';
|
|
@@ -109,8 +110,19 @@ export function saveSession(filePath, data) {
|
|
|
109
110
|
model: data.model,
|
|
110
111
|
messages: data.messages,
|
|
111
112
|
...(data.compactionIdentity ? { compactionIdentity: data.compactionIdentity } : {}),
|
|
112
|
-
|
|
113
|
+
// THE EPHEMERAL-RUN GATE IS THE THIRD STRIP IN THIS CHAIN (tui-subagent-panel
|
|
114
|
+
// §4.5.4 / RV-P0-1), and it is the only one that protects EVERY write path:
|
|
115
|
+
// `/save`, the session checkpoint and the exit flush all arrive here. Without it a
|
|
116
|
+
// dispatch-time save would carry each child's 24-event timeline into the file, no
|
|
117
|
+
// matter how careful the dispatch exit is - the live `team` entry holds the LIVE
|
|
118
|
+
// runs while the dispatch is running (`agent/reducer.ts::teamUpdate`).
|
|
119
|
+
entries: stripEphemeralRuns(stripServiceTail(stripLiveToolOutput(data.entries))),
|
|
113
120
|
todos: data.todos,
|
|
121
|
+
// ONE KEY, WRITTEN ONLY WHEN THERE IS SOMETHING TO WRITE, so a session with the
|
|
122
|
+
// capability off produces a file byte-identical to today's.
|
|
123
|
+
...(data.acceptance && data.acceptance.length > 0
|
|
124
|
+
? { acceptance: data.acceptance }
|
|
125
|
+
: {}),
|
|
114
126
|
...(data.meta ? { meta: data.meta } : {}),
|
|
115
127
|
};
|
|
116
128
|
writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf-8');
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { Message } from '@aragon-agent/core';
|
|
22
22
|
import type { Entry } from '../agent/reducer.js';
|
|
23
|
-
import type { TodoItem } from '../todo/types.js';
|
|
23
|
+
import type { AcceptanceItem, TodoItem } from '../todo/types.js';
|
|
24
24
|
import type { CompactionIdentity } from '../compaction/memory-identity.js';
|
|
25
25
|
import { type SavedSession } from './persist.js';
|
|
26
26
|
/** Who this process is, as the rest of the CLI sees it. */
|
|
@@ -50,7 +50,12 @@ export interface StartupSessionInput {
|
|
|
50
50
|
*/
|
|
51
51
|
export interface SessionRestorePort {
|
|
52
52
|
replaceMessages(messages: Message[], identity?: CompactionIdentity): void;
|
|
53
|
-
|
|
53
|
+
/**
|
|
54
|
+
* The acceptance table is OPTIONAL on this port, so a test double or an `exec`
|
|
55
|
+
* caller that predates the feature keeps compiling and restores "no criteria" -
|
|
56
|
+
* the same additive shape as `SavedSession.acceptance`.
|
|
57
|
+
*/
|
|
58
|
+
restoreTodos(items: TodoItem[], acceptance?: AcceptanceItem[]): void;
|
|
54
59
|
setModel(providerId: string, modelId: string, baseUrl?: string): void;
|
|
55
60
|
}
|
|
56
61
|
export type StartupSessionResolution = {
|
|
@@ -39,8 +39,11 @@ import { basenameId, isValidSessionId, looksLikeSessionPath, resolveSessionRef,
|
|
|
39
39
|
*/
|
|
40
40
|
export function applyRestoredSession(port, saved, opts = {}) {
|
|
41
41
|
port.replaceMessages(saved.messages, saved.compactionIdentity);
|
|
42
|
-
// Absence clears the previous conversation's
|
|
43
|
-
|
|
42
|
+
// Absence clears the previous conversation's plan, including old files. The
|
|
43
|
+
// verdicts come back with it, for the reason `SavedSession.acceptance` records:
|
|
44
|
+
// restoring the steps and dropping the conclusions shows a plan as unstarted that
|
|
45
|
+
// the user already watched being verified.
|
|
46
|
+
port.restoreTodos(saved.todos ?? [], saved.acceptance ?? []);
|
|
44
47
|
if (!opts.skipModel && saved.model?.providerId && saved.model?.modelId) {
|
|
45
48
|
port.setModel(saved.model.providerId, saved.model.modelId, saved.model.baseUrl);
|
|
46
49
|
}
|
package/dist/session/store.js
CHANGED
|
@@ -188,6 +188,9 @@ export function writeSession(input) {
|
|
|
188
188
|
? { compactionIdentity: input.session.compactionIdentity } : {}),
|
|
189
189
|
entries: input.session.entries,
|
|
190
190
|
todos: input.session.todos ?? [],
|
|
191
|
+
// Optional on the input, so an `exec` caller that has no acceptance table writes
|
|
192
|
+
// no key at all instead of an empty one.
|
|
193
|
+
...(input.session.acceptance ? { acceptance: input.session.acceptance } : {}),
|
|
191
194
|
meta: input.meta,
|
|
192
195
|
});
|
|
193
196
|
writePointer(input.meta.cwd, input.id, input.meta.updatedAt);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isAdapterProvider } from '../config/schema.js';
|
|
2
2
|
import { normalizeTodos } from '../todo/normalize.js';
|
|
3
3
|
import { TODO_LIMITS } from '../todo/limits.js';
|
|
4
|
+
import { acceptanceSummary, normalizeAcceptance } from '../todo/acceptance.js';
|
|
4
5
|
import { validateCompactionIdentity } from '../compaction/memory-identity.js';
|
|
5
6
|
import { MemoryError } from '../compaction/memory.js';
|
|
6
7
|
function fail(path, expected) {
|
|
@@ -160,7 +161,26 @@ const ENTRY_FIELDS = {
|
|
|
160
161
|
team: { dispatchId: string, requested: number, runs: array(subagent), aborted: boolean,
|
|
161
162
|
durationMs: optional(number), active: boolean },
|
|
162
163
|
todo: { items: array(todo), doneCount: number, total: number, live: boolean,
|
|
163
|
-
interrupted: optional(boolean)
|
|
164
|
+
interrupted: optional(boolean),
|
|
165
|
+
// THE ACCEPTANCE BLOCK ON A TRANSCRIPT CARD (todo-acceptance-criteria §6.12).
|
|
166
|
+
// IT IS THE PROJECTION, NOT THE RAW TABLE: `Entry.acceptance` is an
|
|
167
|
+
// `AcceptanceSnapshot | null` (`agent/reducer.ts`), because the card reads
|
|
168
|
+
// `checkedCount` / `failedCount` without re-walking the rows - and `null` is a
|
|
169
|
+
// real value there, the one every card written while the capability is off
|
|
170
|
+
// holds. Demanding an items array here would make every session containing a todo
|
|
171
|
+
// card unloadable, and the CLI would tell the user to delete their conversation.
|
|
172
|
+
// OPTIONAL AND LOOSELY TYPED, then normalized per entry below: a card saved before
|
|
173
|
+
// this feature has no such key, and an item that is malformed must cost that one
|
|
174
|
+
// criterion rather than the whole session. "Strict at the boundary" means the
|
|
175
|
+
// SHAPE is enforced, not that a single bad row takes the file down.
|
|
176
|
+
acceptance: optional((value, path) => {
|
|
177
|
+
if (value === null)
|
|
178
|
+
return;
|
|
179
|
+
const snapshot = record(value, path);
|
|
180
|
+
if (!Array.isArray(snapshot.items))
|
|
181
|
+
fail(`${path}.items`, 'an array');
|
|
182
|
+
optional(number)(snapshot.updatedAt, `${path}.updatedAt`);
|
|
183
|
+
}) },
|
|
164
184
|
retry: {
|
|
165
185
|
attempt: number, maxRetries: number, errorType: string, message: string, delayMs: number,
|
|
166
186
|
resumeAt: optional(number), startedAt: number, totalRetries: optional(number),
|
|
@@ -256,5 +276,48 @@ export function validateSession(value) {
|
|
|
256
276
|
if (source.todos !== undefined) {
|
|
257
277
|
prepared.todos = normalizeTodos(source.todos, TODO_LIMITS.maxItems).items;
|
|
258
278
|
}
|
|
279
|
+
// THE SESSION FILE'S OWN TABLE, normalized exactly like a model payload: a
|
|
280
|
+
// user-editable file gets a model payload's treatment (`TodoStore.restore`'s
|
|
281
|
+
// standing argument). Absent stays absent, so an old file loads unchanged.
|
|
282
|
+
if (source.acceptance !== undefined) {
|
|
283
|
+
prepared.acceptance = normalizeAcceptance(source.acceptance, [], { enabled: true }).items;
|
|
284
|
+
}
|
|
285
|
+
prepared.entries = sanitizeEntryAcceptance(prepared.entries);
|
|
259
286
|
return prepared;
|
|
260
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* Drop the acceptance rows a persisted card cannot use, keeping every usable one.
|
|
290
|
+
*
|
|
291
|
+
* ONE BAD ROW MUST NOT COST THE SESSION: the card is HISTORY, and a resume that
|
|
292
|
+
* refuses because one evidence string was a number would throw away the
|
|
293
|
+
* conversation to protect a footnote. Rows are repaired by the same normalizer the
|
|
294
|
+
* model's payloads go through, which is also what guarantees a card on screen and a
|
|
295
|
+
* card in the file agree about what a criterion is.
|
|
296
|
+
*
|
|
297
|
+
* THE PROJECTION IS REBUILT FROM ITS ROWS, never trusted: `total` / `checkedCount` /
|
|
298
|
+
* `failedCount` are derived quantities, and a file that edited them (or a build that
|
|
299
|
+
* later changed how they are counted) would otherwise draw a header that disagrees
|
|
300
|
+
* with the rows underneath it. `updatedAt` is carried over so a card does not claim
|
|
301
|
+
* to have changed when it was only reloaded; a row set that ends up empty becomes
|
|
302
|
+
* `null`, which is what the card means by "no acceptance block".
|
|
303
|
+
*/
|
|
304
|
+
function sanitizeEntryAcceptance(entries) {
|
|
305
|
+
if (!Array.isArray(entries))
|
|
306
|
+
return entries;
|
|
307
|
+
return entries.map((entry) => {
|
|
308
|
+
if (!entry || typeof entry !== 'object')
|
|
309
|
+
return entry;
|
|
310
|
+
const card = entry;
|
|
311
|
+
if (card.kind !== 'todo' || card.acceptance === undefined)
|
|
312
|
+
return entry;
|
|
313
|
+
if (card.acceptance === null)
|
|
314
|
+
return card;
|
|
315
|
+
const snapshot = card.acceptance;
|
|
316
|
+
const items = normalizeAcceptance(snapshot.items, [], { enabled: true }).items;
|
|
317
|
+
const updatedAt = typeof snapshot.updatedAt === 'number' ? snapshot.updatedAt : 0;
|
|
318
|
+
return {
|
|
319
|
+
...card,
|
|
320
|
+
acceptance: items.length > 0 ? acceptanceSummary(items, () => updatedAt) : null,
|
|
321
|
+
};
|
|
322
|
+
});
|
|
323
|
+
}
|
package/dist/team/limits.d.ts
CHANGED
|
@@ -96,6 +96,31 @@ export declare const TEAM_LIMITS: {
|
|
|
96
96
|
* command; below it, a basename or a program name. Mirrors `statusCompactCols`.
|
|
97
97
|
* This chooses WHICH FACT to show; `activityBudget` chooses how much of it. */
|
|
98
98
|
readonly activityWideCols: 100;
|
|
99
|
+
/**
|
|
100
|
+
* Below this many columns the roster's activity cell gives way ENTIRELY
|
|
101
|
+
* (tui-subagent-panel §4.2.2).
|
|
102
|
+
*
|
|
103
|
+
* STRUCTURAL, like everything else in this block: twelve characters of prose in
|
|
104
|
+
* a 40-column terminal push the description column below its own twelve-column
|
|
105
|
+
* floor, and "who is doing what" outranks "what they are writing right now" when
|
|
106
|
+
* there is room for only one. That is why the cell returns 0 rather than
|
|
107
|
+
* `activityMinChars` below this width.
|
|
108
|
+
*/
|
|
109
|
+
readonly activityDropCols: 56;
|
|
110
|
+
/**
|
|
111
|
+
* Events kept per child in `SubagentRun.timeline` (§4.5.3). Twenty-four covers
|
|
112
|
+
* a typical dispatch's complete tool sequence; ten children x 24 x 120 chars is
|
|
113
|
+
* about 29 KB at peak, and the ring is EPHEMERAL - it never reaches a file.
|
|
114
|
+
*/
|
|
115
|
+
readonly timelineEntries: 24;
|
|
116
|
+
/** Display clamp on one timeline line; the same order as `activityArgChars`. */
|
|
117
|
+
readonly timelineTextChars: 120;
|
|
118
|
+
/**
|
|
119
|
+
* Row ceiling of the Agents board's projection. The overlay scrolls, so this is
|
|
120
|
+
* a memory bound rather than a fit: one row per fact and at most ten children
|
|
121
|
+
* plus one detail section, which no healthy dispatch can reach.
|
|
122
|
+
*/
|
|
123
|
+
readonly boardMaxRows: 240;
|
|
99
124
|
/** Retries of a child that produced NOTHING. One, and not configurable: a
|
|
100
125
|
* second retry doubles the worst-case latency of a failing dispatch and buys
|
|
101
126
|
* nothing a re-dispatch by the lead would not buy better. */
|
package/dist/team/limits.js
CHANGED
|
@@ -107,6 +107,32 @@ export const TEAM_LIMITS = {
|
|
|
107
107
|
* command; below it, a basename or a program name. Mirrors `statusCompactCols`.
|
|
108
108
|
* This chooses WHICH FACT to show; `activityBudget` chooses how much of it. */
|
|
109
109
|
activityWideCols: 100,
|
|
110
|
+
/**
|
|
111
|
+
* Below this many columns the roster's activity cell gives way ENTIRELY
|
|
112
|
+
* (tui-subagent-panel §4.2.2).
|
|
113
|
+
*
|
|
114
|
+
* STRUCTURAL, like everything else in this block: twelve characters of prose in
|
|
115
|
+
* a 40-column terminal push the description column below its own twelve-column
|
|
116
|
+
* floor, and "who is doing what" outranks "what they are writing right now" when
|
|
117
|
+
* there is room for only one. That is why the cell returns 0 rather than
|
|
118
|
+
* `activityMinChars` below this width.
|
|
119
|
+
*/
|
|
120
|
+
activityDropCols: 56,
|
|
121
|
+
// --- The Agents board (tui-subagent-panel §4.4 / §4.5) ---
|
|
122
|
+
/**
|
|
123
|
+
* Events kept per child in `SubagentRun.timeline` (§4.5.3). Twenty-four covers
|
|
124
|
+
* a typical dispatch's complete tool sequence; ten children x 24 x 120 chars is
|
|
125
|
+
* about 29 KB at peak, and the ring is EPHEMERAL - it never reaches a file.
|
|
126
|
+
*/
|
|
127
|
+
timelineEntries: 24,
|
|
128
|
+
/** Display clamp on one timeline line; the same order as `activityArgChars`. */
|
|
129
|
+
timelineTextChars: 120,
|
|
130
|
+
/**
|
|
131
|
+
* Row ceiling of the Agents board's projection. The overlay scrolls, so this is
|
|
132
|
+
* a memory bound rather than a fit: one row per fact and at most ten children
|
|
133
|
+
* plus one detail section, which no healthy dispatch can reach.
|
|
134
|
+
*/
|
|
135
|
+
boardMaxRows: 240,
|
|
110
136
|
// --- Cold-start retry (team-live-activity F-4) ---
|
|
111
137
|
/** Retries of a child that produced NOTHING. One, and not configurable: a
|
|
112
138
|
* second retry doubles the worst-case latency of a failing dispatch and buys
|
package/dist/team/runtime.js
CHANGED
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
* pre-feature behaviour.
|
|
29
29
|
*/
|
|
30
30
|
import { TeamBus } from './bus.js';
|
|
31
|
+
import { settledRun } from './settled.js';
|
|
32
|
+
import { appendTimeline, withSettleEntry } from './timeline.js';
|
|
31
33
|
import { TEAM_AGGREGATE_LABEL, TEAM_LIMITS } from './limits.js';
|
|
32
34
|
import { TeamOverseer, buildReplacementPrompt, nextOverseerLadderStepMs, resolveOverseerFirstCheckMs, } from './overseer.js';
|
|
33
35
|
import { shouldRetryColdStart } from './retry.js';
|
|
@@ -581,7 +583,13 @@ export class TeamRuntime {
|
|
|
581
583
|
}), { inputTokens: 0, outputTokens: 0 });
|
|
582
584
|
const outcome = {
|
|
583
585
|
dispatchId,
|
|
584
|
-
|
|
586
|
+
// THE DISPATCH EXIT'S STRIP (tui-subagent-panel §4.5.4). `settledRun` drops the
|
|
587
|
+
// four fields with no reader on a settled run (`activity` / `activityArgs` /
|
|
588
|
+
// `retry` / `timeline`) and KEEPS `lastIntervention`, which the settled card's
|
|
589
|
+
// badge and the supervision report read. The save boundary strips the fifth one
|
|
590
|
+
// (`team/settled.ts` + `session/persist.ts`) - one gate is not enough, because
|
|
591
|
+
// the live entry's runs are written to disk during the dispatch.
|
|
592
|
+
runs: handles.map((h) => settledRun(h.run)),
|
|
585
593
|
requested,
|
|
586
594
|
startedAt,
|
|
587
595
|
endedAt: Date.now(),
|
|
@@ -999,6 +1007,16 @@ export class TeamRuntime {
|
|
|
999
1007
|
at,
|
|
1000
1008
|
reasonHead: decision.reason.slice(0, 60),
|
|
1001
1009
|
};
|
|
1010
|
+
// The board's timeline records the supervisor's ACTIONS only (tui-subagent-panel
|
|
1011
|
+
// §4.5.2): a `wait` decision is an inspection, not an intervention, and one line
|
|
1012
|
+
// per inspection would fill the ring with `nothing happened`.
|
|
1013
|
+
if (decision.action !== 'wait') {
|
|
1014
|
+
handle.run.timeline = appendTimeline(handle.run.timeline, {
|
|
1015
|
+
kind: 'overseer',
|
|
1016
|
+
at,
|
|
1017
|
+
text: decision.action + ': ' + decision.reason.slice(0, 60),
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1002
1020
|
this.publish(dispatchId, handle.run);
|
|
1003
1021
|
}
|
|
1004
1022
|
}
|
|
@@ -1199,7 +1217,14 @@ export class TeamRuntime {
|
|
|
1199
1217
|
// Events
|
|
1200
1218
|
// -------------------------------------------------------------------------
|
|
1201
1219
|
publish(dispatchId, run) {
|
|
1202
|
-
const copy = {
|
|
1220
|
+
const copy = {
|
|
1221
|
+
// The attempt's terminal event rides the EMITTED snapshot only (see
|
|
1222
|
+
// `timeline.ts::withSettleEntry`): `publish` is every state change's single exit,
|
|
1223
|
+
// so this is the one place that also covers the two paths which set a terminal
|
|
1224
|
+
// phase without going through `settlePhase` (§4.5.2 / RV-P1-3).
|
|
1225
|
+
...withSettleEntry(run, Date.now()),
|
|
1226
|
+
filesTouched: [...run.filesTouched],
|
|
1227
|
+
};
|
|
1203
1228
|
if (this.snapshotState && this.snapshotState.dispatchId === dispatchId) {
|
|
1204
1229
|
this.snapshotState = {
|
|
1205
1230
|
...this.snapshotState,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two stripping lists, and the two functions that apply them
|
|
3
|
+
* (tui-subagent-panel §4.5.4).
|
|
4
|
+
*
|
|
5
|
+
* WHY TWO LISTS AND NOT ONE. The fields fall into three groups, not two:
|
|
6
|
+
*
|
|
7
|
+
* - `activity` / `activityArgs` / `retry` / `timeline` have NO reader on a settled run
|
|
8
|
+
* (the card and the report read `summary` / `error` / the counters), so they are
|
|
9
|
+
* removed at the dispatch exit as well;
|
|
10
|
+
* - `lastIntervention` MUST survive onto the settled run -
|
|
11
|
+
* `overseer-runtime-supervision.test.ts` asserts it and the supervision report reads
|
|
12
|
+
* it - but `team/types.ts` marks it TRANSIENT / never persisted, and it is not part
|
|
13
|
+
* of `session/validate-session.ts`'s persisted shape either. So it is stripped at
|
|
14
|
+
* the SAVE boundary only;
|
|
15
|
+
* - `retryable`, `truncated`, `compactions`, `lastTool`, `summary`, `error` are facts
|
|
16
|
+
* that still mean something after the dispatch, and are in NEITHER list. Deleting
|
|
17
|
+
* `retryable` in passing would be the kind of "cleanup" that loses a contract.
|
|
18
|
+
*
|
|
19
|
+
* WHY TWO PLACES AND NOT ONE (§4.5.4 / RV-P0-1). `dispatch()`'s exit only cleans the
|
|
20
|
+
* FINAL outcome. Everything written to disk goes through `saveSession`, and during a
|
|
21
|
+
* dispatch the live `team` entry holds the LIVE runs - `teamUpdate` writes them
|
|
22
|
+
* straight into `view.entries`. So a `/save`, a checkpoint or the exit flush issued
|
|
23
|
+
* mid-dispatch would carry the timeline into `<id>.json` even with the dispatch exit
|
|
24
|
+
* perfectly clean. The save boundary is therefore the second, independent gate, and it
|
|
25
|
+
* is the one that protects all three write paths (`R-12`).
|
|
26
|
+
*
|
|
27
|
+
* WHY THIS IS NOT IN `runtime.ts` (RV-P1-4): that file is already past the 1,000-line
|
|
28
|
+
* ceiling `CLAUDE.md` sets and has no dated exception in `.claude-index/config.md`, so
|
|
29
|
+
* new logic goes here and `runtime.ts` keeps one call.
|
|
30
|
+
*
|
|
31
|
+
* ASCII ONLY: `src/team/**` is inside `glyphs.test.ts`'s static scan.
|
|
32
|
+
*/
|
|
33
|
+
import type { Entry } from '../agent/reducer.js';
|
|
34
|
+
import type { SubagentRun } from './types.js';
|
|
35
|
+
/** Fields with no reader on a settled run. Stripped at the dispatch exit. */
|
|
36
|
+
export declare const SETTLE_STRIP_FIELDS: readonly ["activity", "activityArgs", "retry", "timeline"];
|
|
37
|
+
/**
|
|
38
|
+
* Fields that may never reach a file. `lastIntervention` joins the four above because
|
|
39
|
+
* it must live on the settled run while staying out of every persisted one.
|
|
40
|
+
*/
|
|
41
|
+
export declare const PERSIST_STRIP_FIELDS: readonly ["activity", "activityArgs", "retry", "timeline", "lastIntervention"];
|
|
42
|
+
/**
|
|
43
|
+
* The dispatch exit: one run, without `SETTLE_STRIP_FIELDS`.
|
|
44
|
+
*
|
|
45
|
+
* `lastIntervention` is deliberately KEPT (see this file's header) - the settled card's
|
|
46
|
+
* badge and the supervision report both read it.
|
|
47
|
+
*/
|
|
48
|
+
export declare function settledRun(run: SubagentRun): SubagentRun;
|
|
49
|
+
/**
|
|
50
|
+
* The save boundary: every `kind: 'team'` entry's runs, without
|
|
51
|
+
* `PERSIST_STRIP_FIELDS`.
|
|
52
|
+
*
|
|
53
|
+
* Entries that carry no team runs - or whose runs carry none of the fields - are
|
|
54
|
+
* returned UNTOUCHED, which is what keeps an ordinary session file byte-identical to
|
|
55
|
+
* the one this build produced before the feature.
|
|
56
|
+
*/
|
|
57
|
+
export declare function stripEphemeralRuns(entries: Entry[]): Entry[];
|