@wix/pathgrade 0.30.0 → 0.32.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.
@@ -67,13 +67,18 @@ export function buildClaudeSdkOptions(inputs) {
67
67
  // then layer driver-owned hermetic overrides on top — `CLAUDE_CONFIG_DIR`
68
68
  // wins on collision so an upstream leak (or a user-supplied env value)
69
69
  // cannot weaken the per-trial isolation invariant.
70
+ const useLocalOAuth = inputs.runtimeEnv.PATHGRADE_CLAUDE_LOCAL_OAUTH === '1';
70
71
  const env = {};
71
72
  for (const [key, value] of Object.entries(inputs.runtimeEnv)) {
72
73
  if (value === undefined)
73
74
  continue;
75
+ if (key === 'PATHGRADE_CLAUDE_LOCAL_OAUTH')
76
+ continue;
74
77
  env[key] = value;
75
78
  }
76
- env.CLAUDE_CONFIG_DIR = path.join(inputs.workspacePath, CLAUDE_CONFIG_SUBDIR);
79
+ if (!useLocalOAuth) {
80
+ env.CLAUDE_CONFIG_DIR = path.join(inputs.workspacePath, CLAUDE_CONFIG_SUBDIR);
81
+ }
77
82
  opts.env = env;
78
83
  return opts;
79
84
  }
@@ -85,11 +85,19 @@ async function resolveClaude(userEnv, ports) {
85
85
  // Keychain OAuth token unusable — it's scoped to direct Anthropic, not to
86
86
  // a proxy. Skip the Keychain branch so the host-forward fallback wins.
87
87
  const hostSignalsProxy = !!ports.hostEnv('ANTHROPIC_BASE_URL');
88
- // On macOS, prefer Keychain OAuth (direct Anthropic token).
88
+ // On macOS, prefer Claude Code's native claude.ai OAuth. Do not expose
89
+ // the OAuth access token as ANTHROPIC_API_KEY: Claude Code treats that env
90
+ // var as an external API-key auth path, and first-party OAuth tokens are
91
+ // rejected there as invalid API keys.
89
92
  if (ports.platform === 'darwin' && !hostSignalsProxy) {
90
93
  const token = await ports.readKeychainToken('Claude Code-credentials');
91
94
  if (token) {
92
- return { env: { ANTHROPIC_API_KEY: token }, setupCommands: [], copyFromHome: [] };
95
+ return {
96
+ env: { PATHGRADE_CLAUDE_LOCAL_OAUTH: '1' },
97
+ setupCommands: [],
98
+ copyFromHome: ['.claude.json'],
99
+ linkFromHome: ['Library/Keychains'],
100
+ };
93
101
  }
94
102
  }
95
103
  // Fallback: forward host API key and base URL.
@@ -11,6 +11,9 @@ async function hydrateTraces(report, traceFile, resolved) {
11
11
  }
12
12
  export async function loadReports(resultsDir, opts) {
13
13
  const resolved = path.resolve(resultsDir);
14
+ if (!await fs.pathExists(resolved)) {
15
+ return [];
16
+ }
14
17
  const files = (await fs.readdir(resolved))
15
18
  .filter(f => f.endsWith('.json'))
16
19
  .reverse();
package/dist/sdk/agent.js CHANGED
@@ -91,6 +91,14 @@ class AgentImpl {
91
91
  const turns = maxTurns ?? 30;
92
92
  return Math.ceil((turns * 80_000 + 200_000) / 1000);
93
93
  }
94
+ accumulateTurnUsage(turnResult) {
95
+ if (turnResult.inputTokens || turnResult.outputTokens) {
96
+ this.llm.addTokens?.(turnResult.inputTokens ?? 0, turnResult.outputTokens ?? 0);
97
+ }
98
+ if (turnResult.costUsd !== undefined) {
99
+ this.llm.addCost?.(turnResult.costUsd);
100
+ }
101
+ }
94
102
  async executeLoggedTurnResult(session, message, turnNumber, kind) {
95
103
  const timestamp = () => new Date().toISOString();
96
104
  this._messages.push({ role: 'user', content: message });
@@ -103,6 +111,7 @@ class AgentImpl {
103
111
  this.verbose.turnStart({ turn: turnNumber, kind, message });
104
112
  const turnStart = Date.now();
105
113
  const turnResult = await session.executeTurn(message);
114
+ this.accumulateTurnUsage(turnResult);
106
115
  const response = getVisibleAssistantMessage(turnResult);
107
116
  const durationMs = Date.now() - turnStart;
108
117
  this._log.push(buildModelAgentResultLogEntry({
@@ -132,7 +141,16 @@ class AgentImpl {
132
141
  if (turnResult.timedOut) {
133
142
  throw new Error(`Agent (limit: ${timeoutSec}s) timed out (agent killed)`);
134
143
  }
135
- throw new Error(`Agent exited with code ${turnResult.exitCode}`);
144
+ // Surface the underlying detail (e.g. an ask-bus rejection message
145
+ // from the Claude SDK driver) and the typed `errorSubtype` so a
146
+ // failing `prompt()`/`startChat()` does not collapse to a bare
147
+ // "Agent exited with code 1" — matching what `runConversation`
148
+ // already does via `converse.ts:buildTurnExitError`.
149
+ const detail = turnResult.rawOutput?.trim();
150
+ const subtype = turnResult.errorSubtype;
151
+ const subtypeTag = subtype ? ` (${subtype})` : '';
152
+ const suffix = detail ? `: ${detail}` : '';
153
+ throw new Error(`Agent exited with code ${turnResult.exitCode}${subtypeTag}${suffix}`);
136
154
  }
137
155
  return turnResult;
138
156
  }
@@ -165,7 +183,11 @@ class AgentImpl {
165
183
  messages: this._messages,
166
184
  log: this._log,
167
185
  exec: (cmd) => this.exec(cmd),
168
- sendTurn: (message) => ms.executeTurn(message),
186
+ sendTurn: async (message) => {
187
+ const turnResult = await ms.executeTurn(message);
188
+ this.accumulateTurnUsage(turnResult);
189
+ return turnResult;
190
+ },
169
191
  verbose: this.verbose,
170
192
  });
171
193
  }
@@ -180,17 +202,10 @@ class AgentImpl {
180
202
  const sendTurn = async (message) => {
181
203
  const turnResult = await ms.executeTurn(message);
182
204
  turnNumber++;
183
- // Accumulate agent turn tokens (from CLI stream-json) on the shared tracker
184
- if (turnResult.inputTokens || turnResult.outputTokens) {
185
- this.llm.addTokens?.(turnResult.inputTokens ?? 0, turnResult.outputTokens ?? 0);
186
- }
187
- // Accumulate agent turn cost on the same shared tracker when
188
- // the upstream provider reports it (Claude SDK populates
189
- // `costUsd` from `total_cost_usd`; Codex/Cursor leave it
190
- // undefined, in which case this is a no-op).
191
- if (turnResult.costUsd !== undefined) {
192
- this.llm.addCost?.(turnResult.costUsd);
193
- }
205
+ // Accumulate agent turn tokens (from CLI stream-json) on the shared tracker.
206
+ // Cost is populated by Claude SDK (from `total_cost_usd`); Codex/Cursor leave
207
+ // it undefined, in which case this is a no-op.
208
+ this.accumulateTurnUsage(turnResult);
194
209
  for (const toolEvent of turnResult.toolEvents) {
195
210
  this._log.push({
196
211
  type: 'tool_event',
package/dist/sdk/chat.js CHANGED
@@ -78,7 +78,15 @@ export class ChatSessionImpl {
78
78
  });
79
79
  if (turnResult.exitCode !== 0) {
80
80
  this._done = true;
81
- throw new Error(`Agent exited with code ${turnResult.exitCode}`);
81
+ // Match `agent.ts:executeLoggedTurnResult` append the driver's
82
+ // captured `rawOutput` and typed `errorSubtype` so chat-session
83
+ // failures expose actionable detail (e.g. ask-bus rejection from
84
+ // the Claude SDK driver) instead of a bare exit-code string.
85
+ const detail = turnResult.rawOutput?.trim();
86
+ const subtype = turnResult.errorSubtype;
87
+ const subtypeTag = subtype ? ` (${subtype})` : '';
88
+ const suffix = detail ? `: ${detail}` : '';
89
+ throw new Error(`Agent exited with code ${turnResult.exitCode}${subtypeTag}${suffix}`);
82
90
  }
83
91
  this._turn = turnNumber;
84
92
  this._lastMessage = response;
@@ -18,7 +18,7 @@ export { buildAskBatchLogEntries } from './agent-result-log.js';
18
18
  export { getAgentCapabilities } from './types.js';
19
19
  export type { AgentTransport, AgentCapabilities, AgentName } from './types.js';
20
20
  export type { AskBus, AskBatch, AskQuestion, AskOption, AskAnswer, AskResolution, AskBatchSnapshot, AskAnswerSnapshot, AskResolutionSnapshot, AskHandle, AskHandler, AskSource, AskLifecycle, AskAnswerSource, Unsubscribe as AskBusUnsubscribe, } from './ask-bus/types.js';
21
- export type { Agent, AgentOptions, Message, Scorer, CheckScorer, ScoreScorer, JudgeScorer, ToolUsageScorer, ScorerContext, EvalResult, ScorerResultEntry, ScorerStatus, ChatSession, ConversationResult, ConverseOptions, Reaction, TextReaction, AskUserReaction, AskUserQuestion, AskUserOption, ReactionPreviewEntry, TextReactionPreviewEntry, AskUserReactionPreviewEntry, ReactionPreviewResult, ReactionPreviewTurn, Persona, PersonaConfig, ConversationWindowConfig, PathgradePluginOptions, PathgradeMeta, TurnTiming, TokenUsage, EvaluateOptions, ReactionPreviewStatus, } from './types.js';
21
+ export type { Agent, AgentOptions, Message, Scorer, CheckScorer, ScoreScorer, JudgeScorer, ToolUsageScorer, ScorerContext, EvalResult, ScorerResultEntry, ScorerStatus, ChatSession, ConversationResult, ConverseOptions, UntilPredicate, UntilContext, Reaction, TextReaction, AskUserReaction, AskUserQuestion, AskUserOption, ReactionPreviewEntry, TextReactionPreviewEntry, AskUserReactionPreviewEntry, ReactionPreviewResult, ReactionPreviewTurn, StepScorer, Persona, PersonaConfig, ConversationWindowConfig, TurnDetail, ReactionFiredEntry, PathgradePluginOptions, PathgradeMeta, TurnTiming, TokenUsage, EvaluateOptions, ReactionPreviewStatus, ScoreResult, JudgeInput, CodeJudgeToolName, ToolExpectation, SessionArtifactMatchOptions, SessionArtifactContent, SessionArtifacts, RecordedEvalResult, PathgradeTestMeta, } from './types.js';
22
22
  export type { ConversationWindow, ConversationWindowOptions } from './conversation-window.js';
23
23
  export type { JudgePipelineOptions } from './judge-pipeline.js';
24
24
  export type { RunScorerOptions } from './run-scorer.js';
package/package.json CHANGED
@@ -1,7 +1,19 @@
1
1
  {
2
2
  "name": "@wix/pathgrade",
3
- "version": "0.30.0",
3
+ "version": "0.32.0",
4
4
  "description": "Evaluate whether AI agents discover and use your skills correctly",
5
+ "main": "./dist/sdk/index.js",
6
+ "types": "./dist/sdk/index.d.ts",
7
+ "typesVersions": {
8
+ "*": {
9
+ "plugin": [
10
+ "./dist/plugin/index.d.ts"
11
+ ],
12
+ "mcp-mock": [
13
+ "./dist/core/mcp-mock.d.ts"
14
+ ]
15
+ }
16
+ },
5
17
  "exports": {
6
18
  ".": {
7
19
  "types": "./dist/sdk/index.d.ts",
@@ -84,5 +96,5 @@
84
96
  "typescript": "^5.9.3",
85
97
  "zod": "4.3.6"
86
98
  },
87
- "falconPackageHash": "d98d954f1467c94ec73646e4a73cd9096d86991e79e3786c42690dd7"
99
+ "falconPackageHash": "2eac6cd3615471de5203991805252e0bd5555626a7e922a3ac009150"
88
100
  }