pi-oracle 0.7.4 → 0.7.6

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 (31) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +53 -18
  3. package/docs/ORACLE_DESIGN.md +16 -8
  4. package/docs/platform-smoke.md +156 -0
  5. package/extensions/oracle/index.ts +10 -4
  6. package/extensions/oracle/lib/config.ts +53 -27
  7. package/extensions/oracle/lib/jobs.ts +9 -5
  8. package/extensions/oracle/lib/poller.ts +1 -0
  9. package/extensions/oracle/lib/runtime.ts +107 -32
  10. package/extensions/oracle/lib/tools.ts +138 -12
  11. package/extensions/oracle/shared/browser-profile-helpers.d.mts +59 -0
  12. package/extensions/oracle/shared/browser-profile-helpers.mjs +395 -0
  13. package/extensions/oracle/shared/process-helpers.mjs +12 -1
  14. package/extensions/oracle/shared/state-coordination-helpers.mjs +8 -2
  15. package/extensions/oracle/worker/auth-bootstrap.mjs +39 -10
  16. package/extensions/oracle/worker/chatgpt-ui-helpers.d.mts +2 -0
  17. package/extensions/oracle/worker/chatgpt-ui-helpers.mjs +157 -1
  18. package/extensions/oracle/worker/chromium-cookie-source.mjs +2 -1
  19. package/extensions/oracle/worker/run-job.mjs +107 -25
  20. package/package.json +30 -9
  21. package/platform-smoke.config.mjs +66 -0
  22. package/scripts/oracle-real-smoke.mjs +500 -0
  23. package/scripts/platform-smoke/Dockerfile.ubuntu +8 -0
  24. package/scripts/platform-smoke/artifacts.mjs +87 -0
  25. package/scripts/platform-smoke/assertions.mjs +34 -0
  26. package/scripts/platform-smoke/crabbox-runner.mjs +135 -0
  27. package/scripts/platform-smoke/doctor.mjs +239 -0
  28. package/scripts/platform-smoke/invariants.mjs +124 -0
  29. package/scripts/platform-smoke/platform-build-windows.ps1 +168 -0
  30. package/scripts/platform-smoke/targets.mjs +434 -0
  31. package/scripts/platform-smoke.mjs +152 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,37 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.7.6 - 2026-06-04
6
+
7
+ ### Changed
8
+ - updated the local pi development baseline to `@earendil-works/pi-coding-agent` / `@earendil-works/pi-ai` `0.78.1` and regenerated the npm lockfile
9
+ - documented `pi` `0.78.1+` as the suggested tested floor while keeping pi runtime packages as optional wildcard peers so newer pi releases are not blocked by npm peer ranges
10
+ - added Ant Ling, NVIDIA NIM, and MiniMax China provider env mappings to the oracle real-smoke/platform-smoke provider metadata
11
+
12
+ ### Fixed
13
+ - made startup poller and wake-up routing mode-aware with Pi 0.78.1 `ctx.mode`, so print and JSON one-shot runs do not start background pollers or publish oracle UI status
14
+ - guarded oracle startup status and warning notifications with `ctx.hasUI` for non-UI modes
15
+
16
+ ### Compatibility
17
+ - reviewed the pi `0.78.1` changelog, extension docs, package docs, prompt-template docs, and matching examples; the oracle extension remains compatible with current extension lifecycle and package install/update behavior
18
+
19
+ ## 0.7.5 - 2026-06-02
20
+
21
+ ### Added
22
+ - added a Crabbox platform release smoke gate for macOS, Ubuntu, and Windows native with doctor-first validation, packed-install real-extension proof, stop evidence, and platform artifacts
23
+ - added canonical workflow docs and scripts for everyday local validation, focused platform-sensitive runs, and full release/publish smoke coverage
24
+
25
+ ### Changed
26
+ - made the default packed real smoke deterministic by installing the packed package into a clean pi project and invoking the installed `oracle_submit` tool path without waiting on a model-agent turn
27
+ - made Windows native a supported package OS and moved reusable Windows smoke dependencies into the Parallels template/snapshot workflow
28
+
29
+ ### Fixed
30
+ - hardened Windows archive/process/profile handling, including taskkill cleanup, executable resolution, tar/zstd archive behavior, path safety, and auth-bootstrap absolute-path checks
31
+ - removed production `as unknown as` casts and switched Linux/Windows runtime profile copies to Node recursive copy instead of relying on POSIX `cp`
32
+
33
+ ### Validation
34
+ - verified `npm run verify:oracle`, `git diff --check`, and `npm run smoke:platform:all` across macOS, Ubuntu, and Windows native before release
35
+
5
36
  ## 0.7.4 - 2026-05-28
6
37
 
7
38
  ### Changed
@@ -66,6 +97,7 @@
66
97
 
67
98
  ### Changed
68
99
  - made `/oracle-auth` success and failure output easier to scan, with compact source summaries and source-specific troubleshooting for configured Chromium cookie sources
100
+ - expanded package support to Linux, using ordinary profile copies off macOS and documenting `@steipete/sweet-cookie`'s Linux keyring/password options for Chromium cookie import
69
101
  - tightened README quickstart/command wording around preflight-first `/oracle` behavior, context-rich archive selection, cleanup retention, and preset defaults
70
102
  - added the resolved oracle model preset snapshot to `oracle_submit` queued/dispatched output so agents can see what preset will run
71
103
  - clarified `oracle_preflight` output so users can see that it validates the persisted pi session, local config, and ChatGPT auth seed created by `oracle_auth`
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  `pi-oracle` lets a `pi` agent send hard, long-running work to ChatGPT.com or Grok through the web app, with repo archives, background execution, saved results, and a best-effort wake-up back into `pi` when the answer is ready.
4
4
 
5
- > Status: experimental public beta. Validated primarily on macOS with Google Chrome/Chromium and the current pi package baseline. Pi-bundled runtime packages are optional wildcard peers so npm peer ranges do not block users from trying newer pi releases, though runtime behavior is only verified against the tested baseline until a follow-up package release confirms it. Normal oracle jobs run in an isolated browser profile, not your active browser window.
5
+ > Status: experimental public beta. Validated on macOS, Linux, and Windows native with Chromium-family browsers and pi `0.78.1`. Pi `0.78.1+` is the suggested tested floor for mode-aware background polling, but pi-bundled runtime packages remain optional wildcard peers so npm peer ranges do not block users from trying newer pi releases. Normal oracle jobs run in an isolated browser profile, not your active browser window.
6
6
 
7
7
  ## What a successful run looks like
8
8
 
@@ -37,7 +37,7 @@ Do not use it for:
37
37
 
38
38
  - short local coding tasks that `pi` can handle directly
39
39
  - projects that must never be uploaded to ChatGPT.com, Grok, or another configured web provider
40
- - non-macOS environments or machines without the required local browser/tooling
40
+ - machines outside the currently supported local browser/tooling setup
41
41
 
42
42
  ## Problem it solves
43
43
 
@@ -75,13 +75,15 @@ pi install https://github.com/fitchmultz/pi-oracle
75
75
 
76
76
  You need:
77
77
 
78
- - macOS
78
+ - macOS, Linux, or Windows native
79
79
  - Node.js 22 or newer
80
- - `pi` 0.65.0 or newer
81
- - Google Chrome or another Chromium-family browser
80
+ - Suggested tested floor: `pi` 0.78.1 or newer; older pi versions are not blocked by package metadata but are outside the current validation baseline
81
+ - Google Chrome/Chromium or another Chromium-family browser
82
82
  - ChatGPT or Grok already signed in to the configured local browser profile for the provider you plan to use
83
83
  - `agent-browser`, `tar`, and `zstd` available on the machine
84
+ - on macOS APFS clone mode, `cp` available on PATH or via `PI_ORACLE_CP_PATH`; Linux/Windows runtime profile copies use Node's recursive copy
84
85
  - a normal persisted `pi` session, not `pi --no-session`
86
+ - on Linux, encrypted Chromium cookies may also require `secret-tool` (GNOME/libsecret) or `kwallet-query` + `dbus-send` (KDE), unless a Chrome/Brave safe-storage password override is set for the auth run
85
87
 
86
88
  ### 3. Sync provider auth once
87
89
 
@@ -202,11 +204,23 @@ Notes:
202
204
  - When an agent is unsure which oracle preset fits, it should omit `preset` and use the configured default model instead of asking by default. If the prompt says to use Grok, it should pass `provider: "grok"` to `oracle_submit`.
203
205
  - You usually do not need browser paths unless auto-detection fails.
204
206
 
207
+ ### Linux cookie import notes
208
+
209
+ `/oracle-auth` delegates the default cookie read to `@steipete/sweet-cookie`'s Linux Chrome/Chromium backend. The packaged default auto-detects existing Google Chrome, Chromium, Chromium Browser, or Brave profile roots under `${XDG_CONFIG_HOME:-~/.config}` and passes non-Google roots as absolute profile paths so the correct cookie DB is read. Set `auth.chromeProfile` to another profile name, a profile directory, or a `Cookies` DB path when needed, and leave `auth.chromiumKeychain` unset on Linux.
210
+
211
+ Sweet Cookie's Linux encrypted-cookie handling is controlled outside pi-oracle:
212
+
213
+ - `SWEET_COOKIE_LINUX_KEYRING=gnome|kwallet|basic` selects GNOME/libsecret, KDE KWallet, or no keyring probing.
214
+ - GNOME probing shells out to `secret-tool`; KDE probing shells out to `kwallet-query` and `dbus-send`.
215
+ - `SWEET_COOKIE_CHROME_SAFE_STORAGE_PASSWORD` and `SWEET_COOKIE_BRAVE_SAFE_STORAGE_PASSWORD` bypass keyring probing when you already know the browser safe-storage password.
216
+
217
+ Do not put safe-storage passwords in project config or persistent shell startup files. Prefer keyring helpers when possible; if you use an environment override for one `/oracle-auth` run, pi-oracle scrubs it before launching browser/helper subprocesses after cookie import.
218
+
205
219
  ### Custom Chromium cookie sources
206
220
 
207
- Use this only for a Chromium-family browser that the default cookie importer cannot read.
221
+ Most Chrome/Chromium-compatible browsers should work through Sweet Cookie's default Chrome backend when `auth.chromeProfile` points at the right profile or cookie DB. pi-oracle does not currently select Sweet Cookie's Edge or Firefox backends. The `auth.chromiumKeychain` alternate path is macOS-only and is intended for a Chromium-family browser that is not one of Sweet Cookie's built-in Chrome/Brave/Arc/Chromium targets or otherwise cannot import cookies without dependency patching.
208
222
 
209
- Before running `/oracle-auth` with this path:
223
+ Before running `/oracle-auth` with this macOS path:
210
224
 
211
225
  1. Log into ChatGPT or Grok in the target browser profile, depending on `defaults.provider`.
212
226
  2. Fully quit the browser so its `Cookies` database is stable.
@@ -214,7 +228,7 @@ Before running `/oracle-auth` with this path:
214
228
  4. Find the browser's macOS Keychain safe-storage item account and service name.
215
229
  5. Configure all of `browser.executablePath`, `auth.chromeCookiePath`, and `auth.chromiumKeychain` in `~/.pi/agent/extensions/oracle.json`.
216
230
 
217
- Example Helium config:
231
+ Example macOS Helium config:
218
232
 
219
233
  ```json
220
234
  {
@@ -233,7 +247,9 @@ Example Helium config:
233
247
  }
234
248
  ```
235
249
 
236
- `auth.chromeCookiePath` must be paired with `auth.chromiumKeychain`; partial config is rejected so oracle does not silently fall back to another browser source.
250
+ `auth.chromeCookiePath` remains the cookie database path for backward compatibility. On macOS, `auth.chromiumKeychain` must be paired with `auth.chromeCookiePath`; partial config is rejected so oracle does not silently fall back to a different browser source. When both are present on macOS, `/oracle-auth` uses pi-oracle's repo-owned generic Chromium cookie reader instead of patching `@steipete/sweet-cookie` internals. On Linux, `auth.chromiumKeychain` is rejected; use Sweet Cookie's Linux keyring/password environment options instead.
251
+
252
+ If macOS prompts for Keychain access during `/oracle-auth`, allow access for the configured browser safe-storage item. If auth still fails after cookies are synced, the cookie DB may be stale, from the wrong profile, or for an account that is logged out; reopen the configured browser profile, confirm ChatGPT works there, quit the browser, and rerun `/oracle-auth`. On Linux, inspect `/oracle-auth` diagnostics for Sweet Cookie warnings about `secret-tool`, `kwallet-query`, or safe-storage password overrides.
237
253
 
238
254
  ## Available providers and presets
239
255
 
@@ -279,19 +295,19 @@ Review the code and design docs before using it with private or regulated materi
279
295
 
280
296
  ## Current limits
281
297
 
282
- - Experimental public beta, validated primarily on macOS.
298
+ - Experimental public beta, validated on macOS, Linux, and Windows native with Chromium-family browsers.
283
299
  - Provider UI, auth, model controls, and artifact download behavior can drift.
284
300
  - Archive uploads are capped at 250 MiB for ChatGPT and 200 MiB for Grok after default exclusions and automatic whole-repo pruning.
285
301
  - A real ChatGPT or Grok web session is required for the provider you use.
286
302
  - The README currently uses command-level proof and design docs; no public screenshot or demo GIF is checked into the repo.
287
- - Production hardening should keep focusing on UI drift detection, auth recovery, artifact capture, and environment diagnostics.
303
+ - Production hardening should keep focusing on UI drift detection, auth recovery, artifact capture, platform compatibility, and environment diagnostics.
288
304
 
289
305
  ## Troubleshooting
290
306
 
291
307
  ### `/oracle-auth` fails or says login is required
292
308
 
293
309
  - Make sure the selected provider works in the same local browser profile you configured.
294
- - For custom Chromium cookie sources, confirm `auth.chromeCookiePath` points at that profile's `Cookies` DB and `auth.chromiumKeychain.services` names the browser's safe-storage Keychain service.
310
+ - For custom Chromium cookie sources, confirm `auth.chromeCookiePath` points at that profile's `Cookies` DB. On macOS, also confirm `auth.chromiumKeychain.services` names the browser's safe-storage Keychain service. On Linux, leave `auth.chromiumKeychain` unset and use Sweet Cookie's `SWEET_COOKIE_LINUX_KEYRING`, `SWEET_COOKIE_CHROME_SAFE_STORAGE_PASSWORD`, or `SWEET_COOKIE_BRAVE_SAFE_STORAGE_PASSWORD` options for encrypted Chrome/Chromium/Brave cookies.
295
311
  - Re-run `/oracle-auth`.
296
312
  - Agent callers can use `oracle_auth({})` once before retrying a stale-auth oracle submission.
297
313
  - If the provider is half-logged-in or challenge flow state looks weird, finish the login/challenge in the headed auth browser and retry.
@@ -304,7 +320,7 @@ This usually means the cookie import worked but the source cookies are not the a
304
320
  2. Confirm the selected provider works there without logging in again.
305
321
  3. Quit the browser fully so its `Cookies` DB is stable.
306
322
  4. Confirm `auth.chromeCookiePath` points at that exact profile's `Cookies` DB.
307
- 5. Confirm `auth.chromiumKeychain.services` names the browser's safe-storage Keychain service for that DB.
323
+ 5. On macOS, confirm `auth.chromiumKeychain.services` names the browser's safe-storage Keychain service for that DB. On Linux, confirm the relevant Sweet Cookie keyring helper or Chrome/Brave safe-storage password override is available.
308
324
  6. Re-run `/oracle-auth`.
309
325
 
310
326
  ### You hit a challenge or verification page
@@ -330,14 +346,14 @@ This usually means the cookie import worked but the source cookies are not the a
330
346
  - The command returns a `Retry after ...` timestamp when that guard is active.
331
347
  - Wait until that time, then rerun `/oracle-clean <job-id|all>`.
332
348
 
333
- ### `agent-browser`, `tar`, or `zstd` is missing
349
+ ### A local dependency like `agent-browser`, `tar`, or `zstd` is missing
334
350
 
335
- Install the missing local dependency and rerun the command.
351
+ Install the missing local dependency and rerun the command. On macOS APFS clone mode, `cp` must also be available on PATH or configured with `PI_ORACLE_CP_PATH`; Linux and Windows profile copies use Node's recursive copy.
336
352
 
337
353
  ### Auto-detection picked the wrong browser profile
338
354
 
339
355
  - Set `auth.chromeProfile` in `~/.pi/agent/extensions/oracle.json`.
340
- - For custom Chromium cookie sources, set `auth.chromeCookiePath` to the exact profile `Cookies` DB and pair it with `auth.chromiumKeychain`.
356
+ - For custom Chromium cookie sources, set `auth.chromeCookiePath` to the exact profile `Cookies` DB. Pair it with `auth.chromiumKeychain` only on macOS; on Linux, rely on Sweet Cookie's keyring/password environment options.
341
357
  - Re-run `/oracle-auth`.
342
358
 
343
359
  ### You want more details about a failed run
@@ -350,6 +366,7 @@ Useful local checks:
350
366
 
351
367
  ```bash
352
368
  npm run check:oracle-extension
369
+ npm run check:platform-smoke
353
370
  npm run typecheck
354
371
  npm run typecheck:worker-helpers
355
372
  npm run sanity:oracle
@@ -358,9 +375,26 @@ npm test
358
375
  npm run verify:oracle
359
376
  ```
360
377
 
361
- `npm publish` is guarded by `prepublishOnly`, which runs `npm run verify:oracle`.
378
+ `npm publish` is guarded by `prepublishOnly`, which runs `npm run release:check`. That release gate requires doctor-first macOS, Ubuntu, and Windows native Crabbox evidence. The required Crabbox runtime suite uses packed-install proof, not source-tree `pi -e` loading.
379
+
380
+ Use the narrowest validation workflow that proves the change:
381
+
382
+ | Situation | Command(s) |
383
+ | --- | --- |
384
+ | Everyday local iteration | `npm run verify:oracle` |
385
+ | Platform-sensitive changes | `npm run smoke:platform:doctor`, then a focused `node scripts/platform-smoke.mjs run --target <target> --suite <suite>` |
386
+ | Platform matrix proof | `npm run smoke:platform:all` |
387
+ | Publish/release gate | `npm run release:check` |
388
+
389
+ For macOS, Ubuntu, and Windows native package/build plus packed runtime validation, use [`docs/platform-smoke.md`](docs/platform-smoke.md). The full release gate is:
390
+
391
+ ```bash
392
+ npm run release:check
393
+ ```
394
+
395
+ The real runtime suite defaults to deterministic installed-tool execution so platform proof stays bounded. Provider/model defaults remain `zai/glm-5.1` for doctor/config and for optional model-agent debugging; override with `PI_ORACLE_REAL_TEST_PROVIDER` and `PI_ORACLE_REAL_TEST_MODEL` when needed. For inner-loop source loading only, use `npm run smoke:real:source`; it is not release proof. Set `PI_ORACLE_REAL_TEST_MODEL_AGENT=1` only when debugging the slower model-agent path. The optional second real-agent negative symlink check is opt-in via `PI_ORACLE_REAL_TEST_NEGATIVE_SYMLINK=1`; `npm run sanity:oracle` covers archive/symlink rejection by default without adding another model-agent turn to the platform release gate.
362
396
 
363
- For end-to-end local-extension smoke testing, use [`docs/ORACLE_ISOLATED_PI_VALIDATION.md`](docs/ORACLE_ISOLATED_PI_VALIDATION.md). That workflow launches isolated `pi` sessions against this checkout and uses `instant` or `thinking_light`, as required by the project validation policy.
397
+ For manual end-to-end local-extension smoke testing, use [`docs/ORACLE_ISOLATED_PI_VALIDATION.md`](docs/ORACLE_ISOLATED_PI_VALIDATION.md). That workflow launches isolated `pi` coding-agent sessions against this checkout and uses `instant` or `thinking_light`, as required by the project validation policy.
364
398
 
365
399
  ## Project map
366
400
 
@@ -373,6 +407,7 @@ For end-to-end local-extension smoke testing, use [`docs/ORACLE_ISOLATED_PI_VALI
373
407
  | [`prompts/oracle.md`](prompts/oracle.md) | `/oracle` prompt-template workflow |
374
408
  | [`prompts/oracle-followup.md`](prompts/oracle-followup.md) | `/oracle-followup` prompt-template workflow |
375
409
  | `scripts/oracle-sanity-*` | Local sanity and archive-safety checks |
410
+ | `scripts/platform-smoke*` | Crabbox macOS, Ubuntu, and Windows release smoke gate |
376
411
  | [`docs/ORACLE_DESIGN.md`](docs/ORACLE_DESIGN.md) | Architecture, lifecycle, queueing, persistence, recovery behavior |
377
412
  | [`docs/ORACLE_ISOLATED_PI_VALIDATION.md`](docs/ORACLE_ISOLATED_PI_VALIDATION.md) | Repeatable isolated `pi` validation workflow |
378
413
  | [`docs/ORACLE_RECOVERY_DRILL.md`](docs/ORACLE_RECOVERY_DRILL.md) | Safe expired-auth recovery drill |
@@ -1,13 +1,14 @@
1
1
  # pi-oracle design
2
2
 
3
- Status: isolated-profile concurrency architecture implemented in code; major live validation now passes, but a few non-blocking hardening items remain.
4
- Date: 2026-04-03
3
+ Status: isolated-profile concurrency architecture implemented in code and validated against the current pi baseline.
4
+ Date: 2026-06-04
5
5
 
6
6
  Companion doc:
7
7
  - `docs/ORACLE_RECOVERY_DRILL.md` — safe expired-auth recovery validation drill
8
8
 
9
9
  Compatibility target:
10
- - `pi` 0.65.0+
10
+ - `pi` 0.78.1+ is the suggested tested floor for current mode-aware poller behavior
11
+ - package metadata keeps pi runtime packages as optional wildcard peers, so this suggested floor is not enforced as a hard npm install requirement
11
12
  - current extension lifecycle only; no backward-compatibility shims for removed `session_switch` / `session_fork` events
12
13
 
13
14
  ## Goal
@@ -246,7 +247,7 @@ Browser/auth settings are global-only because they control local privileged brow
246
247
  "authSeedProfileDir": "<absolute path to oracle auth seed profile>",
247
248
  "runtimeProfilesDir": "<absolute path to oracle runtime profiles dir>",
248
249
  "maxConcurrentJobs": 2,
249
- "cloneStrategy": "apfs-clone",
250
+ "cloneStrategy": "copy",
250
251
  "chatUrl": "https://chatgpt.com/",
251
252
  "authUrl": "https://chatgpt.com/auth/login",
252
253
  "runMode": "headless",
@@ -260,7 +261,7 @@ Browser/auth settings are global-only because they control local privileged brow
260
261
  "chromeProfile": "<optional Chrome/Chromium profile name>",
261
262
  "chromeCookiePath": "<optional absolute path to Chromium Cookies DB>",
262
263
  "chromiumKeychain": {
263
- "account": "<macOS Keychain account for non-built-in Chromium browsers>",
264
+ "account": "<macOS-only Keychain account for non-built-in Chromium browsers>",
264
265
  "services": ["<safe-storage service name>"],
265
266
  "label": "<optional human-readable label>"
266
267
  }
@@ -282,9 +283,13 @@ Browser/auth settings are global-only because they control local privileged brow
282
283
  }
283
284
  ```
284
285
 
285
- `auth.chromiumKeychain` is an opt-in alternate cookie source for Chromium-family browsers that are not handled by the default `@steipete/sweet-cookie` Chrome-compatible importer. It must be configured with `auth.chromeCookiePath`; partial config is rejected so `/oracle-auth` cannot silently fall back to a different browser profile.
286
+ `browser.cloneStrategy` defaults to `apfs-clone` on macOS and `copy` on Linux/Windows. macOS APFS clone mode uses `cp -cR` and preflights `cp`; set `PI_ORACLE_CP_PATH` only when the default PATH lookup cannot find the intended copy executable. Linux and Windows runtime profile copies use Node's recursive copy instead of depending on POSIX `cp`.
286
287
 
287
- When both `auth.chromeCookiePath` and `auth.chromiumKeychain` are present, auth bootstrap:
288
+ The default `/oracle-auth` cookie importer delegates to `@steipete/sweet-cookie`'s Chrome/Chromium backend. On Linux, pi-oracle auto-detects existing Google Chrome, Chromium, Chromium Browser, or Brave profile roots under `${XDG_CONFIG_HOME:-~/.config}` and passes non-Google roots as absolute profile paths so Sweet Cookie reads the intended cookie DB. pi-oracle does not currently select Sweet Cookie's Edge or Firefox backends. Encrypted Linux Chromium cookies are handled by Sweet Cookie via `secret-tool`, `kwallet-query`/`dbus-send`, `SWEET_COOKIE_LINUX_KEYRING=gnome|kwallet|basic`, or the `SWEET_COOKIE_CHROME_SAFE_STORAGE_PASSWORD` / `SWEET_COOKIE_BRAVE_SAFE_STORAGE_PASSWORD` overrides. Prefer keyring helpers over password environment variables; if a password override is used for `/oracle-auth`, pi-oracle scrubs it before launching browser/helper subprocesses after cookie import.
289
+
290
+ `auth.chromiumKeychain` is a macOS-only opt-in alternate cookie source for Chromium-family browsers that are not handled by the default `@steipete/sweet-cookie` Chrome-compatible importer. It must be configured with `auth.chromeCookiePath`; partial config is rejected so `/oracle-auth` cannot silently fall back to a different browser profile. On Linux, valid config should leave `auth.chromiumKeychain` unset and use Sweet Cookie's Linux keyring/password options instead.
291
+
292
+ When both `auth.chromeCookiePath` and `auth.chromiumKeychain` are present on macOS, auth bootstrap:
288
293
 
289
294
  1. reads the configured macOS Keychain safe-storage password using `account` and the ordered `services` list
290
295
  2. snapshots the Chromium `Cookies` DB plus `Cookies-wal` / `Cookies-shm` sidecars, tolerating sidecars that disappear while the browser is closing
@@ -292,7 +297,7 @@ When both `auth.chromeCookiePath` and `auth.chromiumKeychain` are present, auth
292
297
  4. dedupes duplicate cookie rows by keeping the first row after newest-expiry ordering
293
298
  5. filters importable provider auth cookies and seeds the isolated oracle auth profile
294
299
 
295
- Operational requirements for this path:
300
+ Operational requirements for this macOS-only path:
296
301
 
297
302
  - ChatGPT or Grok must already be logged in in the configured browser profile, depending on the provider being synced.
298
303
  - The target browser should be fully quit before `/oracle-auth` so the cookie DB snapshot is stable.
@@ -633,3 +638,6 @@ Recent proof points:
633
638
  - expired-auth drill post-repair success: `fa26a2a7-0057-4a21-b3e0-71c1d020facf`
634
639
  - successful multi-artifact completion: `b6b3599c-6b91-4315-adfa-8a83aa5eda9b`
635
640
  - repo-owned sanity harness: `npm run sanity:oracle`
641
+ - real installed-extension smoke source of truth: `scripts/oracle-real-smoke.mjs`; required release proof runs packed-install mode (`npm run smoke:real:packed`) and executes installed-package `oracle_submit` deterministically, with optional slower model-agent debugging via `PI_ORACLE_REAL_TEST_MODEL_AGENT=1`; source mode (`npm run smoke:real:source`) is inner-loop/debug only
642
+ - macOS, Ubuntu, and Windows native package/build/runtime smoke source of truth: `docs/platform-smoke.md`; use `npm run verify:oracle` for everyday local iteration, `npm run smoke:platform:doctor` plus a focused target/suite run for platform-sensitive changes, `npm run smoke:platform:all` for doctor-first platform matrix evidence, and `npm run release:check` for the full local-plus-platform release gate
643
+ - release gate: `npm run release:check`, also used by `prepublishOnly`, combines static verification and all required Crabbox platform smokes
@@ -0,0 +1,156 @@
1
+ # pi-oracle Crabbox platform smoke
2
+
3
+ `pi-oracle` uses Crabbox for the local release-blocking platform gate. The gate runs on macOS, Ubuntu Linux, and native Windows and is meant to catch broken package installs, platform assumptions, and real `pi` tool-call failures before push or publish.
4
+
5
+ ## Source of truth
6
+
7
+ - Config: [`../platform-smoke.config.mjs`](../platform-smoke.config.mjs)
8
+ - CLI: [`../scripts/platform-smoke.mjs`](../scripts/platform-smoke.mjs)
9
+ - Target runner: [`../scripts/platform-smoke/targets.mjs`](../scripts/platform-smoke/targets.mjs)
10
+ - Windows build script: [`../scripts/platform-smoke/platform-build-windows.ps1`](../scripts/platform-smoke/platform-build-windows.ps1)
11
+ - Real runtime smoke: [`../scripts/oracle-real-smoke.mjs`](../scripts/oracle-real-smoke.mjs)
12
+ - Artifact root: `.artifacts/platform-smoke/` (gitignored)
13
+
14
+ Required targets: `macos`, `ubuntu`, `windows-native`.
15
+ Required suites: `platform-build`, `real-extension`.
16
+ Crabbox baseline: `0.26.0` or newer.
17
+
18
+ ## Required local setup
19
+
20
+ Install Crabbox with Homebrew and keep it on `PATH`:
21
+
22
+ ```bash
23
+ brew install openclaw/tap/crabbox
24
+ crabbox --version
25
+ crabbox providers
26
+ ```
27
+
28
+ `PLATFORM_SMOKE_CRABBOX` is the reusable binary override. `PI_ORACLE_SMOKE_CRABBOX` is a project-specific alias and wins when both are set.
29
+
30
+ Target setup:
31
+
32
+ - macOS: Remote Login enabled; noninteractive `ssh $USER@localhost` works; `node`, `npm`, `git`, `tar`, `rsync`, `zstd`, and `agent-browser` are on the SSH PATH.
33
+ - Ubuntu: Docker is running and the configured image (`PI_ORACLE_SMOKE_UBUNTU_IMAGE`, default `pi-oracle-platform-smoke:node24`) has `node`, `npm`, `git`, `tar`, `rsync`, `zstd`, and `agent-browser` on PATH. Build the local image when needed with `docker build -t pi-oracle-platform-smoke:node24 -f scripts/platform-smoke/Dockerfile.ubuntu .`.
34
+ - Windows native: Parallels has stopped source VM `pi-extension-windows-template` and the configured power-off snapshot (`crabbox-ready` by default for this repo). The template must have OpenSSH, PowerShell, Git, Node/npm, `tar`, `zstd`, and `agent-browser` on PATH. Do not bake API keys, browser sessions, project checkouts, `.pi` state, artifacts, or secrets into the template.
35
+
36
+ Real runtime suite auth:
37
+
38
+ - Default deterministic installed-tool smoke does not require provider API keys.
39
+ - Provider/model defaults remain `zai/glm-5.1` for optional model-agent debugging.
40
+ - Set `PI_ORACLE_REAL_TEST_MODEL_AGENT=1` to run the slower model-agent path; then the provider auth env is required (`ZAI_API_KEY` by default, reported only as present/redacted).
41
+ - Override with `PI_ORACLE_REAL_TEST_PROVIDER` and `PI_ORACLE_REAL_TEST_MODEL`; auth variable names live in `platform-smoke.config.mjs`.
42
+
43
+ ## Canonical validation workflows
44
+
45
+ Use the narrowest workflow that proves the change. Do not run the full platform matrix for ordinary edits when the local gate and cheap invariants prove the change.
46
+
47
+ | Situation | Canonical command(s) | What it proves |
48
+ | --- | --- | --- |
49
+ | Everyday local iteration | `npm run verify:oracle` | Syntax, bundle, platform-smoke invariants, type checks, oracle sanity, and package dry-run pass locally. |
50
+ | Platform-sensitive change | `npm run smoke:platform:doctor`, then `node scripts/platform-smoke.mjs run --target <target> --suite <suite>` | Target setup is ready and the affected platform/suite works without paying for unrelated targets. |
51
+ | Platform matrix proof | `npm run smoke:platform:all` | Doctor-first packed-install proof passes on every required target and suite. |
52
+ | Publish/release gate | `npm run release:check` | Local verification (`verify:oracle`) passes, then the doctor-first platform matrix passes. |
53
+
54
+ Platform-sensitive changes include archive behavior, process cleanup, runtime/browser profile handling, package metadata, Crabbox harness code, or anything that may differ across macOS/Linux/Windows.
55
+
56
+ ## Commands
57
+
58
+ Doctor is mandatory before the full platform matrix. The canonical all-target platform command enforces that:
59
+
60
+ ```bash
61
+ npm run smoke:platform:all
62
+ ```
63
+
64
+ Focused commands:
65
+
66
+ ```bash
67
+ npm run smoke:platform:doctor
68
+ npm run smoke:platform:macos
69
+ npm run smoke:platform:ubuntu
70
+ npm run smoke:platform:windows-native
71
+ node scripts/platform-smoke.mjs run --target windows-native --suite real-extension
72
+ ```
73
+
74
+ Full release gate:
75
+
76
+ ```bash
77
+ npm run release:check
78
+ ```
79
+
80
+ `release:check` runs `verify:oracle` before `smoke:platform:all`, matching the Crabbox doctor-first release order: cheap harness checks, doctor, full matrix, then artifact review. `prepublishOnly` runs `npm run release:check`.
81
+
82
+ ## What `platform-build` proves
83
+
84
+ On each required target, `platform-build`:
85
+
86
+ 1. checks Node major version against `nodeValidationMajor`;
87
+ 2. runs `npm ci`;
88
+ 3. requires target tools (`zstd`, `agent-browser`) to already be available from target setup;
89
+ 4. runs `npm run verify:oracle:platform`, the platform-focused gate for syntax, platform-smoke invariants, real-smoke script syntax, platform-sensitive oracle sanity coverage, and package dry-run;
90
+ 5. runs `npm pack`;
91
+ 6. creates a fresh target-local pi project;
92
+ 7. runs `npm install --no-save <packed tarball>`;
93
+ 8. runs `pi install -l ./node_modules/pi-oracle`;
94
+ 9. runs `pi list`;
95
+ 10. asserts the installed package came from `node_modules/pi-oracle` and did not use `pi -e` / source-extension shortcuts.
96
+
97
+ ## What `real-extension` proves
98
+
99
+ `real-extension` is required release proof. It runs `npm run smoke:real:packed` on each target, which:
100
+
101
+ 1. packs this checkout with `npm pack`;
102
+ 2. installs the tarball into a clean pi project;
103
+ 3. runs `pi install -l ./node_modules/pi-oracle`;
104
+ 4. asserts `pi list` shows the packed install path;
105
+ 5. executes `oracle_submit` from the installed package path, not source `pi -e`;
106
+ 6. asserts whole-project archive creation and default exclusions.
107
+
108
+ The default runtime suite executes the installed tool directly so platform proof is deterministic and bounded instead of waiting on a model turn. Set `PI_ORACLE_REAL_TEST_MODEL_AGENT=1` only when you specifically need to debug the slower model-agent path. Symlink escape rejection and other negative archive cases are covered by `npm run sanity:oracle`; the optional second-agent negative check is available with `PI_ORACLE_REAL_TEST_NEGATIVE_SYMLINK=1` when debugging that path.
109
+
110
+ For inner-loop/debug only, use:
111
+
112
+ ```bash
113
+ npm run smoke:real:source
114
+ ```
115
+
116
+ That source-mode smoke loads `extensions/oracle/index.ts` with `pi --no-extensions -e`; it is useful while developing but is not release proof.
117
+
118
+ ## Artifacts
119
+
120
+ Each suite writes reviewable evidence under:
121
+
122
+ ```text
123
+ .artifacts/platform-smoke/<run-id>/<target>/<suite>/
124
+ summary.json
125
+ target.json
126
+ suite.json
127
+ command.txt
128
+ exit-code.txt
129
+ crabbox.stdout.txt
130
+ crabbox.stderr.txt
131
+ crabbox.timing.json
132
+ crabbox.stop.stdout.txt
133
+ crabbox.stop.stderr.txt
134
+ crabbox.stop.exit-code.txt
135
+ assertions.json
136
+ artifact-manifest.json
137
+ failures.md # only on failure
138
+ ```
139
+
140
+ `platform-build` also writes packed install extracts (`packed-tarball.txt`, `packed-node-install.*`, `pi-install.*`, `pi-list.*`). Passing suites require `summary.ok === true`, `assertions.ok === true`, and `artifact-manifest.missing.length === 0`.
141
+
142
+ Artifacts are local evidence only. Do not commit or share them without redaction. Secret scans fail on bearer/API-key/cookie-like values.
143
+
144
+ ## Windows template maintenance
145
+
146
+ When Windows lacks a reusable tool such as `zstd` or `agent-browser`, update the shared `pi-extension-windows-template` infrastructure rather than adding a per-run installer:
147
+
148
+ 1. revert/switch `pi-extension-windows-template` to the current canonical `crabbox-ready` snapshot;
149
+ 2. boot the template;
150
+ 3. install/update the reusable tool globally without secrets;
151
+ 4. verify from a fresh SSH session: `node --version`, `npm --version`, `git --version`, `tar --version`, `zstd --version`, `agent-browser --version`, and `agent-browser install`;
152
+ 5. remove downloads, caches, checkouts, `.pi`, `.artifacts`, `.debug`, browser auth/session state, and secrets;
153
+ 6. shut down cleanly;
154
+ 7. create/promote the configured power-off `crabbox-ready` snapshot;
155
+ 8. run `npm run smoke:platform:doctor` and `npm run smoke:platform:windows-native` against the promoted snapshot;
156
+ 9. clean stale clones/leases.
@@ -39,9 +39,13 @@ export default function oracleExtension(pi: ExtensionAPI) {
39
39
  function startPollerForContext(ctx: ExtensionContext) {
40
40
  try {
41
41
  const sessionFile = getSessionFile(ctx);
42
+ if (ctx.mode === "print" || ctx.mode === "json") {
43
+ stopPoller(ctx);
44
+ return;
45
+ }
42
46
  if (!hasPersistedSessionFile(sessionFile)) {
43
47
  stopPoller(ctx);
44
- ctx.ui.setStatus("oracle", ctx.ui.theme.fg("accent", "oracle: unavailable"));
48
+ if (ctx.hasUI) ctx.ui.setStatus("oracle", ctx.ui.theme.fg("accent", "oracle: unavailable"));
45
49
  return;
46
50
  }
47
51
 
@@ -49,15 +53,17 @@ export default function oracleExtension(pi: ExtensionAPI) {
49
53
  void runStartupMaintenance(ctx).catch((error) => {
50
54
  const message = `Oracle startup maintenance failed: ${error instanceof Error ? error.message : String(error)}`;
51
55
  console.error(message);
52
- ctx.ui.notify(message, "warning");
56
+ if (ctx.hasUI) ctx.ui.notify(message, "warning");
53
57
  });
54
58
  startPoller(pi, ctx, config.poller.intervalMs, workerPath);
55
59
  refreshOracleStatus(ctx);
56
60
  } catch (error) {
57
61
  const message = error instanceof Error ? error.message : String(error);
58
62
  stopPoller(ctx);
59
- ctx.ui.setStatus("oracle", ctx.ui.theme.fg("error", "oracle: config error"));
60
- ctx.ui.notify(message, "warning");
63
+ if (ctx.hasUI) {
64
+ ctx.ui.setStatus("oracle", ctx.ui.theme.fg("error", "oracle: config error"));
65
+ ctx.ui.notify(message, "warning");
66
+ }
61
67
  }
62
68
  }
63
69