@post-print/agent-test 0.3.3 → 0.3.5

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 (106) hide show
  1. package/README.md +126 -157
  2. package/dist/check.d.ts +38 -0
  3. package/dist/check.d.ts.map +1 -0
  4. package/dist/check.js +169 -0
  5. package/dist/check.js.map +1 -0
  6. package/dist/cli.d.ts +12 -14
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +342 -366
  9. package/dist/cli.js.map +1 -1
  10. package/dist/compare-scenario.d.ts +33 -0
  11. package/dist/compare-scenario.d.ts.map +1 -0
  12. package/dist/compare-scenario.js +128 -0
  13. package/dist/compare-scenario.js.map +1 -0
  14. package/dist/debug-bundle.d.ts +2 -2
  15. package/dist/debug-bundle.d.ts.map +1 -1
  16. package/dist/debug-bundle.js +12 -12
  17. package/dist/debug-bundle.js.map +1 -1
  18. package/dist/doctor.d.ts +6 -1
  19. package/dist/doctor.d.ts.map +1 -1
  20. package/dist/doctor.js +136 -14
  21. package/dist/doctor.js.map +1 -1
  22. package/dist/expect.d.ts +6 -5
  23. package/dist/expect.d.ts.map +1 -1
  24. package/dist/expect.js +67 -57
  25. package/dist/expect.js.map +1 -1
  26. package/dist/host-log.d.ts +17 -0
  27. package/dist/host-log.d.ts.map +1 -0
  28. package/dist/host-log.js +154 -0
  29. package/dist/host-log.js.map +1 -0
  30. package/dist/hosts.d.ts +22 -0
  31. package/dist/hosts.d.ts.map +1 -0
  32. package/dist/hosts.js +84 -0
  33. package/dist/hosts.js.map +1 -0
  34. package/dist/html-report.d.ts +0 -13
  35. package/dist/html-report.d.ts.map +1 -1
  36. package/dist/html-report.js +381 -318
  37. package/dist/html-report.js.map +1 -1
  38. package/dist/index.d.ts +15 -8
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +13 -7
  41. package/dist/index.js.map +1 -1
  42. package/dist/live-isolation.d.ts +11 -5
  43. package/dist/live-isolation.d.ts.map +1 -1
  44. package/dist/live-isolation.js +32 -14
  45. package/dist/live-isolation.js.map +1 -1
  46. package/dist/load-adapters.d.ts +13 -0
  47. package/dist/load-adapters.d.ts.map +1 -0
  48. package/dist/load-adapters.js +76 -0
  49. package/dist/load-adapters.js.map +1 -0
  50. package/dist/load-suite.d.ts.map +1 -1
  51. package/dist/load-suite.js +16 -0
  52. package/dist/load-suite.js.map +1 -1
  53. package/dist/mcp-config.d.ts +8 -0
  54. package/dist/mcp-config.d.ts.map +1 -1
  55. package/dist/mcp-config.js +46 -0
  56. package/dist/mcp-config.js.map +1 -1
  57. package/dist/preflight.d.ts +2 -2
  58. package/dist/preflight.d.ts.map +1 -1
  59. package/dist/preflight.js +4 -4
  60. package/dist/preflight.js.map +1 -1
  61. package/dist/progress.d.ts +7 -0
  62. package/dist/progress.d.ts.map +1 -1
  63. package/dist/progress.js +39 -9
  64. package/dist/progress.js.map +1 -1
  65. package/dist/record-trace.d.ts +11 -20
  66. package/dist/record-trace.d.ts.map +1 -1
  67. package/dist/record-trace.js +10 -57
  68. package/dist/record-trace.js.map +1 -1
  69. package/dist/report-preview-server.d.ts +2 -0
  70. package/dist/report-preview-server.d.ts.map +1 -0
  71. package/dist/report-preview-server.js +24 -0
  72. package/dist/report-preview-server.js.map +1 -0
  73. package/dist/report-preview.d.ts +11 -0
  74. package/dist/report-preview.d.ts.map +1 -0
  75. package/dist/report-preview.js +161 -0
  76. package/dist/report-preview.js.map +1 -0
  77. package/dist/run-suite.d.ts +62 -11
  78. package/dist/run-suite.d.ts.map +1 -1
  79. package/dist/run-suite.js +697 -206
  80. package/dist/run-suite.js.map +1 -1
  81. package/dist/scenario-story.d.ts +41 -0
  82. package/dist/scenario-story.d.ts.map +1 -0
  83. package/dist/scenario-story.js +198 -0
  84. package/dist/scenario-story.js.map +1 -0
  85. package/dist/suite-summary.d.ts +2 -0
  86. package/dist/suite-summary.d.ts.map +1 -1
  87. package/dist/suite-summary.js +70 -22
  88. package/dist/suite-summary.js.map +1 -1
  89. package/dist/theme.d.ts +29 -5
  90. package/dist/theme.d.ts.map +1 -1
  91. package/dist/theme.js +204 -45
  92. package/dist/theme.js.map +1 -1
  93. package/dist/types.d.ts +107 -24
  94. package/dist/types.d.ts.map +1 -1
  95. package/dist/validate-seeds.d.ts.map +1 -1
  96. package/dist/validate-seeds.js +21 -6
  97. package/dist/validate-seeds.js.map +1 -1
  98. package/dist/validate-suite.d.ts +3 -1
  99. package/dist/validate-suite.d.ts.map +1 -1
  100. package/dist/validate-suite.js +256 -22
  101. package/dist/validate-suite.js.map +1 -1
  102. package/package.json +5 -5
  103. package/dist/compare.d.ts +0 -79
  104. package/dist/compare.d.ts.map +0 -1
  105. package/dist/compare.js +0 -232
  106. package/dist/compare.js.map +0 -1
package/README.md CHANGED
@@ -1,210 +1,179 @@
1
1
  # @post-print/agent-test
2
2
 
3
- **Source of truth for** agent-test package.
3
+ <!-- source-of-truth: the direct-agent test package -->
4
4
 
5
- <!-- doc-meta: owner=eng | last-reviewed=2026-07-29 -->
5
+ <!-- doc-meta: owner=eng | last-reviewed=2026-09-13 -->
6
6
 
7
- Jest-shaped agent scenario runner built on `@post-print/agent-harness`.
7
+ <!-- review-deps: paths=packages/test/src/*.ts,packages/test/src/**/*.ts,packages/test/package.json -->
8
8
 
9
- ## In-repo smoke (this monorepo)
9
+ Scenario runner for real Cursor, Claude, and OpenAI Codex agents, built on `@post-print/agent-harness`.
10
10
 
11
- After `bun run build` at the repo root:
11
+ > **Deprecated and removed:** stored-trace replay is not an agent test. `host: "replay"`, `replayTrace`, `--record-fixtures`, and the old `--live` mode flag are rejected with migration guidance.
12
12
 
13
- ```bash
14
- node packages/test/dist/cli.js --suites-dir packages/test/fixtures --suite smoke
15
- node packages/test/dist/cli.js --doctor
13
+ ## Direct TypeScript API
14
+
15
+ `runAgentTest` is the execution core. JSON suites load into this same function.
16
+
17
+ ```ts
18
+ import { runAgentTest } from "@post-print/agent-test";
19
+
20
+ const result = await runAgentTest({
21
+ cwd: process.cwd(),
22
+ scenario: {
23
+ name: "uses the project instructions",
24
+ prompt: "Review the current change.",
25
+ rubric: { mustReadPath: ["AGENTS.md"] },
26
+ },
27
+ });
16
28
  ```
17
29
 
18
- There is no top-level `agent-suites/` here consumer examples below assume a consuming repo. Live `--live` needs an **exported** `CURSOR_API_KEY` for Cursor (default). `--host claude` needs an explicit `CLAUDE_AUTH_MODE=api-key` (with `ANTHROPIC_API_KEY`) or `CLAUDE_AUTH_MODE=subscription` (the Claude Code CLI login); nothing is inferred (copy repo-root `.env.example`; the CLI does not auto-load `.env`). Judge classifiers still need `CURSOR_API_KEY` unless you pass `--no-judge`.
30
+ The default host is Cursor. Set `scenario.host`, `defaults.host`, or the top-level `host` option to `claude` or `openai`. The scenario host wins over the top-level override, which wins over suite defaults. The default suite name is `direct`. Sealed-workspace isolation, judging, timeout enforcement, and announce-stop retry are enabled by default.
19
31
 
20
- ## CLI (consumers, Node >= 22)
32
+ ## JSON suites and CLI
21
33
 
22
- Works under **Node >= 22** (the published `agent-test` bin):
34
+ JSON is an authoring adapter, not a stored answer. This repository keeps host-agent suites under `agent-suites/<suite>/scenarios.json`. Consumer repositories can use the same layout.
23
35
 
24
36
  ```bash
25
37
  npx agent-test --suites-dir agent-suites
26
- npx agent-test --suites-dir agent-suites --suite ambient-routing
27
- npx agent-test --suites-dir agent-suites --live --suite ambient-routing # exported CURSOR_API_KEY required
28
- npx agent-test --suites-dir agent-suites --live --host claude --suite ambient-routing # CLAUDE_AUTH_MODE + claude CLI
29
- npx agent-test --live --compare-pairs skeleton-clean:skeleton-messy --out-dir "$TMPDIR/compare"
30
- npx agent-test compare --a clean.suite-report.json --b messy.suite-report.json --out-dir "$TMPDIR/compare"
31
- npx agent-test --suites-dir agent-suites --report-out "$TMPDIR/agent-test-report" # dir: html + suite JSON
32
- npx agent-test --suites-dir agent-suites --report-out "$TMPDIR/reports/run.html" # file: html only
33
- npx agent-test --doctor
38
+ npx agent-test --suites-dir agent-suites --host cursor
39
+ npx agent-test --suites-dir agent-suites --suite smoke
40
+ npx agent-test --suites-dir agent-suites --suite tools
41
+ npx agent-test --suites-dir agent-suites --suite mcp
42
+ npx agent-test --suites-dir agent-suites --suite judge
43
+ npx agent-test --suites-dir agent-suites --suite depth
44
+ npx agent-test --check --suites-dir agent-suites
34
45
  ```
35
46
 
36
- ### Report output
47
+ In-repo suites list `hosts: ["cursor", "claude", "openai"]`. `npx agent-test --suites-dir agent-suites` and `bun run test` run every suite on each host. That is the consumer confidence gate. Pass `--host cursor` to pin one adapter.
37
48
 
38
- By default the HTML report goes to a fresh temp directory. `--report-out <path>` puts it where you want:
49
+ `smoke` is the short host proof. `tools` checks Read and Write. `mcp` checks echo invoke and a lookup read. `judge` starts a second host call that scores the reply. One judge scenario runs two workspace arms and scores both transcripts together. `depth` checks workspace roots, seed patches, injected context, mustRun, and skill invoke. `bun run test:smoke` stays on Cursor.
39
50
 
40
- | `--report-out` value | Result |
41
- | --- | --- |
42
- | ends with `.html` | the HTML report is written to exactly that file (parent dirs created) |
43
- | any other path | treated as a directory: `report.html` plus all other report content — per-suite `<suite>.suite-report.json`, and the compare JSON / markdown / HTML when `--compare-pairs` is used |
51
+ `scenario.host` pins that scenario to one host. A matrix run skips it on the other hosts.
44
52
 
45
- `--out-dir` still wins for compare output when both are given. `--no-html-report` skips the HTML report entirely.
53
+ ## Custom hosts
46
54
 
47
- Bun is fine for local package development (`bun install` / `bun run build` in this monorepo), but consumers do not need Bun to run suites.
55
+ A consumer repo can register its own adapter.
48
56
 
49
- Default suites root: `agent-suites/` (must exist, or pass `--suites-dir`). Absolute `--suites-dir` is supported. Optional `--rubrics-dir` loads harness-only answer keys from `<rubricsDir>/<suite>/rubrics.json` (preferred over a sibling file when present).
57
+ ```js
58
+ // agent-test.config.mjs
59
+ import { defineConfig } from "@post-print/agent-test";
50
60
 
51
- ### Harness-only rubrics
52
-
53
- `scenarios.json` may omit `rubric` (or use `{}`) and keep only prompts / `seedPatch` / `compareId`. Put `must` / `mustNot` / `judge` / tool matchers in:
54
-
55
- - sibling `rubrics.json` or `scenarios.rubric.json`: `{ "scenarios": { "<scenario name>": { "must": […] } } }`
56
- - or `--rubrics-dir <path>` `<path>/<suiteName>/rubrics.json`
61
+ export default defineConfig({
62
+ adapters: [
63
+ {
64
+ host: "gemini",
65
+ missingAuth() {
66
+ return process.env.GEMINI_API_KEY ? undefined : "GEMINI_API_KEY not set";
67
+ },
68
+ classifierHost: "cursor",
69
+ async run(options) {
70
+ return {
71
+ host: "gemini",
72
+ status: "completed",
73
+ durationMs: 0,
74
+ trace: {
75
+ messages: [{ role: "assistant", content: options.prompt }],
76
+ toolCalls: [],
77
+ shellCommands: [],
78
+ artifacts: {},
79
+ },
80
+ };
81
+ },
82
+ },
83
+ ],
84
+ });
85
+ ```
57
86
 
58
- External entries **replace** the inline rubric for that scenario name. Unknown names in the rubrics file are an error. Keep rubrics off agent-visible roots (absolute `--suites-dir` / `--rubrics-dir` under `$TMPDIR`, or outside the IDE-open workspace).
87
+ Then `--host gemini` and a suite `hosts` list can include `gemini`. You can also pass `--adapter ./hosts/gemini.mjs`. The module can export `{ adapters: [...] }` or call `registerHostAdapter` as a side effect.
59
88
 
60
- Live output always uses ANSI color (including under Cursor agent shells that set `NO_COLOR`).
89
+ Do not reuse `cursor`, `claude`, `openai`, `replay`, or `all` as the slug.
61
90
 
62
- ## Environment variables
91
+ Direct runs need host auth. Cursor uses `CURSOR_API_KEY`, or `CURSOR_AUTH_MODE=subscription` after `Cursor.auth.login()`. The Cursor app login does not count. Claude uses `CLAUDE_AUTH_MODE` plus `ANTHROPIC_API_KEY` or a Claude Code login. OpenAI uses `OPENAI_API_KEY` or `CODEX_API_KEY`, or `OPENAI_AUTH_MODE=subscription` after `codex login`. The judge uses the same host family. It runs when a rubric has judge questions or `mustInvokeSkill`. A `compare` scenario runs two arms. `compare.faster` and `compare.cheaper` pick a metric winner. `rubric.judge` is optional and scores both transcripts. `--no-judge` turns the judge off. The CLI does not load `.env`.
63
92
 
64
- See repo-root `.env.example`. Common knobs:
93
+ `--allow-user-input` starts a second classifier as the user. That user agent answers AskQuestion-style tools. The test agent then continues with the original task plus the transcript.
65
94
 
66
- | Variable | Purpose |
67
- | ------------------------------------------- | ------------------------------------------------------------- |
68
- | `CURSOR_API_KEY` | Required for `--live` Cursor and judge classifiers |
69
- | `CLAUDE_AUTH_MODE` | Required for `--live --host claude`: `api-key` or `subscription` (no default) |
70
- | `ANTHROPIC_API_KEY` | Required when `CLAUDE_AUTH_MODE=api-key` |
71
- | `CLAUDE_CODE_BIN` | Optional path to Claude Code CLI binary |
72
- | `CLAUDE_AGENT_MODEL` | Optional Claude model override |
73
- | `CLAUDE_CODE_ALLOWED_TOOLS` | Optional `--allowedTools` list for Claude live runs |
74
- | `AGENT_TEST_DEBUG` | Same as `--debug` when `1`/`true` |
75
- | `AGENT_TEST_VERBOSE` | Extra tips (e.g. OOM isolation) when `1` |
76
- | `AGENT_TEST_VERBOSE_PATHS` | Print full paths when `1` |
77
- | `AGENT_TEST_QUIET` | Suppress progress when `1` |
78
- | `AGENT_TEST_TIMEOUT_MS` | Live hard timeout (default 600000; `0` disables) |
79
- | `AGENT_TEST_LIVE_RETRIES` | Judge infra retry attempts (default 3) |
80
- | `AGENT_TEST_SCENARIO_RETRIES` | Live announce-stop scenario retries (default 1; `0` disables) |
81
- | `AGENT_TEST_ALLOW_IN_PLACE` | Allow `--no-worktree` live runs when `1` |
82
- | `AGENT_TEST_NO_WORKTREE` | Disable worktree isolation when `1`/`true` |
83
- | `AGENT_TEST_NO_ISOLATE` | Disable isolated subprocesses when `1` |
84
- | `AGENT_TEST_SCENARIO_SETTLE_MS` | Settle delay between live scenarios |
85
- | `CURSOR_AGENT_MODEL` / `CURSOR_JUDGE_MODEL` | Optional model overrides |
86
- | `CURSOR_JUDGE_TEMPERATURE` | Optional judge temperature |
95
+ ## Check, rubrics, and compare
87
96
 
88
- ## Debug mode
97
+ `--check` inspects the suite, seeds, package, and host. It does not launch an agent. A live run runs the same check first, then starts the host.
89
98
 
90
99
  ```bash
91
- npx agent-test --suites-dir agent-suites --suite smoke --debug
92
- npx agent-test --suites-dir agent-suites --live --debug
93
- npx agent-test --suites-dir agent-suites --live --debug --debug-dir "$TMPDIR/agent-test-debug"
100
+ npx agent-test --check --suites-dir agent-suites
94
101
  ```
95
102
 
96
- `--debug` (or `AGENT_TEST_DEBUG=1`) implies `--keep-recordings`, verbose failure detail, and full paths. Every non-skipped scenario writes a bundle under the session root:
103
+ A compare scenario sets `compare.a` and `compare.b`. Each arm can override workspace, prompt, host, skills, or extra rubric checks. Arm rubric arrays append onto the scenario rubric. Do not put `judge` on an arm. `compare.faster` and `compare.cheaper` name the arm that must win on time or tokens. Add `rubric.judge` when you want a pairwise judge. Omit it for a metric-only compare. `--no-judge` skips the judge.
97
104
 
105
+ ```json
106
+ {
107
+ "name": "cheaper prompt",
108
+ "prompt": "Read README.txt. Reply with one sentence.",
109
+ "compare": {
110
+ "a": { "label": "verbose", "prompt": "Read README.txt. Write a long summary." },
111
+ "b": { "label": "short" },
112
+ "cheaper": "b"
113
+ },
114
+ "rubric": { "mustReadPath": ["README.txt"] }
115
+ }
98
116
  ```
99
- sessions/<id>/<suite>/<scenario>.debug/
100
- summary.md # verdict + Why (category hint + evidence + trace stats)
101
- transcript.md # Why, prompt, rubric, interleaved messages/tools (incl. results), failures
102
- scenario.json # prompt + rubric + seed metadata
103
- result.json # pass/fail, duration, failures, usage, skillsInvoked, routing, counts
104
- trace.json
105
- failures.json # includes category + evidence
106
- judge-debug.json # when judge criteria ran (SDK status/error, sizes, attempt)
107
- environment.json # versions/models/timeout/isolation; API keys only as booleans
108
- rerun.sh # shell-quoted exact re-run command (export API keys yourself)
109
- ```
110
-
111
- **Debug dir default:** omit `--debug-dir` to stage under `$TMPDIR/agent-spec/sessions/<id>/…` (outside the repo). Passing an in-repo `--debug-dir` (for example `./agent-test-debug`) is supported — harness staging paths under that dir are excluded from worktree leak checks — but prefer `$TMPDIR` so debug artifacts never appear in `git status`.
112
-
113
- `--debug-dir <path>` replaces `$TMPDIR/agent-spec` as the sessions parent (`<path>/sessions/<id>/…`).
114
-
115
- Failure categories printed on FAIL lines and in `failures.json`:
116
-
117
- | Category | Meaning |
118
- | ----------------- | -------------------------------------------------------------------------------------- |
119
- | `rubric_miss` | Assertion/judge criterion miss |
120
- | `judge_infra` | Judge SDK/API failure (not a criterion miss) |
121
- | `agent_runtime` | Agent session error, timeout, AskQuestion, subprocess exit |
122
- | `worktree_leak` | Live agent mutated the caller working tree (harness `--debug-dir` staging is excluded) |
123
- | `recording_error` | Failed to persist a staging/fixture trace |
124
117
 
125
- **Cancel:** `Ctrl+C` (SIGINT) kills in-flight isolated scenario subprocesses and best-effort cancels the active Cursor SDK run, then cleans scenario worktrees.
118
+ Use two workspaces when one arm has a skill and the other does not. Put `mustInvokeSkill` on the skill arm only.
126
119
 
127
- ## Live dogfood
128
-
129
- Live runs need `CURSOR_API_KEY` and a suites directory that exists. Preflight fails when the resolved suites directory is missing (default `agent-suites/` if `--suites-dir` is omitted). `--suites-dir` may be relative to the repo cwd or an absolute path (for example a scrubbed suite tree under `$TMPDIR`).
130
-
131
- Passing live runs write staging traces under `$TMPDIR/agent-spec/sessions/<pid>-<timestamp>/` (removed on exit unless `--keep-recordings`). Use `--record-fixtures` to overwrite each scenario's committed `replayTrace` path. `--no-worktree` requires `AGENT_TEST_ALLOW_IN_PLACE=1`.
132
-
133
- ### Isolation model
120
+ ```json
121
+ {
122
+ "name": "skill vs no skill",
123
+ "prompt": "Read every markdown file. Write a detailed shipping plan.",
124
+ "compare": {
125
+ "a": {
126
+ "label": "no skill",
127
+ "workspace": "workspaces/skill-off",
128
+ "rubric": { "mustNotInvokeSkill": ["brief-ship"] }
129
+ },
130
+ "b": {
131
+ "label": "with skill",
132
+ "workspace": "workspaces/skill-on",
133
+ "skills": [".agents/skills/brief-ship/SKILL.md"],
134
+ "rubric": { "mustInvokeSkill": ["brief-ship"] }
135
+ },
136
+ "cheaper": "b"
137
+ },
138
+ "rubric": {
139
+ "mustReadPath": ["note.md"],
140
+ "judge": ["Did the skill arm stay closer to the note?"]
141
+ }
142
+ }
143
+ ```
134
144
 
135
- Live runs use a **detached git worktree** for agent file edits. That is not full filesystem isolation:
145
+ `--doctor`, `--validate-only`, `--validate-paths`, and `--validate-seeds` are aliases for `--check`.
136
146
 
137
- - **Worktree does:** keep seed/apply edits and agent Write/Edit tools off the caller's working tree (leak checks catch escapes).
138
- - **Worktree does not:** stop context (skills/rules) from loading from the caller checkout by design, or stop Cursor **local** agents from Shell/Read against the IDE-open workspace instead of only `local.cwd`.
147
+ `scenarios.json` can omit inline rubric keys when a sibling `rubrics.json` / `scenarios.rubric.json` or `--rubrics-dir` supplies them.
139
148
 
140
- Therefore: do **not** put answer keys, golden replays, or judge-bearing scenario text where a null-arm agent can forage them on the caller/IDE root. Prefer:
149
+ ## Isolation and diagnostics
141
150
 
142
- - opaque prompts + `compareId`
143
- - seeds that only mutate fixtures (not skill bodies)
144
- - harness-only rubrics (sibling `rubrics.json` / `scenarios.rubric.json`, or `--rubrics-dir` outside the open workspace)
145
- - consumer orchestrators that park answer keys off the open workspace (toolbox pattern)
146
- - cloud runtime when true FS isolation is required
151
+ In-repo suites set `workspace` on every scenario. The runner copies that folder into a temp repo. Omit `workspace`, or set `"."`, to copy HEAD plus caller context instead. The folder gets its own `.git`. The runner fails the scenario when tool paths leave that folder. A leftover caller-tree check still restores leaked caller edits.
147
152
 
148
- Live agent runs have a **hard timeout** (default **10 minutes**, override with `--timeout-ms` or `AGENT_TEST_TIMEOUT_MS`; disable with `--no-timeout` or `AGENT_TEST_TIMEOUT_MS=0`). If the agent invokes `AskQuestion` or similar user-input tools, the harness fails fast with a clear error live mode is single-shot and cannot supply follow-up turns. Use `--allow-user-input` only for intentional multi-turn dogfood (the run may still hang waiting for stdin).
153
+ Host-global user skills stay out of the run by default. Those trees live under `~/.cursor/skills`, `~/.claude/skills`, `~/.codex/skills`, and `~/.agents/skills`. A custom `workspace` is a fixture. Keep `allowUserSkills` false for that case. Set `allowUserSkills` to true on the scenario or suite defaults when the test needs the machine skill set. The `skills` field only overlays repo-relative folders into the sealed workspace.
149
154
 
150
- Announce-stop flakes (agent exits after Routing with no tools) are retried once by default on live runs (`AGENT_TEST_SCENARIO_RETRIES=1` or `--scenario-retries 1`; set `0` to disable). This is separate from `AGENT_TEST_LIVE_RETRIES` (judge infra only).
155
+ `contextSources` and `skills` are relative to the workspace root when `workspace` is a subfolder. A bare `contextSources` name is a file in that root. `seedPatch` stays a caller-repo path. Its hunks are relative to that workspace.
151
156
 
152
- ### Dialogue skills in live runs
157
+ `--debug` retains an evidence bundle under `$TMPDIR/agent-spec/sessions/<id>/` by default. Use `--debug-dir` to override the parent directory.
153
158
 
154
- Skills that expect multi-turn Socratic dialogue (for example `crystallize`) will hang or fail in `--live` unless the scenario is written for one-shot completion:
159
+ Host SDK INFO lines stay hidden. Set `AGENT_TEST_HOST_LOGS=1` or `--debug` to print them.
155
160
 
156
- - **Replay-only** commit a golden trace where the agent finishes without asking questions; use `host: "replay"` or `skip: true` with live skipped at suite level.
157
- - **One-shot live prompt** — instruct the agent to mirror intent and emit the final artifact in a single turn (`no AskQuestion; produce Crystallized idea now`).
158
- - **Ambient routing** — fuzzy-intent scenarios that only require mirroring + one assumption are naturally one-shot; full crystallize dialogue is not.
161
+ A TTY run prints `agent started`, then updates an `agent` clock every 0.1s. Tool names and a short reply preview print as the host streams them. The clock line stays one row so the terminal can overwrite it. The HTML report line is a localhost link. A click opens the browser. The preview exits after 30 minutes idle. Set `AGENT_TEST_NO_REPORT_PREVIEW=1` to skip the preview.
159
162
 
160
- Do not weaken dialogue-first product skills for CI; reshape the suite contract instead.
163
+ `Ctrl+C` cancels active host work and deletes the temp folder. `--no-worktree` requires `AGENT_TEST_ALLOW_IN_PLACE=1` because agent edits will persist in the caller checkout.
161
164
 
162
165
  ## MCP servers
163
166
 
164
- Live Cursor runs can attach **inline** MCP servers from suite/scenario JSON. Ambient project/user MCP (`.cursor/mcp.json`) is not loaded tests stay hermetic.
167
+ Scenarios can attach inline stdio or HTTP/SSE MCP servers through suite defaults or scenario overrides. Ambient project/user MCP configuration is not loaded. When `workspace` is a subfolder, stdio MCP cwd is the caller repo. Script args stay caller-relative.
165
168
 
166
- ```json
167
- {
168
- "defaults": {
169
- "mcpServers": {
170
- "docs": {
171
- "type": "http",
172
- "url": "https://example.com/mcp",
173
- "headers": { "Authorization": "Bearer ${DOCS_TOKEN}" }
174
- }
175
- }
176
- },
177
- "scenarios": [
178
- {
179
- "name": "use echo",
180
- "prompt": "Call the echo tool with text hello.",
181
- "mcpServers": {
182
- "echo": {
183
- "type": "stdio",
184
- "command": "node",
185
- "args": ["packages/test/fixtures/mcp-echo/server.mjs"]
186
- }
187
- },
188
- "rubric": {
189
- "mustCallTool": ["echo:hello"],
190
- "mustNotCallTool": ["shell"]
191
- }
192
- }
193
- ]
194
- }
195
- ```
169
+ ## In-repo package checks
196
170
 
197
- - Suite `defaults.mcpServers` merge with scenario `mcpServers` by server name (scenario wins).
198
- - `${ENV_VAR}` placeholders expand in `command`, `args`, `env`, `url`, `headers`, and OAuth fields at run time.
199
- - Rubric `mustCallTool` / `mustNotCallTool` match tool **name** substrings (works with MCP name prefixes). Use `name:argFragment` to also require a substring in JSON args.
200
- - Rubric `mustReadPath` / `mustNotReadPath` match substrings on **Read** tool JSON args (registry-first / avoid inventing paths). Keep hallucination scoring in live `judge` questions — no heavy factuality engine in v1.
201
- - Suite defaults may set `profile: "skeleton"` and/or `contextSources` (additive paths / `.skeleton/customize/` basenames). Shared/cursor/claude defaults stay backwards-compatible.
202
- - Live runs surface provider `usage` on traces/results; suite summary + HTML report include token sum / p50 / p95 when present.
203
- - `--compare-pairs A:B` (or `agent-test compare --a/--b`) pairs scenarios by **`compareId`** when present, else band-neutral scenario name (`outcome:` / `transfer:` stripped), and writes `compare-report.json` / `.md` / `.html` with pass/fail, tokens, toolCallCount, durationMs, and skill/registry hop proxies. Suite HTML also embeds an A/B table when two reports are present.
204
- - Replay hosts ignore `mcpServers` but still score recorded `toolCalls` against those matchers.
171
+ Default CI does not launch a paid agent:
205
172
 
206
- ## Library
207
-
208
- ```ts
209
- import { runAllSuites, expectTrace } from "@post-print/agent-test";
173
+ ```bash
174
+ bun run build
175
+ node packages/test/dist/cli.js --check --suites-dir packages/test/fixtures --suite smoke
176
+ node packages/test/dist/cli.js --check --suites-dir agent-suites --suite smoke
210
177
  ```
178
+
179
+ Host-agent acceptance is `bun run test`. That command runs smoke, tools, mcp, judge, and depth on Cursor, Claude, and Codex. `bun run test:smoke`, `bun run test:tools`, `bun run test:mcp`, `bun run test:judge`, and `bun run test:depth` stay on Cursor. A key-gated GitHub Actions job runs the same suites on Cursor when `CURSOR_API_KEY` is present.
@@ -0,0 +1,38 @@
1
+ import { type AgentHost } from "@post-print/agent-harness";
2
+ export interface CheckOptions {
3
+ cwd: string;
4
+ suitesDir: string;
5
+ filter?: string;
6
+ rubricsDir?: string;
7
+ /** CLI host override. Wins over suite defaults when set. */
8
+ host?: AgentHost;
9
+ /** CLI host matrix. Wins over `host` when more than one name is listed. */
10
+ hosts?: readonly AgentHost[];
11
+ cliPath?: string;
12
+ }
13
+ export interface CheckReport {
14
+ /** Package, suite, and seed checks passed. Host readiness is separate. */
15
+ ok: boolean;
16
+ packageOk: boolean;
17
+ suiteOk: boolean;
18
+ seedsOk: boolean;
19
+ hostReady: boolean;
20
+ hosts: AgentHost[];
21
+ messages: string[];
22
+ }
23
+ /** Hosts a live run will launch after suite defaults and an optional CLI override. */
24
+ export declare function collectSuiteHosts(options: {
25
+ cwd: string;
26
+ suitesDir: string;
27
+ filter?: string;
28
+ rubricsDir?: string;
29
+ host?: AgentHost;
30
+ hosts?: readonly AgentHost[];
31
+ }): Promise<AgentHost[]>;
32
+ /** Missing auth for every host this run will launch. Undefined when all hosts are ready. */
33
+ export declare function missingHostsAuth(hosts: readonly AgentHost[]): string | undefined;
34
+ /** Suite, seed, package, and host checks. Does not launch an agent. */
35
+ export declare function runCheck(options: CheckOptions): Promise<CheckReport>;
36
+ export declare function formatCheckReport(report: CheckReport): string;
37
+ export declare function formatCheckSummary(report: CheckReport): string;
38
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,2BAA2B,CAAC;AAS7E,MAAM,WAAW,YAAY;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC3B,0EAA0E;IAC1E,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAoBD,sFAAsF;AACtF,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;CAC7B,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAmDvB;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,GAAG,SAAS,CAMhF;AAED,uEAAuE;AACvE,wBAAsB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAsE1E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE7D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAO9D"}
package/dist/check.js ADDED
@@ -0,0 +1,169 @@
1
+ import { access } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { isKnownAgentHost } from "@post-print/agent-harness";
4
+ import { discoverSuites } from "./discover-suites.js";
5
+ import { missingAgentAuth, runDoctor } from "./doctor.js";
6
+ import { resolveSuiteHosts, uniqueHosts } from "./hosts.js";
7
+ import { loadSuiteFile } from "./load-suite.js";
8
+ import { formatSeedValidationReport, validateSeedPatches } from "./validate-seeds.js";
9
+ import { formatValidationReport, validateSuitePaths } from "./validate-suite.js";
10
+ function filterSuitePaths(suitePaths, filter) {
11
+ if (!filter) {
12
+ return suitePaths;
13
+ }
14
+ return suitePaths.filter((path) => path.includes(`/${filter}/`) || path.endsWith(`/${filter}/scenarios.json`));
15
+ }
16
+ async function suitesDirExists(cwd, suitesDir) {
17
+ try {
18
+ await access(resolve(cwd, suitesDir));
19
+ return true;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ /** Hosts a live run will launch after suite defaults and an optional CLI override. */
26
+ export async function collectSuiteHosts(options) {
27
+ const cliHosts = uniqueHosts(options.hosts ?? (options.host ? [options.host] : undefined));
28
+ if (cliHosts?.length === 1) {
29
+ return cliHosts;
30
+ }
31
+ const root = resolve(options.cwd, options.suitesDir);
32
+ let suitePaths = [];
33
+ try {
34
+ suitePaths = filterSuitePaths(await discoverSuites(root), options.filter);
35
+ }
36
+ catch {
37
+ return cliHosts ?? ["cursor"];
38
+ }
39
+ if (suitePaths.length === 0) {
40
+ return cliHosts ?? ["cursor"];
41
+ }
42
+ const hosts = new Set();
43
+ for (const suitePath of suitePaths) {
44
+ try {
45
+ const suite = await loadSuiteFile(suitePath, { rubricsDir: options.rubricsDir });
46
+ const resolved = resolveSuiteHosts({
47
+ cliHosts,
48
+ suiteHosts: suite.hosts,
49
+ defaultHost: suite.defaults?.host,
50
+ });
51
+ if (resolved.length > 1 || (suite.hosts !== undefined && suite.hosts.length > 0)) {
52
+ for (const host of resolved) {
53
+ hosts.add(host);
54
+ }
55
+ continue;
56
+ }
57
+ const fallback = suite.defaults?.host ?? "cursor";
58
+ for (const scenario of suite.scenarios) {
59
+ if (scenario.skip) {
60
+ continue;
61
+ }
62
+ const host = scenario.host ?? fallback;
63
+ if (isKnownAgentHost(host)) {
64
+ hosts.add(host);
65
+ }
66
+ }
67
+ if (suite.scenarios.length === 0 && isKnownAgentHost(fallback)) {
68
+ hosts.add(fallback);
69
+ }
70
+ }
71
+ catch {
72
+ // Invalid files are reported by suite validation.
73
+ }
74
+ }
75
+ if (hosts.size === 0) {
76
+ return cliHosts ?? ["cursor"];
77
+ }
78
+ return [...hosts];
79
+ }
80
+ /** Missing auth for every host this run will launch. Undefined when all hosts are ready. */
81
+ export function missingHostsAuth(hosts) {
82
+ const missing = hosts.map((host) => missingAgentAuth(host)).filter((message) => message);
83
+ if (missing.length === 0) {
84
+ return undefined;
85
+ }
86
+ return missing.join("\n");
87
+ }
88
+ /** Suite, seed, package, and host checks. Does not launch an agent. */
89
+ export async function runCheck(options) {
90
+ const messages = [];
91
+ const doctor = runDoctor({ cliPath: options.cliPath });
92
+ messages.push("package");
93
+ for (const message of doctor.messages) {
94
+ messages.push(` ${message}`);
95
+ }
96
+ const hosts = await collectSuiteHosts(options);
97
+ const hostError = missingHostsAuth(hosts);
98
+ const hostReady = hostError === undefined;
99
+ messages.push("host");
100
+ messages.push(` ${hosts.join(", ")}: ${hostReady ? "ready" : (hostError ?? "not ready")}`);
101
+ let suiteOk = false;
102
+ const suitesRoot = resolve(options.cwd, options.suitesDir);
103
+ if (!(await suitesDirExists(options.cwd, options.suitesDir))) {
104
+ messages.push("suite");
105
+ messages.push(` missing ${suitesRoot}`);
106
+ }
107
+ else {
108
+ const suitePaths = filterSuitePaths(await discoverSuites(suitesRoot), options.filter);
109
+ if (suitePaths.length === 0) {
110
+ messages.push("suite");
111
+ messages.push(` No suites found under ${options.suitesDir}`);
112
+ }
113
+ else {
114
+ const suiteReport = await validateSuitePaths(suitePaths, {
115
+ validatePaths: true,
116
+ repoRoot: options.cwd,
117
+ rubricsDir: options.rubricsDir,
118
+ });
119
+ suiteOk = suiteReport.ok;
120
+ messages.push("suite");
121
+ for (const line of formatValidationReport(suiteReport).split("\n")) {
122
+ messages.push(` ${line}`);
123
+ }
124
+ }
125
+ }
126
+ const seedReport = await validateSeedPatches({
127
+ cwd: options.cwd,
128
+ suitesDir: options.suitesDir,
129
+ rubricsDir: options.rubricsDir,
130
+ filter: options.filter,
131
+ }).catch((error) => ({
132
+ ok: false,
133
+ issues: [
134
+ {
135
+ suite: options.suitesDir,
136
+ scenario: "*",
137
+ seedPatch: "",
138
+ message: error instanceof Error ? error.message : String(error),
139
+ },
140
+ ],
141
+ checked: 0,
142
+ }));
143
+ const seedsOk = seedReport.ok;
144
+ messages.push("seeds");
145
+ for (const line of formatSeedValidationReport(seedReport).split("\n")) {
146
+ messages.push(` ${line}`);
147
+ }
148
+ return {
149
+ ok: doctor.ok && suiteOk && seedsOk,
150
+ packageOk: doctor.ok,
151
+ suiteOk,
152
+ seedsOk,
153
+ hostReady,
154
+ hosts,
155
+ messages,
156
+ };
157
+ }
158
+ export function formatCheckReport(report) {
159
+ return ["agent-test check", ...report.messages].join("\n");
160
+ }
161
+ export function formatCheckSummary(report) {
162
+ const suite = report.suiteOk ? "suite ok" : "suite failed";
163
+ const pkg = report.packageOk ? "package ok" : "package failed";
164
+ const host = report.hostReady
165
+ ? `host ${report.hosts.join(",")} ready`
166
+ : `host ${report.hosts.join(",")} not ready`;
167
+ return `check ${pkg} · ${suite} · ${host}`;
168
+ }
169
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts CHANGED
@@ -7,18 +7,24 @@ export interface ParsedCliArgs {
7
7
  /** Prefer `<rubricsDir>/<suite>/rubrics.json` (harness-only answer keys). */
8
8
  rubricsDir?: string;
9
9
  host?: AgentHost;
10
+ /** Host matrix when `--host` lists more than one adapter. */
11
+ hosts?: AgentHost[];
12
+ /** True when `--host` included `all`. Re-expand after adapters load. */
13
+ hostAll?: boolean;
14
+ /** Consumer adapter modules (`--adapter`). */
15
+ adapterModules?: string[];
10
16
  filter?: string;
11
17
  scenarioFilter?: string;
12
18
  stagingSessionId?: string;
13
- record: boolean;
14
- recordFixtures: boolean;
15
- live: boolean;
16
19
  judge?: boolean;
17
20
  worktree?: boolean;
18
21
  keepRecordings: boolean;
19
22
  timeoutMs?: number;
20
23
  noTimeout: boolean;
21
24
  allowUserInput: boolean;
25
+ /** Check the suite and host. Do not launch an agent. */
26
+ check: boolean;
27
+ help: boolean;
22
28
  doctor: boolean;
23
29
  htmlReport: boolean;
24
30
  /** Explicit HTML report path (ends in .html) or output directory for all report content. */
@@ -31,20 +37,12 @@ export interface ParsedCliArgs {
31
37
  failOn: FailOnMode;
32
38
  /** Live announce-stop retries (overrides AGENT_TEST_SCENARIO_RETRIES). */
33
39
  scenarioRetries?: number;
34
- /** Offline compare subcommand (`agent-test compare --a … --b …`). */
35
- compareMode: boolean;
36
- compareA?: string;
37
- compareB?: string;
38
- /** Live/replay A:B suite dirs or report JSON paths. */
39
- comparePairs?: string;
40
- compareOutDir?: string;
41
40
  }
41
+ /** Usage text for `--help`. */
42
+ export declare function formatHelp(): string;
42
43
  /** Parse agent-test CLI argv (exported for unit tests). */
43
44
  export declare function parseCliArgs(argv: string[]): ParsedCliArgs;
44
- /**
45
- * Split `--report-out` into an HTML file path and, when a directory was given,
46
- * the directory every other report artifact is written to.
47
- */
45
+ /** Resolve an explicit report target into the HTML path and optional artifact directory. */
48
46
  export declare function resolveReportOutput(reportOut?: string): {
49
47
  htmlPath?: string;
50
48
  outDir?: string;