@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
|
@@ -102,7 +102,7 @@ export function renderCallText(result, streamed, context) {
|
|
|
102
102
|
evidence: callEvidence(result, head),
|
|
103
103
|
}),
|
|
104
104
|
...(admittedTell === undefined ? [] : tellPayloadLines(admittedTell.row.text, context)),
|
|
105
|
-
...subordinateLines([`!
|
|
105
|
+
...subordinateLines([`! ${safeText(result.observation.failure.diagnostic)}`]),
|
|
106
106
|
].join("\n");
|
|
107
107
|
}
|
|
108
108
|
const inputObservation = result.observation;
|
|
@@ -152,32 +152,36 @@ export function renderKillText(result, alias, context) {
|
|
|
152
152
|
void context;
|
|
153
153
|
return result.results.map((member) => killResultText(member.id, member.evidence, alias)).join("\n");
|
|
154
154
|
}
|
|
155
|
-
export function
|
|
155
|
+
export function callOutcome(result) {
|
|
156
156
|
if (result.dispatch.kind === "failed" || result.alias.kind === "failed" || result.observation.kind === "failed")
|
|
157
|
-
return
|
|
157
|
+
return "failed";
|
|
158
158
|
if (result.observation.kind !== "observed")
|
|
159
|
-
return
|
|
159
|
+
return "accepted";
|
|
160
160
|
return result.observation.observation.reason === "failed" ||
|
|
161
161
|
result.observation.observation.reason === "invalid-output"
|
|
162
|
-
?
|
|
163
|
-
:
|
|
162
|
+
? "failed"
|
|
163
|
+
: "accepted";
|
|
164
164
|
}
|
|
165
|
-
export function
|
|
165
|
+
export function killOutcome(result) {
|
|
166
166
|
return result.results.some((member) => member.evidence === "unavailable" || member.evidence === "hung" || member.evidence === "untidy")
|
|
167
|
-
?
|
|
168
|
-
:
|
|
167
|
+
? "failed"
|
|
168
|
+
: "accepted";
|
|
169
169
|
}
|
|
170
|
-
export function
|
|
171
|
-
return result.tell.wake.kind === "failed" ?
|
|
170
|
+
export function tellOutcome(result) {
|
|
171
|
+
return result.tell.wake.kind === "failed" ? "failed" : "accepted";
|
|
172
172
|
}
|
|
173
|
-
export function
|
|
174
|
-
return result.observation.reason === "failed" || result.observation.reason === "invalid-output"
|
|
173
|
+
export function askOutcome(result) {
|
|
174
|
+
return result.observation.reason === "failed" || result.observation.reason === "invalid-output"
|
|
175
|
+
? "failed"
|
|
176
|
+
: "accepted";
|
|
175
177
|
}
|
|
176
|
-
export function
|
|
177
|
-
|
|
178
|
+
export function forkOutcome(receipt) {
|
|
179
|
+
if (receipt.kind === "forked")
|
|
180
|
+
return receipt.dispatch.kind === "failed" ? "failed" : "accepted";
|
|
181
|
+
return receipt.kind === "upstream-forked" || receipt.kind === "fork-failed" ? "failed" : "refused";
|
|
178
182
|
}
|
|
179
|
-
export function
|
|
183
|
+
export function historyOutcome(result, id) {
|
|
180
184
|
if (id === undefined)
|
|
181
|
-
return
|
|
182
|
-
return result.kind === "exact" ?
|
|
185
|
+
return "accepted";
|
|
186
|
+
return result.kind === "exact" ? "accepted" : "refused";
|
|
183
187
|
}
|
|
@@ -58,6 +58,7 @@ export function renderContractCatalogue(list) {
|
|
|
58
58
|
: row.phase === "abandoned"
|
|
59
59
|
? row.abandonNote
|
|
60
60
|
: undefined;
|
|
61
|
+
const testimonyLead = ` ${row.phase === "claimed" ? "review" : "note"} `;
|
|
61
62
|
const lines = [
|
|
62
63
|
`${contractMark(row)} ${safeText(row.id)} · ${formatAge(row.phaseAt, list.observedAt)} · ${safeText(row.title ?? "title unavailable")}`,
|
|
63
64
|
` ${terminal ? outcome : progressStrip(row)}`,
|
|
@@ -65,11 +66,11 @@ export function renderContractCatalogue(list) {
|
|
|
65
66
|
? []
|
|
66
67
|
: renderBoundedPayload({
|
|
67
68
|
text: testimony,
|
|
68
|
-
first:
|
|
69
|
-
continuation: "
|
|
69
|
+
first: testimonyLead,
|
|
70
|
+
continuation: " ".repeat(testimonyLead.length),
|
|
70
71
|
columns: 100,
|
|
71
72
|
maxLines: 3,
|
|
72
|
-
quote: "
|
|
73
|
+
quote: "",
|
|
73
74
|
truncated: false,
|
|
74
75
|
})),
|
|
75
76
|
];
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { parseAkuId } from "../../akuma/identity.js";
|
|
2
1
|
import { gateDisplayName, lifecycleWord, shortGitId } from "./contract-observation.js";
|
|
3
2
|
import { receiptPayload } from "./receipt.js";
|
|
4
3
|
import { renderOpaqueBlock, DEFAULT_CLI_COLUMNS } from "./terminal.js";
|
|
@@ -68,9 +67,7 @@ function journalBody(fact, workspace) {
|
|
|
68
67
|
const lines = [
|
|
69
68
|
` gate ${fact.data.gate}`,
|
|
70
69
|
` verdict ${fact.data.verdict}`,
|
|
71
|
-
snapshot === undefined
|
|
72
|
-
? " subject verification"
|
|
73
|
-
: ` subject verification · snapshot ${shortGitId(snapshot)}`,
|
|
70
|
+
...(snapshot === undefined ? [] : [` snapshot ${shortGitId(snapshot)}`]),
|
|
74
71
|
];
|
|
75
72
|
if (fact.data.summary !== undefined) {
|
|
76
73
|
const clipped = fact.data.summary.length > 4096 ? `${fact.data.summary.slice(0, 4096)}\n[truncated]` : fact.data.summary;
|
|
@@ -84,7 +81,7 @@ function journalBody(fact, workspace) {
|
|
|
84
81
|
const lines = [` sequence ${String(fact.data.seq)}`, ` title ${fact.data.title}`];
|
|
85
82
|
const body = fact.data.body.replace(/^(?:\r?\n)+/u, "").trimEnd();
|
|
86
83
|
if (body.length > 0)
|
|
87
|
-
lines.push(" body", ...renderOpaqueBlock(body, "
|
|
84
|
+
lines.push(" body", ...renderOpaqueBlock(body, " ", DEFAULT_CLI_COLUMNS));
|
|
88
85
|
return lines;
|
|
89
86
|
}
|
|
90
87
|
case "abandoned": {
|
|
@@ -127,16 +124,8 @@ function bindLine(bind, dispatch) {
|
|
|
127
124
|
const target = bind.data.coordinates.target?.replace(/^refs\/heads\//u, "") ?? "targetless";
|
|
128
125
|
const gates = bind.data.terms.gates.map(gateDisplayName);
|
|
129
126
|
const gateFact = gates.length === 0 ? "" : ` · ${gates.length === 1 ? "gate" : "gates"} ${gates.join(" · ")}`;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
alias = ` · @${parseAkuId(dispatch.dispatch.akuId).archetype}`;
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
alias = "";
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return `bound to ${target} @ ${shortGitId(bind.data.coordinates.start)}${gateFact}${alias}`;
|
|
127
|
+
const caller = dispatch?.source === "dispatch" ? ` · ${dispatch.dispatch.akuId}` : "";
|
|
128
|
+
return `bound to ${target} @ ${shortGitId(bind.data.coordinates.start)}${gateFact}${caller}`;
|
|
140
129
|
}
|
|
141
130
|
/**
|
|
142
131
|
* The skeleton row is itself the first line of the beat's full form; the fold names the rest.
|
|
@@ -196,7 +185,7 @@ function skeletonBeatLines(beat, history) {
|
|
|
196
185
|
}
|
|
197
186
|
case "arc": {
|
|
198
187
|
const body = fact.data.body.replace(/^(?:\r?\n)+/u, "").trimEnd();
|
|
199
|
-
const folded = body.length === 0 ? [] : renderOpaqueBlock(body, "
|
|
188
|
+
const folded = body.length === 0 ? [] : renderOpaqueBlock(body, " ", DEFAULT_CLI_COLUMNS);
|
|
200
189
|
return [`${clock(first)} arc ${fact.data.title}${payloadSuffix(folded)}`];
|
|
201
190
|
}
|
|
202
191
|
case "claimed":
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CliOutcome } from "../streams.js";
|
|
1
2
|
import type { BlockedDebtList, DebtBatchResult, DebtContextResult, DebtDecompositionTree, DebtDetail, DebtDoctorReport, DebtList, DebtMutationResult, DebtQueryResult, DebtUpdateResult } from "../../debt/index.js";
|
|
2
3
|
import { type TextRenderContext } from "./terminal.js";
|
|
3
4
|
export { debtMark } from "./marks.js";
|
|
@@ -25,4 +26,4 @@ export declare function renderDebtContext(result: DebtContextResult, context?: T
|
|
|
25
26
|
export declare function renderDebtMutation(verb: string, result: DebtMutationResult, context?: TextRenderContext): string;
|
|
26
27
|
/** One lifecycle answer: a single mutation or a plural batch, both native shapes. */
|
|
27
28
|
export declare function renderDebtLifecycle(verb: string, result: DebtMutationResult | DebtBatchResult, context?: TextRenderContext): string;
|
|
28
|
-
export declare function
|
|
29
|
+
export declare function debtOutcome(result: DebtNativeResult): CliOutcome;
|
|
@@ -240,18 +240,18 @@ export function renderDebtMutation(verb, result, context = DEFAULT_CONTEXT) {
|
|
|
240
240
|
export function renderDebtLifecycle(verb, result, context = DEFAULT_CONTEXT) {
|
|
241
241
|
return "items" in result ? renderBatch(verb, result, context.columns) : renderMutation(verb, result, context.columns);
|
|
242
242
|
}
|
|
243
|
-
export function
|
|
243
|
+
export function debtOutcome(result) {
|
|
244
244
|
if ("issues" in result)
|
|
245
|
-
return result.issues.length === 0 ?
|
|
245
|
+
return result.issues.length === 0 ? "accepted" : "failed";
|
|
246
246
|
if ("items" in result) {
|
|
247
247
|
const kinds = result.items.map((item) => item.outcome.kind);
|
|
248
|
-
return kinds.includes("retry") ?
|
|
248
|
+
return kinds.includes("retry") ? "retryable" : kinds.includes("refused") ? "refused" : "accepted";
|
|
249
249
|
}
|
|
250
250
|
if ("kind" in result) {
|
|
251
251
|
if (result.kind === "retry")
|
|
252
|
-
return
|
|
252
|
+
return "retryable";
|
|
253
253
|
if (result.kind === "refused")
|
|
254
|
-
return
|
|
254
|
+
return "refused";
|
|
255
255
|
}
|
|
256
|
-
return
|
|
256
|
+
return "accepted";
|
|
257
257
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CliOutcome } from "../streams.js";
|
|
1
2
|
import type { NukeResult } from "../../index.js";
|
|
2
3
|
export declare function renderNukeText(result: NukeResult): string;
|
|
3
|
-
export declare function
|
|
4
|
+
export declare function nukeOutcome(result: NukeResult): CliOutcome;
|
|
@@ -18,6 +18,8 @@ export function renderNukeText(result) {
|
|
|
18
18
|
}
|
|
19
19
|
return "";
|
|
20
20
|
}
|
|
21
|
-
export function
|
|
22
|
-
|
|
21
|
+
export function nukeOutcome(result) {
|
|
22
|
+
if (result.kind === "refused")
|
|
23
|
+
return "refused";
|
|
24
|
+
return result.pending.some((surface) => surface.required) ? "retryable" : "accepted";
|
|
23
25
|
}
|
|
@@ -102,7 +102,7 @@ export function gatesAwaitLines(placement) {
|
|
|
102
102
|
.map((report) => gateDisplayName(report.gate));
|
|
103
103
|
if (events.length === 0)
|
|
104
104
|
return [];
|
|
105
|
-
return [`⧗ awaiting ${events.
|
|
105
|
+
return [`⧗ awaiting ${events.join(", ")}`];
|
|
106
106
|
}
|
|
107
107
|
function targetMovedDetail(stop) {
|
|
108
108
|
if ("integratedAt" in stop) {
|
|
@@ -192,8 +192,13 @@ function gatesUnsatisfiedStopLines(stop, columns, dependent) {
|
|
|
192
192
|
// carry the story, and the caller closes the receipt with the awaiting margin line.
|
|
193
193
|
const lines = [];
|
|
194
194
|
const target = stop.refusal.target;
|
|
195
|
-
if (dependent !== undefined)
|
|
196
|
-
|
|
195
|
+
if (dependent !== undefined) {
|
|
196
|
+
const awaiting = gatesAwaitLines(stop);
|
|
197
|
+
if (awaiting.length === 0)
|
|
198
|
+
receiptRow(lines, " ", "dependent", [{ text: dependent, opaque: true }], columns);
|
|
199
|
+
for (const line of awaiting)
|
|
200
|
+
receiptRow(lines, "⧗", dependent, [{ text: "·" }, { text: line.slice(2) }], columns);
|
|
201
|
+
}
|
|
197
202
|
else if (target !== undefined)
|
|
198
203
|
receiptRow(lines, " ", "target", [{ text: target, opaque: true }, { text: "· unchanged" }], columns);
|
|
199
204
|
lines.push(...gateAlarmRows(stop, columns));
|
|
@@ -121,12 +121,7 @@ export function reconcileHasFailure(report) {
|
|
|
121
121
|
if (isRepoReport(report)) {
|
|
122
122
|
if (report.kind === "world-observation-failed")
|
|
123
123
|
return true;
|
|
124
|
-
|
|
125
|
-
return completed.contracts.some((item) => {
|
|
126
|
-
return (item.report.lag.some((lag) => reconcileLagIsFailure(lag)) ||
|
|
127
|
-
item.report.settlement.lags.length > 0 ||
|
|
128
|
-
(item.report.settlement.seatClose?.length ?? 0) > 0);
|
|
129
|
-
});
|
|
124
|
+
return report.contracts.some((item) => reconcileHasFailure(item.report));
|
|
130
125
|
}
|
|
131
126
|
return (report.lag.some((lag) => reconcileLagIsFailure(lag)) ||
|
|
132
127
|
(report.settlement?.lags.length ?? 0) > 0 ||
|
|
@@ -134,7 +129,13 @@ export function reconcileHasFailure(report) {
|
|
|
134
129
|
}
|
|
135
130
|
export function renderReconcile(report, context) {
|
|
136
131
|
const columns = context?.columns ?? DEFAULT_CLI_COLUMNS;
|
|
137
|
-
const lines = [
|
|
132
|
+
const lines = [
|
|
133
|
+
isRepoReport(report) && report.kind === "world-observation-failed"
|
|
134
|
+
? "! reconcile failed"
|
|
135
|
+
: reconcileHasFailure(report)
|
|
136
|
+
? "! reconcile incomplete"
|
|
137
|
+
: "✓ reconcile",
|
|
138
|
+
];
|
|
138
139
|
const seen = new Set();
|
|
139
140
|
if (isRepoReport(report)) {
|
|
140
141
|
if (report.kind === "world-observation-failed") {
|
|
@@ -33,11 +33,15 @@ function renderDirtyRefusal(refusal, indent, columns, identity) {
|
|
|
33
33
|
lines.push(...collectionLines(name, refusal[name], indent));
|
|
34
34
|
}
|
|
35
35
|
wrap(lines, gitShortStat(refusal.shortStat), indent, columns);
|
|
36
|
-
if (refusal.option
|
|
37
|
-
|
|
36
|
+
if (refusal.option === undefined) {
|
|
37
|
+
if (refusal.submodules.length > 0)
|
|
38
|
+
wrap(lines, "reason submodule changes cannot be captured for review", indent, columns);
|
|
39
|
+
}
|
|
40
|
+
else if (!refusal.option.available) {
|
|
41
|
+
lines.push(`${indent}option ${refusal.option.flag} · unavailable with submodule changes`);
|
|
38
42
|
}
|
|
39
43
|
else {
|
|
40
|
-
lines.push(`${indent}option
|
|
44
|
+
lines.push(`${indent}option ${refusal.option.flag} · captures complete non-ignored worktree bytes`);
|
|
41
45
|
lines.push(`${indent}capture index private · real index unchanged, including any unmerged entries`);
|
|
42
46
|
lines.push(`${indent}staging not required for --include-dirty`);
|
|
43
47
|
}
|
|
@@ -31,7 +31,7 @@ export declare function renderBoundedTextBlock(value: string, input: Readonly<{
|
|
|
31
31
|
lines?: number;
|
|
32
32
|
truncated?: boolean;
|
|
33
33
|
}>): readonly string[];
|
|
34
|
-
|
|
34
|
+
type BoundedPayload = Readonly<{
|
|
35
35
|
text: string;
|
|
36
36
|
first: string;
|
|
37
37
|
continuation: string;
|
|
@@ -39,7 +39,10 @@ export declare function renderBoundedPayload(input: Readonly<{
|
|
|
39
39
|
maxLines: number;
|
|
40
40
|
quote: string;
|
|
41
41
|
truncated: boolean;
|
|
42
|
-
|
|
42
|
+
/** Keep source line breaks and indentation; single-line previews fold whitespace instead. */
|
|
43
|
+
preserveLines?: true;
|
|
44
|
+
}>;
|
|
45
|
+
export declare function renderBoundedPayload(input: BoundedPayload): readonly string[];
|
|
43
46
|
export declare function quotedText(value: string): string;
|
|
44
47
|
export declare function safeText(value: string): string;
|
|
45
48
|
type CheckoutNotFollowable = Readonly<{
|
|
@@ -138,18 +138,8 @@ export function truncateMiddleDisplayText(value, maximum) {
|
|
|
138
138
|
const headColumns = Math.ceil(available / 2);
|
|
139
139
|
const tailColumns = available - headColumns;
|
|
140
140
|
const head = takeDisplayColumns(clean, headColumns).text.replace(/…+$/u, "");
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
let used = 0;
|
|
144
|
-
while (tailStart > 0) {
|
|
145
|
-
const candidate = characters[tailStart - 1];
|
|
146
|
-
const width = displayColumns(candidate);
|
|
147
|
-
if (used + width > tailColumns)
|
|
148
|
-
break;
|
|
149
|
-
used += width;
|
|
150
|
-
tailStart -= 1;
|
|
151
|
-
}
|
|
152
|
-
return `${head}…${characters.slice(tailStart).join("").replace(/^…+/u, "")}`;
|
|
141
|
+
const tail = takeDisplayColumnsFromEnd(clean, tailColumns).text.replace(/^…+/u, "");
|
|
142
|
+
return `${head}…${tail}`;
|
|
153
143
|
}
|
|
154
144
|
export function renderBoundedTextBlock(value, input) {
|
|
155
145
|
const maximumLines = input.lines ?? 3;
|
|
@@ -179,6 +169,78 @@ export function renderBoundedTextBlock(value, input) {
|
|
|
179
169
|
return lines.length === 0 ? [input.first.trimEnd()] : lines;
|
|
180
170
|
}
|
|
181
171
|
export function renderBoundedPayload(input) {
|
|
172
|
+
return input.preserveLines === true ? renderPreservedPayload(input) : renderFoldedPayload(input);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Paragraph-preserving payload: source line breaks and leading indentation stay,
|
|
176
|
+
* each line wraps at a word boundary where one exists, and the last rendered
|
|
177
|
+
* line carries either the closing quote or the one truncation mark.
|
|
178
|
+
*/
|
|
179
|
+
function renderPreservedPayload(input) {
|
|
180
|
+
const closing = input.quote === "" ? "" : input.quote === "“" ? "”" : input.quote;
|
|
181
|
+
if (input.text.length === 0)
|
|
182
|
+
return [input.quote === "" ? input.first.trimEnd() : `${input.first}${input.quote}${closing}`];
|
|
183
|
+
const source = input.text.split(/\r?\n/u).map((line) => safeText(line).replace(/\s+$/u, ""));
|
|
184
|
+
const lines = [];
|
|
185
|
+
let truncated = input.truncated;
|
|
186
|
+
let done = false;
|
|
187
|
+
/** Paragraph breaks are deferred so they never spend the preview's last usable line. */
|
|
188
|
+
let pendingBlanks = 0;
|
|
189
|
+
for (const line of source) {
|
|
190
|
+
if (done)
|
|
191
|
+
break;
|
|
192
|
+
if (line.length === 0) {
|
|
193
|
+
if (lines.length > 0)
|
|
194
|
+
pendingBlanks += 1;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
// A paragraph break never spends the preview's last line: content wins over a blank.
|
|
198
|
+
const room = input.maxLines - lines.length - 1;
|
|
199
|
+
for (let count = 0; count < Math.min(pendingBlanks, Math.max(0, room)); count += 1)
|
|
200
|
+
lines.push(input.continuation.trimEnd());
|
|
201
|
+
pendingBlanks = 0;
|
|
202
|
+
const indent = /^ */u.exec(line)[0];
|
|
203
|
+
let rest = line.slice(indent.length);
|
|
204
|
+
while (rest.length > 0) {
|
|
205
|
+
if (lines.length >= input.maxLines) {
|
|
206
|
+
truncated = true;
|
|
207
|
+
done = true;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
const prefix = lines.length === 0 ? input.first : input.continuation;
|
|
211
|
+
const opening = input.quote !== "" && lines.length === 0 ? input.quote : "";
|
|
212
|
+
// One cell stays reserved for a closing quote or an omission mark.
|
|
213
|
+
const budget = Math.max(1, input.columns - displayColumns(prefix) - displayColumns(opening) - 1);
|
|
214
|
+
const fragment = wrapFragment(rest, budget);
|
|
215
|
+
if (fragment.body.length === 0) {
|
|
216
|
+
truncated = true;
|
|
217
|
+
done = true;
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
lines.push(`${prefix}${opening}${indent}${fragment.body}`);
|
|
221
|
+
rest = fragment.remaining;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (lines.length === 0)
|
|
225
|
+
return [input.first.trimEnd()];
|
|
226
|
+
if (truncated)
|
|
227
|
+
lines[lines.length - 1] = truncateDisplayText(`${lines[lines.length - 1]}…`, input.columns);
|
|
228
|
+
else if (closing !== "")
|
|
229
|
+
lines[lines.length - 1] += closing;
|
|
230
|
+
return lines;
|
|
231
|
+
}
|
|
232
|
+
/** One wrapped fragment: a word boundary is preferred over splitting a word. */
|
|
233
|
+
function wrapFragment(rest, budget) {
|
|
234
|
+
const taken = takeDisplayColumns(rest, budget);
|
|
235
|
+
if (taken.rest.length === 0)
|
|
236
|
+
return { body: taken.text, remaining: "" };
|
|
237
|
+
const split = taken.text.lastIndexOf(" ");
|
|
238
|
+
if (split <= 0 || split < Math.floor(taken.text.length / 2))
|
|
239
|
+
return { body: taken.text, remaining: taken.rest };
|
|
240
|
+
return { body: taken.text.slice(0, split), remaining: `${taken.text.slice(split + 1)}${taken.rest}` };
|
|
241
|
+
}
|
|
242
|
+
/** Single-line and bounded summaries fold whitespace into one grapheme-safe stream. */
|
|
243
|
+
function renderFoldedPayload(input) {
|
|
182
244
|
let rest = safeText(input.text).replace(/\s+/gu, " ").trim();
|
|
183
245
|
const lines = [];
|
|
184
246
|
for (let index = 0; index < input.maxLines; index += 1) {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { panelHead } from "./akuma-activity.js";
|
|
2
|
+
import { safeText } from "./terminal.js";
|
|
3
|
+
function callerText(caller) {
|
|
4
|
+
if (caller.kind === "unknown")
|
|
5
|
+
return "unknown";
|
|
6
|
+
return caller.kind === "akuma" ? `${caller.akuId} · world ${caller.world}` : `${caller.integration}:${caller.id}`;
|
|
7
|
+
}
|
|
8
|
+
function originText(origin) {
|
|
9
|
+
return origin.kind === "request"
|
|
10
|
+
? `request · ${origin.parent} · ${origin.requestId}`
|
|
11
|
+
: `fork · ${origin.parent} · ${origin.at}`;
|
|
12
|
+
}
|
|
13
|
+
function selfHead(facts, dispatch, workdir) {
|
|
14
|
+
const self = facts.self;
|
|
15
|
+
if (self.kind === "akuma") {
|
|
16
|
+
const aliases = facts.profile?.kind === "available" ? facts.profile.aliases : [];
|
|
17
|
+
const identity = `${self.akuId}${aliases.length ? ` (${aliases.join(" · ")})` : ""}`;
|
|
18
|
+
return panelHead(identity, undefined, dispatch === undefined ? undefined : { kind: "associated", contractId: dispatch }, workdir == null ? [] : [workdir]).map(safeText);
|
|
19
|
+
}
|
|
20
|
+
const value = self.kind === "none" ? "none" : self.kind === "invalid" ? `invalid · ${self.reason}` : callerText(self);
|
|
21
|
+
return [safeText(`${value} (not an akuma)`)];
|
|
22
|
+
}
|
|
23
|
+
function contextText(contract) {
|
|
24
|
+
if (contract.kind === "resolved")
|
|
25
|
+
return contract.id;
|
|
26
|
+
if (contract.kind === "unavailable")
|
|
27
|
+
return `unavailable · ${contract.reason}`;
|
|
28
|
+
return contract.kind;
|
|
29
|
+
}
|
|
30
|
+
export function renderWhoami(facts) {
|
|
31
|
+
const row = (label, value) => ` ${label.padEnd(11)} ${safeText(value)}`;
|
|
32
|
+
const self = facts.self;
|
|
33
|
+
const profile = self.kind === "akuma" && facts.profile?.kind === "available" ? facts.profile : undefined;
|
|
34
|
+
const dispatch = profile?.contracts.length === 1 ? profile.contracts[0] : undefined;
|
|
35
|
+
const lines = selfHead(facts, dispatch, profile?.workdir);
|
|
36
|
+
if (self.kind === "akuma") {
|
|
37
|
+
lines.push(row("initiator", facts.initiatorUnavailable === undefined
|
|
38
|
+
? (facts.initiator ?? "none")
|
|
39
|
+
: `unavailable · ${facts.initiatorUnavailable}`));
|
|
40
|
+
if (profile !== undefined)
|
|
41
|
+
lines.push(row("parent", callerText(profile.birth.caller)));
|
|
42
|
+
}
|
|
43
|
+
lines.push(row("world", facts.world ?? "none"));
|
|
44
|
+
const context = contextText(facts.contract);
|
|
45
|
+
if (context !== dispatch)
|
|
46
|
+
lines.push(row("context", context));
|
|
47
|
+
lines.push(row("requests", facts.requests));
|
|
48
|
+
if (self.kind === "akuma" && facts.profile?.kind === "unavailable")
|
|
49
|
+
lines.push(row("profile", `unavailable · ${facts.profile.reason}`));
|
|
50
|
+
if (profile !== undefined) {
|
|
51
|
+
lines.push(row("runtime", `${profile.provider ?? "unknown"} · ${profile.model ?? "unknown"}`));
|
|
52
|
+
if (profile.birth.origin.kind !== "direct")
|
|
53
|
+
lines.push(row("origin", originText(profile.birth.origin)));
|
|
54
|
+
}
|
|
55
|
+
return lines.join("\n");
|
|
56
|
+
}
|
|
@@ -2,6 +2,7 @@ import { type LibraryExecution } from "../akuma/requests.js";
|
|
|
2
2
|
import { type ActorId } from "../index.js";
|
|
3
3
|
import type { ExecutionObserver } from "../protocol/execution-observation.js";
|
|
4
4
|
import { type ParsedCommand, type ParsedInvocation } from "./parse.js";
|
|
5
|
+
import { type CliOutcome } from "./streams.js";
|
|
5
6
|
export type ParsedCommandInvocation = Extract<ParsedInvocation, {
|
|
6
7
|
command: ParsedCommand;
|
|
7
8
|
}>;
|
|
@@ -30,7 +31,7 @@ export type CliRuntimeInput = Readonly<{
|
|
|
30
31
|
export declare function writeExecutionProgress(stream?: NodeJS.WritableStream): Promise<ExecutionProgressDriver>;
|
|
31
32
|
type AkumaFailureProjection = Readonly<{
|
|
32
33
|
body: string;
|
|
33
|
-
|
|
34
|
+
outcome: CliOutcome;
|
|
34
35
|
}>;
|
|
35
36
|
/** Projection of one native Akuma addressing/observation failure into its stated refusal body. */
|
|
36
37
|
export declare function akumaFailureProjection(error: unknown, command: ParsedCommand): Promise<AkumaFailureProjection | undefined>;
|