@blackbelt-technology/pi-agent-dashboard 0.5.0 → 0.5.2
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.
- package/AGENTS.md +26 -5
- package/README.md +49 -7
- package/docs/architecture.md +129 -1
- package/package.json +15 -15
- package/packages/extension/package.json +11 -3
- package/packages/extension/src/__tests__/ask-user-tool.test.ts +1 -1
- package/packages/extension/src/__tests__/bridge-slash-command-routing.test.ts +362 -0
- package/packages/extension/src/__tests__/command-handler.test.ts +78 -8
- package/packages/extension/src/__tests__/enrich-model-metadata.test.ts +1 -1
- package/packages/extension/src/__tests__/extension-slash-command-detection.test.ts +107 -0
- package/packages/extension/src/__tests__/no-tui-multiselect-arm-regression.test.ts +1 -1
- package/packages/extension/src/__tests__/prompt-expander.test.ts +110 -1
- package/packages/extension/src/__tests__/provider-register-reload.test.ts +74 -0
- package/packages/extension/src/__tests__/retry-tracker.test.ts +147 -0
- package/packages/extension/src/__tests__/server-launcher-launch.test.ts +78 -0
- package/packages/extension/src/__tests__/session-sync.test.ts +72 -0
- package/packages/extension/src/__tests__/usage-limit-orderer.test.ts +105 -0
- package/packages/extension/src/ask-user-tool.ts +1 -1
- package/packages/extension/src/bridge-context.ts +68 -4
- package/packages/extension/src/bridge.ts +79 -11
- package/packages/extension/src/command-handler.ts +95 -15
- package/packages/extension/src/flow-event-wiring.ts +1 -1
- package/packages/extension/src/multiselect-list.ts +1 -1
- package/packages/extension/src/pi-env.d.ts +16 -9
- package/packages/extension/src/prompt-expander.ts +74 -63
- package/packages/extension/src/provider-register.ts +16 -9
- package/packages/extension/src/retry-tracker.ts +123 -0
- package/packages/extension/src/server-launcher.ts +31 -70
- package/packages/extension/src/session-sync.ts +10 -1
- package/packages/extension/src/slash-dispatch.ts +123 -0
- package/packages/extension/src/usage-limit-orderer.ts +76 -0
- package/packages/server/bin/pi-dashboard.mjs +84 -0
- package/packages/server/package.json +8 -7
- package/packages/server/scripts/fix-pty-permissions.cjs +52 -0
- package/packages/server/src/__tests__/changelog-fs.test.ts +171 -0
- package/packages/server/src/__tests__/changelog-parser.test.ts +220 -0
- package/packages/server/src/__tests__/changelog-remote.test.ts +193 -0
- package/packages/server/src/__tests__/cli-parse.test.ts +16 -4
- package/packages/server/src/__tests__/directory-service-openspec-enabled.test.ts +187 -0
- package/packages/server/src/__tests__/directory-service-refresh-force.test.ts +1 -1
- package/packages/server/src/__tests__/directory-service-specs-mtime.test.ts +1 -1
- package/packages/server/src/__tests__/directory-service-toctou.test.ts +1 -1
- package/packages/server/src/__tests__/directory-service.test.ts +2 -2
- package/packages/server/src/__tests__/dispatch-extension-command-router.test.ts +178 -0
- package/packages/server/src/__tests__/e2e/model-proxy-google-flash.test.ts +184 -0
- package/packages/server/src/__tests__/event-wiring-providers-list.test.ts +68 -1
- package/packages/server/src/__tests__/fixtures/pi-changelog-slice.md +180 -0
- package/packages/server/src/__tests__/fork-empty-session-preflight.test.ts +268 -0
- package/packages/server/src/__tests__/headless-pid-registry.test.ts +316 -0
- package/packages/server/src/__tests__/is-pi-process.test.ts +1 -1
- package/packages/server/src/__tests__/keeper-manager.test.ts +298 -0
- package/packages/server/src/__tests__/legacy-pi-cleanup.test.ts +149 -0
- package/packages/server/src/__tests__/model-proxy-api-key-routes.test.ts +277 -0
- package/packages/server/src/__tests__/model-proxy-auth-gate.test.ts +263 -0
- package/packages/server/src/__tests__/model-proxy-multi-user.test.ts +169 -0
- package/packages/server/src/__tests__/model-proxy-routes.test.ts +286 -0
- package/packages/server/src/__tests__/model-proxy-second-port.test.ts +116 -0
- package/packages/server/src/__tests__/openspec-connect-snapshot.test.ts +64 -8
- package/packages/server/src/__tests__/openspec-group-broadcast.test.ts +97 -0
- package/packages/server/src/__tests__/openspec-group-join.test.ts +80 -0
- package/packages/server/src/__tests__/openspec-group-routes.test.ts +370 -0
- package/packages/server/src/__tests__/openspec-group-store.test.ts +496 -0
- package/packages/server/src/__tests__/package-manager-wrapper-resolve.test.ts +4 -4
- package/packages/server/src/__tests__/package-routes.test.ts +1 -1
- package/packages/server/src/__tests__/pending-fork-registry.test.ts +48 -24
- package/packages/server/src/__tests__/pi-ai-shape.test.ts +147 -0
- package/packages/server/src/__tests__/pi-changelog-integration.test.ts +165 -0
- package/packages/server/src/__tests__/pi-changelog-routes.test.ts +409 -0
- package/packages/server/src/__tests__/pi-core-checker.test.ts +155 -13
- package/packages/server/src/__tests__/pi-core-updater-managed-path.test.ts +62 -3
- package/packages/server/src/__tests__/pi-core-updater.test.ts +1 -1
- package/packages/server/src/__tests__/pi-dashboard-bin-wrapper.test.ts +84 -0
- package/packages/server/src/__tests__/pi-dev-version-check.test.ts +184 -0
- package/packages/server/src/__tests__/pi-version-skew.test.ts +4 -4
- package/packages/server/src/__tests__/process-manager-keeper-spawn.test.ts +206 -0
- package/packages/server/src/__tests__/provider-auth-routes.test.ts +12 -4
- package/packages/server/src/__tests__/provider-catalogue-cache.test.ts +13 -23
- package/packages/server/src/__tests__/provider-routes-recursion-guard.test.ts +131 -0
- package/packages/server/src/__tests__/recommended-routes.test.ts +3 -3
- package/packages/server/src/__tests__/spawn-correlation-token-integration.test.ts +91 -0
- package/packages/server/src/__tests__/spawn-register-watchdog.test.ts +84 -0
- package/packages/server/src/__tests__/spawn-token.test.ts +57 -0
- package/packages/server/src/__tests__/tunnel-watchdog.test.ts +139 -0
- package/packages/server/src/auth-plugin.ts +3 -0
- package/packages/server/src/bootstrap-state.ts +10 -0
- package/packages/server/src/browser-gateway.ts +27 -10
- package/packages/server/src/browser-handlers/handler-context.ts +9 -0
- package/packages/server/src/browser-handlers/session-action-handler.ts +128 -19
- package/packages/server/src/changelog-fs.ts +167 -0
- package/packages/server/src/changelog-parser.ts +321 -0
- package/packages/server/src/changelog-remote.ts +134 -0
- package/packages/server/src/cli.ts +62 -82
- package/packages/server/src/config-api.ts +14 -2
- package/packages/server/src/directory-service.ts +106 -4
- package/packages/server/src/event-wiring.ts +90 -6
- package/packages/server/src/headless-pid-registry.ts +344 -37
- package/packages/server/src/legacy-pi-cleanup.ts +151 -0
- package/packages/server/src/model-proxy/__tests__/api-key-store.test.ts +142 -0
- package/packages/server/src/model-proxy/__tests__/auth-json-contention.test.ts +98 -0
- package/packages/server/src/model-proxy/__tests__/concurrency.test.ts +107 -0
- package/packages/server/src/model-proxy/__tests__/failed-auth-backoff.test.ts +46 -0
- package/packages/server/src/model-proxy/__tests__/recursion-guard.test.ts +61 -0
- package/packages/server/src/model-proxy/__tests__/streamer.test.ts +139 -0
- package/packages/server/src/model-proxy/api-key-store.ts +87 -0
- package/packages/server/src/model-proxy/auth-gate.ts +116 -0
- package/packages/server/src/model-proxy/concurrency.ts +76 -0
- package/packages/server/src/model-proxy/convert/UPSTREAM.md +13 -0
- package/packages/server/src/model-proxy/convert/__tests__/anthropic-in.test.ts +137 -0
- package/packages/server/src/model-proxy/convert/__tests__/anthropic-out.test.ts +183 -0
- package/packages/server/src/model-proxy/convert/__tests__/openai-in.test.ts +134 -0
- package/packages/server/src/model-proxy/convert/__tests__/openai-out.test.ts +166 -0
- package/packages/server/src/model-proxy/convert/anthropic-in.ts +129 -0
- package/packages/server/src/model-proxy/convert/anthropic-out.ts +173 -0
- package/packages/server/src/model-proxy/convert/index.ts +8 -0
- package/packages/server/src/model-proxy/convert/openai-in.ts +119 -0
- package/packages/server/src/model-proxy/convert/openai-out.ts +151 -0
- package/packages/server/src/model-proxy/convert/types.ts +70 -0
- package/packages/server/src/model-proxy/failed-auth-backoff.ts +45 -0
- package/packages/server/src/model-proxy/internal-auth-storage.ts +146 -0
- package/packages/server/src/model-proxy/internal-registry.ts +157 -0
- package/packages/server/src/model-proxy/recursion-guard.ts +72 -0
- package/packages/server/src/model-proxy/registry-singleton.ts +109 -0
- package/packages/server/src/model-proxy/request-log.ts +53 -0
- package/packages/server/src/model-proxy/streamer.ts +59 -0
- package/packages/server/src/openspec-group-store.ts +490 -0
- package/packages/server/src/pending-client-correlations.ts +73 -0
- package/packages/server/src/pending-fork-registry.ts +24 -12
- package/packages/server/src/pi-core-checker.ts +77 -17
- package/packages/server/src/pi-core-updater.ts +16 -6
- package/packages/server/src/pi-dev-version-check.ts +145 -0
- package/packages/server/src/pi-gateway.ts +4 -0
- package/packages/server/src/pi-version-skew.ts +12 -4
- package/packages/server/src/process-manager.ts +182 -11
- package/packages/server/src/provider-auth-storage.ts +29 -47
- package/packages/server/src/provider-catalogue-cache.ts +24 -18
- package/packages/server/src/restart-helper.ts +17 -16
- package/packages/server/src/routes/bootstrap-routes.ts +37 -0
- package/packages/server/src/routes/jj-routes.ts +3 -0
- package/packages/server/src/routes/model-proxy-api-key-routes.ts +168 -0
- package/packages/server/src/routes/model-proxy-refresh-routes.ts +24 -0
- package/packages/server/src/routes/model-proxy-routes.ts +330 -0
- package/packages/server/src/routes/openspec-group-routes.ts +231 -0
- package/packages/server/src/routes/pi-changelog-routes.ts +194 -0
- package/packages/server/src/routes/pi-core-routes.ts +1 -1
- package/packages/server/src/routes/provider-auth-routes.ts +8 -1
- package/packages/server/src/routes/provider-routes.ts +28 -5
- package/packages/server/src/routes/system-routes.ts +44 -2
- package/packages/server/src/rpc-keeper/__tests__/fixtures/mock-pi-shim.sh +9 -0
- package/packages/server/src/rpc-keeper/__tests__/fixtures/mock-pi.cjs +50 -0
- package/packages/server/src/rpc-keeper/__tests__/keeper.test.ts +371 -0
- package/packages/server/src/rpc-keeper/dispatch-router.ts +85 -0
- package/packages/server/src/rpc-keeper/keeper-manager.ts +364 -0
- package/packages/server/src/rpc-keeper/keeper.cjs +313 -0
- package/packages/server/src/server.ts +254 -60
- package/packages/server/src/session-api.ts +63 -4
- package/packages/server/src/session-discovery.ts +1 -1
- package/packages/server/src/session-file-reader.ts +1 -1
- package/packages/server/src/spawn-register-watchdog.ts +62 -7
- package/packages/server/src/spawn-token.ts +20 -0
- package/packages/server/src/tunnel-watchdog.ts +230 -0
- package/packages/server/src/tunnel.ts +5 -1
- package/packages/shared/package.json +1 -1
- package/packages/shared/src/__tests__/binary-lookup-resolveJiti.test.ts +228 -0
- package/packages/shared/src/__tests__/bootstrap/__snapshots__/cube.test.ts.snap +24 -17
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/a-electron.test.ts.snap +5 -4
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/b-npm-global.test.ts.snap +6 -5
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/c-dev-monorepo.test.ts.snap +1 -0
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/e-stale-partial.test.ts.snap +5 -4
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/f-cwd-variants.test.ts.snap +2 -1
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/g-windows-specifics.test.ts.snap +5 -3
- package/packages/shared/src/__tests__/bootstrap/fixtures/dev-monorepo.ts +1 -1
- package/packages/shared/src/__tests__/changelog-types.test.ts +78 -0
- package/packages/shared/src/__tests__/config-openspec.test.ts +74 -0
- package/packages/shared/src/__tests__/model-proxy-config.test.ts +146 -0
- package/packages/shared/src/__tests__/no-raw-node-import.test.ts +7 -5
- package/packages/shared/src/__tests__/node-spawn-jiti-contract.test.ts +56 -20
- package/packages/shared/src/__tests__/node-spawn.test.ts +51 -0
- package/packages/shared/src/__tests__/openspec-groups-types.test.ts +135 -0
- package/packages/shared/src/__tests__/publish-workflow-contract.test.ts +96 -0
- package/packages/shared/src/__tests__/recommended-extensions.test.ts +11 -3
- package/packages/shared/src/__tests__/server-launcher.test.ts +227 -0
- package/packages/shared/src/__tests__/tool-registry-definitions.test.ts +1 -1
- package/packages/shared/src/bootstrap-install.ts +1 -1
- package/packages/shared/src/browser-protocol.ts +70 -0
- package/packages/shared/src/changelog-types.ts +111 -0
- package/packages/shared/src/config.ts +172 -2
- package/packages/shared/src/dashboard-plugin/manifest-types.ts +16 -1
- package/packages/shared/src/dashboard-plugin/slot-props.ts +8 -0
- package/packages/shared/src/dashboard-plugin/slot-types.ts +57 -0
- package/packages/shared/src/platform/binary-lookup.ts +204 -0
- package/packages/shared/src/platform/node-spawn.ts +71 -26
- package/packages/shared/src/protocol.ts +27 -1
- package/packages/shared/src/recommended-extensions.ts +18 -0
- package/packages/shared/src/rest-api.ts +219 -1
- package/packages/shared/src/server-launcher.ts +277 -0
- package/packages/shared/src/skill-block-parser.ts +1 -1
- package/packages/shared/src/tool-registry/__tests__/pi-ai-registration.test.ts +124 -0
- package/packages/shared/src/tool-registry/definitions.ts +15 -3
- package/packages/shared/src/types.ts +62 -0
- package/packages/shared/src/__tests__/resolve-jiti.test.ts +0 -53
- package/packages/shared/src/resolve-jiti.ts +0 -102
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.70.0] - 2026-04-23
|
|
4
|
+
|
|
5
|
+
### New Features
|
|
6
|
+
|
|
7
|
+
- Searchable auth provider login flow: the `/login` provider selector now supports fuzzy search/filtering, making it faster to find providers when many are configured. See [docs/providers.md](docs/providers.md). ([#3572](https://github.com/badlogic/pi-mono/pull/3572) by [@mitsuhiko](https://github.com/mitsuhiko))
|
|
8
|
+
- GPT-5.5 Codex support: `openai-codex/gpt-5.5` is available as a model option, including `xhigh` reasoning support and corrected priority-tier pricing.
|
|
9
|
+
- Terminal progress indicators are now opt-in: OSC 9;4 progress reporting during streaming/compaction is off by default and can be toggled via `terminal.showTerminalProgress` in `/settings` ([#3588](https://github.com/badlogic/pi-mono/issues/3588))
|
|
10
|
+
- `--no-builtin-tools` / `createAgentSession({ noTools: "builtin" })` now correctly disables only built-in tools while keeping extension tools active. See [docs/extensions.md](docs/extensions.md) and [README.md](README.md) ([#3592](https://github.com/badlogic/pi-mono/issues/3592))
|
|
11
|
+
|
|
12
|
+
### Breaking Changes
|
|
13
|
+
|
|
14
|
+
- Disabled OSC 9;4 terminal progress indicators by default. Set `terminal.showTerminalProgress` to `true` in `/settings` to re-enable ([#3588](https://github.com/badlogic/pi-mono/issues/3588))
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Added searchable auth provider login flow with fuzzy filtering in the provider selector ([#3572](https://github.com/badlogic/pi-mono/pull/3572) by [@mitsuhiko](https://github.com/mitsuhiko))
|
|
19
|
+
- Added GPT-5.5 Codex model
|
|
20
|
+
- Added auth source labels in `/login` so provider entries can show when auth comes from `--api-key`, an environment variable, or custom provider fallback without exposing secrets.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Updated default model selection across providers to current recommended models.
|
|
25
|
+
- Improved stale extension context errors after session replacement or reload to tell extension authors to avoid captured `pi`/command `ctx` and use `withSession` for post-replacement work.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Fixed `/model` selector cancellation to request render instead of incorrectly triggering login selector.
|
|
30
|
+
- Changed login, OAuth, and extension selectors for more consistent styling.
|
|
31
|
+
- Added Amazon Bedrock setup guidance to `/login` and updated `/model` copy to refer to configured providers instead of only API keys.
|
|
32
|
+
- Improved no-model and missing-auth warnings to point users to `/login` for OAuth or API key setup.
|
|
33
|
+
- Fixed `/quit` shutdown ordering to stop the TUI before extension UI teardown can repaint, preserving the final rendered frame while still emitting `session_shutdown` before process exit.
|
|
34
|
+
- Fixed `SettingsManager.inMemory()` initial settings being lost after reloads triggered by SDK resource loading ([#3616](https://github.com/badlogic/pi-mono/issues/3616))
|
|
35
|
+
- Fixed `models.json` provider compatibility to accept `compat.supportsLongCacheRetention`, allowing proxies to opt out of long-retention cache fields when needed while long retention is enabled by default when requested ([#3543](https://github.com/badlogic/pi-mono/issues/3543))
|
|
36
|
+
- Fixed `--thinking xhigh` for `openai-codex` `gpt-5.5` so it is no longer downgraded to `high`.
|
|
37
|
+
- Fixed git package installs with custom `npmCommand` values such as `pnpm` by avoiding npm-specific production flags in that compatibility path ([#3604](https://github.com/badlogic/pi-mono/issues/3604))
|
|
38
|
+
- Fixed first user messages rendering without spacing after existing notices such as compaction summaries or status messages ([#3613](https://github.com/badlogic/pi-mono/issues/3613))
|
|
39
|
+
- Fixed the handoff extension example to use the replacement-session context after creating a new session, avoiding stale `ctx` errors when it installs the generated prompt ([#3606](https://github.com/badlogic/pi-mono/issues/3606))
|
|
40
|
+
- Fixed session replacement and `/quit` teardown ordering to run host-owned extension UI cleanup synchronously after `session_shutdown` handlers complete but before invalidating the old extension context, preventing stale extension UI from rendering against a disposed session ([#3597](https://github.com/badlogic/pi-mono/pull/3597) by [@vegarsti](https://github.com/vegarsti))
|
|
41
|
+
- Fixed crash on `/quit` when an extension registers a custom footer whose `render()` accesses `ctx`, by tearing down extension-provided UI before invalidating the extension runner during shutdown ([#3595](https://github.com/badlogic/pi-mono/issues/3595))
|
|
42
|
+
- Fixed auto-retry to treat Bedrock/Smithy HTTP/2 transport failures like `http2 request did not get a response` as transient errors, so the agent retries automatically instead of waiting for a manual nudge ([#3594](https://github.com/badlogic/pi-mono/issues/3594))
|
|
43
|
+
- Fixed the CLI/SDK tool-selection split so `--no-builtin-tools` and `createAgentSession({ noTools: "builtin" })` disable only built-in default tools while keeping extension/custom tools enabled, instead of falling through to the same "disable everything" path as `--no-tools` ([#3592](https://github.com/badlogic/pi-mono/issues/3592))
|
|
44
|
+
- Fixed remaining hardcoded `pi` / `.pi` branding to route through `APP_NAME` and `CONFIG_DIR_NAME` extension points, so SDK rebrands get consistent naming in `/quit` description, `process.title`, and the project-local extensions directory ([#3583](https://github.com/badlogic/pi-mono/pull/3583) by [@jlaneve](https://github.com/jlaneve))
|
|
45
|
+
- Fixed `pi-coding-agent` shipping `uuid@11`, which triggered `npm audit` moderate vulnerability reports for downstream installs; the package now depends on `uuid@14` ([#3577](https://github.com/badlogic/pi-mono/issues/3577))
|
|
46
|
+
- Fixed `openai-completions` streamed tool-call assembly to coalesce deltas by stable tool index when OpenAI-compatible gateways mutate tool call IDs mid-stream, preventing malformed Kimi K2.6/OpenCode tool streams from splitting one call into multiple bogus tool calls ([#3576](https://github.com/badlogic/pi-mono/issues/3576))
|
|
47
|
+
- Fixed `ctx.ui.setWorkingMessage()` to persist across loader recreation, matching the behavior of `ctx.ui.setWorkingIndicator()` ([#3566](https://github.com/badlogic/pi-mono/issues/3566))
|
|
48
|
+
- Fixed coding-agent `fs.watch` error handling for theme and git-footer watchers to retry after transient watcher failures such as `EMFILE`, avoiding startup crashes in large repos ([#3564](https://github.com/badlogic/pi-mono/issues/3564))
|
|
49
|
+
- Fixed built-in `kimi-coding` model generation to attach the expected `User-Agent` header so direct Kimi Coding requests use the provider's expected client identity ([#3586](https://github.com/badlogic/pi-mono/issues/3586))
|
|
50
|
+
- Fixed extension shortcut conflict diagnostics to display at startup instead of only on reload, so extension authors discover reserved keybinding conflicts immediately rather than discovering them later through user feedback ([#3617](https://github.com/badlogic/pi-mono/issues/3617))
|
|
51
|
+
- Fixed `models.json` Anthropic-compatible provider configuration to accept `compat.supportsEagerToolInputStreaming`, allowing proxies that reject per-tool `eager_input_streaming` to use the legacy fine-grained tool streaming beta header instead ([#3575](https://github.com/badlogic/pi-mono/issues/3575))
|
|
52
|
+
- Fixed startup banner extension labels to strip trailing `index.js`/`index.ts` suffixes ([#3596](https://github.com/badlogic/pi-mono/pull/3596) by [@aliou](https://github.com/aliou))
|
|
53
|
+
- Fixed OSC 9;4 terminal progress updates to stay alive in terminals such as Ghostty during long-running agent work ([#3610](https://github.com/badlogic/pi-mono/issues/3610))
|
|
54
|
+
- Fixed OpenAI-compatible completion usage parsing to avoid double-counting reasoning tokens already included in `completion_tokens` ([#3581](https://github.com/badlogic/pi-mono/issues/3581))
|
|
55
|
+
- Fixed `openai-responses` compatibility for strict OpenAI-compatible proxies by allowing `models.json` to disable the underscore-containing `session_id` header with `compat.sendSessionIdHeader: false` ([#3579](https://github.com/badlogic/pi-mono/issues/3579))
|
|
56
|
+
- Fixed GPT-5.5 Codex capability handling to clamp unsupported minimal reasoning to `low` and apply the model's 2.5x priority service-tier pricing multiplier ([#3618](https://github.com/badlogic/pi-mono/pull/3618) by [@markusylisiurunen](https://github.com/markusylisiurunen))
|
|
57
|
+
|
|
58
|
+
## [0.69.0] - 2026-04-22
|
|
59
|
+
|
|
60
|
+
### New Features
|
|
61
|
+
|
|
62
|
+
- TypeBox 1.x migration for extensions and SDK integrations, including TypeBox-native tool argument validation that now works in eval-restricted runtimes such as Cloudflare Workers. See [docs/extensions.md](docs/extensions.md) and [docs/sdk.md](docs/sdk.md).
|
|
63
|
+
- Stacked extension autocomplete providers via `ctx.ui.addAutocompleteProvider(...)`, allowing extensions to layer custom completion logic on top of built-in slash and path completion. See [docs/extensions.md#autocomplete-providers](docs/extensions.md#autocomplete-providers) and [examples/extensions/github-issue-autocomplete.ts](examples/extensions/github-issue-autocomplete.ts).
|
|
64
|
+
- Terminating tool results via `terminate: true`, allowing custom tools to end on a final tool call without paying for an automatic follow-up LLM turn. See [docs/extensions.md](docs/extensions.md) and [examples/extensions/structured-output.ts](examples/extensions/structured-output.ts).
|
|
65
|
+
- OSC 9;4 terminal progress indicators during agent streaming and compaction for supporting terminals.
|
|
66
|
+
|
|
67
|
+
### Breaking Changes
|
|
68
|
+
|
|
69
|
+
- Migrated first-party coding-agent code, SDK/examples/docs, and package metadata from `@sinclair/typebox` 0.34.x to `typebox` 1.x. New extensions, SDK integrations, and pi packages should depend on and import from `typebox`. Legacy extension loading still aliases the root `@sinclair/typebox` package, but `@sinclair/typebox/compiler` is no longer shimmed. This migration also picks up the new `@mariozechner/pi-ai` TypeBox-native validator path, so tool argument validation now works in eval-restricted runtimes such as Cloudflare Workers instead of being skipped ([#3112](https://github.com/badlogic/pi-mono/issues/3112))
|
|
70
|
+
- Session-replacement commands now invalidate captured pre-replacement session-bound extension objects after `ctx.newSession()`, `ctx.fork()`, and `ctx.switchSession()`. Old `pi` and command `ctx` references now throw instead of silently targeting the replaced session. Migration: if code needs to keep working in the replacement session after one of those calls, pass `withSession` to that same method and do the post-switch work there. In practice, move post-switch `pi.sendUserMessage()`, `pi.sendMessage()`, and command-ctx/session-manager access into `withSession`, and use only the `ReplacedSessionContext` passed to that callback for session-bound operations. Footguns: `withSession` runs after the old extension instance has already received `session_shutdown`, old cleanup may already have invalidated captured state, captured old `pi` / old command `ctx` are stale, and previously extracted raw objects such as `const sm = ctx.sessionManager` remain the caller's responsibility and must not be reused after the switch.
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
|
|
74
|
+
- Added support for terminating tool results via `terminate: true`, allowing custom tools to end the current tool batch without an automatic follow-up LLM call, plus a `structured-output.ts` extension example and extension docs showing the pattern ([#3525](https://github.com/badlogic/pi-mono/issues/3525))
|
|
75
|
+
- Added OSC 9;4 terminal progress indicators during agent streaming and compaction, so terminals like iTerm2, WezTerm, Windows Terminal, and Kitty show activity in their tab bar
|
|
76
|
+
- Added `ctx.ui.addAutocompleteProvider(...)` for stacking extension autocomplete providers on top of the built-in slash/path provider, plus a `github-issue-autocomplete.ts` example and extension docs ([#2983](https://github.com/badlogic/pi-mono/issues/2983))
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- Fixed exported session HTML to sanitize markdown link URLs before rendering them into anchor tags, blocking `javascript:`-style payloads while preserving safe links in shared/exported sessions ([#3532](https://github.com/badlogic/pi-mono/issues/3532))
|
|
81
|
+
- Fixed `ctx.getSystemPrompt()` inside `before_agent_start` to reflect chained system-prompt changes made by earlier `before_agent_start` handlers, and clarified the extension docs around provider-payload rewrites and what `ctx.getSystemPrompt()` does and does not report ([#3539](https://github.com/badlogic/pi-mono/issues/3539))
|
|
82
|
+
- Fixed built-in `google-gemini-cli` model lists and selector entries to include `gemini-3.1-flash-lite-preview`, so Cloud Code Assist users no longer need manual `--model` fallback selection to use it ([#3545](https://github.com/badlogic/pi-mono/issues/3545))
|
|
83
|
+
- Fixed extension session-replacement flows so `ctx.newSession()`, `ctx.fork()`, `ctx.switchSession()`, and imported-session replacements fully rebind before post-switch work runs, added `withSession` replacement callbacks with fresh `ReplacedSessionContext` helpers, and make stale pre-replacement `pi` / `ctx` session-bound accesses throw instead of silently targeting the wrong session ([#2860](https://github.com/badlogic/pi-mono/issues/2860))
|
|
84
|
+
- Fixed `models.json` built-in provider overrides to accept `headers` without requiring `baseUrl`, so request-header-only overrides now load and apply correctly ([#3538](https://github.com/badlogic/pi-mono/issues/3538))
|
|
85
|
+
|
|
86
|
+
## [0.68.1] - 2026-04-22
|
|
87
|
+
|
|
88
|
+
### New Features
|
|
89
|
+
|
|
90
|
+
- Fireworks provider support with built-in models and `FIREWORKS_API_KEY` auth. See [README.md#providers--models](README.md#providers--models) and [docs/providers.md](docs/providers.md).
|
|
91
|
+
- Configurable inline tool image width via `terminal.imageWidthCells` in `/settings`. See [docs/settings.md#terminal--images](docs/settings.md#terminal--images).
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
|
|
95
|
+
- Added built-in Fireworks provider support, including `FIREWORKS_API_KEY` setup/docs and the default Fireworks model `accounts/fireworks/models/kimi-k2p6` ([#3519](https://github.com/badlogic/pi-mono/issues/3519))
|
|
96
|
+
|
|
97
|
+
### Fixed
|
|
98
|
+
|
|
99
|
+
- Fixed interactive inline tool images to honor configurable `terminal.imageWidthCells` via `/settings`, so tool-output images are no longer hard-capped to 60 terminal cells ([#3508](https://github.com/badlogic/pi-mono/issues/3508))
|
|
100
|
+
- Fixed `sessionDir` in `settings.json` to expand `~`, so portable session-directory settings no longer require a shell wrapper ([#3514](https://github.com/badlogic/pi-mono/issues/3514))
|
|
101
|
+
- Fixed parallel tool-call rows to leave the pending state as soon as each tool is finalized, while still appending persisted tool results in assistant source order ([#3503](https://github.com/badlogic/pi-mono/issues/3503))
|
|
102
|
+
- Fixed exported session markdown to render Markdown while showing HTML-like message content such as `<file name="...">...</file>` verbatim, so shared sessions match the TUI instead of letting the browser interpret message text ([#3484](https://github.com/badlogic/pi-mono/issues/3484))
|
|
103
|
+
- Fixed exported session HTML to render `grep` and `find` output through their existing TUI renderers and `ls` output through a native template renderer, avoiding missing formatting and spacing artifacts in shared sessions ([#3491](https://github.com/badlogic/pi-mono/pull/3491) by [@aliou](https://github.com/aliou))
|
|
104
|
+
- Fixed `@` autocomplete fuzzy search to follow symlinked directories and include symlinked paths in results ([#3507](https://github.com/badlogic/pi-mono/issues/3507))
|
|
105
|
+
- Fixed proxied agent streams to preserve the proxy-safe serializable subset of stream options, including session, transport, retry-delay, metadata, header, cache-retention, and thinking-budget settings ([#3512](https://github.com/badlogic/pi-mono/issues/3512))
|
|
106
|
+
- Hardened Anthropic streaming against malformed tool-call JSON by owning SSE parsing with defensive JSON repair, replacing the deprecated `fine-grained-tool-streaming` beta header with per-tool `eager_input_streaming`, and updating stale test model references ([#3175](https://github.com/badlogic/pi-mono/issues/3175))
|
|
107
|
+
- Fixed Bedrock runtime endpoint resolution to stop pinning built-in regional endpoints over `AWS_REGION` / `AWS_PROFILE`, restoring `us.*` and `eu.*` inference profile support after v0.68.0 while preserving custom VPC/proxy endpoint overrides ([#3481](https://github.com/badlogic/pi-mono/issues/3481), [#3485](https://github.com/badlogic/pi-mono/issues/3485), [#3486](https://github.com/badlogic/pi-mono/issues/3486), [#3487](https://github.com/badlogic/pi-mono/issues/3487), [#3488](https://github.com/badlogic/pi-mono/issues/3488))
|
|
108
|
+
|
|
109
|
+
## [0.68.0] - 2026-04-20
|
|
110
|
+
|
|
111
|
+
### New Features
|
|
112
|
+
|
|
113
|
+
- Configurable streaming working indicator for extensions via `ctx.ui.setWorkingIndicator()`, including animated, static, and hidden indicators. See [docs/tui.md#working-indicator](docs/tui.md#working-indicator), [docs/extensions.md](docs/extensions.md), and [examples/extensions/working-indicator.ts](examples/extensions/working-indicator.ts).
|
|
114
|
+
- `before_agent_start` now exposes `systemPromptOptions` (`BuildSystemPromptOptions`) so extensions can inspect the structured system-prompt inputs without re-discovering resources. See [docs/extensions.md#before_agent_start](docs/extensions.md#before_agent_start) and [examples/extensions/prompt-customizer.ts](examples/extensions/prompt-customizer.ts).
|
|
115
|
+
- Configurable keybindings for scoped model selector actions and session-tree filter actions. See [docs/keybindings.md](docs/keybindings.md).
|
|
116
|
+
- `/clone` duplicates the current active branch into a new session, while extensions can choose whether to fork `before` or `at` an entry via `ctx.fork(..., { position })`. See [README.md](README.md), [docs/extensions.md](docs/extensions.md), and [docs/session.md](docs/session.md).
|
|
117
|
+
|
|
118
|
+
### Breaking Changes
|
|
119
|
+
|
|
120
|
+
- Changed SDK and CLI tool selection from cwd-bound built-in tool instances to tool-name allowlists. `createAgentSession({ tools })` now expects `string[]` names such as `"read"` and `"bash"` instead of `Tool[]`, `--tools` now allowlists built-in, extension, and custom tools by name, and `--no-tools` now disables all tools by default rather than only built-ins. Migrate SDK code from `tools: [readTool, bashTool]` to `tools: ["read", "bash"]` ([#2835](https://github.com/badlogic/pi-mono/issues/2835), [#3452](https://github.com/badlogic/pi-mono/issues/3452))
|
|
121
|
+
- Removed prebuilt cwd-bound tool and tool-definition exports from `@mariozechner/pi-coding-agent`, including `readTool`, `bashTool`, `editTool`, `writeTool`, `grepTool`, `findTool`, `lsTool`, `readOnlyTools`, `codingTools`, and the corresponding `*ToolDefinition` values. Use the explicit factory exports instead, for example `createReadTool(cwd)`, `createBashTool(cwd)`, `createCodingTools(cwd)`, and `createReadToolDefinition(cwd)` ([#3452](https://github.com/badlogic/pi-mono/issues/3452))
|
|
122
|
+
- Removed ambient `process.cwd()` / default agent-dir fallback behavior from public resource helpers. `DefaultResourceLoader`, `loadProjectContextFiles()`, and `loadSkills()` now require explicit cwd/agent-dir style inputs, and exported system-prompt option types now require an explicit `cwd`. Pass the session or project cwd explicitly instead of relying on process-global defaults ([#3452](https://github.com/badlogic/pi-mono/issues/3452))
|
|
123
|
+
|
|
124
|
+
### Added
|
|
125
|
+
|
|
126
|
+
- Added extension support for customizing the interactive streaming working indicator via `ctx.ui.setWorkingIndicator()`, including custom animated frames, static indicators, hidden indicators, a new `working-indicator.ts` example extension, and updated extension/TUI/RPC docs ([#3413](https://github.com/badlogic/pi-mono/issues/3413))
|
|
127
|
+
- Added `systemPromptOptions` (`BuildSystemPromptOptions`) to `before_agent_start` extension events, so extensions can inspect the structured inputs used to build the current system prompt ([#3473](https://github.com/badlogic/pi-mono/pull/3473) by [@dljsjr](https://github.com/dljsjr))
|
|
128
|
+
- Added `/clone` to duplicate the current active branch into a new session, while keeping `/fork` focused on forking from a previous user message ([#2962](https://github.com/badlogic/pi-mono/issues/2962))
|
|
129
|
+
- Added `ctx.fork()` support for `position: "before" | "at"` so extensions and integrations can branch before a user message or duplicate the current point in the conversation; the interactive clone/fork UX builds on that runtime support ([#3431](https://github.com/badlogic/pi-mono/pull/3431) by [@mitsuhiko](https://github.com/mitsuhiko))
|
|
130
|
+
- Added configurable keybinding ids for scoped model selector actions and tree filter actions, so those interactive shortcuts can be remapped in `keybindings.json` ([#3343](https://github.com/badlogic/pi-mono/pull/3343) by [@mpazik](https://github.com/mpazik))
|
|
131
|
+
- Added `PI_OAUTH_CALLBACK_HOST` support for built-in OAuth login flows, allowing local callback servers used by `pi auth` to bind to a custom interface instead of hardcoded `127.0.0.1` ([#3409](https://github.com/badlogic/pi-mono/pull/3409) by [@Michaelliv](https://github.com/Michaelliv))
|
|
132
|
+
- Added `reason` and `targetSessionFile` metadata to `session_shutdown` extension events, so extensions can distinguish quit, reload, new-session, resume, and fork teardown paths ([#2863](https://github.com/badlogic/pi-mono/issues/2863))
|
|
133
|
+
|
|
134
|
+
### Changed
|
|
135
|
+
|
|
136
|
+
- Changed `pi update` to batch npm package updates per scope and run git package updates with bounded parallelism, reducing multi-package update time while preserving skip behavior for pinned and already-current packages ([#2980](https://github.com/badlogic/pi-mono/issues/2980))
|
|
137
|
+
- Changed Bedrock session requests to omit `maxTokens` when model token limits are unknown and to omit `temperature` when unset, letting Bedrock use provider defaults and avoid unnecessary TPM quota reservation ([#3400](https://github.com/badlogic/pi-mono/pull/3400) by [@wirjo](https://github.com/wirjo))
|
|
138
|
+
|
|
139
|
+
### Fixed
|
|
140
|
+
|
|
141
|
+
- Fixed `AgentSession` system-prompt option initialization to avoid constructing an invalid empty `BuildSystemPromptOptions`, so `npm run check` passes after `cwd` became mandatory.
|
|
142
|
+
- Fixed shell-path resolution to stop consulting ambient `process.cwd()` state during bash execution, so session/project-specific `shellPath` settings now follow the active coding-agent session cwd instead of the launcher cwd ([#3452](https://github.com/badlogic/pi-mono/issues/3452))
|
|
143
|
+
- Fixed `ctx.ui.setWorkingIndicator()` custom frames to render verbatim instead of forcing the theme accent color, so extensions now own working-indicator coloring when they customize it ([#3467](https://github.com/badlogic/pi-mono/issues/3467))
|
|
144
|
+
- Fixed `pi update` reinstalling npm packages that are already at the latest published version by checking the installed package version before running `npm install <pkg>@latest` ([#3000](https://github.com/badlogic/pi-mono/issues/3000))
|
|
145
|
+
- Fixed `@` autocomplete plain queries to stop matching against the full cwd/base path, so path fragments in worktree names no longer crowd out intended results such as `@plan` ([#2778](https://github.com/badlogic/pi-mono/issues/2778))
|
|
146
|
+
- Fixed built-in tool wrapping to use the same extension-runner context path as extension tools, so built-in tools receive execution context and `read` can warn when the current model does not support images ([#3429](https://github.com/badlogic/pi-mono/issues/3429))
|
|
147
|
+
- Fixed `openai-completions` assistant replay to preserve `compat.requiresThinkingAsText` text-part serialization, avoiding same-model follow-up crashes when previous assistant messages mix thinking and text ([#3387](https://github.com/badlogic/pi-mono/issues/3387))
|
|
148
|
+
- Fixed direct OpenAI Chat Completions sessions to map `sessionId` and `cacheRetention` to prompt caching fields, sending `prompt_cache_key` when caching is enabled and `prompt_cache_retention: "24h"` for direct `api.openai.com` requests with long retention ([#3426](https://github.com/badlogic/pi-mono/issues/3426))
|
|
149
|
+
- Fixed OpenAI-compatible Chat Completions sessions to optionally send aligned `session_id`, `x-client-request-id`, and `x-session-affinity` headers from `sessionId` via `compat.sendSessionAffinityHeaders`, improving cache-affinity routing for backends such as Fireworks ([#3430](https://github.com/badlogic/pi-mono/issues/3430))
|
|
150
|
+
- Fixed threaded `/resume` session relationships and current-session detection to canonicalize symlinked session paths during selector comparisons, so shared session directories no longer break parent-child matching or active-session delete protection ([#3364](https://github.com/badlogic/pi-mono/issues/3364))
|
|
151
|
+
- Fixed `/session`, Sessions docs, and CLI help to consistently document that session reuse supports both file paths and session IDs, and that `/session` shows the current session ID ([#3390](https://github.com/badlogic/pi-mono/issues/3390))
|
|
152
|
+
- Fixed Windows pnpm global install detection to recognize `\\.pnpm\\` store paths, so update notices now suggest `pnpm install -g @mariozechner/pi-coding-agent` instead of falling back to npm ([#3378](https://github.com/badlogic/pi-mono/issues/3378))
|
|
153
|
+
- Fixed missing `@sinclair/typebox` runtime dependency in `@mariozechner/pi-coding-agent`, so strict pnpm installs no longer fail with `ERR_MODULE_NOT_FOUND` when starting `pi` ([#3434](https://github.com/badlogic/pi-mono/issues/3434))
|
|
154
|
+
- Fixed xterm uppercase typing in the interactive editor by decoding printable `modifyOtherKeys` input and normalizing shifted letter matching, so `Shift+letter` no longer disappears in `pi` ([#3436](https://github.com/badlogic/pi-mono/issues/3436))
|
|
155
|
+
- Fixed `/compact` to reuse the session thinking level for compaction summaries instead of forcing `high`, avoiding invalid reasoning-effort errors on `github-copilot/claude-opus-4.7` sessions configured for `medium` thinking ([#3438](https://github.com/badlogic/pi-mono/issues/3438))
|
|
156
|
+
- Fixed shared/exported plain-text tool output to preserve indentation instead of collapsing leading whitespace in the web share page ([#3440](https://github.com/badlogic/pi-mono/issues/3440))
|
|
157
|
+
- Fixed exported share pages to use browser-safe `T` and `O` shortcuts with clickable header toggles for thinking and tool visibility instead of browser-reserved `Ctrl+T` / `Ctrl+O` bindings ([#3374](https://github.com/badlogic/pi-mono/pull/3374) by [@vekexasia](https://github.com/vekexasia))
|
|
158
|
+
- Fixed skill resolution to dedupe symlinked aliases by canonical path, so `pi config` no longer shows duplicate skill entries when `~/.pi/agent/skills` points to `~/.agents/skills` ([#3417](https://github.com/badlogic/pi-mono/pull/3417) by [@rwachtler](https://github.com/rwachtler))
|
|
159
|
+
- Fixed OpenRouter request attribution to include Pi app headers (`HTTP-Referer: https://pi.dev`, `X-OpenRouter-Title: pi`, `X-OpenRouter-Categories: cli-agent`) when sessions are created through the coding-agent SDK and install telemetry is enabled ([#3414](https://github.com/badlogic/pi-mono/issues/3414))
|
|
160
|
+
- Fixed custom-model `compat` schema/docs to support `cacheControlFormat: "anthropic"` for OpenAI-compatible providers that expose Anthropic-style prompt caching via `cache_control` markers ([#3392](https://github.com/badlogic/pi-mono/issues/3392))
|
|
161
|
+
- Fixed Cloud Code Assist tool schemas to strip JSON Schema meta-declaration keys before provider translation, avoiding validation failures for tool-enabled sessions that use `$schema`, `$defs`, and related metadata ([#3412](https://github.com/badlogic/pi-mono/pull/3412) by [@vladlearns](https://github.com/vladlearns))
|
|
162
|
+
- Fixed direct Bedrock sessions to honor `model.baseUrl` as the runtime client endpoint, restoring support for custom Bedrock VPC or proxy routes ([#3402](https://github.com/badlogic/pi-mono/pull/3402) by [@wirjo](https://github.com/wirjo))
|
|
163
|
+
- Fixed the `edit` tool to coerce stringified `edits` JSON before validation, so models that send the array payload as a JSON string no longer fall back to ad-hoc shell edits ([#3370](https://github.com/badlogic/pi-mono/pull/3370) by [@dannote](https://github.com/dannote))
|
|
164
|
+
- Fixed package manifest positive glob entries to expand before loading packaged resources, restoring manifest patterns such as `skills/**/*.md` ([#3350](https://github.com/badlogic/pi-mono/pull/3350) by [@neonspectra](https://github.com/neonspectra))
|
|
165
|
+
|
|
166
|
+
## [0.67.68] - 2026-04-17
|
|
167
|
+
|
|
168
|
+
## [0.67.67] - 2026-04-17
|
|
169
|
+
|
|
170
|
+
### New Features
|
|
171
|
+
|
|
172
|
+
- Bedrock sessions can now authenticate with `AWS_BEARER_TOKEN_BEDROCK`, enabling Converse API access without local SigV4 credentials. See [docs/providers.md#amazon-bedrock](docs/providers.md#amazon-bedrock).
|
|
173
|
+
|
|
174
|
+
### Added
|
|
175
|
+
|
|
176
|
+
- Added Bedrock bearer-token authentication support via `AWS_BEARER_TOKEN_BEDROCK`, enabling coding-agent sessions to use Bedrock Converse without local SigV4 credentials ([#3125](https://github.com/badlogic/pi-mono/pull/3125) by [@wirjo](https://github.com/wirjo))
|
|
177
|
+
|
|
178
|
+
### Fixed
|
|
179
|
+
|
|
180
|
+
- Fixed `/scoped-models` Alt+Up/Down to stay a no-op in the implicit `all enabled` state instead of materializing a full explicit enabled-model list and marking the selector dirty ([#3331](https://github.com/badlogic/pi-mono/issues/3331))
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the fork-empty-session silent-degrade path in `handleResumeSession`.
|
|
3
|
+
*
|
|
4
|
+
* When the source session has no on-disk JSONL, fork SHALL silently spawn a
|
|
5
|
+
* fresh session in the same cwd, inherit the parent's `attachedProposal`,
|
|
6
|
+
* and emit `resume_result` with `code: "FORK_DEGRADED_TO_NEW"`.
|
|
7
|
+
*
|
|
8
|
+
* See change: fix-fork-empty-session-silent-timeout.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
11
|
+
import WebSocket from "ws";
|
|
12
|
+
|
|
13
|
+
// Spy on existsSync so we control the on-disk truth.
|
|
14
|
+
const existsSyncSpy = vi.fn();
|
|
15
|
+
vi.mock("node:fs", async () => {
|
|
16
|
+
const actual = await vi.importActual<typeof import("node:fs")>("node:fs");
|
|
17
|
+
return {
|
|
18
|
+
...actual,
|
|
19
|
+
existsSync: (p: string) => existsSyncSpy(p),
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
vi.mock("../process-manager.js", () => ({
|
|
24
|
+
spawnPiSession: vi.fn(),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
vi.mock("@blackbelt-technology/pi-dashboard-shared/config.js", () => ({
|
|
28
|
+
loadConfig: vi.fn().mockReturnValue({ spawnStrategy: "headless" }),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
import { handleResumeSession } from "../browser-handlers/session-action-handler.js";
|
|
32
|
+
import { spawnPiSession } from "../process-manager.js";
|
|
33
|
+
|
|
34
|
+
function makeMockWs(): { ws: WebSocket; messages: any[] } {
|
|
35
|
+
const messages: any[] = [];
|
|
36
|
+
const ws = {
|
|
37
|
+
readyState: WebSocket.OPEN,
|
|
38
|
+
send: vi.fn((data: string) => messages.push(JSON.parse(data))),
|
|
39
|
+
} as unknown as WebSocket;
|
|
40
|
+
return { ws, messages };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function makeCtx(session: any, sentLog: any[]) {
|
|
44
|
+
const { ws } = makeMockWs();
|
|
45
|
+
const enqueue = vi.fn();
|
|
46
|
+
const ctx = {
|
|
47
|
+
ws,
|
|
48
|
+
sessionManager: {
|
|
49
|
+
get: () => session,
|
|
50
|
+
update: vi.fn(),
|
|
51
|
+
} as any,
|
|
52
|
+
eventStore: {} as any,
|
|
53
|
+
piGateway: {} as any,
|
|
54
|
+
headlessPidRegistry: { register: vi.fn() } as any,
|
|
55
|
+
pendingDashboardSpawns: new Map<string, number>(),
|
|
56
|
+
pendingResumeRegistry: {} as any,
|
|
57
|
+
pendingResumeIntents: { record: vi.fn() } as any,
|
|
58
|
+
pendingForkRegistry: { recordFork: vi.fn() } as any,
|
|
59
|
+
pendingClientCorrelations: { record: vi.fn() } as any,
|
|
60
|
+
pendingAttachRegistry: { enqueue, consume: vi.fn(), size: vi.fn() } as any,
|
|
61
|
+
sendTo: (_target: any, msg: any) => sentLog.push(msg),
|
|
62
|
+
broadcast: vi.fn(),
|
|
63
|
+
getSubscribers: vi.fn().mockReturnValue([]),
|
|
64
|
+
trackUiRequest: vi.fn(),
|
|
65
|
+
replayPendingUiRequests: vi.fn(),
|
|
66
|
+
markReplaying: vi.fn(),
|
|
67
|
+
clearReplaying: vi.fn(),
|
|
68
|
+
} as any;
|
|
69
|
+
return { ctx, enqueue };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
describe("handleResumeSession: fork-empty-session silent-degrade", () => {
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
existsSyncSpy.mockReset();
|
|
75
|
+
(spawnPiSession as any).mockReset();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("degrades to fresh spawn when sessionFile does not exist", async () => {
|
|
79
|
+
existsSyncSpy.mockReturnValue(false);
|
|
80
|
+
(spawnPiSession as any).mockResolvedValue({
|
|
81
|
+
success: true,
|
|
82
|
+
message: "Pi session spawned headless (pid 999)",
|
|
83
|
+
pid: 999,
|
|
84
|
+
spawnToken: "tok_degrade",
|
|
85
|
+
dashboardSpawned: true,
|
|
86
|
+
});
|
|
87
|
+
const session = {
|
|
88
|
+
id: "S1",
|
|
89
|
+
cwd: "/tmp",
|
|
90
|
+
status: "active",
|
|
91
|
+
sessionFile: "/path/that/does/not/exist.jsonl",
|
|
92
|
+
resuming: false,
|
|
93
|
+
};
|
|
94
|
+
const sent: any[] = [];
|
|
95
|
+
const { ctx } = makeCtx(session, sent);
|
|
96
|
+
|
|
97
|
+
await handleResumeSession(
|
|
98
|
+
{ type: "resume_session", sessionId: "S1", mode: "fork", requestId: "rq_x" } as any,
|
|
99
|
+
ctx,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// spawnPiSession IS called — fresh spawn (no sessionFile, no mode).
|
|
103
|
+
expect(spawnPiSession).toHaveBeenCalledTimes(1);
|
|
104
|
+
const callArgs = (spawnPiSession as any).mock.calls[0];
|
|
105
|
+
expect(callArgs[0]).toBe("/tmp"); // cwd
|
|
106
|
+
expect(callArgs[1]).toEqual({ strategy: "headless" }); // no sessionFile, no mode
|
|
107
|
+
|
|
108
|
+
// resume_result carries success: true, the degradation code, and echoed requestId.
|
|
109
|
+
expect(sent).toHaveLength(1);
|
|
110
|
+
const result = sent[0];
|
|
111
|
+
expect(result.type).toBe("resume_result");
|
|
112
|
+
expect(result.success).toBe(true);
|
|
113
|
+
expect(result.sessionId).toBe("S1");
|
|
114
|
+
expect(result.code).toBe("FORK_DEGRADED_TO_NEW");
|
|
115
|
+
expect(result.requestId).toBe("rq_x");
|
|
116
|
+
expect(result.message).toMatch(/fresh session/i);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("inherits attachedProposal from parent on degraded path", async () => {
|
|
120
|
+
existsSyncSpy.mockReturnValue(false);
|
|
121
|
+
(spawnPiSession as any).mockResolvedValue({
|
|
122
|
+
success: true,
|
|
123
|
+
message: "ok",
|
|
124
|
+
pid: 1000,
|
|
125
|
+
spawnToken: "tok_d2",
|
|
126
|
+
dashboardSpawned: true,
|
|
127
|
+
});
|
|
128
|
+
const session = {
|
|
129
|
+
id: "S2",
|
|
130
|
+
cwd: "/proj",
|
|
131
|
+
status: "active",
|
|
132
|
+
sessionFile: "/proj/missing.jsonl",
|
|
133
|
+
attachedProposal: "feature-x",
|
|
134
|
+
resuming: false,
|
|
135
|
+
};
|
|
136
|
+
const sent: any[] = [];
|
|
137
|
+
const { ctx, enqueue } = makeCtx(session, sent);
|
|
138
|
+
|
|
139
|
+
await handleResumeSession(
|
|
140
|
+
{ type: "resume_session", sessionId: "S2", mode: "fork" } as any,
|
|
141
|
+
ctx,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
expect(enqueue).toHaveBeenCalledWith("/proj", "feature-x");
|
|
145
|
+
expect(sent[0].code).toBe("FORK_DEGRADED_TO_NEW");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("does NOT enqueue attachProposal when parent has none", async () => {
|
|
149
|
+
existsSyncSpy.mockReturnValue(false);
|
|
150
|
+
(spawnPiSession as any).mockResolvedValue({
|
|
151
|
+
success: true,
|
|
152
|
+
message: "ok",
|
|
153
|
+
spawnToken: "tok_d3",
|
|
154
|
+
});
|
|
155
|
+
const session = {
|
|
156
|
+
id: "S3",
|
|
157
|
+
cwd: "/proj",
|
|
158
|
+
status: "active",
|
|
159
|
+
sessionFile: "/proj/missing.jsonl",
|
|
160
|
+
attachedProposal: undefined,
|
|
161
|
+
resuming: false,
|
|
162
|
+
};
|
|
163
|
+
const sent: any[] = [];
|
|
164
|
+
const { ctx, enqueue } = makeCtx(session, sent);
|
|
165
|
+
|
|
166
|
+
await handleResumeSession(
|
|
167
|
+
{ type: "resume_session", sessionId: "S3", mode: "fork" } as any,
|
|
168
|
+
ctx,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
expect(enqueue).not.toHaveBeenCalled();
|
|
172
|
+
expect(sent[0].code).toBe("FORK_DEGRADED_TO_NEW");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("proceeds normally (real fork) when sessionFile exists", async () => {
|
|
176
|
+
existsSyncSpy.mockReturnValue(true);
|
|
177
|
+
(spawnPiSession as any).mockResolvedValue({
|
|
178
|
+
success: true,
|
|
179
|
+
message: "Pi session spawned headless (pid 1234)",
|
|
180
|
+
pid: 1234,
|
|
181
|
+
spawnToken: "tok_real_fork",
|
|
182
|
+
dashboardSpawned: true,
|
|
183
|
+
});
|
|
184
|
+
const session = {
|
|
185
|
+
id: "S4",
|
|
186
|
+
cwd: "/tmp",
|
|
187
|
+
status: "active",
|
|
188
|
+
sessionFile: "/path/that/exists.jsonl",
|
|
189
|
+
resuming: false,
|
|
190
|
+
};
|
|
191
|
+
const sent: any[] = [];
|
|
192
|
+
const { ctx } = makeCtx(session, sent);
|
|
193
|
+
|
|
194
|
+
await handleResumeSession(
|
|
195
|
+
{ type: "resume_session", sessionId: "S4", mode: "fork", requestId: "rq_y" } as any,
|
|
196
|
+
ctx,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
// spawnPiSession called with real fork args (sessionFile + mode).
|
|
200
|
+
expect(spawnPiSession).toHaveBeenCalledTimes(1);
|
|
201
|
+
const callArgs = (spawnPiSession as any).mock.calls[0];
|
|
202
|
+
expect(callArgs[1].sessionFile).toBe("/path/that/exists.jsonl");
|
|
203
|
+
expect(callArgs[1].mode).toBe("fork");
|
|
204
|
+
|
|
205
|
+
// No degradation code on real fork.
|
|
206
|
+
const result = sent[sent.length - 1];
|
|
207
|
+
expect(result.code).toBeUndefined();
|
|
208
|
+
expect(result.success).toBe(true);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("continue mode is unaffected by the degradation path", async () => {
|
|
212
|
+
existsSyncSpy.mockReturnValue(false); // file missing — but continue mode shouldn't check
|
|
213
|
+
(spawnPiSession as any).mockResolvedValue({
|
|
214
|
+
success: true,
|
|
215
|
+
message: "ok",
|
|
216
|
+
spawnToken: "tok_continue",
|
|
217
|
+
});
|
|
218
|
+
const session = {
|
|
219
|
+
id: "S5",
|
|
220
|
+
cwd: "/tmp",
|
|
221
|
+
status: "ended",
|
|
222
|
+
sessionFile: "/path/that/does/not/exist.jsonl",
|
|
223
|
+
resuming: false,
|
|
224
|
+
};
|
|
225
|
+
const sent: any[] = [];
|
|
226
|
+
const { ctx, enqueue } = makeCtx(session, sent);
|
|
227
|
+
|
|
228
|
+
await handleResumeSession(
|
|
229
|
+
{ type: "resume_session", sessionId: "S5", mode: "continue", requestId: "rq_z" } as any,
|
|
230
|
+
ctx,
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
expect(spawnPiSession).toHaveBeenCalledTimes(1);
|
|
234
|
+
const callArgs = (spawnPiSession as any).mock.calls[0];
|
|
235
|
+
expect(callArgs[1].mode).toBe("continue");
|
|
236
|
+
expect(enqueue).not.toHaveBeenCalled();
|
|
237
|
+
const result = sent[sent.length - 1];
|
|
238
|
+
expect(result.code).toBeUndefined();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("spawn failure on degraded path does NOT set FORK_DEGRADED_TO_NEW code", async () => {
|
|
242
|
+
existsSyncSpy.mockReturnValue(false);
|
|
243
|
+
(spawnPiSession as any).mockResolvedValue({
|
|
244
|
+
success: false,
|
|
245
|
+
message: "Directory does not exist: /tmp",
|
|
246
|
+
code: "DIR_MISSING",
|
|
247
|
+
});
|
|
248
|
+
const session = {
|
|
249
|
+
id: "S6",
|
|
250
|
+
cwd: "/tmp",
|
|
251
|
+
status: "active",
|
|
252
|
+
sessionFile: "/missing.jsonl",
|
|
253
|
+
resuming: false,
|
|
254
|
+
};
|
|
255
|
+
const sent: any[] = [];
|
|
256
|
+
const { ctx } = makeCtx(session, sent);
|
|
257
|
+
|
|
258
|
+
await handleResumeSession(
|
|
259
|
+
{ type: "resume_session", sessionId: "S6", mode: "fork" } as any,
|
|
260
|
+
ctx,
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
const result = sent[0];
|
|
264
|
+
expect(result.success).toBe(false);
|
|
265
|
+
expect(result.code).toBeUndefined();
|
|
266
|
+
expect(result.message).toMatch(/Directory does not exist/);
|
|
267
|
+
});
|
|
268
|
+
});
|