@astrosheep/keiyaku 4.5.19 → 4.5.21
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/README.md +4 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +14 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +53 -20
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +237 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +6 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +2 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -3
- package/build/src/akuma/akuma-handle.d.ts +5 -1
- package/build/src/akuma/akuma-handle.js +4 -1
- package/build/src/akuma/akuma-instance.d.ts +7 -2
- package/build/src/akuma/akuma-instance.js +14 -7
- package/build/src/akuma/akuma-observe.d.ts +11 -0
- package/build/src/akuma/akuma-observe.js +23 -0
- package/build/src/akuma/akuma-product.d.ts +2 -0
- package/build/src/akuma/akuma-product.js +6 -0
- package/build/src/akuma/akuma.d.ts +20 -1
- package/build/src/akuma/akuma.js +2 -0
- package/build/src/akuma/allowed.d.ts +20 -0
- package/build/src/akuma/allowed.js +11 -0
- package/build/src/akuma/archetype.js +3 -0
- package/build/src/akuma/body.d.ts +25 -5
- package/build/src/akuma/body.js +70 -31
- package/build/src/akuma/call-request.d.ts +5 -0
- package/build/src/akuma/call-request.js +14 -4
- package/build/src/akuma/fleet-execution.d.ts +28 -0
- package/build/src/akuma/fleet-execution.js +36 -4
- package/build/src/akuma/fleet-observation.d.ts +54 -0
- package/build/src/akuma/fleet-request.d.ts +10 -0
- package/build/src/akuma/fleet-request.js +13 -3
- package/build/src/akuma/heart/facts.d.ts +2 -0
- package/build/src/akuma/heart/index.d.ts +1 -0
- package/build/src/akuma/heart/index.js +4 -1
- package/build/src/akuma/heart/rows.d.ts +2 -0
- package/build/src/akuma/heart/rows.js +7 -5
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +3 -1
- package/build/src/akuma/heart/tells.js +6 -5
- package/build/src/akuma/heart/timeline.js +1 -1
- package/build/src/akuma/provider-recipe.d.ts +1 -0
- package/build/src/akuma/provider-recipe.js +5 -0
- package/build/src/akuma/provider.d.ts +1 -1
- package/build/src/akuma/provider.js +1 -1
- package/build/src/akuma/providers/acp/core.js +3 -6
- package/build/src/akuma/providers/acp/index.js +3 -0
- package/build/src/akuma/providers/claude/index.js +10 -10
- package/build/src/akuma/providers/codex-app-server/index.js +12 -11
- package/build/src/akuma/providers/execution-environment.d.ts +6 -0
- package/build/src/akuma/providers/execution-environment.js +24 -0
- package/build/src/akuma/providers/grok-build/index.js +3 -0
- package/build/src/akuma/providers/opencode-sdk/index.js +32 -23
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +8 -1
- package/build/src/akuma/providers/opencode-sdk/session.js +6 -5
- package/build/src/akuma/providers/pi/events.js +7 -2
- package/build/src/akuma/providers/pi/index.js +5 -2
- package/build/src/akuma/request-observation.d.ts +45 -0
- package/build/src/akuma/request-observation.js +162 -0
- package/build/src/akuma/request-rendezvous.d.ts +6 -3
- package/build/src/akuma/request-rendezvous.js +80 -14
- package/build/src/akuma/request-serve.js +27 -4
- package/build/src/akuma/request-wire.d.ts +5 -0
- package/build/src/akuma/request-wire.js +2 -0
- package/build/src/akuma/turn-drive.d.ts +1 -0
- package/build/src/akuma/turn-drive.js +2 -0
- package/build/src/akuma-body.js +5 -0
- package/build/src/body/amend.js +6 -4
- package/build/src/body/decode.d.ts +3 -1
- package/build/src/body/decode.js +53 -17
- package/build/src/body/region.d.ts +9 -1
- package/build/src/body/region.js +87 -12
- package/build/src/body/render.js +1 -1
- package/build/src/body/verification.d.ts +3 -1
- package/build/src/body/verification.js +4 -1
- package/build/src/cli/accepted.js +19 -2
- package/build/src/cli/commands/akuma-invoke.d.ts +3 -1
- package/build/src/cli/commands/akuma-invoke.js +134 -14
- package/build/src/cli/commands/akuma.js +24 -12
- package/build/src/cli/commands/contract-help.d.ts +15 -15
- package/build/src/cli/commands/contract-help.js +45 -19
- package/build/src/cli/commands/contract-invoke.d.ts +3 -0
- package/build/src/cli/commands/contract-invoke.js +25 -11
- package/build/src/cli/commands/contract.js +6 -4
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +1 -1
- package/build/src/cli/commands/status-set.js +15 -24
- package/build/src/cli/commands/task.js +18 -18
- package/build/src/cli/invoke.d.ts +3 -0
- package/build/src/cli/invoke.js +58 -23
- package/build/src/cli/main.js +5 -0
- package/build/src/cli/parse.d.ts +3 -0
- package/build/src/cli/parse.js +26 -4
- package/build/src/cli/render/akuma-activity.d.ts +100 -2
- package/build/src/cli/render/akuma-activity.js +485 -40
- package/build/src/cli/render/akuma.d.ts +10 -0
- package/build/src/cli/render/akuma.js +31 -21
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/board.js +1 -1
- package/build/src/cli/render/catalog.js +16 -13
- package/build/src/cli/render/contract-history.js +39 -10
- package/build/src/cli/render/contract-observation.js +10 -6
- package/build/src/cli/render/contract.js +109 -106
- package/build/src/cli/render/execution-progress.d.ts +26 -0
- package/build/src/cli/render/execution-progress.js +178 -0
- package/build/src/cli/render/kanshi-akuma.js +27 -39
- package/build/src/cli/render/kanshi.js +33 -26
- package/build/src/cli/render/nuke.js +1 -1
- package/build/src/cli/render/receipt.d.ts +1 -1
- package/build/src/cli/render/receipt.js +6 -6
- package/build/src/cli/render/refusal.js +10 -7
- package/build/src/cli/render/region.js +1 -1
- package/build/src/cli/render/settings.js +12 -2
- package/build/src/cli/render/status-line.d.ts +30 -0
- package/build/src/cli/render/status-line.js +58 -0
- package/build/src/cli/render/status-set.js +1 -1
- package/build/src/cli/render/task.d.ts +2 -0
- package/build/src/cli/render/task.js +11 -7
- package/build/src/cli/render/terminal.d.ts +0 -1
- package/build/src/cli/render/terminal.js +47 -15
- package/build/src/cli/result.d.ts +1 -0
- package/build/src/cli/runtime.d.ts +2 -0
- package/build/src/cli/runtime.js +36 -4
- package/build/src/cli/usage.js +2 -2
- package/build/src/cli/version.d.ts +1 -0
- package/build/src/cli/version.js +25 -0
- package/build/src/git/hooks.d.ts +13 -1
- package/build/src/git/hooks.js +2 -1
- package/build/src/git/workspace.d.ts +1 -1
- package/build/src/git/workspace.js +1 -1
- package/build/src/identity/mint.d.ts +13 -0
- package/build/src/identity/mint.js +26 -0
- package/build/src/identity/normalize.d.ts +4 -0
- package/build/src/identity/normalize.js +30 -0
- package/build/src/index.d.ts +2 -0
- package/build/src/index.js +1 -0
- package/build/src/kanshi/read.js +17 -4
- package/build/src/kanshi/report.d.ts +1 -0
- package/build/src/library/akuma-creation.d.ts +2 -0
- package/build/src/library/akuma-creation.js +34 -18
- package/build/src/library/audit.d.ts +2 -0
- package/build/src/library/audit.js +1 -0
- package/build/src/library/bind.js +18 -16
- package/build/src/library/composition.d.ts +1 -0
- package/build/src/library/contract-bind.d.ts +3 -1
- package/build/src/library/contract-bind.js +5 -3
- package/build/src/library/contract-execution.d.ts +2 -0
- package/build/src/library/contract-execution.js +15 -1
- package/build/src/library/contract-forwarding.d.ts +4 -0
- package/build/src/library/contract-forwarding.js +3 -0
- package/build/src/library/contract-handle.d.ts +7 -0
- package/build/src/library/contract-handle.js +25 -0
- package/build/src/library/contract-operations.d.ts +7 -2
- package/build/src/library/contract-operations.js +21 -1
- package/build/src/library/contract-types.d.ts +1 -0
- package/build/src/library/execution-result.d.ts +2 -2
- package/build/src/library/execution.d.ts +8 -0
- package/build/src/library/execution.js +102 -0
- package/build/src/library/fleet.d.ts +4 -1
- package/build/src/library/fleet.js +32 -8
- package/build/src/library/keiyaku.d.ts +2 -0
- package/build/src/library/mutation.js +15 -7
- package/build/src/plugin/akuma-signals.d.ts +6 -0
- package/build/src/plugin/akuma-signals.js +9 -1
- package/build/src/plugin/public.d.ts +6 -2
- package/build/src/plugin/runtime.d.ts +1 -3
- package/build/src/plugin/runtime.js +95 -103
- package/build/src/protocol/amend.js +4 -3
- package/build/src/protocol/attempt.d.ts +2 -0
- package/build/src/protocol/bind.js +41 -14
- package/build/src/protocol/completion.d.ts +3 -0
- package/build/src/protocol/completion.js +35 -11
- package/build/src/protocol/deliver.js +165 -92
- package/build/src/protocol/execution-observation.d.ts +181 -0
- package/build/src/protocol/execution-observation.js +45 -0
- package/build/src/protocol/intent.d.ts +18 -22
- package/build/src/protocol/intent.js +63 -41
- package/build/src/protocol/operations.d.ts +2 -0
- package/build/src/protocol/placement.js +5 -1
- package/build/src/protocol/progress.d.ts +5 -1
- package/build/src/protocol/progress.js +10 -1
- package/build/src/protocol/read/status.d.ts +1 -0
- package/build/src/protocol/read/status.js +10 -2
- package/build/src/protocol/reintegrate.d.ts +1 -1
- package/build/src/protocol/reintegrate.js +70 -43
- package/build/src/protocol/result-codec.js +27 -11
- package/build/src/protocol/review.js +53 -30
- package/build/src/protocol/run.d.ts +83 -36
- package/build/src/protocol/run.js +90 -75
- package/build/src/runtime/proc/run.d.ts +16 -4
- package/build/src/runtime/proc/run.js +64 -22
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settings.js +5 -14
- package/build/src/task/document.d.ts +5 -1
- package/build/src/task/document.js +6 -1
- package/build/src/verification/execution.d.ts +10 -2
- package/build/src/verification/execution.js +143 -42
- package/build/src/verification/observation.d.ts +41 -0
- package/build/src/verification/observation.js +29 -0
- package/package.json +3 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { renderAcceptedAudit } from "./audit.js";
|
|
2
2
|
import { appendHookPayload, executionCleanupLines, executionStopLines, hookFailureSummary, outcomeLines, receiptPayload, receiptRow, reuseLines, stopLines, titleLines, } from "./receipt.js";
|
|
3
|
-
import {
|
|
3
|
+
import { renderOpaqueBlock, safeText, tone } from "./terminal.js";
|
|
4
4
|
const HANG = " ";
|
|
5
5
|
function isRecord(value) {
|
|
6
6
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -14,23 +14,19 @@ function retryLines(detail, indent, columns) {
|
|
|
14
14
|
function lagRows(lag, columns) {
|
|
15
15
|
const lines = [];
|
|
16
16
|
if (lag.kind === "worktree-retained") {
|
|
17
|
-
receiptRow(lines, "!", "lag", [{ text:
|
|
17
|
+
receiptRow(lines, "!", "lag", [{ text: "worktree retained" }, { text: lag.path, opaque: true }], columns);
|
|
18
18
|
}
|
|
19
19
|
else if (lag.kind === "worktree-follow-retained") {
|
|
20
20
|
receiptRow(lines, "!", "lag", [
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
},
|
|
21
|
+
{ text: "worktree follow retained" },
|
|
22
|
+
{ text: "·" },
|
|
23
|
+
{ text: lag.reason.replaceAll("-", " ") },
|
|
24
|
+
{ text: "·" },
|
|
25
|
+
{ text: lag.path, opaque: true },
|
|
25
26
|
], columns);
|
|
26
27
|
}
|
|
27
28
|
else if (lag.kind === "unsealed-bytes") {
|
|
28
|
-
receiptRow(lines, "!", "lag", [
|
|
29
|
-
{
|
|
30
|
-
text: `unsealed-bytes ${lag.path}${lag.head === undefined ? "" : ` head ${lag.head}`}${lag.paths.length === 0 ? "" : ` paths ${lag.paths.join(",")}`}`,
|
|
31
|
-
opaque: true,
|
|
32
|
-
},
|
|
33
|
-
], columns);
|
|
29
|
+
receiptRow(lines, "!", "lag", [{ text: "unsealed bytes" }, { text: lag.path, opaque: true }], columns);
|
|
34
30
|
}
|
|
35
31
|
else if (lag.kind === "target-checkout-retained") {
|
|
36
32
|
receiptRow(lines, "!", "lag", [{ text: `target-checkout-retained ${lag.target} ${lag.path}`, opaque: true }], columns);
|
|
@@ -57,39 +53,43 @@ function lagRows(lag, columns) {
|
|
|
57
53
|
}
|
|
58
54
|
function settlementLagRows(lag, columns) {
|
|
59
55
|
const lines = [];
|
|
60
|
-
receiptRow(lines, "!", "settlement", [
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
lag.path === undefined ? undefined : `path ${lag.path}`,
|
|
66
|
-
]
|
|
67
|
-
.filter((part) => part !== undefined)
|
|
68
|
-
.join(" "),
|
|
69
|
-
opaque: true,
|
|
70
|
-
},
|
|
71
|
-
], columns);
|
|
56
|
+
receiptRow(lines, "!", "settlement", [{ text: lag.surface.replaceAll("-", " ") }], columns);
|
|
57
|
+
if (lag.taskId !== undefined)
|
|
58
|
+
receiptRow(lines, " ", "task", [{ text: lag.taskId, opaque: true }], columns);
|
|
59
|
+
if (lag.path !== undefined)
|
|
60
|
+
receiptRow(lines, " ", "path", [{ text: lag.path, opaque: true }], columns);
|
|
72
61
|
receiptPayload(lines, "diagnostic", lag.diagnostic);
|
|
73
62
|
return lines;
|
|
74
63
|
}
|
|
75
|
-
function
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
64
|
+
function overlapRows(overlaps, color) {
|
|
65
|
+
const groups = new Map();
|
|
66
|
+
for (const overlap of overlaps) {
|
|
67
|
+
let patterns = groups.get(overlap.contract);
|
|
68
|
+
if (patterns === undefined) {
|
|
69
|
+
patterns = new Map();
|
|
70
|
+
groups.set(overlap.contract, patterns);
|
|
81
71
|
}
|
|
72
|
+
for (const pattern of overlap.patterns)
|
|
73
|
+
patterns.set(JSON.stringify([pattern.mine, pattern.theirs]), pattern);
|
|
82
74
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
75
|
+
if (groups.size === 0)
|
|
76
|
+
return [];
|
|
77
|
+
const lines = ["", ` ${tone("overlap", "dim", color)}`];
|
|
78
|
+
for (const [contract, patterns] of groups) {
|
|
79
|
+
if (lines.length > 2)
|
|
80
|
+
lines.push("");
|
|
81
|
+
const identity = safeText(contract);
|
|
82
|
+
lines.push(` ${tone("└─", "dim", color)} ${color ? `\u001b[1m${identity}\u001b[0m` : identity}`);
|
|
83
|
+
let first = true;
|
|
84
|
+
for (const { mine, theirs } of patterns.values()) {
|
|
85
|
+
if (mine === theirs)
|
|
86
|
+
lines.push(` ${safeText(mine)}`);
|
|
87
|
+
else {
|
|
88
|
+
if (!first)
|
|
89
|
+
lines.push("");
|
|
90
|
+
lines.push(` this ${safeText(mine)}`, ` other ${safeText(theirs)}`);
|
|
91
|
+
}
|
|
92
|
+
first = false;
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
return lines;
|
|
@@ -101,19 +101,6 @@ function pushBlock(lines, block) {
|
|
|
101
101
|
}
|
|
102
102
|
function acceptedRecord(result, columns) {
|
|
103
103
|
const record = [];
|
|
104
|
-
for (const fact of result.facts) {
|
|
105
|
-
const contract = fact.contract === result.contract ? [] : [{ text: fact.contract, opaque: true }];
|
|
106
|
-
receiptRow(record, " ", "journal", fact.kind === "reintegrated"
|
|
107
|
-
? [
|
|
108
|
-
...contract,
|
|
109
|
-
{ text: fact.entry, opaque: true },
|
|
110
|
-
{ text: "· reintegrated" },
|
|
111
|
-
{ text: fact.data.predecessor, opaque: true },
|
|
112
|
-
{ text: "->" },
|
|
113
|
-
{ text: fact.data.snapshot, opaque: true },
|
|
114
|
-
]
|
|
115
|
-
: [...contract, { text: fact.entry, opaque: true }, { text: `· ${fact.kind}` }], columns);
|
|
116
|
-
}
|
|
117
104
|
if (result.recoverySnapshot !== undefined)
|
|
118
105
|
receiptRow(record, " ", "recovery snapshot", [{ text: result.recoverySnapshot, opaque: true }], columns);
|
|
119
106
|
if (result.verb === "deliver") {
|
|
@@ -134,25 +121,10 @@ function acceptedLagRows(result, columns) {
|
|
|
134
121
|
pushBlock(obligations, executionStopLines(result.executionStops ?? [], columns));
|
|
135
122
|
return obligations;
|
|
136
123
|
}
|
|
137
|
-
function
|
|
138
|
-
let payload = false;
|
|
139
|
-
return lines.map((line) => {
|
|
140
|
-
if (line.length === 0) {
|
|
141
|
-
payload = !payload;
|
|
142
|
-
return line;
|
|
143
|
-
}
|
|
144
|
-
return payload ? line : ` ${line}`;
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
function acceptedDeviations(result, columns) {
|
|
124
|
+
function acceptedDeviations(result, columns, color) {
|
|
148
125
|
const deviations = [];
|
|
149
|
-
if (result.verb === "review") {
|
|
150
|
-
if (result.workspace !== undefined)
|
|
151
|
-
pushBlock(deviations, workspaceRows(result.workspace, columns));
|
|
152
|
-
return deviations;
|
|
153
|
-
}
|
|
154
126
|
if (result.overlaps !== undefined)
|
|
155
|
-
pushBlock(deviations, overlapRows(result.overlaps,
|
|
127
|
+
pushBlock(deviations, overlapRows(result.overlaps, color));
|
|
156
128
|
if (result.overlapFailure !== undefined) {
|
|
157
129
|
receiptRow(deviations, "!", "overlap", [{ text: "unavailable" }], columns);
|
|
158
130
|
receiptPayload(deviations, "diagnostic", result.overlapFailure);
|
|
@@ -161,29 +133,57 @@ function acceptedDeviations(result, columns) {
|
|
|
161
133
|
}
|
|
162
134
|
function recordBlock(result, columns) {
|
|
163
135
|
const rows = [...acceptedRecord(result, columns), ...acceptedLagRows(result, columns)];
|
|
164
|
-
return
|
|
136
|
+
return rows;
|
|
165
137
|
}
|
|
166
|
-
function
|
|
138
|
+
function nonGatingVerificationLines(result, columns) {
|
|
167
139
|
const lines = [];
|
|
140
|
+
const verification = result.completion?.verification;
|
|
141
|
+
if (verification === undefined || verification.verdict !== "unsatisfied")
|
|
142
|
+
return lines;
|
|
143
|
+
receiptRow(lines, "!", "verification", [{ text: "unsatisfied" }, { text: `(${verification.mode})` }, { text: "· not required by Contract gates" }], columns);
|
|
144
|
+
if (result.verificationSummary !== undefined) {
|
|
145
|
+
receiptPayload(lines, " summary", result.verificationSummary);
|
|
146
|
+
}
|
|
147
|
+
return lines;
|
|
148
|
+
}
|
|
149
|
+
function shortGitId(value) {
|
|
150
|
+
return /^[0-9a-f]{40}$/iu.test(value) ? value.slice(0, 7) : value;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Shared presentation of a completed placement, so a deliver and a review that placed the same candidate read
|
|
154
|
+
* identically: one git-shaped target movement row, naming the reference it advanced, then the final lifecycle
|
|
155
|
+
* state. Satisfied Verification adds one fact row naming the commit the verdict ran against; placement made that
|
|
156
|
+
* commit the reference's new head, so the two rows share one sha. Verification mode words stay in JSON and
|
|
157
|
+
* `history`, never in ordinary receipt text. A completion without an advanced reference states no movement.
|
|
158
|
+
* Journal ULIDs stay in JSON and `history`, never in ordinary receipt text.
|
|
159
|
+
*/
|
|
160
|
+
function completedPlacementLines(result, columns) {
|
|
168
161
|
const completion = result.completion;
|
|
169
162
|
if (completion === undefined)
|
|
170
|
-
return
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
: []),
|
|
178
|
-
], columns);
|
|
179
|
-
if (verification !== undefined && "verdict" in verification && verification.verdict === "unsatisfied") {
|
|
180
|
-
receiptRow(lines, "!", "verification", [{ text: "unsatisfied" }, { text: `(${verification.mode})` }, { text: "· not required by Contract gates" }], columns);
|
|
181
|
-
if (result.verificationSummary !== undefined) {
|
|
182
|
-
receiptPayload(lines, " summary", result.verificationSummary);
|
|
183
|
-
}
|
|
163
|
+
return [];
|
|
164
|
+
const lines = [];
|
|
165
|
+
if (completion.predecessor !== undefined && completion.target !== undefined) {
|
|
166
|
+
receiptRow(lines, " ", "target", [
|
|
167
|
+
{ text: `${shortGitId(completion.predecessor)}..${shortGitId(completion.integration)}` },
|
|
168
|
+
{ text: completion.target, opaque: true },
|
|
169
|
+
], columns);
|
|
184
170
|
}
|
|
171
|
+
if (completion.verification?.verdict === "satisfied") {
|
|
172
|
+
receiptRow(lines, " ", "verification", [{ text: "satisfied" }, { text: `· on ${shortGitId(completion.integration)}` }], columns);
|
|
173
|
+
}
|
|
174
|
+
lines.push(...nonGatingVerificationLines(result, columns));
|
|
175
|
+
// Placement admission always admits the claim entry beside the movement, so a completed placement is claimed.
|
|
176
|
+
receiptRow(lines, "●", "claimed", [], columns);
|
|
185
177
|
return lines;
|
|
186
178
|
}
|
|
179
|
+
/** Evidence handles stay in JSON and history; ordinary receipt text carries only outstanding obligations. */
|
|
180
|
+
function obligationLines(result, columns) {
|
|
181
|
+
const rows = [];
|
|
182
|
+
if (result.recoverySnapshot !== undefined)
|
|
183
|
+
receiptRow(rows, " ", "recovery snapshot", [{ text: result.recoverySnapshot, opaque: true }], columns);
|
|
184
|
+
rows.push(...acceptedLagRows(result, columns));
|
|
185
|
+
return rows;
|
|
186
|
+
}
|
|
187
187
|
function movementLines(result, columns) {
|
|
188
188
|
const count = result.facts.filter((fact) => fact.kind === "reintegrated").length;
|
|
189
189
|
if (count === 0)
|
|
@@ -213,7 +213,7 @@ function continuationLines(result, columns) {
|
|
|
213
213
|
}
|
|
214
214
|
return lines;
|
|
215
215
|
}
|
|
216
|
-
function renderAcceptedBind(result, columns) {
|
|
216
|
+
function renderAcceptedBind(result, columns, color) {
|
|
217
217
|
const lines = titleLines("✓", "bound", result.contract, columns);
|
|
218
218
|
if (result.workspace !== undefined)
|
|
219
219
|
receiptRow(lines, " ", "workspace", [{ text: "worktree" }, { text: result.workspace.path, opaque: true }], columns);
|
|
@@ -221,27 +221,34 @@ function renderAcceptedBind(result, columns) {
|
|
|
221
221
|
receiptRow(lines, " ", "no target", [], columns);
|
|
222
222
|
else
|
|
223
223
|
receiptRow(lines, " ", "target", [{ text: result.target, opaque: true }], columns);
|
|
224
|
-
|
|
224
|
+
for (const warning of result.warnings ?? [])
|
|
225
|
+
receiptRow(lines, "!", "region warning", [{ text: warning }], columns);
|
|
226
|
+
lines.push(...acceptedDeviations(result, columns, color), ...recordBlock(result, columns));
|
|
225
227
|
return lines.join("\n");
|
|
226
228
|
}
|
|
227
|
-
function renderAcceptedAmend(result, columns) {
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
229
|
+
function renderAcceptedAmend(result, columns, color) {
|
|
230
|
+
const changed = result.diff.length > 0;
|
|
231
|
+
const lines = titleLines("✓", changed ? "terms replaced" : "terms unchanged", result.contract, columns);
|
|
232
|
+
if (changed)
|
|
233
|
+
receiptPayload(lines, " terms diff", result.diff);
|
|
234
|
+
lines.push(...acceptedDeviations(result, columns, color), ...recordBlock(result, columns));
|
|
231
235
|
return lines.join("\n");
|
|
232
236
|
}
|
|
233
237
|
function renderAcceptedDeliver(result, columns) {
|
|
234
238
|
const complete = result.completion !== undefined;
|
|
235
|
-
const title = complete ? "delivered" : "deliver
|
|
239
|
+
const title = complete ? "delivered" : "deliver incomplete";
|
|
236
240
|
const lines = titleLines("✓", title, result.contract, columns);
|
|
237
241
|
if (result.leading !== undefined) {
|
|
238
|
-
receiptRow(lines, " ", "leading", [{ text: result.leading.kind
|
|
242
|
+
receiptRow(lines, " ", "leading", [{ text: result.leading.kind.replaceAll("-", " ") }], columns);
|
|
239
243
|
}
|
|
240
244
|
if (result.tenderSnapshot !== undefined)
|
|
241
245
|
receiptRow(lines, " ", "tender commit", [{ text: result.tenderSnapshot, opaque: true }], columns);
|
|
242
246
|
if (result.integration !== undefined)
|
|
243
247
|
receiptRow(lines, " ", "content identity (not commit)", [{ text: result.integration.changeId, opaque: true }], columns);
|
|
244
|
-
|
|
248
|
+
if (complete)
|
|
249
|
+
lines.push(...completedPlacementLines(result, columns));
|
|
250
|
+
else
|
|
251
|
+
lines.push(...movementLines(result, columns));
|
|
245
252
|
if (result.verification !== undefined) {
|
|
246
253
|
lines.push(...stopLines(result.verification, columns, result.contract));
|
|
247
254
|
}
|
|
@@ -251,16 +258,12 @@ function renderAcceptedDeliver(result, columns) {
|
|
|
251
258
|
if (!complete)
|
|
252
259
|
receiptRow(lines, " ", "candidate", [{ text: "kept" }], columns);
|
|
253
260
|
lines.push(...continuationLines(result, columns));
|
|
254
|
-
lines.push(...recordBlock(result, columns));
|
|
261
|
+
lines.push(...(complete ? obligationLines(result, columns) : recordBlock(result, columns)));
|
|
255
262
|
return lines.join("\n");
|
|
256
263
|
}
|
|
257
264
|
function renderAcceptedReview(result, columns) {
|
|
258
|
-
const lines = titleLines("✓", `review ${result.verdict}
|
|
259
|
-
lines.push(...
|
|
260
|
-
if (result.completion !== undefined) {
|
|
261
|
-
receiptRow(lines, " ", "placement", [{ text: "complete" }], columns);
|
|
262
|
-
receiptRow(lines, " ", "integration commit", [{ text: result.completion.integration, opaque: true }], columns);
|
|
263
|
-
}
|
|
265
|
+
const lines = titleLines("✓", `review ${result.verdict}`, result.contract, columns);
|
|
266
|
+
lines.push(...completedPlacementLines(result, columns));
|
|
264
267
|
if (result.verification !== undefined) {
|
|
265
268
|
lines.push(...stopLines(result.verification, columns, result.contract));
|
|
266
269
|
}
|
|
@@ -268,11 +271,11 @@ function renderAcceptedReview(result, columns) {
|
|
|
268
271
|
lines.push(...stopLines(result.placement, columns, result.contract));
|
|
269
272
|
}
|
|
270
273
|
lines.push(...continuationLines(result, columns));
|
|
271
|
-
lines.push(...
|
|
274
|
+
lines.push(...obligationLines(result, columns));
|
|
272
275
|
return lines.join("\n");
|
|
273
276
|
}
|
|
274
277
|
function renderAcceptedArc(result, columns) {
|
|
275
|
-
const lines = titleLines("✓",
|
|
278
|
+
const lines = titleLines("✓", `entered chapter ${result.chapter.seq}`, result.contract, columns);
|
|
276
279
|
receiptRow(lines, " ", "chapter", [{ text: String(result.chapter.seq) }, { text: "·" }, { text: result.chapter.title }], columns);
|
|
277
280
|
lines.push(...recordBlock(result, columns));
|
|
278
281
|
return lines.join("\n");
|
|
@@ -290,9 +293,9 @@ export function renderAccepted(result, context) {
|
|
|
290
293
|
case "audit":
|
|
291
294
|
return renderAcceptedAudit(result, context);
|
|
292
295
|
case "bind":
|
|
293
|
-
return renderAcceptedBind(result, columns);
|
|
296
|
+
return renderAcceptedBind(result, columns, context?.color === true);
|
|
294
297
|
case "amend":
|
|
295
|
-
return renderAcceptedAmend(result, columns);
|
|
298
|
+
return renderAcceptedAmend(result, columns, context?.color === true);
|
|
296
299
|
case "review":
|
|
297
300
|
return renderAcceptedReview(result, columns);
|
|
298
301
|
case "arc":
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ExecutionEvent } from "../../library/execution.js";
|
|
2
|
+
import { type TextRenderContext } from "./terminal.js";
|
|
3
|
+
import { type StatusLineOptions, type StatusLineStream } from "./status-line.js";
|
|
4
|
+
/** Sparse rendering for consumers that do not own a live stream. */
|
|
5
|
+
export declare function executionProgressLines(event: ExecutionEvent, context: TextRenderContext): readonly string[];
|
|
6
|
+
export type ExecutionProgressOptions = StatusLineOptions & Readonly<{
|
|
7
|
+
stream: StatusLineStream;
|
|
8
|
+
context: TextRenderContext;
|
|
9
|
+
}>;
|
|
10
|
+
/** Consumes witnessed events into either a live TTY line or sparse text. */
|
|
11
|
+
export declare class ExecutionProgressRenderer {
|
|
12
|
+
private readonly input;
|
|
13
|
+
private readonly status;
|
|
14
|
+
private verificationStartedAt;
|
|
15
|
+
private declarations;
|
|
16
|
+
private declarationFailed;
|
|
17
|
+
private phaseFailed;
|
|
18
|
+
private phaseUnknown;
|
|
19
|
+
constructor(input: ExecutionProgressOptions);
|
|
20
|
+
consume(event: ExecutionEvent): Promise<void>;
|
|
21
|
+
finish(): void;
|
|
22
|
+
private consumeVerification;
|
|
23
|
+
private write;
|
|
24
|
+
private finalMark;
|
|
25
|
+
}
|
|
26
|
+
export declare function renderExecutionProgress(events: AsyncIterable<ExecutionEvent>, input: ExecutionProgressOptions): Promise<void>;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { renderOpaqueBlock, safeText } from "./terminal.js";
|
|
2
|
+
import { StatusLine } from "./status-line.js";
|
|
3
|
+
const LIVE_OUTPUT_BYTES = 4 * 1024;
|
|
4
|
+
function boundedUtf8Prefix(value) {
|
|
5
|
+
let bytes = 0;
|
|
6
|
+
let text = "";
|
|
7
|
+
for (const character of value) {
|
|
8
|
+
const size = Buffer.byteLength(character);
|
|
9
|
+
if (bytes + size > LIVE_OUTPUT_BYTES)
|
|
10
|
+
return { text, truncated: true };
|
|
11
|
+
bytes += size;
|
|
12
|
+
text += character;
|
|
13
|
+
}
|
|
14
|
+
return { text, truncated: false };
|
|
15
|
+
}
|
|
16
|
+
function elapsed(ms) {
|
|
17
|
+
const seconds = Math.max(0, Math.floor(ms / 1_000));
|
|
18
|
+
return seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m${seconds % 60}s`;
|
|
19
|
+
}
|
|
20
|
+
function phaseDetail(observation) {
|
|
21
|
+
if (observation.phase === "declaration")
|
|
22
|
+
return `declaration ${observation.index ?? "?"}/${observation.total ?? "?"}`;
|
|
23
|
+
return observation.name === undefined ? observation.phase : `${observation.phase} · ${safeText(observation.name)}`;
|
|
24
|
+
}
|
|
25
|
+
function phaseStartLine(observation) {
|
|
26
|
+
return `● ${[phaseDetail(observation), ...(observation.cwd === undefined ? [] : [safeText(observation.cwd)])].join(" · ")}`;
|
|
27
|
+
}
|
|
28
|
+
function phaseMark(outcome) {
|
|
29
|
+
if (outcome === undefined)
|
|
30
|
+
return "?";
|
|
31
|
+
return outcome === "ok" || outcome === "exit 0" ? "✓" : "×";
|
|
32
|
+
}
|
|
33
|
+
function phaseFinishLine(observation) {
|
|
34
|
+
const facts = [
|
|
35
|
+
phaseDetail(observation),
|
|
36
|
+
...(observation.elapsedMs === undefined ? [] : [elapsed(observation.elapsedMs)]),
|
|
37
|
+
];
|
|
38
|
+
if (observation.outcome !== undefined && observation.outcome !== "ok" && observation.outcome !== "exit 0")
|
|
39
|
+
facts.push(safeText(observation.outcome));
|
|
40
|
+
return `${phaseMark(observation.outcome)} ${facts.join(" · ")}`;
|
|
41
|
+
}
|
|
42
|
+
function outputLines(observation, context) {
|
|
43
|
+
const output = boundedUtf8Prefix(observation.text);
|
|
44
|
+
return [
|
|
45
|
+
observation.stream,
|
|
46
|
+
...renderOpaqueBlock(output.text, " ", context.columns),
|
|
47
|
+
...(output.truncated ? [" [live output truncated]"] : []),
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
/** Sparse rendering for consumers that do not own a live stream. */
|
|
51
|
+
export function executionProgressLines(event, context) {
|
|
52
|
+
switch (event.kind) {
|
|
53
|
+
case "admitted":
|
|
54
|
+
return [`✓ admitted ${event.fact.kind} · ${event.contractId}`];
|
|
55
|
+
case "verification":
|
|
56
|
+
return event.observation.kind === "output"
|
|
57
|
+
? outputLines(event.observation, context)
|
|
58
|
+
: [
|
|
59
|
+
event.observation.state === "started"
|
|
60
|
+
? phaseStartLine(event.observation)
|
|
61
|
+
: phaseFinishLine(event.observation),
|
|
62
|
+
];
|
|
63
|
+
case "stage":
|
|
64
|
+
return [`${event.state === "started" ? "●" : "✓"} ${event.stage}`];
|
|
65
|
+
case "progress-dropped":
|
|
66
|
+
return [`progress dropped ${event.count} event${event.count === 1 ? "" : "s"}`];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Consumes witnessed events into either a live TTY line or sparse text. */
|
|
70
|
+
export class ExecutionProgressRenderer {
|
|
71
|
+
input;
|
|
72
|
+
status;
|
|
73
|
+
verificationStartedAt;
|
|
74
|
+
declarations;
|
|
75
|
+
declarationFailed = false;
|
|
76
|
+
phaseFailed = false;
|
|
77
|
+
phaseUnknown = false;
|
|
78
|
+
constructor(input) {
|
|
79
|
+
this.input = input;
|
|
80
|
+
this.status = new StatusLine(input.stream, input);
|
|
81
|
+
}
|
|
82
|
+
async consume(event) {
|
|
83
|
+
if (event.kind === "verification") {
|
|
84
|
+
await this.consumeVerification(event);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
await this.write(executionProgressLines(event, this.input.context));
|
|
88
|
+
}
|
|
89
|
+
finish() {
|
|
90
|
+
if (!this.status.isTTY || this.verificationStartedAt === undefined)
|
|
91
|
+
return;
|
|
92
|
+
const now = this.input.now ?? (() => performance.now());
|
|
93
|
+
const duration = elapsed(now() - this.verificationStartedAt);
|
|
94
|
+
if (this.declarations !== undefined) {
|
|
95
|
+
const { passed, total } = this.declarations;
|
|
96
|
+
this.status.finish(`verify ${this.finalMark()} ${passed}/${total} · ${duration}`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.status.finish(`verify ${this.finalMark()} · ${duration}`);
|
|
100
|
+
}
|
|
101
|
+
async consumeVerification(event) {
|
|
102
|
+
const observation = event.observation;
|
|
103
|
+
if (observation.kind === "output") {
|
|
104
|
+
await this.write(outputLines(observation, this.input.context));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (observation.state === "started") {
|
|
108
|
+
this.verificationStartedAt ??= (this.input.now ?? (() => performance.now()))();
|
|
109
|
+
if (this.status.isTTY)
|
|
110
|
+
this.status.show((duration) => `verify ● ${phaseDetail(observation)} · ${elapsed(duration)}`);
|
|
111
|
+
else
|
|
112
|
+
await this.write([phaseStartLine(observation)]);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const mark = phaseMark(observation.outcome);
|
|
116
|
+
this.phaseFailed ||= mark === "×";
|
|
117
|
+
this.phaseUnknown ||= mark === "?";
|
|
118
|
+
if (observation.phase === "declaration") {
|
|
119
|
+
const total = observation.total ?? this.declarations?.total ?? 0;
|
|
120
|
+
const passed = (this.declarations?.passed ?? 0) + (mark === "✓" ? 1 : 0);
|
|
121
|
+
this.declarations = { passed, total };
|
|
122
|
+
this.declarationFailed ||= mark !== "✓";
|
|
123
|
+
}
|
|
124
|
+
if (this.status.isTTY)
|
|
125
|
+
this.status.show((duration) => `verify ${mark} ${phaseDetail(observation)} · ${elapsed(duration)}`);
|
|
126
|
+
else
|
|
127
|
+
await this.write([phaseFinishLine(observation)]);
|
|
128
|
+
}
|
|
129
|
+
write(lines) {
|
|
130
|
+
if (this.status.isTTY) {
|
|
131
|
+
this.status.writeBlock(lines);
|
|
132
|
+
return Promise.resolve();
|
|
133
|
+
}
|
|
134
|
+
return writeChunk(this.input.stream, `${lines.join("\n")}\n`);
|
|
135
|
+
}
|
|
136
|
+
finalMark() {
|
|
137
|
+
return this.phaseFailed || this.declarationFailed ? "×" : this.phaseUnknown ? "?" : "✓";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export async function renderExecutionProgress(events, input) {
|
|
141
|
+
const renderer = new ExecutionProgressRenderer(input);
|
|
142
|
+
const destination = watchDestination(input.stream);
|
|
143
|
+
const iterator = events[Symbol.asyncIterator]();
|
|
144
|
+
try {
|
|
145
|
+
for (;;) {
|
|
146
|
+
const next = await Promise.race([iterator.next(), destination.promise]);
|
|
147
|
+
if (next.done === true)
|
|
148
|
+
break;
|
|
149
|
+
await renderer.consume(next.value);
|
|
150
|
+
}
|
|
151
|
+
renderer.finish();
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
destination.detach();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/** Reject when the destination dies while the producer is still owned. */
|
|
158
|
+
function watchDestination(stream) {
|
|
159
|
+
let detach = () => undefined;
|
|
160
|
+
const promise = new Promise((_, reject) => {
|
|
161
|
+
const onError = (error) => reject(error);
|
|
162
|
+
const onClose = () => reject(Object.assign(new Error("write on prematurely closed destination"), { code: "ERR_STREAM_PREMATURE_CLOSE" }));
|
|
163
|
+
stream.once("error", onError);
|
|
164
|
+
stream.once("close", onClose);
|
|
165
|
+
detach = () => {
|
|
166
|
+
stream.off("error", onError);
|
|
167
|
+
stream.off("close", onClose);
|
|
168
|
+
};
|
|
169
|
+
});
|
|
170
|
+
promise.catch(() => undefined);
|
|
171
|
+
return { promise, detach };
|
|
172
|
+
}
|
|
173
|
+
/** Await one destination write: backpressure and error propagation in one callback. */
|
|
174
|
+
function writeChunk(stream, text) {
|
|
175
|
+
return new Promise((resolve, reject) => {
|
|
176
|
+
stream.write(text, (error) => (error ? reject(error) : resolve()));
|
|
177
|
+
});
|
|
178
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { snapshotActivityLines } from "./akuma-activity.js";
|
|
2
|
+
import { elapsedMilliseconds, entityLines, identityLine, RECENT_TONE_MS, renderSectionBlock, safeText, tone, } from "./terminal.js";
|
|
2
3
|
const NARROW_COLUMNS = 72;
|
|
4
|
+
const ACTIVITY_INDENT = " ";
|
|
3
5
|
function mostRecentTimestamp(...values) {
|
|
4
6
|
return values.reduce((latest, value) => {
|
|
5
7
|
if (value === null || value === undefined)
|
|
@@ -24,40 +26,27 @@ function akumaStatusTone(row, observedAt) {
|
|
|
24
26
|
function akumaMark(life) {
|
|
25
27
|
return life === "running"
|
|
26
28
|
? "●"
|
|
27
|
-
: life === "
|
|
28
|
-
? "
|
|
29
|
-
: life === "
|
|
30
|
-
? "
|
|
31
|
-
: life === "
|
|
32
|
-
? "
|
|
29
|
+
: life === "asleep"
|
|
30
|
+
? "○"
|
|
31
|
+
: life === "killed"
|
|
32
|
+
? "×"
|
|
33
|
+
: life === "stranded" || life === "stillborn" || life === "untidy"
|
|
34
|
+
? "!"
|
|
33
35
|
: "?";
|
|
34
36
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const latest = snapshot.entries.flatMap((entry) => (entry.kind === "row" ? [entry.row] : [])).at(-1);
|
|
40
|
-
if (latest === undefined) {
|
|
41
|
-
if (snapshot.kind !== "idle" || snapshot.outcome === undefined)
|
|
42
|
-
return undefined;
|
|
43
|
-
return snapshot.outcome.outcome.kind === "answered"
|
|
44
|
-
? snapshot.outcome.outcome.answer
|
|
45
|
-
: snapshot.outcome.outcome.diagnostic;
|
|
46
|
-
}
|
|
47
|
-
if (latest.kind === "tool")
|
|
48
|
-
return latest.name;
|
|
49
|
-
return "text" in latest ? latest.text : "activity";
|
|
37
|
+
/** Bounded latest semantic entry, rendered by the same activity renderer as a targeted snapshot. */
|
|
38
|
+
function latestActivityLines(snapshot, context) {
|
|
39
|
+
const bounded = { ...context, columns: Math.max(1, context.columns - ACTIVITY_INDENT.length) };
|
|
40
|
+
return snapshotActivityLines(snapshot, bounded, { latest: true }).map((line) => `${ACTIVITY_INDENT}${line}`);
|
|
50
41
|
}
|
|
51
42
|
function akumaLabel(row) {
|
|
52
43
|
const aliases = row.aliases ?? [];
|
|
53
44
|
return aliases.length === 0 ? "" : `(${aliases.join(" ")})`;
|
|
54
45
|
}
|
|
55
46
|
function endpointFact(id, observed) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
? `-> ${id} (unavailable)`
|
|
60
|
-
: `-> ${id}`;
|
|
47
|
+
// A bounded or failed Contract read leaves the disposition unknown; a parenthetical that
|
|
48
|
+
// cannot name the reason is absent, while a complete read that established absence says so.
|
|
49
|
+
return observed === "missing" ? `${id} (missing)` : id;
|
|
61
50
|
}
|
|
62
51
|
function renderAkuma(report, context) {
|
|
63
52
|
const section = report.akuma;
|
|
@@ -66,25 +55,26 @@ function renderAkuma(report, context) {
|
|
|
66
55
|
if (section.kind === "failed")
|
|
67
56
|
return ["AKUMA // unavailable", "", tone(`! ${safeText(section.failure.message)}`, "alert", context.color)];
|
|
68
57
|
const rows = section.value.rows;
|
|
58
|
+
if (rows.length === 0)
|
|
59
|
+
return [];
|
|
69
60
|
const rowLines = rows.map((row) => {
|
|
70
61
|
const statusTone = akumaStatusTone(row, report.observedAt);
|
|
71
62
|
const mark = statusTone === null ? akumaMark(row.life) : tone(akumaMark(row.life), statusTone, context.color);
|
|
72
63
|
const lifeAt = "lifeAt" in row ? row.lifeAt : null;
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
64
|
+
const lifeAge = formatAge(lifeAt, report.observedAt);
|
|
65
|
+
const life = `${row.life} · ${lifeAge}`;
|
|
66
|
+
const activityAge = "lastActivityAt" in row && row.lastActivityAt !== null ? formatAge(row.lastActivityAt, report.observedAt) : null;
|
|
67
|
+
const activity = activityAge === null || activityAge === lifeAge ? [] : [`activity ${activityAge}`];
|
|
77
68
|
const key = row.life === "stranded" && "strandedReason" in row && row.strandedReason === "resume-unsupported"
|
|
78
69
|
? [life, ...activity, "resume unsupported"]
|
|
79
70
|
: [life, ...activity];
|
|
80
|
-
const relation = row.contract === undefined ? [
|
|
81
|
-
const snapshot =
|
|
71
|
+
const relation = row.contract === undefined ? [] : [endpointFact(row.contract.id, row.contract.observed)];
|
|
72
|
+
const snapshot = row.snapshot;
|
|
73
|
+
const snapshotLines = snapshot === undefined ? [] : latestActivityLines(snapshot, context);
|
|
82
74
|
const aliases = akumaLabel(row);
|
|
83
75
|
if (context.columns > NARROW_COLUMNS) {
|
|
84
76
|
const lines = [identityLine(mark, row.id, `${aliases} · ${[...key, ...relation].join(" · ")}`.trim())];
|
|
85
|
-
return
|
|
86
|
-
? lines
|
|
87
|
-
: [...lines, ...plumbFacts([boundedActivity(snapshot, context.columns, " ")], context.columns)];
|
|
77
|
+
return [...lines, ...snapshotLines];
|
|
88
78
|
}
|
|
89
79
|
const identity = aliases.length === 0 ? row.id : `${row.id} ${aliases}`;
|
|
90
80
|
const lines = entityLines({
|
|
@@ -95,9 +85,7 @@ function renderAkuma(report, context) {
|
|
|
95
85
|
facts: [...key.slice(1), ...relation],
|
|
96
86
|
context,
|
|
97
87
|
});
|
|
98
|
-
return
|
|
99
|
-
? lines
|
|
100
|
-
: [...lines, ...plumbFacts([boundedActivity(snapshot, context.columns, " ")], context.columns)];
|
|
88
|
+
return [...lines, ...snapshotLines];
|
|
101
89
|
});
|
|
102
90
|
const rendered = renderSectionBlock({
|
|
103
91
|
name: "AKUMA",
|