@astrosheep/keiyaku 4.1.0 → 4.1.2

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 (278) hide show
  1. package/README.md +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -0
  3. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +3 -0
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -6
  5. package/build/src/akuma/akuma-errors.d.ts +6 -0
  6. package/build/src/akuma/akuma-errors.js +9 -0
  7. package/build/src/akuma/akuma-handle.d.ts +39 -0
  8. package/build/src/akuma/akuma-handle.js +263 -0
  9. package/build/src/akuma/akuma-observe.d.ts +19 -0
  10. package/build/src/akuma/akuma-observe.js +74 -0
  11. package/build/src/akuma/akuma-product-symbols.d.ts +1 -0
  12. package/build/src/akuma/akuma-product-symbols.js +1 -0
  13. package/build/src/akuma/akuma-product.d.ts +18 -0
  14. package/build/src/akuma/akuma-product.js +154 -0
  15. package/build/src/akuma/akuma.d.ts +37 -81
  16. package/build/src/akuma/akuma.js +39 -447
  17. package/build/src/akuma/allowed.d.ts +1 -0
  18. package/build/src/akuma/allowed.js +6 -0
  19. package/build/src/akuma/archetype.js +8 -5
  20. package/build/src/akuma/body-supervisor.d.ts +26 -0
  21. package/build/src/akuma/body-supervisor.js +89 -0
  22. package/build/src/akuma/body.d.ts +45 -4
  23. package/build/src/akuma/body.js +145 -35
  24. package/build/src/akuma/coordinate.js +17 -7
  25. package/build/src/akuma/heart/facts.js +1 -1
  26. package/build/src/akuma/heart/index.d.ts +1 -1
  27. package/build/src/akuma/heart/index.js +2 -4
  28. package/build/src/akuma/heart/request-authority.js +4 -4
  29. package/build/src/akuma/heart/request-rows.js +27 -16
  30. package/build/src/akuma/heart/rows.js +79 -41
  31. package/build/src/akuma/heart/soul.js +1 -1
  32. package/build/src/akuma/heart/storage.d.ts +1 -0
  33. package/build/src/akuma/heart/storage.js +76 -11
  34. package/build/src/akuma/heart/tells.js +35 -18
  35. package/build/src/akuma/heart/timeline.js +19 -11
  36. package/build/src/akuma/identity.d.ts +1 -0
  37. package/build/src/akuma/identity.js +1 -0
  38. package/build/src/akuma/index.d.ts +3 -3
  39. package/build/src/akuma/index.js +1 -1
  40. package/build/src/akuma/nuke.js +106 -14
  41. package/build/src/akuma/projection-read.d.ts +17 -0
  42. package/build/src/akuma/projection-read.js +135 -0
  43. package/build/src/akuma/projection.d.ts +1 -16
  44. package/build/src/akuma/projection.js +77 -154
  45. package/build/src/akuma/provider-recipe.js +11 -5
  46. package/build/src/akuma/provider.js +105 -62
  47. package/build/src/akuma/providers/acp/config.js +5 -6
  48. package/build/src/akuma/providers/acp/core.js +17 -10
  49. package/build/src/akuma/providers/acp/events.js +38 -29
  50. package/build/src/akuma/providers/acp/index.js +13 -9
  51. package/build/src/akuma/providers/claude/events.js +8 -12
  52. package/build/src/akuma/providers/claude/index.d.ts +1 -0
  53. package/build/src/akuma/providers/claude/index.js +55 -26
  54. package/build/src/akuma/providers/claude/input.js +6 -2
  55. package/build/src/akuma/providers/codex-app-server/events.js +61 -36
  56. package/build/src/akuma/providers/codex-app-server/index.js +25 -13
  57. package/build/src/akuma/providers/grok-build/index.js +22 -25
  58. package/build/src/akuma/providers/index.js +2 -18
  59. package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
  60. package/build/src/akuma/providers/opencode-sdk/index.js +26 -17
  61. package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
  62. package/build/src/akuma/providers/pi/events.js +26 -19
  63. package/build/src/akuma/providers/pi/index.js +58 -40
  64. package/build/src/akuma/publication.js +9 -9
  65. package/build/src/akuma/request-execution.d.ts +6 -0
  66. package/build/src/akuma/request-execution.js +86 -0
  67. package/build/src/akuma/request-serve.d.ts +12 -1
  68. package/build/src/akuma/request-serve.js +19 -122
  69. package/build/src/akuma/request-wire.d.ts +2 -2
  70. package/build/src/akuma/request-wire.js +75 -102
  71. package/build/src/akuma/requests.js +2 -2
  72. package/build/src/akuma/{body-turn.d.ts → turn-drive.d.ts} +2 -25
  73. package/build/src/akuma/{body-turn.js → turn-drive.js} +20 -103
  74. package/build/src/akuma-body.js +6 -5
  75. package/build/src/body/amend.d.ts +4 -1
  76. package/build/src/body/amend.js +14 -6
  77. package/build/src/body/decode.js +2 -4
  78. package/build/src/body/envelope.js +2 -4
  79. package/build/src/body/region.d.ts +1 -2
  80. package/build/src/body/region.js +2 -70
  81. package/build/src/body/render.js +17 -12
  82. package/build/src/body/shape.js +1 -7
  83. package/build/src/cli/accepted.d.ts +1 -1
  84. package/build/src/cli/accepted.js +8 -1
  85. package/build/src/cli/commands/akuma-invoke.js +18 -6
  86. package/build/src/cli/commands/akuma.d.ts +0 -6
  87. package/build/src/cli/commands/akuma.js +11 -24
  88. package/build/src/cli/commands/amend.d.ts +2 -2
  89. package/build/src/cli/commands/amend.js +2 -4
  90. package/build/src/cli/commands/bind.d.ts +4 -4
  91. package/build/src/cli/commands/bind.js +16 -6
  92. package/build/src/cli/commands/contract-invoke.d.ts +25 -0
  93. package/build/src/cli/commands/contract-invoke.js +193 -0
  94. package/build/src/cli/commands/contract.d.ts +109 -10
  95. package/build/src/cli/commands/contract.js +339 -16
  96. package/build/src/cli/commands/install.d.ts +1 -1
  97. package/build/src/cli/commands/install.js +23 -15
  98. package/build/src/cli/commands/task-invoke.js +187 -67
  99. package/build/src/cli/commands/task-query.js +48 -24
  100. package/build/src/cli/commands/task.js +150 -38
  101. package/build/src/cli/coordinates.js +2 -4
  102. package/build/src/cli/invoke.js +92 -208
  103. package/build/src/cli/main.js +4 -2
  104. package/build/src/cli/parse.d.ts +3 -90
  105. package/build/src/cli/parse.js +27 -233
  106. package/build/src/cli/render/akuma-activity.d.ts +38 -0
  107. package/build/src/cli/render/akuma-activity.js +362 -0
  108. package/build/src/cli/render/akuma-tool-command.js +6 -7
  109. package/build/src/cli/render/akuma-tool.js +10 -8
  110. package/build/src/cli/render/akuma.d.ts +1 -1
  111. package/build/src/cli/render/akuma.js +61 -353
  112. package/build/src/cli/render/audit.js +5 -15
  113. package/build/src/cli/render/board.d.ts +1 -0
  114. package/build/src/cli/render/board.js +17 -0
  115. package/build/src/cli/render/catalog.js +81 -8
  116. package/build/src/cli/render/contract-history.d.ts +2 -0
  117. package/build/src/cli/render/contract-history.js +83 -0
  118. package/build/src/cli/render/contract-observation.d.ts +10 -0
  119. package/build/src/cli/render/contract-observation.js +58 -0
  120. package/build/src/cli/render/contract.d.ts +1 -2
  121. package/build/src/cli/render/contract.js +41 -142
  122. package/build/src/cli/render/kanshi.js +239 -215
  123. package/build/src/cli/render/receipt.js +2 -9
  124. package/build/src/cli/render/refusal.js +10 -15
  125. package/build/src/cli/render/region.js +22 -6
  126. package/build/src/cli/render/settings.js +4 -4
  127. package/build/src/cli/render/task.js +34 -14
  128. package/build/src/cli/render/terminal.js +16 -5
  129. package/build/src/cli/result.d.ts +3 -3
  130. package/build/src/cli/runtime.d.ts +6 -1
  131. package/build/src/cli/runtime.js +84 -63
  132. package/build/src/cli/selectors.js +2 -4
  133. package/build/src/cli/usage.js +6 -5
  134. package/build/src/contract-worktree.d.ts +1 -23
  135. package/build/src/contract-worktree.js +79 -155
  136. package/build/src/coordination/durable-file.js +7 -3
  137. package/build/src/coordination/sqlite-transaction-lock.js +29 -12
  138. package/build/src/core/facts/codec.js +7 -3
  139. package/build/src/core/facts/types.d.ts +1 -1
  140. package/build/src/core/subject.js +16 -9
  141. package/build/src/core/verbs/abandon.d.ts +1 -1
  142. package/build/src/core/verbs/abandon.js +1 -1
  143. package/build/src/core/verbs/amend.d.ts +1 -1
  144. package/build/src/core/verbs/amend.js +7 -7
  145. package/build/src/core/verbs/attestation.js +4 -1
  146. package/build/src/core/verbs/bind.d.ts +1 -1
  147. package/build/src/core/verbs/bind.js +1 -1
  148. package/build/src/core/verbs/placement.d.ts +1 -1
  149. package/build/src/core/verbs/placement.js +10 -8
  150. package/build/src/dispatch/index.js +8 -6
  151. package/build/src/duration.js +5 -1
  152. package/build/src/git/admission.js +5 -3
  153. package/build/src/git/hooks.d.ts +8 -0
  154. package/build/src/git/hooks.js +63 -14
  155. package/build/src/git/identity.js +1 -4
  156. package/build/src/git/integration.d.ts +2 -3
  157. package/build/src/git/integration.js +32 -39
  158. package/build/src/git/nuke.d.ts +1 -1
  159. package/build/src/git/nuke.js +110 -57
  160. package/build/src/git/observe.d.ts +13 -1
  161. package/build/src/git/observe.js +51 -44
  162. package/build/src/git/process.js +4 -2
  163. package/build/src/git/read-observation.js +10 -8
  164. package/build/src/git/reconcile.d.ts +22 -2
  165. package/build/src/git/reconcile.js +38 -274
  166. package/build/src/git/repository.d.ts +2 -0
  167. package/build/src/git/repository.js +13 -22
  168. package/build/src/git/scratch.d.ts +8 -5
  169. package/build/src/git/scratch.js +29 -2
  170. package/build/src/git/target-placement.d.ts +9 -10
  171. package/build/src/git/target-placement.js +59 -62
  172. package/build/src/git/tender.js +13 -46
  173. package/build/src/git/terminal-reconcile.d.ts +21 -0
  174. package/build/src/git/terminal-reconcile.js +278 -0
  175. package/build/src/git/terminal-seal.js +15 -12
  176. package/build/src/git/tree.js +5 -2
  177. package/build/src/git/workspace.d.ts +24 -2
  178. package/build/src/git/workspace.js +120 -16
  179. package/build/src/identity/coordinates.js +3 -1
  180. package/build/src/identity/selector.js +6 -3
  181. package/build/src/kanshi/fleet.d.ts +6 -0
  182. package/build/src/kanshi/fleet.js +27 -0
  183. package/build/src/kanshi/index.d.ts +1 -1
  184. package/build/src/kanshi/read.js +60 -48
  185. package/build/src/kanshi/report.d.ts +11 -23
  186. package/build/src/kanshi/select.js +25 -24
  187. package/build/src/library/address.d.ts +2 -1
  188. package/build/src/library/address.js +7 -8
  189. package/build/src/library/akuma-creation.js +20 -12
  190. package/build/src/library/audit.d.ts +0 -1
  191. package/build/src/library/audit.js +1 -2
  192. package/build/src/library/bind.d.ts +53 -5
  193. package/build/src/library/bind.js +98 -22
  194. package/build/src/library/catalog.d.ts +1 -0
  195. package/build/src/library/catalog.js +6 -3
  196. package/build/src/library/configuration.js +3 -1
  197. package/build/src/library/continuation.d.ts +15 -4
  198. package/build/src/library/continuation.js +24 -16
  199. package/build/src/library/contract-bind.d.ts +26 -0
  200. package/build/src/library/contract-bind.js +106 -0
  201. package/build/src/library/contract-operations.d.ts +77 -0
  202. package/build/src/library/contract-operations.js +130 -0
  203. package/build/src/library/contract-types.d.ts +95 -0
  204. package/build/src/library/contract-types.js +1 -0
  205. package/build/src/library/contract.d.ts +19 -154
  206. package/build/src/library/contract.js +46 -261
  207. package/build/src/library/fleet.d.ts +1 -1
  208. package/build/src/library/fleet.js +19 -11
  209. package/build/src/library/input.d.ts +2 -0
  210. package/build/src/library/input.js +14 -0
  211. package/build/src/library/keiyaku.d.ts +8 -7
  212. package/build/src/library/keiyaku.js +3 -3
  213. package/build/src/library/nuke.js +14 -5
  214. package/build/src/library/reconcile.d.ts +9 -4
  215. package/build/src/library/reconcile.js +30 -24
  216. package/build/src/library/refusal.d.ts +13 -5
  217. package/build/src/library/refusal.js +7 -0
  218. package/build/src/library/region.d.ts +8 -7
  219. package/build/src/library/region.js +31 -11
  220. package/build/src/library/repo.js +2 -2
  221. package/build/src/markdown/lex.js +9 -2
  222. package/build/src/markdown/parse.js +11 -7
  223. package/build/src/markdown/query.js +4 -2
  224. package/build/src/protocol/amend.js +3 -1
  225. package/build/src/protocol/attempt.d.ts +7 -3
  226. package/build/src/protocol/attempt.js +9 -5
  227. package/build/src/protocol/audit.d.ts +1 -1
  228. package/build/src/protocol/audit.js +4 -14
  229. package/build/src/protocol/bind.d.ts +19 -6
  230. package/build/src/protocol/bind.js +28 -13
  231. package/build/src/protocol/completion.d.ts +0 -1
  232. package/build/src/protocol/completion.js +1 -3
  233. package/build/src/protocol/deliver.d.ts +1 -3
  234. package/build/src/protocol/deliver.js +15 -39
  235. package/build/src/protocol/intent.d.ts +1 -0
  236. package/build/src/protocol/intent.js +9 -7
  237. package/build/src/protocol/operations.d.ts +3 -7
  238. package/build/src/protocol/operations.js +5 -3
  239. package/build/src/protocol/placement.d.ts +0 -1
  240. package/build/src/protocol/placement.js +6 -6
  241. package/build/src/protocol/read/observation.d.ts +11 -0
  242. package/build/src/protocol/read/observation.js +37 -0
  243. package/build/src/protocol/read/status.d.ts +23 -12
  244. package/build/src/protocol/read/status.js +90 -72
  245. package/build/src/protocol/reconcile.d.ts +1 -0
  246. package/build/src/protocol/reconcile.js +2 -3
  247. package/build/src/protocol/reintegrate.js +1 -1
  248. package/build/src/protocol/review.d.ts +0 -1
  249. package/build/src/protocol/review.js +15 -22
  250. package/build/src/protocol/run.d.ts +1 -0
  251. package/build/src/protocol/run.js +4 -5
  252. package/build/src/runtime/proc/launch.d.ts +33 -0
  253. package/build/src/runtime/proc/launch.js +98 -0
  254. package/build/src/runtime/proc/line-rpc.js +9 -3
  255. package/build/src/runtime/proc/run.d.ts +12 -6
  256. package/build/src/runtime/proc/run.js +78 -21
  257. package/build/src/runtime/proc/stdio.js +7 -10
  258. package/build/src/settings.js +6 -2
  259. package/build/src/settlement/holder.js +13 -10
  260. package/build/src/settlement/settle.js +39 -6
  261. package/build/src/task/board.js +12 -6
  262. package/build/src/task/compose.js +85 -22
  263. package/build/src/task/context.js +21 -8
  264. package/build/src/task/document.js +46 -10
  265. package/build/src/task/identity.js +5 -2
  266. package/build/src/task/index.d.ts +0 -1
  267. package/build/src/task/index.js +119 -34
  268. package/build/src/task/input.js +29 -7
  269. package/build/src/task/mutation.js +61 -19
  270. package/build/src/task/operations.d.ts +6 -1
  271. package/build/src/task/operations.js +83 -29
  272. package/build/src/task/query.js +55 -26
  273. package/build/src/task/store.d.ts +3 -1
  274. package/build/src/task/store.js +81 -17
  275. package/build/src/verification/execution.js +14 -11
  276. package/build/src/workspace-place.js +19 -7
  277. package/build/src/world.js +16 -6
  278. package/package.json +8 -3
@@ -1,8 +1,8 @@
1
- import { displayColumns, renderTextBlock, safeText, tone } from "./terminal.js";
1
+ import { visibleFleetRows } from "../../kanshi/fleet.js";
2
+ import { abbreviateGitIds, afterWording, candidateFact, dependentWording, displayGitId, gateFact, gitIdsInRow, mergeSummary, } from "./contract-observation.js";
3
+ import { displayColumns, renderTextBlock, safeText, tone, truncateDisplayText, } from "./terminal.js";
2
4
  const PLUMB = " │ ";
3
- const PATH_PREFIX = `${PLUMB}↳ `;
4
5
  const MAX_VISIBLE_ROWS = 10;
5
- const FIELD_WIDTH = 8;
6
6
  function contractMark(row) {
7
7
  if (row.phase === "claimed")
8
8
  return "✓";
@@ -41,17 +41,15 @@ function akumaMark(life) {
41
41
  return "×";
42
42
  return "?";
43
43
  }
44
- function gateMark(report) {
45
- if (report.current.kind !== "attested")
46
- return "?";
47
- return report.current.verdict === "satisfied" ? "✓" : "!";
48
- }
49
- function worldGateMark(report) {
50
- if (report.current.kind === "stale")
51
- return "~";
52
- if (report.current.kind !== "attested")
53
- return " ";
54
- return report.current.verdict === "satisfied" ? "✓" : "✗";
44
+ function gitAbbreviations(report) {
45
+ const ids = [];
46
+ if (report.contracts.kind !== "present")
47
+ return abbreviateGitIds(ids);
48
+ if (report.contracts.value.state !== null)
49
+ ids.push(report.contracts.value.state);
50
+ for (const row of report.contracts.value.rows)
51
+ ids.push(...gitIdsInRow(row));
52
+ return abbreviateGitIds(ids);
55
53
  }
56
54
  function formatAge(source, observedAt) {
57
55
  if (source === null || source === undefined)
@@ -69,9 +67,6 @@ function formatAge(source, observedAt) {
69
67
  const hours = Math.floor(minutes / 60);
70
68
  return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;
71
69
  }
72
- function isLost(life) {
73
- return life === "stranded" || life === "hung" || life === "untidy";
74
- }
75
70
  function branchName(target) {
76
71
  if (target === null)
77
72
  return null;
@@ -90,13 +85,16 @@ function targetFacts(row) {
90
85
  facts.push("target moved");
91
86
  return facts;
92
87
  }
88
+ function selectedTargetFacts(row, abbreviations) {
89
+ return [
90
+ ...targetFacts(row),
91
+ ...(row.target !== null && row.targetObservation?.head !== null && row.targetObservation?.head !== undefined
92
+ ? [`target head ${displayGitId(row.targetObservation.head, abbreviations)}`]
93
+ : []),
94
+ ];
95
+ }
93
96
  function workspaceState(row) {
94
97
  const observation = row.workspaceObservation;
95
- if (row.workspace === "here" && observation.kind === "failed") {
96
- return `workspace here · failed · ${observation.diagnostic}`;
97
- }
98
- if (row.workspace === "here")
99
- return `workspace here · ${observation.kind}`;
100
98
  if (observation.kind === "failed")
101
99
  return `worktree unavailable · ${observation.diagnostic}`;
102
100
  if (observation.kind === "unappointed")
@@ -113,59 +111,63 @@ function workspaceState(row) {
113
111
  ];
114
112
  return counts.length === 0 ? "worktree dirty" : `worktree dirty · ${counts.join(" · ")}`;
115
113
  }
116
- function showWorkspacePath(row, hot) {
117
- if (row.workspace !== "worktree")
118
- return false;
119
- if (row.workspaceObservation.kind === "unappointed")
120
- return false;
121
- if (row.workspaceObservation.kind !== "clean" && row.workspaceObservation.kind !== "failed")
122
- return true;
123
- return hot;
124
- }
125
- function contractHot(row) {
126
- if (row.title === null)
127
- return true;
128
- if (row.phase === "pending-delivery")
129
- return true;
130
- if (row.holder.kind === "unavailable" || row.holder.kind === "held")
131
- return true;
132
- if (row.fleet.length > 0)
133
- return true;
134
- if (row.targetLag.kind === "counted" && row.targetLag.behind > 0)
135
- return true;
136
- if (row.workspaceObservation.kind !== "clean" && row.workspaceObservation.kind !== "unappointed") {
137
- return true;
114
+ function mergeFacts(row, selected, abbreviations) {
115
+ const observation = row.workspaceObservation;
116
+ const summary = mergeSummary(observation);
117
+ if (summary === undefined ||
118
+ (observation.kind !== "clean" && observation.kind !== "dirty") ||
119
+ observation.merge === null) {
120
+ return [];
138
121
  }
139
- return row.gates.reports.some((report) => report.current.kind === "stale"
140
- || (report.current.kind === "attested" && report.current.verdict === "unsatisfied"));
141
- }
142
- function taskHot(row) {
143
- return row.disposition === "blocked" || row.disposition === "in_progress";
122
+ if (!selected)
123
+ return [summary];
124
+ const paths = observation.merge.unmergedPaths;
125
+ return [
126
+ summary,
127
+ `merge head ${displayGitId(observation.merge.head, abbreviations)}`,
128
+ ...(paths.length === 0 ? ["0 paths"] : paths),
129
+ ];
144
130
  }
145
- function akumaHot(row) {
146
- if (row.life === "running" || row.life === "stillborn" || isLost(row.life))
147
- return true;
148
- return row.contract?.observed === "missing" || row.contract?.observed === "unavailable";
131
+ function worldAfterFacts(row) {
132
+ return row.after.map(afterWording);
149
133
  }
150
134
  function activitySnapshotLine(row) {
151
135
  const snapshot = row.snapshot;
152
136
  if (snapshot === undefined)
153
137
  return undefined;
154
- const entries = snapshot.entries.flatMap((entry) => entry.kind === "row" ? [entry.row] : []);
138
+ const entries = snapshot.entries.flatMap((entry) => (entry.kind === "row" ? [entry.row] : []));
155
139
  const latest = entries.at(-1);
156
140
  if (latest === undefined) {
157
141
  if (snapshot.kind === "idle" && snapshot.outcome !== undefined) {
158
- return snapshot.outcome.outcome.kind === "answered" ? snapshot.outcome.outcome.answer : snapshot.outcome.outcome.diagnostic;
142
+ return snapshot.outcome.outcome.kind === "answered"
143
+ ? snapshot.outcome.outcome.answer
144
+ : snapshot.outcome.outcome.diagnostic;
159
145
  }
160
- return "empty";
146
+ return undefined;
161
147
  }
162
- if (latest.kind === "said" || latest.kind === "thought" || latest.kind === "note" || latest.kind === "call" || latest.kind === "tell") {
148
+ if (latest.kind === "said" ||
149
+ latest.kind === "thought" ||
150
+ latest.kind === "note" ||
151
+ latest.kind === "call" ||
152
+ latest.kind === "tell") {
163
153
  return latest.text;
164
154
  }
165
155
  if (latest.kind === "tool")
166
156
  return latest.name;
167
157
  return "activity";
168
158
  }
159
+ function boundedActivity(value, columns, prefix) {
160
+ const budget = Math.max(1, columns - displayColumns(prefix));
161
+ return `activity "${truncateDisplayText(value, Math.max(1, budget - displayColumns('activity ""')))}"`;
162
+ }
163
+ function renderColdFleetLine(row, prefix, snapshot, columns) {
164
+ const mark = akumaMark(row.life);
165
+ const identity = identityLine(mark, row.id, prefix);
166
+ if (snapshot === undefined)
167
+ return [identity];
168
+ const activity = boundedActivity(snapshot, columns, PLUMB);
169
+ return [identity, ...plumbFacts([activity], columns)];
170
+ }
169
171
  function plumbFacts(facts, columns) {
170
172
  const clean = facts.map(safeText).filter((fact) => fact.length > 0);
171
173
  if (clean.length === 0)
@@ -184,45 +186,9 @@ function plumbFacts(facts, columns) {
184
186
  lines.push(current);
185
187
  return lines;
186
188
  }
187
- function plumbBlock(value, columns) {
188
- return renderTextBlock(value, PLUMB, columns);
189
- }
190
- function plumbPath(path) {
191
- return `${PATH_PREFIX}${safeText(path)}`;
192
- }
193
189
  function identityLine(mark, identity, extra = "") {
194
190
  return extra.length === 0 ? `${mark} ${safeText(identity)}` : `${mark} ${safeText(identity)} ${safeText(extra)}`;
195
191
  }
196
- function renderGates(reports, observedAt, columns, includeSummaries) {
197
- if (reports.length === 0)
198
- return [];
199
- const lines = [...plumbFacts([`gates: ${reports.map((report) => `${gateMark(report)} ${report.gate} ${formatAge(report.current.kind === "attested" ? report.current.at : null, observedAt)}`).join(" · ")}`], columns)];
200
- if (!includeSummaries)
201
- return lines;
202
- for (const report of reports) {
203
- if (report.current.kind !== "attested" || report.current.summary === undefined)
204
- continue;
205
- lines.push(...plumbBlock(`${report.gate}: ${report.current.summary}`, columns));
206
- }
207
- return lines;
208
- }
209
- function fieldPrefix(label) {
210
- return ` ${label.padEnd(FIELD_WIDTH, " ")}`;
211
- }
212
- function fieldLine(label, value) {
213
- return `${fieldPrefix(label)}${safeText(value)}`;
214
- }
215
- function fieldBlock(label, value, columns) {
216
- const continuation = " ".repeat(fieldPrefix(label).length);
217
- return renderTextBlock(value, continuation, columns).map((line, index) => index === 0
218
- ? `${fieldPrefix(label)}${line.slice(continuation.length)}`
219
- : line);
220
- }
221
- function renderWorldGates(reports) {
222
- if (reports.length === 0)
223
- return [];
224
- return [fieldLine("GATES", reports.map((report) => `[${worldGateMark(report)}] ${report.gate}`).join(" "))];
225
- }
226
192
  function failure(name, section, context) {
227
193
  return [`[ ${name} ]`, "", `${tone(`! ${safeText(section.failure.message)}`, "alert", context.color)}`];
228
194
  }
@@ -236,57 +202,127 @@ function endpointFact(id, observed) {
236
202
  return `-> ${id} (unavailable)`;
237
203
  return `-> ${id}`;
238
204
  }
239
- function renderNamespaceTasks(row, context) {
240
- if (row.namespaceTasks.kind === "absent")
241
- return plumbFacts(["namespace tasks absent"], context.columns);
242
- if (row.namespaceTasks.kind === "failed") {
243
- return plumbFacts([`namespace tasks failed ${row.namespaceTasks.failure.message}`], context.columns);
244
- }
245
- const lines = [...plumbFacts([`namespace tasks ${row.namespaceTasks.value.length}`], context.columns)];
246
- for (const task of row.namespaceTasks.value) {
247
- const scan = `${taskMark(task)} ${task.id} · P${task.priority} ${task.disposition}`;
248
- const title = safeText(task.title);
249
- const inline = `${scan} — ${title}`;
250
- if (displayColumns(inline) <= context.columns - displayColumns(PLUMB)) {
251
- lines.push(...plumbFacts([inline], context.columns));
205
+ function linkedTask(report, taskId) {
206
+ if (report.tasks.kind !== "present")
207
+ return `! ${taskId} · unavailable`;
208
+ const task = report.tasks.value.rows.find((candidate) => candidate.id === taskId);
209
+ return task === undefined ? `! ${taskId} · missing` : `${taskMark(task)} ${task.id} · ${task.disposition}`;
210
+ }
211
+ function linkedAkuma(report, id, aliases) {
212
+ const alias = aliases.length === 0 ? "" : ` (${aliases.join(" ")})`;
213
+ if (report.akuma.kind !== "present")
214
+ return `! ${id}${alias} · unavailable`;
215
+ const akuma = report.akuma.value.rows.find((candidate) => candidate.id === id);
216
+ return akuma === undefined ? `! ${id}${alias} · missing` : `${akumaMark(akuma.life)} ${id}${alias} · ${akuma.life}`;
217
+ }
218
+ function isTerminalAkuma(life) {
219
+ return life === "killed" || life === "stillborn";
220
+ }
221
+ function attachmentTimestamp(akuma) {
222
+ if ("lifeAt" in akuma && akuma.lifeAt !== null)
223
+ return akuma.lifeAt;
224
+ if ("lastActivityAt" in akuma && akuma.lastActivityAt !== null)
225
+ return akuma.lastActivityAt;
226
+ return null;
227
+ }
228
+ function worldAttachments(row, report) {
229
+ if (report.akuma.kind !== "present")
230
+ return row.fleet;
231
+ const byId = new Map(report.akuma.value.rows.map((akuma) => [akuma.id, akuma]));
232
+ const nonTerminal = new Set();
233
+ const unknown = new Set();
234
+ let latestTerminal;
235
+ row.fleet.forEach((attached) => {
236
+ const akuma = byId.get(attached.id);
237
+ if (akuma === undefined) {
238
+ unknown.add(attached.id);
239
+ return;
252
240
  }
253
- else {
254
- lines.push(...plumbFacts([`${scan} —`], context.columns));
255
- lines.push(...plumbBlock(title, context.columns));
241
+ if (!isTerminalAkuma(akuma.life)) {
242
+ nonTerminal.add(attached.id);
243
+ return;
256
244
  }
257
- }
245
+ const at = attachmentTimestamp(akuma);
246
+ if (latestTerminal === undefined || (at !== null && (latestTerminal.at === null || at > latestTerminal.at))) {
247
+ latestTerminal = { id: attached.id, at };
248
+ }
249
+ });
250
+ const retained = new Set(unknown);
251
+ for (const id of nonTerminal)
252
+ retained.add(id);
253
+ if (nonTerminal.size === 0 && latestTerminal !== undefined)
254
+ retained.add(latestTerminal.id);
255
+ return row.fleet.filter((attached) => retained.has(attached.id));
256
+ }
257
+ function linkedFacts(row, report, mode) {
258
+ const linked = [];
259
+ if (row.holder.kind === "held")
260
+ linked.push(linkedTask(report, row.holder.taskId));
261
+ if (row.holder.kind === "unavailable")
262
+ linked.push("! task · unavailable");
263
+ const attachments = mode === "world" ? worldAttachments(row, report) : row.fleet;
264
+ for (const attached of attachments)
265
+ linked.push(linkedAkuma(report, attached.id, attached.aliases));
266
+ return linked;
267
+ }
268
+ function semanticBlock(name, facts, context) {
269
+ const lines = [` ${name}`];
270
+ const values = facts.length === 0 ? ["none"] : facts;
271
+ for (const fact of values)
272
+ lines.push(...renderTextBlock(safeText(fact), " ", context.columns));
258
273
  return lines;
259
274
  }
260
- function renderContractRow(row, report, context, selection) {
261
- const hot = contractHot(row);
262
- const compact = !hot && selection !== "contract";
275
+ function namespaceTaskFacts(row) {
276
+ if (row.namespaceTasks.kind === "absent")
277
+ return ["absent"];
278
+ if (row.namespaceTasks.kind === "failed") {
279
+ return [`failed ${row.namespaceTasks.failure.message}`];
280
+ }
281
+ return row.namespaceTasks.value.map((task) => `${taskMark(task)} ${task.id} · P${task.priority} ${task.disposition} — ${task.title}`);
282
+ }
283
+ function renderSelectedContractRow(row, report, context, abbreviations) {
263
284
  const title = row.title ?? "title unavailable";
264
- const phase = `${row.phase} · ${formatAge(row.phaseAt, report.observedAt)}`;
265
- const journal = `journal ${formatAge(row.lastJournalAt, report.observedAt)}`;
266
- const lines = [identityLine(contractMark(row), row.id)];
267
- lines.push(...plumbFacts(compact ? [title, phase, journal, ...targetFacts(row)] : [title], context.columns));
268
- if (!compact)
269
- lines.push(...plumbFacts([phase, journal, ...targetFacts(row)], context.columns));
270
- lines.push(...plumbFacts([workspaceState(row)], context.columns));
271
- if (showWorkspacePath(row, hot || selection === "contract")
272
- && row.workspaceObservation.kind !== "unappointed"
273
- && row.workspaceObservation.kind !== "failed"
274
- && row.workspaceObservation.location.kind === "worktree") {
275
- lines.push(plumbPath(row.workspaceObservation.location.path));
285
+ const lines = [
286
+ identityLine(contractMark(row), row.id, `· ${row.phase} · ${formatAge(row.phaseAt, report.observedAt)} · ${title}`),
287
+ ];
288
+ lines.push(...semanticBlock("after", worldAfterFacts(row), context));
289
+ lines.push(...semanticBlock("dependents", row.dependents.map(dependentWording), context));
290
+ const gateFacts = row.gates.reports.flatMap((gate) => [
291
+ `${gateFact(gate)} ${formatAge(gate.current.kind === "attested" ? gate.current.at : null, report.observedAt)}`,
292
+ ...(gate.current.kind === "attested" && gate.current.summary !== undefined
293
+ ? [`${gate.gate}: ${gate.current.summary}`]
294
+ : []),
295
+ ]);
296
+ lines.push(...semanticBlock("gates", gateFacts, context));
297
+ lines.push(...semanticBlock("candidate/integration", candidateFacts(row, abbreviations), context));
298
+ lines.push(...semanticBlock("target", selectedTargetFacts(row, abbreviations), context));
299
+ const workspaceFacts = [workspaceState(row)];
300
+ if (row.workspaceObservation.kind !== "unappointed" &&
301
+ row.workspaceObservation.kind !== "failed" &&
302
+ row.workspaceObservation.location.kind === "worktree") {
303
+ workspaceFacts.push(`path ${row.workspaceObservation.location.path}`);
276
304
  }
277
- lines.push(...renderGates(row.gates.reports, report.observedAt, context.columns, selection === "contract"));
278
- if (row.holder.kind === "held")
279
- lines.push(...plumbFacts([`task ${row.holder.taskId}`], context.columns));
280
- if (row.holder.kind === "unavailable")
281
- lines.push(...plumbFacts(["holder unavailable"], context.columns));
282
- for (const attached of row.fleet) {
283
- const aliases = attached.aliases.length === 0 ? "" : ` (${attached.aliases.join(" ")})`;
284
- lines.push(...plumbFacts([`akuma ${attached.id}${aliases}`], context.columns));
305
+ lines.push(...semanticBlock("workspace/merge", [...workspaceFacts, ...mergeFacts(row, true, abbreviations)], context));
306
+ const attachments = [...linkedFacts(row, report, "selected")];
307
+ if (row.issue !== undefined) {
308
+ const detail = row.issue.kind === "hook-failure" ? row.issue.diagnostic : `target-checkout-retained ${row.issue.target}`;
309
+ attachments.push(`lag (observed now): ${detail}`);
285
310
  }
286
- if (selection === "contract")
287
- lines.push(...renderNamespaceTasks(row, context));
311
+ lines.push(...semanticBlock("attachments", attachments, context));
312
+ lines.push(...semanticBlock("namespace tasks", namespaceTaskFacts(row), context));
288
313
  return lines;
289
314
  }
315
+ function candidateFacts(row, abbreviations) {
316
+ if (row.delivery === null)
317
+ return [candidateFact(row.delivery)];
318
+ const delivery = row.delivery;
319
+ return [
320
+ `tender ${displayGitId(delivery.tenderSnapshot, abbreviations)}`,
321
+ `integration ${displayGitId(delivery.integration.predecessor, abbreviations)} -> ${displayGitId(delivery.integration.snapshot, abbreviations)}`,
322
+ `method ${delivery.method}`,
323
+ `change ${delivery.integration.changeId}`,
324
+ ];
325
+ }
290
326
  function isTerminalContract(row) {
291
327
  return row.phase === "claimed" || row.phase === "abandoned";
292
328
  }
@@ -294,51 +330,40 @@ function isTerminalTask(row) {
294
330
  return row.disposition === "done" || row.disposition === "drop";
295
331
  }
296
332
  function renderWorldContractRow(row, report, context) {
297
- const hot = contractHot(row);
298
333
  const title = row.title ?? "title unavailable";
299
- const phase = `${row.phase} · ${formatAge(row.phaseAt, report.observedAt)}`;
300
- if (!hot)
301
- return [identityLine(contractMark(row), row.id, `· "${title}" · ${phase} · ${targetFacts(row).join(" · ")}`)];
302
- const lines = [identityLine(contractMark(row), row.id)];
303
- lines.push(...fieldBlock("TITLE", title, context.columns));
304
- lines.push(fieldLine("STATE", phase));
305
- lines.push(fieldLine("GIT", [...targetFacts(row), workspaceState(row)].join(" · ")));
306
- if (showWorkspacePath(row, hot)
307
- && row.workspaceObservation.kind !== "unappointed"
308
- && row.workspaceObservation.kind !== "failed"
309
- && row.workspaceObservation.location.kind === "worktree") {
310
- lines.push(fieldLine("DIR", row.workspaceObservation.location.path));
311
- }
312
- lines.push(...renderWorldGates(row.gates.reports));
313
- const linked = [];
314
- if (row.holder.kind === "held")
315
- linked.push(row.holder.taskId);
316
- if (row.holder.kind === "unavailable")
317
- linked.push("holder unavailable");
318
- for (const attached of row.fleet) {
319
- const aliases = attached.aliases.length === 0 ? "" : ` (${attached.aliases.join(" ")})`;
320
- linked.push(`${attached.id}${aliases}`);
321
- }
322
- if (linked.length > 0) {
323
- lines.push(fieldLine("LINKED", linked[0]));
324
- for (const item of linked.slice(1))
325
- lines.push(` ${" ".repeat(FIELD_WIDTH)}${safeText(item)}`);
326
- }
334
+ const facts = [
335
+ candidateFact(row.delivery),
336
+ ...targetFacts(row),
337
+ ...worldAfterFacts(row),
338
+ ...(row.dependents.length === 0 ? [] : [`dependents ${row.dependents.map(dependentWording).join(" · ")}`]),
339
+ ...row.gates.reports.map(gateFact),
340
+ ...linkedFacts(row, report, "world"),
341
+ ];
342
+ const lines = [
343
+ identityLine(contractMark(row), row.id, `· ${row.phase} · ${formatAge(row.lastJournalAt, report.observedAt)} · ${title}`),
344
+ ];
345
+ lines.push(...plumbFacts(facts, context.columns));
327
346
  return lines;
328
347
  }
329
- function selectRows(rows, isHot) {
330
- return [...rows.filter(isHot), ...rows.filter((row) => !isHot(row))].slice(0, MAX_VISIBLE_ROWS);
331
- }
332
- function sectionFooter(visible, total, unit, selector) {
348
+ function selectRecentRows(rows, timestamp) {
349
+ return [...rows]
350
+ .sort((left, right) => {
351
+ const leftAt = timestamp(left);
352
+ const rightAt = timestamp(right);
353
+ if (leftAt === rightAt)
354
+ return 0;
355
+ return leftAt > rightAt ? -1 : 1;
356
+ })
357
+ .slice(0, MAX_VISIBLE_ROWS);
358
+ }
359
+ function sectionFooter({ visible, total, unit, selector, neutral, }) {
333
360
  if (visible === total)
334
- return [` (all ${total} live ${unit} shown)`];
335
- return [` + ${total - visible} more live ${unit} not shown`, ` keiyaku ls ${selector}/`];
336
- }
337
- function sectionBlock(name, unit, selector, rows, total) {
338
- const lines = [`[ ${name} ] ${total} live`, ""];
339
- for (const row of rows)
340
- lines.push(...row);
341
- lines.push("", ...sectionFooter(rows.length, total, unit, selector));
361
+ return [` (all ${total}${neutral ? "" : " live"} ${unit} shown)`];
362
+ return [` + ${total - visible} more${neutral ? "" : " live"} ${unit} not shown`, ` keiyaku ls ${selector}/`];
363
+ }
364
+ function sectionBlock({ name, unit, selector, rows, total, neutral = false, }) {
365
+ const lines = [`[ ${name} ] ${total}${neutral ? ` ${unit}` : " live"}`, "", ...rows.flat()];
366
+ lines.push("", ...sectionFooter({ visible: rows.length, total, unit, selector, neutral }));
342
367
  return lines;
343
368
  }
344
369
  function renderContracts(report, context) {
@@ -348,8 +373,18 @@ function renderContracts(report, context) {
348
373
  if (section.kind === "failed")
349
374
  return failure("KEIYAKU", section, context);
350
375
  const live = section.value.rows.filter((row) => !isTerminalContract(row));
351
- const rows = selectRows(live, contractHot);
352
- return sectionBlock("KEIYAKU", "keiyaku", "kei", rows.map((row) => renderWorldContractRow(row, report, context)), live.length);
376
+ const rows = selectRecentRows(live, (row) => row.lastJournalAt);
377
+ const abbreviations = gitAbbreviations(report);
378
+ const candidates = live.filter((row) => row.delivery !== null).length;
379
+ const rendered = sectionBlock({
380
+ name: "KEIYAKU",
381
+ unit: "keiyaku",
382
+ selector: "kei",
383
+ rows: rows.map((row) => renderWorldContractRow(row, report, context)),
384
+ total: live.length,
385
+ });
386
+ const header = `[ KEIYAKU ] contract state ${section.value.state === null ? "-" : displayGitId(section.value.state, abbreviations)} · observedAt ${report.observedAt} · ${live.length} live · candidate ${candidates}`;
387
+ return [header, "", ...rendered.slice(1)];
353
388
  }
354
389
  function renderSelectedContract(report, context) {
355
390
  const section = report.contracts;
@@ -358,7 +393,9 @@ function renderSelectedContract(report, context) {
358
393
  if (section.kind === "failed")
359
394
  return [tone(`! ${safeText(section.failure.message)}`, "alert", context.color)];
360
395
  const row = section.value.rows[0];
361
- return row === undefined ? [`${PLUMB}keiyaku absent`] : renderContractRow(row, report, context, "contract");
396
+ return row === undefined
397
+ ? [`${PLUMB}keiyaku absent`]
398
+ : renderSelectedContractRow(row, report, context, gitAbbreviations(report));
362
399
  }
363
400
  function renderTasks(report, context) {
364
401
  const section = report.tasks;
@@ -367,23 +404,16 @@ function renderTasks(report, context) {
367
404
  if (section.kind === "failed")
368
405
  return failure("TASK", section, context);
369
406
  const live = section.value.rows.filter((row) => !isTerminalTask(row));
370
- const rows = selectRows(live, taskHot);
407
+ const rows = selectRecentRows(live, (row) => row.updatedAt);
371
408
  const rowLines = rows.map((row) => {
372
- const compact = !taskHot(row);
373
- const relation = row.contract === undefined
374
- ? ["unbound"]
375
- : [endpointFact(row.contract.id, row.contract.observed)];
376
- if (compact)
377
- return [identityLine(taskMark(row), row.id, `· "${row.title}" · ${row.disposition} · P${row.priority} · ${relation.join(" · ")}`)];
378
- const lines = [identityLine(taskMark(row), row.id)];
379
- lines.push(...fieldBlock("TITLE", row.title, context.columns));
380
- lines.push(fieldLine("STATE", `${row.disposition} · P${row.priority}`));
381
- for (const blocker of row.blockers ?? [])
382
- lines.push(fieldLine("BLOCKED", blocker.id));
383
- lines.push(fieldLine("LINKED", relation.join(" · ")));
409
+ const relation = row.contract === undefined ? ["unbound"] : [endpointFact(row.contract.id, row.contract.observed)];
410
+ const lines = [
411
+ identityLine(taskMark(row), row.id, `· ${row.disposition} · P${row.priority} · ${row.title} · ${relation.join(" · ")}`),
412
+ ];
413
+ lines.push(...plumbFacts((row.blockers ?? []).map((blocker) => `blocked ${blocker.id}`), context.columns));
384
414
  return lines;
385
415
  });
386
- return sectionBlock("TASK", "task", "task", rowLines, live.length);
416
+ return sectionBlock({ name: "TASK", unit: "task", selector: "task", rows: rowLines, total: live.length });
387
417
  }
388
418
  function akumaLabel(row) {
389
419
  const aliases = row.aliases ?? [];
@@ -395,14 +425,7 @@ function renderAkuma(report, context) {
395
425
  return sectionAbsent("FLEET", context.columns);
396
426
  if (section.kind === "failed")
397
427
  return failure("FLEET", section, context);
398
- const live = section.value.rows
399
- .filter((row) => row.life === "running")
400
- .sort((left, right) => {
401
- const l = "lastActivityAt" in left && left.lastActivityAt !== null ? Date.parse(left.lastActivityAt) : -Infinity;
402
- const r = "lastActivityAt" in right && right.lastActivityAt !== null ? Date.parse(right.lastActivityAt) : -Infinity;
403
- return r - l;
404
- });
405
- const rows = live.slice(0, MAX_VISIBLE_ROWS);
428
+ const rows = visibleFleetRows(section.value.rows);
406
429
  const rowLines = rows.map((row) => {
407
430
  const lifeAt = "lifeAt" in row ? row.lifeAt : null;
408
431
  const life = `${row.life} · ${formatAge(lifeAt, report.observedAt)}`;
@@ -412,29 +435,30 @@ function renderAkuma(report, context) {
412
435
  const key = row.life === "stranded" && "strandedReason" in row && row.strandedReason === "resume-unsupported"
413
436
  ? [life, ...activity, "resume unsupported"]
414
437
  : [life, ...activity];
415
- const relation = row.contract === undefined
416
- ? ["unbound"]
417
- : [endpointFact(row.contract.id, row.contract.observed)];
438
+ const relation = row.contract === undefined ? ["unbound"] : [endpointFact(row.contract.id, row.contract.observed)];
418
439
  const snapshot = activitySnapshotLine(row);
419
- if (!akumaHot(row))
420
- return [identityLine(akumaMark(row.life), row.id, `${akumaLabel(row)} · ${[...key, ...relation, ...(snapshot === undefined ? [] : [snapshot])].join(" · ")}`.trim())];
421
- const lines = [identityLine(akumaMark(row.life), row.id, akumaLabel(row))];
422
- lines.push(fieldLine("LIFE", key.join(" · ")));
423
- if (snapshot !== undefined)
424
- lines.push(fieldLine("SNAPSHOT", snapshot));
425
- lines.push(fieldLine("LINKED", relation.join(" · ")));
426
- return lines;
440
+ const prefix = `${akumaLabel(row)} · ${[...key, ...relation].join(" · ")}`.trim();
441
+ return renderColdFleetLine(row, prefix, snapshot, context.columns);
442
+ });
443
+ return sectionBlock({
444
+ name: "FLEET",
445
+ unit: "akuma",
446
+ selector: "aku",
447
+ rows: rowLines,
448
+ total: section.value.rows.length,
449
+ neutral: true,
427
450
  });
428
- return sectionBlock("FLEET", "akuma", "aku", rowLines, live.length);
429
451
  }
430
452
  export function renderKanshiText(report, context = { columns: 80, color: false }, selection = "world") {
431
453
  if (selection === "contract")
432
454
  return renderSelectedContract(report, context).join("\n");
433
455
  return [
434
456
  ...renderContracts(report, context),
435
- "", "",
457
+ "",
458
+ "",
436
459
  ...renderAkuma(report, context),
437
- "", "",
460
+ "",
461
+ "",
438
462
  ...renderTasks(report, context),
439
463
  ].join("\n");
440
464
  }
@@ -64,11 +64,7 @@ function prerequisiteRows(stop, columns) {
64
64
  return [];
65
65
  const lines = [];
66
66
  for (const prerequisite of stop.refusal.unmet) {
67
- receiptRow(lines, " ", "prerequisite", [
68
- { text: prerequisite.contractId, opaque: true },
69
- { text: "·" },
70
- { text: prerequisite.state },
71
- ], columns);
67
+ receiptRow(lines, " ", "prerequisite", [{ text: prerequisite.contractId, opaque: true }, { text: "·" }, { text: prerequisite.state }], columns);
72
68
  }
73
69
  return lines;
74
70
  }
@@ -136,10 +132,7 @@ export function cleanupLines(cleanup, columns) {
136
132
  }
137
133
  export function leakLines(leak, columns) {
138
134
  const lines = [];
139
- receiptRow(lines, "!", "leak", [
140
- { text: "worktree" },
141
- { text: leak.path, opaque: true },
142
- ], columns);
135
+ receiptRow(lines, "!", "leak", [{ text: "worktree" }, { text: leak.path, opaque: true }], columns);
143
136
  receiptPayload(lines, "diagnostic", leak.diagnostic);
144
137
  return lines;
145
138
  }