@astrosheep/keiyaku 4.6.14 → 4.6.16
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/build/plugins/claude/skills/keiyaku/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-akuma/SKILL.md +13 -8
- package/build/plugins/codex/skills/keiyaku/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +13 -8
- package/build/plugins/opencode/skills/keiyaku/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +13 -8
- package/build/skills/keiyaku/SKILL.md +1 -1
- package/build/skills/keiyaku-akuma/SKILL.md +13 -8
- package/build/src/akuma/archetype.js +2 -2
- package/build/src/cli/commands/akuma-grammar.js +18 -14
- package/build/src/cli/commands/akuma.d.ts +2 -1
- package/build/src/cli/commands/akuma.js +24 -25
- package/build/src/cli/commands/contract-help.d.ts +11 -11
- package/build/src/cli/commands/contract-help.js +16 -16
- package/build/src/cli/commands/contract.d.ts +3 -2
- package/build/src/cli/commands/contract.js +45 -65
- package/build/src/cli/commands/debt-grammar.js +8 -15
- package/build/src/cli/commands/debt.d.ts +2 -1
- package/build/src/cli/commands/debt.js +22 -22
- package/build/src/cli/commands/install.d.ts +2 -1
- package/build/src/cli/commands/install.js +4 -3
- package/build/src/cli/commands/whoami.d.ts +46 -0
- package/build/src/cli/commands/whoami.js +127 -0
- package/build/src/cli/main.js +5 -4
- package/build/src/cli/parse.d.ts +7 -1
- package/build/src/cli/parse.js +23 -3
- package/build/src/cli/render/akuma-activity.d.ts +10 -23
- package/build/src/cli/render/akuma-activity.js +178 -212
- package/build/src/cli/render/akuma.d.ts +7 -6
- package/build/src/cli/render/akuma.js +22 -18
- package/build/src/cli/render/catalog.js +4 -3
- package/build/src/cli/render/contract-history.js +5 -16
- package/build/src/cli/render/debt.d.ts +2 -1
- package/build/src/cli/render/debt.js +6 -6
- package/build/src/cli/render/nuke.d.ts +2 -1
- package/build/src/cli/render/nuke.js +4 -2
- package/build/src/cli/render/receipt.js +8 -3
- package/build/src/cli/render/reconcile.js +8 -7
- package/build/src/cli/render/refusal.js +7 -3
- package/build/src/cli/render/terminal.d.ts +5 -2
- package/build/src/cli/render/terminal.js +74 -12
- package/build/src/cli/render/whoami.d.ts +2 -0
- package/build/src/cli/render/whoami.js +56 -0
- package/build/src/cli/runtime.d.ts +2 -1
- package/build/src/cli/runtime.js +59 -58
- package/build/src/cli/streams.d.ts +11 -1
- package/build/src/cli/streams.js +6 -2
- package/build/src/cli/usage.d.ts +1 -0
- package/build/src/cli/usage.js +7 -6
- package/build/src/contract-worktree.js +1 -1
- package/build/src/library/selection.d.ts +1 -0
- package/build/src/library/selection.js +1 -1
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/package.json +2 -2
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +13 -8
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { defaultWaitComplete } from "../../akuma/akuma-observe.js";
|
|
2
2
|
import { renderDiffstat, toolContent, toolRepr } from "./akuma-tool.js";
|
|
3
|
+
import { dispositionText } from "./debt.js";
|
|
3
4
|
import { debtDispositionMark } from "./marks.js";
|
|
4
5
|
import { DEFAULT_CLI_COLUMNS, displayColumns, padToDisplay, renderBoundedPayload, renderBoundedTextBlock, safeText, takeDisplayColumns, takeDisplayColumnsFromEnd, truncateDisplayText, truncateMiddleDisplayText, } from "./terminal.js";
|
|
5
6
|
export const DEFAULT_CONTEXT = { columns: DEFAULT_CLI_COLUMNS, color: false };
|
|
6
|
-
|
|
7
|
-
const
|
|
7
|
+
/** The action family's fixed 3-cell state margin and minimum verb cell. */
|
|
8
|
+
const ACTION_MARGIN = " ";
|
|
9
|
+
const ACTION_VERB_WIDTH = 6;
|
|
10
|
+
/** Top-level rows: one mark plus its separator, and two spaces beneath it. */
|
|
11
|
+
const TOP_SPEAK = "▎ ";
|
|
12
|
+
const TOP_INPUT = "▸ ";
|
|
13
|
+
const TOP_PENDING = "⧗ ";
|
|
14
|
+
const TOP_ANSWER = "✓ ";
|
|
15
|
+
const TOP_FAILURE = "! ";
|
|
16
|
+
const TOP_CONTINUATION = " ";
|
|
17
|
+
/** The one row-omission glyph, in verb position. */
|
|
18
|
+
const OMISSION = "···";
|
|
8
19
|
/**
|
|
9
20
|
* The one blessed ruler: a run of U+2500 as wide as the frame head's widest line,
|
|
10
21
|
* never wider than the terminal, marking the boundary between an observation
|
|
@@ -56,47 +67,13 @@ export function actionReceipt(input) {
|
|
|
56
67
|
function contractFacts(contract) {
|
|
57
68
|
return contract.kind === "failed" ? [`! contract failed ${safeText(contract.diagnostic)}`] : [];
|
|
58
69
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
: "unknown";
|
|
67
|
-
}
|
|
68
|
-
function label(row, tool) {
|
|
69
|
-
if (row.kind === "said")
|
|
70
|
-
return "";
|
|
71
|
-
if (row.kind === "thought")
|
|
72
|
-
return "think";
|
|
73
|
-
if (row.kind === "note")
|
|
74
|
-
return "note";
|
|
75
|
-
if (row.kind === "call")
|
|
76
|
-
return "call";
|
|
77
|
-
if (row.kind === "tell")
|
|
78
|
-
return row.state === "told" ? "told" : "tell";
|
|
79
|
-
if (row.kind === "outcome")
|
|
80
|
-
return row.outcome.kind === "answered" ? "answer" : "error";
|
|
81
|
-
if (row.kind === "turn")
|
|
82
|
-
return "call";
|
|
83
|
-
if (row.kind !== "tool")
|
|
84
|
-
return row.kind;
|
|
85
|
-
return tool.label;
|
|
86
|
-
}
|
|
87
|
-
function mark(row, live = false) {
|
|
88
|
-
if (row.kind === "outcome")
|
|
89
|
-
return row.outcome.kind === "answered" ? "✓" : "!";
|
|
90
|
-
if (row.kind === "tell" && row.state === "pending")
|
|
91
|
-
return "⧗";
|
|
92
|
-
if (row.kind === "tool") {
|
|
93
|
-
if (row.state === "active")
|
|
94
|
-
return live ? "●" : "?";
|
|
95
|
-
if (row.state === "unsettled")
|
|
96
|
-
return "?";
|
|
97
|
-
return row.state.status === "ok" ? "✓" : "!";
|
|
98
|
-
}
|
|
99
|
-
return "│";
|
|
70
|
+
/** The action family's one mark cell: a settled success stays blank, and live is only a frame mark. */
|
|
71
|
+
function toolMargin(row, live) {
|
|
72
|
+
if (row.state === "active")
|
|
73
|
+
return live ? "● " : "? ";
|
|
74
|
+
if (row.state === "unsettled")
|
|
75
|
+
return "? ";
|
|
76
|
+
return row.state.status === "ok" ? ACTION_MARGIN : "! ";
|
|
100
77
|
}
|
|
101
78
|
function rowText(row, tool) {
|
|
102
79
|
if (row.kind === "said" ||
|
|
@@ -126,48 +103,30 @@ function rowText(row, tool) {
|
|
|
126
103
|
...(repr.suffix === undefined ? {} : { suffix: repr.suffix }),
|
|
127
104
|
};
|
|
128
105
|
}
|
|
129
|
-
function eventPrefix(glyph, verb, time, columns) {
|
|
130
|
-
const gutter = time === undefined ? " ".repeat(TIME_WIDTH) : time.padEnd(TIME_WIDTH);
|
|
131
|
-
return actionCell(`${gutter} ${glyph}`, verb, columns);
|
|
132
|
-
}
|
|
133
|
-
/** The action column one row spends: six cells by default, or the name's own width when longer. */
|
|
134
|
-
function verbColumn(verb) {
|
|
135
|
-
return Math.max(VERB_WIDTH, displayColumns(verb));
|
|
136
|
-
}
|
|
137
106
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* leaves after the separator so an exact-fit name stays whole and args trim first.
|
|
107
|
+
* The action family's one prefix: a state margin, a verb cell at least six cells wide and as wide as a
|
|
108
|
+
* longer name, then one space. Continuation lines align with the actual content start.
|
|
141
109
|
*/
|
|
142
|
-
function
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
function compactLayout() {
|
|
164
|
-
return { ...plainLayout(), compactRun: true };
|
|
165
|
-
}
|
|
166
|
-
function historyLayout() {
|
|
167
|
-
return { ...compactLayout(), history: true };
|
|
168
|
-
}
|
|
169
|
-
function quotedBody(row) {
|
|
170
|
-
return row.kind === "thought" || row.kind === "tell" || (row.kind === "outcome" && row.outcome.kind === "answered");
|
|
110
|
+
function actionPrefix(margin, verb, columns) {
|
|
111
|
+
const available = Math.max(0, columns - displayColumns(margin) - 1);
|
|
112
|
+
const width = Math.min(Math.max(ACTION_VERB_WIDTH, displayColumns(verb)), available);
|
|
113
|
+
const label = truncateDisplayText(verb, width);
|
|
114
|
+
return { first: `${margin}${padToDisplay(label, width)} `, continuation: `${margin}${" ".repeat(width + 1)}` };
|
|
115
|
+
}
|
|
116
|
+
function rowPrefix(row, tool, columns, view) {
|
|
117
|
+
if (row.kind === "tool")
|
|
118
|
+
return actionPrefix(toolMargin(row, view.live === true), tool.label, columns);
|
|
119
|
+
if (row.kind === "thought")
|
|
120
|
+
return actionPrefix(ACTION_MARGIN, "think", columns);
|
|
121
|
+
if (row.kind === "note")
|
|
122
|
+
return actionPrefix(ACTION_MARGIN, "note", columns);
|
|
123
|
+
if (row.kind === "outcome")
|
|
124
|
+
return { first: row.outcome.kind === "answered" ? TOP_ANSWER : TOP_FAILURE, continuation: TOP_CONTINUATION };
|
|
125
|
+
if (row.kind === "said")
|
|
126
|
+
return { first: TOP_SPEAK, continuation: TOP_SPEAK };
|
|
127
|
+
if (row.kind === "tell" && row.state === "pending")
|
|
128
|
+
return { first: TOP_PENDING, continuation: TOP_CONTINUATION };
|
|
129
|
+
return { first: TOP_INPUT, continuation: TOP_CONTINUATION };
|
|
171
130
|
}
|
|
172
131
|
function pathTail(path, maximum) {
|
|
173
132
|
if (displayColumns(path) <= maximum)
|
|
@@ -230,6 +189,9 @@ function renderRunCommand(first, continuation, text, suffix, columns) {
|
|
|
230
189
|
const tail = takeDisplayColumnsFromEnd(command, tailBudget).text;
|
|
231
190
|
return [`${first}$ ${head}…`, `${continuation}…${tail}${keptSuffix}`];
|
|
232
191
|
}
|
|
192
|
+
function omissionMarker(text, columns) {
|
|
193
|
+
return `${actionPrefix(ACTION_MARGIN, OMISSION, columns).first}${text}`;
|
|
194
|
+
}
|
|
233
195
|
function rowBody(row, text, columns) {
|
|
234
196
|
if (row.kind !== "tool" || row.call.kind !== "other")
|
|
235
197
|
return text;
|
|
@@ -237,84 +199,60 @@ function rowBody(row, text, columns) {
|
|
|
237
199
|
}
|
|
238
200
|
function tailAnswerPreview(first, text, columns) {
|
|
239
201
|
const readable = safeText(text).replace(/\s+/gu, " ").trim();
|
|
240
|
-
const budget = Math.max(0, columns - displayColumns(first
|
|
202
|
+
const budget = Math.max(0, columns - displayColumns(first));
|
|
241
203
|
const tail = takeDisplayColumnsFromEnd(readable, budget).text;
|
|
242
204
|
const preview = tail.length === readable.length ? tail : `…${takeDisplayColumnsFromEnd(readable, Math.max(0, budget - 1)).text}`;
|
|
243
|
-
return [`${first}
|
|
205
|
+
return [`${first}${preview}`];
|
|
244
206
|
}
|
|
245
|
-
function
|
|
246
|
-
const { tool, layout, first, continuation } = options;
|
|
247
|
-
if (tool?.overflow !== "command")
|
|
248
|
-
return undefined;
|
|
249
|
-
if (layout.compactRun !== true)
|
|
250
|
-
return renderRunCommand(first, continuation, value.text, value.suffix ?? "", columns);
|
|
251
|
-
const remaining = columns - displayColumns(first);
|
|
207
|
+
function renderCommandOverflow(first, continuation, value, columns, view) {
|
|
252
208
|
const suffix = value.suffix ?? "";
|
|
209
|
+
if (view.compact !== true && view.history !== true)
|
|
210
|
+
return renderRunCommand(first, continuation, value.text, suffix, columns);
|
|
211
|
+
const remaining = columns - displayColumns(first);
|
|
253
212
|
const withSuffix = remaining - displayColumns(suffix);
|
|
254
213
|
const showSuffix = suffix.length > 0 && withSuffix >= 6;
|
|
255
214
|
return [
|
|
256
215
|
`${first}${truncateMiddleDisplayText(value.text, Math.max(0, showSuffix ? withSuffix : remaining))}${showSuffix ? suffix : ""}`,
|
|
257
216
|
];
|
|
258
217
|
}
|
|
259
|
-
|
|
260
|
-
|
|
218
|
+
/** Every selected timeline row renders through here: one prefix family per row class. */
|
|
219
|
+
function renderRow(row, context, view = {}) {
|
|
220
|
+
const tool = row.kind === "tool" ? toolRepr(row) : undefined;
|
|
261
221
|
const value = rowText(row, tool);
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
222
|
+
const { first, continuation } = rowPrefix(row, tool, context.columns, view);
|
|
223
|
+
const compact = view.compact === true;
|
|
224
|
+
if (tool?.overflow === "command")
|
|
225
|
+
return renderCommandOverflow(first, continuation, value, context.columns, view);
|
|
265
226
|
if (tool?.pathPreview !== undefined)
|
|
266
227
|
return [renderPathPreview(first, value.text, tool.pathPreview, context.columns)];
|
|
267
|
-
if (
|
|
228
|
+
if (view.tailAnswer === true && row.kind === "outcome" && row.outcome.kind === "answered")
|
|
268
229
|
return tailAnswerPreview(first, value.text, context.columns);
|
|
269
230
|
const available = context.columns - displayColumns(first) - displayColumns(value.suffix ?? "");
|
|
231
|
+
const singleLine = compact || row.kind === "call" || row.kind === "tell" || row.kind === "turn";
|
|
270
232
|
return renderBoundedPayload({
|
|
271
233
|
text: rowBody(row, value.text, available),
|
|
272
234
|
first,
|
|
273
235
|
continuation,
|
|
274
236
|
columns: context.columns,
|
|
275
|
-
maxLines:
|
|
276
|
-
|
|
277
|
-
: layout.history === true
|
|
278
|
-
? Number.MAX_SAFE_INTEGER
|
|
279
|
-
: value.lines,
|
|
280
|
-
quote: quotedBody(row) ? (layout.singleLine === true ? '"' : "“") : "",
|
|
237
|
+
maxLines: singleLine ? 1 : view.history === true ? Number.MAX_SAFE_INTEGER : value.lines,
|
|
238
|
+
quote: "",
|
|
281
239
|
truncated: "truncated" in row && row.truncated === true,
|
|
240
|
+
...(singleLine || row.kind === "tool" ? {} : { preserveLines: true }),
|
|
282
241
|
});
|
|
283
242
|
}
|
|
284
|
-
function
|
|
285
|
-
const { inFlightSay = false, live = false, unsettled = false } = options;
|
|
286
|
-
const tool = row.kind === "tool" ? toolRepr(row) : undefined;
|
|
287
|
-
const glyph = inFlightSay ? (live ? "●" : "?") : unsettled ? "?" : mark(row, live);
|
|
288
|
-
const verb = label(row, tool);
|
|
289
|
-
return renderRow(row, context, {
|
|
290
|
-
layout,
|
|
291
|
-
first: layout.head(time, glyph, verb, context.columns),
|
|
292
|
-
continuation: layout.continuation(verb),
|
|
293
|
-
tool,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
function groupedEntries(entries, context, layout = plainLayout(), options = {}) {
|
|
243
|
+
function groupedEntries(entries, context, view = {}) {
|
|
297
244
|
const lines = [];
|
|
298
|
-
let previousClock;
|
|
299
245
|
for (const entry of entries) {
|
|
300
246
|
if (entry.kind === "gap") {
|
|
301
|
-
lines.push(
|
|
247
|
+
lines.push(omissionMarker(`${entry.count} omitted`, context.columns));
|
|
302
248
|
continue;
|
|
303
249
|
}
|
|
304
|
-
|
|
305
|
-
const at = clock(row.at);
|
|
306
|
-
const changed = previousClock === undefined || at !== previousClock;
|
|
307
|
-
lines.push(...renderTimelineRow(row, context, layout, changed ? at : undefined, {
|
|
308
|
-
inFlightSay: options.inFlightSay?.(row) ?? false,
|
|
309
|
-
live: options.live === true,
|
|
310
|
-
unsettled: options.unsettled?.(row) ?? false,
|
|
311
|
-
}));
|
|
312
|
-
previousClock = at;
|
|
250
|
+
lines.push(...renderRow(entry.row, context, view));
|
|
313
251
|
}
|
|
314
252
|
return lines;
|
|
315
253
|
}
|
|
316
|
-
function groupedRows(rows, context,
|
|
317
|
-
return groupedEntries(rows.filter((row) => row.kind !== "turn").map((row) => ({ kind: "row", row })), context,
|
|
254
|
+
function groupedRows(rows, context, view = {}) {
|
|
255
|
+
return groupedEntries(rows.filter((row) => row.kind !== "turn").map((row) => ({ kind: "row", row })), context, view);
|
|
318
256
|
}
|
|
319
257
|
/** Ordered entry stream of one retained snapshot; an idle outcome keeps its sequence position. */
|
|
320
258
|
function orderedSnapshotEntries(snapshot) {
|
|
@@ -377,7 +315,7 @@ export function snapshotActivityLines(snapshot, context, selection = {}) {
|
|
|
377
315
|
return latest === undefined
|
|
378
316
|
? []
|
|
379
317
|
: groupedEntries([latest], context, {
|
|
380
|
-
|
|
318
|
+
compact: true,
|
|
381
319
|
...(selection.tailAnswer === true ? { tailAnswer: true } : {}),
|
|
382
320
|
});
|
|
383
321
|
}
|
|
@@ -412,16 +350,6 @@ function rememberPendingTells(state, activity) {
|
|
|
412
350
|
function baselineOmissionCount(activity, after, before) {
|
|
413
351
|
return activity.rows.filter((row) => row.sequence > after && (before === undefined || row.sequence < before) && isSettledStreamRow(row)).length;
|
|
414
352
|
}
|
|
415
|
-
function renderStreamRow(state, row, lines, options) {
|
|
416
|
-
const { context, layout, inFlightSay = false, unsettled = false } = options;
|
|
417
|
-
const at = clock(row.at);
|
|
418
|
-
const changed = state.previousClock === undefined || at !== state.previousClock;
|
|
419
|
-
lines.push(...renderTimelineRow(row, context, layout, changed ? at : undefined, {
|
|
420
|
-
inFlightSay,
|
|
421
|
-
unsettled,
|
|
422
|
-
}));
|
|
423
|
-
state.previousClock = at;
|
|
424
|
-
}
|
|
425
353
|
/**
|
|
426
354
|
* A say is in-flight only while it is the newest row of the open turn: it may still be streaming, so it
|
|
427
355
|
* stays in the redrawable frame. A say with any successor row is settled evidence and renders on the rail.
|
|
@@ -511,37 +439,21 @@ function observeActivitySnapshot(state, activity) {
|
|
|
511
439
|
}
|
|
512
440
|
else if (row.kind === "said" || row.kind === "tell")
|
|
513
441
|
state.checkpointTools = 0;
|
|
514
|
-
emitRow(state, emissions, { kind: "row", row
|
|
442
|
+
emitRow(state, emissions, { kind: "row", row });
|
|
515
443
|
}
|
|
516
444
|
return emissions;
|
|
517
445
|
}
|
|
518
|
-
function renderEmissions(state, emissions, context, layout) {
|
|
519
|
-
const lines = [];
|
|
520
|
-
for (const emission of emissions) {
|
|
521
|
-
if (emission.kind === "gap")
|
|
522
|
-
lines.push(layout.marker(emission.count));
|
|
523
|
-
else
|
|
524
|
-
renderStreamRow(state, emission.row, lines, {
|
|
525
|
-
context,
|
|
526
|
-
layout,
|
|
527
|
-
...(emission.inFlightSay === undefined ? {} : { inFlightSay: emission.inFlightSay }),
|
|
528
|
-
...(emission.unsettled === undefined ? {} : { unsettled: emission.unsettled }),
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
return lines;
|
|
532
|
-
}
|
|
533
446
|
/**
|
|
534
447
|
* Append-only live view over one command's successive settled snapshots.
|
|
535
448
|
* After each say or Tell, the first three tools print as they settle; later
|
|
536
449
|
* tools until the next checkpoint fold into one omission marker. Failed tools
|
|
537
450
|
* always print.
|
|
538
451
|
*/
|
|
539
|
-
export function activityStream(context
|
|
452
|
+
export function activityStream(context) {
|
|
540
453
|
const state = {
|
|
541
454
|
newestSettledSequence: undefined,
|
|
542
455
|
admissionSequence: undefined,
|
|
543
456
|
pendingTellSequences: new Set(),
|
|
544
|
-
previousClock: undefined,
|
|
545
457
|
renderedBoundaries: new Set(),
|
|
546
458
|
admittedTellSequences: new Set(),
|
|
547
459
|
checkpointTools: 0,
|
|
@@ -587,15 +499,15 @@ export function activityStream(context, layout = plainLayout()) {
|
|
|
587
499
|
state.omitted = 0;
|
|
588
500
|
for (const row of [...state.liveRows.values()].sort((left, right) => left.sequence - right.sequence)) {
|
|
589
501
|
const unresolved = row.kind === "tool" && row.state === "active" ? { ...row, state: "unsettled" } : row;
|
|
590
|
-
emissions.push({ kind: "row", row: unresolved
|
|
502
|
+
emissions.push({ kind: "row", row: unresolved });
|
|
591
503
|
}
|
|
592
504
|
state.liveRows.clear();
|
|
593
505
|
return emissions;
|
|
594
506
|
};
|
|
595
|
-
const render = (emissions) =>
|
|
507
|
+
const render = (emissions) => groupedEntries(emissions, context);
|
|
596
508
|
const frame = () => groupedEntries([...state.liveRows.values()]
|
|
597
509
|
.sort((left, right) => left.sequence - right.sequence)
|
|
598
|
-
.map((row) => ({ kind: "row", row })), context,
|
|
510
|
+
.map((row) => ({ kind: "row", row })), context, { live: true });
|
|
599
511
|
const observe = (activity) => render(observeActivitySnapshot(state, activity));
|
|
600
512
|
return Object.assign(observe, {
|
|
601
513
|
seed: (activity, alreadyRenderedSequence) => render(seed(activity, alreadyRenderedSequence)),
|
|
@@ -627,9 +539,6 @@ function conclusionMarkVerb(status, outcome) {
|
|
|
627
539
|
return { mark: "!", verb: "untidy" };
|
|
628
540
|
return { mark: "!", verb: "stranded" };
|
|
629
541
|
}
|
|
630
|
-
function clockFromMs(at) {
|
|
631
|
-
return clock(new Date(at).toISOString());
|
|
632
|
-
}
|
|
633
542
|
function durationText(durationMs) {
|
|
634
543
|
const seconds = Math.max(0, Math.round(durationMs / 1000));
|
|
635
544
|
if (seconds < 60)
|
|
@@ -637,20 +546,17 @@ function durationText(durationMs) {
|
|
|
637
546
|
return `${Math.floor(seconds / 60)}m${String(seconds % 60)}s`;
|
|
638
547
|
}
|
|
639
548
|
/**
|
|
640
|
-
*
|
|
641
|
-
* this wait began keeps its duration, a target already
|
|
642
|
-
* duration, and an unfinished target carries the elapsed wait.
|
|
549
|
+
* One wait-style conclusion for every observer of an input-bound Tell. A target
|
|
550
|
+
* that settled at or after this wait began keeps its duration, a target already
|
|
551
|
+
* settled names no duration, and an unfinished target carries the elapsed wait.
|
|
643
552
|
*/
|
|
644
|
-
function conclusionClause(at, startedAt, complete, end) {
|
|
645
|
-
if (!complete)
|
|
646
|
-
return ` — waited ${durationText(Math.max(0, end - startedAt))}`;
|
|
647
|
-
return at >= startedAt ? ` — ${durationText(Math.max(0, at - startedAt))}` : "";
|
|
648
|
-
}
|
|
649
|
-
/** One wait-style conclusion for every observer of an input-bound Tell. */
|
|
650
553
|
function waitConclusionRow(input) {
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
554
|
+
const duration = input.complete
|
|
555
|
+
? input.at !== undefined && input.at >= input.startedAt
|
|
556
|
+
? ` — ${durationText(Math.max(0, input.at - input.startedAt))}`
|
|
557
|
+
: ""
|
|
558
|
+
: ` — waited ${durationText(Math.max(0, input.end - input.startedAt))}`;
|
|
559
|
+
return `${input.mark} ${input.verb}${duration}`;
|
|
654
560
|
}
|
|
655
561
|
export function inputWaitConclusion(observation, input) {
|
|
656
562
|
const end = input.now ?? Date.now();
|
|
@@ -673,7 +579,7 @@ export function inputWaitConclusion(observation, input) {
|
|
|
673
579
|
...conclusion,
|
|
674
580
|
}),
|
|
675
581
|
...(observation.reason === "failed" || observation.reason === "invalid-output"
|
|
676
|
-
? [`!
|
|
582
|
+
? [`! ${safeText(observation.diagnostic)}`]
|
|
677
583
|
: []),
|
|
678
584
|
];
|
|
679
585
|
}
|
|
@@ -741,7 +647,7 @@ export function inputWaitStream(context, head, options) {
|
|
|
741
647
|
lines.push(...result.evidence);
|
|
742
648
|
lines.push(...activity.flush());
|
|
743
649
|
if (result.kind === "failed")
|
|
744
|
-
lines.push(`!
|
|
650
|
+
lines.push(`! ${safeText(result.diagnostic)}`);
|
|
745
651
|
else
|
|
746
652
|
lines.push(...inputWaitConclusion(result.observation, {
|
|
747
653
|
startedAt,
|
|
@@ -798,12 +704,12 @@ function renderReportedChangeLines(snapshot) {
|
|
|
798
704
|
return [
|
|
799
705
|
`changes ${snapshot.reportedChanges.length + snapshot.reportedChangesOmitted}`,
|
|
800
706
|
...snapshot.reportedChanges.map((change) => ` ${renderDiffstat(change.diffstat).padEnd(width)} ${safeText(change.path)}`),
|
|
801
|
-
...(snapshot.reportedChangesOmitted > 0 ? [`
|
|
707
|
+
...(snapshot.reportedChangesOmitted > 0 ? [` ${OMISSION} ${snapshot.reportedChangesOmitted} more files`] : []),
|
|
802
708
|
];
|
|
803
709
|
}
|
|
804
710
|
function renderDebtRow(row, columns) {
|
|
805
711
|
const prefix = ` ${debtDispositionMark(row.disposition)} ${row.id} · `;
|
|
806
|
-
const body = `${safeText(row.title)} · ${row.disposition} · P${row.priority}`;
|
|
712
|
+
const body = `${safeText(row.title)} · ${dispositionText(row.disposition)} · P${row.priority}`;
|
|
807
713
|
const inline = `${prefix}${body}`;
|
|
808
714
|
if (displayColumns(inline) <= columns)
|
|
809
715
|
return [inline];
|
|
@@ -839,13 +745,12 @@ function snapshotCore(view, context, options) {
|
|
|
839
745
|
}
|
|
840
746
|
function snapshotConclusion(status) {
|
|
841
747
|
const timeline = status.timeline;
|
|
842
|
-
// The outcome row (
|
|
843
|
-
//
|
|
748
|
+
// The outcome row (`✓` / `!`) is already the ending; a closer would be a second mark carrying no
|
|
749
|
+
// new information, so it is absent exactly then.
|
|
844
750
|
if (timeline.kind === "idle" && timeline.outcome !== undefined)
|
|
845
751
|
return "";
|
|
846
|
-
const last = [...timeline.entries].reverse().find((entry) => entry.kind === "row")?.row;
|
|
847
752
|
const { mark, verb } = conclusionMarkVerb(status, "life");
|
|
848
|
-
return `${
|
|
753
|
+
return `${mark} ${verb}`;
|
|
849
754
|
}
|
|
850
755
|
export function snapshotText(view, context, options = {}) {
|
|
851
756
|
const core = snapshotCore(view, context, options);
|
|
@@ -900,17 +805,69 @@ export function historyRawAnswer(result, historyId) {
|
|
|
900
805
|
const outcome = result.outcome.outcome;
|
|
901
806
|
return outcome.kind === "answered" ? outcome.answer : outcome.diagnostic;
|
|
902
807
|
}
|
|
808
|
+
/** One compact wait result line: an observed life mark, the complete identity, a bounded summary. */
|
|
809
|
+
const WAIT_SUMMARY_SEPARATOR = " — ";
|
|
810
|
+
const WAIT_LIFE = {
|
|
811
|
+
running: { mark: "●", state: "running" },
|
|
812
|
+
killed: { mark: "×", state: "killed" },
|
|
813
|
+
hung: { mark: "?", state: "hung" },
|
|
814
|
+
untidy: { mark: "!", state: "untidy" },
|
|
815
|
+
stranded: { mark: "!", state: "stranded" },
|
|
816
|
+
};
|
|
817
|
+
function foldedSummary(value) {
|
|
818
|
+
return safeText(value).replace(/\s+/gu, " ").trim();
|
|
819
|
+
}
|
|
820
|
+
function preview(value, fallback) {
|
|
821
|
+
return foldedSummary(value) || fallback;
|
|
822
|
+
}
|
|
823
|
+
function waitLine(mark, subject, summary, columns) {
|
|
824
|
+
const head = `${mark} ${subject}`;
|
|
825
|
+
const room = columns - displayColumns(head) - displayColumns(WAIT_SUMMARY_SEPARATOR);
|
|
826
|
+
const folded = foldedSummary(summary);
|
|
827
|
+
return room < 1 || folded.length === 0
|
|
828
|
+
? head
|
|
829
|
+
: `${head}${WAIT_SUMMARY_SEPARATOR}${truncateDisplayText(folded, room)}`;
|
|
830
|
+
}
|
|
903
831
|
/**
|
|
904
|
-
*
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
832
|
+
* The final public snapshot as one wait summary. A stopped life stays explicit over any older
|
|
833
|
+
* outcome; pending input stays visible beside the life it belongs to; a sleeping member without
|
|
834
|
+
* pending input shows its current answered preview or failed diagnostic, else completion. The
|
|
835
|
+
* mark reports the observed life, never continuing liveness.
|
|
836
|
+
*/
|
|
837
|
+
function waitSummary(status) {
|
|
838
|
+
const pending = status.timeline.entries.some((entry) => entry.kind === "row" && entry.row.kind === "tell" && entry.row.state === "pending");
|
|
839
|
+
const outcome = status.timeline.kind === "idle" ? status.timeline.outcome?.outcome : undefined;
|
|
840
|
+
const observed = WAIT_LIFE[status.life] ??
|
|
841
|
+
(pending
|
|
842
|
+
? { mark: "⧗", state: "pending tell" }
|
|
843
|
+
: outcome === undefined
|
|
844
|
+
? { mark: "✓", state: "completed" }
|
|
845
|
+
: outcome.kind === "answered"
|
|
846
|
+
? { mark: "✓", state: preview(outcome.answer, "answered") }
|
|
847
|
+
: { mark: "!", state: preview(outcome.diagnostic, "failed") });
|
|
848
|
+
return {
|
|
849
|
+
...observed,
|
|
850
|
+
summary: [
|
|
851
|
+
observed.state,
|
|
852
|
+
...(pending && status.life !== "asleep" ? ["pending tell"] : []),
|
|
853
|
+
...(status.strandedReason === undefined ? [] : [status.strandedReason]),
|
|
854
|
+
].join(FACT_SEPARATOR),
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* One wait's final text: one compact line per observed member, then one failure line per member
|
|
859
|
+
* the wait could not read. A wait opens no frame and extracts no separate answer, so an answer is
|
|
860
|
+
* visible only as the snapshot's own bounded summary.
|
|
908
861
|
*/
|
|
909
862
|
export function waitText(result, presentation, context) {
|
|
910
863
|
const alias = result.observations.length === 1 && result.unobserved.length === 0 ? presentation.alias : undefined;
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
864
|
+
return [
|
|
865
|
+
...result.observations.map((observation) => {
|
|
866
|
+
const { mark, summary } = waitSummary(observation.status);
|
|
867
|
+
return waitLine(mark, identity(observation.status.id, alias), summary, context.columns);
|
|
868
|
+
}),
|
|
869
|
+
...result.unobserved.map((member) => waitLine("!", safeText(member.id), `observation failed${FACT_SEPARATOR}${member.diagnostic}`, context.columns)),
|
|
870
|
+
].join("\n");
|
|
914
871
|
}
|
|
915
872
|
export function historyText(result, presentation, context) {
|
|
916
873
|
if (presentation.id !== undefined) {
|
|
@@ -924,12 +881,12 @@ export function historyText(result, presentation, context) {
|
|
|
924
881
|
return result.kind === "last" ? result.answer : "no answer retained";
|
|
925
882
|
if (result.kind !== "history")
|
|
926
883
|
throw new Error("history result lacks page");
|
|
927
|
-
const rows = groupedRows(result.history.rows, context,
|
|
884
|
+
const rows = groupedRows(result.history.rows, context, { history: true });
|
|
928
885
|
const paging = result.history.omitted > 0
|
|
929
886
|
? [
|
|
930
|
-
|
|
887
|
+
omissionMarker(result.history.hasLater
|
|
931
888
|
? `${result.history.omitted} later events · showing first ${result.history.rows.length}`
|
|
932
|
-
: `${result.history.omitted} earlier events · showing last ${result.history.rows.length}
|
|
889
|
+
: `${result.history.omitted} earlier events · showing last ${result.history.rows.length}`, context.columns),
|
|
933
890
|
]
|
|
934
891
|
: [];
|
|
935
892
|
// History is an immutable timeline, so it takes the shared heading and content boundary and
|
|
@@ -938,7 +895,7 @@ export function historyText(result, presentation, context) {
|
|
|
938
895
|
const head = panelHead(result.id, presentation.alias, result.contract);
|
|
939
896
|
return [...head, ...(content.length === 0 ? [] : [frameRule(head, context.columns), ...content])].join("\n");
|
|
940
897
|
}
|
|
941
|
-
/** One bounded preview of a
|
|
898
|
+
/** One bounded, quoted preview of a Tell an outer receipt already admitted, indented beneath it. */
|
|
942
899
|
export function tellPayloadLines(text, context) {
|
|
943
900
|
return renderBoundedPayload({
|
|
944
901
|
text,
|
|
@@ -950,38 +907,47 @@ export function tellPayloadLines(text, context) {
|
|
|
950
907
|
truncated: false,
|
|
951
908
|
});
|
|
952
909
|
}
|
|
953
|
-
/** One admitted Tell as a timeline row inside a shared
|
|
910
|
+
/** One admitted Tell as a timeline input row inside a shared panel; the panel owns the identity. */
|
|
954
911
|
export function tellAdmissionRow(tell, context) {
|
|
955
|
-
const
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
912
|
+
const lead = tell.wake.kind === "failed" ? TOP_FAILURE : tell.wake.kind === "held" ? TOP_PENDING : TOP_INPUT;
|
|
913
|
+
return renderBoundedPayload({
|
|
914
|
+
text: tell.row.text,
|
|
915
|
+
first: lead,
|
|
916
|
+
continuation: TOP_CONTINUATION,
|
|
917
|
+
columns: context.columns,
|
|
918
|
+
maxLines: 1,
|
|
919
|
+
quote: "",
|
|
920
|
+
truncated: false,
|
|
921
|
+
})[0];
|
|
963
922
|
}
|
|
964
923
|
/**
|
|
965
|
-
* One Tell action receipt: the delivery verdict and complete subject
|
|
966
|
-
*
|
|
924
|
+
* One Tell action receipt: the delivery verdict and complete subject stand whole on the first line
|
|
925
|
+
* with the submitted payload folded onto that same line, bounded so only its preview truncates. A
|
|
926
|
+
* held Tell keeps neutral vocabulary; a failed delivery keeps its concrete diagnosis and native log
|
|
927
|
+
* coordinates as separate supporting facts.
|
|
967
928
|
*/
|
|
968
929
|
export function tellText(result, alias, context) {
|
|
969
930
|
const wake = result.tell.wake;
|
|
970
931
|
const mark = wake.kind === "failed" ? "!" : wake.kind === "held" ? "⧗" : "✓";
|
|
971
932
|
const verb = wake.kind === "failed" || wake.kind === "held" ? "tell" : "told";
|
|
972
|
-
const
|
|
933
|
+
const head = actionReceipt({
|
|
973
934
|
mark,
|
|
974
935
|
verb,
|
|
975
936
|
id: result.akuma,
|
|
976
937
|
...(alias === undefined ? {} : { alias }),
|
|
977
|
-
});
|
|
938
|
+
})[0];
|
|
939
|
+
const preview = safeText(result.tell.row.text).replace(/\s+/gu, " ").trim();
|
|
940
|
+
const prefix = `${head} — `;
|
|
941
|
+
// The verdict and identity never truncate, so an over-wide identity still keeps one visible
|
|
942
|
+
// ellipsis for the input it could not show.
|
|
943
|
+
const room = Math.max(1, context.columns - displayColumns(prefix));
|
|
944
|
+
const verdict = preview.length === 0 ? head : `${prefix}${truncateDisplayText(preview, room)}`;
|
|
978
945
|
if (wake.kind !== "failed")
|
|
979
|
-
return
|
|
946
|
+
return verdict;
|
|
980
947
|
const child = "child" in wake ? wake.child : undefined;
|
|
981
948
|
const failure = `! tell delivery failed · ${safeText(wake.diagnostic)}${child === undefined ? "" : ` · log ${child.log.path} ${child.log.from}..${child.log.to}`}`;
|
|
982
949
|
return [
|
|
983
|
-
|
|
984
|
-
...tellPayloadLines(result.tell.row.text, context),
|
|
950
|
+
verdict,
|
|
985
951
|
...subordinateLines(renderBoundedTextBlock(failure, {
|
|
986
952
|
first: "",
|
|
987
953
|
continuation: "",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CliOutcome } from "../streams.js";
|
|
1
2
|
import type { LiveStatusObservation } from "../../akuma/akuma-observe.js";
|
|
2
3
|
import type { TellResult } from "../../akuma/body.js";
|
|
3
4
|
import type { AkuId } from "../../akuma/identity.js";
|
|
@@ -29,10 +30,10 @@ export declare function renderCallText(result: CallResult, streamed: boolean, co
|
|
|
29
30
|
export declare function renderFailedCallObservation(result: CallResult, context: TextRenderContext): string;
|
|
30
31
|
export declare function renderForkText(receipt: ForkResult): string;
|
|
31
32
|
export declare function renderKillText(result: AkumaKillResult, alias: string | undefined, context: TextRenderContext): string;
|
|
32
|
-
export declare function
|
|
33
|
-
export declare function
|
|
34
|
-
export declare function
|
|
35
|
-
export declare function
|
|
36
|
-
export declare function
|
|
37
|
-
export declare function
|
|
33
|
+
export declare function callOutcome(result: CallResult): CliOutcome;
|
|
34
|
+
export declare function killOutcome(result: AkumaKillResult): CliOutcome;
|
|
35
|
+
export declare function tellOutcome(result: AkumaTellResult): CliOutcome;
|
|
36
|
+
export declare function askOutcome(result: AkumaAskResult): CliOutcome;
|
|
37
|
+
export declare function forkOutcome(receipt: ForkResult): CliOutcome;
|
|
38
|
+
export declare function historyOutcome(result: AkumaHistoryResult, id: string | undefined): CliOutcome;
|
|
38
39
|
export {};
|