@vikrant82/opencode-cache-keepalive 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/MIGRATION.md +57 -0
  2. package/README.md +75 -51
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1093 -649
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/config.d.ts +8 -25
  7. package/dist/lib/config.d.ts.map +1 -1
  8. package/dist/lib/control.d.ts +10 -37
  9. package/dist/lib/control.d.ts.map +1 -1
  10. package/dist/lib/paths.d.ts +5 -12
  11. package/dist/lib/paths.d.ts.map +1 -1
  12. package/dist/lib/replay-warmer.d.ts +95 -0
  13. package/dist/lib/replay-warmer.d.ts.map +1 -0
  14. package/dist/lib/state.d.ts +15 -117
  15. package/dist/lib/state.d.ts.map +1 -1
  16. package/dist/lib/tui/commands.d.ts +1 -6
  17. package/dist/lib/tui/commands.d.ts.map +1 -1
  18. package/dist/lib/tui/footer.d.ts +5 -5
  19. package/dist/lib/tui/footer.d.ts.map +1 -1
  20. package/dist/lib/tui/format.d.ts.map +1 -1
  21. package/dist/lib/types.d.ts +123 -0
  22. package/dist/lib/types.d.ts.map +1 -0
  23. package/dist/tui.d.ts +3 -0
  24. package/dist/tui.d.ts.map +1 -1
  25. package/lib/config.ts +106 -74
  26. package/lib/control.ts +50 -86
  27. package/lib/paths.ts +12 -14
  28. package/lib/replay-warmer.ts +1200 -0
  29. package/lib/state.ts +171 -181
  30. package/lib/tui/commands.tsx +36 -144
  31. package/lib/tui/footer.tsx +54 -156
  32. package/lib/tui/format.ts +4 -0
  33. package/lib/types.ts +130 -0
  34. package/package.json +3 -2
  35. package/tui.tsx +40 -0
  36. package/dist/lib/keepalive.d.ts +0 -88
  37. package/dist/lib/keepalive.d.ts.map +0 -1
  38. package/dist/lib/model.d.ts +0 -8
  39. package/dist/lib/model.d.ts.map +0 -1
  40. package/dist/lib/system.d.ts +0 -11
  41. package/dist/lib/system.d.ts.map +0 -1
  42. package/lib/keepalive.ts +0 -665
  43. package/lib/model.ts +0 -19
  44. package/lib/system.ts +0 -19
package/MIGRATION.md ADDED
@@ -0,0 +1,57 @@
1
+ # 0.2.0 migration and release notes
2
+
3
+ > These notes describe the 0.2.0 package contents prepared for release. They do not imply that the package has been published, nor validated savings or provider cache TTLs.
4
+
5
+ ## What changes
6
+
7
+ The prior synthetic `~` ping approach is replaced with replay of the latest eligible real model request. The request is sent through the original `fetch` unchanged and may be retained only in process memory for replay. Replays stop at API-specific SSE checkpoints, rather than completing a generated response. No request URL, headers, body, credentials, or conversation text are persisted.
8
+
9
+ The wrapper observes calls to global `fetch`, then forwards them to the original `fetch` with the same arguments and returns its result. It records only requests that pass eligibility checks; unrelated global traffic is forwarded unchanged. Replay payload capture is limited to POSTs at allowed host suffixes and supported API paths ending in `/v1/messages`, `/v1/responses` or `/responses`, or `/chat/completions`, with a recognized session ID (`X-Session-Id`, `x-session-affinity`, or `X-Interaction-Id`), a JSON request body, and a model containing an `intervals` key. The default host suffix is `githubcopilot.com`; default model substrings are `claude` (285,000 ms) and `gpt` (1,680,000 ms). First matching interval key wins, case-insensitively. Child sessions are excluded unless `includeChildSessions` is enabled. These are code eligibility rules, not a claim of provider-wide support.
10
+
11
+ An observed request for an enabled session on an allowed host begins a replay gap and resets its successful replay count; only eligible POSTs on supported paths become replay payloads. A successful replay is capped by `maxReplaysPerGap`; `"auto"` calculates `floor((missFactor - cacheReadFactor) / cacheReadFactor)` (9 at defaults). This is a configurable input-cost estimate, not verified provider pricing or net savings. The displayed avoided cache-write tokens are gross; refresh cached-read tokens are separate usage and gross display values do not subtract that cost. Token usage may be API-specific or unavailable. No universal replay expiry is promised: stop/lapse conditions include a fresh real request, reaching the cap, HTTP rejection, a Messages cache-creation-only replay, retry exhaustion, session disablement, or request-payload eviction at the in-memory storage budget. Network/timeout/other non-OK failures retry once after 10 seconds, then lapse; HTTP 400/401/403 stop immediately. The default replay timeout is 60 seconds and `maxStoredBytes` defaults to 67,108,864 bytes (64 MiB).
12
+
13
+ Session `/keepalive-on`, `/keepalive-off`, and `/keepalive-toggle` are runtime controls. The global `enabled` option remains the master switch. Disabling clears the saved request payload; re-enabling does not recover it, so a fresh eligible real request is required. Per-session controls use `control-<directory-hash>.json` under OpenCode's plugin storage directory and expire after 30 days. Version 1 folder-wide controls are ignored. Version 2 state snapshots hold telemetry/process totals, not replay payloads; state files are associated with a process and stale-process cleanup, while `server.log` may contain session IDs, model/API/host/path, replay status/latency, and token-usage metadata.
14
+
15
+ ## Option changes
16
+
17
+ Plugin options explicitly supplied in `opencode.json` take precedence over matching environment variables; environment values otherwise override defaults. These old options are ignored with deprecation warnings:
18
+
19
+ - `intervalMs` / `intervalSeconds` → configure `intervals` (model substring to milliseconds).
20
+ - `windowMs` / `windowMinutes` → no universal warm-window setting; warming follows the gap, cap, stop, and lapse rules above.
21
+ - `providerAllowlist` / `modelAllowlist` → configure `hosts` / `intervals`.
22
+ - `revertPing`, `pingToken`, `injectSystemInstruction`, `claudeBusyWarm`, `claudeBusyWarmIntervalMs`, `claudeBusyWarmWindowMs` → removed with synthetic pings.
23
+ - `/keepalive-interval` → removed; configure `intervals` before startup.
24
+
25
+ Existing runtime control files with version 1 folder-level `enabled` values are ignored; they are not migrated. State v1 files are ignored and not deleted by v2 cleanup. Back up any settings you need, configure the new options, and use session controls as desired.
26
+
27
+ ## Loading and updating
28
+
29
+ The package exposes a server entry (`.` / `./server`) and a separate TUI module (`./tui`). The loader contract is source-verified against OpenCode v1.18.33: `opencode.json` loads server plugins, `tui.json`/`tui.jsonc` loads TUI plugins, and package `./server` or `./tui` exports are selected by plugin kind. The plugin config accepts a package string or `[package, options]`; options belong in the server registration. See [TUI configuration docs](https://opencode.ai/docs/tui/), [server config schema](https://opencode.ai/config.json), [TUI config schema](https://opencode.ai/tui.json), and [v1.18.33 plugin loader source](https://github.com/anomalyco/opencode/tree/v1.18.33/packages/opencode/src/plugin). This source verification does not establish live plugin integration.
30
+
31
+ After 0.2.0 is published, register the same pinned package specifier (`@vikrant82/opencode-cache-keepalive@0.2.0`) in both files; the specifier is available only after publication. For local development, `opencode.json` can use `./dist/index.js`, while `tui.json` can use `./tui.tsx` relative to that config file; the package's `./tui` export intentionally targets TypeScript source, not an emitted JavaScript bundle.
32
+
33
+ The v1.18.33 source contract supports the README's server plugin-options tuple. It differs from the installed SDK declaration previously inspected (`Config.plugin: string[]`); the source-tagged OpenCode schema and loader are the basis for this documentation.
34
+
35
+ The previously stated OpenCode `>=1.4.3` peer baseline and Node `>=18` README baseline are not validated support ranges (`package.json` has no Node `engines` field). The observed check environment was Node 22.22.3, OpenCode 1.18.33, `@opencode-ai/plugin` 1.17.16, and `@opencode-ai/sdk` 1.17.16; live integration remains untested.
36
+
37
+ After 0.2.0 is published, an installation update can be pinned explicitly, for example:
38
+
39
+ ```bash
40
+ npm install @vikrant82/opencode-cache-keepalive@0.2.0
41
+ ```
42
+
43
+ This is an example for use only after publication; it does not assert that publication has occurred. Package metadata in this source tree is prepared as 0.2.0.
44
+
45
+ ## Uncompleted release checklist
46
+
47
+ - [x] Verify separate server/TUI loading contract from OpenCode v1.18.33 source and published config documentation.
48
+ - [ ] **Accepted/deferred risk:** live footer visibility and session toggles were observed by the human, but final isolated-build loading/integration was not established. Loader contract verification alone does not confirm plugin integration.
49
+ - [x] **Review finding — Request body capture:** fixed by synchronously cloning eligible `Request` bodies before forwarding and verified with a consuming-transport replay regression.
50
+ - [x] **Review finding — multi-instance routing:** fixed by selecting unknown-session owners against host/model eligibility and keeping known ownership authoritative; disjoint-host, overlapping-config, and disabled-owner regressions pass.
51
+ - [x] **Request stream rejection after immediate disposal:** attached an immediate rejection observer while preserving rejection for recorder error handling; focused stream-error regression passes.
52
+ - [ ] Verify migration behavior and config precedence in the release package, including ignored legacy options and v1 control/state files.
53
+ - [ ] Review privacy boundaries in persisted state and logs for the release build.
54
+ - [ ] Validate replay lifecycle, API checkpoints, rejection/retry behavior, storage cap, and cost/usage reporting against intended supported environments; do not claim TTL, savings, or provider support without evidence.
55
+ - [x] Prepare package metadata and lockfile for 0.2.0 and include `MIGRATION.md` in package files; publication remains a separate delivery action.
56
+ - [ ] In a dedicated disposable TTY session, smoke-test idle/tool-busy replay and active-model suppression; cap, rejection, and restart behavior; absence of synthetic conversation turns; sanitized state files and logs. Final isolated-build loading was not established; retain the accepted/deferred live UI integration risk until verified.
57
+ - [ ] After publication, verify the published archive/version; no publication is performed here.
package/README.md CHANGED
@@ -4,23 +4,21 @@
4
4
  [![License: AGPL-3.0-or-later](https://img.shields.io/badge/License-AGPL--3.0--or--later-blue.svg)](./LICENSE)
5
5
  [![OpenCode Plugin](https://img.shields.io/badge/OpenCode-Plugin-purple.svg)](https://github.com/opencode-ai/plugin)
6
6
 
7
- Keep LLM prompt caches warm during idle periods with invisible pings and a live TUI readout.
7
+ Replay the last real model request to keep supported prompt caches warm during idle and tool-busy gaps.
8
8
 
9
9
  ## Why This Exists
10
10
 
11
- - Provider prompt caches (Copilot, Anthropic, etc.) expire after ~5-60 minutes of inactivity
12
- - Next turn pays full input token cost + latency penalty on cache miss
13
- - This plugin sends minimal `~` pings during idle windows to keep the cached prefix alive at negligible cost
11
+ - Prompt caches expire after provider-specific inactivity windows; a later turn can pay full input cost
12
+ - A global `fetch` wrapper passes every request to the original `fetch` unchanged; it only records eligible requests for later replay
13
+ - Replays are bounded per gap by a break-even cost cap; ordinary real requests are not delayed, rewritten, or replaced
14
14
 
15
15
  ## Features
16
16
 
17
- - **Automatic warm window**: arms after real turns, expires after configurable window (default 55min)
18
- - **Live TUI footer**: idle time, pings sent/left, last ping cache hit/miss with token counts
19
- - **Synthetic ping reversion**: removes `~`/`~` turns from conversation history
17
+ - **Idle and tool-busy warming**: refreshes the current session's replayed cache without adding conversation turns
18
+ - **Live TUI footer**: cache state, next refresh, refresh count, gross avoided cache-write tokens, and resume hit ratio
19
+ - **Privacy-first persistence**: session telemetry only; request URL, headers, body, credentials, and conversation text are not stored
20
20
  - **Runtime toggle**: `/keepalive-toggle`, `/keepalive-on`, `/keepalive-off` slash commands
21
- - **Runtime interval override**: set a per-project ping interval with presets, custom durations, or reset to the plugin default
22
- - **Secure mode support**: works with `OPENCODE_SERVER_PASSWORD`
23
- - **Configurable provider/model allowlists**
21
+ - **Per-model timing**: Claude and GPT model substrings have configurable intervals; allowed host suffixes limit eligible capture
24
22
 
25
23
  ## Installation
26
24
 
@@ -28,7 +26,7 @@ Keep LLM prompt caches warm during idle periods with invisible pings and a live
28
26
  npm install @vikrant82/opencode-cache-keepalive
29
27
  ```
30
28
 
31
- Register in your `opencode.json`:
29
+ Register the server plugin in `opencode.json`:
32
30
 
33
31
  ```json
34
32
  {
@@ -36,6 +34,16 @@ Register in your `opencode.json`:
36
34
  }
37
35
  ```
38
36
 
37
+ Register the same package in `tui.json` to load its separate TUI entry:
38
+
39
+ ```json
40
+ {
41
+ "plugin": ["@vikrant82/opencode-cache-keepalive"]
42
+ }
43
+ ```
44
+
45
+ OpenCode's v1.18.33 loader reads plugin lists from these separate config files and resolves package `./server` and `./tui` exports by plugin kind. When installing the published 0.2.0 release, use the same pinned package specifier in both files; availability depends on publication.
46
+
39
47
  ### Local Development
40
48
 
41
49
  To use a locally built version during development:
@@ -46,11 +54,19 @@ To use a locally built version during development:
46
54
  }
47
55
  ```
48
56
 
49
- Run `npm run build` first, then restart opencode. Rebuild and restart after code changes.
57
+ In `tui.json`, load the source TUI entry separately:
58
+
59
+ ```json
60
+ {
61
+ "plugin": ["./tui.tsx"]
62
+ }
63
+ ```
64
+
65
+ Paths are relative to the declaring config file. Run `npm run build` for the server bundle, then restart OpenCode; `./tui` is intentionally exported as TypeScript source for the TUI loader, not an emitted `dist/tui.js` file.
50
66
 
51
67
  ## Configuration
52
68
 
53
- All options can be set via plugin config in `opencode.json` or environment variables. Env vars take precedence.
69
+ Options can be set in the plugin options in `opencode.json` or with the listed environment variables. An explicitly provided plugin option takes precedence over its environment variable; otherwise the environment variable overrides the default.
54
70
 
55
71
  ```json
56
72
  {
@@ -58,9 +74,8 @@ All options can be set via plugin config in `opencode.json` or environment varia
58
74
  [
59
75
  "@vikrant82/opencode-cache-keepalive",
60
76
  {
61
- "intervalMs": 300000,
62
- "windowMs": 3600000,
63
- "providerAllowlist": ["copilot", "anthropic"],
77
+ "intervals": { "claude": 285000, "gpt": 1680000 },
78
+ "hosts": ["githubcopilot.com"],
64
79
  "debug": true
65
80
  }
66
81
  ]
@@ -68,59 +83,68 @@ All options can be set via plugin config in `opencode.json` or environment varia
68
83
  }
69
84
  ```
70
85
 
71
- | Option | Default | Env Var | Description |
72
- | ------------------------- | ------------------------------------------------------ | -------------------------------- | ----------------------------------------------------------------- |
73
- | `enabled` | `true` | `OPENCODE_KEEPALIVE_ENABLED` | Master switch. When false, no timers or hooks are registered. |
74
- | `intervalMs` | `270000` (4.5min) | `OPENCODE_KEEPALIVE_INTERVAL_MS` | Milliseconds between pings. Must stay under provider cache TTL. |
75
- | `windowMs` | `3300000` (55min) | `OPENCODE_KEEPALIVE_WINDOW_MS` | How long to keep warming after last real response. |
76
- | `pingToken` | `"~"` | — | Single token sent as user message; model replies with same token. |
77
- | `revertPing` | `true` | `OPENCODE_KEEPALIVE_REVERT_PING` | Remove synthetic ping turns from session history. |
78
- | `injectSystemInstruction` | `true` | — | Append stable instruction so model answers `~` with single token. |
79
- | `includeChildSessions` | `false` | — | Warm subagent/child sessions too. Off by default. |
80
- | `debug` | `false` | `OPENCODE_KEEPALIVE_DEBUG` | Enable verbose logging to server.log. |
81
- | `providerAllowlist` | `["copilot"]` | — | Provider ID substrings eligible for warming. |
82
- | `modelAllowlist` | `["claude","anthropic","sonnet","opus","haiku","gpt"]` | — | Model ID substrings eligible for warming. |
86
+ The tuple-with-options form is supported by OpenCode's v1.18.33 plugin config schema (`string` or `[package, options]`). The options example applies to the server plugin configuration in `opencode.json`.
87
+
88
+ | Option | Default | Env Var | Description |
89
+ | ---------------------- | ----------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------- |
90
+ | `enabled` | `true` | `OPENCODE_KEEPALIVE_ENABLED` | Master switch. |
91
+ | `intervals` | `{claude:285000,gpt:1680000}` | `OPENCODE_KEEPALIVE_INTERVALS` | Milliseconds per matching model substring; first case-insensitive match wins. |
92
+ | `hosts` | `["githubcopilot.com"]` | `OPENCODE_KEEPALIVE_HOSTS` | Allowed hostname suffixes. |
93
+ | `cacheReadFactor` | `0.1` | `OPENCODE_KEEPALIVE_CACHE_READ_FACTOR` | Relative cost of cached input. |
94
+ | `missFactor` | `1.0` | `OPENCODE_KEEPALIVE_MISS_FACTOR` | Relative cost of uncached input. |
95
+ | `maxReplaysPerGap` | `"auto"` (9) | `OPENCODE_KEEPALIVE_MAX_REPLAYS_PER_GAP` | Auto cap is `floor((missFactor-cacheReadFactor)/cacheReadFactor)`. |
96
+ | `includeChildSessions` | `false` | `OPENCODE_KEEPALIVE_INCLUDE_CHILD_SESSIONS` | Include child sessions. |
97
+ | `replayTimeoutMs` | `60000` | `OPENCODE_KEEPALIVE_REPLAY_TIMEOUT_MS` | Maximum time for one replay attempt. |
98
+ | `maxStoredBytes` | `67108864` (64 MiB) | `OPENCODE_KEEPALIVE_MAX_STORED_BYTES` | Maximum in-memory request-body storage for replay targets. |
99
+ | `debug` | `false` | `OPENCODE_KEEPALIVE_DEBUG` | Verbose server log output. |
83
100
 
84
101
  ## TUI Integration
85
102
 
86
- The plugin registers a sidebar footer showing live keepalive status:
103
+ The package contains separate server and TUI entries. Source-verified against OpenCode v1.18.33: server plugins load from `opencode.json`; TUI plugins load from `tui.json` (or `tui.jsonc`) using the package's `./tui` export. See the [TUI configuration docs](https://opencode.ai/docs/tui/), [server config schema](https://opencode.ai/config.json), [TUI config schema](https://opencode.ai/tui.json), and [v1.18.33 plugin loader source](https://github.com/anomalyco/opencode/tree/v1.18.33/packages/opencode/src/plugin). The human has observed the footer and commands in a live UI; loading the final isolated build and its UI integration were not established, so treat that integration as an open release risk.
104
+
105
+ When loaded, the sidebar footer is hidden until a session has a persisted replay entry. It reports:
87
106
 
88
107
  ```
89
- keepalive armed every 4m 30s
90
- idle 03:42 · sent 2 · left 10
91
- ✓ hit input 12.4k · read 11.8k · write 0
108
+ keepalive idle · 2/9 · next 4:45
109
+ refreshes 2 · hits 1/1 · saved ~49k tok
92
110
  ```
93
111
 
94
112
  Metrics:
95
113
 
96
- - **idle**: Time since last real assistant response
97
- - **every**: Effective ping interval, including any runtime project override
98
- - **sent**: Ping attempts in current warm window (includes failures)
99
- - **left**: Estimated pings remaining before window expires
100
- - **hit/miss**: Cache hit status of last ping with token breakdown
114
+ - **state**: `keepalive standby · model working`, `keepalive idle/busy`, a refresh stop/expiry reason, or `keepalive off`
115
+ - **refresh**: Time until next refresh, or successful refresh count in the current gap
116
+ - **metrics**: Session refresh count, resume hits/count when available, and gross cache-write tokens avoided. “Saved” is gross and does not subtract refresh cost; replay cache-read token usage is logged in `server.log` as `cacheRead` when the API exposes it, and resume accounting logs `replayRead`.
101
117
 
102
118
  Slash commands (available in TUI palette):
103
119
 
104
- - `/keepalive-toggle` — Toggle keepalive on/off at runtime
105
- - `/keepalive-on` — Enable keepalive
106
- - `/keepalive-off` — Disable keepalive
107
- - `/keepalive-interval` — Set this project's ping interval at runtime (presets for 5-minute and 30-minute caches, custom durations, or reset to the plugin default); persists per project until changed
120
+ - `/keepalive-toggle` — Toggle keepalive for the current session only
121
+ - `/keepalive-on` — Enable keepalive for the current session
122
+ - `/keepalive-off` — Disable keepalive for the current session
123
+
124
+ Runtime overrides are stored by session in the project's `control-<directory-hash>.json` file. `/keepalive-off` aborts scheduled/in-flight replays and discards the in-memory replay payload. `/keepalive-on` permits future capture but does not restore that payload: make a fresh eligible real request to resume warming. Legacy folder-wide version 1 `enabled` values are ignored; the config `enabled` option remains the global master switch. Child sessions are excluded unless `includeChildSessions` is enabled.
108
125
 
109
126
  ## How It Works
110
127
 
111
- 1. Real turn completes → `session.idle` event → engine arms warm window
112
- 2. Every `intervalMs` (with ±15s jitter), engine sends `~` as user message
113
- 3. Model replies with `~` (single token); engine reads `tokens.cache.read` to detect hit
114
- 4. Synthetic `~`/`~` turn is reverted from session history (if `revertPing` enabled)
115
- 5. Window closes after `windowMs` or when a new real turn starts
116
- 6. Server plugin persists state to disk; TUI plugin polls it every 1s for live readout
128
+ 1. A request passes through the wrapper to the original `fetch` unchanged. An eligible request is a POST to a configured host suffix and supported API path, with a session ID and a model matching an `intervals` key; child sessions are excluded by default. Supported path suffixes are `/v1/messages`, `/v1/responses` or `/responses`, and `/chat/completions` (optional trailing slash).
129
+ 2. During idle or tool-busy gaps, the engine replays the current session request at its model's interval. It aborts after an API-specific SSE checkpoint: Messages `message_start`, Responses' first event other than `response.created`/`response.in_progress`, or the first Chat Completions chunk.
130
+ 3. A new real request starts a gap and resets its replay counter; actual eligible requests replace the saved payload. Successful replays stop at the auto (or numeric) cap. Network errors, timeouts, and other non-OK statuses get one retry after 10 seconds, then lapse; HTTP 400/401/403 reject and stop immediately. For Messages, a replay reporting zero cache-read and positive cache-creation tokens lapses that session. These are event/status-driven stops, not a universal TTL; the footer's “cache expired” label indicates a lapse, not a measured provider TTL.
131
+ 4. The next real completion for that session reports whether the cache hit; “saved” counts gross cache-write tokens avoided (prompt tokens on a hit, zero on a miss). Refresh cache-read cost is reported separately in `server.log` as `replayRead`.
132
+ 5. The server writes sanitized v2 per-process telemetry files; payloads (including URL, headers, and body) remain only in memory. The TUI reads the freshest session entry and polls every second. Process state files are cleaned up with their process lifecycle/stale-process cleanup; session control overrides are separately persisted and ignored after 30 days.
133
+
134
+ ### Cost model and cache cap
135
+
136
+ With cached reads costing `cacheReadFactor` and a full miss costing `missFactor`, the automatic replay cap is `floor((missFactor - cacheReadFactor) / cacheReadFactor)`. At defaults, one full-cache miss costs 1.0 input units, a cached read costs 0.1, and the maximum is 9 successful replays per gap. The estimate is an input-token-equivalent comparison, not a billing guarantee; provider pricing and cache-write rules can differ.
137
+
138
+ ### Privacy and upgrade notes
139
+
140
+ The replay request (including its URL, headers, and body) is held only in process memory and is never written to disk. State files contain session telemetry and process totals; `server.log` can contain session IDs, model/API/host/path, replay outcomes/status/latency, and token-usage metadata, but not request bodies, credentials, or conversation text. Legacy/v1 state files are ignored and not removed by v2 cleanup. Version 0.2.0 removes synthetic `~` messages and their system prompt instruction. This is a breaking behavior change: old `intervalMs`/`intervalSeconds`, `windowMs`/`windowMinutes`, `revertPing`, `pingToken`, `injectSystemInstruction`, provider/model allowlists, and Claude busy-warm options are ignored with warnings; runtime `/keepalive-interval` is removed. Configure `intervals` and `hosts` instead. See [MIGRATION.md](./MIGRATION.md) for migration notes and release checks.
117
141
 
118
142
  ## Compatibility
119
143
 
120
- - **OpenCode**: >=1.4.3
121
- - **Node**: >=18 (ESM)
122
- - **Supported providers**: Copilot (default), Anthropic, OpenAI (via allowlists)
123
- - **Models**: Claude, GPT families (via allowlists)
144
+ - **Previously stated/declared baseline, not tested support range**: OpenCode >=1.4.3 (peer dependency); Node >=18 was previously stated but `package.json` has no `engines` field. This checkout's observed environment was Node 22.22.3, OpenCode 1.18.33, `@opencode-ai/plugin` 1.17.16, and `@opencode-ai/sdk` 1.17.16. Live plugin/TUI integration is untested, and compatibility across the declared ranges has not been validated.
145
+ - **Supported hosts by default**: `githubcopilot.com` and its subdomains; configure other allowed host suffixes explicitly
146
+ - **Supported API paths**: `/v1/messages`, `/v1/responses` or `/responses`, and `/chat/completions`
147
+ - **Eligible models**: request model string must contain a configured `intervals` key; defaults are `claude` and `gpt` (case-insensitive, first matching key wins)
124
148
 
125
149
  ## Development
126
150
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAYjD,QAAA,MAAM,MAAM,EAAE,MA8Cb,CAAA;AAED,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAUjD,QAAA,MAAM,MAAM,EAAE,MAwBb,CAAA;AAED,eAAe,MAAM,CAAA"}