@wix/pathgrade 0.29.0

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 (238) hide show
  1. package/bin/pathgrade.js +2 -0
  2. package/dist/affected/anchor.d.ts +18 -0
  3. package/dist/affected/anchor.js +42 -0
  4. package/dist/affected/config.d.ts +25 -0
  5. package/dist/affected/config.js +98 -0
  6. package/dist/affected/format.d.ts +45 -0
  7. package/dist/affected/format.js +87 -0
  8. package/dist/affected/git.d.ts +33 -0
  9. package/dist/affected/git.js +68 -0
  10. package/dist/affected/glob.d.ts +17 -0
  11. package/dist/affected/glob.js +25 -0
  12. package/dist/affected/meta.d.ts +26 -0
  13. package/dist/affected/meta.js +158 -0
  14. package/dist/affected/select.d.ts +30 -0
  15. package/dist/affected/select.js +101 -0
  16. package/dist/affected/sidecar.d.ts +32 -0
  17. package/dist/affected/sidecar.js +86 -0
  18. package/dist/affected/types.d.ts +43 -0
  19. package/dist/affected/types.js +7 -0
  20. package/dist/agents/claude/ask-user-answer-store.d.ts +28 -0
  21. package/dist/agents/claude/ask-user-answer-store.js +29 -0
  22. package/dist/agents/claude/ask-user-bridge.d.ts +56 -0
  23. package/dist/agents/claude/ask-user-bridge.js +162 -0
  24. package/dist/agents/claude/sdk-message-projector.d.ts +43 -0
  25. package/dist/agents/claude/sdk-message-projector.js +208 -0
  26. package/dist/agents/claude/sdk-options.d.ts +52 -0
  27. package/dist/agents/claude/sdk-options.js +79 -0
  28. package/dist/agents/claude.d.ts +56 -0
  29. package/dist/agents/claude.js +143 -0
  30. package/dist/agents/codex-app-server/agent.d.ts +35 -0
  31. package/dist/agents/codex-app-server/agent.js +388 -0
  32. package/dist/agents/codex-app-server/fixtures/app-server-client.d.ts +19 -0
  33. package/dist/agents/codex-app-server/fixtures/app-server-client.js +104 -0
  34. package/dist/agents/codex-app-server/fixtures/run-gate.d.ts +25 -0
  35. package/dist/agents/codex-app-server/fixtures/run-gate.js +48 -0
  36. package/dist/agents/codex-app-server/protocol/ClientRequest.d.ts +27 -0
  37. package/dist/agents/codex-app-server/protocol/ClientRequest.js +7 -0
  38. package/dist/agents/codex-app-server/protocol/DynamicToolCallParams.d.ts +9 -0
  39. package/dist/agents/codex-app-server/protocol/DynamicToolCallParams.js +4 -0
  40. package/dist/agents/codex-app-server/protocol/GrantedPermissionProfile.d.ts +6 -0
  41. package/dist/agents/codex-app-server/protocol/GrantedPermissionProfile.js +7 -0
  42. package/dist/agents/codex-app-server/protocol/McpElicitationRequestParams.d.ts +23 -0
  43. package/dist/agents/codex-app-server/protocol/McpElicitationRequestParams.js +8 -0
  44. package/dist/agents/codex-app-server/protocol/Op.d.ts +11 -0
  45. package/dist/agents/codex-app-server/protocol/Op.js +5 -0
  46. package/dist/agents/codex-app-server/protocol/PermissionsRequestApprovalParams.d.ts +10 -0
  47. package/dist/agents/codex-app-server/protocol/PermissionsRequestApprovalParams.js +6 -0
  48. package/dist/agents/codex-app-server/protocol/PermissionsRequestApprovalResponse.d.ts +15 -0
  49. package/dist/agents/codex-app-server/protocol/PermissionsRequestApprovalResponse.js +4 -0
  50. package/dist/agents/codex-app-server/protocol/SandboxMode.d.ts +1 -0
  51. package/dist/agents/codex-app-server/protocol/SandboxMode.js +4 -0
  52. package/dist/agents/codex-app-server/protocol/ServerRequest.d.ts +42 -0
  53. package/dist/agents/codex-app-server/protocol/ServerRequest.js +7 -0
  54. package/dist/agents/codex-app-server/protocol/ThreadStartParams.d.ts +45 -0
  55. package/dist/agents/codex-app-server/protocol/ThreadStartParams.js +10 -0
  56. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputAnswer.d.ts +6 -0
  57. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputAnswer.js +4 -0
  58. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputOption.d.ts +7 -0
  59. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputOption.js +4 -0
  60. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputParams.d.ts +10 -0
  61. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputParams.js +4 -0
  62. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputQuestion.d.ts +12 -0
  63. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputQuestion.js +4 -0
  64. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputResponse.d.ts +9 -0
  65. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputResponse.js +4 -0
  66. package/dist/agents/codex-app-server/protocol/TurnCompletedNotification.d.ts +5 -0
  67. package/dist/agents/codex-app-server/protocol/TurnCompletedNotification.js +4 -0
  68. package/dist/agents/codex-app-server/protocol/index.d.ts +16 -0
  69. package/dist/agents/codex-app-server/protocol/index.js +11 -0
  70. package/dist/agents/codex-app-server/transport.d.ts +84 -0
  71. package/dist/agents/codex-app-server/transport.js +246 -0
  72. package/dist/agents/codex-app-server/wire-translators.d.ts +19 -0
  73. package/dist/agents/codex-app-server/wire-translators.js +52 -0
  74. package/dist/agents/codex.d.ts +7 -0
  75. package/dist/agents/codex.js +164 -0
  76. package/dist/agents/cursor.d.ts +39 -0
  77. package/dist/agents/cursor.js +233 -0
  78. package/dist/agents/registry.d.ts +17 -0
  79. package/dist/agents/registry.js +27 -0
  80. package/dist/agents/transcript-agent.d.ts +14 -0
  81. package/dist/agents/transcript-agent.js +59 -0
  82. package/dist/analytics/engine.d.ts +18 -0
  83. package/dist/analytics/engine.js +66 -0
  84. package/dist/commands/affected.d.ts +31 -0
  85. package/dist/commands/affected.js +150 -0
  86. package/dist/commands/analyze.d.ts +21 -0
  87. package/dist/commands/analyze.js +167 -0
  88. package/dist/commands/init.d.ts +3 -0
  89. package/dist/commands/init.js +242 -0
  90. package/dist/commands/preview-reactions.d.ts +10 -0
  91. package/dist/commands/preview-reactions.js +88 -0
  92. package/dist/commands/preview.d.ts +5 -0
  93. package/dist/commands/preview.js +17 -0
  94. package/dist/commands/report.d.ts +39 -0
  95. package/dist/commands/report.js +108 -0
  96. package/dist/commands/run-args.d.ts +22 -0
  97. package/dist/commands/run-args.js +69 -0
  98. package/dist/commands/run-changed.d.ts +26 -0
  99. package/dist/commands/run-changed.js +138 -0
  100. package/dist/commands/validate.d.ts +13 -0
  101. package/dist/commands/validate.js +233 -0
  102. package/dist/core/mcp-mock.d.ts +3 -0
  103. package/dist/core/mcp-mock.js +23 -0
  104. package/dist/core/mcp-mock.types.d.ts +15 -0
  105. package/dist/core/mcp-mock.types.js +1 -0
  106. package/dist/core/skills.d.ts +15 -0
  107. package/dist/core/skills.js +76 -0
  108. package/dist/evals/discovery.d.ts +7 -0
  109. package/dist/evals/discovery.js +69 -0
  110. package/dist/mcp-mock-server.d.ts +1 -0
  111. package/dist/mcp-mock-server.js +116 -0
  112. package/dist/pathgrade.d.ts +10 -0
  113. package/dist/pathgrade.js +243 -0
  114. package/dist/plugin/index.d.ts +9 -0
  115. package/dist/plugin/index.js +81 -0
  116. package/dist/plugin/lifecycle.d.ts +45 -0
  117. package/dist/plugin/lifecycle.js +146 -0
  118. package/dist/plugin/reporter.d.ts +36 -0
  119. package/dist/plugin/reporter.js +275 -0
  120. package/dist/plugin/setup.d.ts +1 -0
  121. package/dist/plugin/setup.js +3 -0
  122. package/dist/providers/copy-filter.d.ts +18 -0
  123. package/dist/providers/copy-filter.js +66 -0
  124. package/dist/providers/credentials.d.ts +36 -0
  125. package/dist/providers/credentials.js +202 -0
  126. package/dist/providers/mcp-config.d.ts +34 -0
  127. package/dist/providers/mcp-config.js +55 -0
  128. package/dist/providers/sandbox-exec.d.ts +8 -0
  129. package/dist/providers/sandbox-exec.js +82 -0
  130. package/dist/providers/sandbox.d.ts +22 -0
  131. package/dist/providers/sandbox.js +158 -0
  132. package/dist/providers/sandboxed-claude-spawn.d.ts +24 -0
  133. package/dist/providers/sandboxed-claude-spawn.js +57 -0
  134. package/dist/providers/workspace.d.ts +15 -0
  135. package/dist/providers/workspace.js +73 -0
  136. package/dist/reporters/browser.d.ts +2 -0
  137. package/dist/reporters/browser.js +85 -0
  138. package/dist/reporters/cli.d.ts +2 -0
  139. package/dist/reporters/cli.js +131 -0
  140. package/dist/reporters/diagnostics.d.ts +46 -0
  141. package/dist/reporters/diagnostics.js +147 -0
  142. package/dist/reporters/github-comment.d.ts +67 -0
  143. package/dist/reporters/github-comment.js +252 -0
  144. package/dist/reporters/loader.d.ts +8 -0
  145. package/dist/reporters/loader.js +36 -0
  146. package/dist/reporters/results-path.d.ts +2 -0
  147. package/dist/reporters/results-path.js +10 -0
  148. package/dist/reporters/verbose-emitter.d.ts +69 -0
  149. package/dist/reporters/verbose-emitter.js +103 -0
  150. package/dist/sdk/agent-crash.d.ts +19 -0
  151. package/dist/sdk/agent-crash.js +20 -0
  152. package/dist/sdk/agent-resolution.d.ts +12 -0
  153. package/dist/sdk/agent-resolution.js +21 -0
  154. package/dist/sdk/agent-result-log.d.ts +19 -0
  155. package/dist/sdk/agent-result-log.js +45 -0
  156. package/dist/sdk/agent.d.ts +4 -0
  157. package/dist/sdk/agent.js +354 -0
  158. package/dist/sdk/ask-bus/bus.d.ts +21 -0
  159. package/dist/sdk/ask-bus/bus.js +129 -0
  160. package/dist/sdk/ask-bus/handler.d.ts +31 -0
  161. package/dist/sdk/ask-bus/handler.js +244 -0
  162. package/dist/sdk/ask-bus/parsers.d.ts +9 -0
  163. package/dist/sdk/ask-bus/parsers.js +30 -0
  164. package/dist/sdk/ask-bus/projection.d.ts +26 -0
  165. package/dist/sdk/ask-bus/projection.js +45 -0
  166. package/dist/sdk/ask-bus/types.d.ts +69 -0
  167. package/dist/sdk/ask-bus/types.js +1 -0
  168. package/dist/sdk/chat.d.ts +29 -0
  169. package/dist/sdk/chat.js +93 -0
  170. package/dist/sdk/conversation-window.d.ts +14 -0
  171. package/dist/sdk/conversation-window.js +38 -0
  172. package/dist/sdk/converse.d.ts +42 -0
  173. package/dist/sdk/converse.js +329 -0
  174. package/dist/sdk/eval-runtime.d.ts +10 -0
  175. package/dist/sdk/eval-runtime.js +17 -0
  176. package/dist/sdk/evaluate.d.ts +13 -0
  177. package/dist/sdk/evaluate.js +325 -0
  178. package/dist/sdk/index.d.ts +31 -0
  179. package/dist/sdk/index.js +20 -0
  180. package/dist/sdk/judge-pipeline.d.ts +7 -0
  181. package/dist/sdk/judge-pipeline.js +178 -0
  182. package/dist/sdk/judge-prompt-builder.d.ts +7 -0
  183. package/dist/sdk/judge-prompt-builder.js +76 -0
  184. package/dist/sdk/judge-tool-runner.d.ts +19 -0
  185. package/dist/sdk/judge-tool-runner.js +51 -0
  186. package/dist/sdk/judge-tool-session.d.ts +47 -0
  187. package/dist/sdk/judge-tool-session.js +213 -0
  188. package/dist/sdk/judge-tools.d.ts +29 -0
  189. package/dist/sdk/judge-tools.js +283 -0
  190. package/dist/sdk/managed-session.d.ts +50 -0
  191. package/dist/sdk/managed-session.js +110 -0
  192. package/dist/sdk/persona.d.ts +5 -0
  193. package/dist/sdk/persona.js +33 -0
  194. package/dist/sdk/reaction-loader.d.ts +4 -0
  195. package/dist/sdk/reaction-loader.js +119 -0
  196. package/dist/sdk/reaction-preview.d.ts +6 -0
  197. package/dist/sdk/reaction-preview.js +94 -0
  198. package/dist/sdk/run-scorer.d.ts +10 -0
  199. package/dist/sdk/run-scorer.js +124 -0
  200. package/dist/sdk/runtime-policy.d.ts +21 -0
  201. package/dist/sdk/runtime-policy.js +89 -0
  202. package/dist/sdk/scorer-utils.d.ts +6 -0
  203. package/dist/sdk/scorer-utils.js +39 -0
  204. package/dist/sdk/scorers.d.ts +64 -0
  205. package/dist/sdk/scorers.js +80 -0
  206. package/dist/sdk/snapshots.d.ts +41 -0
  207. package/dist/sdk/snapshots.js +148 -0
  208. package/dist/sdk/types.d.ts +416 -0
  209. package/dist/sdk/types.js +17 -0
  210. package/dist/sdk/visible-turn.d.ts +4 -0
  211. package/dist/sdk/visible-turn.js +23 -0
  212. package/dist/tool-events.d.ts +45 -0
  213. package/dist/tool-events.js +167 -0
  214. package/dist/types.d.ts +372 -0
  215. package/dist/types.js +37 -0
  216. package/dist/utils/cli.d.ts +55 -0
  217. package/dist/utils/cli.js +131 -0
  218. package/dist/utils/env.d.ts +8 -0
  219. package/dist/utils/env.js +26 -0
  220. package/dist/utils/llm-mocks.d.ts +43 -0
  221. package/dist/utils/llm-mocks.js +108 -0
  222. package/dist/utils/llm-providers/anthropic.d.ts +2 -0
  223. package/dist/utils/llm-providers/anthropic.js +132 -0
  224. package/dist/utils/llm-providers/cli.d.ts +20 -0
  225. package/dist/utils/llm-providers/cli.js +162 -0
  226. package/dist/utils/llm-providers/openai.d.ts +2 -0
  227. package/dist/utils/llm-providers/openai.js +56 -0
  228. package/dist/utils/llm-types.d.ts +107 -0
  229. package/dist/utils/llm-types.js +1 -0
  230. package/dist/utils/llm.d.ts +36 -0
  231. package/dist/utils/llm.js +209 -0
  232. package/dist/utils/shutdown.d.ts +15 -0
  233. package/dist/utils/shutdown.js +41 -0
  234. package/dist/utils/timeout.d.ts +8 -0
  235. package/dist/utils/timeout.js +32 -0
  236. package/dist/viewer.html +1178 -0
  237. package/package.json +88 -0
  238. package/templates/eval.ts.template +28 -0
@@ -0,0 +1,64 @@
1
+ import type { CheckScorer, CodeJudgeToolName, ScorerContext, JudgeScorer, ScoreScorer, ScoreResult, ToolExpectation, ToolUsageScorer } from './types.js';
2
+ /**
3
+ * Create a check scorer — a boolean gate that passes (1.0) or fails (0.0).
4
+ */
5
+ export declare function check(name: string, fn: (ctx: ScorerContext) => boolean | Promise<boolean>, opts?: {
6
+ weight?: number;
7
+ }): CheckScorer;
8
+ /**
9
+ * Create a score scorer — returns a number (0-1) or { score, details } for partial credit.
10
+ */
11
+ export declare function score(name: string, fn: (ctx: ScorerContext) => number | ScoreResult | Promise<number | ScoreResult>, opts?: {
12
+ weight?: number;
13
+ }): ScoreScorer;
14
+ /**
15
+ * Create a judge scorer — uses an LLM to evaluate against a rubric.
16
+ * Transcript is auto-included. Tool events opt-in via includeToolEvents.
17
+ *
18
+ * @param opts.input - Additional context to include in the judge prompt alongside
19
+ * the transcript. Each key becomes a section heading; string values are rendered
20
+ * as-is, objects are JSON-stringified. Use this to pass file contents, command
21
+ * output, or other artifacts that the agent produced but may not appear in the
22
+ * transcript. The judge LLM only sees the conversation transcript by default —
23
+ * if the agent wrote a file, the judge cannot verify its contents unless you read
24
+ * the file and pass it here.
25
+ *
26
+ * @example
27
+ * // Read the file the agent created and pass it to the judge
28
+ * const content = await agent.exec('cat output.md');
29
+ * judge('file quality', {
30
+ * rubric: 'The output file should contain a valid markdown document...',
31
+ * input: { 'output.md contents': content.stdout },
32
+ * })
33
+ * // Or derive the judge input from scorer context
34
+ * judge('file quality', {
35
+ * rubric: 'The output file should contain a valid markdown document...',
36
+ * input: async (ctx) => ({ 'output.md contents': await ctx.artifacts.read('output.md') }),
37
+ * })
38
+ */
39
+ export declare function judge(name: string, opts: {
40
+ rubric: string;
41
+ weight?: number;
42
+ model?: string;
43
+ retry?: boolean | number;
44
+ includeToolEvents?: boolean;
45
+ /** Additional context for the judge. See function docs for usage pattern. */
46
+ input?: import('./types.js').JudgeInput;
47
+ /**
48
+ * Opt-in allowlist of tools the judge LLM may call during a multi-turn
49
+ * tool-use loop. When set to a non-empty array, the judge runs in a
50
+ * tool-use loop against a provider that supports callWithTools. When
51
+ * omitted, behavior is byte-for-byte unchanged.
52
+ */
53
+ tools?: CodeJudgeToolName[];
54
+ /** Cap on LLM calls per tool-use judge; default 10. */
55
+ maxRounds?: number;
56
+ /** Anthropic prompt caching. Default: true when tools is set, unchanged otherwise. */
57
+ cacheControl?: boolean;
58
+ }): JudgeScorer;
59
+ /**
60
+ * Create a tool usage scorer — matches tool events against expectations.
61
+ */
62
+ export declare function toolUsage(name: string, expectations: ToolExpectation[], opts?: {
63
+ weight?: number;
64
+ }): ToolUsageScorer;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Create a check scorer — a boolean gate that passes (1.0) or fails (0.0).
3
+ */
4
+ export function check(name, fn, opts) {
5
+ return {
6
+ type: 'check',
7
+ name,
8
+ weight: opts?.weight ?? 1,
9
+ fn,
10
+ };
11
+ }
12
+ /**
13
+ * Create a score scorer — returns a number (0-1) or { score, details } for partial credit.
14
+ */
15
+ export function score(name, fn, opts) {
16
+ return {
17
+ type: 'score',
18
+ name,
19
+ weight: opts?.weight ?? 1,
20
+ fn,
21
+ };
22
+ }
23
+ /**
24
+ * Create a judge scorer — uses an LLM to evaluate against a rubric.
25
+ * Transcript is auto-included. Tool events opt-in via includeToolEvents.
26
+ *
27
+ * @param opts.input - Additional context to include in the judge prompt alongside
28
+ * the transcript. Each key becomes a section heading; string values are rendered
29
+ * as-is, objects are JSON-stringified. Use this to pass file contents, command
30
+ * output, or other artifacts that the agent produced but may not appear in the
31
+ * transcript. The judge LLM only sees the conversation transcript by default —
32
+ * if the agent wrote a file, the judge cannot verify its contents unless you read
33
+ * the file and pass it here.
34
+ *
35
+ * @example
36
+ * // Read the file the agent created and pass it to the judge
37
+ * const content = await agent.exec('cat output.md');
38
+ * judge('file quality', {
39
+ * rubric: 'The output file should contain a valid markdown document...',
40
+ * input: { 'output.md contents': content.stdout },
41
+ * })
42
+ * // Or derive the judge input from scorer context
43
+ * judge('file quality', {
44
+ * rubric: 'The output file should contain a valid markdown document...',
45
+ * input: async (ctx) => ({ 'output.md contents': await ctx.artifacts.read('output.md') }),
46
+ * })
47
+ */
48
+ export function judge(name, opts) {
49
+ const tools = opts.tools && opts.tools.length > 0 ? [...opts.tools] : undefined;
50
+ const includeToolEvents = opts.includeToolEvents
51
+ ?? (tools?.includes('getToolEvents') ? true : undefined);
52
+ // When tools is set, default cacheControl to true (mitigates the
53
+ // 10–70× input-token inflation measured in the spike). Explicit
54
+ // false opts out; explicit true is a no-op.
55
+ const cacheControl = opts.cacheControl ?? (tools ? true : undefined);
56
+ return {
57
+ type: 'judge',
58
+ name,
59
+ weight: opts.weight ?? 1,
60
+ rubric: opts.rubric,
61
+ model: opts.model,
62
+ retry: opts.retry,
63
+ includeToolEvents,
64
+ input: opts.input,
65
+ tools,
66
+ maxRounds: opts.maxRounds,
67
+ cacheControl,
68
+ };
69
+ }
70
+ /**
71
+ * Create a tool usage scorer — matches tool events against expectations.
72
+ */
73
+ export function toolUsage(name, expectations, opts) {
74
+ return {
75
+ type: 'tool_usage',
76
+ name,
77
+ weight: opts?.weight ?? 1,
78
+ expectations,
79
+ };
80
+ }
@@ -0,0 +1,41 @@
1
+ import type { LogEntry } from '../types.js';
2
+ import type { ToolEvent } from '../tool-events.js';
3
+ import type { AgentName, ConversationResult, Message, TurnTiming } from './types.js';
4
+ export declare const RUN_SNAPSHOT_VERSION = 1;
5
+ export interface RunSnapshot {
6
+ version: 1;
7
+ timestamp: string;
8
+ agent: AgentName;
9
+ messages: Message[];
10
+ log: LogEntry[];
11
+ toolEvents: ToolEvent[];
12
+ turnTimings: TurnTiming[];
13
+ conversationResult: {
14
+ turns: number;
15
+ completionReason: ConversationResult['completionReason'];
16
+ completionDetail?: string;
17
+ turnTimings: TurnTiming[];
18
+ };
19
+ workspace: string | null;
20
+ }
21
+ export declare function buildRunSnapshot(params: {
22
+ agent: AgentName;
23
+ messages: Message[];
24
+ log: LogEntry[];
25
+ conversationResult: ConversationResult;
26
+ workspace: string | null;
27
+ timestamp?: string;
28
+ }): RunSnapshot;
29
+ export declare class SnapshotParseError extends Error {
30
+ constructor(message: string, options?: {
31
+ cause?: unknown;
32
+ });
33
+ }
34
+ export declare class SnapshotVersionError extends Error {
35
+ constructor(version: number);
36
+ }
37
+ export declare class WorkspaceMissingError extends Error {
38
+ constructor(message: string);
39
+ }
40
+ export declare function buildTranscript(messages: Message[]): string;
41
+ export declare function loadRunSnapshot(snapshotPath: string): Promise<RunSnapshot>;
@@ -0,0 +1,148 @@
1
+ import fs from 'fs-extra';
2
+ export const RUN_SNAPSHOT_VERSION = 1;
3
+ export function buildRunSnapshot(params) {
4
+ const { agent, messages, log, conversationResult, workspace, timestamp } = params;
5
+ const toolEvents = log
6
+ .filter((entry) => entry.type === 'tool_event' && entry.tool_event)
7
+ .map((entry) => entry.tool_event);
8
+ return {
9
+ version: RUN_SNAPSHOT_VERSION,
10
+ timestamp: timestamp ?? new Date().toISOString(),
11
+ agent,
12
+ messages: [...messages],
13
+ log: [...log],
14
+ toolEvents,
15
+ turnTimings: [...conversationResult.turnTimings],
16
+ conversationResult: {
17
+ turns: conversationResult.turns,
18
+ completionReason: conversationResult.completionReason,
19
+ ...(conversationResult.completionDetail ? { completionDetail: conversationResult.completionDetail } : {}),
20
+ turnTimings: [...conversationResult.turnTimings],
21
+ },
22
+ workspace,
23
+ };
24
+ }
25
+ export class SnapshotParseError extends Error {
26
+ constructor(message, options) {
27
+ super(message);
28
+ this.name = 'SnapshotParseError';
29
+ if (options?.cause !== undefined) {
30
+ this.cause = options.cause;
31
+ }
32
+ }
33
+ }
34
+ export class SnapshotVersionError extends Error {
35
+ constructor(version) {
36
+ super(`Unsupported snapshot version: ${version}`);
37
+ this.name = 'SnapshotVersionError';
38
+ }
39
+ }
40
+ export class WorkspaceMissingError extends Error {
41
+ constructor(message) {
42
+ super(message);
43
+ this.name = 'WorkspaceMissingError';
44
+ }
45
+ }
46
+ const ASK_SOURCE_VALUES = new Set(['claude', 'codex-app-server', 'cursor']);
47
+ const ASK_LIFECYCLE_VALUES = new Set(['live', 'post-hoc']);
48
+ function validateLogEntries(entries) {
49
+ for (let i = 0; i < entries.length; i++) {
50
+ const entry = entries[i];
51
+ if (!entry || typeof entry !== 'object') {
52
+ throw new SnapshotParseError(`Snapshot log entry ${i} must be an object`);
53
+ }
54
+ const record = entry;
55
+ if (record.type === 'ask_batch') {
56
+ if (typeof record.batch_id !== 'string') {
57
+ throw new SnapshotParseError(`ask_batch log entry ${i} is missing required field: batch_id`);
58
+ }
59
+ if (typeof record.turn_number !== 'number') {
60
+ throw new SnapshotParseError(`ask_batch log entry ${i} is missing required field: turn_number`);
61
+ }
62
+ if (typeof record.source !== 'string' || !ASK_SOURCE_VALUES.has(record.source)) {
63
+ throw new SnapshotParseError(`ask_batch log entry ${i} has invalid source: ${String(record.source)}`);
64
+ }
65
+ if (typeof record.lifecycle !== 'string' || !ASK_LIFECYCLE_VALUES.has(record.lifecycle)) {
66
+ throw new SnapshotParseError(`ask_batch log entry ${i} has invalid lifecycle: ${String(record.lifecycle)}`);
67
+ }
68
+ if (typeof record.source_tool !== 'string') {
69
+ throw new SnapshotParseError(`ask_batch log entry ${i} is missing required field: source_tool`);
70
+ }
71
+ if (typeof record.question_count !== 'number') {
72
+ throw new SnapshotParseError(`ask_batch log entry ${i} is missing required field: question_count`);
73
+ }
74
+ }
75
+ // Legacy blocked_prompt_* fields on agent_result entries remain accepted
76
+ // without additional validation — their schema is owned by the writer.
77
+ }
78
+ }
79
+ export function buildTranscript(messages) {
80
+ return messages
81
+ .map((msg) => `[${msg.role === 'user' ? 'User' : 'Agent'}]\n${msg.content}`)
82
+ .join('\n\n');
83
+ }
84
+ export async function loadRunSnapshot(snapshotPath) {
85
+ let parsed;
86
+ try {
87
+ parsed = await fs.readJSON(snapshotPath);
88
+ }
89
+ catch (error) {
90
+ throw new SnapshotParseError(`Failed to read snapshot JSON from ${snapshotPath}`, { cause: error });
91
+ }
92
+ return validateRunSnapshot(parsed);
93
+ }
94
+ function validateRunSnapshot(input) {
95
+ if (!input || typeof input !== 'object') {
96
+ throw new SnapshotParseError('Snapshot must be a JSON object');
97
+ }
98
+ const snapshot = input;
99
+ if (typeof snapshot.version !== 'number') {
100
+ throw new SnapshotParseError('Snapshot is missing required field: version');
101
+ }
102
+ if (snapshot.version > RUN_SNAPSHOT_VERSION) {
103
+ throw new SnapshotVersionError(snapshot.version);
104
+ }
105
+ if (!Array.isArray(snapshot.messages)) {
106
+ throw new SnapshotParseError('Snapshot is missing required field: messages');
107
+ }
108
+ if (!Array.isArray(snapshot.log)) {
109
+ throw new SnapshotParseError('Snapshot is missing required field: log');
110
+ }
111
+ validateLogEntries(snapshot.log);
112
+ if (!Array.isArray(snapshot.toolEvents)) {
113
+ throw new SnapshotParseError('Snapshot is missing required field: toolEvents');
114
+ }
115
+ if (!snapshot.conversationResult || typeof snapshot.conversationResult !== 'object') {
116
+ throw new SnapshotParseError('Snapshot is missing required field: conversationResult');
117
+ }
118
+ if (!Array.isArray(snapshot.conversationResult.turnTimings)) {
119
+ throw new SnapshotParseError('Snapshot conversationResult is missing required field: turnTimings');
120
+ }
121
+ if (typeof snapshot.conversationResult.turns !== 'number') {
122
+ throw new SnapshotParseError('Snapshot conversationResult is missing required field: turns');
123
+ }
124
+ if (typeof snapshot.conversationResult.completionReason !== 'string') {
125
+ throw new SnapshotParseError('Snapshot conversationResult is missing required field: completionReason');
126
+ }
127
+ const turnTimings = Array.isArray(snapshot.turnTimings)
128
+ ? snapshot.turnTimings
129
+ : snapshot.conversationResult.turnTimings;
130
+ return {
131
+ version: RUN_SNAPSHOT_VERSION,
132
+ timestamp: typeof snapshot.timestamp === 'string' ? snapshot.timestamp : new Date(0).toISOString(),
133
+ agent: snapshot.agent === 'claude' || snapshot.agent === 'codex' || snapshot.agent === 'cursor' ? snapshot.agent : 'claude',
134
+ messages: snapshot.messages,
135
+ log: snapshot.log,
136
+ toolEvents: snapshot.toolEvents,
137
+ turnTimings,
138
+ conversationResult: {
139
+ turns: snapshot.conversationResult.turns,
140
+ completionReason: snapshot.conversationResult.completionReason,
141
+ ...(snapshot.conversationResult.completionDetail
142
+ ? { completionDetail: snapshot.conversationResult.completionDetail }
143
+ : {}),
144
+ turnTimings: snapshot.conversationResult.turnTimings,
145
+ },
146
+ workspace: typeof snapshot.workspace === 'string' ? snapshot.workspace : null,
147
+ };
148
+ }