@astrosheep/keiyaku 4.6.11 → 4.6.13

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.
Files changed (138) hide show
  1. package/build/plugins/claude/skills/keiyaku/SKILL.md +3 -1
  2. package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
  3. package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +3 -2
  4. package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +9 -8
  5. package/build/plugins/codex/skills/keiyaku/SKILL.md +3 -1
  6. package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
  7. package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +3 -2
  8. package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +9 -8
  9. package/build/plugins/opencode/skills/keiyaku/SKILL.md +3 -1
  10. package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
  11. package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +3 -2
  12. package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +9 -8
  13. package/build/skills/keiyaku/SKILL.md +3 -1
  14. package/build/skills/keiyaku-babysit/SKILL.md +1 -1
  15. package/build/skills/keiyaku-bind/SKILL.md +3 -2
  16. package/build/skills/keiyaku-workflow/SKILL.md +9 -8
  17. package/build/src/akuma/akuma-errors.d.ts +5 -0
  18. package/build/src/akuma/akuma-errors.js +9 -0
  19. package/build/src/akuma/akuma-owner.d.ts +14 -19
  20. package/build/src/akuma/akuma-owner.js +56 -54
  21. package/build/src/akuma/akuma-selection-execution.d.ts +5 -4
  22. package/build/src/akuma/akuma-selection-execution.js +59 -17
  23. package/build/src/akuma/akuma.d.ts +1 -2
  24. package/build/src/akuma/allowed.d.ts +2 -3
  25. package/build/src/akuma/allowed.js +1 -3
  26. package/build/src/akuma/body.js +17 -7
  27. package/build/src/akuma/call-initial-tell.d.ts +18 -0
  28. package/build/src/akuma/call-initial-tell.js +18 -0
  29. package/build/src/akuma/call-request.d.ts +20 -4
  30. package/build/src/akuma/heart/facts.d.ts +13 -0
  31. package/build/src/akuma/heart/facts.js +6 -0
  32. package/build/src/akuma/heart/index.d.ts +29 -14
  33. package/build/src/akuma/heart/index.js +75 -29
  34. package/build/src/akuma/heart/rows.d.ts +9 -2
  35. package/build/src/akuma/heart/rows.js +72 -11
  36. package/build/src/akuma/heart/storage.d.ts +2 -8
  37. package/build/src/akuma/heart/storage.js +13 -13
  38. package/build/src/akuma/heart/tells.d.ts +3 -1
  39. package/build/src/akuma/heart/tells.js +18 -2
  40. package/build/src/akuma/provider.d.ts +2 -4
  41. package/build/src/akuma/provider.js +29 -6
  42. package/build/src/akuma/providers/acp/core.js +23 -21
  43. package/build/src/akuma/providers/claude/index.js +0 -8
  44. package/build/src/akuma/providers/codex-app-server/index.js +9 -8
  45. package/build/src/akuma/providers/execution-environment.d.ts +1 -1
  46. package/build/src/akuma/providers/execution-environment.js +1 -0
  47. package/build/src/akuma/providers/opencode-sdk/events.js +111 -81
  48. package/build/src/akuma/providers/opencode-sdk/index.js +179 -150
  49. package/build/src/akuma/providers/opencode-sdk/native-http.js +7 -3
  50. package/build/src/akuma/providers/opencode-sdk/session.d.ts +5 -3
  51. package/build/src/akuma/providers/opencode-sdk/session.js +32 -27
  52. package/build/src/akuma/providers/paseo/index.js +0 -2
  53. package/build/src/akuma/providers/pi/index.js +23 -20
  54. package/build/src/akuma/selection-observation.d.ts +78 -9
  55. package/build/src/akuma/selection-owner-port.d.ts +2 -1
  56. package/build/src/akuma/selection-owner-port.js +6 -1
  57. package/build/src/akuma/selection-request.d.ts +1 -1
  58. package/build/src/akuma/selection-request.js +8 -3
  59. package/build/src/akuma/turn-drive.js +79 -48
  60. package/build/src/akuma-body.js +5 -3
  61. package/build/src/cli/commands/akuma-grammar.js +2 -2
  62. package/build/src/cli/commands/akuma.js +24 -16
  63. package/build/src/cli/commands/contract-grammar.d.ts +3 -7
  64. package/build/src/cli/commands/contract-grammar.js +12 -10
  65. package/build/src/cli/commands/contract-help.d.ts +3 -13
  66. package/build/src/cli/commands/contract-help.js +7 -16
  67. package/build/src/cli/commands/contract.js +19 -35
  68. package/build/src/cli/commands/debt.js +30 -29
  69. package/build/src/cli/parse.js +0 -1
  70. package/build/src/cli/render/akuma-activity.d.ts +36 -9
  71. package/build/src/cli/render/akuma-activity.js +142 -65
  72. package/build/src/cli/render/akuma.d.ts +6 -0
  73. package/build/src/cli/render/akuma.js +67 -24
  74. package/build/src/cli/render/catalog.js +0 -1
  75. package/build/src/cli/render/contract-observation.d.ts +16 -3
  76. package/build/src/cli/render/contract-observation.js +3 -0
  77. package/build/src/cli/render/contract.d.ts +2 -2
  78. package/build/src/cli/render/contract.js +4 -4
  79. package/build/src/cli/render/delivery-preview.d.ts +7 -0
  80. package/build/src/cli/render/{audit.js → delivery-preview.js} +29 -27
  81. package/build/src/cli/render/kanshi-akuma.d.ts +3 -1
  82. package/build/src/cli/render/kanshi-akuma.js +23 -8
  83. package/build/src/cli/render/kanshi.js +4 -1
  84. package/build/src/cli/render/receipt.js +3 -3
  85. package/build/src/cli/render/refusal.js +2 -2
  86. package/build/src/cli/render/terminal.d.ts +0 -1
  87. package/build/src/cli/render/terminal.js +1 -1
  88. package/build/src/cli/square-identity.d.ts +15 -0
  89. package/build/src/cli/square-identity.js +180 -0
  90. package/build/src/contract-worktree.js +1 -1
  91. package/build/src/core/verbs/placement.d.ts +2 -1
  92. package/build/src/core/verbs/placement.js +1 -1
  93. package/build/src/debt/context.d.ts +0 -5
  94. package/build/src/debt/context.js +32 -44
  95. package/build/src/git/process.d.ts +1 -0
  96. package/build/src/git/process.js +18 -1
  97. package/build/src/git/read-observation.js +2 -1
  98. package/build/src/git/scratch.d.ts +5 -1
  99. package/build/src/git/scratch.js +41 -12
  100. package/build/src/git/target-placement.d.ts +22 -4
  101. package/build/src/git/target-placement.js +44 -20
  102. package/build/src/index.d.ts +2 -2
  103. package/build/src/kanshi/read.js +187 -105
  104. package/build/src/kanshi/report.d.ts +5 -0
  105. package/build/src/library/address.d.ts +18 -4
  106. package/build/src/library/address.js +27 -6
  107. package/build/src/library/contract-address.d.ts +6 -0
  108. package/build/src/library/contract-address.js +12 -1
  109. package/build/src/library/contract-execution.d.ts +2 -2
  110. package/build/src/library/contract-execution.js +13 -17
  111. package/build/src/library/contract-operations.d.ts +59 -94
  112. package/build/src/library/contract-operations.js +23 -19
  113. package/build/src/library/contract-outcomes.d.ts +3 -3
  114. package/build/src/library/contract-settings.d.ts +1 -0
  115. package/build/src/library/contract-settings.js +1 -1
  116. package/build/src/library/invocation.d.ts +2 -2
  117. package/build/src/library/invocation.js +1 -1
  118. package/build/src/library/keiyaku.d.ts +2 -2
  119. package/build/src/library/keiyaku.js +2 -2
  120. package/build/src/library/outcome.d.ts +148 -268
  121. package/build/src/library/outcome.js +4 -8
  122. package/build/src/library/refusal.d.ts +2 -2
  123. package/build/src/library/refusal.js +2 -2
  124. package/build/src/plugin/runtime.js +15 -19
  125. package/build/src/protocol/{audit.d.ts → delivery-preview.d.ts} +62 -97
  126. package/build/src/protocol/delivery-preview.js +167 -0
  127. package/build/src/protocol/progress.d.ts +1 -1
  128. package/build/src/runtime/proc/run.js +22 -4
  129. package/build/src/runtime/proc/windows-launch.exe +0 -0
  130. package/build/src/verification/execution.d.ts +1 -1
  131. package/build/src/verification/execution.js +5 -3
  132. package/package.json +5 -2
  133. package/skills/keiyaku/SKILL.md +3 -1
  134. package/skills/keiyaku-babysit/SKILL.md +1 -1
  135. package/skills/keiyaku-bind/SKILL.md +3 -2
  136. package/skills/keiyaku-workflow/SKILL.md +9 -8
  137. package/build/src/cli/render/audit.d.ts +0 -7
  138. package/build/src/protocol/audit.js +0 -203
@@ -6,11 +6,13 @@ export const DEFAULT_CONTEXT = { columns: DEFAULT_CLI_COLUMNS, color: false };
6
6
  const TIME_WIDTH = 5;
7
7
  const VERB_WIDTH = 6;
8
8
  /**
9
- * The one blessed ruler: a run of U+2500 exactly as wide as the frame head's
10
- * widest line, marking the boundary between an observation frame and its content.
9
+ * The one blessed ruler: a run of U+2500 as wide as the frame head's widest line,
10
+ * never wider than the terminal, marking the boundary between an observation
11
+ * frame and its content.
11
12
  */
12
- export function frameRule(headLines) {
13
- const width = headLines.reduce((widest, line) => Math.max(widest, displayColumns(line)), 0);
13
+ export function frameRule(headLines, columns) {
14
+ const widest = headLines.reduce((widest, line) => Math.max(widest, displayColumns(line)), 0);
15
+ const width = columns === undefined ? widest : Math.min(widest, Math.max(0, columns));
14
16
  return "─".repeat(width);
15
17
  }
16
18
  /** Tool rows an activity view prints after each say or Tell checkpoint; the surplus folds in place. */
@@ -21,14 +23,35 @@ function identity(id, alias) {
21
23
  function associatedContractId(contract) {
22
24
  return contract.kind === "associated" ? contract.contractId : undefined;
23
25
  }
24
- export function associatedIdentity(id, alias, contract) {
25
- const contractId = contract === undefined ? undefined : associatedContractId(contract);
26
- return `${identity(id, alias)}${contractId === undefined ? "" : `\n└─ ${contractId}`}`;
26
+ /** The one human-fact separator of this family. */
27
+ const FACT_SEPARATOR = " · ";
28
+ /** A supporting fact of an action receipt or an observation panel is one indent deep. */
29
+ const SUBORDINATE_INDENT = " ";
30
+ /** Indent already-decided supporting lines one level, for every caller of this family. */
31
+ export function subordinateLines(lines) {
32
+ return lines.map((line) => `${SUBORDINATE_INDENT}${line}`);
27
33
  }
28
- export function snapshotHeading(id, alias, contract) {
34
+ /**
35
+ * The one observation identity line: complete Akuma identity, optional alias as a parenthetical
36
+ * supplement, and a known associated Contract inline behind the shared separator.
37
+ */
38
+ function panelIdentity(id, alias, contract) {
29
39
  const contractId = contract === undefined ? undefined : associatedContractId(contract);
30
- const head = [identity(id, alias), ...(contractId === undefined ? [] : [`└─ ${contractId}`])];
31
- return [...head, frameRule(head)];
40
+ return `${identity(id, alias)}${contractId === undefined ? "" : `${FACT_SEPARATOR}${contractId}`}`;
41
+ }
42
+ /**
43
+ * Identity and its static coordinates. The execution directory and any already-exposed effective
44
+ * actions belong above the content boundary; an absent coordinate is an absent line.
45
+ */
46
+ export function panelHead(id, alias, contract, context = []) {
47
+ return [panelIdentity(id, alias, contract), ...subordinateLines(context)];
48
+ }
49
+ /**
50
+ * One action receipt: the verdict and the complete subject on the first line, every supporting fact
51
+ * indented beneath it. Identity and evidence are never merged into one punctuation run.
52
+ */
53
+ export function actionReceipt(input) {
54
+ return [`${input.mark} ${input.verb} ${identity(input.id, input.alias)}`, ...subordinateLines(input.evidence ?? [])];
32
55
  }
33
56
  function contractFacts(contract) {
34
57
  return contract.kind === "failed" ? [`! contract failed ${safeText(contract.diagnostic)}`] : [];
@@ -44,7 +67,7 @@ function clock(at) {
44
67
  }
45
68
  function label(row, tool) {
46
69
  if (row.kind === "said")
47
- return "say";
70
+ return "";
48
71
  if (row.kind === "thought")
49
72
  return "think";
50
73
  if (row.kind === "note")
@@ -118,12 +141,14 @@ function verbColumn(verb) {
118
141
  */
119
142
  function actionCell(head, verb, columns) {
120
143
  const prefix = `${head} `;
144
+ if (verb === "")
145
+ return prefix;
121
146
  const available = Math.max(0, columns - displayColumns(prefix) - 1);
122
147
  const width = Math.min(verbColumn(verb), available);
123
148
  return `${prefix}${padToDisplay(truncateDisplayText(verb, width), width)} `;
124
149
  }
125
- function continuationPrefix() {
126
- return " ".repeat(TIME_WIDTH) + " │ " + " ".repeat(VERB_WIDTH) + " ";
150
+ function continuationPrefix(verb) {
151
+ return " ".repeat(TIME_WIDTH) + " │ " + (verb === "" ? "" : " ".repeat(VERB_WIDTH + 1));
127
152
  }
128
153
  function timelineMarker(text) {
129
154
  return `${" ".repeat(TIME_WIDTH)} ⋮ ${text}`;
@@ -142,10 +167,7 @@ function historyLayout() {
142
167
  return { ...compactLayout(), history: true };
143
168
  }
144
169
  function quotedBody(row) {
145
- return (row.kind === "said" ||
146
- row.kind === "thought" ||
147
- row.kind === "tell" ||
148
- (row.kind === "outcome" && row.outcome.kind === "answered"));
170
+ return row.kind === "thought" || row.kind === "tell" || (row.kind === "outcome" && row.outcome.kind === "answered");
149
171
  }
150
172
  function pathTail(path, maximum) {
151
173
  if (displayColumns(path) <= maximum)
@@ -235,7 +257,7 @@ function toolOverflowPreview(options, value, columns) {
235
257
  ];
236
258
  }
237
259
  function renderRow(row, context, options) {
238
- const { layout, first, continuation, tool, inFlightSay = false } = options;
260
+ const { layout, first, continuation, tool } = options;
239
261
  const value = rowText(row, tool);
240
262
  const overflow = toolOverflowPreview(options, value, context.columns);
241
263
  if (overflow !== undefined)
@@ -255,8 +277,7 @@ function renderRow(row, context, options) {
255
277
  : layout.history === true
256
278
  ? Number.MAX_SAFE_INTEGER
257
279
  : value.lines,
258
- quote: quotedBody(row) ? (layout.singleLine === true && row.kind !== "said" ? '"' : "“") : "",
259
- openQuote: row.kind === "said" && inFlightSay,
280
+ quote: quotedBody(row) ? (layout.singleLine === true ? '"' : "“") : "",
260
281
  truncated: "truncated" in row && row.truncated === true,
261
282
  });
262
283
  }
@@ -264,12 +285,12 @@ function renderTimelineRow(row, context, layout, time, options = {}) {
264
285
  const { inFlightSay = false, live = false, unsettled = false } = options;
265
286
  const tool = row.kind === "tool" ? toolRepr(row) : undefined;
266
287
  const glyph = inFlightSay ? (live ? "●" : "?") : unsettled ? "?" : mark(row, live);
288
+ const verb = label(row, tool);
267
289
  return renderRow(row, context, {
268
290
  layout,
269
- first: layout.head(time, glyph, label(row, tool), context.columns),
270
- continuation: layout.continuation(),
291
+ first: layout.head(time, glyph, verb, context.columns),
292
+ continuation: layout.continuation(verb),
271
293
  tool,
272
- inFlightSay,
273
294
  });
274
295
  }
275
296
  function groupedEntries(entries, context, layout = plainLayout(), options = {}) {
@@ -695,7 +716,9 @@ export function inputWaitStream(context, head, options) {
695
716
  throw new Error("input wait observed before admission");
696
717
  opened = true;
697
718
  const identity = head();
698
- lines.push(...snapshotHeading(identity.id, identity.alias, identity.contract));
719
+ const headLines = panelHead(identity.id, identity.alias, identity.contract, identity.cwd === undefined ? [] : [safeText(identity.cwd)]);
720
+ // A streamed panel always states an observed conclusion before it closes, so its rule opens here.
721
+ lines.push(...headLines, frameRule(headLines, context.columns));
699
722
  };
700
723
  const observe = (observation) => {
701
724
  const lines = [];
@@ -714,6 +737,8 @@ export function inputWaitStream(context, head, options) {
714
737
  const conclude = (result) => {
715
738
  const lines = [];
716
739
  open(lines, result.kind === "failed");
740
+ if (result.kind === "failed" && result.evidence !== undefined)
741
+ lines.push(...result.evidence);
717
742
  lines.push(...activity.flush());
718
743
  if (result.kind === "failed")
719
744
  lines.push(`! error ${safeText(result.diagnostic)}`);
@@ -724,7 +749,7 @@ export function inputWaitStream(context, head, options) {
724
749
  now: now(),
725
750
  ...(lastStatus === undefined ? {} : { status: lastStatus }),
726
751
  }));
727
- lines.push(...head().facts);
752
+ lines.push(...subordinateLines(head().facts));
728
753
  return `${lines.join("\n")}${options.answerSeparator === true ? "\n\n" : ""}`;
729
754
  };
730
755
  return { admitted: admit, observe, frame, flush, conclude, opened: () => opened };
@@ -736,11 +761,26 @@ export function callObservationStream(context, head, options = {}) {
736
761
  ...(options.now === undefined ? {} : { now: options.now }),
737
762
  });
738
763
  stream.admitted({ ...(options.admittedAt === undefined ? {} : { at: options.admittedAt }), rows: [] });
764
+ /** Tell rows already settled on the timeline, so a failed close never replays one. */
765
+ const settledTells = new Set();
739
766
  return {
740
767
  ...stream,
768
+ observe: (observation) => {
769
+ for (const row of observation.rows)
770
+ if (row.kind === "tell" && row.state === "told")
771
+ settledTells.add(row.sequence);
772
+ return stream.observe(observation);
773
+ },
741
774
  conclude: (observation) => {
742
- if (observation.kind === "failed")
743
- return stream.conclude({ kind: "failed", diagnostic: observation.failure.diagnostic });
775
+ if (observation.kind === "failed") {
776
+ const tell = observation.tell;
777
+ const evidence = tell === undefined || settledTells.has(tell.row.sequence) ? [] : [tellAdmissionRow(tell, context)];
778
+ return stream.conclude({
779
+ kind: "failed",
780
+ diagnostic: observation.failure.diagnostic,
781
+ ...(evidence.length === 0 ? {} : { evidence }),
782
+ });
783
+ }
744
784
  if (observation.kind !== "observed")
745
785
  return "";
746
786
  return stream.conclude({
@@ -785,15 +825,15 @@ function renderDebtContextLines(created, columns) {
785
825
  }
786
826
  function snapshotCore(view, context, options) {
787
827
  const activity = snapshotActivityLines(view.status.timeline, context);
788
- const facts = [
828
+ // Static coordinates belong above the content boundary; a dynamic diagnostic stays below it.
829
+ const contextFacts = [
789
830
  ...(options.showAllowed === true ? [`allowed ${view.status.allowed.join(", ") || "none"}`] : []),
790
- ...contractFacts(view.contract),
791
- ...(options.facts ?? []),
792
- ...(view.status.cwd === undefined ? [] : [`cwd ${safeText(view.status.cwd)}`]),
831
+ ...(view.status.cwd === undefined ? [] : [safeText(view.status.cwd)]),
793
832
  ];
833
+ const facts = [...contractFacts(view.contract), ...(options.facts ?? [])];
794
834
  return {
795
835
  activity,
796
- lines: [...snapshotHeading(view.status.id, options.alias, view.contract), ...activity],
836
+ head: panelHead(view.status.id, options.alias, view.contract, contextFacts),
797
837
  facts,
798
838
  };
799
839
  }
@@ -809,28 +849,36 @@ function snapshotConclusion(status) {
809
849
  }
810
850
  export function snapshotText(view, context, options = {}) {
811
851
  const core = snapshotCore(view, context, options);
812
- const debtContext = renderDebtContextLines(view.createdDebts, context.columns);
813
852
  const conclusion = snapshotConclusion(view.status);
853
+ const content = [...core.activity, ...(conclusion.length === 0 ? [] : [conclusion])];
814
854
  return [
815
- ...core.lines,
816
- ...(conclusion.length === 0 ? [] : [conclusion]),
817
- ...(debtContext.length > 0 ? ["", ...debtContext] : []),
818
- ...(view.status.timeline.reportedChanges.length > 0 || view.status.timeline.reportedChangesOmitted > 0 ? [""] : []),
819
- ...renderReportedChangeLines(view.status.timeline),
820
- ...(core.facts.length > 0 ? ["", ...core.facts] : []),
855
+ ...core.head,
856
+ ...(content.length === 0 ? [] : [frameRule(core.head, context.columns), ...content]),
857
+ ...subordinateLines([
858
+ ...renderReportedChangeLines(view.status.timeline),
859
+ ...renderDebtContextLines(view.createdDebts, context.columns - SUBORDINATE_INDENT.length),
860
+ ...core.facts,
861
+ ]),
821
862
  ].join("\n");
822
863
  }
823
864
  function killResultLabel(evidence) {
824
865
  if (evidence === "killed")
825
- return "✓ killed";
866
+ return { mark: "✓", verb: "killed", evidence: [] };
826
867
  if (evidence === "already-killed")
827
- return "✓ already killed";
868
+ return { mark: "✓", verb: "already killed", evidence: [] };
828
869
  if (evidence === "already-stopped")
829
- return "✓ already stopped";
830
- return `! not killed · ${evidence}`;
870
+ return { mark: "✓", verb: "already stopped", evidence: [] };
871
+ return { mark: "!", verb: "not killed", evidence: [evidence] };
831
872
  }
832
873
  export function killResultText(id, evidence, alias) {
833
- return [...snapshotHeading(id, alias, undefined), "", killResultLabel(evidence)].join("\n");
874
+ const label = killResultLabel(evidence);
875
+ return actionReceipt({
876
+ mark: label.mark,
877
+ verb: label.verb,
878
+ id,
879
+ ...(alias === undefined ? {} : { alias }),
880
+ evidence: label.evidence,
881
+ }).join("\n");
834
882
  }
835
883
  function answerBytes(answer, structured) {
836
884
  return !structured && typeof answer === "string" ? answer : JSON.stringify(answer);
@@ -884,32 +932,61 @@ export function historyText(result, presentation, context) {
884
932
  : `${result.history.omitted} earlier events · showing last ${result.history.rows.length}`),
885
933
  ]
886
934
  : [];
887
- return [...snapshotHeading(result.id, presentation.alias, result.contract), ...paging, ...rows].join("\n");
935
+ // History is an immutable timeline, so it takes the shared heading and content boundary and
936
+ // never gains a fabricated current-state conclusion or a live mark.
937
+ const content = [...paging, ...rows];
938
+ const head = panelHead(result.id, presentation.alias, result.contract);
939
+ return [...head, ...(content.length === 0 ? [] : [frameRule(head, context.columns), ...content])].join("\n");
940
+ }
941
+ /** One bounded preview of a submitted Tell, indented once beneath its verdict or evidence. */
942
+ export function tellPayloadLines(text, context) {
943
+ return renderBoundedPayload({
944
+ text,
945
+ first: SUBORDINATE_INDENT,
946
+ continuation: `${SUBORDINATE_INDENT}│ `,
947
+ columns: context.columns,
948
+ maxLines: 1,
949
+ quote: '"',
950
+ truncated: false,
951
+ });
888
952
  }
889
- export function tellText(result, alias, context, options = {}) {
890
- const wake = result.tell.wake;
891
- const target = identity(result.akuma, alias);
953
+ /** One admitted Tell as a timeline row inside a shared input panel; the panel owns the identity. */
954
+ export function tellAdmissionRow(tell, context) {
955
+ const wake = tell.wake;
892
956
  const glyph = wake.kind === "failed" ? "!" : wake.kind === "held" ? "⧗" : "✓";
893
957
  const verb = wake.kind === "failed" || wake.kind === "held" ? "tell" : "told";
894
- const row = groupedRows([result.tell.row], context, {
958
+ return groupedRows([tell.row], context, {
895
959
  ...plainLayout(),
896
960
  head: (time, _glyph, _verb, columns) => eventPrefix(glyph, verb, time, columns),
897
961
  singleLine: true,
898
962
  }).join("\n");
899
- const heading = options.identity === false ? [] : snapshotHeading(target, undefined, undefined);
900
- if (wake.kind === "failed") {
901
- const child = "child" in wake ? wake.child : undefined;
902
- const failure = `! tell delivery failed · ${safeText(wake.diagnostic)}${child === undefined ? "" : ` · log ${child.log.path} ${child.log.from}..${child.log.to}`}`;
903
- return [
904
- ...heading,
905
- row,
906
- ...renderBoundedTextBlock(failure, {
907
- first: "",
908
- continuation: " ",
909
- columns: context.columns,
910
- lines: Number.MAX_SAFE_INTEGER,
911
- }),
912
- ].join("\n");
913
- }
914
- return [...heading, row].join("\n");
963
+ }
964
+ /**
965
+ * One Tell action receipt: the delivery verdict and complete subject, then the submitted payload
966
+ * once. A held Tell keeps neutral vocabulary; a failed delivery keeps its own concrete diagnosis.
967
+ */
968
+ export function tellText(result, alias, context) {
969
+ const wake = result.tell.wake;
970
+ const mark = wake.kind === "failed" ? "!" : wake.kind === "held" ? "⧗" : "✓";
971
+ const verb = wake.kind === "failed" || wake.kind === "held" ? "tell" : "told";
972
+ const verdict = actionReceipt({
973
+ mark,
974
+ verb,
975
+ id: result.akuma,
976
+ ...(alias === undefined ? {} : { alias }),
977
+ });
978
+ if (wake.kind !== "failed")
979
+ return [...verdict, ...tellPayloadLines(result.tell.row.text, context)].join("\n");
980
+ const child = "child" in wake ? wake.child : undefined;
981
+ const failure = `! tell delivery failed · ${safeText(wake.diagnostic)}${child === undefined ? "" : ` · log ${child.log.path} ${child.log.from}..${child.log.to}`}`;
982
+ return [
983
+ ...verdict,
984
+ ...tellPayloadLines(result.tell.row.text, context),
985
+ ...subordinateLines(renderBoundedTextBlock(failure, {
986
+ first: "",
987
+ continuation: "",
988
+ columns: context.columns - SUBORDINATE_INDENT.length,
989
+ lines: Number.MAX_SAFE_INTEGER,
990
+ })),
991
+ ].join("\n");
915
992
  }
@@ -19,8 +19,14 @@ export declare function waitedTellProgress(result: AkumaAskResult, alias: string
19
19
  /** The shared identity frame for one admitted call input. */
20
20
  export declare function callObservationHead(input: Readonly<{
21
21
  akuma: string;
22
+ cwd?: string;
22
23
  }> & CallWaitHead): ObservedCallHead;
23
24
  export declare function renderCallText(result: CallResult, streamed: boolean, context: TextRenderContext): string;
25
+ /**
26
+ * The failure panel for an observing call whose stream never opened. It opens the same shared head
27
+ * over the failure's own evidence, including a Tell the invocation had already admitted.
28
+ */
29
+ export declare function renderFailedCallObservation(result: CallResult, context: TextRenderContext): string;
24
30
  export declare function renderForkText(receipt: ForkResult): string;
25
31
  export declare function renderKillText(result: AkumaKillResult, alias: string | undefined, context: TextRenderContext): string;
26
32
  export declare function callExitCode(result: CallResult): number;
@@ -1,4 +1,4 @@
1
- import { associatedIdentity, inputWaitStream, killResultText, snapshotHeading, tellText, } from "./akuma-activity.js";
1
+ import { actionReceipt, callObservationStream, inputWaitStream, killResultText, subordinateLines, tellAdmissionRow, tellPayloadLines, } from "./akuma-activity.js";
2
2
  import { safeText } from "./terminal.js";
3
3
  export function askProgressStream(akuma, alias, context) {
4
4
  let target = akuma;
@@ -13,7 +13,7 @@ export function askProgressStream(akuma, alias, context) {
13
13
  return stream.admitted({
14
14
  at: tell.row.at,
15
15
  sequence: tell.row.sequence,
16
- rows: [tellText({ akuma: target, tell }, alias, context, { identity: false })],
16
+ rows: [tellAdmissionRow(tell, context)],
17
17
  });
18
18
  },
19
19
  observe: (observation) => stream.observe(observation),
@@ -39,8 +39,8 @@ function dispatchLines(stage) {
39
39
  return (stage.seatClose ?? []).map((lag) => `dispatch lag ${lag.kind} ${safeText(lag.diagnostic)}`);
40
40
  }
41
41
  if (stage.failure.kind === "conflict")
42
- return [`dispatch failed conflict ${stage.failure.current.contractId}`];
43
- return [`dispatch failed ${stage.failure.kind} ${safeText(stage.failure.diagnostic)}`];
42
+ return [`! dispatch failed conflict ${stage.failure.current.contractId}`];
43
+ return [`! dispatch failed ${stage.failure.kind} ${safeText(stage.failure.diagnostic)}`];
44
44
  }
45
45
  /** The shared identity frame for one admitted call input. */
46
46
  export function callObservationHead(input) {
@@ -49,7 +49,7 @@ export function callObservationHead(input) {
49
49
  const facts = [
50
50
  ...dispatchLines(input.dispatch),
51
51
  ...(input.alias.kind === "failed"
52
- ? [`alias failed ${input.alias.failure.kind} ${safeText(input.alias.failure.diagnostic)}`]
52
+ ? [`! alias failed ${input.alias.failure.kind} ${safeText(input.alias.failure.diagnostic)}`]
53
53
  : []),
54
54
  ];
55
55
  return {
@@ -57,8 +57,17 @@ export function callObservationHead(input) {
57
57
  ...(alias === undefined ? {} : { alias }),
58
58
  contract: contractId === undefined ? { kind: "none" } : { kind: "associated", contractId },
59
59
  facts,
60
+ ...(input.cwd === undefined ? {} : { cwd: input.cwd }),
60
61
  };
61
62
  }
63
+ /** The admitted context a call action receipt can state without reading anything new. */
64
+ function callEvidence(result, head) {
65
+ return [
66
+ ...(head.contract.kind === "associated" ? [safeText(head.contract.contractId)] : []),
67
+ safeText(result.execution.cwd),
68
+ ...head.facts,
69
+ ];
70
+ }
62
71
  export function renderCallText(result, streamed, context) {
63
72
  if (streamed)
64
73
  return "";
@@ -66,23 +75,34 @@ export function renderCallText(result, streamed, context) {
66
75
  akuma: result.akuma,
67
76
  dispatch: result.dispatch,
68
77
  alias: result.alias,
78
+ cwd: result.execution.cwd,
69
79
  });
80
+ const receipt = (mark, extra = []) => actionReceipt({
81
+ mark,
82
+ verb: "called",
83
+ id: result.akuma,
84
+ ...(head.alias === undefined ? {} : { alias: head.alias }),
85
+ evidence: [...callEvidence(result, head), ...extra],
86
+ }).join("\n");
70
87
  if (result.observation.kind === "detached" || result.observation.kind === "born") {
71
- const branches = [
72
- ...(head.contract.kind === "associated" ? [safeText(head.contract.contractId)] : []),
73
- safeText(result.execution.cwd),
74
- ];
75
- return [
76
- associatedIdentity(result.akuma, head.alias),
77
- ...branches.map((fact, index) => `${index === branches.length - 1 ? "└─" : "├─"} ${fact}`),
78
- ...head.facts,
79
- ].join("\n");
88
+ // Birth and integration are admitted facts; a failed Dispatch/Alias stage marks the receipt
89
+ // honestly instead of letting a successful action line stand over it.
90
+ return receipt(result.dispatch.kind === "failed" || result.alias.kind === "failed" ? "!" : "✓");
80
91
  }
81
92
  if (result.observation.kind === "failed") {
93
+ // The child, its admitted Tell input, and its context survive a failed stage; a detached failure
94
+ // stays an action receipt rather than becoming an observation panel.
95
+ const admittedTell = result.observation.tell;
82
96
  return [
83
- ...snapshotHeading(head.id, head.alias, head.contract),
84
- ...head.facts,
85
- `! error ${safeText(result.observation.failure.diagnostic)}`,
97
+ ...actionReceipt({
98
+ mark: "!",
99
+ verb: "called",
100
+ id: result.akuma,
101
+ ...(head.alias === undefined ? {} : { alias: head.alias }),
102
+ evidence: callEvidence(result, head),
103
+ }),
104
+ ...(admittedTell === undefined ? [] : tellPayloadLines(admittedTell.row.text, context)),
105
+ ...subordinateLines([`! error ${safeText(result.observation.failure.diagnostic)}`]),
86
106
  ].join("\n");
87
107
  }
88
108
  const inputObservation = result.observation;
@@ -94,20 +114,43 @@ export function renderCallText(result, streamed, context) {
94
114
  ...(inputObservation.completedAt === undefined ? {} : { completedAt: inputObservation.completedAt }),
95
115
  });
96
116
  }
117
+ /**
118
+ * The failure panel for an observing call whose stream never opened. It opens the same shared head
119
+ * over the failure's own evidence, including a Tell the invocation had already admitted.
120
+ */
121
+ export function renderFailedCallObservation(result, context) {
122
+ const failure = callObservationStream(context, callObservationHead({
123
+ akuma: result.akuma,
124
+ dispatch: result.dispatch,
125
+ alias: result.alias,
126
+ cwd: result.execution.cwd,
127
+ }));
128
+ return failure.conclude(result.observation);
129
+ }
97
130
  export function renderForkText(receipt) {
98
131
  if (receipt.kind !== "forked") {
99
- if (receipt.kind === "unknown-history")
100
- return `${receipt.at} has no matching retained answered turn`;
101
- if (receipt.kind === "provider-cannot-fork")
102
- return `${receipt.provider} cannot fork`;
103
- return receipt.diagnostic;
132
+ const reason = receipt.kind === "unknown-history"
133
+ ? `${receipt.at} has no matching retained answered turn`
134
+ : receipt.kind === "provider-cannot-fork"
135
+ ? `${receipt.provider} cannot fork`
136
+ : receipt.diagnostic;
137
+ return actionReceipt({ mark: "!", verb: "fork", id: receipt.parent, evidence: [reason] }).join("\n");
104
138
  }
105
139
  const contractId = receipt.dispatch.kind === "dispatched" ? receipt.dispatch.dispatch.contractId : undefined;
106
- return associatedIdentity(receipt.child, undefined, contractId === undefined ? { kind: "none" } : { kind: "associated", contractId });
140
+ return actionReceipt({
141
+ mark: receipt.dispatch.kind === "failed" ? "!" : "✓",
142
+ verb: "forked",
143
+ id: receipt.child,
144
+ evidence: [
145
+ `from ${receipt.parent}`,
146
+ ...(contractId === undefined ? [] : [safeText(contractId)]),
147
+ ...dispatchLines(receipt.dispatch),
148
+ ],
149
+ }).join("\n");
107
150
  }
108
151
  export function renderKillText(result, alias, context) {
109
152
  void context;
110
- return result.results.map((member) => killResultText(member.id, member.evidence, alias)).join("\n\n");
153
+ return result.results.map((member) => killResultText(member.id, member.evidence, alias)).join("\n");
111
154
  }
112
155
  export function callExitCode(result) {
113
156
  if (result.dispatch.kind === "failed" || result.alias.kind === "failed" || result.observation.kind === "failed")
@@ -64,7 +64,6 @@ export function renderContractCatalogue(list) {
64
64
  columns: 100,
65
65
  maxLines: 3,
66
66
  quote: "“",
67
- openQuote: false,
68
67
  truncated: false,
69
68
  })),
70
69
  ];
@@ -1,5 +1,17 @@
1
- import type { ContractAfterEdge, ContractGateReport, ContractRow, ContractWorkspaceObservation } from "../../index.js";
1
+ import type { ContractAfterEdge, ContractRow, ContractWorkspaceObservation } from "../../index.js";
2
+ type GateDisplayReport = Readonly<{
3
+ gate: string;
4
+ current: Readonly<{
5
+ kind: "missing";
6
+ } | {
7
+ kind: "stale";
8
+ } | {
9
+ kind: "attested";
10
+ verdict: "satisfied" | "unsatisfied";
11
+ }>;
12
+ }>;
2
13
  export declare function shortGitId(value: string): string;
14
+ export declare function contractOperationName(operation: string): string;
3
15
  export declare function gateDisplayName(gate: string): string;
4
16
  /**
5
17
  * The one display vocabulary for a Contract's lifecycle phase. The journal fact kind stays `claimed`; every
@@ -8,8 +20,8 @@ export declare function gateDisplayName(gate: string): string;
8
20
  export declare function lifecycleWord(phase: ContractRow["phase"]): string;
9
21
  /** The one readable projection of delivery and current-candidate gate progress. */
10
22
  export declare function progressStrip(row: Pick<ContractRow, "delivery" | "gates">): string;
11
- export declare function gateGlyph(report: ContractGateReport): string;
12
- export declare function gateFact(report: ContractGateReport): string;
23
+ export declare function gateGlyph(report: GateDisplayReport): string;
24
+ export declare function gateFact(report: GateDisplayReport): string;
13
25
  export declare function verificationFact(status: ContractRow["verification"]): string | undefined;
14
26
  export declare function afterWording(edge: ContractAfterEdge): string;
15
27
  export declare function mergeSummary(observation: ContractWorkspaceObservation): string | undefined;
@@ -18,3 +30,4 @@ export declare function gitIdsInRow(row: ContractRow): readonly string[];
18
30
  export declare function displayGitId(value: string, abbreviations: ReadonlyMap<string, string>): string;
19
31
  /** Render the pinned delivery target and the same-epoch observed target head. */
20
32
  export declare function targetMovementFacts(row: ContractRow, abbreviations: ReadonlyMap<string, string>): readonly string[];
33
+ export {};
@@ -2,6 +2,9 @@ const GIT_OBJECT_ID = /^[0-9a-f]{40}$/iu;
2
2
  export function shortGitId(value) {
3
3
  return GIT_OBJECT_ID.test(value) ? value.slice(0, 7) : value;
4
4
  }
5
+ export function contractOperationName(operation) {
6
+ return operation === "deliver-preview" ? "deliver --dry-run" : operation;
7
+ }
5
8
  export function gateDisplayName(gate) {
6
9
  if (gate === "reviewed")
7
10
  return "review";
@@ -1,6 +1,6 @@
1
- import type { AbandonOutcome, AmendOutcome, ArcOutcome, AuditOutcome, BindOutcome, DeliverOutcome, ReviewOutcome } from "../../index.js";
1
+ import type { AbandonOutcome, AmendOutcome, ArcOutcome, DeliveryPreviewOutcome, BindOutcome, DeliverOutcome, ReviewOutcome } from "../../index.js";
2
2
  import { type TextRenderContext } from "./terminal.js";
3
- export type ContractOutcome = BindOutcome | AmendOutcome | DeliverOutcome | ReviewOutcome | AuditOutcome | ArcOutcome | AbandonOutcome;
3
+ export type ContractOutcome = BindOutcome | AmendOutcome | DeliverOutcome | ReviewOutcome | DeliveryPreviewOutcome | ArcOutcome | AbandonOutcome;
4
4
  export type AcceptedContractOutcome = Extract<ContractOutcome, {
5
5
  kind: "accepted";
6
6
  }>;
@@ -1,5 +1,5 @@
1
1
  import { effectCleanup, effectExecutionStops, effectLags, effectRecoverySnapshot, effectRetainedCheckouts, effectRetainedWorktrees, effectRetiredWorktrees, effectSettlementLags, } from "./effects.js";
2
- import { renderAcceptedAudit } from "./audit.js";
2
+ import { renderDeliveryPreview } from "./delivery-preview.js";
3
3
  import { appendHookPayload, executionCleanupLines, executionStopLines, gatesAwaitLines, hookFailureSummary, outcomeLines, receiptPayload, receiptRow, stopLines, titleLines, } from "./receipt.js";
4
4
  import { abbreviateGitIds, displayGitId, lifecycleWord } from "./contract-observation.js";
5
5
  import { renderDiffstat } from "./akuma-tool.js";
@@ -216,7 +216,7 @@ function landedChangesLines(scope, columns) {
216
216
  * identically: one git-shaped target movement row, naming the reference it advanced, then the final lifecycle
217
217
  * state. Satisfied Verification adds one fact row naming the integrated result; placement made that commit the
218
218
  * reference's new head, so the movement and integrated-result rows share one sha. The verdict names reuse in the
219
- * audit surface's vocabulary and carries no qualifier when this command executed declarations. A completion
219
+ * standing-evidence vocabulary and carries no qualifier when this command executed declarations. A completion
220
220
  * without an advanced reference states no movement. Journal ULIDs stay in JSON and `history`, never in ordinary
221
221
  * receipt text.
222
222
  */
@@ -403,8 +403,8 @@ function renderAcceptedAbandon(result, columns) {
403
403
  export function renderAccepted(result, context) {
404
404
  const columns = context?.columns ?? DEFAULT_CLI_COLUMNS;
405
405
  switch (result.operation) {
406
- case "audit":
407
- return renderAcceptedAudit(result, context);
406
+ case "deliver-preview":
407
+ return renderDeliveryPreview(result, context);
408
408
  case "bind":
409
409
  return renderAcceptedBind(result, columns, context?.color === true);
410
410
  case "amend":
@@ -0,0 +1,7 @@
1
+ import type { DeliveryPreviewOutcome } from "../../index.js";
2
+ import { type TextRenderContext } from "./terminal.js";
3
+ type AcceptedDeliveryPreview = Extract<DeliveryPreviewOutcome, {
4
+ kind: "accepted";
5
+ }>;
6
+ export declare function renderDeliveryPreview(result: AcceptedDeliveryPreview, context?: TextRenderContext): string;
7
+ export {};