voratiq 0.1.0-beta.21 → 0.1.0-beta.23

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 (222) hide show
  1. package/README.md +19 -23
  2. package/dist/agents/launch/chat.d.ts +3 -1
  3. package/dist/agents/launch/chat.js +2 -0
  4. package/dist/agents/runtime/policy.js +2 -1
  5. package/dist/auth/providers/utils.js +1 -1
  6. package/dist/bin.js +28 -7
  7. package/dist/cli/auto.js +4 -16
  8. package/dist/cli/contract.d.ts +26 -17
  9. package/dist/cli/contract.js +3 -1
  10. package/dist/cli/doctor.d.ts +12 -0
  11. package/dist/cli/doctor.js +115 -0
  12. package/dist/cli/list.js +5 -1
  13. package/dist/cli/message.js +16 -11
  14. package/dist/cli/operator-envelope.d.ts +27 -7
  15. package/dist/cli/operator-envelope.js +95 -3
  16. package/dist/cli/option-parsers.d.ts +2 -0
  17. package/dist/cli/option-parsers.js +7 -0
  18. package/dist/cli/output.d.ts +1 -5
  19. package/dist/cli/reduce.js +5 -13
  20. package/dist/cli/run.js +5 -12
  21. package/dist/cli/spec.js +4 -10
  22. package/dist/cli/verify.d.ts +1 -1
  23. package/dist/cli/verify.js +51 -22
  24. package/dist/commands/auto/command.d.ts +1 -0
  25. package/dist/commands/auto/command.js +22 -15
  26. package/dist/commands/auto/errors.js +1 -1
  27. package/dist/commands/auto/validation.js +3 -1
  28. package/dist/commands/doctor/agents.d.ts +5 -0
  29. package/dist/commands/{init → doctor}/agents.js +40 -20
  30. package/dist/commands/doctor/command.d.ts +22 -0
  31. package/dist/commands/doctor/command.js +100 -0
  32. package/dist/commands/doctor/environment.d.ts +2 -0
  33. package/dist/commands/{init → doctor}/environment.js +41 -7
  34. package/dist/commands/{init/types.d.ts → doctor/fix-types.d.ts} +30 -9
  35. package/dist/commands/doctor/fix.d.ts +2 -0
  36. package/dist/commands/{init/command.js → doctor/fix.js} +109 -11
  37. package/dist/commands/doctor/reconcile.d.ts +2 -0
  38. package/dist/commands/doctor/reconcile.js +103 -0
  39. package/dist/commands/interactive/lifecycle.d.ts +2 -0
  40. package/dist/commands/interactive/lifecycle.js +16 -0
  41. package/dist/commands/list/command.d.ts +1 -0
  42. package/dist/commands/list/command.js +241 -361
  43. package/dist/commands/list/normalization.d.ts +51 -0
  44. package/dist/commands/list/normalization.js +309 -0
  45. package/dist/commands/list/records.d.ts +9 -0
  46. package/dist/commands/list/records.js +6 -0
  47. package/dist/commands/message/command.d.ts +2 -2
  48. package/dist/commands/message/command.js +29 -16
  49. package/dist/commands/message/errors.d.ts +12 -3
  50. package/dist/commands/message/errors.js +19 -3
  51. package/dist/commands/prune/command.js +4 -1
  52. package/dist/commands/reduce/command.js +16 -17
  53. package/dist/commands/reduce/errors.d.ts +2 -2
  54. package/dist/commands/reduce/errors.js +3 -3
  55. package/dist/commands/reduce/targets.js +12 -3
  56. package/dist/commands/root-launcher/command.js +12 -6
  57. package/dist/commands/run/command.d.ts +1 -0
  58. package/dist/commands/run/command.js +4 -1
  59. package/dist/commands/run/record-init.d.ts +2 -0
  60. package/dist/commands/run/record-init.js +8 -1
  61. package/dist/commands/run/spec-provenance.d.ts +37 -0
  62. package/dist/commands/run/spec-provenance.js +384 -0
  63. package/dist/commands/run/validation.d.ts +4 -0
  64. package/dist/commands/run/validation.js +25 -62
  65. package/dist/commands/shared/resolve-stage-competitors.js +2 -1
  66. package/dist/commands/spec/command.js +64 -138
  67. package/dist/commands/spec/errors.d.ts +5 -0
  68. package/dist/commands/spec/errors.js +9 -0
  69. package/dist/commands/verify/agents.d.ts +4 -2
  70. package/dist/commands/verify/agents.js +4 -11
  71. package/dist/commands/verify/command.js +23 -6
  72. package/dist/commands/verify/errors.d.ts +12 -0
  73. package/dist/commands/verify/errors.js +22 -0
  74. package/dist/commands/verify/lifecycle.js +1 -1
  75. package/dist/commands/verify/targets.js +108 -12
  76. package/dist/competition/shared/preflight.d.ts +1 -1
  77. package/dist/competition/shared/preflight.js +15 -2
  78. package/dist/competition/shared/teardown.d.ts +7 -0
  79. package/dist/competition/shared/teardown.js +6 -0
  80. package/dist/configs/agents/defaults.js +13 -44
  81. package/dist/configs/agents/loader.js +1 -1
  82. package/dist/configs/environment/loader.js +2 -1
  83. package/dist/configs/orchestration/loader.js +2 -1
  84. package/dist/configs/sandbox/loader.js +2 -1
  85. package/dist/configs/settings/loader.js +1 -1
  86. package/dist/configs/verification/loader.js +2 -1
  87. package/dist/contracts/list.d.ts +129 -149
  88. package/dist/contracts/list.js +47 -99
  89. package/dist/domain/interactive/model/types.d.ts +2 -0
  90. package/dist/domain/interactive/model/types.js +16 -1
  91. package/dist/domain/interactive/persistence/adapter.d.ts +23 -0
  92. package/dist/domain/interactive/persistence/adapter.js +67 -5
  93. package/dist/domain/interactive/prompt.d.ts +1 -1
  94. package/dist/domain/interactive/prompt.js +1 -1
  95. package/dist/domain/interactive/session-env.d.ts +10 -0
  96. package/dist/domain/interactive/session-env.js +25 -0
  97. package/dist/domain/message/competition/adapter.js +3 -9
  98. package/dist/domain/message/model/types.d.ts +32 -1
  99. package/dist/domain/message/model/types.js +25 -1
  100. package/dist/domain/reduce/competition/adapter.js +30 -16
  101. package/dist/domain/reduce/competition/finalize.d.ts +7 -0
  102. package/dist/domain/reduce/competition/finalize.js +19 -0
  103. package/dist/domain/reduce/model/types.d.ts +3 -3
  104. package/dist/domain/run/competition/agents/artifacts.js +4 -2
  105. package/dist/domain/run/competition/agents/lifecycle.js +1 -1
  106. package/dist/domain/run/competition/agents/workspace.js +2 -1
  107. package/dist/domain/run/competition/errors.d.ts +1 -1
  108. package/dist/domain/run/competition/errors.js +4 -7
  109. package/dist/domain/run/competition/reports.js +2 -1
  110. package/dist/domain/run/model/enhanced.d.ts +1 -1
  111. package/dist/domain/run/model/enhanced.js +2 -1
  112. package/dist/domain/run/model/types.d.ts +384 -0
  113. package/dist/domain/run/model/types.js +87 -0
  114. package/dist/domain/spec/competition/adapter.d.ts +1 -0
  115. package/dist/domain/spec/competition/adapter.js +9 -10
  116. package/dist/domain/spec/model/mutators.d.ts +20 -0
  117. package/dist/domain/spec/model/mutators.js +146 -0
  118. package/dist/domain/spec/model/types.d.ts +3 -0
  119. package/dist/domain/spec/model/types.js +5 -0
  120. package/dist/domain/spec/persistence/adapter.d.ts +1 -0
  121. package/dist/domain/spec/persistence/adapter.js +7 -2
  122. package/dist/domain/verify/competition/adapter.d.ts +1 -1
  123. package/dist/domain/verify/competition/adapter.js +4 -9
  124. package/dist/domain/verify/competition/finalize.d.ts +9 -0
  125. package/dist/domain/verify/competition/finalize.js +22 -3
  126. package/dist/domain/verify/competition/programmatic.js +2 -1
  127. package/dist/domain/verify/competition/prompt.js +1 -1
  128. package/dist/domain/verify/competition/shared-layout.js +1 -1
  129. package/dist/domain/verify/model/types.d.ts +2 -2
  130. package/dist/interactive/providers/launch.d.ts +2 -0
  131. package/dist/interactive/providers/launch.js +19 -2
  132. package/dist/interactive/providers/mcp.d.ts +1 -0
  133. package/dist/interactive/providers/mcp.js +45 -7
  134. package/dist/interactive/substrate.js +32 -5
  135. package/dist/mcp/server.d.ts +1 -0
  136. package/dist/mcp/server.js +337 -44
  137. package/dist/policy/auto.d.ts +0 -1
  138. package/dist/policy/auto.js +3 -14
  139. package/dist/policy/verification.js +18 -1
  140. package/dist/preflight/agents.d.ts +24 -0
  141. package/dist/preflight/agents.js +71 -0
  142. package/dist/preflight/environment.d.ts +6 -0
  143. package/dist/preflight/environment.js +17 -0
  144. package/dist/preflight/formatting.d.ts +5 -0
  145. package/dist/preflight/formatting.js +20 -0
  146. package/dist/preflight/index.d.ts +2 -0
  147. package/dist/preflight/index.js +6 -9
  148. package/dist/preflight/operator.d.ts +32 -0
  149. package/dist/preflight/operator.js +40 -0
  150. package/dist/preflight/settings.d.ts +2 -0
  151. package/dist/preflight/settings.js +17 -0
  152. package/dist/render/transcripts/apply.js +2 -1
  153. package/dist/render/transcripts/interactive.d.ts +16 -0
  154. package/dist/render/transcripts/interactive.js +42 -0
  155. package/dist/render/transcripts/list.d.ts +41 -0
  156. package/dist/render/transcripts/list.js +152 -3
  157. package/dist/render/transcripts/message.d.ts +3 -5
  158. package/dist/render/transcripts/message.js +29 -74
  159. package/dist/render/transcripts/reduce.d.ts +2 -4
  160. package/dist/render/transcripts/reduce.js +31 -75
  161. package/dist/render/transcripts/root-launcher.js +2 -12
  162. package/dist/render/transcripts/run.d.ts +4 -4
  163. package/dist/render/transcripts/run.js +36 -47
  164. package/dist/render/transcripts/spec.d.ts +1 -4
  165. package/dist/render/transcripts/spec.js +15 -62
  166. package/dist/render/transcripts/verify.d.ts +6 -7
  167. package/dist/render/transcripts/verify.js +54 -85
  168. package/dist/render/utils/cli-writer.d.ts +4 -0
  169. package/dist/render/utils/cli-writer.js +1 -0
  170. package/dist/render/utils/duration.d.ts +5 -0
  171. package/dist/render/utils/duration.js +6 -0
  172. package/dist/render/utils/progressive-render.d.ts +3 -0
  173. package/dist/render/utils/progressive-render.js +44 -0
  174. package/dist/render/utils/runs.d.ts +1 -0
  175. package/dist/render/utils/runs.js +1 -0
  176. package/dist/render/utils/transcript-shell.d.ts +2 -1
  177. package/dist/render/utils/transcript-shell.js +19 -6
  178. package/dist/utils/diff.d.ts +2 -0
  179. package/dist/utils/diff.js +1 -0
  180. package/dist/utils/errors.d.ts +2 -1
  181. package/dist/utils/errors.js +3 -1
  182. package/dist/utils/git.d.ts +1 -1
  183. package/dist/utils/git.js +25 -2
  184. package/dist/utils/list-target.d.ts +4 -0
  185. package/dist/utils/list-target.js +35 -0
  186. package/dist/utils/swarm-session-ack.d.ts +9 -0
  187. package/dist/utils/swarm-session-ack.js +17 -0
  188. package/dist/utils/terminal.d.ts +1 -0
  189. package/dist/utils/terminal.js +11 -0
  190. package/dist/workspace/artifact-paths.d.ts +55 -0
  191. package/dist/workspace/artifact-paths.js +106 -0
  192. package/dist/workspace/chat/artifacts.d.ts +7 -0
  193. package/dist/workspace/chat/artifacts.js +95 -4
  194. package/dist/workspace/chat/native-usage.js +1 -1
  195. package/dist/workspace/chat/sources.d.ts +2 -5
  196. package/dist/workspace/chat/sources.js +4 -4
  197. package/dist/workspace/constants.d.ts +47 -0
  198. package/dist/workspace/constants.js +47 -0
  199. package/dist/workspace/errors.js +2 -2
  200. package/dist/workspace/layout.js +3 -1
  201. package/dist/workspace/managed-state.d.ts +32 -0
  202. package/dist/workspace/managed-state.js +104 -0
  203. package/dist/workspace/path-formatters.d.ts +9 -0
  204. package/dist/workspace/path-formatters.js +46 -0
  205. package/dist/workspace/path-resolvers.d.ts +1 -0
  206. package/dist/workspace/path-resolvers.js +5 -0
  207. package/dist/workspace/session-paths.d.ts +16 -0
  208. package/dist/workspace/session-paths.js +59 -0
  209. package/dist/workspace/setup.js +67 -2
  210. package/dist/workspace/shim.d.ts +1 -0
  211. package/dist/workspace/shim.js +3 -3
  212. package/package.json +2 -2
  213. package/dist/cli/init.d.ts +0 -15
  214. package/dist/cli/init.js +0 -70
  215. package/dist/commands/init/agents.d.ts +0 -4
  216. package/dist/commands/init/command.d.ts +0 -2
  217. package/dist/commands/init/environment.d.ts +0 -2
  218. package/dist/render/transcripts/init.d.ts +0 -7
  219. package/dist/render/transcripts/init.js +0 -83
  220. package/dist/workspace/structure.d.ts +0 -143
  221. package/dist/workspace/structure.js +0 -319
  222. /package/dist/commands/{init/types.js → doctor/fix-types.js} +0 -0
@@ -1,9 +1,6 @@
1
1
  import type { ExtractedTokenUsage } from "../../domain/run/model/types.js";
2
2
  import type { TokenUsageResult } from "../../workspace/chat/token-usage-result.js";
3
- type CliWriter = Pick<NodeJS.WriteStream, "write"> & {
4
- isTTY?: boolean;
5
- columns?: number;
6
- };
3
+ import type { CliWriter } from "../utils/cli-writer.js";
7
4
  export interface MessageProgressContext {
8
5
  messageId: string;
9
6
  createdAt: string;
@@ -44,6 +41,7 @@ export interface MessageTranscriptOptions {
44
41
  elapsed: string;
45
42
  workspacePath: string;
46
43
  status: "queued" | "running" | "succeeded" | "failed" | "aborted";
44
+ targetDisplay?: string;
47
45
  recipients: readonly MessageTranscriptRecipientBlock[];
48
46
  isTty?: boolean;
49
47
  includeSummarySection?: boolean;
@@ -68,5 +66,5 @@ export declare function formatMessageRecipientDuration(input: {
68
66
  startedAt?: string;
69
67
  completedAt?: string;
70
68
  now?: number;
71
- }): string | undefined;
69
+ }): string;
72
70
  export {};
@@ -1,43 +1,13 @@
1
1
  import { getAgentStatusStyle, getRunStatusStyle } from "../../status/colors.js";
2
2
  import { TERMINAL_MESSAGE_STATUSES } from "../../status/index.js";
3
3
  import { formatAgentErrorLine } from "../utils/agents.js";
4
- import { formatRenderLifecycleDuration } from "../utils/duration.js";
4
+ import { formatRenderLifecycleDuration, formatRenderLifecycleRowDuration, } from "../utils/duration.js";
5
5
  import { createInteractiveFrameRenderer } from "../utils/interactive-frame.js";
6
+ import { clearRefreshIntervalHandle, formatProgressiveRenderErrorDetail, parseProgressTimestamp, } from "../utils/progressive-render.js";
6
7
  import { buildStageFrameLines, buildStageFrameSections, } from "../utils/stage-output.js";
7
8
  import { renderTranscript } from "../utils/transcript.js";
8
9
  import { buildStandardSessionShellSection, formatTranscriptStatusLabel, renderTranscriptStatusTable, resolveTranscriptShellStyle, resolveTranscriptShellStyleFromWriter, } from "../utils/transcript-shell.js";
9
10
  const DASH = "—";
10
- function formatErrorDetail(error) {
11
- if (error instanceof Error) {
12
- return error.message;
13
- }
14
- if (typeof error === "string") {
15
- return error;
16
- }
17
- if (error === null || error === undefined) {
18
- return "unknown error";
19
- }
20
- if (typeof error === "number" ||
21
- typeof error === "boolean" ||
22
- typeof error === "bigint") {
23
- return `${error}`;
24
- }
25
- if (typeof error === "symbol") {
26
- return error.description ?? error.toString();
27
- }
28
- if (typeof error === "object") {
29
- try {
30
- const serialized = JSON.stringify(error);
31
- if (serialized) {
32
- return serialized;
33
- }
34
- }
35
- catch {
36
- // Ignore serialization errors and fall back.
37
- }
38
- }
39
- return "unknown error";
40
- }
41
11
  function buildMessageStageShell(options) {
42
12
  return {
43
13
  metadataLines: buildStandardSessionShellSection({
@@ -69,13 +39,6 @@ export function createMessageRenderer(options = {}) {
69
39
  const interactiveFrameRenderer = createInteractiveFrameRenderer(stdout);
70
40
  const recipientOrder = [];
71
41
  const recipientRecords = new Map();
72
- function stopRefreshLoop() {
73
- if (!refreshInterval) {
74
- return;
75
- }
76
- clearInterval(refreshInterval);
77
- refreshInterval = undefined;
78
- }
79
42
  function hasRunningRecipients() {
80
43
  for (const recipient of recipientRecords.values()) {
81
44
  if (recipient.status === "running") {
@@ -86,7 +49,7 @@ export function createMessageRenderer(options = {}) {
86
49
  }
87
50
  function syncRefreshLoop() {
88
51
  if (!stdout.isTTY || disabled || !context || !hasRunningRecipients()) {
89
- stopRefreshLoop();
52
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
90
53
  return;
91
54
  }
92
55
  if (refreshInterval) {
@@ -95,7 +58,7 @@ export function createMessageRenderer(options = {}) {
95
58
  refreshInterval = setInterval(() => {
96
59
  guard(() => {
97
60
  if (!stdout.isTTY || disabled || !context || !hasRunningRecipients()) {
98
- stopRefreshLoop();
61
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
99
62
  return;
100
63
  }
101
64
  const nextElapsed = formatMessageProgressElapsed(context, now());
@@ -116,25 +79,15 @@ export function createMessageRenderer(options = {}) {
116
79
  }
117
80
  catch (error) {
118
81
  disabled = true;
119
- stopRefreshLoop();
82
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
120
83
  if (!warningLogged) {
121
84
  warningLogged = true;
122
- stderr.write(`[voratiq] Progressive message output disabled: ${formatErrorDetail(error)}\n`);
85
+ stderr.write(`[voratiq] Progressive message output disabled: ${formatProgressiveRenderErrorDetail(error)}\n`);
123
86
  }
124
87
  }
125
88
  }
126
- function safeParse(value) {
127
- if (!value) {
128
- return undefined;
129
- }
130
- const parsed = Date.parse(value);
131
- return Number.isNaN(parsed) ? undefined : parsed;
132
- }
133
89
  function formatDuration(record) {
134
- if (record.status === "running") {
135
- return DASH;
136
- }
137
- return (formatRenderLifecycleDuration({
90
+ return formatRenderLifecycleRowDuration({
138
91
  lifecycle: {
139
92
  status: record.status,
140
93
  startedAt: record.startedAt,
@@ -142,21 +95,21 @@ export function createMessageRenderer(options = {}) {
142
95
  },
143
96
  terminalStatuses: TERMINAL_MESSAGE_STATUSES,
144
97
  now: now(),
145
- }) ?? DASH);
98
+ });
146
99
  }
147
100
  function syncContextLifecycleFromRecipientRecords() {
148
101
  if (!context) {
149
102
  return;
150
103
  }
151
- let earliestStartedAt = safeParse(context.startedAt);
152
- let latestCompletedAt = safeParse(context.completedAt);
104
+ let earliestStartedAt = parseProgressTimestamp(context.startedAt);
105
+ let latestCompletedAt = parseProgressTimestamp(context.completedAt);
153
106
  for (const recipient of recipientRecords.values()) {
154
- const startedAt = safeParse(recipient.startedAt);
107
+ const startedAt = parseProgressTimestamp(recipient.startedAt);
155
108
  if (startedAt !== undefined &&
156
109
  (earliestStartedAt === undefined || startedAt < earliestStartedAt)) {
157
110
  earliestStartedAt = startedAt;
158
111
  }
159
- const completedAt = safeParse(recipient.completedAt);
112
+ const completedAt = parseProgressTimestamp(recipient.completedAt);
160
113
  if (completedAt !== undefined &&
161
114
  (latestCompletedAt === undefined || completedAt > latestCompletedAt)) {
162
115
  latestCompletedAt = completedAt;
@@ -259,7 +212,7 @@ export function createMessageRenderer(options = {}) {
259
212
  });
260
213
  },
261
214
  complete(status, lifecycle) {
262
- stopRefreshLoop();
215
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
263
216
  guard(() => {
264
217
  if (context && lifecycle) {
265
218
  context = {
@@ -281,24 +234,26 @@ export function createMessageRenderer(options = {}) {
281
234
  };
282
235
  }
283
236
  export function renderMessageTranscript(options) {
284
- const { recipients, isTty, includeSummarySection = true } = options;
237
+ const { recipients, isTty, includeSummarySection = true, targetDisplay, } = options;
285
238
  const style = { isTty };
286
239
  const resolvedStyle = resolveTranscriptShellStyle(style);
287
240
  const sections = [];
288
241
  if (includeSummarySection) {
242
+ const metadataLines = buildStandardSessionShellSection({
243
+ badgeText: options.messageId,
244
+ badgeVariant: "message",
245
+ status: {
246
+ value: options.status,
247
+ color: getRunStatusStyle(options.status).cli,
248
+ },
249
+ elapsed: options.elapsed,
250
+ createdAt: options.createdAt,
251
+ workspacePath: options.workspacePath,
252
+ targetDisplay,
253
+ style,
254
+ });
289
255
  const shell = {
290
- metadataLines: buildStandardSessionShellSection({
291
- badgeText: options.messageId,
292
- badgeVariant: "message",
293
- status: {
294
- value: options.status,
295
- color: getRunStatusStyle(options.status).cli,
296
- },
297
- elapsed: options.elapsed,
298
- createdAt: options.createdAt,
299
- workspacePath: options.workspacePath,
300
- style,
301
- }),
256
+ metadataLines,
302
257
  statusTableLines: recipients.length > 0
303
258
  ? renderTranscriptStatusTable({
304
259
  rows: recipients,
@@ -342,7 +297,7 @@ export function formatMessageElapsed(input) {
342
297
  });
343
298
  }
344
299
  export function formatMessageRecipientDuration(input) {
345
- return formatRenderLifecycleDuration({
300
+ return formatRenderLifecycleRowDuration({
346
301
  lifecycle: {
347
302
  status: input.status,
348
303
  startedAt: input.startedAt,
@@ -1,10 +1,7 @@
1
1
  import type { ExtractedTokenUsage } from "../../domain/run/model/types.js";
2
2
  import type { TokenUsageResult } from "../../workspace/chat/token-usage-result.js";
3
+ import type { CliWriter } from "../utils/cli-writer.js";
3
4
  import type { StageProgressEventConsumer } from "./stage-progress.js";
4
- type CliWriter = Pick<NodeJS.WriteStream, "write"> & {
5
- isTTY?: boolean;
6
- columns?: number;
7
- };
8
5
  export interface ReduceProgressContext {
9
6
  reductionId: string;
10
7
  createdAt: string;
@@ -51,6 +48,7 @@ export interface ReduceTranscriptOptions {
51
48
  elapsed: string;
52
49
  workspacePath: string;
53
50
  status: "queued" | "succeeded" | "failed" | "aborted" | "running";
51
+ targetDisplay?: string;
54
52
  reducers: readonly ReduceTranscriptReducerBlock[];
55
53
  nextCommandLines?: readonly string[];
56
54
  suppressHint?: boolean;
@@ -1,57 +1,29 @@
1
1
  import { getAgentStatusStyle, getRunStatusStyle } from "../../status/colors.js";
2
2
  import { TERMINAL_REDUCTION_STATUSES } from "../../status/index.js";
3
3
  import { formatAgentErrorLine } from "../utils/agents.js";
4
- import { formatRenderLifecycleDuration } from "../utils/duration.js";
4
+ import { formatRenderLifecycleDuration, formatRenderLifecycleRowDuration, } from "../utils/duration.js";
5
5
  import { createInteractiveFrameRenderer } from "../utils/interactive-frame.js";
6
+ import { clearRefreshIntervalHandle, formatProgressiveRenderErrorDetail, parseProgressTimestamp, } from "../utils/progressive-render.js";
6
7
  import { buildStageFrameLines, buildStageFrameSections, } from "../utils/stage-output.js";
7
8
  import { renderTranscript } from "../utils/transcript.js";
8
9
  import { buildStandardSessionShellSection, formatTranscriptStatusLabel, renderTranscriptStatusTable, resolveTranscriptShellStyle, resolveTranscriptShellStyleFromWriter, } from "../utils/transcript-shell.js";
9
10
  const DASH = "—";
10
- function formatErrorDetail(error) {
11
- if (error instanceof Error) {
12
- return error.message;
13
- }
14
- if (typeof error === "string") {
15
- return error;
16
- }
17
- if (error === null || error === undefined) {
18
- return "unknown error";
19
- }
20
- if (typeof error === "number" ||
21
- typeof error === "boolean" ||
22
- typeof error === "bigint") {
23
- return `${error}`;
24
- }
25
- if (typeof error === "symbol") {
26
- return error.description ?? error.toString();
27
- }
28
- if (typeof error === "object") {
29
- try {
30
- const serialized = JSON.stringify(error);
31
- if (serialized) {
32
- return serialized;
33
- }
34
- }
35
- catch {
36
- // Ignore serialization errors and fall back.
37
- }
38
- }
39
- return "unknown error";
40
- }
41
11
  function buildReduceStageShell(options) {
12
+ const metadataLines = buildStandardSessionShellSection({
13
+ badgeText: options.reductionId,
14
+ badgeVariant: "reduce",
15
+ status: {
16
+ value: options.status,
17
+ color: getRunStatusStyle(options.status).cli,
18
+ },
19
+ elapsed: options.elapsed,
20
+ createdAt: options.createdAt,
21
+ workspacePath: options.workspacePath,
22
+ targetDisplay: options.targetDisplay,
23
+ style: options.style,
24
+ });
42
25
  return {
43
- metadataLines: buildStandardSessionShellSection({
44
- badgeText: options.reductionId,
45
- badgeVariant: "reduce",
46
- status: {
47
- value: options.status,
48
- color: getRunStatusStyle(options.status).cli,
49
- },
50
- elapsed: options.elapsed,
51
- createdAt: options.createdAt,
52
- workspacePath: options.workspacePath,
53
- style: options.style,
54
- }),
26
+ metadataLines,
55
27
  statusTableLines: options.tableLines ?? [],
56
28
  };
57
29
  }
@@ -69,13 +41,6 @@ export function createReduceRenderer(options = {}) {
69
41
  const interactiveFrameRenderer = createInteractiveFrameRenderer(stdout);
70
42
  const reducerOrder = [];
71
43
  const reducerRecords = new Map();
72
- function stopRefreshLoop() {
73
- if (!refreshInterval) {
74
- return;
75
- }
76
- clearInterval(refreshInterval);
77
- refreshInterval = undefined;
78
- }
79
44
  function hasRunningReducers() {
80
45
  for (const reducer of reducerRecords.values()) {
81
46
  if (reducer.status === "running") {
@@ -86,7 +51,7 @@ export function createReduceRenderer(options = {}) {
86
51
  }
87
52
  function syncRefreshLoop() {
88
53
  if (!stdout.isTTY || disabled || !context || !hasRunningReducers()) {
89
- stopRefreshLoop();
54
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
90
55
  return;
91
56
  }
92
57
  if (refreshInterval) {
@@ -95,7 +60,7 @@ export function createReduceRenderer(options = {}) {
95
60
  refreshInterval = setInterval(() => {
96
61
  guard(() => {
97
62
  if (!stdout.isTTY || disabled || !context || !hasRunningReducers()) {
98
- stopRefreshLoop();
63
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
99
64
  return;
100
65
  }
101
66
  const nextElapsed = formatReduceProgressElapsed(context);
@@ -116,10 +81,10 @@ export function createReduceRenderer(options = {}) {
116
81
  }
117
82
  catch (error) {
118
83
  disabled = true;
119
- stopRefreshLoop();
84
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
120
85
  if (!warningLogged) {
121
86
  warningLogged = true;
122
- stderr.write(`[voratiq] Progressive reduce output disabled: ${formatErrorDetail(error)}\n`);
87
+ stderr.write(`[voratiq] Progressive reduce output disabled: ${formatProgressiveRenderErrorDetail(error)}\n`);
123
88
  }
124
89
  }
125
90
  }
@@ -134,18 +99,8 @@ export function createReduceRenderer(options = {}) {
134
99
  now: now(),
135
100
  });
136
101
  }
137
- function safeParse(value) {
138
- if (!value) {
139
- return undefined;
140
- }
141
- const parsed = Date.parse(value);
142
- return Number.isNaN(parsed) ? undefined : parsed;
143
- }
144
102
  function formatDuration(record) {
145
- if (record.status === "running") {
146
- return DASH;
147
- }
148
- return (formatRenderLifecycleDuration({
103
+ return formatRenderLifecycleRowDuration({
149
104
  lifecycle: {
150
105
  status: record.status,
151
106
  startedAt: record.startedAt,
@@ -153,21 +108,21 @@ export function createReduceRenderer(options = {}) {
153
108
  },
154
109
  terminalStatuses: TERMINAL_REDUCTION_STATUSES,
155
110
  now: now(),
156
- }) ?? DASH);
111
+ });
157
112
  }
158
113
  function syncContextLifecycleFromReducerRecords() {
159
114
  if (!context) {
160
115
  return;
161
116
  }
162
- let earliestStartedAt = safeParse(context.startedAt);
163
- let latestCompletedAt = safeParse(context.completedAt);
117
+ let earliestStartedAt = parseProgressTimestamp(context.startedAt);
118
+ let latestCompletedAt = parseProgressTimestamp(context.completedAt);
164
119
  for (const reducer of reducerRecords.values()) {
165
- const startedAt = safeParse(reducer.startedAt);
120
+ const startedAt = parseProgressTimestamp(reducer.startedAt);
166
121
  if (startedAt !== undefined &&
167
122
  (earliestStartedAt === undefined || startedAt < earliestStartedAt)) {
168
123
  earliestStartedAt = startedAt;
169
124
  }
170
- const completedAt = safeParse(reducer.completedAt);
125
+ const completedAt = parseProgressTimestamp(reducer.completedAt);
171
126
  if (completedAt !== undefined &&
172
127
  (latestCompletedAt === undefined || completedAt > latestCompletedAt)) {
173
128
  latestCompletedAt = completedAt;
@@ -296,7 +251,7 @@ export function createReduceRenderer(options = {}) {
296
251
  });
297
252
  },
298
253
  complete(status, lifecycle) {
299
- stopRefreshLoop();
254
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
300
255
  guard(() => {
301
256
  if (context && lifecycle) {
302
257
  context = {
@@ -321,7 +276,7 @@ export function createReduceRenderer(options = {}) {
321
276
  };
322
277
  }
323
278
  export function renderReduceTranscript(options) {
324
- const { reductionId, createdAt, elapsed, workspacePath, status, reducers, nextCommandLines, suppressHint, isTty, includeSummarySection = true, } = options;
279
+ const { reductionId, createdAt, elapsed, workspacePath, status, targetDisplay, reducers, nextCommandLines, suppressHint, isTty, includeSummarySection = true, } = options;
325
280
  const style = { isTty };
326
281
  const resolvedStyle = resolveTranscriptShellStyle(style);
327
282
  const sections = [];
@@ -332,6 +287,7 @@ export function renderReduceTranscript(options) {
332
287
  elapsed,
333
288
  workspacePath,
334
289
  status,
290
+ targetDisplay,
335
291
  tableLines: reducers.length > 0
336
292
  ? renderTranscriptStatusTable({
337
293
  rows: reducers,
@@ -372,7 +328,7 @@ export function renderReduceTranscript(options) {
372
328
  return renderTranscript({ sections, hint });
373
329
  }
374
330
  export function formatReducerDuration(options) {
375
- return (formatRenderLifecycleDuration({
331
+ return formatRenderLifecycleRowDuration({
376
332
  lifecycle: {
377
333
  status: options.status,
378
334
  startedAt: options.startedAt,
@@ -380,7 +336,7 @@ export function formatReducerDuration(options) {
380
336
  },
381
337
  terminalStatuses: TERMINAL_REDUCTION_STATUSES,
382
338
  now: options.now,
383
- }) ?? "—");
339
+ });
384
340
  }
385
341
  export function formatReduceElapsed(options) {
386
342
  return formatRenderLifecycleDuration({
@@ -1,28 +1,18 @@
1
1
  import { colorize } from "../../utils/colors.js";
2
2
  export function renderRootLauncherSelectionScreen(options) {
3
+ void options.unavailable;
3
4
  const lines = [
4
5
  "Start a native agent session from this repository.",
5
6
  "",
6
7
  "Enabled agents:",
7
8
  ...options.launchable.map((agent, index) => ` ${index + 1}. ${agent.label}`),
8
9
  ];
9
- if (options.unavailable.length > 0) {
10
- lines.push("", "Unavailable enabled agents:");
11
- for (const agent of options.unavailable) {
12
- lines.push(` - ${agent.label}: ${agent.reasons.join("; ")}`);
13
- }
14
- }
15
10
  lines.push("", "Choose one agent to launch.");
16
11
  return lines.join("\n");
17
12
  }
18
13
  export function renderRootLauncherSingleAgentScreen(options) {
14
+ void options.unavailable;
19
15
  const lines = ["Start a native agent session from this repository.", ""];
20
- if (options.unavailable.length > 0) {
21
- lines.push("", "Unavailable enabled agents:");
22
- for (const agent of options.unavailable) {
23
- lines.push(` - ${agent.label}: ${agent.reasons.join("; ")}`);
24
- }
25
- }
26
16
  lines.push(`Using agent: ${options.selected}`);
27
17
  return lines.join("\n");
28
18
  }
@@ -1,9 +1,6 @@
1
1
  import type { AgentInvocationRecord, RunReport } from "../../domain/run/model/types.js";
2
+ import type { CliWriter } from "../utils/cli-writer.js";
2
3
  import type { StageProgressEventConsumer } from "./stage-progress.js";
3
- type CliWriter = Pick<NodeJS.WriteStream, "write"> & {
4
- isTTY?: boolean;
5
- columns?: number;
6
- };
7
4
  interface RunProgressContext {
8
5
  runId: string;
9
6
  status: RunReport["status"];
@@ -32,6 +29,8 @@ export interface RunTranscriptAgentRecord {
32
29
  startedAt?: string;
33
30
  completedAt?: string;
34
31
  diffStatistics?: string;
32
+ outputPath?: string;
33
+ errorLine?: string;
35
34
  }
36
35
  export interface RunTranscriptOptions {
37
36
  runId: string;
@@ -40,6 +39,7 @@ export interface RunTranscriptOptions {
40
39
  createdAt: string;
41
40
  startedAt?: string;
42
41
  completedAt?: string;
42
+ targetDisplay?: string;
43
43
  agents: readonly RunTranscriptAgentRecord[];
44
44
  isTty?: boolean;
45
45
  now?: number;
@@ -1,12 +1,14 @@
1
1
  import { TERMINAL_RUN_STATUSES } from "../../status/index.js";
2
2
  import { formatCompactDiffStatistics } from "../../utils/diff.js";
3
- import { formatAgentDuration, formatAgentStatusLabelWithStyle, } from "../utils/agents.js";
3
+ import { formatAgentDuration, formatAgentErrorLine, formatAgentStatusLabelWithStyle, } from "../utils/agents.js";
4
4
  import { formatAgentBadge } from "../utils/badges.js";
5
5
  import { formatRenderLifecycleDuration } from "../utils/duration.js";
6
6
  import { createInteractiveFrameRenderer } from "../utils/interactive-frame.js";
7
+ import { clearRefreshIntervalHandle, formatProgressiveRenderErrorDetail, } from "../utils/progressive-render.js";
7
8
  import { formatRunTimestamp } from "../utils/records.js";
8
9
  import { buildRunMetadataSectionWithStyle } from "../utils/runs.js";
9
10
  import { buildStageFrameLines, renderStageFinalFrame, } from "../utils/stage-output.js";
11
+ import { renderTranscript } from "../utils/transcript.js";
10
12
  import { renderTranscriptStatusTable, resolveTranscriptShellStyle, resolveTranscriptShellStyleFromWriter, } from "../utils/transcript-shell.js";
11
13
  const DASH = "—";
12
14
  export function formatRunElapsed(source, now) {
@@ -33,6 +35,7 @@ export function renderRunTranscript(options) {
33
35
  completedAt: options.completedAt,
34
36
  }, options.now) ?? DASH,
35
37
  createdAt: formatRunTimestamp(options.createdAt),
38
+ targetDisplay: options.targetDisplay,
36
39
  }, style),
37
40
  statusTableLines: options.agents.length === 0
38
41
  ? []
@@ -53,41 +56,34 @@ export function renderRunTranscript(options) {
53
56
  extras: [{ header: "CHANGES", accessor: (row) => row.diff }],
54
57
  }),
55
58
  };
56
- return renderStageFinalFrame({
57
- metadataLines: shell.metadataLines,
58
- statusTableLines: shell.statusTableLines,
59
- });
60
- }
61
- function formatErrorDetail(error) {
62
- if (error instanceof Error) {
63
- return error.message;
64
- }
65
- if (typeof error === "string") {
66
- return error;
67
- }
68
- if (error === null || error === undefined) {
69
- return "unknown error";
70
- }
71
- if (typeof error === "number" ||
72
- typeof error === "boolean" ||
73
- typeof error === "bigint") {
74
- return `${error}`;
75
- }
76
- if (typeof error === "symbol") {
77
- return error.description ?? error.toString();
59
+ if (options.agents.length === 0) {
60
+ return renderStageFinalFrame({
61
+ metadataLines: shell.metadataLines,
62
+ statusTableLines: shell.statusTableLines,
63
+ });
78
64
  }
79
- if (typeof error === "object") {
80
- try {
81
- const serialized = JSON.stringify(error);
82
- if (serialized) {
83
- return serialized;
84
- }
65
+ const sections = [
66
+ [
67
+ ...shell.metadataLines,
68
+ ...(shell.statusTableLines.length > 0
69
+ ? ["", ...shell.statusTableLines]
70
+ : []),
71
+ ],
72
+ ["---"],
73
+ ];
74
+ options.agents.forEach((agent, index) => {
75
+ const block = [`Agent: ${agent.agentId}`];
76
+ if (agent.errorLine) {
77
+ const inlineError = agent.errorLine.replace(/\s+/gu, " ").trim();
78
+ block.push("", formatAgentErrorLine(inlineError, style));
85
79
  }
86
- catch {
87
- // ignore JSON serialization failures; fall through to default message.
80
+ block.push("", `Output: ${agent.outputPath ?? DASH}`);
81
+ if (index < options.agents.length - 1) {
82
+ block.push("", "---");
88
83
  }
89
- }
90
- return "unknown error";
84
+ sections.push(block);
85
+ });
86
+ return renderTranscript({ sections });
91
87
  }
92
88
  export function createRunRenderer(options = {}) {
93
89
  const stdout = options.stdout ?? process.stdout;
@@ -103,13 +99,6 @@ export function createRunRenderer(options = {}) {
103
99
  const interactiveFrameRenderer = createInteractiveFrameRenderer(stdout);
104
100
  const agentOrder = [];
105
101
  const agentRecords = new Map();
106
- function stopRefreshLoop() {
107
- if (!refreshInterval) {
108
- return;
109
- }
110
- clearInterval(refreshInterval);
111
- refreshInterval = undefined;
112
- }
113
102
  function hasRunningAgents() {
114
103
  for (const record of agentRecords.values()) {
115
104
  if (record.status === "running") {
@@ -120,11 +109,11 @@ export function createRunRenderer(options = {}) {
120
109
  }
121
110
  function syncRefreshLoop() {
122
111
  if (!stdout.isTTY || disabled) {
123
- stopRefreshLoop();
112
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
124
113
  return;
125
114
  }
126
115
  if (!hasRunningAgents()) {
127
- stopRefreshLoop();
116
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
128
117
  return;
129
118
  }
130
119
  if (refreshInterval) {
@@ -133,11 +122,11 @@ export function createRunRenderer(options = {}) {
133
122
  refreshInterval = setInterval(() => {
134
123
  guard(() => {
135
124
  if (!stdout.isTTY || disabled || !context) {
136
- stopRefreshLoop();
125
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
137
126
  return;
138
127
  }
139
128
  if (!hasRunningAgents()) {
140
- stopRefreshLoop();
129
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
141
130
  return;
142
131
  }
143
132
  const nextElapsed = formatRunElapsed(context);
@@ -158,10 +147,10 @@ export function createRunRenderer(options = {}) {
158
147
  }
159
148
  catch (error) {
160
149
  disabled = true;
161
- stopRefreshLoop();
150
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
162
151
  if (!warningLogged) {
163
152
  warningLogged = true;
164
- const detail = formatErrorDetail(error);
153
+ const detail = formatProgressiveRenderErrorDetail(error);
165
154
  stderr.write(`[voratiq] Progressive run output disabled: ${detail}\n`);
166
155
  }
167
156
  }
@@ -340,7 +329,7 @@ export function createRunRenderer(options = {}) {
340
329
  });
341
330
  },
342
331
  complete(report, options) {
343
- stopRefreshLoop();
332
+ refreshInterval = clearRefreshIntervalHandle(refreshInterval);
344
333
  syncRecordsFromReport(report);
345
334
  guard(() => {
346
335
  this.onProgressEvent({
@@ -1,10 +1,7 @@
1
1
  import type { ExtractedTokenUsage } from "../../domain/run/model/types.js";
2
2
  import type { TokenUsageResult } from "../../workspace/chat/token-usage-result.js";
3
+ import type { CliWriter } from "../utils/cli-writer.js";
3
4
  import type { StageProgressEventConsumer } from "./stage-progress.js";
4
- type CliWriter = Pick<NodeJS.WriteStream, "write"> & {
5
- isTTY?: boolean;
6
- columns?: number;
7
- };
8
5
  export interface SpecProgressContext {
9
6
  sessionId: string;
10
7
  createdAt: string;