voratiq 0.1.0-beta.20 → 0.1.0-beta.21

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 (85) hide show
  1. package/dist/agents/runtime/policy.d.ts +1 -1
  2. package/dist/bin.js +50 -19
  3. package/dist/cli/contract.d.ts +35 -5
  4. package/dist/cli/contract.js +42 -5
  5. package/dist/cli/list.js +4 -1
  6. package/dist/cli/message.d.ts +28 -0
  7. package/dist/cli/message.js +147 -0
  8. package/dist/cli/operator-envelope.d.ts +22 -1
  9. package/dist/cli/operator-envelope.js +48 -3
  10. package/dist/cli/reduce.js +5 -2
  11. package/dist/cli/verify.js +6 -2
  12. package/dist/commands/list/command.d.ts +1 -0
  13. package/dist/commands/list/command.js +117 -7
  14. package/dist/commands/message/command.d.ts +23 -0
  15. package/dist/commands/message/command.js +215 -0
  16. package/dist/commands/message/errors.d.ts +9 -0
  17. package/dist/commands/message/errors.js +20 -0
  18. package/dist/commands/message/lifecycle.d.ts +14 -0
  19. package/dist/commands/message/lifecycle.js +128 -0
  20. package/dist/commands/reduce/command.d.ts +1 -0
  21. package/dist/commands/reduce/command.js +3 -1
  22. package/dist/commands/reduce/targets.d.ts +1 -0
  23. package/dist/commands/reduce/targets.js +48 -2
  24. package/dist/commands/shared/resolve-stage-competitors.js +4 -1
  25. package/dist/commands/verify/command.d.ts +1 -0
  26. package/dist/commands/verify/command.js +2 -1
  27. package/dist/commands/verify/max-parallel.d.ts +1 -1
  28. package/dist/commands/verify/max-parallel.js +3 -1
  29. package/dist/commands/verify/targets.d.ts +2 -1
  30. package/dist/commands/verify/targets.js +154 -22
  31. package/dist/configs/agents/defaults.js +25 -25
  32. package/dist/configs/orchestration/bootstrap.d.ts +6 -1
  33. package/dist/configs/orchestration/bootstrap.js +27 -6
  34. package/dist/configs/orchestration/types.d.ts +25 -10
  35. package/dist/configs/orchestration/types.js +10 -6
  36. package/dist/configs/verification/types.d.ts +5 -0
  37. package/dist/configs/verification/types.js +3 -0
  38. package/dist/contracts/list.d.ts +38 -4
  39. package/dist/contracts/list.js +30 -1
  40. package/dist/domain/message/competition/adapter.d.ts +36 -0
  41. package/dist/domain/message/competition/adapter.js +197 -0
  42. package/dist/domain/message/competition/prompt.d.ts +8 -0
  43. package/dist/domain/message/competition/prompt.js +29 -0
  44. package/dist/domain/message/model/mutators.d.ts +17 -0
  45. package/dist/domain/message/model/mutators.js +107 -0
  46. package/dist/domain/message/model/types.d.ts +100 -0
  47. package/dist/domain/message/model/types.js +87 -0
  48. package/dist/domain/message/persistence/adapter.d.ts +43 -0
  49. package/dist/domain/message/persistence/adapter.js +124 -0
  50. package/dist/domain/reduce/competition/adapter.d.ts +1 -0
  51. package/dist/domain/reduce/competition/adapter.js +57 -4
  52. package/dist/domain/reduce/competition/prompt.d.ts +1 -1
  53. package/dist/domain/reduce/model/types.d.ts +3 -0
  54. package/dist/domain/reduce/model/types.js +2 -1
  55. package/dist/domain/verify/competition/adapter.js +8 -5
  56. package/dist/domain/verify/competition/programmatic.js +3 -0
  57. package/dist/domain/verify/competition/prompt.js +6 -0
  58. package/dist/domain/verify/competition/rubric.js +7 -1
  59. package/dist/domain/verify/competition/shared-layout.d.ts +42 -2
  60. package/dist/domain/verify/competition/shared-layout.js +92 -21
  61. package/dist/domain/verify/competition/target.d.ts +17 -0
  62. package/dist/domain/verify/model/types.d.ts +20 -2
  63. package/dist/domain/verify/model/types.js +15 -2
  64. package/dist/mcp/server.d.ts +2 -2
  65. package/dist/mcp/server.js +30 -13
  66. package/dist/policy/verification.js +2 -0
  67. package/dist/preflight/index.d.ts +2 -0
  68. package/dist/preflight/index.js +3 -1
  69. package/dist/render/transcripts/list.d.ts +2 -0
  70. package/dist/render/transcripts/list.js +24 -0
  71. package/dist/render/transcripts/message.d.ts +72 -0
  72. package/dist/render/transcripts/message.js +362 -0
  73. package/dist/render/transcripts/stage-progress.d.ts +1 -1
  74. package/dist/render/transcripts/verify.d.ts +4 -0
  75. package/dist/render/transcripts/verify.js +7 -1
  76. package/dist/render/utils/transcript-shell.d.ts +1 -1
  77. package/dist/render/utils/transcript-shell.js +6 -0
  78. package/dist/status/index.d.ts +21 -0
  79. package/dist/status/index.js +30 -0
  80. package/dist/workspace/setup.js +13 -7
  81. package/dist/workspace/structure.d.ts +14 -6
  82. package/dist/workspace/structure.js +25 -9
  83. package/dist/workspace/verification-defaults.d.ts +1 -1
  84. package/dist/workspace/verification-defaults.js +255 -0
  85. package/package.json +15 -16
@@ -0,0 +1,147 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { Command, Option } from "commander";
3
+ import { checkPlatformSupport } from "../agents/runtime/sandbox.js";
4
+ import { executeMessageCommand } from "../commands/message/command.js";
5
+ import { buildMarkdownPreviewLines } from "../commands/shared/preview.js";
6
+ import { resolveExtraContextFiles } from "../competition/shared/extra-context.js";
7
+ import { ensureSandboxDependencies, resolveCliContext, } from "../preflight/index.js";
8
+ import { createMessageRenderer, formatMessageElapsed, formatMessageRecipientDuration, renderMessageTranscript, } from "../render/transcripts/message.js";
9
+ import { renderWorkspaceAutoInitializedNotice } from "../render/transcripts/shared.js";
10
+ import { createStageStartLineEmitter } from "../render/utils/stage-output.js";
11
+ import { resolvePath } from "../utils/path.js";
12
+ import { parsePositiveInteger } from "../utils/validators.js";
13
+ import { resolveWorkspacePath, VORATIQ_MESSAGE_FILE, } from "../workspace/structure.js";
14
+ import { parseMessageExecutionCommandOptions } from "./contract.js";
15
+ import { buildMessageOperatorEnvelope, createSilentCliWriter, writeOperatorResultEnvelope, } from "./operator-envelope.js";
16
+ import { writeCommandOutput } from "./output.js";
17
+ export async function runMessageCommand(options) {
18
+ const { prompt, agentIds, profile, maxParallel, extraContext, json = false, stdout, stderr, writeOutput, } = options;
19
+ const effectiveWriteOutput = json
20
+ ? undefined
21
+ : (writeOutput ?? writeCommandOutput);
22
+ const rendererStdout = json ? createSilentCliWriter() : stdout;
23
+ const rendererStderr = json ? createSilentCliWriter() : stderr;
24
+ const isTty = json ? false : (stdout?.isTTY ?? process.stdout.isTTY);
25
+ const { root, workspacePaths, workspaceAutoInitialized } = await resolveCliContext({
26
+ workspaceAutoInitMode: "when-missing",
27
+ });
28
+ const workspaceNotice = workspaceAutoInitialized
29
+ ? renderWorkspaceAutoInitializedNotice()
30
+ : undefined;
31
+ if (workspaceNotice && effectiveWriteOutput) {
32
+ effectiveWriteOutput({
33
+ alerts: [{ severity: "info", message: workspaceNotice }],
34
+ leadingNewline: false,
35
+ });
36
+ }
37
+ checkPlatformSupport();
38
+ ensureSandboxDependencies();
39
+ const extraContextFiles = await resolveExtraContextFiles({
40
+ root,
41
+ paths: extraContext,
42
+ });
43
+ const startLine = createStageStartLineEmitter((message) => {
44
+ effectiveWriteOutput?.({
45
+ alerts: [{ severity: "info", message }],
46
+ });
47
+ });
48
+ if (effectiveWriteOutput) {
49
+ startLine.emit("Messaging…");
50
+ }
51
+ const renderer = createMessageRenderer({
52
+ stdout: rendererStdout,
53
+ stderr: rendererStderr,
54
+ });
55
+ const execution = await executeMessageCommand({
56
+ root,
57
+ messagesFilePath: workspacePaths.messagesFile ??
58
+ resolveWorkspacePath(root, VORATIQ_MESSAGE_FILE),
59
+ prompt,
60
+ agentIds,
61
+ profileName: profile,
62
+ maxParallel,
63
+ extraContextFiles,
64
+ sourceInteractiveSessionId: process.env.VORATIQ_INTERACTIVE_SESSION_ID?.trim() || undefined,
65
+ renderer,
66
+ });
67
+ const body = renderMessageTranscript({
68
+ messageId: execution.messageId,
69
+ createdAt: execution.record.createdAt,
70
+ elapsed: formatMessageElapsed({
71
+ status: execution.record.status,
72
+ startedAt: execution.record.startedAt,
73
+ completedAt: execution.record.completedAt,
74
+ }) ?? "—",
75
+ workspacePath: `.voratiq/message/sessions/${execution.messageId}`,
76
+ status: execution.record.status,
77
+ recipients: await Promise.all(execution.recipients.map(async (recipient) => ({
78
+ agentId: recipient.agentId,
79
+ status: recipient.status,
80
+ duration: formatMessageRecipientDuration({
81
+ status: recipient.status,
82
+ startedAt: recipient.startedAt,
83
+ completedAt: recipient.completedAt,
84
+ }) ?? "—",
85
+ outputPath: recipient.outputPath,
86
+ previewLines: recipient.status === "succeeded" && recipient.outputPath
87
+ ? buildMarkdownPreviewLines(await readFile(resolvePath(root, recipient.outputPath), "utf8"))
88
+ : undefined,
89
+ errorLine: recipient.error ?? undefined,
90
+ }))),
91
+ isTty,
92
+ includeSummarySection: !isTty,
93
+ });
94
+ return {
95
+ body,
96
+ sessionId: execution.messageId,
97
+ status: execution.record.status,
98
+ outputArtifacts: execution.recipients.map((recipient) => ({
99
+ agentId: recipient.agentId,
100
+ outputPath: recipient.outputPath,
101
+ })),
102
+ };
103
+ }
104
+ function collectStringOption(value, previous) {
105
+ return [...previous, value];
106
+ }
107
+ function parseMaxParallelOption(value) {
108
+ return parsePositiveInteger(value, "Expected positive integer after --max-parallel", "--max-parallel must be greater than 0");
109
+ }
110
+ export function createMessageCommand() {
111
+ return new Command("message")
112
+ .description("Send an isolated prompt to one or more agents")
113
+ .requiredOption("--prompt <text>", "Prompt to send")
114
+ .addOption(new Option("--agent <agent-id>", "Set recipient agents directly (repeatable; order preserved)")
115
+ .default([], "")
116
+ .argParser(collectStringOption))
117
+ .option("--profile <name>", 'Orchestration profile (default: "default")')
118
+ .option("--max-parallel <count>", "Max concurrent recipients (default: all)", parseMaxParallelOption)
119
+ .addOption(new Option("--extra-context <path>", "Stage an extra context file into each recipient workspace (repeatable)")
120
+ .default([], "")
121
+ .argParser(collectStringOption))
122
+ .option("--json", "Emit a machine-readable result envelope")
123
+ .allowExcessArguments(false)
124
+ .action(async (options, command) => {
125
+ const input = parseMessageExecutionCommandOptions(options, command);
126
+ const result = await runMessageCommand({
127
+ prompt: input.prompt,
128
+ agentIds: input.agentIds,
129
+ profile: input.profile,
130
+ maxParallel: input.maxParallel,
131
+ extraContext: input.extraContext,
132
+ json: Boolean(options.json),
133
+ });
134
+ if (options.json) {
135
+ writeOperatorResultEnvelope(buildMessageOperatorEnvelope({
136
+ sessionId: result.sessionId,
137
+ status: result.status,
138
+ outputArtifacts: result.outputArtifacts,
139
+ }), result.status === "succeeded" ? 0 : 1);
140
+ return;
141
+ }
142
+ writeCommandOutput({
143
+ body: result.body,
144
+ exitCode: result.status === "succeeded" ? 0 : 1,
145
+ });
146
+ });
147
+ }
@@ -21,8 +21,13 @@ export interface OperatorResultEnvelope {
21
21
  runId?: string;
22
22
  verificationId?: string;
23
23
  reductionId?: string;
24
+ messageId?: string;
24
25
  agentId?: string;
25
26
  };
27
+ target?: {
28
+ kind: string;
29
+ sessionId: string;
30
+ };
26
31
  artifacts: EnvelopeArtifactRef[];
27
32
  selection?: {
28
33
  state: "resolvable" | "unresolved";
@@ -45,6 +50,7 @@ export interface OperatorResultEnvelope {
45
50
  export declare const operatorResultEnvelopeSchema: z.ZodObject<{
46
51
  version: z.ZodLiteral<1>;
47
52
  operator: z.ZodEnum<{
53
+ message: "message";
48
54
  reduce: "reduce";
49
55
  apply: "apply";
50
56
  spec: "spec";
@@ -63,8 +69,13 @@ export declare const operatorResultEnvelopeSchema: z.ZodObject<{
63
69
  runId: z.ZodOptional<z.ZodString>;
64
70
  verificationId: z.ZodOptional<z.ZodString>;
65
71
  reductionId: z.ZodOptional<z.ZodString>;
72
+ messageId: z.ZodOptional<z.ZodString>;
66
73
  agentId: z.ZodOptional<z.ZodString>;
67
74
  }, z.core.$loose>>;
75
+ target: z.ZodOptional<z.ZodObject<{
76
+ kind: z.ZodString;
77
+ sessionId: z.ZodString;
78
+ }, z.core.$loose>>;
68
79
  artifacts: z.ZodArray<z.ZodObject<{
69
80
  kind: z.ZodString;
70
81
  path: z.ZodString;
@@ -99,7 +110,7 @@ export declare const operatorResultEnvelopeSchema: z.ZodObject<{
99
110
  export interface VerifyEnvelopeInput {
100
111
  verificationId: string;
101
112
  target: {
102
- kind: "spec" | "run" | "reduce";
113
+ kind: "spec" | "run" | "reduce" | "message";
103
114
  sessionId: string;
104
115
  };
105
116
  outputPath: string;
@@ -113,6 +124,14 @@ export interface ReduceEnvelopeInput {
113
124
  target: ReductionTarget;
114
125
  status: ReductionStatus;
115
126
  }
127
+ export interface MessageEnvelopeInput {
128
+ sessionId: string;
129
+ status: "queued" | "running" | "succeeded" | "failed" | "aborted";
130
+ outputArtifacts?: ReadonlyArray<{
131
+ agentId: string;
132
+ outputPath?: string;
133
+ }>;
134
+ }
116
135
  export interface ApplyEnvelopeInput {
117
136
  runId: string;
118
137
  agentId: string;
@@ -133,6 +152,7 @@ export declare function buildOperatorEnvelope(options: {
133
152
  unresolvedReasons?: OperatorResultEnvelope["unresolvedReasons"];
134
153
  alerts?: OperatorResultEnvelope["alerts"];
135
154
  error?: OperatorResultEnvelope["error"];
155
+ target?: OperatorResultEnvelope["target"];
136
156
  timestamp?: string;
137
157
  }): OperatorResultEnvelope;
138
158
  export declare function buildFailedOperatorEnvelope(options: {
@@ -150,6 +170,7 @@ export declare function buildRunOperatorEnvelope(options: {
150
170
  }): OperatorResultEnvelope;
151
171
  export declare function buildVerifyOperatorEnvelope(options: VerifyEnvelopeInput): OperatorResultEnvelope;
152
172
  export declare function buildReduceOperatorEnvelope(options: ReduceEnvelopeInput): OperatorResultEnvelope;
173
+ export declare function buildMessageOperatorEnvelope(options: MessageEnvelopeInput): OperatorResultEnvelope;
153
174
  export declare function buildApplyOperatorEnvelope(options: ApplyEnvelopeInput): OperatorResultEnvelope;
154
175
  export declare function buildPruneOperatorEnvelope(options: PruneEnvelopeInput): OperatorResultEnvelope;
155
176
  export declare function writeOperatorResultEnvelope(envelope: OperatorResultEnvelope, exitCode?: number): void;
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { getReductionSessionDirectoryPath, getRunDirectoryPath, getSpecSessionDirectoryPath, } from "../workspace/structure.js";
2
+ import { getMessageSessionDirectoryPath, getReductionSessionDirectoryPath, getRunDirectoryPath, getSpecSessionDirectoryPath, } from "../workspace/structure.js";
3
3
  import { externalExecutionOperators } from "./contract.js";
4
4
  import { toCliError } from "./errors.js";
5
5
  export const operatorResultEnvelopeSchema = z
@@ -14,10 +14,18 @@ export const operatorResultEnvelopeSchema = z
14
14
  runId: z.string().optional(),
15
15
  verificationId: z.string().optional(),
16
16
  reductionId: z.string().optional(),
17
+ messageId: z.string().optional(),
17
18
  agentId: z.string().optional(),
18
19
  })
19
20
  .passthrough()
20
21
  .optional(),
22
+ target: z
23
+ .object({
24
+ kind: z.string(),
25
+ sessionId: z.string(),
26
+ })
27
+ .passthrough()
28
+ .optional(),
21
29
  artifacts: z.array(z
22
30
  .object({
23
31
  kind: z.string(),
@@ -73,6 +81,9 @@ export function buildOperatorEnvelope(options) {
73
81
  if (options.selection) {
74
82
  envelope.selection = options.selection;
75
83
  }
84
+ if (options.target) {
85
+ envelope.target = options.target;
86
+ }
76
87
  if (options.status === "unresolved" &&
77
88
  options.unresolvedReasons &&
78
89
  options.unresolvedReasons.length > 0) {
@@ -153,6 +164,9 @@ export function buildVerifyOperatorEnvelope(options) {
153
164
  if (options.target.kind === "reduce") {
154
165
  ids.reductionId = options.target.sessionId;
155
166
  }
167
+ if (options.target.kind === "message") {
168
+ ids.messageId = options.target.sessionId;
169
+ }
156
170
  const alerts = [];
157
171
  if (options.warningMessage) {
158
172
  alerts.push({ level: "warn", message: options.warningMessage });
@@ -167,6 +181,7 @@ export function buildVerifyOperatorEnvelope(options) {
167
181
  operator: "verify",
168
182
  status,
169
183
  ids,
184
+ target: options.target,
170
185
  artifacts: [
171
186
  {
172
187
  kind: "session",
@@ -235,6 +250,34 @@ export function buildReduceOperatorEnvelope(options) {
235
250
  ],
236
251
  });
237
252
  }
253
+ export function buildMessageOperatorEnvelope(options) {
254
+ return buildOperatorEnvelope({
255
+ operator: "message",
256
+ status: normalizeTerminalStatus(options.status),
257
+ ids: {
258
+ sessionId: options.sessionId,
259
+ },
260
+ artifacts: [
261
+ {
262
+ kind: "session",
263
+ role: "session",
264
+ path: getMessageSessionDirectoryPath(options.sessionId),
265
+ },
266
+ ...(options.outputArtifacts ?? []).flatMap((artifact) => [
267
+ ...(artifact.outputPath
268
+ ? [
269
+ {
270
+ kind: "output",
271
+ role: "output",
272
+ agentId: artifact.agentId,
273
+ path: artifact.outputPath,
274
+ },
275
+ ]
276
+ : []),
277
+ ]),
278
+ ],
279
+ });
280
+ }
238
281
  export function buildApplyOperatorEnvelope(options) {
239
282
  return buildOperatorEnvelope({
240
283
  operator: "apply",
@@ -363,10 +406,12 @@ function getReductionSourcePath(target) {
363
406
  return `.voratiq/spec/sessions/${target.id}`;
364
407
  case "run":
365
408
  return `.voratiq/run/sessions/${target.id}`;
366
- case "verify":
367
- return `.voratiq/verify/sessions/${target.id}`;
368
409
  case "reduce":
369
410
  return `.voratiq/reduce/sessions/${target.id}`;
411
+ case "verify":
412
+ return `.voratiq/verify/sessions/${target.id}`;
413
+ case "message":
414
+ return `.voratiq/message/sessions/${target.id}`;
370
415
  }
371
416
  }
372
417
  function getAgentIdFromSessionArtifactPath(path, sessionId) {
@@ -11,7 +11,7 @@ import { createReduceRenderer, formatReduceElapsed, formatReducerDuration, rende
11
11
  import { createStageStartLineEmitter } from "../render/utils/stage-output.js";
12
12
  import { normalizePathForDisplay, relativeToRoot, resolvePath, } from "../utils/path.js";
13
13
  import { parsePositiveInteger } from "../utils/validators.js";
14
- import { resolveWorkspacePath, VORATIQ_REDUCTION_FILE, VORATIQ_VERIFICATION_FILE, } from "../workspace/structure.js";
14
+ import { resolveWorkspacePath, VORATIQ_MESSAGE_FILE, VORATIQ_REDUCTION_FILE, VORATIQ_VERIFICATION_FILE, } from "../workspace/structure.js";
15
15
  import { parseReduceExecutionCommandOptions } from "./contract.js";
16
16
  import { buildReduceOperatorEnvelope, createSilentCliWriter, writeOperatorResultEnvelope, } from "./operator-envelope.js";
17
17
  import { writeCommandOutput } from "./output.js";
@@ -46,6 +46,8 @@ export async function runReduceCommand(options) {
46
46
  specsFilePath: workspacePaths.specsFile,
47
47
  runsFilePath: workspacePaths.runsFile,
48
48
  reductionsFilePath: workspacePaths.reductionsFile ?? resolveReductionIndexPath(root),
49
+ messagesFilePath: workspacePaths.messagesFile ??
50
+ resolveWorkspacePath(root, VORATIQ_MESSAGE_FILE),
49
51
  verificationsFilePath: workspacePaths.verificationsFile ??
50
52
  resolveWorkspacePath(root, VORATIQ_VERIFICATION_FILE),
51
53
  target,
@@ -159,8 +161,9 @@ export function createReduceCommand() {
159
161
  .description("Reduce artifact sets into a summarized form")
160
162
  .addOption(new Option("--spec <spec-id>", "Spec to reduce"))
161
163
  .addOption(new Option("--run <run-id>", "Run to reduce"))
162
- .addOption(new Option("--verify <verify-id>", "Verification to reduce"))
163
164
  .addOption(new Option("--reduce <reduce-id>", "Reduction to reduce"))
165
+ .addOption(new Option("--verify <verify-id>", "Verification to reduce"))
166
+ .addOption(new Option("--message <message-id>", "Message session to reduce"))
164
167
  .addOption(new Option("--agent <agent-id>", "Set reducers directly (repeatable; order preserved)")
165
168
  .default([], "")
166
169
  .argParser(collectAgentOption))
@@ -19,7 +19,7 @@ import { colorize } from "../utils/colors.js";
19
19
  import { toErrorMessage } from "../utils/errors.js";
20
20
  import { normalizePathForDisplay, relativeToRoot, resolvePath, } from "../utils/path.js";
21
21
  import { parsePositiveInteger } from "../utils/validators.js";
22
- import { resolveWorkspacePath, VORATIQ_REDUCTION_FILE, VORATIQ_VERIFICATION_FILE, VORATIQ_VERIFICATION_SESSIONS_DIR, } from "../workspace/structure.js";
22
+ import { resolveWorkspacePath, VORATIQ_MESSAGE_FILE, VORATIQ_REDUCTION_FILE, VORATIQ_VERIFICATION_FILE, VORATIQ_VERIFICATION_SESSIONS_DIR, } from "../workspace/structure.js";
23
23
  import { parseVerifyExecutionCommandOptions } from "./contract.js";
24
24
  import { buildVerifyOperatorEnvelope, createSilentCliWriter, writeOperatorResultEnvelope, } from "./operator-envelope.js";
25
25
  import { writeCommandOutput } from "./output.js";
@@ -56,6 +56,8 @@ export async function runVerifyCommand(options) {
56
56
  runsFilePath: workspacePaths.runsFile,
57
57
  reductionsFilePath: workspacePaths.reductionsFile ??
58
58
  resolveWorkspacePath(root, VORATIQ_REDUCTION_FILE),
59
+ messagesFilePath: workspacePaths.messagesFile ??
60
+ resolveWorkspacePath(root, VORATIQ_MESSAGE_FILE),
59
61
  verificationsFilePath: workspacePaths.verificationsFile ??
60
62
  resolveWorkspacePath(root, VORATIQ_VERIFICATION_FILE),
61
63
  target,
@@ -120,6 +122,7 @@ export async function runVerifyCommand(options) {
120
122
  completedAt: execution.record.completedAt,
121
123
  }) ?? "—",
122
124
  workspacePath: normalizePathForDisplay(relativeToRoot(root, resolveWorkspacePath(root, VORATIQ_VERIFICATION_SESSIONS_DIR, execution.verificationId))),
125
+ target: execution.record.target,
123
126
  status: execution.record.status,
124
127
  methods: methodBlocks,
125
128
  suppressHint,
@@ -154,10 +157,11 @@ function parseMaxParallelOption(value) {
154
157
  }
155
158
  export function createVerifyCommand() {
156
159
  return new Command("verify")
157
- .description("Verify a recorded spec, run, or reduction")
160
+ .description("Verify a recorded spec, run, reduction, or message session")
158
161
  .addOption(new Option("--spec <spec-id>", "Spec to verify"))
159
162
  .addOption(new Option("--run <run-id>", "Run to verify"))
160
163
  .addOption(new Option("--reduce <reduce-id>", "Reduction to verify"))
164
+ .addOption(new Option("--message <message-id>", "Message session to verify"))
161
165
  .addOption(new Option("--agent <agent-id>", "Set verifiers directly (repeatable; order preserved)")
162
166
  .default([], "")
163
167
  .argParser(collectAgentOption))
@@ -4,6 +4,7 @@ export interface ListCommandInput {
4
4
  specsFilePath: string;
5
5
  runsFilePath: string;
6
6
  reductionsFilePath: string;
7
+ messagesFilePath: string;
7
8
  verificationsFilePath: string;
8
9
  operator: ListOperator;
9
10
  sessionId?: string;
@@ -1,9 +1,11 @@
1
+ import { readMessageRecords, } from "../../domain/message/persistence/adapter.js";
1
2
  import { readReductionRecords, } from "../../domain/reduce/persistence/adapter.js";
2
3
  import { readRunRecords, } from "../../domain/run/persistence/adapter.js";
3
4
  import { readSpecRecords, } from "../../domain/spec/persistence/adapter.js";
4
5
  import { TERMINAL_VERIFICATION_STATUSES } from "../../domain/verify/model/types.js";
5
6
  import { readVerificationRecords, } from "../../domain/verify/persistence/adapter.js";
6
- import { renderListTableTranscript, renderReduceList, renderRunList, renderSpecList, renderVerifyList, } from "../../render/transcripts/list.js";
7
+ import { renderListTableTranscript, renderMessageList, renderReduceList, renderRunList, renderSpecList, renderVerifyList, } from "../../render/transcripts/list.js";
8
+ import { formatMessageElapsed, formatMessageRecipientDuration, renderMessageTranscript, } from "../../render/transcripts/message.js";
7
9
  import { formatReduceElapsed, formatReducerDuration, renderReduceTranscript, } from "../../render/transcripts/reduce.js";
8
10
  import { formatRunElapsed, renderRunTranscript, } from "../../render/transcripts/run.js";
9
11
  import { formatSpecAgentDuration, formatSpecElapsed, renderSpecTranscript, } from "../../render/transcripts/spec.js";
@@ -12,7 +14,7 @@ import { formatAgentDuration } from "../../render/utils/agents.js";
12
14
  import { formatRenderLifecycleDuration } from "../../render/utils/duration.js";
13
15
  import { formatCompactDiffStatistics } from "../../utils/diff.js";
14
16
  import { pathExists } from "../../utils/fs.js";
15
- import { getReductionSessionDirectoryPath, getRunDirectoryPath, getSpecSessionDirectoryPath, getVerificationSessionDirectoryPath, } from "../../workspace/structure.js";
17
+ import { getMessageSessionDirectoryPath, getReductionSessionDirectoryPath, getRunDirectoryPath, getSpecSessionDirectoryPath, getVerificationSessionDirectoryPath, } from "../../workspace/structure.js";
16
18
  const DEFAULT_LIMIT = 10;
17
19
  const DASH = "—";
18
20
  export async function executeListCommand(input) {
@@ -95,9 +97,11 @@ function renderTableOutput(operator, records) {
95
97
  ? renderRunList(records)
96
98
  : operator === "spec"
97
99
  ? renderSpecList(records)
98
- : operator === "reduce"
99
- ? renderReduceList(records)
100
- : renderVerifyList(records);
100
+ : operator === "message"
101
+ ? renderMessageList(records)
102
+ : operator === "reduce"
103
+ ? renderReduceList(records)
104
+ : renderVerifyList(records);
101
105
  return renderListTableTranscript(table);
102
106
  }
103
107
  function renderDetailOutput(operator, record) {
@@ -175,6 +179,32 @@ function renderDetailOutput(operator, record) {
175
179
  isTty: process.stdout.isTTY,
176
180
  });
177
181
  }
182
+ if (operator === "message") {
183
+ const messageRecord = record;
184
+ return renderMessageTranscript({
185
+ messageId: messageRecord.sessionId,
186
+ createdAt: messageRecord.createdAt,
187
+ elapsed: formatMessageElapsed({
188
+ status: messageRecord.status,
189
+ startedAt: messageRecord.startedAt,
190
+ completedAt: messageRecord.completedAt,
191
+ }) ?? DASH,
192
+ workspacePath: getMessageSessionDirectoryPath(messageRecord.sessionId),
193
+ status: messageRecord.status,
194
+ recipients: messageRecord.recipients.map((recipient) => ({
195
+ agentId: recipient.agentId,
196
+ status: recipient.status,
197
+ duration: formatMessageRecipientDuration({
198
+ status: recipient.status,
199
+ startedAt: recipient.startedAt,
200
+ completedAt: recipient.completedAt,
201
+ }) ?? DASH,
202
+ outputPath: recipient.outputPath,
203
+ errorLine: recipient.error ?? undefined,
204
+ })),
205
+ isTty: process.stdout.isTTY,
206
+ });
207
+ }
178
208
  const verificationRecord = record;
179
209
  return renderVerifyTranscript({
180
210
  verificationId: verificationRecord.sessionId,
@@ -185,6 +215,7 @@ function renderDetailOutput(operator, record) {
185
215
  completedAt: verificationRecord.completedAt,
186
216
  }) ?? DASH,
187
217
  workspacePath: getVerificationSessionDirectoryPath(verificationRecord.sessionId),
218
+ target: verificationRecord.target,
188
219
  status: verificationRecord.status,
189
220
  methods: verificationRecord.methods.map((method) => ({
190
221
  verifierLabel: method.method === "programmatic"
@@ -231,6 +262,15 @@ function toJsonTableRecord(operator, record) {
231
262
  },
232
263
  };
233
264
  }
265
+ if (operator === "message") {
266
+ const messageRecord = record;
267
+ return {
268
+ id: messageRecord.sessionId,
269
+ status: messageRecord.status,
270
+ createdAt: messageRecord.createdAt,
271
+ promptPreview: normalizePreviewText(messageRecord.prompt),
272
+ };
273
+ }
234
274
  const verificationRecord = record;
235
275
  return {
236
276
  id: verificationRecord.sessionId,
@@ -275,10 +315,26 @@ function toJsonDetailSession(operator, record) {
275
315
  createdAt: reductionRecord.createdAt,
276
316
  elapsed: formatReductionRecordElapsed(reductionRecord),
277
317
  workspacePath: getReductionSessionDirectoryPath(reductionRecord.sessionId),
318
+ target: {
319
+ kind: reductionRecord.target.type,
320
+ id: reductionRecord.target.id,
321
+ },
278
322
  rows: reductionRecord.reducers.map(toReductionJsonRow),
279
323
  artifacts: reductionRecord.reducers.map(toReductionArtifact),
280
324
  };
281
325
  }
326
+ if (operator === "message") {
327
+ const messageRecord = record;
328
+ return {
329
+ id: messageRecord.sessionId,
330
+ status: messageRecord.status,
331
+ createdAt: messageRecord.createdAt,
332
+ elapsed: formatMessageRecordElapsed(messageRecord),
333
+ workspacePath: getMessageSessionDirectoryPath(messageRecord.sessionId),
334
+ rows: messageRecord.recipients.map(toMessageJsonRow),
335
+ artifacts: messageRecord.recipients.flatMap(toMessageArtifacts),
336
+ };
337
+ }
282
338
  const verificationRecord = record;
283
339
  return {
284
340
  id: verificationRecord.sessionId,
@@ -286,6 +342,10 @@ function toJsonDetailSession(operator, record) {
286
342
  createdAt: verificationRecord.createdAt,
287
343
  elapsed: formatVerificationRecordElapsed(verificationRecord),
288
344
  workspacePath: getVerificationSessionDirectoryPath(verificationRecord.sessionId),
345
+ target: {
346
+ kind: verificationRecord.target.kind,
347
+ id: verificationRecord.target.sessionId,
348
+ },
289
349
  rows: verificationRecord.methods.map(toVerificationJsonRow),
290
350
  artifacts: verificationRecord.methods.map(toVerificationArtifact),
291
351
  };
@@ -311,6 +371,20 @@ function formatReductionRecordElapsed(record) {
311
371
  completedAt: record.completedAt,
312
372
  });
313
373
  }
374
+ function formatMessageRecordElapsed(record) {
375
+ return formatMessageElapsed({
376
+ status: record.status,
377
+ startedAt: record.startedAt,
378
+ completedAt: record.completedAt,
379
+ });
380
+ }
381
+ function normalizePreviewText(value) {
382
+ if (!value) {
383
+ return null;
384
+ }
385
+ const normalized = value.replace(/\s+/gu, " ").trim();
386
+ return normalized.length > 0 ? normalized : null;
387
+ }
314
388
  function formatVerificationRecordElapsed(record) {
315
389
  return formatVerifyElapsed({
316
390
  status: record.status,
@@ -373,6 +447,26 @@ function toReductionArtifact(reducer) {
373
447
  path: reducer.outputPath ?? null,
374
448
  };
375
449
  }
450
+ function toMessageJsonRow(recipient) {
451
+ return {
452
+ agentId: recipient.agentId,
453
+ status: recipient.status,
454
+ duration: formatMessageRecipientDuration({
455
+ status: recipient.status,
456
+ startedAt: recipient.startedAt,
457
+ completedAt: recipient.completedAt,
458
+ }) ?? DASH,
459
+ };
460
+ }
461
+ function toMessageArtifacts(recipient) {
462
+ return [
463
+ {
464
+ kind: "output",
465
+ agentId: recipient.agentId,
466
+ path: recipient.outputPath ?? null,
467
+ },
468
+ ];
469
+ }
376
470
  function getVerificationMethodLabel(method) {
377
471
  return method.method === "programmatic"
378
472
  ? "programmatic"
@@ -456,6 +550,23 @@ async function readOperatorRecords(input) {
456
550
  warnings: warnings.map(formatSessionWarning),
457
551
  };
458
552
  }
553
+ if (operator === "message") {
554
+ if (!(await pathExists(input.messagesFilePath))) {
555
+ return { records: [], warnings: [] };
556
+ }
557
+ const warnings = [];
558
+ const records = await readMessageRecords({
559
+ root,
560
+ messagesFilePath: input.messagesFilePath,
561
+ limit: input.limit,
562
+ predicate: input.predicate,
563
+ onWarning: (warning) => warnings.push(warning),
564
+ });
565
+ return {
566
+ records,
567
+ warnings: warnings.map(formatSessionWarning),
568
+ };
569
+ }
459
570
  if (!(await pathExists(input.verificationsFilePath))) {
460
571
  return { records: [], warnings: [] };
461
572
  }
@@ -482,8 +593,7 @@ function getRecordId(operator, record) {
482
593
  if (operator === "run") {
483
594
  return record.runId;
484
595
  }
485
- return record
486
- .sessionId;
596
+ return record.sessionId;
487
597
  }
488
598
  function formatSessionWarning(warning) {
489
599
  return `Ignoring corrupt session ${warning.displayPath}`;
@@ -0,0 +1,23 @@
1
+ import type { ResolvedExtraContextFile } from "../../competition/shared/extra-context.js";
2
+ import { type MessageCompetitionExecution } from "../../domain/message/competition/adapter.js";
3
+ import { type MessageRecipientEntry, type MessageRecord } from "../../domain/message/model/types.js";
4
+ import type { MessageProgressRenderer } from "../../render/transcripts/message.js";
5
+ export interface ExecuteMessageCommandInput {
6
+ root: string;
7
+ messagesFilePath: string;
8
+ prompt: string;
9
+ agentIds?: readonly string[];
10
+ agentOverrideFlag?: string;
11
+ profileName?: string;
12
+ maxParallel?: number;
13
+ extraContextFiles?: readonly ResolvedExtraContextFile[];
14
+ sourceInteractiveSessionId?: string;
15
+ renderer?: MessageProgressRenderer;
16
+ }
17
+ export interface ExecuteMessageCommandResult {
18
+ messageId: string;
19
+ record: MessageRecord;
20
+ recipients: readonly MessageRecipientEntry[];
21
+ executions: readonly MessageCompetitionExecution[];
22
+ }
23
+ export declare function executeMessageCommand(input: ExecuteMessageCommandInput): Promise<ExecuteMessageCommandResult>;