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
@@ -6,7 +6,7 @@ import process from "node:process";
6
6
  import { collectProviderArtifacts, prepareProviderArtifactCaptureContext, } from "../agents/launch/chat.js";
7
7
  import { writeStagedPrompt } from "../agents/launch/prompt.js";
8
8
  import { resolveAgentProviderForDefinition } from "../agents/launch/provider-state.js";
9
- import { clearActiveInteractive, finalizeActiveInteractive, registerActiveInteractive, } from "../commands/interactive/lifecycle.js";
9
+ import { clearActiveInteractive, finalizeActiveInteractive, getActiveInteractiveTerminationStatus, registerActiveInteractive, } from "../commands/interactive/lifecycle.js";
10
10
  import { createTeardownController, runTeardown, } from "../competition/shared/teardown.js";
11
11
  import { AgentBinaryAccessError, AgentBinaryMissingError, AgentDisabledError, AgentNotFoundError, } from "../configs/agents/errors.js";
12
12
  import { loadAgentById } from "../configs/agents/loader.js";
@@ -14,6 +14,7 @@ import { resolveFirstPartyLaunchPrompt } from "../domain/interactive/prompt.js";
14
14
  import { toErrorMessage } from "../utils/errors.js";
15
15
  import { isMissing } from "../utils/fs.js";
16
16
  import { generateSessionId } from "../utils/session-id.js";
17
+ import { normalizeInteractiveTerm } from "../utils/terminal.js";
17
18
  import { resolveVoratiqCliTarget } from "../utils/voratiq-cli-target.js";
18
19
  import { createBundledVoratiqToolDeclaration, prepareProviderNativeLaunch, resolveFirstPartyMcpStatus, } from "./providers.js";
19
20
  import { appendInteractiveSessionRecord, ensureInteractiveSessionDirectories, resolveInteractiveSessionPaths, rewriteInteractiveSessionRecord, toInteractiveSessionRelativePath, } from "./records.js";
@@ -127,6 +128,7 @@ export async function prepareNativeInteractiveSession(options) {
127
128
  try {
128
129
  firstPartyMcpResolution = await resolveFirstPartyMcpStatus({
129
130
  providerId,
131
+ providerBinary: agent.binary,
130
132
  root: options.root,
131
133
  toolDeclarations,
132
134
  promptForMcpInstall: options.promptForMcpInstall,
@@ -169,6 +171,11 @@ export async function prepareNativeInteractiveSession(options) {
169
171
  agent,
170
172
  root: options.root,
171
173
  toolDeclarations,
174
+ sessionScopedMcpEnv: providerId === "codex"
175
+ ? {
176
+ VORATIQ_INTERACTIVE_SESSION_ID: sessionId,
177
+ }
178
+ : undefined,
172
179
  prompt,
173
180
  launchMode: options.launchMode,
174
181
  firstPartyMcpResolution,
@@ -182,8 +189,8 @@ export async function prepareNativeInteractiveSession(options) {
182
189
  ...process.env,
183
190
  ...providerLaunch.env,
184
191
  VORATIQ_INTERACTIVE_SESSION_ID: sessionId,
185
- VORATIQ_INTERACTIVE_SESSION_ROOT: paths.sessionRoot,
186
192
  };
193
+ delete invocationEnv.VORATIQ_INTERACTIVE_SESSION_ROOT;
187
194
  let artifactCaptureContext;
188
195
  if (providerLaunch.artifactCaptureSupported) {
189
196
  try {
@@ -191,6 +198,13 @@ export async function prepareNativeInteractiveSession(options) {
191
198
  providerId,
192
199
  sessionRoot: paths.sessionRoot,
193
200
  searchEnv: invocationEnv,
201
+ selectionHint: providerId === "codex"
202
+ ? {
203
+ strategy: "codex-session-meta",
204
+ cwd: cwd.path,
205
+ minStartedAt: createdAt,
206
+ }
207
+ : undefined,
194
208
  });
195
209
  }
196
210
  catch {
@@ -251,9 +265,15 @@ export async function spawnPreparedInteractiveSession(prepared, options = {}) {
251
265
  if (stdio === "inherit") {
252
266
  process.stdout.write("\n");
253
267
  }
268
+ const spawnEnv = stdio === "inherit"
269
+ ? {
270
+ ...prepared.invocation.env,
271
+ TERM: normalizeInteractiveTerm(prepared.invocation.env),
272
+ }
273
+ : prepared.invocation.env;
254
274
  const child = spawn(prepared.invocation.command, prepared.invocation.args, {
255
275
  cwd: prepared.invocation.cwd,
256
- env: prepared.invocation.env,
276
+ env: spawnEnv,
257
277
  stdio,
258
278
  });
259
279
  const completion = createProcessCompletionPromise(prepared, child);
@@ -321,9 +341,11 @@ function createProcessCompletionPromise(prepared, child) {
321
341
  return;
322
342
  }
323
343
  finalized = true;
344
+ const terminationStatus = getActiveInteractiveTerminationStatus(prepared.sessionId);
345
+ const signalCountsAsSuccess = terminationStatus === "aborted" && options.signal !== null;
324
346
  const runtimeFailureMessage = options.spawnError
325
347
  ? `Failed during provider execution: ${options.spawnError.message}`
326
- : options.signal
348
+ : options.signal && !signalCountsAsSuccess
327
349
  ? `Provider process terminated by signal ${options.signal}`
328
350
  : options.exitCode && options.exitCode !== 0
329
351
  ? `Provider process exited with code ${options.exitCode}`
@@ -509,10 +531,15 @@ function failure(kind, code, message, cause) {
509
531
  };
510
532
  }
511
533
  function buildBaseRecord(options) {
512
- const { sessionId, createdAt, status, agentId, toolAttachmentStatus, chat, error, } = options;
534
+ const { sessionId, createdAt, status, agentId, toolAttachmentStatus, startedAt, completedAt, chat, error, } = options;
535
+ const resolvedStartedAt = startedAt ?? createdAt;
513
536
  return {
514
537
  sessionId,
515
538
  createdAt,
539
+ startedAt: resolvedStartedAt,
540
+ ...(status !== "running"
541
+ ? { completedAt: completedAt ?? resolvedStartedAt }
542
+ : {}),
516
543
  status,
517
544
  agentId,
518
545
  toolAttachmentStatus,
@@ -62,6 +62,7 @@ interface JsonRpcErrorResponse {
62
62
  };
63
63
  }
64
64
  type JsonRpcResponse = JsonRpcSuccessResponse | JsonRpcErrorResponse;
65
+ export declare const VORATIQ_GUIDE_RESOURCE_URI: "voratiq://guide";
65
66
  export declare function getVoratiqMcpToolDefinitions(): readonly McpToolDefinition[];
66
67
  export declare function createVoratiqMcpRequestHandler(options?: CreateVoratiqMcpRequestHandlerOptions): {
67
68
  handleRequest: (message: JsonRpcRequestMessage) => Promise<JsonRpcResponse>;
@@ -1,9 +1,13 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { mkdtemp, readFile, rm } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
2
5
  import process from "node:process";
3
6
  import { z } from "zod";
4
- import { externalApplyExecutionInputSchema, externalListInspectionInputSchema, externalMessageExecutionInputSchema, externalPruneExecutionInputSchema, externalReduceExecutionInputSchema, externalRunExecutionInputSchema, externalSpecExecutionInputSchema, externalVerifyExecutionInputSchema, } from "../cli/contract.js";
5
- import { operatorResultEnvelopeSchema, } from "../cli/operator-envelope.js";
6
- import { listJsonOutputSchema, } from "../contracts/list.js";
7
+ import { externalApplyExecutionInputSchema, externalInspectionOperatorSchema, externalMessageExecutionInputSchema, externalPruneExecutionInputSchema, externalReduceExecutionInputSchema, externalRunExecutionInputSchema, externalSpecExecutionInputSchema, externalVerifyExecutionInputSchema, } from "../cli/contract.js";
8
+ import { buildSwarmSessionAcknowledgementEnvelope, operatorResultEnvelopeSchema, } from "../cli/operator-envelope.js";
9
+ import { listJsonModes, listJsonModeSchema, listJsonOutputSchema, } from "../contracts/list.js";
10
+ import { VORATIQ_MCP_ACK_OPERATOR_ENV, VORATIQ_MCP_ACK_PATH_ENV, } from "../utils/swarm-session-ack.js";
7
11
  import { getVoratiqVersion } from "../utils/version.js";
8
12
  import { createEntrypointVoratiqCliTarget as createEntrypointCliTarget, resolveVoratiqCliTarget, } from "../utils/voratiq-cli-target.js";
9
13
  const JSON_RPC_VERSION = "2.0";
@@ -14,6 +18,8 @@ const JSON_RPC_INVALID_REQUEST = -32600;
14
18
  const JSON_RPC_METHOD_NOT_FOUND = -32601;
15
19
  const JSON_RPC_INVALID_PARAMS = -32602;
16
20
  const JSON_RPC_INTERNAL_ERROR = -32603;
21
+ const SWARM_EARLY_ACK_TIMEOUT_MS = 15_000;
22
+ const SWARM_EARLY_ACK_POLL_INTERVAL_MS = 100;
17
23
  export const VORATIQ_MCP_PROTOCOL_VERSION = "2025-11-25";
18
24
  export const VORATIQ_SUPPORTED_MCP_PROTOCOL_VERSIONS = [
19
25
  VORATIQ_MCP_PROTOCOL_VERSION,
@@ -23,6 +29,25 @@ export const VORATIQ_SUPPORTED_MCP_PROTOCOL_VERSIONS = [
23
29
  function isSupportedMcpProtocolVersion(protocolVersion) {
24
30
  return VORATIQ_SUPPORTED_MCP_PROTOCOL_VERSIONS.includes(protocolVersion);
25
31
  }
32
+ const mcpListInspectionInputSchema = z.discriminatedUnion("mode", [
33
+ z
34
+ .object({
35
+ operator: externalInspectionOperatorSchema,
36
+ mode: z.literal(listJsonModes[0]),
37
+ verbose: z.boolean().optional(),
38
+ limit: z.number().int().positive().optional(),
39
+ })
40
+ .strict(),
41
+ z
42
+ .object({
43
+ operator: externalInspectionOperatorSchema,
44
+ mode: z.literal(listJsonModes[1]),
45
+ sessionId: z.string().min(1),
46
+ verbose: z.boolean().optional(),
47
+ limit: z.number().int().positive().optional(),
48
+ })
49
+ .strict(),
50
+ ]);
26
51
  const initializeRequestParamsSchema = z
27
52
  .object({
28
53
  protocolVersion: z.string(),
@@ -70,7 +95,7 @@ const toolSpecs = [
70
95
  {
71
96
  name: "voratiq_message",
72
97
  operator: "message",
73
- description: "Send an isolated prompt to one or more Voratiq agents and persist their independent replies as a durable message session.",
98
+ description: "Send an isolated prompt to one or more Voratiq agents and persist their independent replies as a recorded message session.",
74
99
  inputSchemaSource: externalMessageExecutionInputSchema,
75
100
  buildArgs: (input) => buildMessageExecutionArgs(input),
76
101
  outputContract: "execution",
@@ -86,8 +111,8 @@ const toolSpecs = [
86
111
  {
87
112
  name: "voratiq_list",
88
113
  operator: "list",
89
- description: "List recorded Voratiq sessions for one operator (`spec`, `run`, `reduce`, `verify`, or `message`) in table or detail mode.",
90
- inputSchemaSource: externalListInspectionInputSchema,
114
+ description: "List recorded Voratiq sessions for one operator (`spec`, `run`, `reduce`, `verify`, `message`, or `interactive`) in list or detail mode.",
115
+ inputSchemaSource: mcpListInspectionInputSchema,
91
116
  mcpInputSchema: createListMcpInputSchema(),
92
117
  buildArgs: (input) => buildListInspectionArgs(input),
93
118
  outputContract: "list",
@@ -107,7 +132,70 @@ const toolDefinitions = toolSpecs.map((tool) => ({
107
132
  description: tool.description,
108
133
  inputSchema: tool.mcpInputSchema ?? toToolInputJsonSchema(tool.inputSchemaSource),
109
134
  }));
110
- const VORATIQ_MCP_SERVER_INSTRUCTIONS = "Voratiq tools operate on Voratiq workflow state in the current repository. Use voratiq_list for questions about recent or specific spec, run, reduce, verify, or message sessions. Use voratiq_spec, voratiq_run, voratiq_reduce, voratiq_verify, voratiq_message, voratiq_apply, and voratiq_prune for the normal Voratiq workflow. Prefer these tools over shell inspection when the task is about Voratiq workflow history or state.";
135
+ export const VORATIQ_GUIDE_RESOURCE_URI = "voratiq://guide";
136
+ const VORATIQ_GUIDE_RESOURCE_CONTENT = `# Voratiq Operator Guide
137
+
138
+ Voratiq is a workflow system built around composable operators that launch, evaluate, and manage multi-agent work against a repository. It gives interactive agents a structured way to delegate coding tasks, inspect recorded state, verify outcomes, and apply accepted changes without doing all of that inline.
139
+
140
+ ## Operator Classes
141
+
142
+ Voratiq operators fall into two main classes:
143
+
144
+ - **Swarm operators** dispatch agents to produce, synthesize, or evaluate work: spec, run, reduce, verify, message
145
+ - **Control operators** inspect state or mutate accepted outcomes: list, apply, prune
146
+
147
+ ## Swarm Operators
148
+
149
+ **spec** – Drafts or refines a specification for a task from a description, an existing spec, or related repository context. Launches one or more spec agents and records their outputs as a spec session.
150
+
151
+ **run** – Executes a spec session by launching run agents that read the spec, work against a sandboxed workspace, and produce artifacts including diffs and transcripts. Records a run session.
152
+
153
+ **reduce** – Summarizes artifacts from a spec, run, or message session into a single reduced output suitable for comparison or follow-on work. Records a reduce session.
154
+
155
+ **verify** – Evaluates a spec, run, reduction, or message session and records a structured verdict. This is Voratiq's main decision operator: use it to compare outputs, choose stronger candidates, and decide whether work should be applied, inspected further, rerun, or redirected.
156
+
157
+ **message** – Sends an isolated prompt to one or more agents and persists each reply independently as a message session. Use for standalone questions, reviews, or exploration that does not require a full spec/run workflow.
158
+
159
+ ## Control Operators
160
+
161
+ **list** – Lists or inspects recorded sessions for a given operator. This is the primary way to inspect swarm sessions; use it to poll progress, retrieve session IDs, and inspect recorded workflow state.
162
+
163
+ **apply** – Applies an accepted run diff into the current working tree. Synchronous and non-durable; only invoke after verifying that the target run is in an acceptable state.
164
+
165
+ **prune** – Removes pruneable run workspaces or all pruneable state. Synchronous and non-durable; requires explicit confirmation.
166
+
167
+ ## Workflow Composition
168
+
169
+ Operators compose into many workflow shapes rather than one required path. Common patterns include: using message for standalone exploration or review; using spec → verify to compare candidate specs before execution; using spec → run when a task needs structured execution; using run → verify to choose among competing implementations; using reduce when multiple outputs need synthesis before a decision; and using verify whenever a workflow needs a structured recommendation instead of ad hoc judgment. The list operator can be called at any point to inspect recorded state across all operators.
170
+
171
+ ## Swarm Session Behavior
172
+
173
+ The five swarm operators are spec, run, reduce, verify, and message. Each one creates a recorded session and may return before the session is finished. Once a session has been created, treat that session as the unit of work. A returned sessionId means the work has been launched, not completed. Use voratiq_list to inspect active sessions.
174
+
175
+ ## Status Interpretation
176
+
177
+ Session status is primary; recipient status is supporting detail.
178
+
179
+ - **queued** means the session has been accepted and recorded but its work has not started yet.
180
+ - **running** means the session is active and remains the canonical in-flight unit of work.
181
+ - **succeeded** means the session reached a successful terminal state; inspect its outputs and decide what should happen next.
182
+ - **failed** means the session reached a terminal failure state.
183
+ - **unresolved** means the session reached a terminal state without a clear winner or confident decision.
184
+
185
+ Mixed recipient states do not imply session failure. Some recipients may fail while others continue running, and the session remains active until its session status becomes terminal.
186
+
187
+ ## extraContext Contract
188
+
189
+ The extraContext field accepts an array of file paths pointing to additional readable files staged alongside the operator workspace. Pass file paths only — not raw text content, and not paths to files that operators already see by default (such as standard repository context). Passing raw content or redundant paths increases token usage without providing new information.
190
+
191
+ ## maxParallel Semantics
192
+
193
+ The maxParallel field controls the maximum number of agent recipients running in parallel for an operator invocation. Set it deliberately: it directly affects cost and latency. Higher values increase concurrency but also increase total token expenditure and can create contention. Do not treat maxParallel as a free dial to increase throughput without modeling the downstream cost and latency impact.
194
+
195
+ ## Key Discipline Rules
196
+
197
+ Commit to one workflow objective per session; do not interleave unrelated operator calls in the same sequence. Wait for stage boundaries before acting on results: read voratiq_list output before proceeding from one stage to the next. Use voratiq_list as the primary control plane for inspecting recorded state rather than reading session files directly.`;
198
+ const VORATIQ_MCP_SERVER_INSTRUCTIONS = "Voratiq tools operate on Voratiq workflow state in the current repository. Use voratiq_list for questions about recent or specific spec, run, reduce, verify, message, or interactive sessions. The swarm operators (voratiq_spec, voratiq_run, voratiq_reduce, voratiq_verify, voratiq_message) create recorded sessions and may acknowledge before finishing; once launched, treat the session as the unit of work. If a swarm call times out or returns a non-terminal status, inspect progress with voratiq_list instead of retrying. Use voratiq_apply and voratiq_prune for synchronous control actions. Prefer these tools over shell inspection when the task is about Voratiq workflow history or state.";
111
199
  const toolSpecsByName = new Map(toolSpecs.map((tool) => [tool.name, tool]));
112
200
  export function getVoratiqMcpToolDefinitions() {
113
201
  return toolDefinitions;
@@ -144,6 +232,7 @@ export function createVoratiqMcpRequestHandler(options = {}) {
144
232
  tools: {
145
233
  listChanged: true,
146
234
  },
235
+ resources: {},
147
236
  },
148
237
  instructions: VORATIQ_MCP_SERVER_INSTRUCTIONS,
149
238
  serverInfo: {
@@ -185,6 +274,33 @@ export function createVoratiqMcpRequestHandler(options = {}) {
185
274
  });
186
275
  return createSuccessResponse(message.id, result);
187
276
  }
277
+ if (message.method === "resources/list") {
278
+ return createSuccessResponse(message.id, {
279
+ resources: [
280
+ {
281
+ uri: VORATIQ_GUIDE_RESOURCE_URI,
282
+ name: "Voratiq Operator Guide",
283
+ description: "Complete reference for Voratiq operators, workflow composition, swarm-session behavior, extraContext contract, and maxParallel semantics.",
284
+ mimeType: "text/plain",
285
+ },
286
+ ],
287
+ });
288
+ }
289
+ if (message.method === "resources/read") {
290
+ const uri = isRecord(message.params) ? message.params.uri : undefined;
291
+ if (uri === VORATIQ_GUIDE_RESOURCE_URI) {
292
+ return createSuccessResponse(message.id, {
293
+ contents: [
294
+ {
295
+ uri: VORATIQ_GUIDE_RESOURCE_URI,
296
+ mimeType: "text/plain",
297
+ text: VORATIQ_GUIDE_RESOURCE_CONTENT,
298
+ },
299
+ ],
300
+ });
301
+ }
302
+ return createErrorResponse(message.id, JSON_RPC_INVALID_PARAMS, `Unknown resource URI: ${String(uri)}`);
303
+ }
188
304
  return createErrorResponse(message.id, JSON_RPC_METHOD_NOT_FOUND, `Method not found: ${message.method}`);
189
305
  },
190
306
  handleNotification(message) {
@@ -207,7 +323,10 @@ export async function runVoratiqMcpStdioServer(options = {}) {
207
323
  const pendingPayloads = [];
208
324
  let isDraining = false;
209
325
  let hasEnded = false;
326
+ let inFlightHandlers = 0;
327
+ let hasCompletedInitialize = false;
210
328
  let transportEncoding = "framed";
329
+ let writeChain = Promise.resolve();
211
330
  await new Promise((resolve, reject) => {
212
331
  const tryResolve = () => {
213
332
  if (!hasEnded) {
@@ -219,8 +338,53 @@ export async function runVoratiqMcpStdioServer(options = {}) {
219
338
  if (pendingPayloads.length > 0) {
220
339
  return;
221
340
  }
341
+ if (inFlightHandlers > 0) {
342
+ return;
343
+ }
222
344
  resolve();
223
345
  };
346
+ const writeMessageSerialized = (outputEncoding, message) => {
347
+ writeChain = writeChain.then(() => {
348
+ writeMessage(stdout, outputEncoding, message);
349
+ });
350
+ return writeChain;
351
+ };
352
+ const handlePayload = async (payload, outputEncoding) => {
353
+ try {
354
+ const parsed = JSON.parse(payload);
355
+ const message = normalizeIncomingMessage(parsed);
356
+ if (!message) {
357
+ await writeMessageSerialized(outputEncoding, createErrorResponse(null, JSON_RPC_INVALID_REQUEST, "Invalid JSON-RPC message."));
358
+ return;
359
+ }
360
+ if ("id" in message) {
361
+ const response = await requestHandler.handleRequest(message);
362
+ await writeMessageSerialized(outputEncoding, response);
363
+ if (message.method === "initialize" && !("error" in response)) {
364
+ hasCompletedInitialize = true;
365
+ await writeMessageSerialized(outputEncoding, createNotification("notifications/tools/list_changed"));
366
+ }
367
+ return;
368
+ }
369
+ await requestHandler.handleNotification(message);
370
+ }
371
+ catch (error) {
372
+ if (error instanceof SyntaxError) {
373
+ await writeMessageSerialized(outputEncoding, createErrorResponse(null, JSON_RPC_PARSE_ERROR, "Failed to parse JSON-RPC payload.", { message: error.message }));
374
+ return;
375
+ }
376
+ await writeMessageSerialized(outputEncoding, createErrorResponse(null, JSON_RPC_INTERNAL_ERROR, "Unhandled MCP server error.", {
377
+ message: toErrorMessage(error),
378
+ }));
379
+ }
380
+ };
381
+ const dispatchPayload = (payload, outputEncoding) => {
382
+ inFlightHandlers += 1;
383
+ return handlePayload(payload, outputEncoding).finally(() => {
384
+ inFlightHandlers -= 1;
385
+ tryResolve();
386
+ });
387
+ };
224
388
  const drainQueue = () => {
225
389
  if (isDraining) {
226
390
  return;
@@ -228,36 +392,15 @@ export async function runVoratiqMcpStdioServer(options = {}) {
228
392
  isDraining = true;
229
393
  void (async () => {
230
394
  while (pendingPayloads.length > 0) {
231
- const payload = pendingPayloads.shift();
232
- if (payload === undefined) {
395
+ const queued = pendingPayloads.shift();
396
+ if (queued === undefined) {
233
397
  continue;
234
398
  }
235
- try {
236
- const parsed = JSON.parse(payload);
237
- const message = normalizeIncomingMessage(parsed);
238
- if (!message) {
239
- writeMessage(stdout, transportEncoding, createErrorResponse(null, JSON_RPC_INVALID_REQUEST, "Invalid JSON-RPC message."));
240
- continue;
241
- }
242
- if ("id" in message) {
243
- const response = await requestHandler.handleRequest(message);
244
- writeMessage(stdout, transportEncoding, response);
245
- if (message.method === "initialize" && !("error" in response)) {
246
- writeMessage(stdout, transportEncoding, createNotification("notifications/tools/list_changed"));
247
- }
248
- continue;
249
- }
250
- await requestHandler.handleNotification(message);
251
- }
252
- catch (error) {
253
- if (error instanceof SyntaxError) {
254
- writeMessage(stdout, transportEncoding, createErrorResponse(null, JSON_RPC_PARSE_ERROR, "Failed to parse JSON-RPC payload.", { message: error.message }));
255
- continue;
256
- }
257
- writeMessage(stdout, transportEncoding, createErrorResponse(null, JSON_RPC_INTERNAL_ERROR, "Unhandled MCP server error.", {
258
- message: toErrorMessage(error),
259
- }));
399
+ if (!hasCompletedInitialize) {
400
+ await dispatchPayload(queued.payload, queued.transportEncoding);
401
+ continue;
260
402
  }
403
+ void dispatchPayload(queued.payload, queued.transportEncoding);
261
404
  }
262
405
  isDraining = false;
263
406
  tryResolve();
@@ -276,7 +419,10 @@ export async function runVoratiqMcpStdioServer(options = {}) {
276
419
  break;
277
420
  }
278
421
  transportEncoding = extracted.transportEncoding;
279
- pendingPayloads.push(extracted.payload);
422
+ pendingPayloads.push({
423
+ payload: extracted.payload,
424
+ transportEncoding,
425
+ });
280
426
  buffer = Buffer.from(extracted.remaining);
281
427
  }
282
428
  drainQueue();
@@ -285,7 +431,10 @@ export async function runVoratiqMcpStdioServer(options = {}) {
285
431
  const trailingPayload = extractTrailingJsonLine(buffer);
286
432
  if (trailingPayload) {
287
433
  transportEncoding = "jsonl";
288
- pendingPayloads.push(trailingPayload);
434
+ pendingPayloads.push({
435
+ payload: trailingPayload,
436
+ transportEncoding,
437
+ });
289
438
  buffer = Buffer.alloc(0);
290
439
  drainQueue();
291
440
  }
@@ -498,10 +647,20 @@ function appendOptionalTrueFlag(args, flag, enabled) {
498
647
  }
499
648
  export { createEntrypointCliTarget, resolveVoratiqCliTarget };
500
649
  export function createDefaultCliJsonContractInvoker(target = resolveVoratiqCliTarget()) {
501
- return async (input) => await invokeSubprocess({
502
- command: target.command,
503
- args: [...target.argsPrefix, ...input.args],
504
- });
650
+ return async (input) => {
651
+ if (isSwarmExecutionOperator(input.operator)) {
652
+ return await invokeSwarmSubprocessWithEarlyAck({
653
+ command: target.command,
654
+ args: [...target.argsPrefix, ...input.args],
655
+ operator: input.operator,
656
+ cwd: process.cwd(),
657
+ });
658
+ }
659
+ return await invokeSubprocess({
660
+ command: target.command,
661
+ args: [...target.argsPrefix, ...input.args],
662
+ });
663
+ };
505
664
  }
506
665
  async function invokeSubprocess(options) {
507
666
  return await new Promise((resolve) => {
@@ -547,6 +706,142 @@ async function invokeSubprocess(options) {
547
706
  });
548
707
  });
549
708
  }
709
+ async function invokeSwarmSubprocessWithEarlyAck(options) {
710
+ const ackDir = await mkdtemp(join(tmpdir(), "voratiq-mcp-ack-"));
711
+ const ackPath = join(ackDir, "ack.json");
712
+ return await new Promise((resolve) => {
713
+ let settled = false;
714
+ let shouldBufferOutput = true;
715
+ const child = spawn(options.command, options.args, {
716
+ cwd: options.cwd,
717
+ env: {
718
+ ...process.env,
719
+ [VORATIQ_MCP_ACK_PATH_ENV]: ackPath,
720
+ [VORATIQ_MCP_ACK_OPERATOR_ENV]: options.operator,
721
+ },
722
+ stdio: ["ignore", "pipe", "pipe"],
723
+ });
724
+ const stdoutChunks = [];
725
+ const stderrChunks = [];
726
+ const settle = (result) => {
727
+ if (settled) {
728
+ return;
729
+ }
730
+ settled = true;
731
+ void rm(ackDir, { recursive: true, force: true }).catch(() => { });
732
+ resolve(result);
733
+ };
734
+ child.stdout?.setEncoding("utf8");
735
+ child.stderr?.setEncoding("utf8");
736
+ child.stdout?.on("data", (chunk) => {
737
+ if (shouldBufferOutput) {
738
+ stdoutChunks.push(chunk);
739
+ }
740
+ });
741
+ child.stderr?.on("data", (chunk) => {
742
+ if (shouldBufferOutput) {
743
+ stderrChunks.push(chunk);
744
+ }
745
+ });
746
+ child.once("error", (error) => {
747
+ settle({
748
+ kind: "spawn_failed",
749
+ error,
750
+ });
751
+ });
752
+ child.once("close", (code) => {
753
+ settle({
754
+ kind: "success",
755
+ exitCode: code ?? 0,
756
+ stdout: stdoutChunks.join(""),
757
+ stderr: stderrChunks.join(""),
758
+ });
759
+ });
760
+ void waitForSwarmSessionObservation({
761
+ ackPath,
762
+ timeoutMs: SWARM_EARLY_ACK_TIMEOUT_MS,
763
+ pollIntervalMs: SWARM_EARLY_ACK_POLL_INTERVAL_MS,
764
+ })
765
+ .then((observation) => {
766
+ if (!observation) {
767
+ return;
768
+ }
769
+ shouldBufferOutput = false;
770
+ settle({
771
+ kind: "success",
772
+ exitCode: 0,
773
+ stdout: JSON.stringify(buildSwarmSessionAcknowledgementEnvelope({
774
+ operator: options.operator,
775
+ sessionId: observation.sessionId,
776
+ status: observation.status,
777
+ })),
778
+ stderr: "",
779
+ });
780
+ })
781
+ .catch(() => { });
782
+ });
783
+ }
784
+ function isSwarmExecutionOperator(operator) {
785
+ return (operator === "spec" ||
786
+ operator === "run" ||
787
+ operator === "reduce" ||
788
+ operator === "verify" ||
789
+ operator === "message");
790
+ }
791
+ async function waitForSwarmSessionObservation(options) {
792
+ const deadline = Date.now() + options.timeoutMs;
793
+ while (Date.now() < deadline) {
794
+ const observation = await readSwarmSessionRecord({
795
+ ackPath: options.ackPath,
796
+ });
797
+ if (observation) {
798
+ return observation;
799
+ }
800
+ await sleep(options.pollIntervalMs);
801
+ }
802
+ return undefined;
803
+ }
804
+ async function readSwarmSessionRecord(options) {
805
+ try {
806
+ const raw = await readFile(options.ackPath, "utf8");
807
+ const parsed = JSON.parse(raw);
808
+ if (!isRecord(parsed)) {
809
+ return undefined;
810
+ }
811
+ const sessionId = parsed.sessionId;
812
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
813
+ return undefined;
814
+ }
815
+ const status = parsed.status;
816
+ if (status !== "queued" &&
817
+ status !== "running" &&
818
+ status !== "succeeded" &&
819
+ status !== "failed") {
820
+ return undefined;
821
+ }
822
+ return {
823
+ sessionId,
824
+ status,
825
+ };
826
+ }
827
+ catch (error) {
828
+ if (isMissingPathError(error) || error instanceof SyntaxError) {
829
+ return undefined;
830
+ }
831
+ throw error;
832
+ }
833
+ }
834
+ function isMissingPathError(error) {
835
+ return (error !== null &&
836
+ typeof error === "object" &&
837
+ "code" in error &&
838
+ error.code === "ENOENT");
839
+ }
840
+ function sleep(ms) {
841
+ return new Promise((resolve) => {
842
+ setTimeout(resolve, ms);
843
+ });
844
+ }
550
845
  function toToolInputJsonSchema(schema) {
551
846
  const jsonSchema = z.toJSONSchema(schema, {
552
847
  io: "input",
@@ -573,10 +868,8 @@ function createPruneMcpInputSchema() {
573
868
  function createListMcpInputSchema() {
574
869
  return toToolInputJsonSchema(z
575
870
  .object({
576
- operator: z.enum(["spec", "run", "reduce", "verify", "message"]),
577
- mode: z
578
- .enum(["table", "detail"])
579
- .describe("Use `detail` only when inspecting a specific session."),
871
+ operator: externalInspectionOperatorSchema,
872
+ mode: listJsonModeSchema.describe("Use `detail` only when inspecting a specific session."),
580
873
  sessionId: z
581
874
  .string()
582
875
  .min(1)
@@ -8,6 +8,5 @@ export interface AutoVerificationSelectionActionRequired {
8
8
  }
9
9
  export type AutoVerificationSelectionDisposition = AutoVerificationSelectionProceed | AutoVerificationSelectionActionRequired;
10
10
  export declare function classifyAutoVerificationSelection(options: {
11
- targetKind: "spec" | "run";
12
11
  selection?: SelectionDecision;
13
12
  }): AutoVerificationSelectionDisposition;
@@ -1,22 +1,11 @@
1
+ const UNRESOLVED_VERIFICATION_MESSAGE = "Verification did not produce a resolvable candidate; manual review required.";
1
2
  export function classifyAutoVerificationSelection(options) {
2
- const { targetKind, selection } = options;
3
+ const { selection } = options;
3
4
  if (selection?.state === "resolvable") {
4
5
  return { kind: "proceed" };
5
6
  }
6
7
  return {
7
8
  kind: "action_required",
8
- detail: describeActionRequiredSelection({ targetKind, selection }),
9
+ detail: UNRESOLVED_VERIFICATION_MESSAGE,
9
10
  };
10
11
  }
11
- function describeActionRequiredSelection(options) {
12
- const { targetKind, selection } = options;
13
- if (selection?.state === "unresolved" &&
14
- selection.unresolvedReasons.some((reason) => reason.code === "verifier_disagreement")) {
15
- return targetKind === "spec"
16
- ? "Verifiers disagreed on the preferred draft; manual selection required."
17
- : "Verifiers disagreed on the preferred candidate; manual selection required.";
18
- }
19
- return targetKind === "spec"
20
- ? "Verification did not select a draft; manual selection required."
21
- : "Verification did not produce a resolvable candidate; manual selection required.";
22
- }