pi-opencode-cli-bridge 0.2.16 → 0.2.18

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/README.md CHANGED
@@ -33,7 +33,7 @@ The original MIT copyright notice is preserved in [LICENSE](LICENSE). The new pa
33
33
 
34
34
  - Node.js **22.19.0 or newer**.
35
35
  - Pi Coding Agent **1.2.0 or newer**; the development SDK is pinned to 1.2.0.
36
- - OpenCode installed on the same machine and available on `PATH`, or selected with `OPENCODE_PI_BIN`. Supports OpenCode up to **2.2.5**. Real-CLI integration tests cover **1.19.0** and **2.2.5**; intermediate releases are not individually verified.
36
+ - OpenCode installed on the same machine and available on `PATH`, or selected with `OPENCODE_PI_BIN`. Supports OpenCode up to **2.2.6**. Real-CLI integration tests cover **1.19.0** and **2.2.6**; intermediate releases are not individually verified.
37
37
 
38
38
  Check OpenCode before starting Pi:
39
39
 
@@ -88,16 +88,16 @@ For an isolated text smoke test:
88
88
  pi -p --no-session --provider opencode-cli --model opencode/deepseek-v4.1-flash-free --thinking off "Reply with exactly OK"
89
89
  ```
90
90
 
91
- Model availability changes. Refresh the list with `/opencode-pi update` if the example model is no longer listed. Bundled free models do not require an OpenCode login; availability and server-side acceptance are controlled by OpenCode.
91
+ Model availability changes. Refresh the list with `/pi-opencode-cli-bridge update` if the example model is no longer listed. Bundled free models do not require an OpenCode login; availability and server-side acceptance are controlled by OpenCode.
92
92
 
93
- The provider ID `opencode-cli` and the command `/opencode-pi` retain their upstream names for compatibility:
93
+ The command is `/pi-opencode-cli-bridge`; it replaces `/opencode-pi`, which is no longer registered. The provider ID `opencode-cli` and the `OPENCODE_PI_*` environment variables remain unchanged for compatibility:
94
94
 
95
95
  ```text
96
- /opencode-pi status
97
- /opencode-pi models
98
- /opencode-pi test
99
- /opencode-pi update
100
- /opencode-pi help
96
+ /pi-opencode-cli-bridge status
97
+ /pi-opencode-cli-bridge models
98
+ /pi-opencode-cli-bridge test
99
+ /pi-opencode-cli-bridge update
100
+ /pi-opencode-cli-bridge help
101
101
  ```
102
102
 
103
103
  The `test` command prints diagnostic commands; it does not send a model request itself.
@@ -109,7 +109,7 @@ The `test` command prints diagnostic commands; it does not send a model request
109
109
  | `OPENCODE_PI_BIN` | Path to the OpenCode executable. Defaults to `opencode`. |
110
110
  | `OPENCODE_PI_MODELS` | Comma- or space-separated model IDs. IDs without a provider prefix receive `opencode/`. |
111
111
 
112
- An explicit model list skips startup discovery and starts with conservative fallback capabilities. Run `/opencode-pi update` to discover image input, reasoning variants, token limits and costs.
112
+ An explicit model list skips startup discovery and starts with conservative fallback capabilities. Run `/pi-opencode-cli-bridge update` to discover image input, reasoning variants, token limits and costs.
113
113
 
114
114
  Without an override, discovery selects active `opencode/` models whose reported input and output costs are zero. OpenCode 2.x discovery uses the local `/api/model` endpoint, excludes disabled models, and checks every pricing tier before selecting a free model. For explicitly configured tiered models, displayed costs conservatively use the highest reported rate for each cost field. When cost metadata is missing, selection falls back to the upstream free-model naming rules. Review costs before explicitly selecting a paid model.
115
115
 
@@ -140,11 +140,11 @@ Reasoning variants, image support and token limits follow CLI discovery. Token u
140
140
 
141
141
  - Prompts, system instructions, tool declarations, conversation text and attached images pass to OpenCode and its model provider. Do not send confidential data unless that provider's policies are suitable.
142
142
  - The extension does not directly extract credentials or call model HTTP endpoints. The OpenCode subprocess still runs as your user and can use its own configuration, credentials and inherited environment.
143
- - The native-tool guard is a guard rail, **not a sandbox**. Integration tests run the real OpenCode 1.19.0 and 2.2.5 CLIs against a local model fixture that requests native `write` and `bash`/`shell` calls, and check that neither runs with the legacy plugin intact, missing, or failing at startup. Other OpenCode versions, tools contributed by your own global OpenCode configuration (for example MCP servers), and a hostile local process are not covered.
143
+ - The native-tool guard is a guard rail, **not a sandbox**. Integration tests run the real OpenCode 1.19.0 and 2.2.6 CLIs against a local model fixture that requests native `write` and `bash`/`shell` calls, and check that neither runs with the legacy plugin intact, missing, or failing at startup. Other OpenCode versions, tools contributed by your own global OpenCode configuration (for example MCP servers), and a hostile local process are not covered.
144
144
  - Pi and OpenCode can both retain local conversation data. Best-effort cleanup is not a guarantee of secure deletion.
145
145
  - Free-tier model availability and accepted request shapes can change. This fork makes no guarantee of continued access or compliance with a hosted provider's terms; review the applicable terms yourself.
146
- - Live tests on OpenCode 2.2.5 with DeepSeek v4.1 Flash Free verified text replies, a Pi `read` call and tool-result continuation with thinking off. High thinking was not reverified on 2.2.5; an earlier test timed out. No default thinking setting is changed by this package.
147
- - At startup Pi warns when your OpenCode version exceeds the supported maximum, **2.2.5**, or its version cannot be determined.
146
+ - Live tests on OpenCode 2.2.6 with DeepSeek v4.1 Flash Free verified text replies, a Pi `read` call and tool-result continuation with thinking off. High thinking was not reverified on 2.2.6; an earlier test timed out. No default thinking setting is changed by this package.
147
+ - At startup Pi warns when your OpenCode version exceeds the supported maximum, **2.2.6**, or its version cannot be determined.
148
148
  - Timeouts and cancellation escalate from `SIGTERM` to `SIGKILL` on the CLI's process group after 250 ms; on Windows the whole process tree is ended with `taskkill /T /F` (not tested on Windows). If OpenCode quits before reading the prompt, the turn shows OpenCode's own error rather than a broken-pipe error. Malformed or unexpected CLI events end the turn with an error instead of crashing Pi. Shutdown waits for session cleanup.
149
149
 
150
150
  See [SECURITY.md](SECURITY.md) for the trust boundaries and [docs/code-review.md](https://github.com/Gybra/pi-opencode-cli-bridge/blob/main/docs/code-review.md) for what was fixed and what remains. This is an experimental, unaudited fork.
@@ -159,7 +159,7 @@ OPENCODE_PI_INTEGRATION_BIN="$(which opencode)" npm run test:integration
159
159
  npm pack --dry-run
160
160
  ```
161
161
 
162
- `npm test` uses a fake OpenCode executable. `npm run test:integration` needs the real OpenCode CLI at version 1.19.0 or 2.2.5 (on `PATH` or in `OPENCODE_PI_INTEGRATION_BIN`), runs it with isolated home and data directories against a local model fixture, and makes no network request. Neither suite needs API credentials. Development SDKs are pinned; Pi supplies those packages at runtime. The npm archive includes the extension source, README, security policy and license, not tests or installed dependencies.
162
+ `npm test` uses a fake OpenCode executable. `npm run test:integration` needs the real OpenCode CLI at version 1.19.0 or 2.2.6 (on `PATH` or in `OPENCODE_PI_INTEGRATION_BIN`), runs it with isolated home and data directories against a local model fixture, and makes no network request. Neither suite needs API credentials. Development SDKs are pinned; Pi supplies those packages at runtime. The npm archive includes the extension source, README, security policy and license, not tests or installed dependencies.
163
163
 
164
164
  ## License
165
165
 
package/SECURITY.md CHANGED
@@ -10,7 +10,7 @@ Never include prompts, conversation history, images, API keys, auth files or ses
10
10
  - Requests are delegated to the real OpenCode CLI. The extension does not directly read credentials, but the subprocess inherits the environment and uses OpenCode's own configuration and authentication.
11
11
  - System instructions, tool declarations, transcript text and image attachments can reach the selected model provider. Provider retention and training policies apply.
12
12
  - The current Pi tool list is checked before marker responses become Pi tool calls. Pi remains responsible for argument validation and tool permission checks.
13
- - Native OpenCode tools are guarded by an agent permission of `ask` for everything, which non-interactive `opencode run` rejects. On 1.19.0 a generated `tool.execute.before` plugin provides a second guard; on 2.2.5 the bridge relies on permissions, not that legacy plugin. Native declarations remain visible to the model. Real-CLI integration tests on both releases request `write` and `bash`/`shell` side effects and verify that neither executes with the legacy plugin intact, missing, or failing. These guards are not a security boundary against a hostile local process, your own OpenCode configuration (it is loaded and may add tools or agent overrides), or other OpenCode versions.
13
+ - Native OpenCode tools are guarded by an agent permission of `ask` for everything, which non-interactive `opencode run` rejects. On 1.19.0 a generated `tool.execute.before` plugin provides a second guard; on 2.2.6 the bridge relies on permissions, not that legacy plugin. Native declarations remain visible to the model. Real-CLI integration tests on both releases request `write` and `bash`/`shell` side effects and verify that neither executes with the legacy plugin intact, missing, or failing. These guards are not a security boundary against a hostile local process, your own OpenCode configuration (it is loaded and may add tools or agent overrides), or other OpenCode versions.
14
14
  - Temporary project directories and OpenCode session records are removed best-effort. Pi's own conversation history is not deleted by the extension.
15
15
 
16
16
  ## Known gaps
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-opencode-cli-bridge",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "description": "Bridge the OpenCode CLI into Pi Coding Agent",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
package/src/cli.ts CHANGED
@@ -55,7 +55,7 @@ export function runCapture(
55
55
  /** Build the install/setup instructions shown when the opencode CLI is unusable. */
56
56
  export function setupGuidance(error: string): string {
57
57
  return [
58
- "opencode-pi could not use the local OpenCode CLI.",
58
+ "pi-opencode-cli-bridge could not use the local OpenCode CLI.",
59
59
  `Reason: ${error}`,
60
60
  "Install OpenCode (https://opencode.ai), ensure `opencode --version` works on PATH, then reload Pi.",
61
61
  "Set OPENCODE_PI_BIN to override the executable path.",
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@ import type { OpenCodeModelInfo } from "./types/models.js";
9
9
 
10
10
  const PROVIDER_ID = "opencode-cli";
11
11
  const API_ID = "opencode-cli-runner";
12
- const MAX_SUPPORTED_OPENCODE_VERSION = "2.2.5";
12
+ const MAX_SUPPORTED_OPENCODE_VERSION = "2.2.6";
13
13
  let registeredModels: OpenCodeModelInfo[] = [];
14
14
  let lastDiscoveryTime: number | undefined;
15
15
  let lastDiscoveryError: string | undefined;
@@ -45,7 +45,7 @@ async function refreshModels(
45
45
 
46
46
  const newModels = models.filter((model) => !previousModels.has(model.id));
47
47
 
48
- let msg = `opencode-pi: refreshed ${models.length} model(s).`;
48
+ let msg = `pi-opencode-cli-bridge: refreshed ${models.length} model(s).`;
49
49
  if (newModels.length > 0) {
50
50
  msg += ` ${newModels.length} new: ${newModels
51
51
  .slice(0, 5)
@@ -77,7 +77,7 @@ function statusLines(): string[] {
77
77
  const lines = [
78
78
  `Provider: ${PROVIDER_ID}`,
79
79
  `OpenCode binary: ${opencodeBin()}`,
80
- `OpenCode installed: ${existsSync(opencodeBin()) || opencodeBin() === "opencode" ? "check PATH with /opencode-pi test" : "no"}`,
80
+ `OpenCode installed: ${existsSync(opencodeBin()) || opencodeBin() === "opencode" ? "check PATH with /pi-opencode-cli-bridge test" : "no"}`,
81
81
  `Registered models: ${registeredModels.length}`,
82
82
  `Last discovery: ${lastDiscoveryTime ? new Date(lastDiscoveryTime).toLocaleString() : "never"}`,
83
83
  ];
@@ -101,7 +101,7 @@ function statusLines(): string[] {
101
101
  "OpenCode tools are disabled; Pi tool use is bridged with prompt-level tool-call markers.",
102
102
  );
103
103
  lines.push(
104
- "Run /opencode-pi update to refresh the model list from opencode.",
104
+ "Run /pi-opencode-cli-bridge update to refresh the model list from opencode.",
105
105
  );
106
106
  return lines;
107
107
  }
@@ -146,31 +146,31 @@ export default async function opencodePiExtension(pi: ExtensionAPI) {
146
146
  ? "OPENCODE_PI_MODELS skipped discovery, so this was not detected at startup. "
147
147
  : "";
148
148
  ctx.ui.notify(
149
- `opencode-pi: ${fastPathNote}${setupGuidance(cliStatus.detail ?? cliStatus.summary)}`,
149
+ `pi-opencode-cli-bridge: ${fastPathNote}${setupGuidance(cliStatus.detail ?? cliStatus.summary)}`,
150
150
  "warning",
151
151
  );
152
152
  return;
153
153
  }
154
154
  ctx.ui.notify(
155
- `opencode-pi: registered ${registeredModels.length} OpenCode CLI model(s). Use /model and pick ${PROVIDER_ID}.`,
155
+ `pi-opencode-cli-bridge: registered ${registeredModels.length} OpenCode CLI model(s). Use /model and pick ${PROVIDER_ID}.`,
156
156
  "info",
157
157
  );
158
158
  const version = /\d+\.\d+\.\d+/.exec(cliStatus.summary)?.[0];
159
159
  if (!version || version.localeCompare(MAX_SUPPORTED_OPENCODE_VERSION, undefined, { numeric: true }) > 0) {
160
160
  ctx.ui.notify(
161
- `opencode-pi: detected OpenCode ${version ?? cliStatus.summary}. This bridge supports OpenCode up to ${MAX_SUPPORTED_OPENCODE_VERSION}. Please install a supported version.`,
161
+ `pi-opencode-cli-bridge: detected OpenCode ${version ?? cliStatus.summary}. This bridge supports OpenCode up to ${MAX_SUPPORTED_OPENCODE_VERSION}. Please install a supported version.`,
162
162
  "warning",
163
163
  );
164
164
  }
165
165
  if (lastDiscoveryError) {
166
166
  ctx.ui.notify(
167
- `opencode-pi: model discovery used fallback (${lastDiscoveryError})`,
167
+ `pi-opencode-cli-bridge: model discovery used fallback (${lastDiscoveryError})`,
168
168
  "warning",
169
169
  );
170
170
  }
171
171
  });
172
172
 
173
- pi.registerCommand("opencode-pi", {
173
+ pi.registerCommand("pi-opencode-cli-bridge", {
174
174
  description: "OpenCode CLI bridge status and setup help",
175
175
  handler: async (args: string, ctx: any) => {
176
176
  const sub = args.trim().split(/\s+/).filter(Boolean)[0] ?? "status";
@@ -205,7 +205,7 @@ export default async function opencodePiExtension(pi: ExtensionAPI) {
205
205
  }
206
206
  if (sub === "help") {
207
207
  ctx.ui.notify(
208
- "Usage: /opencode-pi [status|models|test|update|help]",
208
+ "Usage: /pi-opencode-cli-bridge [status|models|test|update|help]",
209
209
  "info",
210
210
  );
211
211
  ctx.ui.notify(
@@ -219,7 +219,7 @@ export default async function opencodePiExtension(pi: ExtensionAPI) {
219
219
  return;
220
220
  }
221
221
  ctx.ui.notify(
222
- `Unknown /opencode-pi subcommand: ${sub}. Try /opencode-pi help`,
222
+ `Unknown /pi-opencode-cli-bridge subcommand: ${sub}. Try /pi-opencode-cli-bridge help`,
223
223
  "warning",
224
224
  );
225
225
  },
package/src/models.ts CHANGED
@@ -299,7 +299,7 @@ export async function discoverModels(opts?: {
299
299
  // models to register, so the fast (non-forced) path skips spawning
300
300
  // opencode entirely rather than making explicitly configured users pay a
301
301
  // discovery timeout on every startup when the binary is missing or slow.
302
- // `forceDiscovery` (used by the user-initiated /opencode-pi update
302
+ // `forceDiscovery` (used by the user-initiated /pi-opencode-cli-bridge update
303
303
  // command) still runs discovery so configured models can be enriched with
304
304
  // real capability metadata (reasoning/image/limits) on request.
305
305
  if (configured?.length && !opts?.forceDiscovery) {
package/src/sessions.ts CHANGED
@@ -136,7 +136,7 @@ export function continuationDelta(
136
136
  }
137
137
 
138
138
  export async function createTempAgentDir(): Promise<string> {
139
- const dir = await mkdtemp(join(tmpdir(), "opencode-pi-"));
139
+ const dir = await mkdtemp(join(tmpdir(), "pi-opencode-cli-bridge-"));
140
140
  const configDir = join(dir, ".opencode");
141
141
  const agentsDir = join(configDir, "agents");
142
142
  const pluginsDir = join(configDir, "plugins");