@astrosheep/keiyaku 2.9.8 → 2.9.10
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 +50 -182
- package/build/.tsbuildinfo +1 -1
- package/build/agents/harness/control-types.js +18 -1
- package/build/agents/harness/index.js +2 -0
- package/build/agents/harness/outcome-error.js +81 -0
- package/build/agents/harness/projection.js +10 -7
- package/build/agents/harness/router.js +5 -1
- package/build/agents/providers/claude-agent-sdk/adapter.js +18 -4
- package/build/agents/providers/claude-agent-sdk/registration.js +11 -1
- package/build/agents/providers/claude-agent-sdk/session.js +19 -5
- package/build/agents/providers/codex-app-server/adapter.js +11 -6
- package/build/agents/providers/codex-app-server/events.js +67 -6
- package/build/agents/providers/codex-app-server/registration.js +11 -1
- package/build/agents/providers/opencode-sdk/adapter.js +8 -1
- package/build/agents/providers/opencode-sdk/events.js +24 -2
- package/build/agents/providers/opencode-sdk/registration.js +11 -1
- package/build/agents/providers/pi/checkpoint.js +9 -1
- package/build/agents/providers/pi/events.js +2 -0
- package/build/agents/providers/pi/registration.js +14 -1
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +3 -3
- package/build/cli/commands/akuma/catalog.js +2 -2
- package/build/cli/commands/akuma/{view → show}/handler.js +5 -5
- package/build/cli/commands/akuma/{view → show}/meta.js +3 -3
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +5 -4
- package/build/cli/commands/contract/arc/handler.js +5 -4
- package/build/cli/commands/contract/audit/handler.js +2 -2
- package/build/cli/commands/contract/bind/handler.js +12 -3
- package/build/cli/commands/contract/bind/meta.js +45 -15
- package/build/cli/commands/contract/forfeit/handler.js +9 -5
- package/build/cli/commands/contract/log/handler.js +2 -2
- package/build/cli/commands/contract/petition/handler.js +34 -7
- package/build/cli/commands/contract/renew/handler.js +7 -7
- package/build/cli/commands/contract/renew/meta.js +3 -3
- package/build/cli/commands/metadata.js +10 -6
- package/build/cli/commands/projection/call/meta.js +1 -1
- package/build/cli/commands/projection/catalog.js +2 -0
- package/build/cli/commands/projection/history/handler.js +21 -0
- package/build/cli/commands/projection/history/meta.js +9 -0
- package/build/cli/commands/projection/shared.js +3 -4
- package/build/cli/commands/projection/status/handler.js +3 -3
- package/build/cli/commands/projection/wait/handler.js +20 -11
- package/build/cli/commands/task/add/handler.js +14 -5
- package/build/cli/commands/task/add/meta.js +2 -2
- package/build/cli/commands/task/catalog.js +4 -0
- package/build/cli/commands/task/done/handler.js +1 -4
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/hold/handler.js +3 -0
- package/build/cli/commands/task/hold/meta.js +8 -0
- package/build/cli/commands/task/log/handler.js +1 -1
- package/build/cli/commands/task/log/meta.js +2 -2
- package/build/cli/commands/task/resume/handler.js +3 -0
- package/build/cli/commands/task/resume/meta.js +8 -0
- package/build/cli/commands/task/shared.js +39 -14
- package/build/cli/commands/task/show/handler.js +1 -1
- package/build/cli/commands/task/show/meta.js +1 -1
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +1 -4
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +11 -3
- package/build/cli/commands/task/update/meta.js +3 -3
- package/build/cli/completion.js +3 -2
- package/build/cli/flags.js +51 -14
- package/build/cli/help.js +4 -1
- package/build/cli/index.js +40 -25
- package/build/cli/parse-flags.js +40 -7
- package/build/cli/parse-metadata.js +5 -2
- package/build/cli/parse-selectors.js +2 -3
- package/build/cli/parse.js +40 -6
- package/build/cli/projection-address.js +12 -10
- package/build/cli/render/amendment-warning.js +8 -0
- package/build/cli/render/arc.js +6 -2
- package/build/cli/render/audit.js +400 -81
- package/build/cli/render/kanshi.js +242 -79
- package/build/cli/render/lifecycle.js +56 -0
- package/build/cli/render/misc.js +24 -28
- package/build/cli/render/petition.js +5 -0
- package/build/cli/render/projection-activity.js +65 -29
- package/build/cli/render/projection-history.js +64 -0
- package/build/cli/render/shared.js +23 -9
- package/build/cli/render/status.js +13 -35
- package/build/cli/render/task.js +51 -26
- package/build/cli/render/terminal-failure.js +3 -1
- package/build/cli/render/wait.js +45 -69
- package/build/cli/subagent-guard.js +1 -1
- package/build/cli/types.js +1 -1
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +24 -1
- package/build/config/settings/schema.js +3 -1
- package/build/core/address-carrier.js +89 -0
- package/build/core/addressing.js +255 -196
- package/build/core/amend.js +115 -38
- package/build/core/amendment-criteria.js +17 -0
- package/build/core/amendment-warning.js +10 -0
- package/build/core/arc.js +184 -83
- package/build/core/audit/candidate.js +110 -9
- package/build/core/audit/coordinates.js +120 -65
- package/build/core/audit/evidence.js +19 -23
- package/build/core/audit/facade.js +34 -11
- package/build/core/audit/report.js +5 -5
- package/build/core/bind-reconciliation.js +390 -0
- package/build/core/bind-workspace.js +12 -20
- package/build/core/bind.js +242 -273
- package/build/core/call/call.js +1 -0
- package/build/core/call/context.js +46 -71
- package/build/core/call/prompt.js +6 -3
- package/build/core/context.js +49 -35
- package/build/core/contract-carrier-runtime.js +408 -0
- package/build/core/contract-carrier.js +270 -0
- package/build/core/contract-view.js +33 -27
- package/build/core/contract.js +5 -1
- package/build/core/derived-replay.js +207 -0
- package/build/core/draft.js +125 -57
- package/build/core/forfeit.js +113 -56
- package/build/core/identifier-slug.js +63 -13
- package/build/core/ids.js +4 -4
- package/build/core/lifecycle-history.js +35 -0
- package/build/core/lifecycle-recovery.js +117 -0
- package/build/core/lifecycle-runner.js +377 -0
- package/build/core/log.js +37 -11
- package/build/core/outcome-base.js +181 -0
- package/build/core/process-group.js +139 -0
- package/build/core/projection/generation/database.js +82 -7
- package/build/core/projection/generation/model.js +9 -36
- package/build/core/projection/generation/projection-generation-continuation.js +10 -22
- package/build/core/projection/generation/projection-generation-execution.js +13 -6
- package/build/core/projection/index.js +5 -4
- package/build/core/projection/projection-activity.js +29 -8
- package/build/core/projection/projection-alias.js +23 -10
- package/build/core/projection/projection-core.js +21 -7
- package/build/core/projection/projection-execution-observer.js +91 -39
- package/build/core/projection/projection-history.js +474 -0
- package/build/core/projection/projection-runner-lock.js +12 -0
- package/build/core/projection/projection-status-observation.js +365 -0
- package/build/core/projection/projection-status.js +35 -337
- package/build/core/projection/projection-terminal-failure.js +13 -8
- package/build/core/projection/projection-wait.js +7 -2
- package/build/core/projection/tell/launch-store.js +244 -0
- package/build/core/projection/tell/model.js +3 -3
- package/build/core/projection/tell/store.js +70 -118
- package/build/core/registry.js +22 -87
- package/build/core/renew-build.js +424 -0
- package/build/core/renew-plan.js +239 -0
- package/build/core/renew-rewrite.js +77 -0
- package/build/core/renew.js +295 -520
- package/build/core/repository-ledger/accepted-fold-read.js +19 -0
- package/build/core/repository-ledger/accepted-tail.js +116 -0
- package/build/core/repository-ledger/admission.js +38 -0
- package/build/core/repository-ledger/authoritative-transaction.js +1 -0
- package/build/core/repository-ledger/claim-evidence.js +147 -0
- package/build/core/repository-ledger/codec.js +297 -0
- package/build/core/repository-ledger/current-state-store.js +853 -0
- package/build/core/repository-ledger/fold-repository.js +375 -0
- package/build/core/repository-ledger/fold.js +248 -0
- package/build/core/repository-ledger/git-object-store.js +243 -0
- package/build/core/repository-ledger/history-read.js +15 -0
- package/build/core/repository-ledger/incremental-read.js +153 -0
- package/build/core/repository-ledger/index.js +15 -0
- package/build/core/repository-ledger/inventory-plan.js +75 -0
- package/build/core/repository-ledger/inventory.js +310 -0
- package/build/core/repository-ledger/publication-admission.js +125 -0
- package/build/core/repository-ledger/publication.js +353 -0
- package/build/core/repository-ledger/read-model.js +469 -0
- package/build/core/repository-ledger/transaction-membership.js +78 -0
- package/build/core/repository-ledger/traversal.js +404 -0
- package/build/core/repository-ledger/write-transaction.js +339 -0
- package/build/core/seal.js +168 -161
- package/build/core/settlement/claim-delivery.js +42 -215
- package/build/core/settlement/claim.js +235 -153
- package/build/core/settlement/index.js +4 -4
- package/build/core/settlement/petition-claim-gates.js +52 -33
- package/build/core/settlement/petition-forfeit.js +12 -5
- package/build/core/settlement/petition-head-guard.js +8 -5
- package/build/core/settlement/petition-preview.js +68 -56
- package/build/core/settlement/petition-window.js +50 -0
- package/build/core/settlement/petition.js +252 -131
- package/build/core/settlement/queue-read-model.js +72 -95
- package/build/core/settlement/queue-seat-allocation.js +35 -126
- package/build/core/settlement/queue.js +1 -1
- package/build/core/settlement/settlement.js +172 -80
- package/build/core/settlement/verdict.js +112 -66
- package/build/core/settlement/verification-coordination.js +305 -0
- package/build/core/settlement/verification-supervisor.js +275 -0
- package/build/core/settlement/verification.js +398 -31
- package/build/core/status/board.js +125 -127
- package/build/core/status/lifecycle.js +7 -80
- package/build/core/structured-query.js +23 -0
- package/build/core/target-ref.js +1 -1
- package/build/core/task/board.js +59 -24
- package/build/core/task/commands.js +181 -33
- package/build/core/task/coordinate.js +56 -0
- package/build/core/task/document.js +25 -9
- package/build/core/task/index.js +7 -4
- package/build/core/task/query.js +17 -27
- package/build/core/task/settlement-git.js +164 -179
- package/build/core/task/settlement-policy.js +15 -11
- package/build/core/task/source-board.js +31 -13
- package/build/core/task/task-bind-preparation.js +193 -0
- package/build/core/task/task-contract.js +102 -193
- package/build/core/task/task-file-transaction.js +171 -0
- package/build/core/task/task-git-runtime.js +76 -14
- package/build/core/task/task-git-store.js +68 -169
- package/build/core/task/task-store-repository.js +13 -6
- package/build/core/task/task-worktree.js +6 -33
- package/build/core/task/task.js +1 -1
- package/build/core/task/tree.js +3 -3
- package/build/core/task/validation.js +4 -3
- package/build/core/transcripts.js +93 -1
- package/build/core/worktree-bootstrap.js +44 -36
- package/build/core/worktree-path.js +210 -77
- package/build/flow-error.js +7 -7
- package/build/generated/version.js +2 -2
- package/build/git/core.js +76 -13
- package/build/git/refs.js +168 -46
- package/build/git/streaming-batch.js +73 -13
- package/package.json +1 -1
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +3 -3
- package/skills/keiyaku-task/SKILL.md +4 -2
- package/skills/keiyaku-workflow/SKILL.md +88 -203
- package/build/core/entry.js +0 -305
- package/build/core/ledger-batch.js +0 -194
- package/build/core/ledger.js +0 -84
- package/build/core/projection/leash.js +0 -87
- package/build/core/ref-log.js +0 -119
- package/build/core/renew-session.js +0 -128
- package/build/core/status/ledger-batch.js +0 -1
- package/build/core/status/reconciliation.js +0 -137
|
@@ -1,25 +1,82 @@
|
|
|
1
|
+
import { getConfig } from "../../config/env.js";
|
|
1
2
|
import { formatAgeMs } from "./format.js";
|
|
3
|
+
import { displayColumns, resolveLineColumns, truncateColumns } from "./line-width.js";
|
|
4
|
+
import { renderPendingProjectionTell, renderProjectionActivity, selectProjectionActivityWindow, } from "./projection-activity.js";
|
|
5
|
+
const KANSHI_MAX_COLUMNS = 120;
|
|
6
|
+
const KANSHI_ACTIVITY_ROWS = 3;
|
|
2
7
|
function shortHead(hash) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
8
|
+
return hash?.slice(0, 7);
|
|
9
|
+
}
|
|
10
|
+
function supportsColor() {
|
|
11
|
+
const { terminal } = getConfig();
|
|
12
|
+
if (terminal.noColor !== undefined || terminal.forceColor === "0")
|
|
13
|
+
return false;
|
|
14
|
+
if (terminal.forceColor !== undefined)
|
|
15
|
+
return true;
|
|
16
|
+
return process.stdout.isTTY === true && terminal.term?.toLowerCase() !== "dumb";
|
|
17
|
+
}
|
|
18
|
+
function tone(text, value) {
|
|
19
|
+
if (!supportsColor() || value === undefined || value === "normal")
|
|
20
|
+
return text;
|
|
21
|
+
return value === "description"
|
|
22
|
+
? `\x1b[2m${text}\x1b[0m`
|
|
23
|
+
: `\x1b[31m${text}\x1b[0m`;
|
|
24
|
+
}
|
|
25
|
+
function renderFacts(facts) {
|
|
26
|
+
return {
|
|
27
|
+
plain: facts.map((fact) => fact.text).join(" · "),
|
|
28
|
+
rendered: facts.map((fact) => tone(fact.text, fact.tone)).join(" · "),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Align facts without allowing ANSI bytes to enter width arithmetic. */
|
|
32
|
+
function alignedBoardRow(input) {
|
|
33
|
+
const facts = renderFacts(input.facts);
|
|
34
|
+
const prefix = `${input.prefix} `;
|
|
35
|
+
const titleBudget = Math.max(0, input.width - displayColumns(prefix) - displayColumns(facts.plain) - 1);
|
|
36
|
+
const visibleTitle = truncateColumns(input.title, titleBudget);
|
|
37
|
+
const spaces = " ".repeat(Math.max(1, input.width - displayColumns(prefix) - displayColumns(visibleTitle) - displayColumns(facts.plain)));
|
|
38
|
+
return `${prefix}${tone(visibleTitle, input.titleTone ?? "description")}${spaces}${facts.rendered}`;
|
|
6
39
|
}
|
|
7
40
|
function arcSparkline(arcs) {
|
|
8
|
-
if (arcs <=
|
|
9
|
-
return
|
|
41
|
+
if (arcs <= 1)
|
|
42
|
+
return undefined;
|
|
10
43
|
return Array.from({ length: arcs }, () => "·").join("──");
|
|
11
44
|
}
|
|
12
45
|
function pendingAfterIds(contract) {
|
|
13
46
|
return contract.after.filter((item) => !item.terminal).map((item) => item.id);
|
|
14
47
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The Kanshi shape is the after DAG, not the petition/claim settlement queue.
|
|
50
|
+
* Stable input order settles independent lanes and any malformed cycle remains
|
|
51
|
+
* observable rather than dropping a contract.
|
|
52
|
+
*/
|
|
53
|
+
export function orderKanshiContracts(contracts) {
|
|
54
|
+
const byId = new Map(contracts.map((contract) => [contract.id, contract]));
|
|
55
|
+
const remaining = new Set(contracts.map((contract) => contract.id));
|
|
56
|
+
const emitted = new Set();
|
|
57
|
+
const ordered = [];
|
|
58
|
+
while (remaining.size > 0) {
|
|
59
|
+
const next = contracts.find((contract) => (remaining.has(contract.id)
|
|
60
|
+
&& pendingAfterIds(contract)
|
|
61
|
+
.filter((id) => byId.has(id))
|
|
62
|
+
.every((id) => emitted.has(id))));
|
|
63
|
+
if (!next) {
|
|
64
|
+
// The bind boundary normally rejects cycles. Keep a corrupt historical
|
|
65
|
+
// graph visible in its original deterministic order instead of inventing
|
|
66
|
+
// a dependency edge or omitting work from the board.
|
|
67
|
+
const fallback = contracts.find((contract) => remaining.has(contract.id));
|
|
68
|
+
if (!fallback)
|
|
69
|
+
break;
|
|
70
|
+
ordered.push(fallback);
|
|
71
|
+
emitted.add(fallback.id);
|
|
72
|
+
remaining.delete(fallback.id);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
ordered.push(next);
|
|
76
|
+
emitted.add(next.id);
|
|
77
|
+
remaining.delete(next.id);
|
|
78
|
+
}
|
|
79
|
+
return ordered;
|
|
23
80
|
}
|
|
24
81
|
function renderDriftMark(drift) {
|
|
25
82
|
if (drift.state === "drift")
|
|
@@ -28,73 +85,179 @@ function renderDriftMark(drift) {
|
|
|
28
85
|
return "▲orphaned";
|
|
29
86
|
return undefined;
|
|
30
87
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
88
|
+
function contractGlyph(contract) {
|
|
89
|
+
if (contract.state.state === "corrupt")
|
|
90
|
+
return "×";
|
|
91
|
+
return pendingAfterIds(contract).length > 0 ? "⧗" : "□";
|
|
92
|
+
}
|
|
93
|
+
function contractFacts(contract) {
|
|
94
|
+
const facts = [];
|
|
95
|
+
const spark = arcSparkline(contract.arcs);
|
|
96
|
+
if (spark)
|
|
97
|
+
facts.push({ text: spark });
|
|
98
|
+
const drift = renderDriftMark(contract.baseDrift);
|
|
99
|
+
if (drift)
|
|
100
|
+
facts.push({ text: drift });
|
|
101
|
+
const lifecycle = contract.state.state === "active" ? "open" : contract.state.state;
|
|
102
|
+
const age = formatAgeMs(contract.lastActiveMs);
|
|
103
|
+
facts.push({ text: age ? `${lifecycle} ${age}` : lifecycle });
|
|
104
|
+
if (contract.queueHeadStalled) {
|
|
105
|
+
facts.push({ text: age ? `stalled ${age}` : "stalled", tone: "alert" });
|
|
38
106
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
facts.push(contract.title);
|
|
56
|
-
facts.push(arcMark);
|
|
57
|
-
facts.push(`next ${contract.nextStep.detail}`);
|
|
58
|
-
const age = formatAgeMs(contract.lastActiveMs);
|
|
59
|
-
if (age)
|
|
60
|
-
facts.push(age);
|
|
61
|
-
if (contract.queuePosition)
|
|
62
|
-
facts.push(`Q${contract.queuePosition}`);
|
|
63
|
-
const drift = renderDriftMark(contract.baseDrift);
|
|
64
|
-
if (drift)
|
|
65
|
-
facts.push(drift);
|
|
66
|
-
if (contract.nextStep.hint)
|
|
67
|
-
facts.push(contract.nextStep.hint);
|
|
68
|
-
const pending = pendingAfterIds(contract);
|
|
69
|
-
if (pending.length > 0) {
|
|
70
|
-
facts.push(`⧗ ${pending.map((id) => {
|
|
71
|
-
const dot = id.indexOf(".");
|
|
72
|
-
return dot > 0 ? id.slice(0, dot) : id;
|
|
73
|
-
}).join(",")}`);
|
|
74
|
-
}
|
|
75
|
-
if (contract.state.state === "corrupt") {
|
|
76
|
-
facts.push(`corrupt (${contract.state.reason ?? contract.corruptReason ?? "unknown"})`);
|
|
77
|
-
}
|
|
78
|
-
if (contract.queueHeadStalled) {
|
|
79
|
-
facts.push("朱 stall 去广场");
|
|
80
|
-
}
|
|
81
|
-
const sparkCol = spark.padEnd(14);
|
|
82
|
-
const factText = facts.join(" · ");
|
|
83
|
-
lines.push(`${glyph} ${name.padEnd(18)} ${sparkCol} ${factText}`.trimEnd());
|
|
84
|
-
if (contract.bootstrapDiagnostics.some((diagnostic) => diagnostic.kind === "plan-without-result")) {
|
|
85
|
-
lines.push(" ! bootstrap · no result recorded · forfeit and re-bind");
|
|
86
|
-
}
|
|
87
|
-
for (const diagnostic of contract.queueDiagnostics) {
|
|
88
|
-
if (diagnostic.kind === "legacy-petition") {
|
|
89
|
-
lines.push(" ! legacy petition · no seat · reject then re-petition");
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
if (diagnostic.kind === "duplicate-seat") {
|
|
93
|
-
lines.push(` ! seat ${diagnostic.seat} duplicated with ${diagnostic.with} · ordered by contract id`);
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
lines.push(" ! target mismatch");
|
|
107
|
+
return facts;
|
|
108
|
+
}
|
|
109
|
+
function renderKeiyakuSection(board, width) {
|
|
110
|
+
if (!board.contractsObservable)
|
|
111
|
+
return undefined;
|
|
112
|
+
const lines = [`keiyaku ${board.contracts.length}`];
|
|
113
|
+
for (const contract of orderKanshiContracts(board.contracts)) {
|
|
114
|
+
lines.push(alignedBoardRow({
|
|
115
|
+
prefix: `${contractGlyph(contract)} ${contract.place ?? contract.slug}`,
|
|
116
|
+
title: contract.title,
|
|
117
|
+
facts: contractFacts(contract),
|
|
118
|
+
width,
|
|
119
|
+
}));
|
|
120
|
+
if (contract.replayBlockers.length > 0) {
|
|
121
|
+
lines.push(` ! incomplete replay · ${contract.replayBlockers.map((blocker) => blocker.surface).join(", ")}`);
|
|
122
|
+
lines.push(` • ${contract.replayBlockers[0].recoveryCommand}`);
|
|
97
123
|
}
|
|
98
124
|
}
|
|
99
|
-
return
|
|
125
|
+
return lines.join("\n");
|
|
126
|
+
}
|
|
127
|
+
function activityState(row) {
|
|
128
|
+
switch (row.state) {
|
|
129
|
+
case "lost": return "lost";
|
|
130
|
+
case "startup-timeout": return "stalled";
|
|
131
|
+
case "unknown":
|
|
132
|
+
case "incompatible": return "unknown";
|
|
133
|
+
case "failed":
|
|
134
|
+
case "dead": return "dead";
|
|
135
|
+
case "done": return "returned";
|
|
136
|
+
case "killed":
|
|
137
|
+
case "dismissed": return "dismissed";
|
|
138
|
+
case "minting":
|
|
139
|
+
case "out": return "running";
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function projectionBinding(board, row) {
|
|
143
|
+
if (row.binding?.kind !== "commission")
|
|
144
|
+
return "";
|
|
145
|
+
const place = board.commissionPlaces.get(row.binding.commissionId);
|
|
146
|
+
return place ? `@${place}` : "";
|
|
147
|
+
}
|
|
148
|
+
function projectionFacts(row) {
|
|
149
|
+
const facts = [];
|
|
150
|
+
if (row.durationMs !== undefined)
|
|
151
|
+
facts.push({ text: `up ${formatAgeMs(row.durationMs) ?? "0s"}` });
|
|
152
|
+
if (row.activityAgeMs !== undefined)
|
|
153
|
+
facts.push({ text: `active ${formatAgeMs(row.activityAgeMs) ?? "0s"}` });
|
|
154
|
+
if (row.state !== "out" && row.state !== "minting")
|
|
155
|
+
facts.push({ text: row.state, tone: row.state === "startup-timeout" ? "alert" : "normal" });
|
|
156
|
+
return facts;
|
|
157
|
+
}
|
|
158
|
+
function renderEmbeddedActivity(row, width) {
|
|
159
|
+
const observedAtMs = row.observedAtMs ?? Date.now();
|
|
160
|
+
const selection = row.activity
|
|
161
|
+
? selectProjectionActivityWindow(row.activity, KANSHI_ACTIVITY_ROWS)
|
|
162
|
+
: undefined;
|
|
163
|
+
const ordinary = row.activity
|
|
164
|
+
? renderProjectionActivity(selection.activity, {
|
|
165
|
+
anchorMs: observedAtMs,
|
|
166
|
+
state: activityState(row),
|
|
167
|
+
showPlan: false,
|
|
168
|
+
showSilence: false,
|
|
169
|
+
...(row.workspaceRoot ? { workspaceRoot: row.workspaceRoot } : {}),
|
|
170
|
+
maxColumns: width,
|
|
171
|
+
leadingOmittedCount: selection.leadingOmittedCount,
|
|
172
|
+
})
|
|
173
|
+
: undefined;
|
|
174
|
+
const rendered = ordinary?.lines.map((line, index) => ({
|
|
175
|
+
line,
|
|
176
|
+
at: ordinary.rowAts[index],
|
|
177
|
+
order: index,
|
|
178
|
+
})) ?? [];
|
|
179
|
+
const tells = (row.pendingTells ?? []).map((tell, index) => ({
|
|
180
|
+
line: renderPendingProjectionTell(tell, {
|
|
181
|
+
anchorMs: observedAtMs,
|
|
182
|
+
maxColumns: width,
|
|
183
|
+
renderUnconsumedTail: (tail) => tone(tail, "alert"),
|
|
184
|
+
}),
|
|
185
|
+
at: tell.createdAt,
|
|
186
|
+
order: rendered.length + index,
|
|
187
|
+
}));
|
|
188
|
+
return [...rendered, ...tells]
|
|
189
|
+
.sort((left, right) => {
|
|
190
|
+
const leftAt = Date.parse(left.at ?? "");
|
|
191
|
+
const rightAt = Date.parse(right.at ?? "");
|
|
192
|
+
const safeLeft = Number.isFinite(leftAt) ? leftAt : Number.POSITIVE_INFINITY;
|
|
193
|
+
const safeRight = Number.isFinite(rightAt) ? rightAt : Number.POSITIVE_INFINITY;
|
|
194
|
+
return safeLeft - safeRight || left.order - right.order;
|
|
195
|
+
})
|
|
196
|
+
.map((entry) => entry.line);
|
|
197
|
+
}
|
|
198
|
+
function terminalSummary(board) {
|
|
199
|
+
const omitted = board.projections?.omitted;
|
|
200
|
+
if (!omitted)
|
|
201
|
+
return undefined;
|
|
202
|
+
const compatibleStates = ["failed", "dead", "done", "killed", "dismissed"];
|
|
203
|
+
const details = compatibleStates
|
|
204
|
+
.flatMap((state) => omitted.byState[state] > 0 ? [`${omitted.byState[state]} ${state}`] : []);
|
|
205
|
+
return details.length > 0 ? `+ ${details.join(" · ")}` : undefined;
|
|
206
|
+
}
|
|
207
|
+
function renderAkumaSection(board, width) {
|
|
208
|
+
if (!board.projections)
|
|
209
|
+
return undefined;
|
|
210
|
+
const lines = [`akuma ${board.projections.rows.length}`];
|
|
211
|
+
for (const row of board.projections.rows) {
|
|
212
|
+
const alias = row.alias ? ` ${row.alias}` : "";
|
|
213
|
+
lines.push(alignedBoardRow({
|
|
214
|
+
prefix: `◆ ${row.id}${alias}`,
|
|
215
|
+
title: projectionBinding(board, row),
|
|
216
|
+
titleTone: "normal",
|
|
217
|
+
facts: projectionFacts(row),
|
|
218
|
+
width,
|
|
219
|
+
}));
|
|
220
|
+
lines.push(...renderEmbeddedActivity(row, width));
|
|
221
|
+
}
|
|
222
|
+
const folded = terminalSummary(board);
|
|
223
|
+
if (folded)
|
|
224
|
+
lines.push(tone(folded, "description"));
|
|
225
|
+
return lines.join("\n");
|
|
226
|
+
}
|
|
227
|
+
function taskLabel(task) {
|
|
228
|
+
return task.title === task.id ? `P${task.pri} ${task.id}` : `P${task.pri} ${task.id} ${task.title}`;
|
|
229
|
+
}
|
|
230
|
+
function renderTaskSection(tasks, width) {
|
|
231
|
+
if (!tasks)
|
|
232
|
+
return undefined;
|
|
233
|
+
const lines = [`task ${tasks.total}`];
|
|
234
|
+
for (const task of tasks.topTasks) {
|
|
235
|
+
lines.push(alignedBoardRow({
|
|
236
|
+
prefix: "▶",
|
|
237
|
+
title: taskLabel(task),
|
|
238
|
+
facts: [{ text: `${task.state === "on_hold" ? "on hold · updated" : "in_progress · active"} ${formatAgeMs(task.activityAgeMs) ?? "0s"}` }],
|
|
239
|
+
width,
|
|
240
|
+
}));
|
|
241
|
+
}
|
|
242
|
+
const folded = [
|
|
243
|
+
tasks.ready > 0 ? `${tasks.ready} ready` : undefined,
|
|
244
|
+
tasks.blocked > 0 ? `${tasks.blocked} blocked` : undefined,
|
|
245
|
+
tasks.onHold > 0 ? `${tasks.onHold} on hold` : undefined,
|
|
246
|
+
].filter((fact) => fact !== undefined);
|
|
247
|
+
if (folded.length > 0)
|
|
248
|
+
lines.push(tone(`+ ${folded.join(" · ")}`, "description"));
|
|
249
|
+
return lines.join("\n");
|
|
250
|
+
}
|
|
251
|
+
export function renderKanshiBoard(board) {
|
|
252
|
+
const width = Math.min(KANSHI_MAX_COLUMNS, resolveLineColumns());
|
|
253
|
+
const left = "kanshi ";
|
|
254
|
+
const head = shortHead(board.defaultHead);
|
|
255
|
+
const right = head ? ` 現世 ${head}` : " 現世";
|
|
256
|
+
const dashes = "─".repeat(Math.max(1, width - displayColumns(left) - displayColumns(right)));
|
|
257
|
+
const sections = [
|
|
258
|
+
renderKeiyakuSection(board, width),
|
|
259
|
+
renderAkumaSection(board, width),
|
|
260
|
+
renderTaskSection(board.tasks, width),
|
|
261
|
+
].filter((section) => section !== undefined);
|
|
262
|
+
return `${[`${left}${dashes}${right}`, ...sections].join("\n\n")}\n`;
|
|
100
263
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { attachAddressCarrier } from "../../core/addressing.js";
|
|
2
|
+
import { isCompleteLifecycleOutcome } from "../../core/outcome-base.js";
|
|
3
|
+
import { FlowError } from "../../flow-error.js";
|
|
4
|
+
import { handleCliError } from "./errors.js";
|
|
5
|
+
import { coreTextResponse } from "./shared.js";
|
|
6
|
+
function isSuccessfulDerivedCleanup(result) {
|
|
7
|
+
return result.family === "precommit-effects-only"
|
|
8
|
+
&& "status" in result
|
|
9
|
+
&& result.status === "success"
|
|
10
|
+
&& "cleanup" in result
|
|
11
|
+
&& typeof result.cleanup === "object"
|
|
12
|
+
&& result.cleanup !== null
|
|
13
|
+
&& "status" in result.cleanup
|
|
14
|
+
&& result.cleanup.status === "succeeded"
|
|
15
|
+
&& [...result.prerequisites, ...result.downstream].every((row) => row.status !== "failed");
|
|
16
|
+
}
|
|
17
|
+
export async function buildLifecycleOutcomeResponse(result, context) {
|
|
18
|
+
if (result.family === "committed") {
|
|
19
|
+
return coreTextResponse(`lifecycle committed at ${result.committed.head}${result.replay.action === "reconcile" ? "; downstream reconciliation required" : ""}`, result);
|
|
20
|
+
}
|
|
21
|
+
const cause = result.family === "cancelled-before-effects"
|
|
22
|
+
? result.cancellation
|
|
23
|
+
: result.family === "refused-before-effects"
|
|
24
|
+
? result.failedInvariant
|
|
25
|
+
: [...result.prerequisites, ...result.downstream].find((row) => row.status === "failed")?.cause
|
|
26
|
+
?? { code: "INTERNAL_STATE", message: "durable prerequisite effects require lifecycle reconciliation" };
|
|
27
|
+
if (!context) {
|
|
28
|
+
return { ...coreTextResponse(cause.message, result), exitCode: result.family === "cancelled-before-effects" ? 130 : 1 };
|
|
29
|
+
}
|
|
30
|
+
const facts = "facts" in cause ? cause.facts : undefined;
|
|
31
|
+
const error = new FlowError(cause.code, cause.message, {
|
|
32
|
+
...(facts ? { facts: facts } : {}),
|
|
33
|
+
});
|
|
34
|
+
const rendered = await handleCliError({
|
|
35
|
+
error: context.address ? attachAddressCarrier(error, context.address) : error,
|
|
36
|
+
cwd: context.cwd,
|
|
37
|
+
logLabel: "lifecycle",
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
...rendered,
|
|
41
|
+
payload: result,
|
|
42
|
+
isDomainFailure: true,
|
|
43
|
+
exitCode: result.family === "cancelled-before-effects" ? 130 : 1,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export async function renderLifecycleResult(work, render, context) {
|
|
47
|
+
const value = await work;
|
|
48
|
+
if (isCompleteLifecycleOutcome(value))
|
|
49
|
+
return render(value);
|
|
50
|
+
if (isSuccessfulDerivedCleanup(value)) {
|
|
51
|
+
// Derived cleanup is a successful verb result, but deliberately is not a
|
|
52
|
+
// committed lifecycle result. The verb renderer owns that exact payload.
|
|
53
|
+
return render(value);
|
|
54
|
+
}
|
|
55
|
+
return buildLifecycleOutcomeResponse(value, context);
|
|
56
|
+
}
|
package/build/cli/render/misc.js
CHANGED
|
@@ -3,6 +3,7 @@ import { RESPONSE_MARKERS } from "./response-style.js";
|
|
|
3
3
|
import { formatReview, HINTS_LIST_MAX_ITEMS, REVIEW_SECTION_TITLE, toReviewPayload, } from "./shared.js";
|
|
4
4
|
import { prependAddressReceipt, renderAddressCarrier } from "./address.js";
|
|
5
5
|
import { commissionSlug } from "../../core/ids.js";
|
|
6
|
+
import { renderAmendmentWarning } from "./amendment-warning.js";
|
|
6
7
|
export function buildErrorResponse(input) {
|
|
7
8
|
const shouldRaiseProtocolError = input.errorType === "runtime_error";
|
|
8
9
|
const text = input.errorCode === "PROJECTION_INCOMPATIBLE"
|
|
@@ -28,14 +29,17 @@ export function buildErrorResponse(input) {
|
|
|
28
29
|
}
|
|
29
30
|
function buildErrorText(input) {
|
|
30
31
|
const errorSection = buildSection("Error", input.message);
|
|
31
|
-
const
|
|
32
|
-
? buildSection("
|
|
32
|
+
const conflictSection = input.facts?.kind === "renew_conflict_scratch"
|
|
33
|
+
? buildSection("Conflict scratch", [
|
|
34
|
+
input.facts.scratchPath,
|
|
35
|
+
"",
|
|
33
36
|
"Conflicting paths:",
|
|
34
37
|
...input.facts.conflictPaths.map((filePath) => ` ${filePath}`),
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
"",
|
|
39
|
+
`Ledger: ${input.facts.observedLedgerHead}`,
|
|
40
|
+
`Delivery: ${input.facts.deliveryRef} at ${input.facts.oldHead}`,
|
|
41
|
+
`Target: ${input.facts.targetRef} at ${input.facts.newBase}`,
|
|
42
|
+
"Authoritative ledger and delivery refs were unchanged.",
|
|
39
43
|
].join("\n"))
|
|
40
44
|
: null;
|
|
41
45
|
const reviewSection = input.review ? buildSection(REVIEW_SECTION_TITLE, formatReview(input.review)) : null;
|
|
@@ -43,32 +47,22 @@ function buildErrorText(input) {
|
|
|
43
47
|
&& input.addressCarrier.binding.kind === "commission"
|
|
44
48
|
? input.addressCarrier
|
|
45
49
|
: undefined;
|
|
46
|
-
const
|
|
50
|
+
const renewAddress = commissionedCarrier
|
|
47
51
|
? `@${commissionedCarrier.place.display ?? commissionSlug(commissionedCarrier.binding.commissionId)}`
|
|
48
|
-
:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"Or restore the pre-renew delivery:",
|
|
57
|
-
`» keiyaku ${recoveryAddress} renew --abort`,
|
|
58
|
-
]
|
|
59
|
-
: input.facts.nextAction === "continue-or-abort" ? [
|
|
60
|
-
`» keiyaku ${recoveryAddress} renew --continue`,
|
|
61
|
-
`» keiyaku ${recoveryAddress} renew --abort`,
|
|
62
|
-
] : [`» keiyaku ${recoveryAddress} renew --abort`])
|
|
52
|
+
: undefined;
|
|
53
|
+
const nextActionSection = input.facts?.kind === "renew_conflict_scratch" && renewAddress
|
|
54
|
+
? buildSection("Next action", [
|
|
55
|
+
"Resolve files in the conflict scratch, then:",
|
|
56
|
+
`» keiyaku ${renewAddress} renew --continue`,
|
|
57
|
+
"Or discard the conflict scratch:",
|
|
58
|
+
`» keiyaku ${renewAddress} renew --abort`,
|
|
59
|
+
])
|
|
63
60
|
: null;
|
|
64
|
-
const hints = input.facts?.kind === "
|
|
61
|
+
const hints = input.facts?.kind === "renew_conflict_scratch"
|
|
65
62
|
? []
|
|
66
63
|
: formatHints(input.hints, { maxItems: HINTS_LIST_MAX_ITEMS, maxItemChars: FORMAT_LIST_MAX_ITEM_CHARS });
|
|
67
|
-
if (input.facts?.kind === "renew_conflict") {
|
|
68
|
-
hints.push("your old head survives:", `» git log ${input.facts.recoveryRef}`);
|
|
69
|
-
}
|
|
70
64
|
const hintsSection = buildSection("Hints", hints);
|
|
71
|
-
const body = assembleResponse(colorizeErrorStatus(`${RESPONSE_MARKERS.failure} Failed [${input.errorCode}]`), "Request could not be completed.", [errorSection,
|
|
65
|
+
const body = assembleResponse(colorizeErrorStatus(`${RESPONSE_MARKERS.failure} Failed [${input.errorCode}]`), "Request could not be completed.", [errorSection, conflictSection, nextActionSection, reviewSection, hintsSection].filter((section) => section !== null));
|
|
72
66
|
return input.addressCarrier ? `${renderAddressCarrier(input.addressCarrier)}\n${body}` : body;
|
|
73
67
|
}
|
|
74
68
|
export function buildHelpResponse(input) {
|
|
@@ -82,7 +76,9 @@ export function buildLogResponse(result) {
|
|
|
82
76
|
const { address: _address, ...resultData } = result;
|
|
83
77
|
const payload = resultData;
|
|
84
78
|
return prependAddressReceipt({
|
|
85
|
-
text: result.
|
|
79
|
+
text: result.amendmentWarning
|
|
80
|
+
? `${result.markdown.trimEnd()}\n\nWarning\n${renderAmendmentWarning(result.amendmentWarning)}\n`
|
|
81
|
+
: result.markdown,
|
|
86
82
|
payload: buildPayload(payload),
|
|
87
83
|
}, result.address);
|
|
88
84
|
}
|
|
@@ -8,6 +8,11 @@ import { prependAddressReceipt } from "./address.js";
|
|
|
8
8
|
export function renderPetitionRenewedConsequence(input) {
|
|
9
9
|
return `renewed onto ${input.newBase.slice(0, 8)} · ${input.sealed?.receipts.length ?? 0} receipts replayed`;
|
|
10
10
|
}
|
|
11
|
+
export function renderPetitionRetryConsequence(reason) {
|
|
12
|
+
return reason === "target-drift"
|
|
13
|
+
? "rejected petition after target drift · contract active"
|
|
14
|
+
: "rejected petition after delivery drift · contract active";
|
|
15
|
+
}
|
|
11
16
|
function formatPetitionSealSource(source) {
|
|
12
17
|
return source.arc === null
|
|
13
18
|
? `no open arc · fence ${source.fence}`
|