@abdwhb-png/pi-test-harness 0.7.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 (74) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/LICENSE +21 -0
  3. package/README.md +673 -0
  4. package/dist/diagnostics.d.ts +11 -0
  5. package/dist/diagnostics.d.ts.map +1 -0
  6. package/dist/diagnostics.js +61 -0
  7. package/dist/diagnostics.js.map +1 -0
  8. package/dist/events.d.ts +6 -0
  9. package/dist/events.d.ts.map +1 -0
  10. package/dist/events.js +33 -0
  11. package/dist/events.js.map +1 -0
  12. package/dist/index.d.ts +14 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +19 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/mock-pi-script.mjs +176 -0
  17. package/dist/mock-pi.d.ts +32 -0
  18. package/dist/mock-pi.d.ts.map +1 -0
  19. package/dist/mock-pi.js +150 -0
  20. package/dist/mock-pi.js.map +1 -0
  21. package/dist/mock-tools.d.ts +51 -0
  22. package/dist/mock-tools.d.ts.map +1 -0
  23. package/dist/mock-tools.js +192 -0
  24. package/dist/mock-tools.js.map +1 -0
  25. package/dist/mock-ui.d.ts +13 -0
  26. package/dist/mock-ui.d.ts.map +1 -0
  27. package/dist/mock-ui.js +159 -0
  28. package/dist/mock-ui.js.map +1 -0
  29. package/dist/pi-loader-parity.d.ts +36 -0
  30. package/dist/pi-loader-parity.d.ts.map +1 -0
  31. package/dist/pi-loader-parity.js +60 -0
  32. package/dist/pi-loader-parity.js.map +1 -0
  33. package/dist/playbook.d.ts +44 -0
  34. package/dist/playbook.d.ts.map +1 -0
  35. package/dist/playbook.js +143 -0
  36. package/dist/playbook.js.map +1 -0
  37. package/dist/sandbox.d.ts +27 -0
  38. package/dist/sandbox.d.ts.map +1 -0
  39. package/dist/sandbox.js +269 -0
  40. package/dist/sandbox.js.map +1 -0
  41. package/dist/session.d.ts +13 -0
  42. package/dist/session.d.ts.map +1 -0
  43. package/dist/session.js +187 -0
  44. package/dist/session.js.map +1 -0
  45. package/dist/types.d.ts +171 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +5 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/utils.d.ts +32 -0
  50. package/dist/utils.d.ts.map +1 -0
  51. package/dist/utils.js +46 -0
  52. package/dist/utils.js.map +1 -0
  53. package/package.json +84 -0
  54. package/skills/pi-test-harness/SKILL.md +451 -0
  55. package/skills/pi-test-harness/evals/evals.json +26 -0
  56. package/skills/pi-test-harness/references/api-reference.md +480 -0
  57. package/skills/pi-test-harness/references/mock-pi-cli.md +135 -0
  58. package/skills/pi-test-harness/references/mock-tools.md +176 -0
  59. package/skills/pi-test-harness/references/mock-ui.md +170 -0
  60. package/skills/pi-test-harness/references/playbook-dsl.md +209 -0
  61. package/skills/pi-test-harness/references/sandbox-install.md +113 -0
  62. package/src/diagnostics.ts +90 -0
  63. package/src/events.ts +43 -0
  64. package/src/index.ts +42 -0
  65. package/src/mock-pi-script.mjs +176 -0
  66. package/src/mock-pi.ts +169 -0
  67. package/src/mock-tools.ts +252 -0
  68. package/src/mock-ui.ts +196 -0
  69. package/src/pi-loader-parity.ts +61 -0
  70. package/src/playbook.ts +189 -0
  71. package/src/sandbox.ts +334 -0
  72. package/src/session.ts +249 -0
  73. package/src/types.ts +203 -0
  74. package/src/utils.ts +46 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,161 @@
1
+ # @abdwhb-png/pi-test-harness
2
+
3
+ ## 0.7.0
4
+
5
+ ### Major Changes
6
+
7
+ - [`fork`](https://github.com/abdwhb-png/pi-test-harness) Thanks [@abdwhb](https://github.com/abdwhb)! — Fork from `@marcfargas/pi-test-harness@0.6.1`. Pi 0.83.0 compatibility milestone.
8
+
9
+ **Breaking: Pi `^0.83.0` required.** Drops support for Pi `<0.83.0`.
10
+
11
+ - **`ModelRuntime` isolation** — `createTestSession()` creates an isolated `ModelRuntime` with `authPath` under the working directory and `modelsPath: null`. No credentials file is read from `~/.pi/agent`. A dummy API key is set on the openai provider to satisfy AgentSession auth checks (the model is never called — playbook replaces `streamFunction`).
12
+
13
+ - **Public Agent APIs** — The harness now accesses `session.agent.streamFunction`, `session.agent.state.tools`, and `session.agent.waitForIdle()` through the public typed API surface of Pi 0.83's `Agent` class. No more `(agent as any).streamFn` casts.
14
+
15
+ - **AgentSession typed** — `TestSession.session` is typed as `AgentSession` from `@earendil-works/pi-coding-agent`.
16
+
17
+ - **Hook pipeline — single source of truth** — AgentSession 0.83 installs `beforeToolCall`/`afterToolCall` hooks on the Agent, which drive the extension `tool_call`/`tool_result` events. The harness mock no longer re-emits these hooks manually. Each hook fires exactly once per tool call. Tool result modification via `tool_result` hook return values works correctly because the subscriber reads the finalized result from `tool_execution_end`.
18
+
19
+ - **Removed `ExtensionRunner` dependency from mock-tools** — `interceptToolExecution()` no longer takes an `extensionRunner` parameter. Mock wrappers only replace `tool.execute()`; hook dispatch is handled by AgentSession.
20
+
21
+ - **`ExtensionUIContext` — 0.83 members** — `createMockUIContext()` returns a properly typed `ExtensionUIContext` with all 0.83 members: `setWorkingVisible`, `setWorkingIndicator`, `setHiddenThinkingLabel`, `addAutocompleteProvider`, `getEditorComponent`. No `any` casts on the return type.
22
+
23
+ - **`SandboxOptions.npmCommand`** — New option to specify a custom npm command for `verifySandboxInstall()`. Default resolves to the platform npm. Use `["sfw", "npm"]` to route through Socket Firewall, or provide any `execFileSync`-compatible argv. A nonexistent command produces a clear `ENOENT` error.
24
+
25
+ - **`ToolBlockedError` kept for compat** — Still exported but no longer thrown in the normal mock flow. AgentSession 0.83 blocks tools via `beforeToolCall` before `execute()` is reached. Consumers can use `ToolBlockedError` for instanceof checks on errors from event callbacks.
26
+
27
+ - **`session_shutdown` note** — `session.dispose()` does NOT fire `session_shutdown`. That event fires at Node.js process exit. Extension-owned resources (e.g., SQLite handles) remain open until then.
28
+
29
+ - **Package identity** — Renamed to `@abdwhb-png/pi-test-harness@0.7.0`. Repository/homepage/bugs point to `abdwhb-png/pi-test-harness`. Peer dependencies narrowed to `^0.83.0`. Dev dependencies pinned to exact `0.83.0`.
30
+
31
+ - **CI** — Verify job runs `sfw npm ci` and `sfw npm audit`. Integration tests Node 22 and 24 on Linux and Windows with Pi 0.83. Release workflow changed to manual (`workflow_dispatch`).
32
+
33
+ - **Consumer smoke** — Uses `sfw npm install` with exact `0.83.0` peers, runs a real say-only session, and asserts consumption.
34
+
35
+ ## 0.6.1
36
+
37
+ ### Patch Changes
38
+
39
+ - [`0236306`](https://github.com/marcfargas/pi-test-harness/commit/02363061622b5255fe2905867ec68e7bc0270d8b) Thanks [@marcfargas](https://github.com/marcfargas)! - Fix release metadata after the 0.6.0 migration release.
40
+
41
+ ## 0.6.0
42
+
43
+ ### Minor Changes
44
+
45
+ - [`10eb126`](https://github.com/marcfargas/pi-test-harness/commit/10eb1268fb82eb567ee8ba3e47fb942c5ee40795) Thanks [@marcfargas](https://github.com/marcfargas)! - Migrate the harness to the current `@earendil-works/*` Pi packages and require Pi `>=0.74.0`.
46
+
47
+ This drops direct support for the deprecated `@mariozechner/*` Pi package names, updates the harness for current Pi session/tool APIs, and adds CI coverage across Linux and Windows against the latest patch releases of the last two supported Pi minor lines.
48
+
49
+ ## 0.5.0
50
+
51
+ ### Minor Changes
52
+
53
+ - [#3](https://github.com/marcfargas/pi-test-harness/pull/3) [`225e123`](https://github.com/marcfargas/pi-test-harness/commit/225e123ce6ce2790f739aa3083ad1add3f09e752) Thanks [@marcfargas](https://github.com/marcfargas)! - Add `ToolBlockedError` and `safeRmSync` to the public API.
54
+
55
+ **`ToolBlockedError`** — a typed error class thrown when an extension hook blocks a mocked tool call. Use `instanceof ToolBlockedError` to distinguish hook blocks from real execution errors in tests, instead of matching error message strings.
56
+
57
+ ```ts
58
+ import { ToolBlockedError } from "@marcfargas/pi-test-harness";
59
+
60
+ // Test that a blocked call doesn't crash, just records an error
61
+ const result = t.events.toolResultsFor("bash")[0];
62
+ expect(result.isError).toBe(true);
63
+
64
+ // Or catch it where propagateErrors is relevant
65
+ try {
66
+ await t.run(when("Try write", [calls("bash", {}), says("Done.")]));
67
+ } catch (err) {
68
+ if (err instanceof ToolBlockedError) {
69
+ // Expected — extension hook blocked the call
70
+ } else throw err;
71
+ }
72
+ ```
73
+
74
+ **`safeRmSync(filePath)`** — removes a file, swallowing `EPERM` and `EBUSY` errors only. Intended for `afterEach` cleanup of extension-owned SQLite files on Windows, where `session_shutdown` (which closes DB connections) fires at process exit rather than on `session.dispose()`.
75
+
76
+ ```ts
77
+ import { safeRmSync } from "@marcfargas/pi-test-harness";
78
+
79
+ afterEach(() => {
80
+ t?.dispose();
81
+ safeRmSync(dbPath);
82
+ safeRmSync(dbPath + "-wal");
83
+ safeRmSync(dbPath + "-shm");
84
+ });
85
+ ```
86
+
87
+ ### Patch Changes
88
+
89
+ - [#3](https://github.com/marcfargas/pi-test-harness/pull/3) [`225e123`](https://github.com/marcfargas/pi-test-harness/commit/225e123ce6ce2790f739aa3083ad1add3f09e752) Thanks [@marcfargas](https://github.com/marcfargas)! - Fix tool event collection and block detection.
90
+
91
+ - **`toolResultsFor()` / `toolCallsFor()` now work without `mockTools`**. Previously these always returned `[]` when `mockTools` was not configured, because real tools were not wrapped for collection. Now all tools are always wrapped, regardless of whether mocks are configured.
92
+
93
+ - **Fix double-wrapping on multiple `run()` calls**. Calling `run()` twice in one test would wrap already-wrapped tools again, causing double-counted results and incorrect step numbers. The original tools are now captured once at session creation and reused on every `run()` call.
94
+
95
+ - **Fix block detection regression in `wrapForCollection`**. The `ToolBlockedError` class is thrown by the harness's own mock block path, but pi's native hook chain throws a plain `Error` with a message. Block detection now uses a hybrid check (`instanceof ToolBlockedError` + message fallback) so both paths are correctly classified as blocks rather than test failures.
96
+
97
+ ## 0.4.1
98
+
99
+ ### Patch Changes
100
+
101
+ - [`58693d2`](https://github.com/marcfargas/pi-test-harness/commit/58693d2bab91651fe647dffe740643ab3af13cbf) Thanks [@marcfargas](https://github.com/marcfargas)! - Address code review findings for v0.4.0 standalone release.
102
+
103
+ - **Breaking**: Remove deprecated `call()`/`say()` DSL aliases (use `calls()`/`says()` instead)
104
+ - Fix diagnostic messages to reference current `calls()`/`says()` API names
105
+ - Fix release workflow for npm Trusted Publishers (`--provenance`)
106
+ - Record all mock UI method calls for assertion consistency (`setFooter`, `setHeader`, etc.)
107
+ - Scope playbook `toolCallCounter` to factory closure for concurrency safety
108
+ - Add `verifySandboxInstall()` test suite (4 tests with dummy extension fixture)
109
+ - Update package description to mention all three test layers
110
+
111
+ ## 0.4.0
112
+
113
+ ### Minor Changes
114
+
115
+ - [`688e5fa`](https://github.com/marcfargas/pi-mf-extensions/commit/688e5faa29a1c2673699d5e120b95b619e451ae6) Thanks [@marcfargas](https://github.com/marcfargas)! - Ship compiled `.js` + `.d.ts` output instead of raw TypeScript sources
116
+
117
+ Previously, the package shipped only `.ts` source files and relied on consumers having a TypeScript-aware loader (jiti, vitest). Node 24's `--experimental-strip-types` refuses to process `.ts` files inside `node_modules/`, making the package unusable with `node --test` or any Node-native test runner.
118
+
119
+ Now:
120
+
121
+ - Package exports point to pre-compiled `dist/index.js` (with `dist/index.d.ts` for types)
122
+ - Source `.ts` files are still included for debugging/source maps
123
+ - Build step (`tsc -p tsconfig.build.json`) runs automatically before publish via `prepublishOnly`
124
+
125
+ ## 0.3.0
126
+
127
+ ### Minor Changes
128
+
129
+ - Rename DSL: `call()` → `calls()`, `say()` → `says()`.
130
+
131
+ The new names read more naturally as playbook declarations:
132
+ `when("Deploy", [calls("bash", ...), says("Done.")])` reads as
133
+ "when prompted 'Deploy', the model calls bash then says 'Done.'"
134
+
135
+ The old `call()` and `say()` are kept as deprecated aliases (removal in v0.4).
136
+
137
+ ## 0.2.0
138
+
139
+ ### Minor Changes
140
+
141
+ - Initial release.
142
+
143
+ - Playbook DSL (`when`, `call`, `say`) for scripting agent conversations without LLM calls
144
+ - `createTestSession()` — creates real pi `AgentSession` with extension loading, hooks, and events
145
+ - Mock tool execution — intercept `tool.execute()` per-tool with static, dynamic, or full result handlers
146
+ - Mock UI context — configurable responses for `confirm`, `select`, `input`, `editor` with call recording
147
+ - Event collection — query helpers for tool calls, tool results, blocked calls, UI interactions, and messages
148
+ - Late-bound params and `.then()` callbacks for dynamic multi-step tool flows
149
+ - Playbook diagnostics — clear error messages on exhausted/unconsumed actions with step-level detail
150
+ - Error propagation control — abort on real tool throw (default) or capture as error results
151
+ - `verifySandboxInstall()` — npm pack → temp install → verify extensions and tools load correctly
152
+
153
+ ### Patch Changes
154
+
155
+ - Fix mocked tools bypassing extension hooks (tool_call/tool_result).
156
+
157
+ - Mocked tools now fire `emitToolCall`/`emitToolResult` via the extension runner,
158
+ so extension blocking (e.g., plan mode) works correctly in tests
159
+ - Blocked tool results are recorded in `toolResults` before throwing
160
+ - `wrapForCollection` now propagates `isError` from real tool results (was hardcoded `false`)
161
+ - Hook-blocked tools no longer treated as test failures with `propagateErrors: true`
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marc Fargas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.