@post-print/agent-test 0.1.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 (50) hide show
  1. package/README.md +25 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +194 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/discover-suites.d.ts +2 -0
  7. package/dist/discover-suites.d.ts.map +1 -0
  8. package/dist/discover-suites.js +19 -0
  9. package/dist/discover-suites.js.map +1 -0
  10. package/dist/expect.d.ts +35 -0
  11. package/dist/expect.d.ts.map +1 -0
  12. package/dist/expect.js +265 -0
  13. package/dist/expect.js.map +1 -0
  14. package/dist/index.d.ts +7 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +6 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/live-isolation.d.ts +19 -0
  19. package/dist/live-isolation.d.ts.map +1 -0
  20. package/dist/live-isolation.js +69 -0
  21. package/dist/live-isolation.js.map +1 -0
  22. package/dist/load-suite.d.ts +3 -0
  23. package/dist/load-suite.d.ts.map +1 -0
  24. package/dist/load-suite.js +29 -0
  25. package/dist/load-suite.js.map +1 -0
  26. package/dist/preflight.d.ts +3 -0
  27. package/dist/preflight.d.ts.map +1 -0
  28. package/dist/preflight.js +17 -0
  29. package/dist/preflight.js.map +1 -0
  30. package/dist/progress.d.ts +10 -0
  31. package/dist/progress.d.ts.map +1 -0
  32. package/dist/progress.js +39 -0
  33. package/dist/progress.js.map +1 -0
  34. package/dist/record-trace.d.ts +27 -0
  35. package/dist/record-trace.d.ts.map +1 -0
  36. package/dist/record-trace.js +97 -0
  37. package/dist/record-trace.js.map +1 -0
  38. package/dist/run-suite.d.ts +40 -0
  39. package/dist/run-suite.d.ts.map +1 -0
  40. package/dist/run-suite.js +344 -0
  41. package/dist/run-suite.js.map +1 -0
  42. package/dist/scenario-seed.d.ts +3 -0
  43. package/dist/scenario-seed.d.ts.map +1 -0
  44. package/dist/scenario-seed.js +38 -0
  45. package/dist/scenario-seed.js.map +1 -0
  46. package/dist/types.d.ts +65 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -0
  50. package/package.json +45 -0
@@ -0,0 +1,344 @@
1
+ import { basename, dirname, resolve } from "node:path";
2
+ import { captureWorkingTreeStatus, createScenarioWorktree, enrichTrace, findWorkingTreeLeak, formatWorkingTreeLeak, judgeTrace, loadContext, runAgent, } from "@post-print/agent-harness";
3
+ import { discoverSuites } from "./discover-suites";
4
+ import { assertRubric } from "./expect";
5
+ import { liveScenarioIsolationEnabled, spawnLiveScenario, subprocessFailureMessage, } from "./live-isolation";
6
+ import { loadSuiteFile } from "./load-suite";
7
+ import { formatDuration, logPhase, logProgress, withHeartbeat } from "./progress";
8
+ import { getStagingTracePath, loadStagingTrace, recordTrace, resolveRecordingPath, } from "./record-trace";
9
+ import { seedScenarioWorktree } from "./scenario-seed";
10
+ let activeWorktreeCleanup;
11
+ let liveSignalHandlersRegistered = false;
12
+ /** Best-effort worktree cleanup when live runs are interrupted (SIGINT/SIGTERM). */
13
+ export function registerLiveRunHandlers() {
14
+ if (liveSignalHandlersRegistered) {
15
+ return;
16
+ }
17
+ liveSignalHandlersRegistered = true;
18
+ const interrupt = (code) => {
19
+ const cleanup = activeWorktreeCleanup;
20
+ if (!cleanup) {
21
+ process.exit(code);
22
+ return;
23
+ }
24
+ void cleanup()
25
+ .catch(() => undefined)
26
+ .finally(() => process.exit(code));
27
+ };
28
+ process.on("SIGINT", () => interrupt(130));
29
+ process.on("SIGTERM", () => interrupt(143));
30
+ }
31
+ function releaseLiveMemory() {
32
+ const bunGc = globalThis.Bun?.gc;
33
+ if (typeof bunGc === "function") {
34
+ bunGc(true);
35
+ }
36
+ }
37
+ /** Live-only mode hint from rubric — not part of the user scenario prompt. */
38
+ function outputContractForRubric(rubric) {
39
+ if (rubric.routingBlock) {
40
+ return "hands-off";
41
+ }
42
+ return undefined;
43
+ }
44
+ function normalizeJudgeCriteria(judge) {
45
+ if (!judge?.length) {
46
+ return [];
47
+ }
48
+ return judge.map((item, index) => {
49
+ if (typeof item === "string") {
50
+ return { id: `judge-${index}`, question: item };
51
+ }
52
+ return { id: item.id ?? `judge-${index}`, question: item.question };
53
+ });
54
+ }
55
+ export async function runSuite(options) {
56
+ const suite = await loadSuiteFile(options.suitePath);
57
+ const defaultHost = options.host ?? suite.defaults?.host ?? "replay";
58
+ const results = [];
59
+ const scenarios = options.scenarioFilter
60
+ ? suite.scenarios.filter((scenario) => scenario.name === options.scenarioFilter)
61
+ : suite.scenarios;
62
+ if (options.scenarioFilter && scenarios.length === 0) {
63
+ throw new Error(`Scenario not found: ${options.scenarioFilter}`);
64
+ }
65
+ const total = scenarios.length;
66
+ const isLiveSuite = defaultHost !== "replay";
67
+ const isolateLive = isLiveSuite && liveScenarioIsolationEnabled() && !options.scenarioFilter && total > 1;
68
+ logProgress(`\n${suite.name} (${defaultHost}) — ${total} scenario(s)`);
69
+ if (isolateLive && total > 1) {
70
+ logPhase("live isolation: one subprocess per scenario (AGENT_TEST_NO_ISOLATE=1 to disable)");
71
+ }
72
+ for (let index = 0; index < scenarios.length; index++) {
73
+ const scenario = scenarios[index];
74
+ if (!scenario) {
75
+ continue;
76
+ }
77
+ if (isolateLive) {
78
+ const started = performance.now();
79
+ const exitCode = await spawnLiveScenario({
80
+ cwd: options.cwd,
81
+ suiteName: suite.name,
82
+ scenarioName: scenario.name,
83
+ suitesDir: options.suitesDir ?? "agent-suites",
84
+ suiteFilter: options.suiteFilter ?? suite.name,
85
+ stagingSessionId: options.stagingSessionId,
86
+ keepRecordings: options.keepRecordings,
87
+ recordFixtures: options.recordFixtures,
88
+ worktree: options.worktree,
89
+ judge: options.judge,
90
+ });
91
+ const durationMs = Math.round(performance.now() - started);
92
+ const failures = [];
93
+ if (exitCode !== 0) {
94
+ failures.push({
95
+ matcher: "liveScenario",
96
+ message: subprocessFailureMessage(exitCode),
97
+ });
98
+ }
99
+ else if (options.judge !== false && options.stagingSessionId) {
100
+ const criteria = normalizeJudgeCriteria(scenario.rubric.judge);
101
+ if (criteria.length > 0) {
102
+ releaseLiveMemory();
103
+ logPhase(`LLM judge (${criteria.length} criterion/criteria)…`);
104
+ try {
105
+ const tracePath = getStagingTracePath(options.stagingSessionId, suite.name, scenario.name);
106
+ const trace = await loadStagingTrace(tracePath);
107
+ const judged = await runJudgeRubric(trace, scenario.rubric, options.cwd);
108
+ failures.push(...judged.failures);
109
+ }
110
+ catch (error) {
111
+ failures.push({
112
+ matcher: "judge",
113
+ message: error instanceof Error ? error.message : "failed to load staging trace for judge",
114
+ });
115
+ }
116
+ }
117
+ }
118
+ const passed = failures.length === 0;
119
+ const icon = passed ? "✓" : "✗";
120
+ logProgress(`${icon} [${index + 1}/${total}] ${scenario.name} (${formatDuration(durationMs)})`);
121
+ results.push({
122
+ suite: suite.name,
123
+ scenario: scenario.name,
124
+ passed,
125
+ failures,
126
+ durationMs,
127
+ });
128
+ releaseLiveMemory();
129
+ continue;
130
+ }
131
+ results.push(await runScenario(options.cwd, suite.name, scenario, defaultHost, suite.defaults?.profile, suite.defaults?.skills, options.record, options.recordFixtures, options.judge, options.worktree, options.stagingSessionId, index + 1, total));
132
+ if (isLiveSuite) {
133
+ releaseLiveMemory();
134
+ }
135
+ }
136
+ return {
137
+ suite: suite.name,
138
+ host: defaultHost,
139
+ passed: results.filter((r) => r.passed).length,
140
+ skipped: results.filter((r) => r.skipped).length,
141
+ failed: results.filter((r) => !r.passed && !r.skipped).length,
142
+ results,
143
+ };
144
+ }
145
+ async function runScenario(cwd, suiteName, scenario, defaultHost, defaultProfile, defaultSkills, record, recordFixtures, judge, worktree, stagingSessionId, scenarioIndex, scenarioTotal) {
146
+ const started = performance.now();
147
+ const label = scenarioIndex !== undefined && scenarioTotal !== undefined
148
+ ? `[${scenarioIndex}/${scenarioTotal}] ${scenario.name}`
149
+ : scenario.name;
150
+ if (scenario.skip) {
151
+ logProgress(`${label} — skipped`);
152
+ return {
153
+ suite: suiteName,
154
+ scenario: scenario.name,
155
+ passed: true,
156
+ failures: [],
157
+ skipped: true,
158
+ durationMs: 0,
159
+ };
160
+ }
161
+ const host = scenario.host ?? defaultHost;
162
+ const profile = scenario.profile ?? defaultProfile ?? (host === "cursor" ? "cursor" : "shared");
163
+ const skills = scenario.skills ?? defaultSkills;
164
+ const isLive = host !== "replay";
165
+ logProgress(`${label} — ${host}`);
166
+ const useWorktree = isLive && worktree !== false && !process.env.AGENT_TEST_NO_WORKTREE;
167
+ let worktreeHandle;
168
+ const callerTreeBefore = useWorktree ? await captureWorkingTreeStatus(cwd) : undefined;
169
+ if (useWorktree) {
170
+ logPhase("creating git worktree…");
171
+ worktreeHandle = await createScenarioWorktree(cwd, `${suiteName}-${scenario.name}`);
172
+ activeWorktreeCleanup = worktreeHandle.cleanup;
173
+ logPhase(`worktree → ${worktreeHandle.path}`);
174
+ if (isLive && scenario.seedPatch) {
175
+ logPhase(`seeding worktree diff (${scenario.seedPatch})…`);
176
+ await seedScenarioWorktree(cwd, worktreeHandle.path, scenario.seedPatch);
177
+ }
178
+ }
179
+ else if (isLive) {
180
+ logPhase("worktree disabled — agent may mutate repo cwd (AGENT_TEST_ALLOW_IN_PLACE=1)");
181
+ }
182
+ const runCwd = worktreeHandle?.path ?? cwd;
183
+ try {
184
+ logPhase("loading agent context…");
185
+ // Live worktree runs code in an isolated checkout; load rules/AGENTS from caller cwd
186
+ // so uncommitted .cursor/rules and AGENTS.md edits apply during dogfood.
187
+ const contextRoot = isLive && useWorktree ? cwd : runCwd;
188
+ const context = await loadContext({ cwd: contextRoot, profile, skills });
189
+ const useReplay = host === "replay";
190
+ if (useReplay) {
191
+ logPhase(`replaying ${scenario.replayTrace ?? "trace"}…`);
192
+ }
193
+ else {
194
+ logPhase("running cursor agent (may take several minutes)…");
195
+ }
196
+ const outputContract = isLive ? outputContractForRubric(scenario.rubric) : undefined;
197
+ const agentStarted = performance.now();
198
+ const session = await (isLive
199
+ ? withHeartbeat(runAgent({
200
+ host,
201
+ cwd: runCwd,
202
+ context,
203
+ profile,
204
+ prompt: scenario.prompt,
205
+ outputContract,
206
+ }), { label: "agent still running", started: agentStarted })
207
+ : runAgent({
208
+ host,
209
+ cwd: runCwd,
210
+ context,
211
+ profile,
212
+ prompt: scenario.prompt,
213
+ replayTracePath: useReplay ? scenario.replayTrace : undefined,
214
+ }));
215
+ if (isLive) {
216
+ logPhase(`agent finished (${formatDuration(performance.now() - agentStarted)}) — ${session.status}`);
217
+ }
218
+ let trace = enrichTrace(session.trace);
219
+ const failures = [];
220
+ if (session.status !== "completed") {
221
+ failures.push({
222
+ matcher: "runAgent",
223
+ message: session.error ?? `agent session ${session.status}`,
224
+ });
225
+ }
226
+ logPhase("scoring rubric…");
227
+ failures.push(...assertRubric(trace, scenario.rubric, { skillsMode: context.skillsMode }));
228
+ if (useWorktree && callerTreeBefore !== undefined) {
229
+ const callerTreeAfter = await captureWorkingTreeStatus(cwd);
230
+ const leaked = findWorkingTreeLeak(callerTreeBefore, callerTreeAfter);
231
+ if (leaked.length > 0) {
232
+ failures.push({
233
+ matcher: "workingTreeLeak",
234
+ message: `live agent mutated caller working tree (use worktree isolation):\n${formatWorkingTreeLeak(leaked)}`,
235
+ });
236
+ }
237
+ }
238
+ if (record && isLive) {
239
+ const resolved = resolveRecordingPath(suiteName, scenario.name, scenario.replayTrace, recordFixtures === true, { repoRoot: cwd, stagingSessionId });
240
+ if (resolved) {
241
+ logPhase("recording trace…");
242
+ try {
243
+ const path = await recordTrace(resolved.path, trace);
244
+ const recordLabel = resolved.kind === "fixture" ? "recorded fixture" : "recorded staging";
245
+ logPhase(`${recordLabel} → ${path}`);
246
+ }
247
+ catch (error) {
248
+ failures.push({
249
+ matcher: "recordTrace",
250
+ message: error instanceof Error ? error.message : "failed to record trace",
251
+ });
252
+ }
253
+ }
254
+ }
255
+ const deferJudgeToParent = process.env.AGENT_TEST_CHILD === "1";
256
+ if (judge && isLive && !deferJudgeToParent) {
257
+ const criteria = normalizeJudgeCriteria(scenario.rubric.judge);
258
+ if (criteria.length > 0) {
259
+ logPhase(`LLM judge (${criteria.length} criterion/criteria)…`);
260
+ }
261
+ const judged = await runJudgeRubric(trace, scenario.rubric, runCwd);
262
+ failures.push(...judged.failures);
263
+ trace = judged.trace;
264
+ }
265
+ const durationMs = Math.round(performance.now() - started);
266
+ const icon = failures.length === 0 ? "✓" : "✗";
267
+ logProgress(`${icon} ${label} (${formatDuration(durationMs)})`);
268
+ return {
269
+ suite: suiteName,
270
+ scenario: scenario.name,
271
+ passed: failures.length === 0,
272
+ failures,
273
+ durationMs,
274
+ };
275
+ }
276
+ finally {
277
+ if (worktreeHandle) {
278
+ logPhase("removing worktree…");
279
+ }
280
+ await worktreeHandle?.cleanup();
281
+ if (activeWorktreeCleanup === worktreeHandle?.cleanup) {
282
+ activeWorktreeCleanup = undefined;
283
+ }
284
+ }
285
+ }
286
+ async function runJudgeRubric(trace, rubric, runCwd) {
287
+ const criteria = normalizeJudgeCriteria(rubric.judge);
288
+ if (criteria.length === 0) {
289
+ return { trace, failures: [] };
290
+ }
291
+ const result = await judgeTrace(trace, criteria, { cwd: runCwd });
292
+ if (result.skipped) {
293
+ return {
294
+ trace,
295
+ failures: [{ matcher: "judge", message: result.error ?? "judge skipped" }],
296
+ };
297
+ }
298
+ const judgedTrace = { ...trace, judgeVerdicts: result.verdicts };
299
+ const failures = [];
300
+ for (const verdict of result.verdicts) {
301
+ if (!verdict.pass) {
302
+ failures.push({
303
+ matcher: `judge:${verdict.id}`,
304
+ message: verdict.rationale,
305
+ });
306
+ }
307
+ }
308
+ if (result.error) {
309
+ failures.push({ matcher: "judge", message: result.error });
310
+ }
311
+ return { trace: judgedTrace, failures };
312
+ }
313
+ function suiteNameFromPath(suitePath) {
314
+ return basename(dirname(suitePath));
315
+ }
316
+ export async function runAllSuites(options) {
317
+ const suitePaths = await discoverSuites(resolve(options.cwd, options.suitesDir));
318
+ const filtered = options.filter
319
+ ? suitePaths.filter((suitePath) => {
320
+ const suiteName = suiteNameFromPath(suitePath);
321
+ return suiteName === options.filter || suitePath.includes(`/${options.filter}/`);
322
+ })
323
+ : suitePaths;
324
+ const reports = [];
325
+ for (const suitePath of filtered) {
326
+ reports.push(await runSuite({
327
+ cwd: options.cwd,
328
+ suitePath,
329
+ host: options.host,
330
+ scenarioFilter: options.scenarioFilter,
331
+ record: options.record,
332
+ recordFixtures: options.recordFixtures,
333
+ judge: options.judge,
334
+ worktree: options.worktree,
335
+ stagingSessionId: options.stagingSessionId,
336
+ keepRecordings: options.keepRecordings,
337
+ suitesDir: options.suitesDir,
338
+ suiteFilter: options.filter,
339
+ }));
340
+ }
341
+ return reports;
342
+ }
343
+ export { discoverSuites } from "./discover-suites";
344
+ //# sourceMappingURL=run-suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-suite.js","sourceRoot":"","sources":["../src/run-suite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Apply optional patch and commit so pr-mode `git diff main...HEAD` has scope. */
2
+ export declare function seedScenarioWorktree(repoRoot: string, worktreePath: string, seedPatch: string | undefined): Promise<void>;
3
+ //# sourceMappingURL=scenario-seed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-seed.d.ts","sourceRoot":"","sources":["../src/scenario-seed.ts"],"names":[],"mappings":"AASA,mFAAmF;AACnF,wBAAsB,oBAAoB,CACzC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAAC,IAAI,CAAC,CAkCf"}
@@ -0,0 +1,38 @@
1
+ import { execFile } from "node:child_process";
2
+ import { access } from "node:fs/promises";
3
+ import { resolve } from "node:path";
4
+ import { promisify } from "node:util";
5
+ const execFileAsync = promisify(execFile);
6
+ const SEED_COMMIT_MESSAGE = "agent-test: seed scenario diff (ephemeral worktree only)";
7
+ /** Apply optional patch and commit so pr-mode `git diff main...HEAD` has scope. */
8
+ export async function seedScenarioWorktree(repoRoot, worktreePath, seedPatch) {
9
+ if (!seedPatch) {
10
+ return;
11
+ }
12
+ const patchPath = resolve(repoRoot, seedPatch);
13
+ try {
14
+ await access(patchPath);
15
+ }
16
+ catch {
17
+ throw new Error(`seedPatch not found: ${seedPatch}`);
18
+ }
19
+ await execFileAsync("git", ["apply", "--whitespace=nowarn", patchPath], { cwd: worktreePath });
20
+ await execFileAsync("git", ["add", "-A"], { cwd: worktreePath });
21
+ const { stdout: status } = await execFileAsync("git", ["status", "--porcelain"], {
22
+ cwd: worktreePath,
23
+ });
24
+ if (!status.trim()) {
25
+ throw new Error(`seedPatch applied no changes: ${seedPatch}`);
26
+ }
27
+ await execFileAsync("git", [
28
+ "-c",
29
+ "user.email=agent-test@agent-spec.local",
30
+ "-c",
31
+ "user.name=agent-test",
32
+ "commit",
33
+ "--no-verify",
34
+ "-m",
35
+ SEED_COMMIT_MESSAGE,
36
+ ], { cwd: worktreePath });
37
+ }
38
+ //# sourceMappingURL=scenario-seed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-seed.js","sourceRoot":"","sources":["../src/scenario-seed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,mBAAmB,GAAG,0DAA0D,CAAC;AAEvF,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACzC,QAAgB,EAChB,YAAoB,EACpB,SAA6B;IAE7B,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,OAAO;IACR,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC/C,IAAI,CAAC;QACJ,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,wBAAwB,SAAS,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,qBAAqB,EAAE,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;IAC/F,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;IACjE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE;QAChF,GAAG,EAAE,YAAY;KACjB,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,iCAAiC,SAAS,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,aAAa,CAClB,KAAK,EACL;QACC,IAAI;QACJ,wCAAwC;QACxC,IAAI;QACJ,sBAAsB;QACtB,QAAQ;QACR,aAAa;QACb,IAAI;QACJ,mBAAmB;KACnB,EACD,EAAE,GAAG,EAAE,YAAY,EAAE,CACrB,CAAC;AACH,CAAC"}
@@ -0,0 +1,65 @@
1
+ import type { AgentHost, ContextProfile, SkillContextSetting } from "@post-print/agent-harness";
2
+ export type JudgeRubricItem = string | {
3
+ id?: string;
4
+ question: string;
5
+ };
6
+ export interface ScenarioRubric {
7
+ tier?: "low" | "medium" | "high";
8
+ /** Chat-style tier announce — infer one-line routing from transcript when routing.tier absent. */
9
+ handsOnRouting?: boolean;
10
+ must?: string[];
11
+ mustNot?: string[];
12
+ mustRun?: string[];
13
+ /** Skill folder names the agent must read via SKILL.md (e.g. grill, crystallize). */
14
+ mustInvokeSkill?: string[];
15
+ mustNotInvokeSkill?: string[];
16
+ routingBlock?: boolean;
17
+ reviewDepth?: "quick" | "standard" | "thorough" | "full";
18
+ /** Fuzzy criteria — harness LLM judge on live runs only. */
19
+ judge?: JudgeRubricItem[];
20
+ }
21
+ export interface AgentScenario {
22
+ name: string;
23
+ prompt: string;
24
+ host?: AgentHost;
25
+ profile?: ContextProfile;
26
+ /** Override suite defaults for skill catalog loading. */
27
+ skills?: SkillContextSetting;
28
+ /** Live-only: apply patch + commit in worktree so pr-mode branch diff exists. */
29
+ seedPatch?: string;
30
+ replayTrace?: string;
31
+ rubric: ScenarioRubric;
32
+ skip?: boolean;
33
+ }
34
+ export interface AgentSuiteFile {
35
+ name: string;
36
+ description?: string;
37
+ defaults?: {
38
+ host?: AgentHost;
39
+ profile?: ContextProfile;
40
+ /** none | catalog | full — ambient-routing uses full for IDE parity. */
41
+ skills?: SkillContextSetting;
42
+ };
43
+ scenarios: AgentScenario[];
44
+ }
45
+ export interface AssertionFailure {
46
+ matcher: string;
47
+ message: string;
48
+ }
49
+ export interface ScenarioResult {
50
+ suite: string;
51
+ scenario: string;
52
+ passed: boolean;
53
+ failures: AssertionFailure[];
54
+ skipped?: boolean;
55
+ durationMs: number;
56
+ }
57
+ export interface SuiteRunReport {
58
+ suite: string;
59
+ host: AgentHost;
60
+ passed: number;
61
+ failed: number;
62
+ skipped: number;
63
+ results: ScenarioResult[];
64
+ }
65
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhG,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,MAAM,WAAW,cAAc;IAC9B,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjC,kGAAkG;IAClG,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,qFAAqF;IACrF,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;IACzD,4DAA4D;IAC5D,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,yDAAyD;IACzD,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,SAAS,CAAC;QACjB,OAAO,CAAC,EAAE,cAAc,CAAC;QACzB,wEAAwE;QACxE,MAAM,CAAC,EAAE,mBAAmB,CAAC;KAC7B,CAAC;IACF,SAAS,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC1B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@post-print/agent-test",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "agent-test": "./dist/cli.js"
7
+ },
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "bunx tsc --build",
19
+ "typecheck": "bunx tsc --build",
20
+ "lint": "bunx biome check .",
21
+ "lint:fix": "bunx biome check . --write",
22
+ "test": "vitest run",
23
+ "clean": "rm -rf dist tsconfig.tsbuildinfo"
24
+ },
25
+ "dependencies": {
26
+ "@post-print/agent-harness": "file:../harness"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^22.10.0",
30
+ "typescript": "~6.0.2",
31
+ "vitest": "^4.0.17"
32
+ },
33
+ "description": "Scenario runner and CLI for agent-spec suites",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/post-print/agent-spec.git",
37
+ "directory": "packages/test"
38
+ },
39
+ "license": "MIT",
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "main": "./dist/index.js",
44
+ "types": "./dist/index.d.ts"
45
+ }