@llblab/pi-actors 0.41.1 → 0.42.1
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/AGENTS.md +11 -6
- package/BACKLOG.md +1 -65
- package/CHANGELOG.md +25 -0
- package/README.md +24 -4
- package/dist/index.js +25 -121
- package/dist/lib/async-runs.d.ts +37 -5
- package/dist/lib/async-runs.js +181 -51
- package/dist/lib/automatic-review-runtime.d.ts +18 -0
- package/dist/lib/automatic-review-runtime.js +96 -0
- package/dist/lib/command-templates.js +1 -1
- package/dist/lib/draft-consolidation-transaction.d.ts +65 -0
- package/dist/lib/draft-consolidation-transaction.js +610 -0
- package/dist/lib/draft-consolidation.d.ts +35 -0
- package/dist/lib/draft-consolidation.js +126 -0
- package/dist/lib/draft-review.d.ts +56 -0
- package/dist/lib/draft-review.js +254 -0
- package/dist/lib/draft-sleep.d.ts +65 -0
- package/dist/lib/draft-sleep.js +468 -0
- package/dist/lib/file-state.d.ts +8 -1
- package/dist/lib/file-state.js +115 -18
- package/dist/lib/inspector-actions.d.ts +16 -0
- package/dist/lib/inspector-actions.js +57 -0
- package/dist/lib/inspector-command.d.ts +7 -0
- package/dist/lib/inspector-command.js +37 -0
- package/dist/lib/inspector-overlay.d.ts +23 -3
- package/dist/lib/inspector-overlay.js +327 -70
- package/dist/lib/inspector.d.ts +9 -0
- package/dist/lib/inspector.js +49 -1
- package/dist/lib/observability.d.ts +13 -0
- package/dist/lib/observability.js +160 -6
- package/dist/lib/paths.d.ts +7 -0
- package/dist/lib/paths.js +28 -0
- package/dist/lib/recipes-discovery.js +32 -24
- package/dist/lib/recipes-usage.d.ts +18 -6
- package/dist/lib/recipes-usage.js +445 -34
- package/dist/lib/review-control.d.ts +14 -0
- package/dist/lib/review-control.js +111 -0
- package/dist/lib/review-diagnostics.d.ts +11 -0
- package/dist/lib/review-diagnostics.js +148 -0
- package/dist/lib/review-projection.d.ts +14 -0
- package/dist/lib/review-projection.js +170 -0
- package/dist/lib/run-ui-runtime.d.ts +18 -0
- package/dist/lib/run-ui-runtime.js +123 -0
- package/dist/lib/runs-artifacts.d.ts +1 -1
- package/dist/lib/runs-artifacts.js +1 -1
- package/dist/lib/runs-control.d.ts +10 -2
- package/dist/lib/runs-control.js +37 -7
- package/dist/lib/runs-identity.d.ts +1 -1
- package/dist/lib/runs-identity.js +1 -1
- package/dist/lib/runs-index.d.ts +11 -2
- package/dist/lib/runs-index.js +46 -23
- package/dist/lib/runs-mailbox.d.ts +1 -1
- package/dist/lib/runs-mailbox.js +1 -1
- package/dist/lib/runs-messages.d.ts +1 -1
- package/dist/lib/runs-messages.js +1 -1
- package/dist/lib/runs-outbox.d.ts +1 -1
- package/dist/lib/runs-outbox.js +1 -1
- package/dist/lib/runs-ownership.d.ts +1 -1
- package/dist/lib/runs-ownership.js +18 -4
- package/dist/lib/runs-parent-teardown.d.ts +51 -0
- package/dist/lib/runs-parent-teardown.js +172 -0
- package/dist/lib/runs-process.d.ts +1 -1
- package/dist/lib/runs-process.js +5 -4
- package/dist/lib/runs-retention.d.ts +1 -1
- package/dist/lib/runs-retention.js +1 -1
- package/dist/lib/runs-start.d.ts +5 -3
- package/dist/lib/runs-start.js +7 -48
- package/dist/lib/runs-status.d.ts +5 -3
- package/dist/lib/runs-status.js +7 -6
- package/dist/lib/runtime.d.ts +7 -1
- package/dist/lib/runtime.js +32 -18
- package/dist/lib/tool-review-lineage-transaction.d.ts +27 -0
- package/dist/lib/tool-review-lineage-transaction.js +597 -0
- package/dist/lib/tool-review-lineage.d.ts +24 -0
- package/dist/lib/tool-review-lineage.js +98 -0
- package/dist/lib/tool-review-scheduler.d.ts +80 -0
- package/dist/lib/tool-review-scheduler.js +494 -0
- package/dist/lib/tool-review-transaction.d.ts +50 -0
- package/dist/lib/tool-review-transaction.js +362 -0
- package/dist/lib/tool-review.d.ts +56 -0
- package/dist/lib/tool-review.js +197 -0
- package/dist/lib/tools-inspect.js +28 -4
- package/dist/lib/tools-local.js +21 -4
- package/dist/lib/tools-message.d.ts +1 -0
- package/dist/lib/tools-message.js +29 -17
- package/dist/lib/tools-spawn.js +14 -2
- package/dist/lib/tools.d.ts +1 -0
- package/dist/lib/tools.js +1 -0
- package/dist/recipes/draft-review.json +24 -0
- package/dist/recipes/tool-review.json +24 -0
- package/dist/scripts/async-runner.mjs +9 -9
- package/dist/scripts/build-dist.mjs +6 -1
- package/dist/scripts/conformance.mjs +6 -1
- package/dist/scripts/recipe-utils.mjs +3 -3
- package/dist/scripts/release-gates.mjs +165 -0
- package/dist/skills/actors/SKILL.md +9 -8
- package/dist/skills/swarm/SKILL.md +1 -1
- package/docs/actor-inspector.md +20 -11
- package/docs/async-runs.md +16 -2
- package/docs/recipe-library.md +7 -3
- package/docs/template-recipes.md +4 -11
- package/docs/tool-registry.md +13 -4
- package/index.ts +27 -142
- package/lib/async-runs.ts +283 -67
- package/lib/automatic-review-runtime.ts +135 -0
- package/lib/command-templates.ts +1 -1
- package/lib/draft-consolidation-transaction.ts +821 -0
- package/lib/draft-consolidation.ts +181 -0
- package/lib/draft-review.ts +325 -0
- package/lib/draft-sleep.ts +576 -0
- package/lib/file-state.ts +143 -19
- package/lib/inspector-actions.ts +79 -0
- package/lib/inspector-command.ts +54 -0
- package/lib/inspector-overlay.ts +377 -91
- package/lib/inspector.ts +73 -1
- package/lib/observability.ts +194 -5
- package/lib/paths.ts +43 -0
- package/lib/recipes-discovery.ts +34 -26
- package/lib/recipes-usage.ts +569 -40
- package/lib/review-control.ts +137 -0
- package/lib/review-diagnostics.ts +164 -0
- package/lib/review-projection.ts +200 -0
- package/lib/run-ui-runtime.ts +153 -0
- package/lib/runs-artifacts.ts +1 -1
- package/lib/runs-control.ts +69 -6
- package/lib/runs-identity.ts +1 -1
- package/lib/runs-index.ts +57 -21
- package/lib/runs-mailbox.ts +1 -1
- package/lib/runs-messages.ts +1 -1
- package/lib/runs-outbox.ts +1 -1
- package/lib/runs-ownership.ts +23 -4
- package/lib/runs-parent-teardown.ts +257 -0
- package/lib/runs-process.ts +5 -4
- package/lib/runs-retention.ts +1 -1
- package/lib/runs-start.ts +13 -68
- package/lib/runs-status.ts +17 -8
- package/lib/runtime.ts +34 -17
- package/lib/tool-review-lineage-transaction.ts +881 -0
- package/lib/tool-review-lineage.ts +145 -0
- package/lib/tool-review-scheduler.ts +635 -0
- package/lib/tool-review-transaction.ts +563 -0
- package/lib/tool-review.ts +270 -0
- package/lib/tools-inspect.ts +35 -4
- package/lib/tools-local.ts +29 -4
- package/lib/tools-message.ts +45 -30
- package/lib/tools-spawn.ts +22 -2
- package/lib/tools.ts +5 -0
- package/package.json +5 -3
- package/recipes/draft-review.json +24 -0
- package/recipes/tool-review.json +24 -0
- package/scripts/async-runner.mjs +9 -9
- package/scripts/build-dist.mjs +6 -1
- package/scripts/conformance.mjs +6 -1
- package/scripts/recipe-utils.mjs +3 -3
- package/scripts/release-gates.mjs +165 -0
- package/skills/actors/SKILL.md +9 -8
- package/skills/swarm/SKILL.md +1 -1
|
@@ -5,12 +5,19 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import { stripVTControlCharacters } from "node:util";
|
|
8
|
-
import { matchesKey, truncateToWidth, visibleWidth,
|
|
8
|
+
import { matchesKey, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
9
9
|
import * as Inspector from "./inspector.js";
|
|
10
|
+
const INSPECTOR_TABS = [
|
|
11
|
+
"recipe",
|
|
12
|
+
"communications",
|
|
13
|
+
"turns",
|
|
14
|
+
];
|
|
10
15
|
const DETAIL_SECTION_BREAK = { sectionBreak: true };
|
|
11
16
|
export class ActorInspectorOverlay {
|
|
12
17
|
done;
|
|
18
|
+
killRun;
|
|
13
19
|
ownerId;
|
|
20
|
+
readTurns;
|
|
14
21
|
stateRoot;
|
|
15
22
|
theme;
|
|
16
23
|
tui;
|
|
@@ -24,23 +31,33 @@ export class ActorInspectorOverlay {
|
|
|
24
31
|
detailOpen = false;
|
|
25
32
|
detailScroll = 0;
|
|
26
33
|
detailTurn;
|
|
27
|
-
|
|
34
|
+
feedback;
|
|
35
|
+
killConfirmation;
|
|
36
|
+
killDialogChoice = "cancel";
|
|
28
37
|
readKeys = new Set();
|
|
29
38
|
focus = "tabs";
|
|
30
39
|
filterControlIndex = 0;
|
|
31
40
|
menuLevel = "filter";
|
|
32
41
|
selectorIndex = 0;
|
|
42
|
+
recipeScroll = 0;
|
|
33
43
|
rowIndex = 0;
|
|
34
44
|
selectedRun;
|
|
35
45
|
subagentIndex = 0;
|
|
36
|
-
tab = "
|
|
46
|
+
tab = "recipe";
|
|
47
|
+
turnCache;
|
|
37
48
|
constructor(options) {
|
|
38
49
|
this.done = options.done;
|
|
50
|
+
this.killRun = options.killRun;
|
|
39
51
|
this.ownerId = options.ownerId;
|
|
52
|
+
this.readTurns = options.readTurns ?? Inspector.readActorInspectorTurns;
|
|
40
53
|
this.stateRoot = options.stateRoot;
|
|
41
54
|
this.theme = options.theme;
|
|
42
55
|
this.tui = options.tui;
|
|
43
|
-
this.refreshTimer = setInterval(() =>
|
|
56
|
+
this.refreshTimer = setInterval(() => {
|
|
57
|
+
if (this.focus !== "list" && this.focus !== "detail")
|
|
58
|
+
this.turnCache = undefined;
|
|
59
|
+
this.tui.requestRender();
|
|
60
|
+
}, 1000);
|
|
44
61
|
this.refreshTimer.unref?.();
|
|
45
62
|
}
|
|
46
63
|
handleInput(data) {
|
|
@@ -50,6 +67,34 @@ export class ActorInspectorOverlay {
|
|
|
50
67
|
this.done();
|
|
51
68
|
return;
|
|
52
69
|
}
|
|
70
|
+
if (this.killConfirmation) {
|
|
71
|
+
const key = data.toLowerCase();
|
|
72
|
+
if (matchesKey(data, "escape") || key === "n") {
|
|
73
|
+
this.cancelKill();
|
|
74
|
+
}
|
|
75
|
+
else if (matchesKey(data, "left") ||
|
|
76
|
+
matchesKey(data, "right") ||
|
|
77
|
+
matchesKey(data, "tab")) {
|
|
78
|
+
this.killDialogChoice =
|
|
79
|
+
this.killDialogChoice === "cancel" ? "kill" : "cancel";
|
|
80
|
+
}
|
|
81
|
+
else if (key === "y") {
|
|
82
|
+
this.confirmKill();
|
|
83
|
+
}
|
|
84
|
+
else if (matchesKey(data, "return")) {
|
|
85
|
+
if (this.killDialogChoice === "kill")
|
|
86
|
+
this.confirmKill();
|
|
87
|
+
else
|
|
88
|
+
this.cancelKill();
|
|
89
|
+
}
|
|
90
|
+
this.tui.requestRender();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (data.toLowerCase() === "k") {
|
|
94
|
+
this.requestKill(runs);
|
|
95
|
+
this.tui.requestRender();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
53
98
|
if (matchesKey(data, "escape")) {
|
|
54
99
|
if (this.focus === "select") {
|
|
55
100
|
if (this.menuLevel === "value") {
|
|
@@ -61,6 +106,8 @@ export class ActorInspectorOverlay {
|
|
|
61
106
|
}
|
|
62
107
|
else if (this.focus === "detail")
|
|
63
108
|
this.backDetail();
|
|
109
|
+
else if (this.focus === "recipe")
|
|
110
|
+
this.focus = "tabs";
|
|
64
111
|
else
|
|
65
112
|
this.done();
|
|
66
113
|
this.tui.requestRender();
|
|
@@ -80,19 +127,35 @@ export class ActorInspectorOverlay {
|
|
|
80
127
|
this.tui.requestRender();
|
|
81
128
|
return;
|
|
82
129
|
}
|
|
130
|
+
if (this.focus === "recipe") {
|
|
131
|
+
if (matchesKey(data, "up")) {
|
|
132
|
+
if (this.recipeScroll === 0)
|
|
133
|
+
this.focus = "tabs";
|
|
134
|
+
else
|
|
135
|
+
this.recipeScroll -= 1;
|
|
136
|
+
}
|
|
137
|
+
else if (matchesKey(data, "down"))
|
|
138
|
+
this.recipeScroll += 1;
|
|
139
|
+
else if (matchesKey(data, "pageUp"))
|
|
140
|
+
this.recipeScroll = Math.max(0, this.recipeScroll - this.contentViewportRows());
|
|
141
|
+
else if (matchesKey(data, "pageDown"))
|
|
142
|
+
this.recipeScroll += this.contentViewportRows();
|
|
143
|
+
else if (matchesKey(data, "left"))
|
|
144
|
+
this.focus = "tabs";
|
|
145
|
+
this.tui.requestRender();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
83
148
|
if (this.focus === "detail") {
|
|
84
149
|
if (matchesKey(data, "up"))
|
|
85
150
|
this.detailScroll = Math.max(0, this.detailScroll - 1);
|
|
86
151
|
else if (matchesKey(data, "down"))
|
|
87
152
|
this.detailScroll += 1;
|
|
153
|
+
else if (matchesKey(data, "pageUp"))
|
|
154
|
+
this.detailScroll = Math.max(0, this.detailScroll - this.contentViewportRows());
|
|
155
|
+
else if (matchesKey(data, "pageDown"))
|
|
156
|
+
this.detailScroll += this.contentViewportRows();
|
|
88
157
|
else if (matchesKey(data, "left"))
|
|
89
158
|
this.backDetail();
|
|
90
|
-
else if ((matchesKey(data, "right") || matchesKey(data, "return")) &&
|
|
91
|
-
this.detailView === "evidence" &&
|
|
92
|
-
this.tab === "turns") {
|
|
93
|
-
this.detailView = "transcript";
|
|
94
|
-
this.detailScroll = 0;
|
|
95
|
-
}
|
|
96
159
|
this.tui.requestRender();
|
|
97
160
|
return;
|
|
98
161
|
}
|
|
@@ -108,12 +171,18 @@ export class ActorInspectorOverlay {
|
|
|
108
171
|
}
|
|
109
172
|
else if (this.focus === "tabs") {
|
|
110
173
|
if (matchesKey(data, "left") || matchesKey(data, "right")) {
|
|
111
|
-
|
|
174
|
+
const current = INSPECTOR_TABS.indexOf(this.tab);
|
|
175
|
+
const direction = matchesKey(data, "right") ? 1 : -1;
|
|
176
|
+
this.tab = INSPECTOR_TABS[(current + direction + INSPECTOR_TABS.length) % INSPECTOR_TABS.length];
|
|
112
177
|
this.filterControlIndex = 0;
|
|
178
|
+
this.recipeScroll = 0;
|
|
113
179
|
this.rowIndex = 0;
|
|
114
180
|
}
|
|
115
181
|
else if (matchesKey(data, "up"))
|
|
116
182
|
this.focus = "runs";
|
|
183
|
+
else if ((matchesKey(data, "down") || matchesKey(data, "return")) &&
|
|
184
|
+
this.tab === "recipe")
|
|
185
|
+
this.focus = "recipe";
|
|
117
186
|
else if (matchesKey(data, "down") && this.listItemCount() > 0)
|
|
118
187
|
this.focus = "list";
|
|
119
188
|
else if (matchesKey(data, "return"))
|
|
@@ -121,7 +190,13 @@ export class ActorInspectorOverlay {
|
|
|
121
190
|
}
|
|
122
191
|
else if (this.focus === "list") {
|
|
123
192
|
const count = this.tab === "communications" ? this.communicationPreviews().length : this.turnItems().length;
|
|
124
|
-
if (matchesKey(data, "
|
|
193
|
+
if (matchesKey(data, "left"))
|
|
194
|
+
this.focus = "tabs";
|
|
195
|
+
else if (matchesKey(data, "pageUp"))
|
|
196
|
+
this.rowIndex = Math.max(0, this.rowIndex - this.contentViewportRows());
|
|
197
|
+
else if (matchesKey(data, "pageDown"))
|
|
198
|
+
this.rowIndex = Math.min(Math.max(0, count - 1), this.rowIndex + this.contentViewportRows());
|
|
199
|
+
else if (matchesKey(data, "up")) {
|
|
125
200
|
if (this.rowIndex === 0)
|
|
126
201
|
this.focus = "tabs";
|
|
127
202
|
else
|
|
@@ -138,6 +213,8 @@ export class ActorInspectorOverlay {
|
|
|
138
213
|
this.ensureSelectedRun(this.runs());
|
|
139
214
|
const safeWidth = Math.max(24, width);
|
|
140
215
|
const innerWidth = Math.max(1, safeWidth - 2);
|
|
216
|
+
if (this.killConfirmation)
|
|
217
|
+
return this.renderKillDialog(safeWidth, innerWidth);
|
|
141
218
|
const lines = [];
|
|
142
219
|
lines.push(this.border("╭", " Actor Inspector ", "╮", innerWidth));
|
|
143
220
|
lines.push(this.row(this.renderRunControl(), innerWidth));
|
|
@@ -167,11 +244,21 @@ export class ActorInspectorOverlay {
|
|
|
167
244
|
else
|
|
168
245
|
lines.push(this.border("├", "", "┤", innerWidth));
|
|
169
246
|
this.contentStripeIndices = [];
|
|
170
|
-
const
|
|
247
|
+
const baseContent = this.detailOpen
|
|
171
248
|
? this.renderDetail(innerWidth)
|
|
172
249
|
: this.selectedRun
|
|
173
250
|
? this.renderTimeline(innerWidth)
|
|
174
251
|
: this.renderRunSelector(innerWidth);
|
|
252
|
+
const content = this.feedback && !this.killConfirmation
|
|
253
|
+
? [
|
|
254
|
+
this.theme.fg(this.feedback.ok
|
|
255
|
+
? "success"
|
|
256
|
+
: /^Kill (failed|rejected):/.test(this.feedback.message)
|
|
257
|
+
? "error"
|
|
258
|
+
: "warning", ` ${this.feedback.message}`),
|
|
259
|
+
...baseContent.slice(0, Math.max(0, this.contentViewportRows() - 1)),
|
|
260
|
+
]
|
|
261
|
+
: baseContent;
|
|
175
262
|
const contentViewportRows = this.contentViewportRows();
|
|
176
263
|
const selectorRows = selector.slice(1);
|
|
177
264
|
for (let index = 0; index < Math.max(content.length, contentViewportRows); index += 1) {
|
|
@@ -215,7 +302,9 @@ export class ActorInspectorOverlay {
|
|
|
215
302
|
}
|
|
216
303
|
selectRun(run, index) {
|
|
217
304
|
this.selectedRun = run;
|
|
305
|
+
this.turnCache = undefined;
|
|
218
306
|
this.runIndex = index;
|
|
307
|
+
this.recipeScroll = 0;
|
|
219
308
|
this.rowIndex = 0;
|
|
220
309
|
this.subagentIndex = 0;
|
|
221
310
|
this.communicationFrom = "all";
|
|
@@ -229,7 +318,105 @@ export class ActorInspectorOverlay {
|
|
|
229
318
|
if (next)
|
|
230
319
|
this.selectRun(next.run, nextIndex);
|
|
231
320
|
}
|
|
321
|
+
requestKill(runs) {
|
|
322
|
+
this.feedback = undefined;
|
|
323
|
+
if (this.focus !== "runs") {
|
|
324
|
+
this.feedback = { ok: false, message: "Focus Run before using Kill." };
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const run = runs.find((item) => item.run === this.selectedRun);
|
|
328
|
+
if (!run) {
|
|
329
|
+
this.feedback = { ok: false, message: "Kill unavailable: no owned run." };
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (!this.killRun) {
|
|
333
|
+
this.feedback = { ok: false, message: "Kill unavailable in this Inspector." };
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (run.status !== "running") {
|
|
337
|
+
this.feedback = {
|
|
338
|
+
ok: false,
|
|
339
|
+
message: `Kill unavailable: run is ${run.status}.`,
|
|
340
|
+
};
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (!run.runInstanceId) {
|
|
344
|
+
this.feedback = {
|
|
345
|
+
ok: false,
|
|
346
|
+
message: "Kill unavailable: run generation unavailable.",
|
|
347
|
+
};
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
this.killConfirmation = {
|
|
351
|
+
run: run.run,
|
|
352
|
+
runInstanceId: run.runInstanceId,
|
|
353
|
+
status: run.status,
|
|
354
|
+
};
|
|
355
|
+
this.killDialogChoice = "cancel";
|
|
356
|
+
}
|
|
357
|
+
cancelKill() {
|
|
358
|
+
this.feedback = { ok: false, message: "Kill cancelled." };
|
|
359
|
+
this.killConfirmation = undefined;
|
|
360
|
+
this.killDialogChoice = "cancel";
|
|
361
|
+
}
|
|
362
|
+
confirmKill() {
|
|
363
|
+
const confirmation = this.killConfirmation;
|
|
364
|
+
this.killConfirmation = undefined;
|
|
365
|
+
this.killDialogChoice = "cancel";
|
|
366
|
+
if (!confirmation || !this.killRun) {
|
|
367
|
+
this.feedback = { ok: false, message: "Kill unavailable in this Inspector." };
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
this.feedback = this.killRun(confirmation.run, confirmation.runInstanceId);
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
375
|
+
this.feedback = {
|
|
376
|
+
ok: false,
|
|
377
|
+
message: `Kill failed: ${message.replaceAll(/\s+/g, " ").slice(0, 160)}.`,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
renderKillDialog(_width, innerWidth) {
|
|
382
|
+
const confirmation = this.killConfirmation;
|
|
383
|
+
const totalRows = this.contentViewportRows() + 7;
|
|
384
|
+
const cancel = this.killDialogChoice === "cancel"
|
|
385
|
+
? this.theme.bg("selectedBg", this.theme.fg("accent", " Cancel "))
|
|
386
|
+
: this.theme.fg("muted", " Cancel ");
|
|
387
|
+
const kill = this.killDialogChoice === "kill"
|
|
388
|
+
? this.theme.bg("selectedBg", this.theme.fg("error", " Kill actor "))
|
|
389
|
+
: this.theme.fg("error", " Kill actor ");
|
|
390
|
+
const body = [
|
|
391
|
+
"",
|
|
392
|
+
this.theme.fg("error", "Kill this running actor?"),
|
|
393
|
+
"",
|
|
394
|
+
`${this.theme.fg("muted", "Run:")} ${this.theme.fg("accent", `run:${confirmation.run}`)}`,
|
|
395
|
+
`${this.theme.fg("muted", "Current status:")} ${this.theme.fg("warning", confirmation.status)}`,
|
|
396
|
+
"",
|
|
397
|
+
this.theme.fg("text", "This sends canonical control.kill."),
|
|
398
|
+
this.theme.fg("error", "The action is destructive and cannot be undone."),
|
|
399
|
+
"",
|
|
400
|
+
`${cancel} ${kill}`,
|
|
401
|
+
"",
|
|
402
|
+
];
|
|
403
|
+
const lines = [this.border("╭", " Confirm Actor Kill ", "╮", innerWidth)];
|
|
404
|
+
const availableRows = Math.max(1, totalRows - 2);
|
|
405
|
+
const topPadding = Math.max(0, Math.floor((availableRows - body.length) / 2));
|
|
406
|
+
const dialogRows = [
|
|
407
|
+
...Array.from({ length: topPadding }, () => ""),
|
|
408
|
+
...body,
|
|
409
|
+
].slice(0, availableRows);
|
|
410
|
+
while (dialogRows.length < availableRows)
|
|
411
|
+
dialogRows.push("");
|
|
412
|
+
for (const line of dialogRows)
|
|
413
|
+
lines.push(this.row(this.center(line, innerWidth), innerWidth));
|
|
414
|
+
lines.push(this.border("╰", " ←→/tab choose · enter activate · esc cancel ", "╯", innerWidth));
|
|
415
|
+
return lines;
|
|
416
|
+
}
|
|
232
417
|
listItemCount() {
|
|
418
|
+
if (this.tab === "recipe")
|
|
419
|
+
return 0;
|
|
233
420
|
return this.tab === "communications"
|
|
234
421
|
? this.communicationPreviews().length
|
|
235
422
|
: this.turnItems().length;
|
|
@@ -239,24 +426,35 @@ export class ActorInspectorOverlay {
|
|
|
239
426
|
const runControl = stripVTControlCharacters(this.renderRunControl());
|
|
240
427
|
return Math.max(0, runControl.indexOf("Run:") - 2);
|
|
241
428
|
}
|
|
242
|
-
const label = this.tab === "communications"
|
|
429
|
+
const label = this.tab === "communications"
|
|
430
|
+
? "Messages"
|
|
431
|
+
: this.tab === "turns"
|
|
432
|
+
? "Turns"
|
|
433
|
+
: "Recipe";
|
|
243
434
|
const tabs = stripVTControlCharacters(this.renderTabs());
|
|
244
435
|
return Math.max(0, tabs.indexOf(label) - 2);
|
|
245
436
|
}
|
|
246
437
|
renderKeyHints() {
|
|
247
438
|
const hint = (keys, description) => `${this.theme.fg("accent", keys)}${this.theme.fg("dim", ` ${description}`)}`;
|
|
439
|
+
if (this.killConfirmation)
|
|
440
|
+
return ` ${hint("y/enter", "confirm kill")} ${hint("n/esc", "cancel")}`;
|
|
248
441
|
if (this.focus === "select")
|
|
249
442
|
return this.menuLevel === "value"
|
|
250
443
|
? ` ${hint("↑↓", "option")} ${hint("enter", "apply")} ${hint("←/esc", "back")}`
|
|
251
444
|
: ` ${hint("↑↓", "option")} ${hint("→/enter", "open")} ${hint("←/esc", "back")}`;
|
|
445
|
+
if (this.focus === "recipe")
|
|
446
|
+
return ` ${hint("↑↓/pgup/pgdn", "scroll")} ${hint("↑ at top", "tabs")} ${hint("←/esc", "tabs")}`;
|
|
252
447
|
if (this.focus === "detail")
|
|
253
|
-
return
|
|
254
|
-
? ` ${hint("↑↓", "scroll")} ${hint("→/enter", "readable")} ${hint("←/esc", "back")}`
|
|
255
|
-
: ` ${hint("↑↓", "scroll")} ${hint("←/esc", this.detailView === "transcript" ? "evidence" : "back")}`;
|
|
448
|
+
return ` ${hint("↑↓/pgup/pgdn", "scroll")} ${hint("←/esc", "back")}`;
|
|
256
449
|
if (this.focus === "list")
|
|
257
|
-
return ` ${hint("
|
|
258
|
-
if (this.focus === "runs")
|
|
259
|
-
|
|
450
|
+
return ` ${hint("↑↓/pgup/pgdn", "row")} ${hint("→/enter", "open")} ${hint("←", "tabs")} ${hint("esc", "close")}`;
|
|
451
|
+
if (this.focus === "runs") {
|
|
452
|
+
const run = this.runs().find((item) => item.run === this.selectedRun);
|
|
453
|
+
const killHint = this.killRun && run?.status === "running" && run.runInstanceId
|
|
454
|
+
? ` ${hint("k", "kill")}`
|
|
455
|
+
: "";
|
|
456
|
+
return ` ${hint("←→", "run")} ${hint("↓", "tabs")} ${hint("enter", "list")}${killHint} ${hint("esc", "close")}`;
|
|
457
|
+
}
|
|
260
458
|
return ` ${hint("←→", "navigate")} ${hint("↑↓", "change row")} ${hint("enter", "select")} ${hint("esc", "close")}`;
|
|
261
459
|
}
|
|
262
460
|
renderRunControl() {
|
|
@@ -306,7 +504,7 @@ export class ActorInspectorOverlay {
|
|
|
306
504
|
const subagent = this.subagents()[this.subagentIndex] ?? "all";
|
|
307
505
|
const messagesLabel = `Messages${messageFilters.length > 0 ? ` (${messageFilters.join(", ")})` : ""}`;
|
|
308
506
|
const turnsLabel = `Turns${subagent === "all" ? "" : ` (${subagent})`}`;
|
|
309
|
-
return `${tab("communications", messagesLabel)} ${tab("turns", turnsLabel)}`;
|
|
507
|
+
return `${tab("recipe", "Recipe")} ${tab("communications", messagesLabel)} ${tab("turns", turnsLabel)}`;
|
|
310
508
|
}
|
|
311
509
|
renderRunSelector(width) {
|
|
312
510
|
const runs = this.runs();
|
|
@@ -331,6 +529,8 @@ export class ActorInspectorOverlay {
|
|
|
331
529
|
this.selectedRun = undefined;
|
|
332
530
|
return [this.theme.fg("warning", " Selected run is no longer owned by this session")];
|
|
333
531
|
}
|
|
532
|
+
if (this.tab === "recipe")
|
|
533
|
+
return this.renderRecipe(width);
|
|
334
534
|
const rows = this.tab === "communications"
|
|
335
535
|
? this.communicationRows()
|
|
336
536
|
: this.turnRows();
|
|
@@ -363,6 +563,28 @@ export class ActorInspectorOverlay {
|
|
|
363
563
|
: ` ${row}`;
|
|
364
564
|
});
|
|
365
565
|
}
|
|
566
|
+
renderRecipe(width) {
|
|
567
|
+
if (!this.selectedRun)
|
|
568
|
+
return [];
|
|
569
|
+
const recipe = Inspector.readActorInspectorRecipe(path.join(this.stateRoot, this.selectedRun));
|
|
570
|
+
const logicalLines = [
|
|
571
|
+
...this.detailSection("Identity", this.readableValueLines(recipe.identity, " ")),
|
|
572
|
+
...(recipe.definition
|
|
573
|
+
? this.detailSection("Recipe", this.readableValueLines(recipe.definition, " "))
|
|
574
|
+
: []),
|
|
575
|
+
...this.detailSection("Launch", this.readableValueLines(recipe.launch, " ")),
|
|
576
|
+
...(recipe.composition.length > 0
|
|
577
|
+
? this.detailSection("Composition", this.readableValueLines(recipe.composition, " "))
|
|
578
|
+
: []),
|
|
579
|
+
...this.detailSection("Diagnostics", recipe.diagnostics),
|
|
580
|
+
];
|
|
581
|
+
const wrapped = this.wrapDetailLines(logicalLines.length > 0 ? logicalLines : [" No persisted recipe evidence"], width);
|
|
582
|
+
const viewportRows = this.contentViewportRows();
|
|
583
|
+
const maxStart = Math.max(0, wrapped.lines.length - viewportRows);
|
|
584
|
+
this.recipeScroll = Math.min(this.recipeScroll, maxStart);
|
|
585
|
+
this.contentStripeIndices = wrapped.stripeIndices.slice(this.recipeScroll, this.recipeScroll + viewportRows);
|
|
586
|
+
return wrapped.lines.slice(this.recipeScroll, this.recipeScroll + viewportRows);
|
|
587
|
+
}
|
|
366
588
|
communicationPreviews() {
|
|
367
589
|
if (!this.selectedRun)
|
|
368
590
|
return [];
|
|
@@ -419,16 +641,18 @@ export class ActorInspectorOverlay {
|
|
|
419
641
|
["inbox", preview.inbox_status],
|
|
420
642
|
["timestamp", preview.timestamp],
|
|
421
643
|
];
|
|
422
|
-
|
|
644
|
+
const lines = fields
|
|
423
645
|
.filter(([, value]) => value !== undefined)
|
|
424
646
|
.map(([label, value]) => truncateToWidth(` ${label.padEnd(12, " ")} ${typeof value === "string" ? value : JSON.stringify(value)}`, width, "…"));
|
|
647
|
+
const viewportRows = this.contentViewportRows();
|
|
648
|
+
const maxStart = Math.max(0, lines.length - viewportRows);
|
|
649
|
+
this.detailScroll = Math.min(this.detailScroll, maxStart);
|
|
650
|
+
return lines.slice(this.detailScroll, this.detailScroll + viewportRows);
|
|
425
651
|
}
|
|
426
652
|
const turn = this.detailTurn;
|
|
427
653
|
if (!turn)
|
|
428
654
|
return [this.theme.fg("warning", " Turn row is no longer available")];
|
|
429
|
-
const logicalLines = this.
|
|
430
|
-
? this.turnTranscriptLines(turn)
|
|
431
|
-
: this.turnEvidenceLines(turn);
|
|
655
|
+
const logicalLines = this.turnEvidenceLines(turn);
|
|
432
656
|
const wrapped = this.wrapDetailLines(logicalLines, width);
|
|
433
657
|
const viewportRows = this.contentViewportRows();
|
|
434
658
|
const maxStart = Math.max(0, wrapped.lines.length - viewportRows);
|
|
@@ -452,9 +676,31 @@ export class ActorInspectorOverlay {
|
|
|
452
676
|
const leading = physicalLine.match(/^ */)?.[0] ?? "";
|
|
453
677
|
const content = physicalLine.slice(leading.length);
|
|
454
678
|
const contentWidth = Math.max(1, width - visibleWidth(leading));
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
679
|
+
const labeled = /^(\s*(?:-\s+)?[^:]+:\s+)(\S.*)$/u.exec(physicalLine);
|
|
680
|
+
let wrapped;
|
|
681
|
+
if (visibleWidth(physicalLine) > width &&
|
|
682
|
+
labeled &&
|
|
683
|
+
visibleWidth(labeled[1]) < width) {
|
|
684
|
+
const prefix = labeled[1];
|
|
685
|
+
const value = labeled[2];
|
|
686
|
+
const firstWidth = Math.max(1, width - visibleWidth(prefix));
|
|
687
|
+
const first = this.wrapPreferred(value, firstWidth)[0] ??
|
|
688
|
+
this.takeVisiblePrefix(value, firstWidth);
|
|
689
|
+
const remainder = value.slice(first.length).trimStart();
|
|
690
|
+
const continuation = `${leading} `;
|
|
691
|
+
const continuationWidth = Math.max(1, width - visibleWidth(continuation));
|
|
692
|
+
wrapped = [
|
|
693
|
+
`${prefix}${first}`,
|
|
694
|
+
...(remainder
|
|
695
|
+
? this.wrapPreferred(remainder, continuationWidth).map((visualLine) => `${continuation}${visualLine}`)
|
|
696
|
+
: []),
|
|
697
|
+
];
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
wrapped = visibleWidth(physicalLine) <= width
|
|
701
|
+
? [physicalLine]
|
|
702
|
+
: this.wrapPreferred(content, contentWidth).map((visualLine) => `${leading}${visualLine}`);
|
|
703
|
+
}
|
|
458
704
|
for (const visualLine of wrapped) {
|
|
459
705
|
if (!visualLine.trim())
|
|
460
706
|
continue;
|
|
@@ -465,6 +711,40 @@ export class ActorInspectorOverlay {
|
|
|
465
711
|
}
|
|
466
712
|
return { lines: wrappedLines, stripeIndices };
|
|
467
713
|
}
|
|
714
|
+
wrapPreferred(content, width) {
|
|
715
|
+
const lines = [];
|
|
716
|
+
let remaining = stripVTControlCharacters(content).trimEnd();
|
|
717
|
+
while (remaining && visibleWidth(remaining) > width) {
|
|
718
|
+
const candidate = this.takeVisiblePrefix(remaining, width);
|
|
719
|
+
let splitAt = -1;
|
|
720
|
+
let trimBoundary = false;
|
|
721
|
+
for (let index = 1; index < candidate.length; index += 1) {
|
|
722
|
+
if (/\s/u.test(candidate[index])) {
|
|
723
|
+
splitAt = index + 1;
|
|
724
|
+
trimBoundary = true;
|
|
725
|
+
}
|
|
726
|
+
else if (/[-+=/_,.:]/u.test(candidate[index])) {
|
|
727
|
+
splitAt = index;
|
|
728
|
+
trimBoundary = false;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
if (splitAt <= 0)
|
|
732
|
+
splitAt = candidate.length;
|
|
733
|
+
const head = remaining.slice(0, splitAt).trimEnd();
|
|
734
|
+
if (!head) {
|
|
735
|
+
lines.push(candidate);
|
|
736
|
+
remaining = remaining.slice(candidate.length);
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
lines.push(head);
|
|
740
|
+
remaining = remaining.slice(splitAt);
|
|
741
|
+
if (trimBoundary)
|
|
742
|
+
remaining = remaining.trimStart();
|
|
743
|
+
}
|
|
744
|
+
if (remaining)
|
|
745
|
+
lines.push(remaining);
|
|
746
|
+
return lines;
|
|
747
|
+
}
|
|
468
748
|
detailSection(title, content) {
|
|
469
749
|
if (content.length === 0)
|
|
470
750
|
return [];
|
|
@@ -508,9 +788,10 @@ export class ActorInspectorOverlay {
|
|
|
508
788
|
}
|
|
509
789
|
if (!item || typeof item !== "object")
|
|
510
790
|
return [`${indent}- ${String(item)}`];
|
|
791
|
+
const [first = "", ...rest] = this.readableValueLines(item, `${indent} `, depth + 1);
|
|
511
792
|
return [
|
|
512
|
-
`${indent}
|
|
513
|
-
...
|
|
793
|
+
`${indent}- ${first.trimStart()}`,
|
|
794
|
+
...rest,
|
|
514
795
|
];
|
|
515
796
|
});
|
|
516
797
|
}
|
|
@@ -543,7 +824,7 @@ export class ActorInspectorOverlay {
|
|
|
543
824
|
: "";
|
|
544
825
|
lines.push(` Subagent ${subagent}${stage}`, DETAIL_SECTION_BREAK);
|
|
545
826
|
if (turn.userText)
|
|
546
|
-
lines.push(...this.detailSection("User", [turn.userText]));
|
|
827
|
+
lines.push(...this.detailSection("User", [this.readablePromptText(turn.userText)]));
|
|
547
828
|
if (turn.thinking)
|
|
548
829
|
lines.push(...this.detailSection("Thinking", [turn.thinking]));
|
|
549
830
|
if (turn.assistantText)
|
|
@@ -586,12 +867,6 @@ export class ActorInspectorOverlay {
|
|
|
586
867
|
` ${turn.promptFile}${turn.promptBytes ? ` (${turn.promptBytes} bytes)` : ""}`,
|
|
587
868
|
]
|
|
588
869
|
: []),
|
|
589
|
-
...(turn.recipeContext === undefined
|
|
590
|
-
? []
|
|
591
|
-
: [
|
|
592
|
-
"Recipe Context",
|
|
593
|
-
...this.readableValueLines(turn.recipeContext, " "),
|
|
594
|
-
]),
|
|
595
870
|
];
|
|
596
871
|
lines.push(...this.detailSection("Provenance", provenance));
|
|
597
872
|
return lines.length > 0 ? lines : [" No persisted turn evidence"];
|
|
@@ -600,34 +875,18 @@ export class ActorInspectorOverlay {
|
|
|
600
875
|
const wrapped = /^\s*<file\b[^>]*>\s*([\s\S]*?)\s*<\/file>\s*$/i.exec(text);
|
|
601
876
|
return wrapped?.[1]?.trim() || text;
|
|
602
877
|
}
|
|
603
|
-
|
|
604
|
-
const lines = [];
|
|
605
|
-
if (turn.userText)
|
|
606
|
-
lines.push(...this.detailSection("User", [this.readablePromptText(turn.userText)]));
|
|
607
|
-
if (turn.thinking)
|
|
608
|
-
lines.push(...this.detailSection("Thinking", [turn.thinking]));
|
|
609
|
-
if (turn.assistantText)
|
|
610
|
-
lines.push(...this.detailSection("Assistant", [turn.assistantText]));
|
|
611
|
-
for (const tool of turn.toolCalls) {
|
|
612
|
-
const content = [
|
|
613
|
-
...(tool.arguments === undefined
|
|
614
|
-
? []
|
|
615
|
-
: ["Input", ...this.readableValueLines(tool.arguments, " ")]),
|
|
616
|
-
...(tool.result === undefined
|
|
617
|
-
? []
|
|
618
|
-
: ["Result", ...this.readableValueLines(tool.result, " ")]),
|
|
619
|
-
];
|
|
620
|
-
lines.push(...this.detailSection(`Tool (${tool.name}${tool.resultError ? ", Error" : ""})`, content));
|
|
621
|
-
}
|
|
622
|
-
if (turn.error)
|
|
623
|
-
lines.push(...this.detailSection("Error", [turn.error]));
|
|
624
|
-
return lines.length > 0 ? lines : [" No readable turn content"];
|
|
625
|
-
}
|
|
626
|
-
turnItems() {
|
|
878
|
+
allTurnItems() {
|
|
627
879
|
if (!this.selectedRun)
|
|
628
880
|
return [];
|
|
881
|
+
if (this.turnCache?.run === this.selectedRun)
|
|
882
|
+
return this.turnCache.turns;
|
|
883
|
+
const turns = this.readTurns(path.join(this.stateRoot, this.selectedRun));
|
|
884
|
+
this.turnCache = { run: this.selectedRun, turns };
|
|
885
|
+
return turns;
|
|
886
|
+
}
|
|
887
|
+
turnItems() {
|
|
629
888
|
const selectedSubagent = this.subagents()[this.subagentIndex];
|
|
630
|
-
return
|
|
889
|
+
return this.allTurnItems()
|
|
631
890
|
.filter((turn) => !selectedSubagent ||
|
|
632
891
|
selectedSubagent === "all" ||
|
|
633
892
|
turn.commandId === selectedSubagent)
|
|
@@ -662,7 +921,7 @@ export class ActorInspectorOverlay {
|
|
|
662
921
|
subagents() {
|
|
663
922
|
if (!this.selectedRun || this.tab !== "turns")
|
|
664
923
|
return ["all"];
|
|
665
|
-
const ids =
|
|
924
|
+
const ids = this.allTurnItems().map((turn) => turn.commandId);
|
|
666
925
|
return ["all", ...new Set(ids)];
|
|
667
926
|
}
|
|
668
927
|
valueOptions() {
|
|
@@ -795,17 +1054,11 @@ export class ActorInspectorOverlay {
|
|
|
795
1054
|
else
|
|
796
1055
|
this.detailTurn = this.turnItems()[this.rowIndex];
|
|
797
1056
|
this.detailScroll = 0;
|
|
798
|
-
this.detailView = "evidence";
|
|
799
1057
|
this.detailOpen = Boolean(this.detailCommunication || this.detailTurn);
|
|
800
1058
|
if (this.detailOpen)
|
|
801
1059
|
this.focus = "detail";
|
|
802
1060
|
}
|
|
803
1061
|
backDetail() {
|
|
804
|
-
if (this.detailView === "transcript") {
|
|
805
|
-
this.detailView = "evidence";
|
|
806
|
-
this.detailScroll = 0;
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
1062
|
this.closeDetail();
|
|
810
1063
|
}
|
|
811
1064
|
closeDetail() {
|
|
@@ -813,7 +1066,6 @@ export class ActorInspectorOverlay {
|
|
|
813
1066
|
this.detailCommunication = undefined;
|
|
814
1067
|
this.detailTurn = undefined;
|
|
815
1068
|
this.detailScroll = 0;
|
|
816
|
-
this.detailView = "evidence";
|
|
817
1069
|
this.focus = "list";
|
|
818
1070
|
}
|
|
819
1071
|
border(left, title, right, width) {
|
|
@@ -861,6 +1113,11 @@ export class ActorInspectorOverlay {
|
|
|
861
1113
|
}
|
|
862
1114
|
return plain.slice(index);
|
|
863
1115
|
}
|
|
1116
|
+
center(content, width) {
|
|
1117
|
+
const contentWidth = visibleWidth(content);
|
|
1118
|
+
const leading = Math.max(0, Math.floor((width - contentWidth) / 2));
|
|
1119
|
+
return `${" ".repeat(leading)}${content}`;
|
|
1120
|
+
}
|
|
864
1121
|
fit(content, width) {
|
|
865
1122
|
// A Component render entry must remain exactly one terminal row. Persisted
|
|
866
1123
|
// prompts, messages, and tool results may contain line breaks or tabs;
|
package/dist/lib/inspector.d.ts
CHANGED
|
@@ -55,10 +55,19 @@ export interface ActorInspectorPreviewReadOptions {
|
|
|
55
55
|
}
|
|
56
56
|
export interface ActorInspectorRunItem {
|
|
57
57
|
run: string;
|
|
58
|
+
runInstanceId?: string;
|
|
58
59
|
status: string;
|
|
59
60
|
updatedAt?: string;
|
|
60
61
|
}
|
|
61
62
|
export declare function readActorInspectorRuns(stateRoot: string, ownerId: string): ActorInspectorRunItem[];
|
|
63
|
+
export interface ActorInspectorRecipeView {
|
|
64
|
+
composition: Array<Record<string, unknown>>;
|
|
65
|
+
definition?: Record<string, unknown>;
|
|
66
|
+
diagnostics: string[];
|
|
67
|
+
identity: Record<string, unknown>;
|
|
68
|
+
launch: Record<string, unknown>;
|
|
69
|
+
}
|
|
70
|
+
export declare function readActorInspectorRecipe(stateDir: string): ActorInspectorRecipeView;
|
|
62
71
|
export interface ActorInspectorTurnItem extends SessionEvidence.SessionEvidenceTurn {
|
|
63
72
|
commandId: string;
|
|
64
73
|
diagnostics: string[];
|