@astrosheep/keiyaku 4.6.10 → 4.6.12

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 (135) 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 +13 -17
  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 +35 -8
  71. package/build/src/cli/render/akuma-activity.js +132 -52
  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/contract-observation.d.ts +16 -3
  75. package/build/src/cli/render/contract-observation.js +3 -0
  76. package/build/src/cli/render/contract.d.ts +2 -2
  77. package/build/src/cli/render/contract.js +4 -4
  78. package/build/src/cli/render/delivery-preview.d.ts +7 -0
  79. package/build/src/cli/render/{audit.js → delivery-preview.js} +29 -27
  80. package/build/src/cli/render/kanshi-akuma.d.ts +3 -1
  81. package/build/src/cli/render/kanshi-akuma.js +23 -8
  82. package/build/src/cli/render/kanshi.js +4 -0
  83. package/build/src/cli/render/receipt.js +3 -3
  84. package/build/src/cli/render/refusal.js +2 -2
  85. package/build/src/cli/square-identity.d.ts +15 -0
  86. package/build/src/cli/square-identity.js +180 -0
  87. package/build/src/contract-worktree.js +1 -1
  88. package/build/src/core/verbs/placement.d.ts +2 -1
  89. package/build/src/core/verbs/placement.js +1 -1
  90. package/build/src/debt/context.d.ts +0 -5
  91. package/build/src/debt/context.js +32 -44
  92. package/build/src/git/process.d.ts +1 -0
  93. package/build/src/git/process.js +18 -1
  94. package/build/src/git/read-observation.js +2 -1
  95. package/build/src/git/scratch.d.ts +5 -1
  96. package/build/src/git/scratch.js +41 -12
  97. package/build/src/git/target-placement.d.ts +22 -4
  98. package/build/src/git/target-placement.js +44 -20
  99. package/build/src/index.d.ts +2 -2
  100. package/build/src/kanshi/read.js +187 -105
  101. package/build/src/kanshi/report.d.ts +5 -0
  102. package/build/src/library/address.d.ts +18 -4
  103. package/build/src/library/address.js +27 -6
  104. package/build/src/library/contract-address.d.ts +6 -0
  105. package/build/src/library/contract-address.js +12 -1
  106. package/build/src/library/contract-execution.d.ts +2 -2
  107. package/build/src/library/contract-execution.js +13 -17
  108. package/build/src/library/contract-operations.d.ts +59 -94
  109. package/build/src/library/contract-operations.js +23 -19
  110. package/build/src/library/contract-outcomes.d.ts +3 -3
  111. package/build/src/library/contract-settings.d.ts +1 -0
  112. package/build/src/library/contract-settings.js +1 -1
  113. package/build/src/library/invocation.d.ts +2 -2
  114. package/build/src/library/invocation.js +1 -1
  115. package/build/src/library/keiyaku.d.ts +2 -2
  116. package/build/src/library/keiyaku.js +2 -2
  117. package/build/src/library/outcome.d.ts +148 -268
  118. package/build/src/library/outcome.js +4 -8
  119. package/build/src/library/refusal.d.ts +2 -2
  120. package/build/src/library/refusal.js +2 -2
  121. package/build/src/plugin/runtime.js +16 -21
  122. package/build/src/protocol/{audit.d.ts → delivery-preview.d.ts} +62 -97
  123. package/build/src/protocol/delivery-preview.js +167 -0
  124. package/build/src/protocol/progress.d.ts +1 -1
  125. package/build/src/runtime/proc/run.js +22 -4
  126. package/build/src/runtime/proc/windows-launch.exe +0 -0
  127. package/build/src/verification/execution.d.ts +1 -1
  128. package/build/src/verification/execution.js +5 -3
  129. package/package.json +4 -2
  130. package/skills/keiyaku/SKILL.md +3 -1
  131. package/skills/keiyaku-babysit/SKILL.md +1 -1
  132. package/skills/keiyaku-bind/SKILL.md +3 -2
  133. package/skills/keiyaku-workflow/SKILL.md +9 -8
  134. package/build/src/cli/render/audit.d.ts +0 -7
  135. 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)}`] : [];
@@ -695,7 +718,9 @@ export function inputWaitStream(context, head, options) {
695
718
  throw new Error("input wait observed before admission");
696
719
  opened = true;
697
720
  const identity = head();
698
- lines.push(...snapshotHeading(identity.id, identity.alias, identity.contract));
721
+ const headLines = panelHead(identity.id, identity.alias, identity.contract, identity.cwd === undefined ? [] : [safeText(identity.cwd)]);
722
+ // A streamed panel always states an observed conclusion before it closes, so its rule opens here.
723
+ lines.push(...headLines, frameRule(headLines, context.columns));
699
724
  };
700
725
  const observe = (observation) => {
701
726
  const lines = [];
@@ -714,6 +739,8 @@ export function inputWaitStream(context, head, options) {
714
739
  const conclude = (result) => {
715
740
  const lines = [];
716
741
  open(lines, result.kind === "failed");
742
+ if (result.kind === "failed" && result.evidence !== undefined)
743
+ lines.push(...result.evidence);
717
744
  lines.push(...activity.flush());
718
745
  if (result.kind === "failed")
719
746
  lines.push(`! error ${safeText(result.diagnostic)}`);
@@ -724,7 +751,7 @@ export function inputWaitStream(context, head, options) {
724
751
  now: now(),
725
752
  ...(lastStatus === undefined ? {} : { status: lastStatus }),
726
753
  }));
727
- lines.push(...head().facts);
754
+ lines.push(...subordinateLines(head().facts));
728
755
  return `${lines.join("\n")}${options.answerSeparator === true ? "\n\n" : ""}`;
729
756
  };
730
757
  return { admitted: admit, observe, frame, flush, conclude, opened: () => opened };
@@ -736,11 +763,26 @@ export function callObservationStream(context, head, options = {}) {
736
763
  ...(options.now === undefined ? {} : { now: options.now }),
737
764
  });
738
765
  stream.admitted({ ...(options.admittedAt === undefined ? {} : { at: options.admittedAt }), rows: [] });
766
+ /** Tell rows already settled on the timeline, so a failed close never replays one. */
767
+ const settledTells = new Set();
739
768
  return {
740
769
  ...stream,
770
+ observe: (observation) => {
771
+ for (const row of observation.rows)
772
+ if (row.kind === "tell" && row.state === "told")
773
+ settledTells.add(row.sequence);
774
+ return stream.observe(observation);
775
+ },
741
776
  conclude: (observation) => {
742
- if (observation.kind === "failed")
743
- return stream.conclude({ kind: "failed", diagnostic: observation.failure.diagnostic });
777
+ if (observation.kind === "failed") {
778
+ const tell = observation.tell;
779
+ const evidence = tell === undefined || settledTells.has(tell.row.sequence) ? [] : [tellAdmissionRow(tell, context)];
780
+ return stream.conclude({
781
+ kind: "failed",
782
+ diagnostic: observation.failure.diagnostic,
783
+ ...(evidence.length === 0 ? {} : { evidence }),
784
+ });
785
+ }
744
786
  if (observation.kind !== "observed")
745
787
  return "";
746
788
  return stream.conclude({
@@ -785,15 +827,15 @@ function renderDebtContextLines(created, columns) {
785
827
  }
786
828
  function snapshotCore(view, context, options) {
787
829
  const activity = snapshotActivityLines(view.status.timeline, context);
788
- const facts = [
830
+ // Static coordinates belong above the content boundary; a dynamic diagnostic stays below it.
831
+ const contextFacts = [
789
832
  ...(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)}`]),
833
+ ...(view.status.cwd === undefined ? [] : [safeText(view.status.cwd)]),
793
834
  ];
835
+ const facts = [...contractFacts(view.contract), ...(options.facts ?? [])];
794
836
  return {
795
837
  activity,
796
- lines: [...snapshotHeading(view.status.id, options.alias, view.contract), ...activity],
838
+ head: panelHead(view.status.id, options.alias, view.contract, contextFacts),
797
839
  facts,
798
840
  };
799
841
  }
@@ -809,28 +851,36 @@ function snapshotConclusion(status) {
809
851
  }
810
852
  export function snapshotText(view, context, options = {}) {
811
853
  const core = snapshotCore(view, context, options);
812
- const debtContext = renderDebtContextLines(view.createdDebts, context.columns);
813
854
  const conclusion = snapshotConclusion(view.status);
855
+ const content = [...core.activity, ...(conclusion.length === 0 ? [] : [conclusion])];
814
856
  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] : []),
857
+ ...core.head,
858
+ ...(content.length === 0 ? [] : [frameRule(core.head, context.columns), ...content]),
859
+ ...subordinateLines([
860
+ ...renderReportedChangeLines(view.status.timeline),
861
+ ...renderDebtContextLines(view.createdDebts, context.columns - SUBORDINATE_INDENT.length),
862
+ ...core.facts,
863
+ ]),
821
864
  ].join("\n");
822
865
  }
823
866
  function killResultLabel(evidence) {
824
867
  if (evidence === "killed")
825
- return "✓ killed";
868
+ return { mark: "✓", verb: "killed", evidence: [] };
826
869
  if (evidence === "already-killed")
827
- return "✓ already killed";
870
+ return { mark: "✓", verb: "already killed", evidence: [] };
828
871
  if (evidence === "already-stopped")
829
- return "✓ already stopped";
830
- return `! not killed · ${evidence}`;
872
+ return { mark: "✓", verb: "already stopped", evidence: [] };
873
+ return { mark: "!", verb: "not killed", evidence: [evidence] };
831
874
  }
832
875
  export function killResultText(id, evidence, alias) {
833
- return [...snapshotHeading(id, alias, undefined), "", killResultLabel(evidence)].join("\n");
876
+ const label = killResultLabel(evidence);
877
+ return actionReceipt({
878
+ mark: label.mark,
879
+ verb: label.verb,
880
+ id,
881
+ ...(alias === undefined ? {} : { alias }),
882
+ evidence: label.evidence,
883
+ }).join("\n");
834
884
  }
835
885
  function answerBytes(answer, structured) {
836
886
  return !structured && typeof answer === "string" ? answer : JSON.stringify(answer);
@@ -884,32 +934,62 @@ export function historyText(result, presentation, context) {
884
934
  : `${result.history.omitted} earlier events · showing last ${result.history.rows.length}`),
885
935
  ]
886
936
  : [];
887
- return [...snapshotHeading(result.id, presentation.alias, result.contract), ...paging, ...rows].join("\n");
937
+ // History is an immutable timeline, so it takes the shared heading and content boundary and
938
+ // never gains a fabricated current-state conclusion or a live mark.
939
+ const content = [...paging, ...rows];
940
+ const head = panelHead(result.id, presentation.alias, result.contract);
941
+ return [...head, ...(content.length === 0 ? [] : [frameRule(head, context.columns), ...content])].join("\n");
942
+ }
943
+ /** One bounded preview of a submitted Tell, indented once beneath its verdict or evidence. */
944
+ export function tellPayloadLines(text, context) {
945
+ return renderBoundedPayload({
946
+ text,
947
+ first: SUBORDINATE_INDENT,
948
+ continuation: `${SUBORDINATE_INDENT}│ `,
949
+ columns: context.columns,
950
+ maxLines: 1,
951
+ quote: '"',
952
+ openQuote: false,
953
+ truncated: false,
954
+ });
888
955
  }
889
- export function tellText(result, alias, context, options = {}) {
890
- const wake = result.tell.wake;
891
- const target = identity(result.akuma, alias);
956
+ /** One admitted Tell as a timeline row inside a shared input panel; the panel owns the identity. */
957
+ export function tellAdmissionRow(tell, context) {
958
+ const wake = tell.wake;
892
959
  const glyph = wake.kind === "failed" ? "!" : wake.kind === "held" ? "⧗" : "✓";
893
960
  const verb = wake.kind === "failed" || wake.kind === "held" ? "tell" : "told";
894
- const row = groupedRows([result.tell.row], context, {
961
+ return groupedRows([tell.row], context, {
895
962
  ...plainLayout(),
896
963
  head: (time, _glyph, _verb, columns) => eventPrefix(glyph, verb, time, columns),
897
964
  singleLine: true,
898
965
  }).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");
966
+ }
967
+ /**
968
+ * One Tell action receipt: the delivery verdict and complete subject, then the submitted payload
969
+ * once. A held Tell keeps neutral vocabulary; a failed delivery keeps its own concrete diagnosis.
970
+ */
971
+ export function tellText(result, alias, context) {
972
+ const wake = result.tell.wake;
973
+ const mark = wake.kind === "failed" ? "!" : wake.kind === "held" ? "⧗" : "✓";
974
+ const verb = wake.kind === "failed" || wake.kind === "held" ? "tell" : "told";
975
+ const verdict = actionReceipt({
976
+ mark,
977
+ verb,
978
+ id: result.akuma,
979
+ ...(alias === undefined ? {} : { alias }),
980
+ });
981
+ if (wake.kind !== "failed")
982
+ return [...verdict, ...tellPayloadLines(result.tell.row.text, context)].join("\n");
983
+ const child = "child" in wake ? wake.child : undefined;
984
+ const failure = `! tell delivery failed · ${safeText(wake.diagnostic)}${child === undefined ? "" : ` · log ${child.log.path} ${child.log.from}..${child.log.to}`}`;
985
+ return [
986
+ ...verdict,
987
+ ...tellPayloadLines(result.tell.row.text, context),
988
+ ...subordinateLines(renderBoundedTextBlock(failure, {
989
+ first: "",
990
+ continuation: "",
991
+ columns: context.columns - SUBORDINATE_INDENT.length,
992
+ lines: Number.MAX_SAFE_INTEGER,
993
+ })),
994
+ ].join("\n");
915
995
  }
@@ -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")
@@ -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 {};
@@ -1,7 +1,7 @@
1
1
  import { effectCleanup, effectExecutionStops } from "./effects.js";
2
- import { executionCleanupLines, executionStopLines, receiptPayload, receiptRow, stopLines, titleLines, } from "./receipt.js";
2
+ import { executionCleanupLines, executionStopLines, receiptPayload, receiptRow, titleLines } from "./receipt.js";
3
3
  import { renderRefusalFacts } from "./refusal.js";
4
- import { abbreviateGitIds, displayGitId } from "./contract-observation.js";
4
+ import { abbreviateGitIds, displayGitId, gateFact } from "./contract-observation.js";
5
5
  import { DEFAULT_CLI_COLUMNS, gitShortStat, renderTextBlock, safeText } from "./terminal.js";
6
6
  const CHILD = " ";
7
7
  function workspaceEvidence(workspace) {
@@ -16,11 +16,16 @@ function candidateLines(report, columns, addressed, abbreviations) {
16
16
  return lines;
17
17
  }
18
18
  const identity = candidate.identity;
19
- receiptRow(lines, " ", "candidate", [{ text: "ready" }, { text: displayGitId(identity.tenderSnapshot, abbreviations), opaque: true }], columns);
19
+ receiptRow(lines, " ", "candidate", [{ text: "prepared" }, { text: displayGitId(identity.tenderSnapshot, abbreviations), opaque: true }], columns);
20
20
  lines.push(`${CHILD}integration result ${displayGitId(identity.integration.snapshot, abbreviations)}`);
21
21
  if (!/^0{40}$/u.test(identity.integration.changeId))
22
22
  lines.push(`${CHILD}content identity ${displayGitId(identity.integration.changeId, abbreviations)}`);
23
23
  lines.push(...workspaceEvidence(candidate.workspace));
24
+ for (const report of candidate.requirements.gates)
25
+ lines.push(`${CHILD}${gateFact(report)}`);
26
+ for (const prerequisite of candidate.requirements.unmetPrerequisites) {
27
+ receiptRow(lines, "!", "prerequisite", [{ text: prerequisite.contractId }, { text: prerequisite.state }], columns);
28
+ }
24
29
  lines.push(...renderTextBlock(gitShortStat(candidate.scope), CHILD, columns));
25
30
  if (candidate.scope.paths !== undefined) {
26
31
  for (const path of candidate.scope.paths) {
@@ -31,32 +36,23 @@ function candidateLines(report, columns, addressed, abbreviations) {
31
36
  receiptPayload(lines, "diff", candidate.diff);
32
37
  return lines;
33
38
  }
34
- function verificationLines(verification, columns, addressed) {
39
+ function verificationLines(verification, columns) {
35
40
  const lines = [];
36
- if (verification.kind === "undeclared") {
37
- receiptRow(lines, " ", "verification", [{ text: "none declared" }], columns);
38
- return lines;
39
- }
40
- if (verification.kind === "not-run") {
41
- receiptRow(lines, " ", "verification", [{ text: "not run" }], columns);
42
- return lines;
43
- }
44
- if (verification.kind === "stopped") {
45
- return stopLines(verification.stop, columns, addressed);
46
- }
47
- if (verification.kind === "reused") {
48
- receiptRow(lines, " ", "verification", [{ text: "reused" }, { text: verification.verdict }], columns);
49
- if (verification.summary !== undefined)
50
- receiptPayload(lines, "summary", auditSummary(verification.summary));
41
+ if (verification.kind !== "recorded") {
42
+ const text = verification.kind === "undeclared"
43
+ ? "none declared"
44
+ : verification.kind === "required"
45
+ ? "required · not run"
46
+ : "not run";
47
+ receiptRow(lines, " ", "verification", [{ text }], columns);
51
48
  return lines;
52
49
  }
53
- receiptRow(lines, verification.kind === "satisfied" ? "✓" : "!", "verification", [{ text: verification.kind }, { text: `${verification.passed} of ${verification.total}` }], columns);
54
- if (verification.summary !== undefined) {
55
- receiptPayload(lines, "summary", auditSummary(verification.summary));
56
- }
50
+ receiptRow(lines, verification.verdict === "unsatisfied" ? "!" : " ", "verification", [{ text: "recorded" }, { text: verification.verdict }], columns);
51
+ if (verification.summary !== undefined)
52
+ receiptPayload(lines, "summary", previewSummary(verification.summary));
57
53
  return lines;
58
54
  }
59
- function auditSummary(summary) {
55
+ function previewSummary(summary) {
60
56
  return summary.replace(/\[(\d+) (bash|zsh|pwsh) exit (-?\d+)( output-truncated)?\]/gu, (_, number, executor, exit, truncated) => `declaration ${number} · ${executor} exit ${exit}${truncated ?? ""}`);
61
57
  }
62
58
  function admittedCandidateLines(report, columns) {
@@ -86,6 +82,12 @@ function targetLines(report, columns, addressed, abbreviations) {
86
82
  opaque: true,
87
83
  },
88
84
  ], columns);
85
+ for (const checkout of target.checkouts) {
86
+ if (checkout.kind === "followable")
87
+ continue;
88
+ receiptRow(lines, "!", "checkout cannot follow", [{ text: checkout.path, opaque: true }], columns);
89
+ receiptPayload(lines, "reason", checkout.diagnostic);
90
+ }
89
91
  return lines;
90
92
  }
91
93
  if (target.kind === "moved") {
@@ -114,7 +116,7 @@ function obligationLines(result, columns) {
114
116
  ...executionStopLines(effectExecutionStops(result.effects), columns),
115
117
  ];
116
118
  }
117
- export function renderAcceptedAudit(result, context) {
119
+ export function renderDeliveryPreview(result, context) {
118
120
  const report = result.value;
119
121
  const columns = context?.columns ?? DEFAULT_CLI_COLUMNS;
120
122
  const ids = report.candidate.kind === "ready"
@@ -130,10 +132,10 @@ export function renderAcceptedAudit(result, context) {
130
132
  ids.push(report.target.expected, report.target.observed ?? "");
131
133
  const abbreviations = abbreviateGitIds(ids);
132
134
  return [
133
- ...titleLines("✓", "audit", result.contract, columns),
135
+ ...titleLines("✓", "deliver --dry-run", result.contract, columns),
134
136
  ...candidateLines(report, columns, result.contract, abbreviations),
135
137
  ...admittedCandidateLines(report, columns),
136
- ...verificationLines(report.verification, columns, result.contract),
138
+ ...verificationLines(report.verification, columns),
137
139
  ...targetLines(report, columns, result.contract, abbreviations),
138
140
  ...obligationLines(result, columns),
139
141
  ].join("\n");