@astrosheep/keiyaku 4.6.4 → 4.6.6
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/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +43 -8
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +7 -8
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -3
- package/build/src/akuma/akuma-observe.d.ts +18 -15
- package/build/src/akuma/akuma-observe.js +75 -16
- package/build/src/akuma/akuma-wait.d.ts +4 -3
- package/build/src/akuma/akuma-wait.js +75 -53
- package/build/src/akuma/akuma.d.ts +6 -4
- package/build/src/akuma/akuma.js +4 -0
- package/build/src/akuma/call-initial-tell.d.ts +2 -2
- package/build/src/akuma/call-initial-tell.js +1 -1
- package/build/src/akuma/call-request.d.ts +2 -2
- package/build/src/akuma/heart/index.d.ts +7 -2
- package/build/src/akuma/heart/index.js +50 -5
- package/build/src/akuma/heart/tells.d.ts +33 -2
- package/build/src/akuma/heart/tells.js +24 -18
- package/build/src/akuma/heart/timeline.d.ts +23 -1
- package/build/src/akuma/heart/timeline.js +28 -21
- package/build/src/akuma/projection.d.ts +10 -10
- package/build/src/akuma/providers/pi/index.js +72 -39
- package/build/src/akuma/selection-observation.d.ts +20 -20
- package/build/src/akuma-body.js +1 -0
- package/build/src/alias/index.d.ts +0 -1
- package/build/src/alias/index.js +0 -4
- package/build/src/body/amend.d.ts +0 -4
- package/build/src/body/amend.js +0 -3
- package/build/src/body/region.d.ts +0 -1
- package/build/src/body/region.js +0 -3
- package/build/src/body/verification.d.ts +0 -1
- package/build/src/cli/commands/akuma-grammar.js +23 -66
- package/build/src/cli/commands/akuma.js +17 -30
- package/build/src/cli/commands/contract-grammar.d.ts +14 -1
- package/build/src/cli/commands/contract-grammar.js +54 -21
- package/build/src/cli/commands/contract-help.d.ts +9 -8
- package/build/src/cli/commands/contract-help.js +14 -7
- package/build/src/cli/commands/contract.js +57 -117
- package/build/src/cli/commands/install.d.ts +5 -5
- package/build/src/cli/commands/install.js +1 -4
- package/build/src/cli/commands/task-grammar.js +10 -66
- package/build/src/cli/commands/task.d.ts +0 -1
- package/build/src/cli/commands/task.js +34 -53
- package/build/src/cli/coordinates.d.ts +1 -2
- package/build/src/cli/coordinates.js +1 -4
- package/build/src/cli/parse.d.ts +2 -3
- package/build/src/cli/parse.js +24 -66
- package/build/src/cli/render/akuma.d.ts +3 -16
- package/build/src/cli/render/akuma.js +1 -13
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/contract.js +34 -32
- package/build/src/cli/render/kanshi-akuma.d.ts +8 -2
- package/build/src/cli/render/kanshi-akuma.js +14 -7
- package/build/src/cli/render/kanshi.d.ts +3 -1
- package/build/src/cli/render/kanshi.js +44 -32
- package/build/src/cli/render/receipt.js +6 -1
- package/build/src/cli/render/task.d.ts +1 -1
- package/build/src/cli/render/task.js +3 -27
- package/build/src/cli/render/terminal.d.ts +6 -2
- package/build/src/cli/render/terminal.js +8 -2
- package/build/src/cli/runtime.js +3 -16
- package/build/src/cli/scan.d.ts +26 -0
- package/build/src/cli/scan.js +82 -0
- package/build/src/cli/streams.d.ts +5 -0
- package/build/src/cli/streams.js +11 -0
- package/build/src/contract-worktree.js +38 -21
- package/build/src/core/facts/codec.d.ts +1 -2
- package/build/src/core/facts/codec.js +5 -11
- package/build/src/core/facts/types.d.ts +16 -2
- package/build/src/core/facts/types.js +15 -0
- package/build/src/core/verbs/abandon.js +3 -9
- package/build/src/core/verbs/amend.js +2 -9
- package/build/src/core/verbs/arc.js +6 -13
- package/build/src/core/verbs/attestation.js +2 -9
- package/build/src/core/verbs/bind.js +2 -9
- package/build/src/core/verbs/deliver.js +2 -9
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +2 -9
- package/build/src/core/verbs/reintegrate.d.ts +1 -1
- package/build/src/core/verbs/reintegrate.js +2 -9
- package/build/src/dispatch/index.d.ts +2 -2
- package/build/src/dispatch/index.js +33 -11
- package/build/src/git/hooks.d.ts +2 -4
- package/build/src/git/hooks.js +0 -12
- package/build/src/git/integration.d.ts +5 -3
- package/build/src/git/integration.js +36 -25
- package/build/src/git/nuke.js +4 -4
- package/build/src/git/observe.d.ts +4 -4
- package/build/src/git/observe.js +5 -5
- package/build/src/git/process.d.ts +1 -4
- package/build/src/git/process.js +1 -11
- package/build/src/git/read-observation.js +1 -1
- package/build/src/git/reconcile.d.ts +1 -1
- package/build/src/git/reconcile.js +15 -13
- package/build/src/git/repository.d.ts +2 -6
- package/build/src/git/repository.js +18 -31
- package/build/src/git/scratch.d.ts +6 -6
- package/build/src/git/scratch.js +110 -46
- package/build/src/git/target-placement.d.ts +5 -5
- package/build/src/git/target-placement.js +18 -33
- package/build/src/git/tender.d.ts +6 -2
- package/build/src/git/tender.js +19 -12
- package/build/src/git/terminal-reconcile.js +24 -13
- package/build/src/git/terminal-seal.d.ts +2 -5
- package/build/src/git/terminal-seal.js +5 -3
- package/build/src/git/workspace.d.ts +17 -13
- package/build/src/git/workspace.js +58 -41
- package/build/src/kanshi/index.d.ts +2 -2
- package/build/src/kanshi/index.js +1 -1
- package/build/src/kanshi/read.d.ts +8 -1
- package/build/src/kanshi/read.js +72 -7
- package/build/src/kanshi/report.d.ts +12 -0
- package/build/src/library/akuma-creation.d.ts +4 -4
- package/build/src/library/bind.d.ts +1 -63
- package/build/src/library/bind.js +3 -9
- package/build/src/library/contract-creation.js +2 -30
- package/build/src/library/contract-execution.d.ts +0 -1
- package/build/src/library/contract-execution.js +9 -34
- package/build/src/library/contract-operations.d.ts +5 -1
- package/build/src/library/contract-operations.js +7 -3
- package/build/src/library/contract-types.d.ts +1 -1
- package/build/src/library/delivery.d.ts +91 -93
- package/build/src/library/delivery.js +2 -1
- package/build/src/library/input.d.ts +0 -2
- package/build/src/library/input.js +0 -4
- package/build/src/library/invocation.d.ts +0 -1
- package/build/src/library/invocation.js +3 -25
- package/build/src/library/outcome.d.ts +651 -602
- package/build/src/library/outcome.js +4 -4
- package/build/src/library/reconcile.d.ts +6 -0
- package/build/src/library/reconcile.js +31 -1
- package/build/src/library/repo.d.ts +0 -1
- package/build/src/library/selection.d.ts +1 -10
- package/build/src/library/selection.js +14 -15
- package/build/src/protocol/abandon.d.ts +1 -1
- package/build/src/protocol/abandon.js +3 -10
- package/build/src/protocol/amend.js +2 -5
- package/build/src/protocol/arc.d.ts +1 -1
- package/build/src/protocol/arc.js +2 -9
- package/build/src/protocol/attempt.d.ts +3 -20
- package/build/src/protocol/attempt.js +6 -5
- package/build/src/protocol/audit.d.ts +1 -0
- package/build/src/protocol/audit.js +10 -11
- package/build/src/protocol/completion.d.ts +129 -55
- package/build/src/protocol/completion.js +62 -73
- package/build/src/protocol/deliver.d.ts +7 -5
- package/build/src/protocol/deliver.js +74 -44
- package/build/src/protocol/execution-observation.d.ts +2 -4
- package/build/src/protocol/execution-observation.js +3 -7
- package/build/src/protocol/intent.d.ts +1 -1
- package/build/src/protocol/intent.js +1 -0
- package/build/src/protocol/operations.d.ts +24 -12
- package/build/src/protocol/operations.js +36 -15
- package/build/src/protocol/placement.d.ts +2 -1
- package/build/src/protocol/placement.js +21 -5
- package/build/src/protocol/progress.d.ts +1 -1
- package/build/src/protocol/read/status.js +58 -41
- package/build/src/protocol/reintegrate.d.ts +1 -1
- package/build/src/protocol/reintegrate.js +10 -19
- package/build/src/protocol/review.d.ts +3 -28
- package/build/src/protocol/review.js +10 -37
- package/build/src/protocol/run.d.ts +19 -7
- package/build/src/protocol/run.js +19 -9
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/holder.d.ts +2 -4
- package/build/src/settlement/holder.js +3 -6
- package/build/src/task/board.d.ts +6 -0
- package/build/src/task/board.js +30 -1
- package/build/src/task/catalog.js +1 -4
- package/build/src/task/compose.d.ts +0 -1
- package/build/src/task/compose.js +0 -1
- package/build/src/task/context.d.ts +0 -1
- package/build/src/task/context.js +0 -3
- package/build/src/task/created-observation.d.ts +5 -1
- package/build/src/task/created-observation.js +12 -5
- package/build/src/task/index.d.ts +1 -1
- package/build/src/task/index.js +7 -6
- package/build/src/task/input.d.ts +0 -6
- package/build/src/task/input.js +2 -14
- package/build/src/task/mutation.d.ts +3 -4
- package/build/src/task/mutation.js +11 -39
- package/build/src/task/operations.d.ts +2 -7
- package/build/src/task/operations.js +37 -49
- package/build/src/task/query.d.ts +0 -1
- package/build/src/task/query.js +1 -4
- package/build/src/task/store.d.ts +0 -2
- package/build/src/task/store.js +27 -11
- package/build/src/verification/declaration.js +3 -2
- package/build/src/verification/execution.d.ts +3 -2
- package/build/src/verification/execution.js +10 -6
- package/build/src/workspace-place.d.ts +0 -1
- package/build/src/workspace-place.js +0 -11
- package/package.json +7 -3
|
@@ -38,22 +38,26 @@ function endpointFact(id, observed) {
|
|
|
38
38
|
// cannot name the reason is absent, while a complete read that established absence says so.
|
|
39
39
|
return observed === "missing" ? `${id} (missing)` : id;
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
/**
|
|
42
|
+
* One Akuma board section. The World board omits an empty section because its other
|
|
43
|
+
* sections already say what the World holds; a category board states that emptiness
|
|
44
|
+
* itself, since it is the whole answer.
|
|
45
|
+
*/
|
|
46
|
+
function renderAkumaBoard(section, observedAt, context, emptyRows) {
|
|
43
47
|
if (section.kind === "absent")
|
|
44
48
|
return ["AKUMA // absent"];
|
|
45
49
|
if (section.kind === "failed")
|
|
46
50
|
return ["AKUMA // unavailable", "", tone(`! ${safeText(section.failure.message)}`, "alert", context.color)];
|
|
47
51
|
const rows = section.value.rows;
|
|
48
52
|
if (rows.length === 0)
|
|
49
|
-
return
|
|
53
|
+
return emptyRows;
|
|
50
54
|
const rowLines = rows.map((row) => {
|
|
51
|
-
const statusTone = akumaStatusTone(row,
|
|
55
|
+
const statusTone = akumaStatusTone(row, observedAt);
|
|
52
56
|
const mark = statusTone === null ? akumaMark(row.life) : tone(akumaMark(row.life), statusTone, context.color);
|
|
53
57
|
const lifeAt = "lifeAt" in row ? row.lifeAt : null;
|
|
54
|
-
const lifeAge = formatAge(lifeAt,
|
|
58
|
+
const lifeAge = formatAge(lifeAt, observedAt);
|
|
55
59
|
const life = `${row.life} · ${lifeAge}`;
|
|
56
|
-
const activityAge = "lastActivityAt" in row && row.lastActivityAt !== null ? formatAge(row.lastActivityAt,
|
|
60
|
+
const activityAge = "lastActivityAt" in row && row.lastActivityAt !== null ? formatAge(row.lastActivityAt, observedAt) : null;
|
|
57
61
|
const activity = activityAge === null || activityAge === lifeAge ? [] : [`activity ${activityAge}`];
|
|
58
62
|
const key = row.life === "stranded" && "strandedReason" in row && row.strandedReason === "resume-unsupported"
|
|
59
63
|
? [life, ...activity, "resume unsupported"]
|
|
@@ -85,9 +89,12 @@ function renderAkuma(report, context) {
|
|
|
85
89
|
const header = `AKUMA // ${rows.length} recent`;
|
|
86
90
|
return [header, ...rendered.slice(1)];
|
|
87
91
|
}
|
|
92
|
+
function renderAkuma(report, context) {
|
|
93
|
+
return renderAkumaBoard(report.akuma, report.observedAt, context, []);
|
|
94
|
+
}
|
|
88
95
|
function formatAge(source, observedAt) {
|
|
89
96
|
if (source === null || source === undefined)
|
|
90
97
|
return "—";
|
|
91
98
|
return ageText(source, observedAt);
|
|
92
99
|
}
|
|
93
|
-
export { endpointFact, formatAge, NARROW_COLUMNS, renderAkuma };
|
|
100
|
+
export { endpointFact, formatAge, NARROW_COLUMNS, renderAkuma, renderAkumaBoard };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import type { KanshiReport } from "../../kanshi/index.js";
|
|
1
|
+
import type { KanshiCategoryReport, KanshiReport } from "../../kanshi/index.js";
|
|
2
2
|
import { type TextRenderContext } from "./terminal.js";
|
|
3
3
|
export declare function renderKanshiText(report: KanshiReport, context?: TextRenderContext, selection?: "world" | "contract"): string;
|
|
4
|
+
/** One category board: the section the selector asked for, and nothing it did not read. */
|
|
5
|
+
export declare function renderKanshiCategoryText(report: KanshiCategoryReport, context?: TextRenderContext): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { abbreviateGitIds, afterWording, progressStrip, displayGitId, gateFact, gitIdsInRow, lifecycleWord, mergeSummary, targetMovementFacts, verificationFact, } from "./contract-observation.js";
|
|
2
|
-
import { DEFAULT_CLI_COLUMNS, entityLines, elapsedMilliseconds, identityLine, plumbFacts, RECENT_TONE_MS, renderBoundedPayload, renderSectionBlock, safeText, tone, } from "./terminal.js";
|
|
3
|
-
import { endpointFact, formatAge, NARROW_COLUMNS, renderAkuma } from "./kanshi-akuma.js";
|
|
2
|
+
import { DEFAULT_CLI_COLUMNS, emptyCatalogue, entityLines, elapsedMilliseconds, identityLine, plumbFacts, RECENT_TONE_MS, renderBoundedPayload, renderSectionBlock, safeText, tone, } from "./terminal.js";
|
|
3
|
+
import { endpointFact, formatAge, NARROW_COLUMNS, renderAkuma, renderAkumaBoard } from "./kanshi-akuma.js";
|
|
4
4
|
import { contractMark, taskDispositionMark } from "./marks.js";
|
|
5
5
|
import { dispositionText } from "./task.js";
|
|
6
6
|
const REVIEW_ATTENTION_MS = 15 * 60 * 1_000;
|
|
@@ -26,13 +26,11 @@ function contractStatusTone(row, observedAt) {
|
|
|
26
26
|
const journalAge = elapsedMilliseconds(row.lastJournalAt, observedAt);
|
|
27
27
|
return journalAge !== null && journalAge <= RECENT_TONE_MS ? "recent" : null;
|
|
28
28
|
}
|
|
29
|
-
function
|
|
29
|
+
function contractAbbreviations(section) {
|
|
30
30
|
const ids = [];
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
ids.push(report.contracts.value.state);
|
|
35
|
-
report.contracts.value.rows.forEach((row) => ids.push(...gitIdsInRow(row)));
|
|
31
|
+
if (section.state !== null)
|
|
32
|
+
ids.push(section.state);
|
|
33
|
+
section.rows.forEach((row) => ids.push(...gitIdsInRow(row)));
|
|
36
34
|
return abbreviateGitIds(ids);
|
|
37
35
|
}
|
|
38
36
|
function workspaceState(row) {
|
|
@@ -54,10 +52,10 @@ function mergeFacts(row) {
|
|
|
54
52
|
const summary = mergeSummary(row.workspaceObservation);
|
|
55
53
|
return summary === undefined ? [] : [summary];
|
|
56
54
|
}
|
|
57
|
-
function linkedTask(
|
|
58
|
-
if (
|
|
55
|
+
function linkedTask(tasks, taskId) {
|
|
56
|
+
if (tasks.kind !== "present")
|
|
59
57
|
return `! ${taskId} · unavailable`;
|
|
60
|
-
const task =
|
|
58
|
+
const task = tasks.value.rows.find((candidate) => candidate.id === taskId);
|
|
61
59
|
return task === undefined
|
|
62
60
|
? `! ${taskId} · unavailable`
|
|
63
61
|
: `${taskDispositionMark(task.disposition)} ${task.id} · ${dispositionText(task.disposition)}`;
|
|
@@ -65,12 +63,12 @@ function linkedTask(report, taskId) {
|
|
|
65
63
|
function isTerminalAkuma(life) {
|
|
66
64
|
return life === "killed" || life === "stillborn";
|
|
67
65
|
}
|
|
68
|
-
function linkedAkumaSummary(row,
|
|
66
|
+
function linkedAkumaSummary(row, akuma) {
|
|
69
67
|
if (row.roster.length === 0)
|
|
70
68
|
return undefined;
|
|
71
|
-
if (
|
|
69
|
+
if (akuma === undefined || akuma.kind !== "present")
|
|
72
70
|
return "akuma unavailable";
|
|
73
|
-
const byId = new Map(
|
|
71
|
+
const byId = new Map(akuma.value.rows.map((akuma) => [akuma.id, akuma]));
|
|
74
72
|
const known = row.roster
|
|
75
73
|
.map((attached) => byId.get(attached.id))
|
|
76
74
|
.filter((akuma) => akuma !== undefined);
|
|
@@ -104,11 +102,11 @@ function payload(label, text, context) {
|
|
|
104
102
|
truncated: false,
|
|
105
103
|
});
|
|
106
104
|
}
|
|
107
|
-
function liveAlarms(row,
|
|
105
|
+
function liveAlarms(row, tasks) {
|
|
108
106
|
return [
|
|
109
107
|
...mergeFacts(row),
|
|
110
108
|
...(row.holder.kind === "unavailable" ? ["task unavailable"] : []),
|
|
111
|
-
...(row.holder.kind === "held" && linkedTask(
|
|
109
|
+
...(row.holder.kind === "held" && tasks !== undefined && linkedTask(tasks, row.holder.taskId).startsWith("!")
|
|
112
110
|
? ["task unavailable"]
|
|
113
111
|
: []),
|
|
114
112
|
...(row.issue === undefined ? [] : ["pending reconciliation"]),
|
|
@@ -135,14 +133,14 @@ function staleVerificationFacts(row) {
|
|
|
135
133
|
const fact = verificationFact(row.verification);
|
|
136
134
|
return fact === undefined ? [] : [fact];
|
|
137
135
|
}
|
|
138
|
-
function renderSelectedContractRow(row,
|
|
136
|
+
function renderSelectedContractRow(row, facts, context, abbreviations) {
|
|
139
137
|
const title = row.title ?? "title unavailable";
|
|
140
|
-
const statusTone = contractStatusTone(row,
|
|
138
|
+
const statusTone = contractStatusTone(row, facts.observedAt);
|
|
141
139
|
const lines = [
|
|
142
140
|
...entityLines({
|
|
143
141
|
mark: statusTone === null ? contractMark(row) : tone(contractMark(row), statusTone, context.color),
|
|
144
142
|
identity: row.id,
|
|
145
|
-
state: `${lifecycleWord(row.phase)} · ${formatAge(row.phaseAt,
|
|
143
|
+
state: `${lifecycleWord(row.phase)} · ${formatAge(row.phaseAt, facts.observedAt)}`,
|
|
146
144
|
title,
|
|
147
145
|
facts: [],
|
|
148
146
|
context,
|
|
@@ -170,51 +168,57 @@ function renderSelectedContractRow(row, report, context, abbreviations) {
|
|
|
170
168
|
}
|
|
171
169
|
if (deniedReview?.current.kind === "attested" && deniedReview.current.summary !== undefined)
|
|
172
170
|
lines.push(...payload("review ×", deniedReview.current.summary, context));
|
|
173
|
-
const akuma = linkedAkumaSummary(row,
|
|
171
|
+
const akuma = linkedAkumaSummary(row, facts.akuma);
|
|
174
172
|
if (akuma !== undefined)
|
|
175
173
|
lines.push(...semanticBlock("akuma", [akuma], context));
|
|
176
174
|
if (row.worktreePath !== null)
|
|
177
175
|
lines.push(...semanticBlock("worktree", [`worktree ${row.worktreePath}`], context));
|
|
178
|
-
lines.push(...semanticBlock("alarms", liveAlarms(row,
|
|
176
|
+
lines.push(...semanticBlock("alarms", liveAlarms(row, facts.tasks), context));
|
|
179
177
|
return lines;
|
|
180
178
|
}
|
|
181
|
-
function renderWorldContractRow(row,
|
|
179
|
+
function renderWorldContractRow(row, facts, context, abbreviations) {
|
|
182
180
|
const title = row.title ?? "title unavailable";
|
|
183
|
-
const abbreviations = gitAbbreviations(report);
|
|
184
181
|
const contractFacts = row.phase === "claimed" || row.phase === "abandoned"
|
|
185
182
|
? terminalFacts(row, context, abbreviations)
|
|
186
183
|
.filter((fact) => !fact.startsWith(" "))
|
|
187
184
|
.slice(0, 1)
|
|
188
185
|
: [
|
|
189
186
|
progressStrip(row),
|
|
190
|
-
...(linkedAkumaSummary(row,
|
|
191
|
-
...liveAlarms(row,
|
|
187
|
+
...(linkedAkumaSummary(row, facts.akuma) === undefined ? [] : [linkedAkumaSummary(row, facts.akuma)]),
|
|
188
|
+
...liveAlarms(row, facts.tasks),
|
|
192
189
|
];
|
|
193
|
-
const statusTone = contractStatusTone(row,
|
|
190
|
+
const statusTone = contractStatusTone(row, facts.observedAt);
|
|
194
191
|
return entityLines({
|
|
195
192
|
mark: statusTone === null ? contractMark(row) : tone(contractMark(row), statusTone, context.color),
|
|
196
193
|
identity: row.id,
|
|
197
|
-
state: formatAge(row.phaseAt,
|
|
194
|
+
state: formatAge(row.phaseAt, facts.observedAt),
|
|
198
195
|
title,
|
|
199
196
|
facts: contractFacts,
|
|
200
197
|
context,
|
|
201
198
|
});
|
|
202
199
|
}
|
|
203
|
-
|
|
204
|
-
|
|
200
|
+
/**
|
|
201
|
+
* One Contract board section. A category board states its own emptiness; the World
|
|
202
|
+
* board leaves an empty section out because the world is its surrounding answer.
|
|
203
|
+
*/
|
|
204
|
+
function renderContractBoard(section, facts, context, emptyRows) {
|
|
205
205
|
if (section.kind === "absent")
|
|
206
206
|
return ["CONTRACTS // absent"];
|
|
207
207
|
if (section.kind === "failed")
|
|
208
208
|
return ["CONTRACTS // unavailable", "", tone(`! ${safeText(section.failure.message)}`, "alert", context.color)];
|
|
209
209
|
if (section.value.rows.length === 0)
|
|
210
|
-
return
|
|
210
|
+
return emptyRows;
|
|
211
|
+
const abbreviations = contractAbbreviations(section.value);
|
|
211
212
|
const rendered = renderSectionBlock({
|
|
212
213
|
name: "CONTRACTS",
|
|
213
|
-
rows: section.value.rows.map((row) => renderWorldContractRow(row,
|
|
214
|
+
rows: section.value.rows.map((row) => renderWorldContractRow(row, facts, context, abbreviations)),
|
|
214
215
|
});
|
|
215
216
|
const header = "CONTRACTS // recent";
|
|
216
217
|
return [header, ...rendered.slice(1), ...(section.value.hasMore === true ? ["…"] : [])];
|
|
217
218
|
}
|
|
219
|
+
function renderContracts(report, context) {
|
|
220
|
+
return renderContractBoard(report.contracts, { observedAt: report.observedAt, akuma: report.akuma, tasks: report.tasks }, context, []);
|
|
221
|
+
}
|
|
218
222
|
function renderSelectedContract(report, context) {
|
|
219
223
|
const section = report.contracts;
|
|
220
224
|
if (section.kind === "absent")
|
|
@@ -224,7 +228,7 @@ function renderSelectedContract(report, context) {
|
|
|
224
228
|
const row = section.value.rows[0];
|
|
225
229
|
return row === undefined
|
|
226
230
|
? [" keiyaku absent"]
|
|
227
|
-
: renderSelectedContractRow(row, report, context,
|
|
231
|
+
: renderSelectedContractRow(row, { observedAt: report.observedAt, akuma: report.akuma, tasks: report.tasks }, context, contractAbbreviations(section.value));
|
|
228
232
|
}
|
|
229
233
|
function taskFailureFact(failure) {
|
|
230
234
|
return failure.coordinate === undefined ? failure.message : `${failure.coordinate} · failed ${failure.message}`;
|
|
@@ -277,3 +281,11 @@ export function renderKanshiText(report, context = { columns: DEFAULT_CLI_COLUMN
|
|
|
277
281
|
const blocks = [renderContracts(report, context), renderAkuma(report, context), renderTasks(report, context)].filter((block) => block.length > 0);
|
|
278
282
|
return blocks.length === 0 ? "○ world empty" : blocks.map((block) => block.join("\n")).join("\n\n");
|
|
279
283
|
}
|
|
284
|
+
/** One category board: the section the selector asked for, and nothing it did not read. */
|
|
285
|
+
export function renderKanshiCategoryText(report, context = { columns: DEFAULT_CLI_COLUMNS, color: false }) {
|
|
286
|
+
if (report.category === "akuma")
|
|
287
|
+
return renderAkumaBoard(report.akuma, report.observedAt, context, [emptyCatalogue("akuma")]).join("\n");
|
|
288
|
+
return renderContractBoard(report.contracts, { observedAt: report.observedAt }, context, [
|
|
289
|
+
emptyCatalogue("contracts"),
|
|
290
|
+
]).join("\n");
|
|
291
|
+
}
|
|
@@ -243,7 +243,12 @@ export function cleanupLines(cleanup, columns) {
|
|
|
243
243
|
}
|
|
244
244
|
export function leakLines(leak, columns) {
|
|
245
245
|
const lines = [];
|
|
246
|
-
|
|
246
|
+
if (leak.path === undefined) {
|
|
247
|
+
receiptRow(lines, " ", "verification scratch not retained", [], columns);
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
receiptRow(lines, " ", "verification scratch kept at", [{ text: leak.path, opaque: true }], columns);
|
|
251
|
+
}
|
|
247
252
|
receiptPayload(lines, "reason", leak.diagnostic);
|
|
248
253
|
return lines;
|
|
249
254
|
}
|
|
@@ -22,12 +22,12 @@ type TaskFailure = Extract<TaskMutationResult, {
|
|
|
22
22
|
/** Task dispositions and relation states are snake_case facts; people read them as words. */
|
|
23
23
|
export declare function dispositionText(word: string): string;
|
|
24
24
|
export declare function taskFrameHead(view: string, scope: string): string;
|
|
25
|
+
export declare function renderDoctor(report: TaskDoctorReport): string;
|
|
25
26
|
/** One addressed show selection rendered directly from its native answer. */
|
|
26
27
|
export declare function renderTaskShow(result: TaskShowResult, context?: TextRenderContext): string;
|
|
27
28
|
/** One list read rendered from its native answer and the leaf's presentation-only scope. */
|
|
28
29
|
export declare function renderTaskList(action: "ls" | "ready" | "blocked" | "query", scope: TaskListScope, result: TaskListOutcome, context?: TextRenderContext): string;
|
|
29
30
|
export declare function renderTaskTree(result: TaskDecompositionTree, context?: TextRenderContext): string;
|
|
30
|
-
export declare function renderTaskDoctor(result: TaskDoctorReport): string;
|
|
31
31
|
export declare function renderTaskContext(result: TaskContextResult, context?: TextRenderContext): string;
|
|
32
32
|
export declare function renderTaskCompose(result: TaskCompositionResult, context?: TextRenderContext): string;
|
|
33
33
|
/** One single-Task mutation answer; `verb` is the literal action the leaf invoked. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { taskMark } from "./marks.js";
|
|
2
2
|
import { outcomeLines, receiptPayload, receiptRow, refusalLines } from "./receipt.js";
|
|
3
|
-
import { DEFAULT_CLI_COLUMNS, displayColumns, emptyCatalogue, safeText } from "./terminal.js";
|
|
3
|
+
import { DEFAULT_CLI_COLUMNS, displayColumns, emptyCatalogue, renderTextBlock, safeText, } from "./terminal.js";
|
|
4
4
|
export { taskMark } from "./marks.js";
|
|
5
5
|
const DEFAULT_CONTEXT = { columns: DEFAULT_CLI_COLUMNS, color: false };
|
|
6
6
|
/** Task dispositions and relation states are snake_case facts; people read them as words. */
|
|
@@ -23,28 +23,7 @@ function entityLines(entity, columns, indent = "") {
|
|
|
23
23
|
const inline = `${scan} — ${title}`;
|
|
24
24
|
if (displayColumns(inline) <= columns)
|
|
25
25
|
return [inline];
|
|
26
|
-
return [scan, ...
|
|
27
|
-
}
|
|
28
|
-
/** Wrap `— <title>` as one unit: the dash never dangles alone at a line end. */
|
|
29
|
-
function dashTitleLines(title, indent, columns) {
|
|
30
|
-
const words = title
|
|
31
|
-
.trim()
|
|
32
|
-
.split(/\s+/u)
|
|
33
|
-
.filter((word) => word.length > 0);
|
|
34
|
-
const unit = words.length === 0 ? [`—`] : [`— ${words[0]}`, ...words.slice(1)];
|
|
35
|
-
const lines = [];
|
|
36
|
-
let current = indent;
|
|
37
|
-
for (const word of unit) {
|
|
38
|
-
const candidate = current === indent ? `${indent}${word}` : `${current} ${word}`;
|
|
39
|
-
if (current !== indent && displayColumns(candidate) > columns) {
|
|
40
|
-
lines.push(current);
|
|
41
|
-
current = `${indent}${word}`;
|
|
42
|
-
}
|
|
43
|
-
else
|
|
44
|
-
current = candidate;
|
|
45
|
-
}
|
|
46
|
-
lines.push(current);
|
|
47
|
-
return lines;
|
|
26
|
+
return [scan, ...renderTextBlock(title, `${indent} `, columns, "—")];
|
|
48
27
|
}
|
|
49
28
|
function stateEntity(task) {
|
|
50
29
|
return {
|
|
@@ -206,7 +185,7 @@ function doctorIssue(issue) {
|
|
|
206
185
|
return `! self-relation ${issue.taskId} ${issue.relation}`;
|
|
207
186
|
return `! cycle ${issue.relation} ${issue.tasks.join(" ")}`;
|
|
208
187
|
}
|
|
209
|
-
function renderDoctor(report) {
|
|
188
|
+
export function renderDoctor(report) {
|
|
210
189
|
if (report.issues.length === 0)
|
|
211
190
|
return "✓ doctor healthy";
|
|
212
191
|
const noun = report.issues.length === 1 ? "issue" : "issues";
|
|
@@ -306,9 +285,6 @@ export function renderTaskTree(result, context = DEFAULT_CONTEXT) {
|
|
|
306
285
|
? treeLines(result.value, context.columns).join("\n")
|
|
307
286
|
: renderFailure("tree", result, context.columns);
|
|
308
287
|
}
|
|
309
|
-
export function renderTaskDoctor(result) {
|
|
310
|
-
return renderDoctor(result);
|
|
311
|
-
}
|
|
312
288
|
export function renderTaskContext(result, context = DEFAULT_CONTEXT) {
|
|
313
289
|
if (result.kind !== "accepted")
|
|
314
290
|
return renderFailure("context", result, context.columns);
|
|
@@ -5,7 +5,7 @@ export type TextRenderContext = Readonly<{
|
|
|
5
5
|
columns: number;
|
|
6
6
|
color: boolean;
|
|
7
7
|
}>;
|
|
8
|
-
|
|
8
|
+
type GitShortStat = Readonly<{
|
|
9
9
|
filesChanged: number;
|
|
10
10
|
insertions: number;
|
|
11
11
|
deletions: number;
|
|
@@ -50,7 +50,11 @@ type CheckoutNotFollowable = Readonly<{
|
|
|
50
50
|
paths: readonly string[];
|
|
51
51
|
}>;
|
|
52
52
|
export declare function checkoutNotFollowableLines(refusal: CheckoutNotFollowable): readonly string[];
|
|
53
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Wrap `value` into the column budget under one indent. A `lead` such as an em dash joins the first
|
|
55
|
+
* word as one unit, so it never dangles alone at a line end.
|
|
56
|
+
*/
|
|
57
|
+
export declare function renderTextBlock(value: string, indent: string, columns: number, lead?: string): readonly string[];
|
|
54
58
|
export declare function renderOpaqueBlock(value: string, indent: string, columns: number): readonly string[];
|
|
55
59
|
export type SemanticTone = "dim" | "recent" | "attention" | "alert";
|
|
56
60
|
export declare const RECENT_TONE_MS: number;
|
|
@@ -234,13 +234,19 @@ export function checkoutNotFollowableLines(refusal) {
|
|
|
234
234
|
}
|
|
235
235
|
return lines;
|
|
236
236
|
}
|
|
237
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Wrap `value` into the column budget under one indent. A `lead` such as an em dash joins the first
|
|
239
|
+
* word as one unit, so it never dangles alone at a line end.
|
|
240
|
+
*/
|
|
241
|
+
export function renderTextBlock(value, indent, columns, lead) {
|
|
238
242
|
const words = safeText(value)
|
|
239
243
|
.trim()
|
|
240
244
|
.split(/\s+/u)
|
|
241
245
|
.filter((word) => word.length > 0);
|
|
242
246
|
if (words.length === 0)
|
|
243
|
-
return [indent];
|
|
247
|
+
return [lead === undefined ? indent : `${indent}${lead}`];
|
|
248
|
+
if (lead !== undefined)
|
|
249
|
+
words[0] = `${lead} ${words[0]}`;
|
|
244
250
|
const lines = [];
|
|
245
251
|
let current = indent;
|
|
246
252
|
for (const word of words) {
|
package/build/src/cli/runtime.js
CHANGED
|
@@ -15,7 +15,7 @@ import { createExecutionProgressRenderer } from "./render/execution-progress.js"
|
|
|
15
15
|
import { executionFailureLines } from "./render/receipt.js";
|
|
16
16
|
import { renderRefusal, renderStructuredRefusal } from "./render/refusal.js";
|
|
17
17
|
import { DEFAULT_CLI_COLUMNS, safeText } from "./render/terminal.js";
|
|
18
|
-
import { displayContext, writeJson, writeStderr, writeStdout } from "./streams.js";
|
|
18
|
+
import { displayContext, emit, writeJson, writeStderr, writeStdout } from "./streams.js";
|
|
19
19
|
function processStdin() {
|
|
20
20
|
return (async () => {
|
|
21
21
|
const chunks = [];
|
|
@@ -78,11 +78,7 @@ async function admitBindInput(command, invocation, runtime, processCwd) {
|
|
|
78
78
|
}
|
|
79
79
|
async function runInstall(command, environment) {
|
|
80
80
|
const result = await installHarnesses(command.harnesses, environment);
|
|
81
|
-
|
|
82
|
-
writeJson(result);
|
|
83
|
-
else
|
|
84
|
-
writeStdout(renderInstallText(result));
|
|
85
|
-
return installExitCode(result);
|
|
81
|
+
return emit(command.output, result, () => renderInstallText(result), installExitCode(result));
|
|
86
82
|
}
|
|
87
83
|
/** Projection of one native Akuma addressing/observation failure into its stated refusal body. */
|
|
88
84
|
export async function akumaFailureProjection(error, command) {
|
|
@@ -164,16 +160,7 @@ async function writeFailure(error, command) {
|
|
|
164
160
|
return akumaFailure.exitCode;
|
|
165
161
|
}
|
|
166
162
|
if (error instanceof AkumaArchetypeError && command.command === "call") {
|
|
167
|
-
|
|
168
|
-
writeJson({
|
|
169
|
-
kind: "refused",
|
|
170
|
-
diagnostic: "Akuma not found",
|
|
171
|
-
archetype: error.archetype,
|
|
172
|
-
available: "keiyaku ls aku/",
|
|
173
|
-
});
|
|
174
|
-
else
|
|
175
|
-
writeStdout(renderStructuredRefusal("call", `Akuma not found · ${safeText(error.archetype)}`, ["available keiyaku ls aku/"], usageGuideForCommand(command)));
|
|
176
|
-
return 1;
|
|
163
|
+
return emit(command.output, { kind: "refused", diagnostic: "Akuma not found", archetype: error.archetype, available: "keiyaku ls aku/" }, () => renderStructuredRefusal("call", `Akuma not found · ${safeText(error.archetype)}`, ["available keiyaku ls aku/"], usageGuideForCommand(command)), 1);
|
|
177
164
|
}
|
|
178
165
|
if (command.output === "json")
|
|
179
166
|
writeJson(encodeFailureWire(error));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** One surface's option table, named the way its refusal text names the surface. */
|
|
2
|
+
export type ScanFlagKind = "boolean" | "value" | "raw-value" | "repeat";
|
|
3
|
+
export type ScanSpec<Reader extends string = string> = Readonly<{
|
|
4
|
+
/** Names this surface in refusal text: `bind`, `call`, `task add`. */
|
|
5
|
+
subject: string;
|
|
6
|
+
flags: Readonly<Record<string, ScanFlagKind>>;
|
|
7
|
+
/** The reader that consumes `-` input; absent makes `-` invalid here. */
|
|
8
|
+
stdin?: Reader;
|
|
9
|
+
/** Refusal text for `-` on a surface that reads no stdin. */
|
|
10
|
+
stdinRefusal: string;
|
|
11
|
+
/** Option whose `-` value is stdin input, named as the reader it selects. */
|
|
12
|
+
stdinValue?: Reader;
|
|
13
|
+
/** Tokens this surface refuses everywhere, each with its own option-position refusal text. */
|
|
14
|
+
refused?: Readonly<Record<string, string>>;
|
|
15
|
+
}>;
|
|
16
|
+
export type ScannedArgs<Reader extends string = string> = Readonly<{
|
|
17
|
+
flags: Record<string, string | true | readonly string[]>;
|
|
18
|
+
positionals: readonly string[];
|
|
19
|
+
stdin?: Reader;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* One argument scan for every CLI grammar: `--name value` options, `--` positional-only mode,
|
|
23
|
+
* `-` stdin, and the surface's own refusal text. A refused token is refused in option position with
|
|
24
|
+
* its own text, and in value position as the missing-value refusal.
|
|
25
|
+
*/
|
|
26
|
+
export declare function scanArgs<Reader extends string = string>(argv: readonly string[], spec: ScanSpec<Reader>, fail: (message: string) => never): ScannedArgs<Reader>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { isBlankInput } from "./usage.js";
|
|
2
|
+
/** The one `-` reader for this invocation; a second `-` is the duplicate refusal. */
|
|
3
|
+
function selectStdin(spec, stdin, fail) {
|
|
4
|
+
if (spec.stdin === undefined)
|
|
5
|
+
fail(spec.stdinRefusal);
|
|
6
|
+
if (stdin !== undefined)
|
|
7
|
+
fail("stdin marker '-' may appear only once");
|
|
8
|
+
return spec.stdin;
|
|
9
|
+
}
|
|
10
|
+
/** A value token this surface refuses: `-`, or one of its own refused tokens. */
|
|
11
|
+
function refusedValue(kind, value, spec) {
|
|
12
|
+
if (kind === "raw-value")
|
|
13
|
+
return false;
|
|
14
|
+
return value === "-" || spec.refused?.[value] !== undefined;
|
|
15
|
+
}
|
|
16
|
+
/** The admitted value after `--name`: absent, dash-like, and blank values carry their own refusals. */
|
|
17
|
+
function optionValue(token, value, kind, spec, fail) {
|
|
18
|
+
if (value === undefined || value.startsWith("--") || refusedValue(kind, value, spec))
|
|
19
|
+
fail(`${token} requires a value`);
|
|
20
|
+
if (kind !== "raw-value" && isBlankInput(value))
|
|
21
|
+
fail(`${token} requires a nonblank value`);
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
/** One `--name` option: a boolean, a repeated value, or a single value. Returns its consumed tokens. */
|
|
25
|
+
function assignOption(option, spec, flags, fail) {
|
|
26
|
+
const { token, name, kind, value } = option;
|
|
27
|
+
if (flags[name] !== undefined && kind !== "repeat")
|
|
28
|
+
fail(`duplicate option: ${token}`);
|
|
29
|
+
if (kind === "boolean") {
|
|
30
|
+
flags[name] = true;
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
const admitted = optionValue(token, value, kind, spec, fail);
|
|
34
|
+
flags[name] = kind === "repeat" ? [...(Array.isArray(flags[name]) ? flags[name] : []), admitted] : admitted;
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* One argument scan for every CLI grammar: `--name value` options, `--` positional-only mode,
|
|
39
|
+
* `-` stdin, and the surface's own refusal text. A refused token is refused in option position with
|
|
40
|
+
* its own text, and in value position as the missing-value refusal.
|
|
41
|
+
*/
|
|
42
|
+
export function scanArgs(argv, spec, fail) {
|
|
43
|
+
const flags = {};
|
|
44
|
+
const positionals = [];
|
|
45
|
+
let stdin;
|
|
46
|
+
let positionalOnly = false;
|
|
47
|
+
for (let index = 1; index < argv.length; index += 1) {
|
|
48
|
+
const token = argv[index];
|
|
49
|
+
if (!positionalOnly && token === "--") {
|
|
50
|
+
positionalOnly = true;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!positionalOnly && spec.refused?.[token] !== undefined)
|
|
54
|
+
fail(spec.refused[token]);
|
|
55
|
+
if (!positionalOnly && token === "-") {
|
|
56
|
+
stdin = selectStdin(spec, stdin, fail);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (positionalOnly || !token.startsWith("--")) {
|
|
60
|
+
if (isBlankInput(token))
|
|
61
|
+
fail(`${spec.subject} requires a nonblank value`);
|
|
62
|
+
positionals.push(token);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const name = token.slice(2);
|
|
66
|
+
const kind = spec.flags[name];
|
|
67
|
+
if (kind === undefined)
|
|
68
|
+
fail(`option ${token} is not valid for ${spec.subject}`);
|
|
69
|
+
const reader = spec.stdinValue;
|
|
70
|
+
const value = kind === "boolean" ? undefined : argv[index + 1];
|
|
71
|
+
if (reader !== undefined && reader === name && value === "-") {
|
|
72
|
+
if (stdin !== undefined)
|
|
73
|
+
fail("stdin marker '-' may appear only once");
|
|
74
|
+
flags[name] = "";
|
|
75
|
+
stdin = reader;
|
|
76
|
+
index += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
index += assignOption({ token, name, kind, value }, spec, flags, fail);
|
|
80
|
+
}
|
|
81
|
+
return { flags, positionals, ...(stdin === undefined ? {} : { stdin }) };
|
|
82
|
+
}
|
|
@@ -9,3 +9,8 @@ export declare function displayContext(): TextRenderContext;
|
|
|
9
9
|
export declare function resultContext(): TextRenderContext;
|
|
10
10
|
/** One JSON product answer, verbatim from the native value. */
|
|
11
11
|
export declare function writeJson(value: unknown): void;
|
|
12
|
+
/**
|
|
13
|
+
* One product result: JSON writes the untouched native value, text writes the rendered projection,
|
|
14
|
+
* and the native exit classifier's verdict follows.
|
|
15
|
+
*/
|
|
16
|
+
export declare function emit<Result>(output: "text" | "json", result: Result, text: () => string, code: number): number;
|
package/build/src/cli/streams.js
CHANGED
|
@@ -30,3 +30,14 @@ export function resultContext() {
|
|
|
30
30
|
export function writeJson(value) {
|
|
31
31
|
writeStdout(JSON.stringify(value));
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* One product result: JSON writes the untouched native value, text writes the rendered projection,
|
|
35
|
+
* and the native exit classifier's verdict follows.
|
|
36
|
+
*/
|
|
37
|
+
export function emit(output, result, text, code) {
|
|
38
|
+
if (output === "json")
|
|
39
|
+
writeJson(result);
|
|
40
|
+
else
|
|
41
|
+
writeStdout(text());
|
|
42
|
+
return code;
|
|
43
|
+
}
|