@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,208 @@
1
+ /**
2
+ * SDK message projector — typed `SDKMessage[]` → `AgentTurnResult`.
3
+ *
4
+ * Replaces the legacy NDJSON parser (`extractClaudeStreamJsonEvents`). Pure
5
+ * function: no I/O, no ask-bus, no session state. The Claude SDK driver
6
+ * buffers each turn's `SDKMessage` stream (`for await`) and hands the array
7
+ * here; the projector returns the public `AgentTurnResult` plus the
8
+ * `session_id` the orchestrator threads into the next turn's
9
+ * `Options.resume`.
10
+ *
11
+ * Boundary with the live ask-user bridge: for an `AskUserQuestion`
12
+ * tool-use block the projector emits a `ToolEvent` whose `arguments` shape
13
+ * is the structured `AskUserQuestionInput` (questions / headers / options /
14
+ * multiSelect) plus `answerSource: 'unknown'`. The bridge attaches the
15
+ * answer values and the `'reaction' | 'fallback' | 'declined'` source tag
16
+ * onto the same envelope; the projector itself never mints them.
17
+ */
18
+ const SDK_ERROR_SUBTYPES = [
19
+ 'error_during_execution',
20
+ 'error_max_turns',
21
+ 'error_max_budget_usd',
22
+ 'error_max_structured_output_retries',
23
+ ];
24
+ import { TOOL_NAME_MAP, buildSummary, enrichSkillEvents } from '../../tool-events.js';
25
+ export function projectSdkMessages(input) {
26
+ let sessionId;
27
+ let initSkills;
28
+ let assistantText = '';
29
+ let resultText = '';
30
+ let exitCode = 0;
31
+ let isError = false;
32
+ let inputTokens;
33
+ let outputTokens;
34
+ let cacheCreationInputTokens;
35
+ let cacheReadInputTokens;
36
+ let costUsd;
37
+ let errorSubtype;
38
+ const toolEvents = [];
39
+ for (const msg of input.messages) {
40
+ switch (msg.type) {
41
+ case 'system': {
42
+ const sid = msg.session_id;
43
+ if (sid)
44
+ sessionId = sid;
45
+ const sub = msg.subtype;
46
+ if (sub === 'init') {
47
+ const skills = msg.skills;
48
+ if (Array.isArray(skills))
49
+ initSkills = skills.filter((s) => typeof s === 'string');
50
+ }
51
+ break;
52
+ }
53
+ case 'assistant': {
54
+ const content = msg
55
+ .message?.content ?? [];
56
+ for (const block of content) {
57
+ if (block.type === 'text' && typeof block.text === 'string') {
58
+ assistantText += block.text;
59
+ continue;
60
+ }
61
+ if (block.type === 'tool_use') {
62
+ toolEvents.push(buildToolEvent(block, input.turnNumber, input.answerStore));
63
+ }
64
+ }
65
+ break;
66
+ }
67
+ case 'result': {
68
+ const r = msg;
69
+ if (r.session_id)
70
+ sessionId = r.session_id;
71
+ if (typeof r.result === 'string')
72
+ resultText = r.result;
73
+ if (r.usage) {
74
+ inputTokens =
75
+ (r.usage.input_tokens ?? 0)
76
+ + (r.usage.cache_creation_input_tokens ?? 0)
77
+ + (r.usage.cache_read_input_tokens ?? 0);
78
+ outputTokens = r.usage.output_tokens;
79
+ // Additive cache-token breakdown. `inputTokens` above
80
+ // keeps the existing pathgrade convention of including
81
+ // cache volume — these fields just expose the SDK's own
82
+ // breakdown for consumers that want to reason about cache
83
+ // hits/creation separately.
84
+ cacheCreationInputTokens = r.usage.cache_creation_input_tokens;
85
+ cacheReadInputTokens = r.usage.cache_read_input_tokens;
86
+ }
87
+ // Surface SDK-reported turn cost on success and error result
88
+ // subtypes alike. The driver accumulates these into the
89
+ // conversation cost downstream.
90
+ if (typeof r.total_cost_usd === 'number') {
91
+ costUsd = r.total_cost_usd;
92
+ }
93
+ if (r.is_error || (r.subtype && r.subtype !== 'success')) {
94
+ isError = true;
95
+ exitCode = 1;
96
+ // Surface the SDK's typed error subtype so consumers can
97
+ // triage without regex on text.
98
+ if (r.subtype && SDK_ERROR_SUBTYPES.includes(r.subtype)) {
99
+ errorSubtype = r.subtype;
100
+ }
101
+ }
102
+ break;
103
+ }
104
+ default:
105
+ break;
106
+ }
107
+ }
108
+ const trimmedAssistant = assistantText.trim();
109
+ const trimmedResult = resultText.trim();
110
+ const visible = isError ? '' : (trimmedAssistant || trimmedResult);
111
+ const rawOutput = resultText || assistantText;
112
+ const enriched = enrichSkillEvents(toolEvents);
113
+ const finalToolEvents = prependSlashCommandSkillEvent(enriched, input.firstMessage, initSkills);
114
+ const traceOutput = input.messages.map((m) => JSON.stringify(m)).join('\n');
115
+ const result = {
116
+ rawOutput,
117
+ assistantMessage: visible,
118
+ visibleAssistantMessage: visible,
119
+ visibleAssistantMessageSource: 'assistant_message',
120
+ exitCode,
121
+ traceOutput,
122
+ toolEvents: finalToolEvents,
123
+ runtimePoliciesApplied: [],
124
+ inputTokens,
125
+ outputTokens,
126
+ ...(cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens } : {}),
127
+ ...(cacheReadInputTokens !== undefined ? { cacheReadInputTokens } : {}),
128
+ ...(costUsd !== undefined ? { costUsd } : {}),
129
+ ...(errorSubtype !== undefined ? { errorSubtype } : {}),
130
+ };
131
+ return { result, sessionId };
132
+ }
133
+ /**
134
+ * If the first user message of the turn is `/<name>` and `<name>` is one of
135
+ * the skills the SDK reported in its `init.skills` array, prepend a synthetic
136
+ * `use_skill` tool event so scorers that key on `use_skill` see the implicit
137
+ * skill activation. The Claude SDK does not emit a tool_use for slash-command
138
+ * skill invocations the way an explicit `Skill` tool call does — this is the
139
+ * NDJSON-era behavior the legacy parser also synthesized, preserved here.
140
+ */
141
+ function prependSlashCommandSkillEvent(events, firstMessage, initSkills) {
142
+ if (!firstMessage || !initSkills)
143
+ return events;
144
+ const match = firstMessage.match(/^\/([^\s]+)/);
145
+ if (!match)
146
+ return events;
147
+ const skillName = match[1];
148
+ if (!initSkills.includes(skillName))
149
+ return events;
150
+ return [
151
+ {
152
+ action: 'use_skill',
153
+ provider: 'claude',
154
+ providerToolName: 'Skill',
155
+ arguments: { skill: skillName },
156
+ skillName,
157
+ summary: `use_skill "${skillName}"`,
158
+ confidence: 'high',
159
+ rawSnippet: '(detected from slash command in prompt)',
160
+ },
161
+ ...events,
162
+ ];
163
+ }
164
+ function buildToolEvent(block, turnNumber, answerStore) {
165
+ const providerToolName = String(block.name || 'unknown');
166
+ const rawInput = block.input ?? undefined;
167
+ const toolUseId = typeof block.id === 'string' ? block.id : undefined;
168
+ const action = TOOL_NAME_MAP[providerToolName] ?? 'unknown';
169
+ const args = action === 'ask_user'
170
+ ? buildAskUserArguments(rawInput, answerStore?.get(toolUseId))
171
+ : rawInput;
172
+ const summary = buildSummary(action, providerToolName, args);
173
+ const rawSnippet = JSON.stringify(block).slice(0, 200);
174
+ return {
175
+ action,
176
+ provider: 'claude',
177
+ providerToolName,
178
+ turnNumber,
179
+ arguments: args,
180
+ summary,
181
+ confidence: 'high',
182
+ rawSnippet,
183
+ };
184
+ }
185
+ /**
186
+ * Boundary with the ask-user bridge.
187
+ *
188
+ * The projector emits the structured `AskUserQuestionInput` (questions /
189
+ * headers / options / multiSelect) plus `answerSource: 'unknown'`. The
190
+ * ask-user-bridge attaches the answer values and the
191
+ * `'reaction' | 'fallback' | 'declined'` source tag onto this same envelope.
192
+ *
193
+ * The projector itself never mints answer values, never mints a non-`unknown`
194
+ * source, and never reaches into the bus — it just stamps the boundary so a
195
+ * turn that produces an AskUserQuestion event without a bridge entry still
196
+ * has a snapshot-stable shape for scorers and reporters.
197
+ */
198
+ function buildAskUserArguments(input, bridgeEntry) {
199
+ const base = input ? { ...input } : {};
200
+ if (bridgeEntry) {
201
+ return {
202
+ ...base,
203
+ answers: { ...bridgeEntry.answers },
204
+ answerSource: bridgeEntry.source,
205
+ };
206
+ }
207
+ return { ...base, answerSource: 'unknown' };
208
+ }
@@ -0,0 +1,52 @@
1
+ import type { CanUseTool, Options, SpawnedProcess, SpawnOptions as SdkSpawnOptions } from '@anthropic-ai/claude-agent-sdk';
2
+ import type { McpServersObject } from '../../providers/mcp-config.js';
3
+ export interface ClaudeSdkOptionsInputs {
4
+ /** Per-trial workspace; cwd for the SDK so project-staged skills resolve. */
5
+ workspacePath: string;
6
+ /** Custom spawn hook from the sandboxed-claude-spawn module. */
7
+ spawnClaudeCodeProcess: (opts: SdkSpawnOptions) => SpawnedProcess;
8
+ /** Custom tool-permission callback — the live ask-user bridge. */
9
+ canUseTool: CanUseTool;
10
+ /**
11
+ * The curated workspace runtime env, spread wholesale onto `Options.env`.
12
+ * Carries (1) ANTHROPIC_* credentials resolved by `resolveCredentials()`,
13
+ * (2) sandbox HOME/TMPDIR set by `prepareWorkspace`, and (3) any
14
+ * `createAgent({ env })` keys the user supplied. The driver does not
15
+ * gatekeep which keys reach the SDK subprocess — `prepareWorkspace`
16
+ * curates the workspace env upstream and the sandboxed-spawn module's
17
+ * `SAFE_HOST_VARS` filter defends host-env leakage from a different
18
+ * direction. This is the single env composition point the driver owns.
19
+ */
20
+ runtimeEnv: Record<string, string>;
21
+ /** Forwarded to the SDK only when set. */
22
+ model?: string;
23
+ /**
24
+ * Override for the bundled `claude` binary. Precedence (resolved by the
25
+ * caller): `AgentOptions.claudeCodeExecutable` > `PATHGRADE_CLAUDE_CODE_EXECUTABLE`
26
+ * > undefined (use SDK's bundled per-platform binary).
27
+ */
28
+ claudeCodeExecutable?: string;
29
+ /**
30
+ * Resume session id. Omitted on turn 1; set to the prior turn's
31
+ * `session_id` on every turn after.
32
+ */
33
+ resume?: string;
34
+ /** MCP servers in the SDK's object form, from `loadMcpServersForSdk`. */
35
+ mcpServers?: McpServersObject;
36
+ }
37
+ /**
38
+ * Pick the Claude executable. Precedence:
39
+ *
40
+ * 1. `AgentOptions.claudeCodeExecutable` — explicit run-level override.
41
+ * 2. `PATHGRADE_CLAUDE_CODE_EXECUTABLE` — process env override.
42
+ * 3. `undefined` — fall back to the SDK's bundled per-platform binary.
43
+ *
44
+ * `undefined` is intentional, not "missing": it tells `buildClaudeSdkOptions`
45
+ * to omit `Options.pathToClaudeCodeExecutable` so the SDK uses its bundled
46
+ * default.
47
+ */
48
+ export declare function resolveClaudeCodeExecutable(args: {
49
+ agentOptionsExecutable?: string;
50
+ envExecutable?: string;
51
+ }): string | undefined;
52
+ export declare function buildClaudeSdkOptions(inputs: ClaudeSdkOptionsInputs): Options;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Pure builder that turns pathgrade's per-turn session inputs into the Claude
3
+ * Agent SDK's `Options` object passed to `query()`. The driver class is just
4
+ * orchestration over this builder, the sandboxed-spawn module, the live
5
+ * ask-user bridge, and the SDK message projector.
6
+ */
7
+ import * as path from 'path';
8
+ /**
9
+ * Per-workspace Claude config/home dir. Set via `Options.env.CLAUDE_CONFIG_DIR`
10
+ * so the bundled subprocess does not read host `~/.claude.json`, user memory,
11
+ * or ambient state.
12
+ */
13
+ const CLAUDE_CONFIG_SUBDIR = '.pathgrade-claude-config';
14
+ /**
15
+ * Pick the Claude executable. Precedence:
16
+ *
17
+ * 1. `AgentOptions.claudeCodeExecutable` — explicit run-level override.
18
+ * 2. `PATHGRADE_CLAUDE_CODE_EXECUTABLE` — process env override.
19
+ * 3. `undefined` — fall back to the SDK's bundled per-platform binary.
20
+ *
21
+ * `undefined` is intentional, not "missing": it tells `buildClaudeSdkOptions`
22
+ * to omit `Options.pathToClaudeCodeExecutable` so the SDK uses its bundled
23
+ * default.
24
+ */
25
+ export function resolveClaudeCodeExecutable(args) {
26
+ if (args.agentOptionsExecutable)
27
+ return args.agentOptionsExecutable;
28
+ if (args.envExecutable)
29
+ return args.envExecutable;
30
+ return undefined;
31
+ }
32
+ export function buildClaudeSdkOptions(inputs) {
33
+ const opts = {
34
+ cwd: inputs.workspacePath,
35
+ systemPrompt: { type: 'preset', preset: 'claude_code' },
36
+ settingSources: ['project'],
37
+ // Disable auto-memory at the source. SDK 0.2.117 exposes the toggle
38
+ // through `Options.settings.autoMemoryEnabled` (the field lives on
39
+ // `Settings`, reachable here via the typed `Options.settings?: string
40
+ // | Settings` indirection), so the SDK never runs auto-memory recall,
41
+ // indexing, or writes during a trial. `CLAUDE_CONFIG_DIR` and
42
+ // `settingSources: ['project']` add defense-in-depth: the former
43
+ // redirects any per-trial state to a workspace-scoped scratch dir if
44
+ // the flag is ever ignored upstream, and the latter excludes the
45
+ // user-scope `~/.claude/settings.json` so a host-level
46
+ // `autoMemoryEnabled: true` cannot re-enable it.
47
+ settings: { autoMemoryEnabled: false },
48
+ permissionMode: 'default',
49
+ spawnClaudeCodeProcess: inputs.spawnClaudeCodeProcess,
50
+ canUseTool: inputs.canUseTool,
51
+ };
52
+ if (inputs.model !== undefined)
53
+ opts.model = inputs.model;
54
+ if (inputs.claudeCodeExecutable !== undefined) {
55
+ opts.pathToClaudeCodeExecutable = inputs.claudeCodeExecutable;
56
+ }
57
+ if (inputs.resume !== undefined)
58
+ opts.resume = inputs.resume;
59
+ if (inputs.mcpServers !== undefined)
60
+ opts.mcpServers = inputs.mcpServers;
61
+ // Env composition ownership: the driver does NOT pluck specific keys.
62
+ // `prepareWorkspace` curates the runtime env (safe host vars, sandbox
63
+ // HOME/TMPDIR, resolveCredentials() output, user-supplied
64
+ // `createAgent({ env })`); the sandboxed-spawn module's SAFE_HOST_VARS
65
+ // filter guards host-env leakage from a different direction. The
66
+ // driver's job is to spread that curated env wholesale onto Options.env,
67
+ // then layer driver-owned hermetic overrides on top — `CLAUDE_CONFIG_DIR`
68
+ // wins on collision so an upstream leak (or a user-supplied env value)
69
+ // cannot weaken the per-trial isolation invariant.
70
+ const env = {};
71
+ for (const [key, value] of Object.entries(inputs.runtimeEnv)) {
72
+ if (value === undefined)
73
+ continue;
74
+ env[key] = value;
75
+ }
76
+ env.CLAUDE_CONFIG_DIR = path.join(inputs.workspacePath, CLAUDE_CONFIG_SUBDIR);
77
+ opts.env = env;
78
+ return opts;
79
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Claude agent driver — Claude Agent SDK edition.
3
+ *
4
+ * Replaces the previous CLI-scraping driver with one built on
5
+ * `@anthropic-ai/claude-agent-sdk`. The driver class is just orchestration
6
+ * over five deep modules:
7
+ *
8
+ * - `sandboxedClaudeSpawn` — `Options.spawnClaudeCodeProcess` adapter
9
+ * that filters env and (optionally) wraps
10
+ * argv with macOS sandbox-exec.
11
+ * - `loadMcpServersForSdk` — reads pathgrade's MCP config JSON into
12
+ * the SDK's `Options.mcpServers` shape.
13
+ * - `buildClaudeSdkOptions` — pure builder for the per-turn `Options`.
14
+ * - `createAskUserBridge` — live `canUseTool` that auto-allows
15
+ * non-`AskUserQuestion` tools and resolves
16
+ * `AskUserQuestion` through the ask-bus,
17
+ * returning the SDK's documented `answers`
18
+ * map shape on `updatedInput`. Per-turn
19
+ * answer store feeds the projector.
20
+ * - `projectSdkMessages` — pure typed-message → `AgentTurnResult`
21
+ * projector. Replaces the legacy NDJSON
22
+ * parser wholesale.
23
+ */
24
+ import { type Options as SdkOptions, type Query } from '@anthropic-ai/claude-agent-sdk';
25
+ import { AgentCommandRunner, AgentSession, AgentSessionOptions, BaseAgent, EnvironmentHandle } from '../types.js';
26
+ /** Shape of the SDK `query()` callable, narrowed for orchestration use. */
27
+ export type ClaudeSdkQueryFn = (args: {
28
+ prompt: string | unknown;
29
+ options?: SdkOptions;
30
+ }) => Query;
31
+ export interface ClaudeAgentDeps {
32
+ /** Override the SDK `query()` for tests. Defaults to the real SDK. */
33
+ query?: ClaudeSdkQueryFn;
34
+ /** Override the host platform check for tests. Defaults to `process.platform`. */
35
+ platform?: NodeJS.Platform;
36
+ /** Override the host env for the spawn module's filter. Defaults to `process.env`. */
37
+ hostEnv?: NodeJS.ProcessEnv;
38
+ /** Override `process.env.PATHGRADE_CLAUDE_CODE_EXECUTABLE` for tests. */
39
+ envExecutable?: string;
40
+ /** Optional macOS sandbox-exec profile. None today; preserves the seam. */
41
+ sandboxProfile?: string;
42
+ }
43
+ export interface ClaudeAgentOptions {
44
+ /**
45
+ * Path to a Claude binary that overrides the SDK's bundled per-platform
46
+ * default. Run-level (set on the agent constructor); per-fixture override
47
+ * is intentionally out of scope.
48
+ */
49
+ claudeCodeExecutable?: string;
50
+ }
51
+ export declare class ClaudeAgent extends BaseAgent {
52
+ private readonly deps;
53
+ private readonly opts;
54
+ constructor(deps?: ClaudeAgentDeps, opts?: ClaudeAgentOptions);
55
+ createSession(runtime: EnvironmentHandle, _runCommand: AgentCommandRunner, sessionOptions?: AgentSessionOptions): Promise<AgentSession>;
56
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Claude agent driver — Claude Agent SDK edition.
3
+ *
4
+ * Replaces the previous CLI-scraping driver with one built on
5
+ * `@anthropic-ai/claude-agent-sdk`. The driver class is just orchestration
6
+ * over five deep modules:
7
+ *
8
+ * - `sandboxedClaudeSpawn` — `Options.spawnClaudeCodeProcess` adapter
9
+ * that filters env and (optionally) wraps
10
+ * argv with macOS sandbox-exec.
11
+ * - `loadMcpServersForSdk` — reads pathgrade's MCP config JSON into
12
+ * the SDK's `Options.mcpServers` shape.
13
+ * - `buildClaudeSdkOptions` — pure builder for the per-turn `Options`.
14
+ * - `createAskUserBridge` — live `canUseTool` that auto-allows
15
+ * non-`AskUserQuestion` tools and resolves
16
+ * `AskUserQuestion` through the ask-bus,
17
+ * returning the SDK's documented `answers`
18
+ * map shape on `updatedInput`. Per-turn
19
+ * answer store feeds the projector.
20
+ * - `projectSdkMessages` — pure typed-message → `AgentTurnResult`
21
+ * projector. Replaces the legacy NDJSON
22
+ * parser wholesale.
23
+ */
24
+ import { query as sdkQuery, } from '@anthropic-ai/claude-agent-sdk';
25
+ import { BaseAgent, getRuntimeEnv, getWorkspacePath, } from '../types.js';
26
+ import { createSandboxedClaudeSpawn } from '../providers/sandboxed-claude-spawn.js';
27
+ import { loadMcpServersForSdk } from '../providers/mcp-config.js';
28
+ import { buildClaudeSdkOptions, resolveClaudeCodeExecutable, } from './claude/sdk-options.js';
29
+ import { projectSdkMessages } from './claude/sdk-message-projector.js';
30
+ import { createAskUserBridge } from './claude/ask-user-bridge.js';
31
+ import { createAskUserAnswerStore } from './claude/ask-user-answer-store.js';
32
+ import { requireAskBusForLiveBatches } from '../sdk/ask-bus/bus.js';
33
+ export class ClaudeAgent extends BaseAgent {
34
+ deps;
35
+ opts;
36
+ constructor(deps = {}, opts = {}) {
37
+ super();
38
+ this.deps = deps;
39
+ this.opts = opts;
40
+ }
41
+ async createSession(runtime, _runCommand, sessionOptions) {
42
+ // Live ask-user batches require a real subscriber. Fail fast at session
43
+ // construction rather than silently sending an empty answer back to
44
+ // Claude on the wire when the bus is missing.
45
+ const askBus = requireAskBusForLiveBatches(sessionOptions, 'ClaudeSdkAgent');
46
+ const workspacePath = getWorkspacePath(runtime);
47
+ const queryFn = this.deps.query ?? sdkQuery;
48
+ const platform = this.deps.platform ?? process.platform;
49
+ const hostEnv = this.deps.hostEnv ?? process.env;
50
+ const envExecutable = this.deps.envExecutable ?? process.env.PATHGRADE_CLAUDE_CODE_EXECUTABLE;
51
+ const sandboxedSpawn = createSandboxedClaudeSpawn({
52
+ platform,
53
+ hostEnv,
54
+ sandboxProfile: this.deps.sandboxProfile,
55
+ });
56
+ const claudeCodeExecutable = resolveClaudeCodeExecutable({
57
+ agentOptionsExecutable: this.opts.claudeCodeExecutable,
58
+ envExecutable,
59
+ });
60
+ const mcpServers = await loadMcpServersForSdk(workspacePath);
61
+ let priorSessionId;
62
+ let turnNumber = 0;
63
+ // The live ask-user bridge resolves AskUserQuestion through the bus
64
+ // and writes the resulting answers + source into the per-turn answer
65
+ // store; the projector merges those onto the AskUserQuestion
66
+ // ToolEvent envelope. The store is rebuilt per turn so a question on
67
+ // turn 2 cannot read a stale answer from turn 1 even on toolUseID
68
+ // collisions.
69
+ let answerStore = createAskUserAnswerStore();
70
+ const bridge = createAskUserBridge({
71
+ askBus,
72
+ getTurnNumber: () => turnNumber,
73
+ answerStore: { record: (id, e) => answerStore.record(id, e), get: (id) => answerStore.get(id) },
74
+ });
75
+ const runTurn = async (message) => {
76
+ turnNumber += 1;
77
+ answerStore = createAskUserAnswerStore();
78
+ // Clear any ask-bus rejection captured on a prior turn so a
79
+ // stale error never causes a spurious result on this turn.
80
+ bridge.clearLastError();
81
+ const sdkOptions = buildClaudeSdkOptions({
82
+ workspacePath,
83
+ spawnClaudeCodeProcess: sandboxedSpawn,
84
+ canUseTool: bridge,
85
+ runtimeEnv: getRuntimeEnv(runtime),
86
+ model: sessionOptions?.model,
87
+ claudeCodeExecutable,
88
+ resume: priorSessionId,
89
+ mcpServers,
90
+ });
91
+ const messages = [];
92
+ const stream = queryFn({ prompt: message, options: sdkOptions });
93
+ for await (const msg of stream) {
94
+ messages.push(msg);
95
+ }
96
+ // The legacy NDJSON parser only synthesized the slash-command
97
+ // `use_skill` event from the *opening* user message. The Claude
98
+ // SDK emits a fresh `init` system message (carrying `skills`) on
99
+ // every `query()` call — each turn spawns a fresh subprocess —
100
+ // so passing the current turn's message into the projector on
101
+ // turn 2+ would re-fire synthesis for the same skill activation.
102
+ // Gate by turn number to preserve the legacy semantic: synthesize
103
+ // on turn 1 only, never thereafter.
104
+ const projectorFirstMessage = turnNumber === 1 ? message : undefined;
105
+ const projected = projectSdkMessages({
106
+ messages,
107
+ turnNumber,
108
+ firstMessage: projectorFirstMessage,
109
+ answerStore,
110
+ });
111
+ // Capture the SDK-reported session id BEFORE checking for a bus
112
+ // rejection so the next turn's `Options.resume` points at this
113
+ // turn's session even when the turn ended in an ask-bus error.
114
+ if (projected.sessionId)
115
+ priorSessionId = projected.sessionId;
116
+ // An ask-bus rejection (timeout, missing subscriber, handler
117
+ // throw) produced an SDK deny mid-turn AND captured the underlying
118
+ // error on the bridge. Returning an error `AgentTurnResult` rather
119
+ // than throwing lets the conversation runner project the partial
120
+ // turn through `pushModelAgentMessage` (`ask_batch`,
121
+ // `model_agent_result`, turn timings/details) before propagating
122
+ // the failure — preserving observability into what the agent
123
+ // attempted before being killed.
124
+ const bridgeError = bridge.lastError();
125
+ if (bridgeError) {
126
+ const errorMessage = bridgeError instanceof Error
127
+ ? bridgeError.message
128
+ : String(bridgeError);
129
+ return {
130
+ ...projected.result,
131
+ exitCode: 1,
132
+ errorSubtype: 'bus_rejection',
133
+ rawOutput: errorMessage,
134
+ };
135
+ }
136
+ return projected.result;
137
+ };
138
+ return {
139
+ start: ({ message }) => runTurn(message),
140
+ reply: ({ message }) => runTurn(message),
141
+ };
142
+ }
143
+ }
@@ -0,0 +1,35 @@
1
+ import { AgentCommandRunner, AgentSession, AgentSessionOptions, BaseAgent, EnvironmentHandle } from '../../types.js';
2
+ import { type AppServerSessionHandle } from './transport.js';
3
+ type SandboxMode = 'workspace-write' | 'danger-full-access';
4
+ export interface PermissionGrantLogEntry {
5
+ type: 'permissions_granted';
6
+ turnNumber: number;
7
+ requested: unknown;
8
+ scope: 'turn';
9
+ strictAutoReview: false;
10
+ }
11
+ export interface CodexAppServerAgentDeps {
12
+ /**
13
+ * Inject a transport factory for tests. Default: spawn `codex app-server`
14
+ * via child_process with NDJSON stdio wrapped in an AppServerSessionHandle.
15
+ *
16
+ * Tests using PassThrough streams can construct a handle via
17
+ * {@link createAppServerSessionHandle} with `child: null` — dispose() then
18
+ * only closes the transport and does not attempt any kill sequence.
19
+ */
20
+ createTransport?: (ctx: {
21
+ workspacePath: string;
22
+ env: NodeJS.ProcessEnv;
23
+ }) => Promise<AppServerSessionHandle>;
24
+ /** Sandbox mode for `thread/start`. Default: 'workspace-write'. */
25
+ sandboxMode?: SandboxMode;
26
+ /** Observer for per-grant audit entries (§7 of design decisions). */
27
+ onPermissionGrant?: (entry: PermissionGrantLogEntry) => void;
28
+ }
29
+ export declare class CodexAppServerAgent extends BaseAgent {
30
+ private deps;
31
+ constructor(deps?: CodexAppServerAgentDeps);
32
+ createSession(runtime: EnvironmentHandle, _runCommand: AgentCommandRunner, options?: AgentSessionOptions): Promise<AgentSession>;
33
+ private dispatchServerRequest;
34
+ }
35
+ export {};