@wix/pathgrade 1.0.27 → 1.0.29

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 (64) hide show
  1. package/README.md +12 -19
  2. package/dist/adapters/jest/invocation-adapter.js +5 -1
  3. package/dist/adapters/jest/reporter.js +4 -1
  4. package/dist/adapters/jest/results.js +8 -0
  5. package/dist/adapters/node-test/index.d.ts +5 -0
  6. package/dist/adapters/node-test/index.js +35 -7
  7. package/dist/adapters/node-test/invocation-adapter.js +3 -1
  8. package/dist/adapters/node-test/runner-adapter.js +22 -15
  9. package/dist/adapters/vitest/reporter.js +4 -1
  10. package/dist/agents/claude.js +5 -4
  11. package/dist/agents/codex-app-server/agent.js +1 -51
  12. package/dist/agents/codex-app-server/turn-notifications.d.ts +6 -0
  13. package/dist/agents/codex-app-server/turn-notifications.js +51 -0
  14. package/dist/agents/codex-app-server/turn-state.d.ts +19 -0
  15. package/dist/agents/codex-app-server/turn-state.js +1 -0
  16. package/dist/agents/opencode/protocol.d.ts +7 -0
  17. package/dist/agents/opencode/protocol.js +47 -0
  18. package/dist/agents/opencode.js +1 -47
  19. package/dist/analytics/engine.js +5 -2
  20. package/dist/commands/report.js +16 -2
  21. package/dist/commands/run-args.d.ts +1 -0
  22. package/dist/commands/run-args.js +13 -0
  23. package/dist/commands/run-changed.js +5 -15
  24. package/dist/config/pathgrade.d.ts +3 -0
  25. package/dist/config/pathgrade.js +33 -1
  26. package/dist/internal/direct-mcp-v2/claude-direct-mcp.d.ts +2 -1
  27. package/dist/internal/direct-mcp-v2/claude-direct-mcp.js +35 -17
  28. package/dist/internal/direct-mcp-v2/claude-profile.d.ts +33 -7
  29. package/dist/internal/direct-mcp-v2/claude-profile.js +104 -72
  30. package/dist/internal/direct-mcp-v2/public-scenario-runtime.js +13 -16
  31. package/dist/pathgrade.js +10 -2
  32. package/dist/reporters/cli.js +13 -6
  33. package/dist/reporters/github-comment.js +12 -9
  34. package/dist/reporters/loader.d.ts +1 -0
  35. package/dist/reporters/loader.js +27 -2
  36. package/dist/reporters/report-summary.js +13 -5
  37. package/dist/reporting/core.d.ts +1 -0
  38. package/dist/reporting/core.js +183 -105
  39. package/dist/reporting/types.d.ts +19 -3
  40. package/dist/runners/adapter-loader.js +17 -12
  41. package/dist/runners/direct-reporter-attempts.d.ts +1 -0
  42. package/dist/runners/direct-reporter-attempts.js +7 -0
  43. package/dist/runners/invocation.d.ts +2 -0
  44. package/dist/runners/model-builders.js +1 -0
  45. package/dist/runners/model-validation.js +31 -0
  46. package/dist/runners/model.d.ts +4 -0
  47. package/dist/runners/orchestrator.d.ts +2 -0
  48. package/dist/runners/orchestrator.js +11 -1
  49. package/dist/runners/repeated-attempts.d.ts +7 -0
  50. package/dist/runners/repeated-attempts.js +149 -0
  51. package/dist/runners/repeated-invocation.d.ts +7 -0
  52. package/dist/runners/repeated-invocation.js +129 -0
  53. package/dist/runners/report-projection.js +16 -6
  54. package/dist/runners/vitest-adapter.js +10 -0
  55. package/dist/runners/vitest-invocation.js +2 -0
  56. package/dist/sdk/agent-runtime-options.d.ts +12 -0
  57. package/dist/sdk/agent-runtime-options.js +67 -0
  58. package/dist/sdk/agent.js +4 -57
  59. package/dist/sdk/case-context.js +7 -2
  60. package/dist/sdk/lifecycle.js +8 -3
  61. package/dist/sdk/result-capture.js +4 -1
  62. package/dist/types.d.ts +34 -5
  63. package/dist/viewer.html +19 -19
  64. package/package.json +2 -2
package/dist/types.d.ts CHANGED
@@ -150,6 +150,14 @@ export interface LogEntry {
150
150
  }
151
151
  export interface TrialResult {
152
152
  trial_id: number;
153
+ /** Stable semantic case identity in schema-v2 reports. */
154
+ case_id?: string;
155
+ /** Unique identity for one runner-owned execution of the case. */
156
+ attempt_id?: string;
157
+ /** One-based invocation index. */
158
+ attempt_index?: number;
159
+ /** Display-safe runner outcome for this specific attempt. */
160
+ runner_outcome?: import('./runners/model.js').AttemptOutcome['kind'];
153
161
  name?: string;
154
162
  reward?: number;
155
163
  scorer_results: ScorerResult[];
@@ -192,9 +200,22 @@ export interface TrialResult {
192
200
  }
193
201
  export interface EvalReport {
194
202
  task: string;
195
- pass_rate: number;
196
- pass_at_k: number;
197
- pass_pow_k: number;
203
+ /** Canonical status for this report or consolidated group when available. */
204
+ status?: 'pass' | 'fail';
205
+ /** Schema-v2 canonical average score. */
206
+ mean_reward?: number;
207
+ /** Binary success frequency, absent when attempts are ineligible. */
208
+ success_rate?: number;
209
+ /** Finite-sample pass@k values keyed by k in schema v2; number only for v1 reads. */
210
+ pass_at_k?: Record<string, number> | number;
211
+ pass_at_k_method?: 'finite_sample_unbiased';
212
+ pass_at_k_unavailable_reason?: PassAtKUnavailableReason;
213
+ eligible_case_count?: number;
214
+ attempts_per_case?: number;
215
+ /** @deprecated Version-1 artifact compatibility only. */
216
+ pass_rate?: number;
217
+ /** @deprecated Version-1 artifact compatibility only. New writers omit it. */
218
+ pass_pow_k?: number;
198
219
  trials: TrialResult[];
199
220
  skills_used: string[];
200
221
  }
@@ -208,7 +229,8 @@ export type StrippedTrialResult = Omit<TrialResult, 'session_log' | 'conversatio
208
229
  /**
209
230
  * Per-group entry in the consolidated `.pathgrade/results.json` report.
210
231
  */
211
- export type PathgradeGroupReport = Omit<EvalReport, 'trials'> & {
232
+ export type PathgradeGroupReport = Omit<EvalReport, 'trials' | 'status'> & {
233
+ status?: 'pass' | 'fail';
212
234
  trials: StrippedTrialResult[];
213
235
  /** Relative path from `.pathgrade/` to the trace file for this group. */
214
236
  trace_file: string;
@@ -239,12 +261,16 @@ export interface PathgradeSelectionReport {
239
261
  * external consumers can gate on schema revisions.
240
262
  */
241
263
  export interface PathgradeReport {
242
- version: 1;
264
+ version: 1 | 2;
243
265
  timestamp: string;
244
266
  /** `ci.threshold` from Pathgrade config or legacy plugin config, if configured. */
245
267
  threshold?: number;
246
268
  /** Weighted average of every individual trial score across all groups. */
247
269
  overall_pass_rate: number;
270
+ /** Canonical schema-v2 average reward. */
271
+ overall_mean_reward?: number;
272
+ attempts_requested?: number;
273
+ attempts_completed?: number;
248
274
  /**
249
275
  * Threshold check result. When `threshold` is set: `'pass'` iff
250
276
  * `overall_pass_rate >= threshold`. Otherwise: `'pass'` iff every trial
@@ -259,6 +285,7 @@ export interface PathgradeReport {
259
285
  */
260
286
  selection?: PathgradeSelectionReport;
261
287
  }
288
+ export type PassAtKUnavailableReason = 'non_binary_reward' | 'incomplete_attempts' | 'case_identity_mismatch';
262
289
  export interface TrialPaths {
263
290
  root: string;
264
291
  workspace: string;
@@ -396,6 +423,8 @@ export interface AgentSessionOptions {
396
423
  scriptedMcpHost?: import('./providers/scripted-mcp-mock-host.js').ScriptedMcpMockHost;
397
424
  /** Parent-owned public ScenarioMachineV2 bridge; never serialized into child config. */
398
425
  scenarioMcpServers?: Record<string, import('@anthropic-ai/claude-agent-sdk').McpSdkServerConfigWithInstance>;
426
+ /** RuntimeLock-admitted Claude executable; wins over developer overrides for ScenarioMachineV2 sessions. */
427
+ admittedClaudeCodeExecutable?: string;
399
428
  /** Parent-owned admitted Codex app-server mount; projected only into thread/start memory. */
400
429
  codexScenarioMount?: import('./agents/codex-app-server/scenario-mount.js').CodexScenarioMount;
401
430
  /** Runtime-only values inherited by drivers and persistence sinks for redaction. */
package/dist/viewer.html CHANGED
@@ -838,12 +838,13 @@
838
838
  applyTheme(getTheme());
839
839
 
840
840
  // ─── State ─────────────────────────────────────────────────
841
- let reports = [];
842
- let sortKey = 'date';
843
- let sortDir = 'desc';
841
+ let reports = [], sortKey = 'date', sortDir = 'desc';
844
842
  const $ = id => document.getElementById(id);
845
843
  const esc = s => s ? String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;') : '';
846
-
844
+ const meanReward = r => r.mean_reward ?? r.pass_rate ?? 0;
845
+ const reportStatus = r => r.status === 'pass' || r.status === 'fail' ? r.status : (meanReward(r) >= 0.5 ? 'pass' : 'fail');
846
+ const passAtKSortValue = r => typeof r.pass_at_k === 'number' ? r.pass_at_k : (r.pass_at_k ? Math.max(...Object.values(r.pass_at_k)) : -1);
847
+ const passAtKDisplay = r => typeof r.pass_at_k === 'number' ? (r.pass_at_k * 100).toFixed(0) + '% v1' : r.pass_at_k ? Object.entries(r.pass_at_k).map(([k, value]) => '@' + k + ' ' + (value * 100).toFixed(0) + '%').join(' · ') : r.pass_at_k_unavailable_reason ? '— ' + r.pass_at_k_unavailable_reason.replaceAll('_', ' ') : '—';
847
848
  function parseDate(file) {
848
849
  // filename format: 2026-04-08T14-25-03-134Z → 2026-04-08T14:25:03.134
849
850
  const m = file.match(/(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d+)/);
@@ -877,10 +878,10 @@
877
878
  switch (sortKey) {
878
879
  case 'task': va = (a.task || '').toLowerCase(); vb = (b.task || '').toLowerCase(); break;
879
880
  case 'date': va = parseDate(a.file); vb = parseDate(b.file); break;
880
- case 'pass_rate': va = a.pass_rate || 0; vb = b.pass_rate || 0; break;
881
- case 'pass_at_k': va = a.pass_at_k ?? -1; vb = b.pass_at_k ?? -1; break;
882
- case 'pass_pow_k': va = a.pass_pow_k ?? -1; vb = b.pass_pow_k ?? -1; break;
883
- case 'status': va = a.pass_rate >= 0.5 ? 1 : 0; vb = b.pass_rate >= 0.5 ? 1 : 0; break;
881
+ case 'mean_reward': va = meanReward(a); vb = meanReward(b); break;
882
+ case 'success_rate': va = a.success_rate ?? -1; vb = b.success_rate ?? -1; break;
883
+ case 'pass_at_k': va = passAtKSortValue(a); vb = passAtKSortValue(b); break;
884
+ case 'status': va = reportStatus(a) === 'pass' ? 1 : 0; vb = reportStatus(b) === 'pass' ? 1 : 0; break;
884
885
  default: return 0;
885
886
  }
886
887
  if (va < vb) return sortDir === 'asc' ? -1 : 1;
@@ -936,24 +937,23 @@
936
937
  const header = `<div class="reports-header">
937
938
  ${colHeader('task', 'Task')}
938
939
  ${colHeader('date', 'Date')}
939
- ${colHeader('pass_rate', 'Pass Rate', 'center')}
940
+ ${colHeader('mean_reward', 'Mean Reward', 'center')}
941
+ ${colHeader('success_rate', 'Success Rate', 'center')}
940
942
  ${colHeader('pass_at_k', 'pass@k', 'center')}
941
- ${colHeader('pass_pow_k', 'pass^k', 'center')}
942
943
  ${colHeader('status', 'Status', 'center')}
943
944
  <div></div>
944
945
  </div>`;
945
946
 
946
947
  const rows = sorted.map(r => {
947
- const pr = (r.pass_rate * 100).toFixed(0);
948
- const isPass = r.pass_rate >= 0.5;
948
+ const reward = (meanReward(r) * 100).toFixed(0), isPass = reportStatus(r) === 'pass';
949
949
  const ts = r.timestamp || parseDate(r.file);
950
950
 
951
951
  return `<a class="report-row" onclick="navigate('detail','${esc(r.file)}')" href="javascript:void(0)">
952
952
  <div class="report-task">${esc(r.task)}</div>
953
953
  <div class="report-date">${formatDate(ts)}</div>
954
- <div class="report-metric"><div class="val">${pr}%</div></div>
955
- <div class="report-metric"><div class="val">${r.pass_at_k != null ? (r.pass_at_k * 100).toFixed(0) + '%' : '—'}</div></div>
956
- <div class="report-metric"><div class="val">${r.pass_pow_k != null ? (r.pass_pow_k * 100).toFixed(0) + '%' : '—'}</div></div>
954
+ <div class="report-metric"><div class="val">${reward}%</div></div>
955
+ <div class="report-metric"><div class="val">${r.success_rate != null ? (r.success_rate * 100).toFixed(0) + '%' : '—'}</div></div>
956
+ <div class="report-metric"><div class="val">${esc(passAtKDisplay(r))}</div></div>
957
957
  <div style="text-align:center"><span class="badge ${isPass ? 'badge-pass' : 'badge-fail'}">${isPass ? 'PASS' : 'FAIL'}</span></div>
958
958
  <button class="delete-btn" onclick="event.preventDefault();event.stopPropagation();deleteReport('${esc(r.file)}')" title="Delete report">&#x2715;</button>
959
959
  </a>`;
@@ -975,9 +975,9 @@
975
975
  const totalTokens = r.trials.reduce((s, t) => s + (t.input_tokens || 0) + (t.output_tokens || 0) + (t.conversation_input_tokens || 0) + (t.conversation_output_tokens || 0), 0);
976
976
 
977
977
  const stats = `
978
- <div class="stat-pill"><div class="val">${(r.pass_rate * 100).toFixed(1)}%</div><div class="lbl">Pass Rate</div></div>
979
- <div class="stat-pill"><div class="val">${r.pass_at_k != null ? (r.pass_at_k * 100).toFixed(1) + '%' : '—'}</div><div class="lbl">pass@k</div></div>
980
- <div class="stat-pill"><div class="val">${r.pass_pow_k != null ? (r.pass_pow_k * 100).toFixed(1) + '%' : '—'}</div><div class="lbl">pass^k</div></div>
978
+ <div class="stat-pill"><div class="val">${(meanReward(r) * 100).toFixed(1)}%</div><div class="lbl">Mean Reward</div></div>
979
+ <div class="stat-pill"><div class="val">${r.success_rate != null ? (r.success_rate * 100).toFixed(1) + '%' : '—'}</div><div class="lbl">Success Rate</div></div>
980
+ <div class="stat-pill"><div class="val">${esc(passAtKDisplay(r))}</div><div class="lbl">pass@k</div></div>
981
981
  <div class="stat-pill"><div class="val">${(avgDur / 1000).toFixed(1)}s</div><div class="lbl">Avg Duration</div></div>
982
982
  <div class="stat-pill"><div class="val">~${totalTokens}</div><div class="lbl">Total Tokens</div></div>
983
983
  <div class="stat-pill"><div class="val">${r.skills_used?.join(', ') || 'none'}</div><div class="lbl">Skills</div></div>
@@ -999,7 +999,7 @@
999
999
  }
1000
1000
  function renderTrial(t, idx) {
1001
1001
  const evaluated = t.reward !== undefined;
1002
- const pass = evaluated && t.reward >= 0.5;
1002
+ const pass = evaluated && (t.runner_outcome === undefined ? t.reward >= 0.5 : t.runner_outcome === 'passed' && t.reward === 1);
1003
1003
  const dur = ((t.duration_ms || 0) / 1000).toFixed(1);
1004
1004
  const tokens = (t.input_tokens || 0) + (t.output_tokens || 0);
1005
1005
  const convTokens = (t.conversation_input_tokens || 0) + (t.conversation_output_tokens || 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/pathgrade",
3
- "version": "1.0.27",
3
+ "version": "1.0.29",
4
4
  "packageManager": "yarn@4.12.0",
5
5
  "description": "Evaluate whether AI agents discover and use your skills correctly",
6
6
  "exports": {
@@ -140,5 +140,5 @@
140
140
  "typescript": "^5.9.3",
141
141
  "zod": "4.3.6"
142
142
  },
143
- "falconPackageHash": "5c7c088ce2f8c51308dde9f92d3f259465bbf34021afddb3af39d2d9"
143
+ "falconPackageHash": "126198d020df14b3e6fceef3b0325ac5e84411c5e1b544a0167de604"
144
144
  }