@astrosheep/keiyaku 4.6.8 → 4.6.9

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 (253) hide show
  1. package/README.md +40 -14
  2. package/build/plugins/claude/.claude-plugin/plugin.json +1 -1
  3. package/build/plugins/claude/skills/keiyaku/SKILL.md +5 -6
  4. package/build/plugins/claude/skills/keiyaku-akuma/SKILL.md +1 -1
  5. package/build/plugins/claude/skills/keiyaku-akuma/references/automation.md +8 -8
  6. package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
  7. package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +9 -9
  8. package/build/plugins/claude/skills/keiyaku-debt/SKILL.md +91 -0
  9. package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +2 -2
  10. package/build/plugins/codex/.codex-plugin/plugin.json +1 -1
  11. package/build/plugins/codex/skills/keiyaku/SKILL.md +5 -6
  12. package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +1 -1
  13. package/build/plugins/codex/skills/keiyaku-akuma/references/automation.md +8 -8
  14. package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
  15. package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +9 -9
  16. package/build/plugins/codex/skills/keiyaku-debt/SKILL.md +91 -0
  17. package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +2 -2
  18. package/build/plugins/opencode/index.js +1 -1
  19. package/build/plugins/opencode/skills/keiyaku/SKILL.md +5 -6
  20. package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +1 -1
  21. package/build/plugins/opencode/skills/keiyaku-akuma/references/automation.md +8 -8
  22. package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
  23. package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +9 -9
  24. package/build/plugins/opencode/skills/keiyaku-debt/SKILL.md +91 -0
  25. package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +2 -2
  26. package/build/skills/keiyaku/SKILL.md +5 -6
  27. package/build/skills/keiyaku-akuma/SKILL.md +1 -1
  28. package/build/skills/keiyaku-akuma/references/automation.md +8 -8
  29. package/build/skills/keiyaku-babysit/SKILL.md +1 -1
  30. package/build/skills/keiyaku-bind/SKILL.md +9 -9
  31. package/build/skills/keiyaku-debt/SKILL.md +91 -0
  32. package/build/skills/keiyaku-workflow/SKILL.md +2 -2
  33. package/build/src/akuma/akuma-instance.d.ts +2 -0
  34. package/build/src/akuma/akuma-instance.js +10 -0
  35. package/build/src/akuma/akuma-observe.d.ts +33 -8
  36. package/build/src/akuma/akuma-observe.js +88 -64
  37. package/build/src/akuma/akuma-owner.d.ts +11 -2
  38. package/build/src/akuma/akuma-owner.js +45 -35
  39. package/build/src/akuma/akuma-selection-execution.js +9 -1
  40. package/build/src/akuma/akuma-stream.d.ts +22 -0
  41. package/build/src/akuma/akuma-stream.js +116 -0
  42. package/build/src/akuma/akuma-wait.d.ts +1 -40
  43. package/build/src/akuma/akuma-wait.js +23 -84
  44. package/build/src/akuma/akuma.d.ts +17 -11
  45. package/build/src/akuma/akuma.js +2 -0
  46. package/build/src/akuma/allowed.d.ts +7 -12
  47. package/build/src/akuma/allowed.js +13 -4
  48. package/build/src/akuma/body-supervisor.d.ts +5 -5
  49. package/build/src/akuma/body-supervisor.js +22 -20
  50. package/build/src/akuma/body.js +28 -1
  51. package/build/src/akuma/call-request.d.ts +12 -22
  52. package/build/src/akuma/heart/activity-schema.d.ts +12 -0
  53. package/build/src/akuma/heart/activity-schema.js +6 -0
  54. package/build/src/akuma/heart/index.d.ts +59 -2
  55. package/build/src/akuma/heart/index.js +87 -8
  56. package/build/src/akuma/heart/rows.js +5 -3
  57. package/build/src/akuma/heart/soul.d.ts +9 -0
  58. package/build/src/akuma/heart/soul.js +29 -0
  59. package/build/src/akuma/heart/storage.d.ts +15 -0
  60. package/build/src/akuma/heart/storage.js +55 -0
  61. package/build/src/akuma/heart/timeline.d.ts +7 -0
  62. package/build/src/akuma/heart/timeline.js +10 -0
  63. package/build/src/akuma/index.d.ts +1 -0
  64. package/build/src/akuma/projection.d.ts +25 -0
  65. package/build/src/akuma/projection.js +24 -7
  66. package/build/src/akuma/provider-recipe.d.ts +11 -0
  67. package/build/src/akuma/provider-recipe.js +23 -0
  68. package/build/src/akuma/provider.d.ts +25 -0
  69. package/build/src/akuma/provider.js +99 -7
  70. package/build/src/akuma/providers/acp/events.js +25 -2
  71. package/build/src/akuma/providers/claude/events.js +76 -10
  72. package/build/src/akuma/providers/claude/index.js +2 -5
  73. package/build/src/akuma/providers/codex-app-server/events.js +17 -2
  74. package/build/src/akuma/providers/codex-app-server/index.js +15 -9
  75. package/build/src/akuma/providers/decode.d.ts +8 -0
  76. package/build/src/akuma/providers/decode.js +21 -0
  77. package/build/src/akuma/providers/grok-build/index.js +10 -26
  78. package/build/src/akuma/providers/opencode-sdk/event-stream.d.ts +3 -3
  79. package/build/src/akuma/providers/opencode-sdk/event-stream.js +2 -25
  80. package/build/src/akuma/providers/opencode-sdk/events.d.ts +7 -43
  81. package/build/src/akuma/providers/opencode-sdk/events.js +147 -284
  82. package/build/src/akuma/providers/opencode-sdk/index.js +267 -421
  83. package/build/src/akuma/providers/opencode-sdk/native-http.d.ts +9 -0
  84. package/build/src/akuma/providers/opencode-sdk/native-http.js +69 -0
  85. package/build/src/akuma/providers/opencode-sdk/session.d.ts +42 -36
  86. package/build/src/akuma/providers/opencode-sdk/session.js +75 -82
  87. package/build/src/akuma/providers/paseo/events.d.ts +8 -0
  88. package/build/src/akuma/providers/paseo/events.js +58 -11
  89. package/build/src/akuma/providers/paseo/index.js +11 -7
  90. package/build/src/akuma/providers/pi/events.d.ts +2 -0
  91. package/build/src/akuma/providers/pi/events.js +32 -24
  92. package/build/src/akuma/providers/pi/index.js +21 -35
  93. package/build/src/akuma/request-lifecycle.d.ts +1 -2
  94. package/build/src/akuma/request-lifecycle.js +2 -8
  95. package/build/src/akuma/request-rendezvous.js +38 -55
  96. package/build/src/akuma/request-serve.d.ts +1 -1
  97. package/build/src/akuma/request-serve.js +77 -113
  98. package/build/src/akuma/selection-observation.d.ts +57 -51
  99. package/build/src/akuma/selection-observation.js +3 -3
  100. package/build/src/akuma/turn-drive.d.ts +3 -0
  101. package/build/src/akuma/turn-drive.js +26 -5
  102. package/build/src/akuma-body.js +12 -22
  103. package/build/src/cli/akuma-caller.js +10 -0
  104. package/build/src/cli/commands/akuma-grammar.js +3 -4
  105. package/build/src/cli/commands/akuma.js +13 -51
  106. package/build/src/cli/commands/contract-grammar.d.ts +7 -6
  107. package/build/src/cli/commands/contract-grammar.js +27 -32
  108. package/build/src/cli/commands/contract-help.d.ts +16 -7
  109. package/build/src/cli/commands/contract-help.js +20 -11
  110. package/build/src/cli/commands/contract.js +11 -11
  111. package/build/src/cli/commands/debt-grammar.d.ts +19 -0
  112. package/build/src/cli/commands/debt-grammar.js +323 -0
  113. package/build/src/cli/commands/debt-query.d.ts +5 -0
  114. package/build/src/cli/commands/{task-query.js → debt-query.js} +9 -9
  115. package/build/src/cli/commands/{task.d.ts → debt.d.ts} +2 -2
  116. package/build/src/cli/commands/{task.js → debt.js} +83 -143
  117. package/build/src/cli/coordinates.d.ts +1 -1
  118. package/build/src/cli/coordinates.js +1 -1
  119. package/build/src/cli/parse.d.ts +4 -4
  120. package/build/src/cli/parse.js +17 -16
  121. package/build/src/cli/render/akuma-activity.d.ts +11 -83
  122. package/build/src/cli/render/akuma-activity.js +20 -382
  123. package/build/src/cli/render/catalog.d.ts +2 -2
  124. package/build/src/cli/render/catalog.js +5 -5
  125. package/build/src/cli/render/contract.js +2 -2
  126. package/build/src/cli/render/debt.d.ts +28 -0
  127. package/build/src/cli/render/{task.js → debt.js} +51 -112
  128. package/build/src/cli/render/kanshi.js +28 -28
  129. package/build/src/cli/render/marks.d.ts +5 -5
  130. package/build/src/cli/render/marks.js +4 -10
  131. package/build/src/cli/render/nuke.js +1 -1
  132. package/build/src/cli/runtime.js +3 -3
  133. package/build/src/cli/scan.d.ts +1 -1
  134. package/build/src/cli/usage.d.ts +1 -1
  135. package/build/src/cli/usage.js +4 -4
  136. package/build/src/contract-worktree.js +3 -3
  137. package/build/src/debt/board.d.ts +160 -0
  138. package/build/src/{task → debt}/board.js +89 -89
  139. package/build/src/debt/catalog.d.ts +11 -0
  140. package/build/src/debt/catalog.js +59 -0
  141. package/build/src/{task → debt}/context.d.ts +1 -1
  142. package/build/src/{task → debt}/context.js +1 -1
  143. package/build/src/{task → debt}/created-observation.d.ts +6 -10
  144. package/build/src/{task → debt}/created-observation.js +7 -7
  145. package/build/src/debt/document.d.ts +37 -0
  146. package/build/src/{task → debt}/document.js +37 -37
  147. package/build/src/debt/identity.d.ts +21 -0
  148. package/build/src/{task → debt}/identity.js +35 -35
  149. package/build/src/debt/index.d.ts +111 -0
  150. package/build/src/debt/index.js +203 -0
  151. package/build/src/{task → debt}/input.d.ts +8 -8
  152. package/build/src/{task → debt}/input.js +21 -21
  153. package/build/src/debt/lifecycle-operations.d.ts +6 -0
  154. package/build/src/{task → debt}/lifecycle-operations.js +27 -31
  155. package/build/src/debt/mutation-result.d.ts +981 -0
  156. package/build/src/debt/mutation-result.js +109 -0
  157. package/build/src/debt/mutation.d.ts +424 -0
  158. package/build/src/debt/mutation.js +223 -0
  159. package/build/src/debt/operation-types.d.ts +71 -0
  160. package/build/src/debt/operations.d.ts +28 -0
  161. package/build/src/{task → debt}/operations.js +59 -60
  162. package/build/src/debt/query.d.ts +76 -0
  163. package/build/src/{task → debt}/query.js +55 -55
  164. package/build/src/{task → debt}/store.d.ts +13 -13
  165. package/build/src/{task → debt}/store.js +58 -49
  166. package/build/src/debt/view.d.ts +4 -0
  167. package/build/src/debt/view.js +7 -0
  168. package/build/src/identity/coordinates.d.ts +1 -1
  169. package/build/src/index.d.ts +13 -13
  170. package/build/src/index.js +9 -9
  171. package/build/src/kanshi/index.d.ts +1 -1
  172. package/build/src/kanshi/read.js +33 -33
  173. package/build/src/kanshi/report.d.ts +7 -7
  174. package/build/src/kanshi/select.js +4 -4
  175. package/build/src/library/akumas.d.ts +2 -3
  176. package/build/src/library/bind.d.ts +3 -3
  177. package/build/src/library/bind.js +5 -5
  178. package/build/src/library/contract-creation.js +5 -5
  179. package/build/src/library/contract-execution.js +4 -4
  180. package/build/src/library/contract-types.d.ts +2 -2
  181. package/build/src/library/input.d.ts +2 -2
  182. package/build/src/library/input.js +5 -5
  183. package/build/src/library/invocation.js +2 -2
  184. package/build/src/library/nuke.js +3 -3
  185. package/build/src/library/outcome.d.ts +126 -126
  186. package/build/src/library/outcome.js +3 -3
  187. package/build/src/library/selection.d.ts +1 -4
  188. package/build/src/library/selection.js +11 -62
  189. package/build/src/plugin/public.d.ts +5 -0
  190. package/build/src/plugin/runtime.js +3 -1
  191. package/build/src/runtime/proc/windows-launch.exe +0 -0
  192. package/build/src/settlement/fence.d.ts +3 -3
  193. package/build/src/settlement/fence.js +4 -4
  194. package/build/src/settlement/holder.d.ts +16 -16
  195. package/build/src/settlement/holder.js +69 -63
  196. package/build/src/settlement/settle.d.ts +5 -5
  197. package/build/src/settlement/settle.js +53 -53
  198. package/package.json +12 -6
  199. package/plugins/paseo/plugin/index.server.ts +17 -0
  200. package/plugins/paseo/plugin/paseo-plugin.json +4 -0
  201. package/plugins/paseo/plugin/server/attach.ts +52 -0
  202. package/plugins/paseo/plugin/server/keiyaku.ts +44 -0
  203. package/plugins/paseo/plugin/server/message.ts +60 -0
  204. package/plugins/paseo/plugin/server/mirror.ts +193 -0
  205. package/plugins/paseo/plugin/server/model.ts +14 -0
  206. package/plugins/paseo/plugin/server/provider.ts +276 -0
  207. package/plugins/paseo/plugin/server/sdk-worker.ts +237 -0
  208. package/plugins/paseo/plugin/server/sdk.ts +289 -0
  209. package/plugins/paseo/plugin/server/stop.ts +26 -0
  210. package/plugins/paseo/plugin/server/transport.ts +35 -0
  211. package/plugins/paseo/plugin/shared/attach-rpc.ts +10 -0
  212. package/plugins/paseo/plugin/shared/refresh-rpc.ts +6 -0
  213. package/plugins/paseo/plugin/tsconfig.json +6 -0
  214. package/skills/keiyaku/SKILL.md +5 -6
  215. package/skills/keiyaku-akuma/SKILL.md +1 -1
  216. package/skills/keiyaku-akuma/references/automation.md +8 -8
  217. package/skills/keiyaku-babysit/SKILL.md +1 -1
  218. package/skills/keiyaku-bind/SKILL.md +9 -9
  219. package/skills/keiyaku-debt/SKILL.md +91 -0
  220. package/skills/keiyaku-workflow/SKILL.md +2 -2
  221. package/build/plugins/claude/skills/keiyaku-task/SKILL.md +0 -104
  222. package/build/plugins/codex/skills/keiyaku-task/SKILL.md +0 -104
  223. package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +0 -104
  224. package/build/skills/keiyaku-task/SKILL.md +0 -104
  225. package/build/src/cli/commands/task-grammar.d.ts +0 -19
  226. package/build/src/cli/commands/task-grammar.js +0 -384
  227. package/build/src/cli/commands/task-query.d.ts +0 -5
  228. package/build/src/cli/render/task.d.ts +0 -39
  229. package/build/src/task/board.d.ts +0 -168
  230. package/build/src/task/catalog.d.ts +0 -11
  231. package/build/src/task/catalog.js +0 -59
  232. package/build/src/task/compose-language.d.ts +0 -57
  233. package/build/src/task/compose-language.js +0 -364
  234. package/build/src/task/compose-parser.d.ts +0 -32
  235. package/build/src/task/compose-parser.js +0 -180
  236. package/build/src/task/compose.d.ts +0 -16
  237. package/build/src/task/compose.js +0 -189
  238. package/build/src/task/document.d.ts +0 -39
  239. package/build/src/task/identity.d.ts +0 -21
  240. package/build/src/task/index.d.ts +0 -138
  241. package/build/src/task/index.js +0 -269
  242. package/build/src/task/lifecycle-operations.d.ts +0 -6
  243. package/build/src/task/mutation-result.d.ts +0 -1726
  244. package/build/src/task/mutation-result.js +0 -198
  245. package/build/src/task/mutation.d.ts +0 -590
  246. package/build/src/task/mutation.js +0 -262
  247. package/build/src/task/operation-types.d.ts +0 -71
  248. package/build/src/task/operations.d.ts +0 -28
  249. package/build/src/task/query.d.ts +0 -76
  250. package/build/src/task/view.d.ts +0 -4
  251. package/build/src/task/view.js +0 -7
  252. package/skills/keiyaku-task/SKILL.md +0 -104
  253. /package/build/src/{task → debt}/operation-types.js +0 -0
@@ -2,9 +2,8 @@ import type { AkumaStatus } from "../../akuma/akuma.js";
2
2
  import type { KillEvidence } from "../../akuma/heart/index.js";
3
3
  import type { ActivityRow } from "../../akuma/projection.js";
4
4
  import type { AkumaAskObservation, AkumaAskResult, AkumaTellResult, AkumaWaitResult } from "../../akuma/selection-observation.js";
5
- import type { AkumaObservation, CreatedTaskObservation, DispatchAssociation } from "../../index.js";
5
+ import type { AkumaObservation, CreatedDebtObservation, DispatchAssociation } from "../../index.js";
6
6
  import type { CallObservation, CallResult } from "../../library/akuma-creation.js";
7
- import type { WaitObservedAkuma } from "../../library/akumas.js";
8
7
  import type { AkumaHistoryResult } from "../../library/selection.js";
9
8
  import { type TextRenderContext } from "./terminal.js";
10
9
  export declare const DEFAULT_CONTEXT: TextRenderContext;
@@ -14,10 +13,6 @@ export declare const DEFAULT_CONTEXT: TextRenderContext;
14
13
  */
15
14
  export declare function frameRule(headLines: readonly string[]): string;
16
15
  type StatusTimeline = AkumaObservation["status"]["timeline"];
17
- type StatusTimelineEntry = StatusTimeline["entries"][number];
18
- type RenderRow = ActivityRow | Extract<StatusTimelineEntry, {
19
- kind: "row";
20
- }>["row"];
21
16
  type RenderedSnapshot = StatusTimeline;
22
17
  type RenderedActivity = Readonly<{
23
18
  snapshot: RenderedSnapshot;
@@ -26,9 +21,7 @@ type RenderedActivity = Readonly<{
26
21
  export declare function associatedIdentity(id: string, alias?: string, contract?: DispatchAssociation): string;
27
22
  export declare function snapshotHeading(id: string, alias: string | undefined, contract: DispatchAssociation | undefined): readonly string[];
28
23
  /**
29
- * The one place row prefixes live: time, optional source, mark, verb, content.
30
- * A plain layout is the single-target grammar; a source layout adds the frozen
31
- * source column a plural wait aligns across its selected set.
24
+ * The one place row prefixes live: time, mark, verb, content.
32
25
  */
33
26
  type RowLayout = Readonly<{
34
27
  head: (time: string | undefined, glyph: string, verb: string, columns: number) => string;
@@ -36,14 +29,10 @@ type RowLayout = Readonly<{
36
29
  marker: (count: number) => string;
37
30
  history?: true;
38
31
  compactRun?: true;
39
- /** Plural wait keeps ordinary rows on one line; speech can use its two-line budget. */
32
+ /** A one-row receipt keeps that row on one line; speech can use its two-line budget. */
40
33
  singleLine?: true;
41
34
  /** World-board answer previews keep the conclusion at the tail. */
42
35
  tailAnswer?: true;
43
- /** A plural wait shares one minute clock across all of its attributed rows. */
44
- clock?: {
45
- previous?: string;
46
- };
47
36
  }>;
48
37
  /**
49
38
  * Shared snapshot activity rendering. Full snapshots render the selected
@@ -56,29 +45,12 @@ export declare function snapshotActivityLines(snapshot: RenderedSnapshot, contex
56
45
  }>): readonly string[];
57
46
  /** One command's append-only activity view, with a baseline and a final tail flush. */
58
47
  export type ActivityStream = ((activity: RenderedActivity) => readonly string[]) & Readonly<{
59
- /** Establish a wait baseline without spending the command's live tool budget. */
48
+ /** Establish a live baseline without spending the command's live tool budget. */
60
49
  seed: (activity: RenderedActivity, alreadyRenderedSequence?: number) => readonly string[];
61
50
  /** Current live rows for the redrawable frame; never part of append-only output. */
62
51
  frame: () => readonly string[];
63
52
  /** Emit the pending omission count and unsettled rows once before the command's conclusion. */
64
53
  flush: () => readonly string[];
65
- /** The same decisions undrawn, so concurrent streams can merge before rendering. */
66
- emissions: Readonly<{
67
- observe: (activity: RenderedActivity) => readonly StreamEmission[];
68
- seed: (activity: RenderedActivity, alreadyRenderedSequence?: number) => readonly StreamEmission[];
69
- flush: () => readonly StreamEmission[];
70
- }>;
71
- render: (emissions: readonly StreamEmission[]) => readonly string[];
72
- }>;
73
- /** One decided piece of append-only output: a settled row, or an untimed omission count. */
74
- export type StreamEmission = Readonly<{
75
- kind: "gap";
76
- count: number;
77
- }> | Readonly<{
78
- kind: "row";
79
- row: RenderRow;
80
- inFlightSay?: boolean;
81
- unsettled?: boolean;
82
54
  }>;
83
55
  /**
84
56
  * Append-only live view over one command's successive settled snapshots.
@@ -87,54 +59,12 @@ export type StreamEmission = Readonly<{
87
59
  * always print.
88
60
  */
89
61
  export declare function activityStream(context: TextRenderContext, layout?: RowLayout): ActivityStream;
90
- /** What a wait conclusion renders over: its observed and unobserved members. */
91
- export type WaitConclusionResult = Readonly<{
92
- reason: "completed" | "deadline";
93
- observations: readonly AkumaObservation[];
94
- unobserved: readonly Readonly<{
95
- id: string;
96
- diagnostic: string;
97
- }>[];
98
- }>;
99
- /** One selected Akuma's frozen identity, resolved before the first observation round. */
100
- export type WaitSelectedIdentity = Readonly<{
101
- id: string;
102
- alias?: string;
103
- contract?: DispatchAssociation;
104
- }>;
105
- export type WaitObservationStream = Readonly<{
106
- /** Freeze the selected set's identities so the source column is stable before the first row. */
107
- select: (selected: readonly WaitSelectedIdentity[]) => void;
108
- /** One observation round; returns the head frames and newly settled rows to print. */
109
- observe: (observed: readonly WaitObservedAkuma[]) => readonly string[];
110
- /** Current live rows from all selected streams; never part of append-only output. */
111
- frame: () => readonly string[];
112
- /** In-flight rows with their unresolved marks, emitted by a close that never concluded. */
113
- flush: () => readonly string[];
114
- /** The wait's closing scoreboard, or the empty string when there is nothing to print. */
115
- conclude: (result: WaitConclusionResult) => string;
116
- streamed: () => boolean;
117
- }>;
118
62
  export declare function inputWaitConclusion(observation: AkumaAskObservation, input: Readonly<{
119
63
  startedAt: number;
120
64
  completedAt?: string | null;
121
65
  now?: number;
122
66
  status?: AkumaStatus;
123
67
  }>): readonly string[];
124
- /**
125
- * Live view over a wait's successive observation rounds, one append-only
126
- * stream per selected Akuma. A plural wait opens one aggregate frame naming
127
- * its selected set before any activity row and never opens a per-target frame
128
- * during observation; a single-target wait opens that Akuma's own identity
129
- * frame — the identity and Contract association the observed facts carry —
130
- * and an already settled Akuma prints that frame while replaying no backlog
131
- * rows. `conclude` renders the closing rows once the wait ends: one row per
132
- * observed Akuma in `<clock> <mark> <verb> — <duration>` grammar, with a target
133
- * named for a multi-target scoreboard and no activity replay.
134
- */
135
- export declare function waitObservationStream(context: TextRenderContext, options?: Readonly<{
136
- now?: () => number;
137
- }>): WaitObservationStream;
138
68
  /** The identity a streamed observing call's head frame renders from its resolved birth. */
139
69
  export type ObservedCallHead = Readonly<{
140
70
  id: string;
@@ -190,7 +120,7 @@ export declare function callObservationStream(context: TextRenderContext, head:
190
120
  type SnapshotView = Readonly<{
191
121
  status: AkumaObservation["status"];
192
122
  contract: DispatchAssociation;
193
- createdTasks?: CreatedTaskObservation;
123
+ createdDebts?: CreatedDebtObservation;
194
124
  }>;
195
125
  type SnapshotCoreOptions = Readonly<{
196
126
  alias?: string;
@@ -199,21 +129,19 @@ type SnapshotCoreOptions = Readonly<{
199
129
  }>;
200
130
  export declare function snapshotText(view: SnapshotView, context: TextRenderContext, options?: SnapshotCoreOptions): string;
201
131
  export declare function killResultText(id: string, evidence: KillEvidence, alias?: string): string;
202
- export declare function statusAnswer(view: Readonly<{
203
- status: AkumaObservation["status"];
204
- }>): string | undefined;
205
132
  /** Presentation-only state for one akuma invocation; it never reaches JSON. */
206
133
  type AkumaPresentation = Readonly<{
207
134
  alias?: string;
208
- streamed?: boolean;
209
- structured?: boolean;
210
- startedAt?: number;
211
- selection?: readonly WaitSelectedIdentity[];
212
135
  }>;
213
136
  export declare function askRawAnswer(result: AkumaAskResult, structured: boolean | undefined): string | undefined;
214
137
  export declare function callRawAnswer(result: CallResult, streamed: boolean): string | undefined;
215
- export declare function waitRawAnswer(result: AkumaWaitResult, streamed: boolean): string | undefined;
216
138
  export declare function historyRawAnswer(result: AkumaHistoryResult, historyId: string | undefined): string | undefined;
139
+ /**
140
+ * One wait's final text: each observed Akuma's own status snapshot, then one
141
+ * failure fact per member the wait could not read. A wait observes to its
142
+ * completion judgment and streams nothing, so an answer is visible only as the
143
+ * snapshot's own outcome row.
144
+ */
217
145
  export declare function waitText(result: AkumaWaitResult, presentation: AkumaPresentation, context: TextRenderContext): string;
218
146
  export declare function historyText(result: AkumaHistoryResult, presentation: AkumaPresentation & Readonly<{
219
147
  id?: string;
@@ -1,6 +1,6 @@
1
1
  import { defaultWaitComplete } from "../../akuma/akuma-observe.js";
2
2
  import { renderDiffstat, toolContent, toolRepr } from "./akuma-tool.js";
3
- import { taskDispositionMark } from "./marks.js";
3
+ import { debtDispositionMark } from "./marks.js";
4
4
  import { DEFAULT_CLI_COLUMNS, displayColumns, padToDisplay, renderBoundedPayload, renderBoundedTextBlock, safeText, takeDisplayColumns, takeDisplayColumnsFromEnd, truncateDisplayText, truncateMiddleDisplayText, } from "./terminal.js";
5
5
  export const DEFAULT_CONTEXT = { columns: DEFAULT_CLI_COLUMNS, color: false };
6
6
  const TIME_WIDTH = 5;
@@ -30,10 +30,6 @@ export function snapshotHeading(id, alias, contract) {
30
30
  const head = [identity(id, alias), ...(contractId === undefined ? [] : [`└─ ${contractId}`])];
31
31
  return [...head, frameRule(head)];
32
32
  }
33
- function answeredHeading(id, alias) {
34
- const heading = `✓ answered ${identity(id, alias)}`;
35
- return [heading, frameRule([heading])];
36
- }
37
33
  function contractFacts(contract) {
38
34
  return contract.kind === "failed" ? [`! contract failed ${safeText(contract.diagnostic)}`] : [];
39
35
  }
@@ -145,16 +141,6 @@ function compactLayout() {
145
141
  function historyLayout() {
146
142
  return { ...compactLayout(), history: true };
147
143
  }
148
- function sourceLayout(source, width, clock) {
149
- const gutter = () => `${" ".repeat(TIME_WIDTH)} ${padToDisplay(source, width())} `;
150
- return {
151
- head: (time, glyph, verb, columns) => actionCell(`${time === undefined ? " ".repeat(TIME_WIDTH) : time.padEnd(TIME_WIDTH)} ${padToDisplay(source, width())} ${glyph}`, verb, columns),
152
- continuation: () => `${" ".repeat(TIME_WIDTH)} ${" ".repeat(width())} │ ${" ".repeat(VERB_WIDTH)} `,
153
- marker: (count) => `${gutter()}⋮ ${count} omitted`,
154
- clock,
155
- singleLine: true,
156
- };
157
- }
158
144
  function quotedBody(row) {
159
145
  return (row.kind === "said" ||
160
146
  row.kind === "thought" ||
@@ -408,16 +394,12 @@ function baselineOmissionCount(activity, after, before) {
408
394
  function renderStreamRow(state, row, lines, options) {
409
395
  const { context, layout, inFlightSay = false, unsettled = false } = options;
410
396
  const at = clock(row.at);
411
- const previousClock = layout.clock?.previous ?? state.previousClock;
412
- const changed = previousClock === undefined || at !== previousClock;
397
+ const changed = state.previousClock === undefined || at !== state.previousClock;
413
398
  lines.push(...renderTimelineRow(row, context, layout, changed ? at : undefined, {
414
399
  inFlightSay,
415
400
  unsettled,
416
401
  }));
417
- if (layout.clock !== undefined)
418
- layout.clock.previous = at;
419
- else
420
- state.previousClock = at;
402
+ state.previousClock = at;
421
403
  }
422
404
  /**
423
405
  * A say is in-flight only while it is the newest row of the open turn: it may still be streaming, so it
@@ -598,12 +580,6 @@ export function activityStream(context, layout = plainLayout()) {
598
580
  seed: (activity, alreadyRenderedSequence) => render(seed(activity, alreadyRenderedSequence)),
599
581
  frame,
600
582
  flush: () => render(flush()),
601
- emissions: {
602
- observe: (activity) => observeActivitySnapshot(state, activity),
603
- seed,
604
- flush,
605
- },
606
- render,
607
583
  });
608
584
  }
609
585
  function conclusionMarkVerb(status, outcome) {
@@ -630,18 +606,6 @@ function conclusionMarkVerb(status, outcome) {
630
606
  return { mark: "!", verb: "untidy" };
631
607
  return { mark: "!", verb: "stranded" };
632
608
  }
633
- /**
634
- * The durable moment an Akuma settled, read from the outcome row its own timeline
635
- * retained. Absent for an ending that leaves no outcome row, so the caller falls
636
- * back to the observation that noticed it.
637
- */
638
- function settleMoment(status) {
639
- const outcome = status.timeline.kind === "idle" ? status.timeline.outcome : undefined;
640
- if (outcome === undefined)
641
- return undefined;
642
- const at = new Date(outcome.at).getTime();
643
- return Number.isFinite(at) ? at : undefined;
644
- }
645
609
  function clockFromMs(at) {
646
610
  return clock(new Date(at).toISOString());
647
611
  }
@@ -651,156 +615,6 @@ function durationText(durationMs) {
651
615
  return `${seconds}s`;
652
616
  return `${Math.floor(seconds / 60)}m${String(seconds % 60)}s`;
653
617
  }
654
- function createWaitObservationState() {
655
- return {
656
- streams: new Map(),
657
- sources: new Map(),
658
- tags: new Map(),
659
- contracts: new Map(),
660
- settledAt: new Map(),
661
- sourceWidth: 0,
662
- clock: {},
663
- plural: undefined,
664
- headerEmitted: false,
665
- observed: false,
666
- };
667
- }
668
- function shortestUniquePrefix(value, values) {
669
- for (let length = 4; length <= value.length; length += 1) {
670
- const tag = value.slice(0, length);
671
- if (values.filter((candidate) => candidate.slice(0, length) === tag).length === 1)
672
- return tag;
673
- }
674
- return undefined;
675
- }
676
- function shortestUniqueSegmentSuffix(id, ids) {
677
- const segments = id.split("/");
678
- for (let start = segments.length - 2; start >= 0; start -= 1) {
679
- const tag = segments.slice(start).join("/");
680
- if (ids.filter((candidate) => candidate.endsWith(`/${tag}`) || candidate === tag).length === 1)
681
- return tag;
682
- }
683
- return undefined;
684
- }
685
- function waitIdentityTag(id, ids) {
686
- const finals = ids.map((candidate) => candidate.slice(candidate.lastIndexOf("/") + 1));
687
- const index = ids.indexOf(id);
688
- const own = finals[index];
689
- if (own === undefined)
690
- return id;
691
- return (shortestUniquePrefix(own, finals) ?? shortestUniqueSegmentSuffix(id, ids) ?? shortestUniquePrefix(id, ids) ?? id);
692
- }
693
- /** The selected set fixes identity tags before its first attributed row. */
694
- function freezeWaitTags(state) {
695
- const ids = [...state.sources.keys()];
696
- state.tags = new Map(ids.map((id) => [id, waitIdentityTag(id, ids)]));
697
- state.sourceWidth = Math.max(0, ...Array.from(state.tags.values(), displayColumns));
698
- }
699
- function sourceTag(state, id) {
700
- return state.tags.get(id) ?? waitIdentityTag(id, [...state.sources.keys()]);
701
- }
702
- /** Register one selected or newly observed source; the set freezes the column before the first row. */
703
- function registerWaitSource(state, id, alias, contract) {
704
- if (state.sources.has(id))
705
- return;
706
- const label = alias ?? id;
707
- state.sources.set(id, label);
708
- if (contract !== undefined)
709
- state.contracts.set(id, contract);
710
- }
711
- /**
712
- * The one aggregate head a plural wait prints before any activity row: the
713
- * selected set read as a list, each target on its own line named by the alias
714
- * addressing it, otherwise its complete identity, with its `· kei/<contract>`
715
- * association inline when one exists, all closed by the frame's single rule.
716
- */
717
- function aggregateHeading(state) {
718
- const head = [...state.sources].map(([id, label]) => {
719
- const contractId = associatedContractId(state.contracts.get(id) ?? { kind: "none" });
720
- const named = `${sourceTag(state, id)} ${label}`;
721
- return contractId === undefined ? named : `${named} · ${contractId}`;
722
- });
723
- return [...head, frameRule(head)];
724
- }
725
- function observeWaitRound(state, round, context, now) {
726
- state.observed = true;
727
- // Establish the whole round's sources before any row so widths stay aligned within it.
728
- for (const member of round)
729
- registerWaitSource(state, member.status.id, member.alias, member.contract);
730
- if (!state.headerEmitted)
731
- freezeWaitTags(state);
732
- const lines = [];
733
- // The observation subject opens once: an aggregate head for a plural set, the observed
734
- // identity frame for a single target. Every later round only appends attributed rows.
735
- if (!state.headerEmitted && round.length > 0) {
736
- state.headerEmitted = true;
737
- state.plural ??= state.sources.size > 1;
738
- if (state.plural) {
739
- lines.push(...aggregateHeading(state));
740
- }
741
- else {
742
- const sole = round[0];
743
- lines.push(...snapshotHeading(sole.status.id, sole.alias, sole.contract));
744
- }
745
- }
746
- const parts = [];
747
- for (const { status, rows } of round) {
748
- const known = state.streams.get(status.id);
749
- if (known !== undefined) {
750
- parts.push({ stream: known, emissions: known.emissions.observe({ snapshot: status.timeline, rows }) });
751
- }
752
- else {
753
- // Only a plural wait attributes its rows; a single-target stream keeps the plain row grammar.
754
- const stream = activityStream(context, state.plural === true
755
- ? sourceLayout(sourceTag(state, status.id), () => state.sourceWidth, state.clock)
756
- : plainLayout());
757
- state.streams.set(status.id, stream);
758
- // Seed marks skipped retained evidence without spending this command's live tool budget.
759
- parts.push({ stream, emissions: stream.emissions.seed({ snapshot: status.timeline, rows }) });
760
- }
761
- if (!state.settledAt.has(status.id) && defaultWaitComplete(status))
762
- state.settledAt.set(status.id, settleMoment(status) ?? now());
763
- }
764
- lines.push(...mergeStreamEmissions(parts));
765
- return lines;
766
- }
767
- /**
768
- * Merge one observation's decided output across sources by row time. Each
769
- * source keeps its own order; an omission count travels with the row after it,
770
- * or with the row before it when it trails. Ties keep selection order.
771
- */
772
- function mergeStreamEmissions(parts) {
773
- const queues = parts.map(({ stream, emissions }) => {
774
- const units = [];
775
- let pending = [];
776
- for (const emission of emissions) {
777
- pending.push(emission);
778
- if (emission.kind !== "row")
779
- continue;
780
- const at = Date.parse(emission.row.at);
781
- units.push({ at: Number.isFinite(at) ? at : (units.at(-1)?.at ?? Number.NEGATIVE_INFINITY), emissions: pending });
782
- pending = [];
783
- }
784
- if (pending.length > 0) {
785
- const last = units.at(-1);
786
- if (last === undefined)
787
- units.push({ at: Number.NEGATIVE_INFINITY, emissions: pending });
788
- else
789
- last.emissions.push(...pending);
790
- }
791
- return { stream, units };
792
- });
793
- const lines = [];
794
- for (;;) {
795
- let next;
796
- for (const queue of queues)
797
- if (queue.units.length > 0 && (next === undefined || queue.units[0].at < next.units[0].at))
798
- next = queue;
799
- if (next === undefined)
800
- return lines;
801
- lines.push(...next.stream.render(next.units.shift().emissions));
802
- }
803
- }
804
618
  /**
805
619
  * A conclusion clause asserts real waiting: a target that settled at or after
806
620
  * this wait began keeps its duration, a target already settled names no
@@ -842,91 +656,6 @@ export function inputWaitConclusion(observation, input) {
842
656
  : []),
843
657
  ];
844
658
  }
845
- /** Present ids in frozen selection order, then any result member the selection never named. */
846
- function orderedWaitIds(state, result) {
847
- const ids = [...state.sources.keys()];
848
- const known = new Set(ids);
849
- for (const observation of result.observations) {
850
- if (!known.has(observation.status.id)) {
851
- known.add(observation.status.id);
852
- ids.push(observation.status.id);
853
- }
854
- }
855
- for (const member of result.unobserved) {
856
- if (!known.has(member.id)) {
857
- known.add(member.id);
858
- ids.push(member.id);
859
- }
860
- }
861
- return ids;
862
- }
863
- function flushWaitStreams(state) {
864
- return mergeStreamEmissions([...state.streams.values()].map((stream) => ({ stream, emissions: stream.emissions.flush() })));
865
- }
866
- function concludeWaitStream(state, result, startedAt, now) {
867
- const tail = flushWaitStreams(state);
868
- const end = now();
869
- for (const observation of result.observations)
870
- registerWaitSource(state, observation.status.id, undefined, observation.contract);
871
- for (const member of result.unobserved)
872
- registerWaitSource(state, member.id, undefined);
873
- if (!state.headerEmitted)
874
- freezeWaitTags(state);
875
- const order = orderedWaitIds(state, result);
876
- const multi = order.length > 1;
877
- const observationById = new Map(result.observations.map((observation) => [observation.status.id, observation]));
878
- const unobservedById = new Map(result.unobserved.map((member) => [member.id, member]));
879
- // A failure fact keeps the complete identity even where the scoreboard attributes a target by its identity tag.
880
- const unobservedLines = order
881
- .filter((id) => unobservedById.has(id))
882
- .map((id) => unobservedText(id, unobservedById.get(id).diagnostic));
883
- const conclusions = order.flatMap((id) => {
884
- const observation = observationById.get(id);
885
- if (observation === undefined)
886
- return [];
887
- const status = observation.status;
888
- const complete = defaultWaitComplete(status);
889
- const at = complete ? (state.settledAt.get(id) ?? end) : end;
890
- const { mark, verb } = conclusionMarkVerb(status, statusAnswer(observation) !== undefined ? "answered" : "life");
891
- const target = multi ? ` ${padToDisplay(sourceTag(state, id), state.sourceWidth)}` : "";
892
- return [waitConclusionRow({ at, startedAt, complete, end, mark, verb, target })];
893
- });
894
- const answeredSingle = !multi && result.observations.length === 1 && statusAnswer(result.observations[0]) !== undefined;
895
- const blocks = [
896
- ...(conclusions.length > 0 ? [conclusions.join("\n")] : []),
897
- ...(unobservedLines.length > 0 ? [unobservedLines.join("\n")] : []),
898
- ];
899
- const body = [...tail, ...blocks].join("\n");
900
- // One blank line keeps the bare stdout answer visually separate from the stream.
901
- return answeredSingle ? `${body}\n\n` : body;
902
- }
903
- /**
904
- * Live view over a wait's successive observation rounds, one append-only
905
- * stream per selected Akuma. A plural wait opens one aggregate frame naming
906
- * its selected set before any activity row and never opens a per-target frame
907
- * during observation; a single-target wait opens that Akuma's own identity
908
- * frame — the identity and Contract association the observed facts carry —
909
- * and an already settled Akuma prints that frame while replaying no backlog
910
- * rows. `conclude` renders the closing rows once the wait ends: one row per
911
- * observed Akuma in `<clock> <mark> <verb> — <duration>` grammar, with a target
912
- * named for a multi-target scoreboard and no activity replay.
913
- */
914
- export function waitObservationStream(context, options = {}) {
915
- const now = options.now ?? (() => Date.now());
916
- const startedAt = now();
917
- const state = createWaitObservationState();
918
- const select = (selected) => {
919
- for (const member of selected)
920
- registerWaitSource(state, member.id, member.alias, member.contract);
921
- state.plural ??= selected.length > 1;
922
- freezeWaitTags(state);
923
- };
924
- const observe = (round) => observeWaitRound(state, round, context, now);
925
- const frame = () => [...state.streams.values()].flatMap((stream) => stream.frame());
926
- const flush = () => flushWaitStreams(state);
927
- const conclude = (result) => concludeWaitStream(state, result, startedAt, now);
928
- return { select, observe, frame, flush, conclude, streamed: () => state.observed };
929
- }
930
659
  function failedOutcomeDiagnostic(status) {
931
660
  const outcome = status.timeline.kind === "idle" ? status.timeline.outcome : undefined;
932
661
  return outcome !== undefined && outcome.outcome.kind === "failed" ? outcome.outcome.diagnostic : undefined;
@@ -1032,8 +761,8 @@ function renderReportedChangeLines(snapshot) {
1032
761
  ...(snapshot.reportedChangesOmitted > 0 ? [` ⋮ ${snapshot.reportedChangesOmitted} more files`] : []),
1033
762
  ];
1034
763
  }
1035
- function renderTaskRow(row, columns) {
1036
- const prefix = ` ${taskDispositionMark(row.disposition)} ${row.id} · `;
764
+ function renderDebtRow(row, columns) {
765
+ const prefix = ` ${debtDispositionMark(row.disposition)} ${row.id} · `;
1037
766
  const body = `${safeText(row.title)} · ${row.disposition} · P${row.priority}`;
1038
767
  const inline = `${prefix}${body}`;
1039
768
  if (displayColumns(inline) <= columns)
@@ -1045,28 +774,14 @@ function renderTaskRow(row, columns) {
1045
774
  lines: Number.MAX_SAFE_INTEGER,
1046
775
  });
1047
776
  }
1048
- function renderTaskContextLines(created, columns) {
777
+ function renderDebtContextLines(created, columns) {
1049
778
  if (created === undefined)
1050
779
  return [];
1051
780
  if (created.kind === "failed")
1052
- return [`! tasks failed ${safeText(created.diagnostic)}`];
781
+ return [`! debts failed ${safeText(created.diagnostic)}`];
1053
782
  if (created.rows.length === 0)
1054
783
  return [];
1055
- return [`tasks ${created.rows.length}`, ...created.rows.flatMap((row) => renderTaskRow(row, columns))];
1056
- }
1057
- function answerContextLines(observation, columns) {
1058
- return [
1059
- ...renderTaskContextLines(observation.createdTasks, columns),
1060
- ...renderReportedChangeLines(observation.status.timeline),
1061
- ];
1062
- }
1063
- function answeredBlock(observation, answer, alias, columns) {
1064
- const frame = answeredHeading(observation.status.id, alias).join("\n");
1065
- const context = answerContextLines(observation, columns).join("\n");
1066
- if (context.length === 0)
1067
- return `${frame}\n${answer}`;
1068
- const separator = answer.endsWith("\n") ? "\n" : "\n\n";
1069
- return `${frame}\n${answer}${separator}${context}`;
784
+ return [`debts ${created.rows.length}`, ...created.rows.flatMap((row) => renderDebtRow(row, columns))];
1070
785
  }
1071
786
  function snapshotCore(view, context, options) {
1072
787
  const activity = snapshotActivityLines(view.status.timeline, context);
@@ -1094,12 +809,12 @@ function snapshotConclusion(status) {
1094
809
  }
1095
810
  export function snapshotText(view, context, options = {}) {
1096
811
  const core = snapshotCore(view, context, options);
1097
- const taskContext = renderTaskContextLines(view.createdTasks, context.columns);
812
+ const debtContext = renderDebtContextLines(view.createdDebts, context.columns);
1098
813
  const conclusion = snapshotConclusion(view.status);
1099
814
  return [
1100
815
  ...core.lines,
1101
816
  ...(conclusion.length === 0 ? [] : [conclusion]),
1102
- ...(taskContext.length > 0 ? ["", ...taskContext] : []),
817
+ ...(debtContext.length > 0 ? ["", ...debtContext] : []),
1103
818
  ...(view.status.timeline.reportedChanges.length > 0 || view.status.timeline.reportedChangesOmitted > 0 ? [""] : []),
1104
819
  ...renderReportedChangeLines(view.status.timeline),
1105
820
  ...(core.facts.length > 0 ? ["", ...core.facts] : []),
@@ -1117,16 +832,6 @@ function killResultLabel(evidence) {
1117
832
  export function killResultText(id, evidence, alias) {
1118
833
  return [...snapshotHeading(id, alias, undefined), "", killResultLabel(evidence)].join("\n");
1119
834
  }
1120
- export function statusAnswer(view) {
1121
- if (!defaultWaitComplete(view.status))
1122
- return undefined;
1123
- if (view.status.life !== "asleep")
1124
- return undefined;
1125
- const timeline = view.status.timeline;
1126
- if (timeline.kind !== "idle" || timeline.outcome?.outcome.kind !== "answered")
1127
- return undefined;
1128
- return timeline.outcome.outcome.answer;
1129
- }
1130
835
  function answerBytes(answer, structured) {
1131
836
  return !structured && typeof answer === "string" ? answer : JSON.stringify(answer);
1132
837
  }
@@ -1141,90 +846,23 @@ export function callRawAnswer(result, streamed) {
1141
846
  return streamed ? "" : undefined;
1142
847
  return answerBytes(observation.observation.answer, result.structured === true);
1143
848
  }
1144
- export function waitRawAnswer(result, streamed) {
1145
- const total = result.observations.length + result.unobserved.length;
1146
- if (streamed) {
1147
- // Plural waits leave stdout empty so one answer can never be mistaken for the whole result.
1148
- if (total !== 1)
1149
- return "";
1150
- const single = result.observations[0];
1151
- return single === undefined ? "" : (statusAnswer(single) ?? "");
1152
- }
1153
- if (total !== 1)
1154
- return undefined;
1155
- return statusAnswer(result.observations[0]);
1156
- }
1157
849
  export function historyRawAnswer(result, historyId) {
1158
850
  if (historyId === undefined || result.kind !== "exact")
1159
851
  return undefined;
1160
852
  const outcome = result.outcome.outcome;
1161
853
  return outcome.kind === "answered" ? outcome.answer : outcome.diagnostic;
1162
854
  }
855
+ /**
856
+ * One wait's final text: each observed Akuma's own status snapshot, then one
857
+ * failure fact per member the wait could not read. A wait observes to its
858
+ * completion judgment and streams nothing, so an answer is visible only as the
859
+ * snapshot's own outcome row.
860
+ */
1163
861
  export function waitText(result, presentation, context) {
1164
- const alias = presentation.alias;
1165
- const observations = result.observations;
1166
- const unobserved = result.unobserved;
1167
- const total = observations.length + unobserved.length;
1168
- if (total <= 1) {
1169
- const single = [
1170
- ...observations.map((observation) => {
1171
- const answer = statusAnswer(observation);
1172
- if (answer !== undefined)
1173
- return answeredBlock(observation, answer, alias, context.columns);
1174
- return snapshotText(observation, context, { ...(alias === undefined ? {} : { alias }) });
1175
- }),
1176
- ...unobserved.map((member) => unobservedText(member.id, member.diagnostic)),
1177
- ];
1178
- return single.join("\n\n");
1179
- }
1180
- const end = Date.now();
1181
- const startedAt = presentation.startedAt ?? end;
1182
- const order = [];
1183
- const remember = (id) => {
1184
- if (!order.includes(id))
1185
- order.push(id);
1186
- };
1187
- for (const member of presentation.selection ?? [])
1188
- remember(member.id);
1189
- for (const observation of observations)
1190
- remember(observation.status.id);
1191
- for (const member of unobserved)
1192
- remember(member.id);
1193
- const observationById = new Map(observations.map((observation) => [observation.status.id, observation]));
1194
- const unobservedById = new Map(unobserved.map((member) => [member.id, member]));
1195
- const sourceWidth = Math.max(0, ...order.map((id) => displayColumns(waitIdentityTag(id, order))));
1196
- const blocks = [
1197
- ...order.flatMap((id) => {
1198
- const observation = observationById.get(id);
1199
- if (observation === undefined)
1200
- return [];
1201
- const answer = statusAnswer(observation);
1202
- if (answer !== undefined)
1203
- return [answeredBlock(observation, answer, undefined, context.columns)];
1204
- return [snapshotText(observation, context)];
1205
- }),
1206
- ...(unobserved.length > 0
1207
- ? [
1208
- order
1209
- .filter((id) => unobservedById.has(id))
1210
- .map((id) => unobservedText(id, unobservedById.get(id).diagnostic))
1211
- .join("\n"),
1212
- ]
1213
- : []),
1214
- ];
1215
- const rows = order.flatMap((id) => {
1216
- const observation = observationById.get(id);
1217
- if (observation === undefined)
1218
- return [];
1219
- const status = observation.status;
1220
- const complete = defaultWaitComplete(status);
1221
- const at = complete ? (settleMoment(status) ?? end) : end;
1222
- const { mark, verb } = conclusionMarkVerb(status, statusAnswer(observation) !== undefined ? "answered" : "life");
1223
- return [
1224
- `${clockFromMs(at)} ${padToDisplay(waitIdentityTag(id, order), sourceWidth)} ${mark} ${verb}${conclusionClause(at, startedAt, complete, end)}`,
1225
- ];
1226
- });
1227
- return rows.length > 0 ? [...blocks, rows.join("\n")].join("\n\n") : blocks.join("\n\n");
862
+ const alias = result.observations.length === 1 && result.unobserved.length === 0 ? presentation.alias : undefined;
863
+ const blocks = result.observations.map((observation) => snapshotText(observation, context, { ...(alias === undefined ? {} : { alias }) }));
864
+ const unobserved = result.unobserved.map((member) => unobservedText(member.id, member.diagnostic));
865
+ return [...blocks, ...(unobserved.length === 0 ? [] : [unobserved.join("\n")])].join("\n\n");
1228
866
  }
1229
867
  export function historyText(result, presentation, context) {
1230
868
  if (presentation.id !== undefined) {