voratiq 0.1.0-beta.21 → 0.1.0-beta.22

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 (149) hide show
  1. package/README.md +18 -22
  2. package/dist/agents/launch/chat.d.ts +3 -1
  3. package/dist/agents/launch/chat.js +2 -0
  4. package/dist/bin.js +28 -7
  5. package/dist/cli/auto.js +1 -0
  6. package/dist/cli/contract.d.ts +26 -17
  7. package/dist/cli/contract.js +3 -1
  8. package/dist/cli/doctor.d.ts +12 -0
  9. package/dist/cli/doctor.js +115 -0
  10. package/dist/cli/list.js +4 -1
  11. package/dist/cli/operator-envelope.d.ts +19 -6
  12. package/dist/cli/operator-envelope.js +61 -1
  13. package/dist/cli/run.js +2 -0
  14. package/dist/cli/verify.d.ts +1 -1
  15. package/dist/cli/verify.js +48 -9
  16. package/dist/commands/auto/command.d.ts +1 -0
  17. package/dist/commands/auto/command.js +22 -12
  18. package/dist/commands/auto/errors.js +1 -1
  19. package/dist/commands/doctor/agents.d.ts +5 -0
  20. package/dist/commands/{init → doctor}/agents.js +37 -19
  21. package/dist/commands/doctor/command.d.ts +22 -0
  22. package/dist/commands/doctor/command.js +99 -0
  23. package/dist/commands/doctor/environment.d.ts +2 -0
  24. package/dist/commands/{init → doctor}/environment.js +38 -6
  25. package/dist/commands/{init/types.d.ts → doctor/fix-types.d.ts} +30 -9
  26. package/dist/commands/doctor/fix.d.ts +2 -0
  27. package/dist/commands/{init/command.js → doctor/fix.js} +106 -10
  28. package/dist/commands/doctor/reconcile.d.ts +2 -0
  29. package/dist/commands/doctor/reconcile.js +101 -0
  30. package/dist/commands/interactive/lifecycle.d.ts +2 -0
  31. package/dist/commands/interactive/lifecycle.js +8 -0
  32. package/dist/commands/list/command.d.ts +1 -0
  33. package/dist/commands/list/command.js +211 -352
  34. package/dist/commands/list/normalization.d.ts +56 -0
  35. package/dist/commands/list/normalization.js +317 -0
  36. package/dist/commands/message/command.d.ts +2 -1
  37. package/dist/commands/message/command.js +35 -14
  38. package/dist/commands/message/errors.d.ts +12 -3
  39. package/dist/commands/message/errors.js +19 -3
  40. package/dist/commands/reduce/command.js +16 -17
  41. package/dist/commands/reduce/errors.d.ts +2 -2
  42. package/dist/commands/reduce/errors.js +3 -3
  43. package/dist/commands/reduce/targets.js +11 -2
  44. package/dist/commands/root-launcher/command.js +12 -6
  45. package/dist/commands/run/command.d.ts +1 -0
  46. package/dist/commands/run/command.js +4 -1
  47. package/dist/commands/run/record-init.d.ts +2 -0
  48. package/dist/commands/run/record-init.js +2 -1
  49. package/dist/commands/run/spec-provenance.d.ts +37 -0
  50. package/dist/commands/run/spec-provenance.js +384 -0
  51. package/dist/commands/run/validation.d.ts +4 -0
  52. package/dist/commands/run/validation.js +25 -62
  53. package/dist/commands/spec/command.js +19 -6
  54. package/dist/commands/spec/errors.d.ts +5 -0
  55. package/dist/commands/spec/errors.js +9 -0
  56. package/dist/commands/verify/agents.d.ts +4 -2
  57. package/dist/commands/verify/agents.js +4 -11
  58. package/dist/commands/verify/command.js +15 -5
  59. package/dist/commands/verify/errors.d.ts +12 -0
  60. package/dist/commands/verify/errors.js +22 -0
  61. package/dist/commands/verify/targets.js +108 -12
  62. package/dist/competition/shared/preflight.d.ts +1 -1
  63. package/dist/competition/shared/preflight.js +15 -2
  64. package/dist/contracts/list.d.ts +129 -149
  65. package/dist/contracts/list.js +47 -99
  66. package/dist/domain/interactive/persistence/adapter.d.ts +23 -0
  67. package/dist/domain/interactive/persistence/adapter.js +42 -0
  68. package/dist/domain/message/model/types.d.ts +32 -0
  69. package/dist/domain/message/model/types.js +25 -0
  70. package/dist/domain/reduce/competition/adapter.js +21 -7
  71. package/dist/domain/reduce/competition/finalize.d.ts +7 -0
  72. package/dist/domain/reduce/competition/finalize.js +19 -0
  73. package/dist/domain/reduce/model/types.d.ts +3 -3
  74. package/dist/domain/run/competition/agents/artifacts.js +4 -2
  75. package/dist/domain/run/competition/errors.d.ts +1 -1
  76. package/dist/domain/run/competition/errors.js +4 -7
  77. package/dist/domain/run/model/types.d.ts +384 -0
  78. package/dist/domain/run/model/types.js +87 -0
  79. package/dist/domain/spec/competition/adapter.d.ts +1 -0
  80. package/dist/domain/spec/competition/adapter.js +6 -1
  81. package/dist/domain/spec/model/types.d.ts +3 -0
  82. package/dist/domain/spec/model/types.js +5 -0
  83. package/dist/domain/verify/competition/finalize.d.ts +9 -0
  84. package/dist/domain/verify/competition/finalize.js +22 -3
  85. package/dist/domain/verify/model/types.d.ts +2 -2
  86. package/dist/interactive/providers/mcp.d.ts +1 -0
  87. package/dist/interactive/providers/mcp.js +45 -7
  88. package/dist/interactive/substrate.js +20 -3
  89. package/dist/mcp/server.js +26 -9
  90. package/dist/policy/verification.js +18 -1
  91. package/dist/preflight/agents.d.ts +24 -0
  92. package/dist/preflight/agents.js +71 -0
  93. package/dist/preflight/environment.d.ts +6 -0
  94. package/dist/preflight/environment.js +17 -0
  95. package/dist/preflight/formatting.d.ts +5 -0
  96. package/dist/preflight/formatting.js +20 -0
  97. package/dist/preflight/index.d.ts +2 -0
  98. package/dist/preflight/index.js +5 -9
  99. package/dist/preflight/operator.d.ts +32 -0
  100. package/dist/preflight/operator.js +40 -0
  101. package/dist/preflight/settings.d.ts +2 -0
  102. package/dist/preflight/settings.js +17 -0
  103. package/dist/render/transcripts/interactive.d.ts +16 -0
  104. package/dist/render/transcripts/interactive.js +42 -0
  105. package/dist/render/transcripts/list.d.ts +41 -0
  106. package/dist/render/transcripts/list.js +152 -3
  107. package/dist/render/transcripts/message.d.ts +2 -1
  108. package/dist/render/transcripts/message.js +19 -20
  109. package/dist/render/transcripts/reduce.d.ts +1 -0
  110. package/dist/render/transcripts/reduce.js +21 -21
  111. package/dist/render/transcripts/root-launcher.js +2 -12
  112. package/dist/render/transcripts/run.d.ts +3 -0
  113. package/dist/render/transcripts/run.js +30 -4
  114. package/dist/render/transcripts/spec.js +5 -8
  115. package/dist/render/transcripts/verify.d.ts +5 -3
  116. package/dist/render/transcripts/verify.js +44 -31
  117. package/dist/render/utils/duration.d.ts +5 -0
  118. package/dist/render/utils/duration.js +6 -0
  119. package/dist/render/utils/runs.d.ts +1 -0
  120. package/dist/render/utils/runs.js +1 -0
  121. package/dist/render/utils/transcript-shell.d.ts +2 -1
  122. package/dist/render/utils/transcript-shell.js +19 -6
  123. package/dist/utils/errors.d.ts +2 -1
  124. package/dist/utils/errors.js +3 -1
  125. package/dist/utils/git.d.ts +1 -1
  126. package/dist/utils/git.js +25 -2
  127. package/dist/utils/list-target.d.ts +4 -0
  128. package/dist/utils/list-target.js +35 -0
  129. package/dist/utils/terminal.d.ts +1 -0
  130. package/dist/utils/terminal.js +11 -0
  131. package/dist/workspace/chat/artifacts.d.ts +7 -0
  132. package/dist/workspace/chat/artifacts.js +94 -3
  133. package/dist/workspace/errors.js +2 -2
  134. package/dist/workspace/managed-state.d.ts +32 -0
  135. package/dist/workspace/managed-state.js +103 -0
  136. package/dist/workspace/setup.js +66 -2
  137. package/dist/workspace/shim.d.ts +1 -0
  138. package/dist/workspace/shim.js +3 -3
  139. package/dist/workspace/structure.d.ts +1 -0
  140. package/dist/workspace/structure.js +1 -0
  141. package/package.json +2 -2
  142. package/dist/cli/init.d.ts +0 -15
  143. package/dist/cli/init.js +0 -70
  144. package/dist/commands/init/agents.d.ts +0 -4
  145. package/dist/commands/init/command.d.ts +0 -2
  146. package/dist/commands/init/environment.d.ts +0 -2
  147. package/dist/render/transcripts/init.d.ts +0 -7
  148. package/dist/render/transcripts/init.js +0 -83
  149. /package/dist/commands/{init/types.js → doctor/fix-types.js} +0 -0
@@ -5,8 +5,95 @@ import { repoRelativeRecordPathSchema } from "../../../persistence/record-path-s
5
5
  import { agentStatusSchema, applyStatusSchema as applyStatusValueSchema, IN_PROGRESS_AGENT_STATUSES, runStatusSchema, TERMINAL_AGENT_STATUSES, TERMINAL_RUN_STATUSES, } from "../../../status/index.js";
6
6
  import { validateOperationLifecycleTimestamps, validateRecordLifecycleTimestamps, } from "../../shared/lifecycle.js";
7
7
  export { agentStatusSchema, IN_PROGRESS_AGENT_STATUSES, TERMINAL_AGENT_STATUSES, };
8
+ const RUN_SPEC_TARGET_KIND_VALUES = ["file", "spec"];
9
+ const RUN_SPEC_PROVENANCE_LINEAGE_VALUES = [
10
+ "exact",
11
+ "derived",
12
+ "derived_modified",
13
+ "invalid",
14
+ ];
15
+ const RUN_SPEC_PROVENANCE_ISSUE_VALUES = [
16
+ "malformed_frontmatter",
17
+ "stale_source",
18
+ ];
19
+ export const runSpecTargetKindSchema = z.enum(RUN_SPEC_TARGET_KIND_VALUES);
20
+ export const runSpecProvenanceLineageSchema = z.enum(RUN_SPEC_PROVENANCE_LINEAGE_VALUES);
21
+ export const runSpecProvenanceIssueSchema = z.enum(RUN_SPEC_PROVENANCE_ISSUE_VALUES);
22
+ export const runSpecContentHashSchema = z
23
+ .string()
24
+ .regex(/^sha256:[a-f0-9]{64}$/u);
25
+ export const runSpecSourceDescriptorSchema = z
26
+ .object({
27
+ kind: z.literal("spec"),
28
+ sessionId: z.string().min(1),
29
+ agentId: agentIdSchema,
30
+ outputPath: repoRelativeRecordPathSchema,
31
+ contentHash: runSpecContentHashSchema,
32
+ })
33
+ .strict();
34
+ export const runSpecSourceHintSchema = z
35
+ .object({
36
+ kind: z.literal("spec").optional(),
37
+ sessionId: z.string().min(1).optional(),
38
+ agentId: agentIdSchema.optional(),
39
+ outputPath: repoRelativeRecordPathSchema.optional(),
40
+ contentHash: runSpecContentHashSchema.optional(),
41
+ })
42
+ .strict();
43
+ export const exactRunSpecProvenanceSchema = z
44
+ .object({
45
+ lineage: z.literal("exact"),
46
+ source: runSpecSourceDescriptorSchema.optional(),
47
+ })
48
+ .strict();
49
+ export const derivedRunSpecProvenanceSchema = z
50
+ .object({
51
+ lineage: z.literal("derived"),
52
+ source: runSpecSourceDescriptorSchema,
53
+ currentContentHash: runSpecContentHashSchema,
54
+ })
55
+ .strict();
56
+ export const derivedModifiedRunSpecProvenanceSchema = z
57
+ .object({
58
+ lineage: z.literal("derived_modified"),
59
+ source: runSpecSourceDescriptorSchema,
60
+ currentContentHash: runSpecContentHashSchema,
61
+ })
62
+ .strict();
63
+ export const invalidRunSpecProvenanceSchema = z
64
+ .object({
65
+ lineage: z.literal("invalid"),
66
+ issueCode: runSpecProvenanceIssueSchema,
67
+ source: runSpecSourceHintSchema.optional(),
68
+ currentContentHash: runSpecContentHashSchema.optional(),
69
+ })
70
+ .strict();
71
+ export const runSpecProvenanceSchema = z.union([
72
+ exactRunSpecProvenanceSchema,
73
+ derivedRunSpecProvenanceSchema,
74
+ derivedModifiedRunSpecProvenanceSchema,
75
+ invalidRunSpecProvenanceSchema,
76
+ ]);
77
+ export const fileRunSpecTargetSchema = z
78
+ .object({
79
+ kind: z.literal("file"),
80
+ provenance: invalidRunSpecProvenanceSchema.optional(),
81
+ })
82
+ .strict();
83
+ export const sessionRunSpecTargetSchema = z
84
+ .object({
85
+ kind: z.literal("spec"),
86
+ sessionId: z.string().min(1),
87
+ provenance: runSpecProvenanceSchema.optional(),
88
+ })
89
+ .strict();
90
+ export const runSpecTargetSchema = z.union([
91
+ fileRunSpecTargetSchema,
92
+ sessionRunSpecTargetSchema,
93
+ ]);
8
94
  export const runSpecDescriptorSchema = z.object({
9
95
  path: repoRelativeRecordPathSchema,
96
+ target: runSpecTargetSchema.optional(),
10
97
  });
11
98
  const CHAT_ARTIFACT_FORMATS = [
12
99
  "json",
@@ -15,6 +15,7 @@ export interface SpecCompetitionExecution {
15
15
  readonly agentId: string;
16
16
  readonly outputPath?: string;
17
17
  readonly dataPath?: string;
18
+ readonly contentHash?: `sha256:${string}`;
18
19
  readonly status: "succeeded" | "failed";
19
20
  readonly tokenUsage?: ExtractedTokenUsage;
20
21
  readonly tokenUsageResult: TokenUsageResult;
@@ -1,3 +1,4 @@
1
+ import { createHash } from "node:crypto";
1
2
  import { readFile } from "node:fs/promises";
2
3
  import { join } from "node:path";
3
4
  import { detectAgentProcessFailureDetail } from "../../../agents/runtime/failures.js";
@@ -138,7 +139,7 @@ export function createSpecCompetitionAdapter(input) {
138
139
  }
139
140
  const stagedMarkdownPath = join(workspacePaths.workspacePath, SPEC_MARKDOWN_FILENAME);
140
141
  const stagedDataPath = join(workspacePaths.workspacePath, SPEC_DATA_FILENAME);
141
- await readFile(stagedMarkdownPath, "utf8");
142
+ const markdownContent = await readFile(stagedMarkdownPath, "utf8");
142
143
  const specData = parseSpecData(await readFile(stagedDataPath, "utf8"));
143
144
  const artifactBasename = slugify(specData.title, "spec");
144
145
  const artifactMarkdownFilename = `${artifactBasename}.md`;
@@ -161,6 +162,7 @@ export function createSpecCompetitionAdapter(input) {
161
162
  agentId: candidate.id,
162
163
  outputPath: normalizePathForDisplay(relativeToRoot(root, markdownPromoteResult.artifactPath)),
163
164
  dataPath: normalizePathForDisplay(relativeToRoot(root, dataPromoteResult.artifactPath)),
165
+ contentHash: hashSpecContent(markdownContent),
164
166
  status: "succeeded",
165
167
  tokenUsage,
166
168
  tokenUsageResult,
@@ -194,3 +196,6 @@ function registerScratchWorkspaceTeardown(teardown, workspacePaths, agentId) {
194
196
  function compareSpecExecutionsByAgentId(left, right) {
195
197
  return left.agentId.localeCompare(right.agentId);
196
198
  }
199
+ function hashSpecContent(content) {
200
+ return `sha256:${createHash("sha256").update(content, "utf8").digest("hex")}`;
201
+ }
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import { type SpecAgentStatus, specAgentStatusSchema, type SpecRecordStatus, specRecordStatusSchema, TERMINAL_SPEC_AGENT_STATUSES, TERMINAL_SPEC_STATUSES } from "../../../status/index.js";
3
3
  export type { SpecAgentStatus, SpecRecordStatus };
4
4
  export { specAgentStatusSchema, specRecordStatusSchema, TERMINAL_SPEC_AGENT_STATUSES, TERMINAL_SPEC_STATUSES, };
5
+ export declare const specContentHashSchema: z.ZodString;
5
6
  export declare const specAgentEntrySchema: z.ZodObject<{
6
7
  agentId: z.ZodString;
7
8
  status: z.ZodEnum<{
@@ -14,6 +15,7 @@ export declare const specAgentEntrySchema: z.ZodObject<{
14
15
  completedAt: z.ZodOptional<z.ZodString>;
15
16
  outputPath: z.ZodOptional<z.ZodString>;
16
17
  dataPath: z.ZodOptional<z.ZodString>;
18
+ contentHash: z.ZodOptional<z.ZodString>;
17
19
  tokenUsage: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
18
20
  input_tokens: z.ZodOptional<z.ZodNumber>;
19
21
  output_tokens: z.ZodOptional<z.ZodNumber>;
@@ -66,6 +68,7 @@ export declare const specRecordSchema: z.ZodObject<{
66
68
  completedAt: z.ZodOptional<z.ZodString>;
67
69
  outputPath: z.ZodOptional<z.ZodString>;
68
70
  dataPath: z.ZodOptional<z.ZodString>;
71
+ contentHash: z.ZodOptional<z.ZodString>;
69
72
  tokenUsage: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
70
73
  input_tokens: z.ZodOptional<z.ZodNumber>;
71
74
  output_tokens: z.ZodOptional<z.ZodNumber>;
@@ -9,6 +9,10 @@ export { specAgentStatusSchema, specRecordStatusSchema, TERMINAL_SPEC_AGENT_STAT
9
9
  const IN_PROGRESS_SPEC_STATUSES = [
10
10
  "running",
11
11
  ];
12
+ const SPEC_CONTENT_HASH_PATTERN = /^sha256:[a-f0-9]{64}$/u;
13
+ export const specContentHashSchema = z
14
+ .string()
15
+ .regex(SPEC_CONTENT_HASH_PATTERN);
12
16
  export const specAgentEntrySchema = z
13
17
  .object({
14
18
  agentId: agentIdSchema,
@@ -17,6 +21,7 @@ export const specAgentEntrySchema = z
17
21
  completedAt: z.string().optional(),
18
22
  outputPath: repoRelativeRecordPathSchema.optional(),
19
23
  dataPath: repoRelativeRecordPathSchema.optional(),
24
+ contentHash: specContentHashSchema.optional(),
20
25
  tokenUsage: extractedTokenUsageSchema.optional(),
21
26
  error: z.string().nullable().optional(),
22
27
  })
@@ -1,5 +1,14 @@
1
1
  import type { VerificationMethodResultRef, VerificationStatus } from "../model/types.js";
2
2
  import type { ResolvedVerificationTarget } from "./target.js";
3
+ /**
4
+ * Derive the session-level verification status from per-method outcomes.
5
+ *
6
+ * Session status is "succeeded" when at least one terminal method succeeds.
7
+ * Session status is "aborted" only when all terminal methods are aborted.
8
+ * Otherwise, the session is treated as "failed". When no terminal method
9
+ * snapshots exist yet, preserve the historical default of reporting
10
+ * "succeeded" rather than manufacturing a failure.
11
+ */
3
12
  export declare function deriveVerificationStatusFromMethods(methods: readonly VerificationMethodResultRef[]): VerificationStatus;
4
13
  export declare function maybePersistSelectedSpecPath(options: {
5
14
  root: string;
@@ -1,12 +1,31 @@
1
1
  import { loadVerificationSelectionPolicyOutput } from "../../../policy/index.js";
2
2
  import { rewriteVerificationRecord } from "../persistence/adapter.js";
3
+ /**
4
+ * Derive the session-level verification status from per-method outcomes.
5
+ *
6
+ * Session status is "succeeded" when at least one terminal method succeeds.
7
+ * Session status is "aborted" only when all terminal methods are aborted.
8
+ * Otherwise, the session is treated as "failed". When no terminal method
9
+ * snapshots exist yet, preserve the historical default of reporting
10
+ * "succeeded" rather than manufacturing a failure.
11
+ */
3
12
  export function deriveVerificationStatusFromMethods(methods) {
4
- if (methods.some((method) => method.status === "failed")) {
5
- return "failed";
13
+ const terminalMethods = methods.filter((method) => method.status === "succeeded" ||
14
+ method.status === "failed" ||
15
+ method.status === "aborted");
16
+ const hasSucceeded = terminalMethods.some((method) => method.status === "succeeded");
17
+ if (hasSucceeded) {
18
+ return "succeeded";
6
19
  }
7
- if (methods.some((method) => method.status === "aborted")) {
20
+ const hasTerminalMethods = terminalMethods.length > 0;
21
+ const allTerminalAborted = hasTerminalMethods &&
22
+ terminalMethods.every((method) => method.status === "aborted");
23
+ if (allTerminalAborted) {
8
24
  return "aborted";
9
25
  }
26
+ if (terminalMethods.some((method) => method.status === "failed")) {
27
+ return "failed";
28
+ }
10
29
  return "succeeded";
11
30
  }
12
31
  export async function maybePersistSelectedSpecPath(options) {
@@ -11,8 +11,8 @@ export type VerificationMethodKind = (typeof VERIFICATION_METHOD_KIND_VALUES)[nu
11
11
  export type VerificationScopeKind = (typeof VERIFICATION_SCOPE_KIND_VALUES)[number];
12
12
  export declare const verificationTargetKindSchema: z.ZodEnum<{
13
13
  message: "message";
14
- reduce: "reduce";
15
14
  spec: "spec";
15
+ reduce: "reduce";
16
16
  run: "run";
17
17
  }>;
18
18
  export declare const verificationMethodKindSchema: z.ZodEnum<{
@@ -399,8 +399,8 @@ export declare const verificationIndexEntrySchema: z.ZodObject<{
399
399
  }>;
400
400
  targetKind: z.ZodEnum<{
401
401
  message: "message";
402
- reduce: "reduce";
403
402
  spec: "spec";
403
+ reduce: "reduce";
404
404
  run: "run";
405
405
  }>;
406
406
  targetSessionId: z.ZodString;
@@ -6,6 +6,7 @@ export interface FirstPartyMcpStatusAndArgs {
6
6
  }
7
7
  export declare function resolveFirstPartyMcpStatus(options: {
8
8
  providerId: FirstPartyProviderId;
9
+ providerBinary?: string;
9
10
  root: string;
10
11
  toolDeclarations: readonly NativeToolDeclaration[];
11
12
  promptForMcpInstall?: PromptForMcpInstall;
@@ -1,4 +1,5 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { basename } from "node:path";
2
3
  import { setTimeout as delay } from "node:timers/promises";
3
4
  import { loadRepoSettings } from "../../configs/settings/loader.js";
4
5
  import { BUNDLED_VORATIQ_TOOL_TARGET_NAME, } from "./shared.js";
@@ -44,9 +45,11 @@ export async function resolveFirstPartyMcpStatus(options) {
44
45
  }
45
46
  const runCommand = options.mcpCommandRunner ?? runProviderMcpCommand;
46
47
  const adapter = firstPartyMcpAdapters[options.providerId];
48
+ const providerBinary = resolveProviderBinary(options.providerBinary, adapter.providerCommand);
47
49
  const initialInspection = summarizeFirstPartyMcpInspection({
48
50
  toolDeclarations: options.toolDeclarations,
49
51
  inspections: await adapter.inspectTools({
52
+ providerBinary,
50
53
  root: options.root,
51
54
  toolDeclarations: options.toolDeclarations,
52
55
  runCommand,
@@ -84,12 +87,14 @@ export async function resolveFirstPartyMcpStatus(options) {
84
87
  }
85
88
  await installVoratiqMcpForProvider({
86
89
  adapter,
90
+ providerBinary,
87
91
  root: options.root,
88
92
  toolDeclarations: initialInspection.missingToolDeclarations,
89
93
  runCommand,
90
94
  });
91
95
  const verifiedInspection = await verifyFirstPartyMcpStatus({
92
96
  adapter,
97
+ providerBinary,
93
98
  root: options.root,
94
99
  toolDeclarations: options.toolDeclarations,
95
100
  runCommand,
@@ -141,6 +146,7 @@ async function verifyFirstPartyMcpStatus(options) {
141
146
  lastSummary = summarizeFirstPartyMcpInspection({
142
147
  toolDeclarations: options.toolDeclarations,
143
148
  inspections: await options.adapter.inspectTools({
149
+ providerBinary: options.providerBinary,
144
150
  root: options.root,
145
151
  toolDeclarations: options.toolDeclarations,
146
152
  runCommand: options.runCommand,
@@ -176,7 +182,7 @@ async function inspectGeminiMcpTools(options) {
176
182
  return inspections;
177
183
  }
178
184
  const result = await options.runCommand({
179
- command: "gemini",
185
+ command: options.providerBinary,
180
186
  args: ["mcp", "list"],
181
187
  cwd: options.root,
182
188
  });
@@ -203,6 +209,7 @@ async function inspectCliMcpToolsViaGet(options) {
203
209
  const inspections = new Map();
204
210
  for (const tool of options.toolDeclarations) {
205
211
  inspections.set(tool.name, await inspectCliMcpTool({
212
+ providerBinary: options.providerBinary,
206
213
  providerCommand: options.providerCommand,
207
214
  root: options.root,
208
215
  declaration: tool,
@@ -213,6 +220,7 @@ async function inspectCliMcpToolsViaGet(options) {
213
220
  }
214
221
  async function inspectCodexMcpTools(options) {
215
222
  return await inspectCliMcpToolsViaGet({
223
+ providerBinary: options.providerBinary,
216
224
  providerCommand: "codex",
217
225
  root: options.root,
218
226
  toolDeclarations: options.toolDeclarations,
@@ -221,6 +229,7 @@ async function inspectCodexMcpTools(options) {
221
229
  }
222
230
  async function inspectClaudeMcpTools(options) {
223
231
  return await inspectCliMcpToolsViaGet({
232
+ providerBinary: options.providerBinary,
224
233
  providerCommand: "claude",
225
234
  root: options.root,
226
235
  toolDeclarations: options.toolDeclarations,
@@ -230,7 +239,7 @@ async function inspectClaudeMcpTools(options) {
230
239
  async function inspectCliMcpTool(options) {
231
240
  if (options.providerCommand === "codex") {
232
241
  const result = await options.runCommand({
233
- command: "codex",
242
+ command: options.providerBinary,
234
243
  args: ["mcp", "get", "--json", options.declaration.name],
235
244
  cwd: options.root,
236
245
  });
@@ -260,7 +269,7 @@ async function inspectCliMcpTool(options) {
260
269
  };
261
270
  }
262
271
  const result = await options.runCommand({
263
- command: "claude",
272
+ command: options.providerBinary,
264
273
  args: ["mcp", "get", options.declaration.name],
265
274
  cwd: options.root,
266
275
  });
@@ -345,11 +354,11 @@ function normalizeStringArray(value) {
345
354
  return [...value];
346
355
  }
347
356
  function matchesDeclarationCommandAndArgs(declaration, value) {
348
- if (value.command !== declaration.command) {
357
+ const expectedArgs = declaration.args ? [...declaration.args] : [];
358
+ if (!areStringArraysEqual(value.args, expectedArgs)) {
349
359
  return false;
350
360
  }
351
- const expectedArgs = declaration.args ? [...declaration.args] : [];
352
- return areStringArraysEqual(value.args, expectedArgs);
361
+ return areEquivalentMcpCommands(value.command, declaration.command);
353
362
  }
354
363
  function areStringArraysEqual(left, right) {
355
364
  if (left.length !== right.length) {
@@ -362,6 +371,16 @@ function areStringArraysEqual(left, right) {
362
371
  }
363
372
  return true;
364
373
  }
374
+ function areEquivalentMcpCommands(left, right) {
375
+ if (left === right) {
376
+ return true;
377
+ }
378
+ return isNodeExecutableCommand(left) && isNodeExecutableCommand(right);
379
+ }
380
+ function isNodeExecutableCommand(value) {
381
+ const normalized = basename(value).toLowerCase();
382
+ return normalized === "node" || normalized === "node.exe";
383
+ }
365
384
  function buildCommandMismatchDetail(declaration, actual) {
366
385
  return [
367
386
  `Expected \`${formatCommandAndArgs(declaration.command, declaration.args ?? [])}\`,`,
@@ -425,7 +444,7 @@ function splitCommandLine(value) {
425
444
  async function installVoratiqMcpForProvider(options) {
426
445
  for (const toolDeclaration of options.toolDeclarations) {
427
446
  const result = await options.runCommand({
428
- command: options.adapter.providerCommand,
447
+ command: options.providerBinary,
429
448
  args: options.adapter.buildAddArgs(toolDeclaration),
430
449
  cwd: options.root,
431
450
  });
@@ -535,7 +554,22 @@ async function runProviderMcpCommand(input) {
535
554
  stderr += chunk;
536
555
  });
537
556
  const exitCode = await new Promise((resolve) => {
557
+ let settled = false;
558
+ child.on("error", (error) => {
559
+ if (settled) {
560
+ return;
561
+ }
562
+ settled = true;
563
+ if (stderr.trim().length === 0) {
564
+ stderr = error.message;
565
+ }
566
+ resolve(null);
567
+ });
538
568
  child.on("close", (code) => {
569
+ if (settled) {
570
+ return;
571
+ }
572
+ settled = true;
539
573
  resolve(typeof code === "number" ? code : null);
540
574
  });
541
575
  });
@@ -545,3 +579,7 @@ async function runProviderMcpCommand(input) {
545
579
  stderr,
546
580
  };
547
581
  }
582
+ function resolveProviderBinary(candidate, fallback) {
583
+ const normalized = candidate?.trim();
584
+ return normalized && normalized.length > 0 ? normalized : fallback;
585
+ }
@@ -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,
@@ -191,6 +193,13 @@ export async function prepareNativeInteractiveSession(options) {
191
193
  providerId,
192
194
  sessionRoot: paths.sessionRoot,
193
195
  searchEnv: invocationEnv,
196
+ selectionHint: providerId === "codex"
197
+ ? {
198
+ strategy: "codex-session-meta",
199
+ cwd: cwd.path,
200
+ minStartedAt: createdAt,
201
+ }
202
+ : undefined,
194
203
  });
195
204
  }
196
205
  catch {
@@ -251,9 +260,15 @@ export async function spawnPreparedInteractiveSession(prepared, options = {}) {
251
260
  if (stdio === "inherit") {
252
261
  process.stdout.write("\n");
253
262
  }
263
+ const spawnEnv = stdio === "inherit"
264
+ ? {
265
+ ...prepared.invocation.env,
266
+ TERM: normalizeInteractiveTerm(prepared.invocation.env),
267
+ }
268
+ : prepared.invocation.env;
254
269
  const child = spawn(prepared.invocation.command, prepared.invocation.args, {
255
270
  cwd: prepared.invocation.cwd,
256
- env: prepared.invocation.env,
271
+ env: spawnEnv,
257
272
  stdio,
258
273
  });
259
274
  const completion = createProcessCompletionPromise(prepared, child);
@@ -321,9 +336,11 @@ function createProcessCompletionPromise(prepared, child) {
321
336
  return;
322
337
  }
323
338
  finalized = true;
339
+ const terminationStatus = getActiveInteractiveTerminationStatus(prepared.sessionId);
340
+ const signalCountsAsSuccess = terminationStatus === "aborted" && options.signal !== null;
324
341
  const runtimeFailureMessage = options.spawnError
325
342
  ? `Failed during provider execution: ${options.spawnError.message}`
326
- : options.signal
343
+ : options.signal && !signalCountsAsSuccess
327
344
  ? `Provider process terminated by signal ${options.signal}`
328
345
  : options.exitCode && options.exitCode !== 0
329
346
  ? `Provider process exited with code ${options.exitCode}`
@@ -1,9 +1,9 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import process from "node:process";
3
3
  import { z } from "zod";
4
- import { externalApplyExecutionInputSchema, externalListInspectionInputSchema, externalMessageExecutionInputSchema, externalPruneExecutionInputSchema, externalReduceExecutionInputSchema, externalRunExecutionInputSchema, externalSpecExecutionInputSchema, externalVerifyExecutionInputSchema, } from "../cli/contract.js";
4
+ import { externalApplyExecutionInputSchema, externalInspectionOperatorSchema, externalMessageExecutionInputSchema, externalPruneExecutionInputSchema, externalReduceExecutionInputSchema, externalRunExecutionInputSchema, externalSpecExecutionInputSchema, externalVerifyExecutionInputSchema, } from "../cli/contract.js";
5
5
  import { operatorResultEnvelopeSchema, } from "../cli/operator-envelope.js";
6
- import { listJsonOutputSchema, } from "../contracts/list.js";
6
+ import { listJsonModes, listJsonModeSchema, listJsonOutputSchema, } from "../contracts/list.js";
7
7
  import { getVoratiqVersion } from "../utils/version.js";
8
8
  import { createEntrypointVoratiqCliTarget as createEntrypointCliTarget, resolveVoratiqCliTarget, } from "../utils/voratiq-cli-target.js";
9
9
  const JSON_RPC_VERSION = "2.0";
@@ -23,6 +23,25 @@ export const VORATIQ_SUPPORTED_MCP_PROTOCOL_VERSIONS = [
23
23
  function isSupportedMcpProtocolVersion(protocolVersion) {
24
24
  return VORATIQ_SUPPORTED_MCP_PROTOCOL_VERSIONS.includes(protocolVersion);
25
25
  }
26
+ const mcpListInspectionInputSchema = z.discriminatedUnion("mode", [
27
+ z
28
+ .object({
29
+ operator: externalInspectionOperatorSchema,
30
+ mode: z.literal(listJsonModes[0]),
31
+ verbose: z.boolean().optional(),
32
+ limit: z.number().int().positive().optional(),
33
+ })
34
+ .strict(),
35
+ z
36
+ .object({
37
+ operator: externalInspectionOperatorSchema,
38
+ mode: z.literal(listJsonModes[1]),
39
+ sessionId: z.string().min(1),
40
+ verbose: z.boolean().optional(),
41
+ limit: z.number().int().positive().optional(),
42
+ })
43
+ .strict(),
44
+ ]);
26
45
  const initializeRequestParamsSchema = z
27
46
  .object({
28
47
  protocolVersion: z.string(),
@@ -86,8 +105,8 @@ const toolSpecs = [
86
105
  {
87
106
  name: "voratiq_list",
88
107
  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,
108
+ description: "List recorded Voratiq sessions for one operator (`spec`, `run`, `reduce`, `verify`, `message`, or `interactive`) in list or detail mode.",
109
+ inputSchemaSource: mcpListInspectionInputSchema,
91
110
  mcpInputSchema: createListMcpInputSchema(),
92
111
  buildArgs: (input) => buildListInspectionArgs(input),
93
112
  outputContract: "list",
@@ -107,7 +126,7 @@ const toolDefinitions = toolSpecs.map((tool) => ({
107
126
  description: tool.description,
108
127
  inputSchema: tool.mcpInputSchema ?? toToolInputJsonSchema(tool.inputSchemaSource),
109
128
  }));
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.";
129
+ 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. 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.";
111
130
  const toolSpecsByName = new Map(toolSpecs.map((tool) => [tool.name, tool]));
112
131
  export function getVoratiqMcpToolDefinitions() {
113
132
  return toolDefinitions;
@@ -573,10 +592,8 @@ function createPruneMcpInputSchema() {
573
592
  function createListMcpInputSchema() {
574
593
  return toToolInputJsonSchema(z
575
594
  .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."),
595
+ operator: externalInspectionOperatorSchema,
596
+ mode: listJsonModeSchema.describe("Use `detail` only when inspecting a specific session."),
580
597
  sessionId: z
581
598
  .string()
582
599
  .min(1)
@@ -208,7 +208,7 @@ async function readArtifactJson(options) {
208
208
  }
209
209
  function buildVerificationSelectionVerifiers(options) {
210
210
  const participatingRubrics = resolveWinnerPolicyParticipatingRubrics(options);
211
- return participatingRubrics.map((rubric) => {
211
+ const verifiers = participatingRubrics.map((rubric) => {
212
212
  if (rubric.status !== "succeeded") {
213
213
  return {
214
214
  verifierAgentId: rubric.verifierId,
@@ -223,6 +223,23 @@ function buildVerificationSelectionVerifiers(options) {
223
223
  ...(preferredCandidateId ? { preferredCandidateId } : {}),
224
224
  };
225
225
  });
226
+ const addedFailedVerifierIds = new Set(verifiers
227
+ .filter((verifier) => verifier.status === "failed")
228
+ .map((verifier) => verifier.verifierAgentId));
229
+ for (const rubric of options.policyInput.rubrics) {
230
+ if (rubric.status === "succeeded") {
231
+ continue;
232
+ }
233
+ if (addedFailedVerifierIds.has(rubric.verifierId)) {
234
+ continue;
235
+ }
236
+ verifiers.push({
237
+ verifierAgentId: rubric.verifierId,
238
+ status: "failed",
239
+ });
240
+ addedFailedVerifierIds.add(rubric.verifierId);
241
+ }
242
+ return verifiers;
226
243
  }
227
244
  function resolveVerificationWinnerPolicy(winnerPolicy) {
228
245
  return winnerPolicy ?? DEFAULT_VERIFICATION_WINNER_POLICY;
@@ -0,0 +1,24 @@
1
+ import type { PreflightIssue } from "../competition/shared/preflight.js";
2
+ import type { AgentDefinition } from "../configs/agents/types.js";
3
+ export interface CollectConfiguredAgentReadinessInput {
4
+ readonly root: string;
5
+ readonly resolvedAgentIds?: readonly string[];
6
+ readonly includeSettings?: boolean;
7
+ }
8
+ export interface ConfiguredAgentReadinessResult {
9
+ readonly agents: readonly AgentDefinition[];
10
+ readonly issues: readonly PreflightIssue[];
11
+ readonly preProviderIssueCount: number;
12
+ readonly noAgentsEnabled: boolean;
13
+ }
14
+ export interface CollectResolvedAgentReadinessInput {
15
+ readonly root: string;
16
+ readonly agents: readonly AgentDefinition[];
17
+ readonly includeSettings?: boolean;
18
+ }
19
+ export interface ResolvedAgentReadinessResult {
20
+ readonly issues: readonly PreflightIssue[];
21
+ readonly preProviderIssueCount: number;
22
+ }
23
+ export declare function collectConfiguredAgentReadiness(input: CollectConfiguredAgentReadinessInput): Promise<ConfiguredAgentReadinessResult>;
24
+ export declare function collectResolvedAgentReadiness(input: CollectResolvedAgentReadinessInput): Promise<ResolvedAgentReadinessResult>;