diff --git a/Dockerfile b/Dockerfile index 824a5d0..a27f12d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,8 +25,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* \ && ln -s /usr/bin/fdfind /usr/local/bin/fd -ARG OPENCODE_VERSION=2.0.27 -ARG OPENCHAMBER_VERSION=2.2.0 +ARG OPENCODE_VERSION=2.0.29 +ARG OPENCHAMBER_VERSION=2.3.2 ARG TYPESCRIPT_VERSION=7.0.2 ARG PNPM_VERSION=12.11.2 ARG TARGETARCH diff --git a/README.md b/README.md index 818bd11..b72696d 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Grafana and Karakeep can connect before their credentials are validated; check a - **Build** is the default agent and can use all configured tools. **General** can implement and test; **Explore** is read-only. Both subagents may use Context7 but deny Grafana, Lunch Money, Karakeep, Notion, Robinhood, and further delegation. Build and General ask before `rm` commands whose text contains `.config`, `.local`, `HOME`, `~`, or `/data/.`, or ends in `/data`. Tool permissions do not sandbox shell access. - [Superpowers](https://github.com/obra/superpowers) supplies planning, debugging, testing, and review skills. The image also ships [`commit-push-pr` and `go-repo`](skills/). [`AGENTS.md`](AGENTS.md) requires repository edits in `/data/workspace/.worktrees//`. - [OpenCode Quota](https://github.com/slkiser/opencode-quota) provides `/quota` and `/quota_status`. -- Defaults and pinned plugins live in [`opencode.jsonc`](opencode.jsonc). The image converts it to `/etc/opencode/opencode.json`; project `opencode.json(c)` files can override settings. See the [V2 configuration guide](https://opencode.ai/v2/docs/config). +- Defaults and pinned plugins live in [`opencode.jsonc`](opencode.jsonc). The image converts it to `/etc/opencode/opencode.json`, which overrides matching settings in global and project `opencode.json(c)` files. See the [V2 configuration guide](https://opencode.ai/v2/docs/config). - Each startup copies the image's [`AGENTS.md`](AGENTS.md) to `/data/.config/opencode/AGENTS.md`, replacing local edits. Change instructions in this repository and rebuild. To replace the image defaults, install dependencies, edit `opencode.jsonc`, run `node scripts/build-config.mjs runtime.json`, and mount the output read-only at `/etc/opencode/opencode.json`. Restart the container after replacing it. diff --git a/opencode.jsonc b/opencode.jsonc index 25f1a04..93dbc80 100644 --- a/opencode.jsonc +++ b/opencode.jsonc @@ -128,23 +128,21 @@ "superpowers@git+https://github.com/obra/superpowers.git#bb92a77741419a4ab5f06e711a283343f1ada0c3", "@slkiser/opencode-quota@5.0.2" ], - "experimental": { - "policies": [ - { - "action": "provider.use", - "resource": "*", - "effect": "deny" - }, - { - "action": "provider.use", - "resource": "google", - "effect": "allow" - }, - { - "action": "provider.use", - "resource": "github-copilot", - "effect": "allow" - } - ] - } + "policies": [ + { + "action": "provider.use", + "resource": "*", + "effect": "deny" + }, + { + "action": "provider.use", + "resource": "google", + "effect": "allow" + }, + { + "action": "provider.use", + "resource": "github-copilot", + "effect": "allow" + } + ] } diff --git a/package.json b/package.json index 5eb53dc..db7b837 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "test": "node --test tests/*.test.mjs" }, "devDependencies": { - "@opencode/plugin": "2.0.27", - "@opencode/schema": "2.0.27", - "effect": "4.0.2", + "@opencode/plugin": "2.0.29", + "@opencode/schema": "2.0.29", + "effect": "4.0.4", "jsonc-parser": "3.3.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index def5e74..c3a9ec2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -167,14 +167,14 @@ importers: .: devDependencies: '@opencode/plugin': - specifier: 2.0.27 - version: 2.0.27(@opentelemetry/semantic-conventions@1.43.0)(redis@6.3.0(@opentelemetry/api@1.9.0)) + specifier: 2.0.29 + version: 2.0.29(@opentelemetry/semantic-conventions@1.43.0)(redis@6.3.0(@opentelemetry/api@1.9.0)) '@opencode/schema': - specifier: 2.0.27 - version: 2.0.27 + specifier: 2.0.29 + version: 2.0.29 effect: - specifier: 4.0.2 - version: 4.0.2 + specifier: 4.0.4 + version: 4.0.4 jsonc-parser: specifier: 3.3.1 version: 3.3.1 @@ -400,11 +400,11 @@ packages: resolution: {integrity: sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==} engines: {node: ^20.17.0 || >=22.9.0} - '@opencode/ai@2.0.27': - resolution: {integrity: sha512-RiVtSBo1veffbDnrWo++04XdlcSEzqCAxo1TWDtG/5fZSjWLuiII6OT6Fo/N8ScU/awy9X3omfvun1aq4Lfttw==} + '@opencode/ai@2.0.29': + resolution: {integrity: sha512-Hu5U8FadWuI+do1ToBj9bhEL2wfP01JUaOWq8S6JaeHRaXcjvdsuCCFlGUtlA9PMn084gP4ewdInYPIv0B/98w==} - '@opencode/client@2.0.27': - resolution: {integrity: sha512-RqJodg+QsUgqqJVo+b2PGk2w96l7424nM4BijUSb49Iep9IyUfjDH3zfii4OGfCsmZkNCYK83Mgk9e9EeRA1iQ==} + '@opencode/client@2.0.29': + resolution: {integrity: sha512-fxjzqFAXEGiMDCzCfuKPyZbmrLQAwv0JQIi2rXfrjh3uE3UvItfqPjsiW1/sVPncJvu4UiRXHi+/0ksv3uHDPA==} peerDependencies: effect: 4.0.1 solid-js: '>=1.9.0' @@ -414,10 +414,10 @@ packages: solid-js: optional: true - '@opencode/plugin@2.0.27': - resolution: {integrity: sha512-TlK5PhHDCIieQEt/zjPlb/5BYbsyQnMSjXWhqL3rYjobKIauUNxdG+UCSCaLyQPhS9ab5zThg9v9tF6xiSyFyw==} + '@opencode/plugin@2.0.29': + resolution: {integrity: sha512-ZK1oUWrHl8u/9pt7lEJVDNKhhXQWMdHvaUuQ/96o9tDbbN+XaYTe4p6gt86F5bm0w9YgspE3TEX9WriI402Pbw==} peerDependencies: - '@opencode/theme': 2.0.27 + '@opencode/theme': 2.0.29 '@opentui/core': '>=0.5.17' '@opentui/solid': '>=0.5.17' solid-js: '>=1.9.0' @@ -431,14 +431,14 @@ packages: solid-js: optional: true - '@opencode/protocol@2.0.27': - resolution: {integrity: sha512-t1j+m5T3TBusHaL58t6gSSQQEFoi+qjVyQ0Eta/4mLeZLJDqSV8BNN6N93GFpV2MJ1iBpGmrH0C02n2Q+nDHfw==} + '@opencode/protocol@2.0.29': + resolution: {integrity: sha512-Eik6a2u2znmWdyPgpxCnMXJXySslG0Yj/XQzmM/Z/3pAxy0nMJnKLaFznnvXPNoPPII14L+CH7kUhBjLtOPGgQ==} - '@opencode/schema@2.0.27': - resolution: {integrity: sha512-BxGuiIFo503tW6UYxoBrrgjyczEvPiU3fDn45FxUHtmZgBC8kFE+ldI56ab8kV0Lu5C94ZKOniRb2bWqDu4tAg==} + '@opencode/schema@2.0.29': + resolution: {integrity: sha512-2qSyUGaeItugP3QujZrBhg2f4a4wdL9ab0m0fObHM+hlZ659YmWGzBRNI9qWR7At8AI9gnDCmgnnrQrx5/aprg==} - '@opencode/util@2.0.27': - resolution: {integrity: sha512-2TIEAJsX4UsyV9CHSk+/6jHWrEllgomgD0WQ8Ne+SN4xlmN9cGUvZo/Jgk0XrZZXSmADDOIER2HLcaI0tAr22A==} + '@opencode/util@2.0.29': + resolution: {integrity: sha512-o0xmrV5MFzB4hhapow4tSbStXAWF27598tDabqq+damJAuvPCBGorDBciosenXpOnNsEHhJm37l5KwOhb1+SNA==} '@opentelemetry/api-logs@0.219.0': resolution: {integrity: sha512-FFx7YnaYJlIjqWW/AG/yAZ0L/NEY724PipXXXQLdtZPbLwBGbUMTGL1i/esI56TWfTUXxhLfpgrnWJCG8aUJyg==} @@ -780,8 +780,8 @@ packages: effect@4.0.1: resolution: {integrity: sha512-b1VlQG9g8fwxE5QnIZuPoOP/0MsqHJSRKxUijjoM80E5q95FXrX5yWtY5XI8G+GJsBQAVSDbLS458z9a++uVvw==} - effect@4.0.2: - resolution: {integrity: sha512-YeYnLqSFrL4+tCOXRrfNP03w8FILoF/wDl+ukraJAGzXrjcS383W7LAAvGBbLatEyktmLxRq+9xJinx7QzXW5A==} + effect@4.0.4: + resolution: {integrity: sha512-Sr50OeVSC3M5UkoUYUhFf3EULryhGaZZUf6OzDHTvaznOw7HRlxOKdF3/4nvQXHL22StOyMG3Cvo8Bt7xUp+Ng==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1697,10 +1697,10 @@ snapshots: node-gyp: 12.4.0 proc-log: 6.1.0 - '@opencode/ai@2.0.27': + '@opencode/ai@2.0.29': dependencies: '@aws-sdk/credential-providers': 3.1057.0 - '@opencode/schema': 2.0.27 + '@opencode/schema': 2.0.29 '@smithy/eventstream-codec': 4.2.14 '@smithy/util-utf8': 4.2.2 aws4fetch: 1.0.20 @@ -1709,21 +1709,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@opencode/client@2.0.27(effect@4.0.1)': + '@opencode/client@2.0.29(effect@4.0.1)': dependencies: - '@opencode/protocol': 2.0.27 - '@opencode/schema': 2.0.27 + '@opencode/protocol': 2.0.29 + '@opencode/schema': 2.0.29 optionalDependencies: effect: 4.0.1 - '@opencode/plugin@2.0.27(@opentelemetry/semantic-conventions@1.43.0)(redis@6.3.0(@opentelemetry/api@1.9.0))': + '@opencode/plugin@2.0.29(@opentelemetry/semantic-conventions@1.43.0)(redis@6.3.0(@opentelemetry/api@1.9.0))': dependencies: '@ai-sdk/provider': 3.0.8 - '@opencode/ai': 2.0.27 - '@opencode/client': 2.0.27(effect@4.0.1) - '@opencode/protocol': 2.0.27 - '@opencode/schema': 2.0.27 - '@opencode/util': 2.0.27(@opentelemetry/semantic-conventions@1.43.0)(redis@6.3.0(@opentelemetry/api@1.9.0)) + '@opencode/ai': 2.0.29 + '@opencode/client': 2.0.29(effect@4.0.1) + '@opencode/protocol': 2.0.29 + '@opencode/schema': 2.0.29 + '@opencode/util': 2.0.29(@opentelemetry/semantic-conventions@1.43.0)(redis@6.3.0(@opentelemetry/api@1.9.0)) effect: 4.0.1 transitivePeerDependencies: - '@opentelemetry/sdk-trace-web' @@ -1733,17 +1733,17 @@ snapshots: - supports-color - utf-8-validate - '@opencode/protocol@2.0.27': + '@opencode/protocol@2.0.29': dependencies: - '@opencode/schema': 2.0.27 + '@opencode/schema': 2.0.29 effect: 4.0.1 - '@opencode/schema@2.0.27': + '@opencode/schema@2.0.29': dependencies: '@standard-schema/spec': 1.1.0 effect: 4.0.1 - '@opencode/util@2.0.27(@opentelemetry/semantic-conventions@1.43.0)(redis@6.3.0(@opentelemetry/api@1.9.0))': + '@opencode/util@2.0.29(@opentelemetry/semantic-conventions@1.43.0)(redis@6.3.0(@opentelemetry/api@1.9.0))': dependencies: '@effect/opentelemetry': 4.0.1(@opentelemetry/api-logs@0.219.0)(@opentelemetry/api@1.9.0)(@opentelemetry/resources@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-logs@0.219.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-node@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.43.0)(effect@4.0.1) '@effect/platform-node': 4.0.1(effect@4.0.1)(redis@6.3.0(@opentelemetry/api@1.9.0)) @@ -2100,7 +2100,7 @@ snapshots: effect@4.0.1: {} - effect@4.0.2: {} + effect@4.0.4: {} emoji-regex@8.0.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5fdb217..ebce58a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,21 +1,23 @@ minimumReleaseAgeStrict: true minimumReleaseAgeExclude: - - '@opencode/ai@2.0.27' - - '@opencode/cli-darwin-arm64@2.0.27' - - '@opencode/cli-darwin-x64-baseline@2.0.27' - - '@opencode/cli-darwin-x64@2.0.27' - - '@opencode/cli-linux-arm64-musl@2.0.27' - - '@opencode/cli-linux-arm64@2.0.27' - - '@opencode/cli-linux-x64-baseline-musl@2.0.27' - - '@opencode/cli-linux-x64-baseline@2.0.27' - - '@opencode/cli-linux-x64-musl@2.0.27' - - '@opencode/cli-linux-x64@2.0.27' - - '@opencode/cli-windows-arm64@2.0.27' - - '@opencode/cli-windows-x64-baseline@2.0.27' - - '@opencode/cli-windows-x64@2.0.27' - - '@opencode/cli@2.0.27' - - '@opencode/client@2.0.27' - - '@opencode/plugin@2.0.27' - - '@opencode/protocol@2.0.27' - - '@opencode/schema@2.0.27' - - '@opencode/util@2.0.27' + - '@openchamber/sdk@2.3.2' + - '@openchamber/web@2.3.2' + - '@opencode/ai@2.0.29' + - '@opencode/cli-darwin-arm64@2.0.29' + - '@opencode/cli-darwin-x64-baseline@2.0.29' + - '@opencode/cli-darwin-x64@2.0.29' + - '@opencode/cli-linux-arm64-musl@2.0.29' + - '@opencode/cli-linux-arm64@2.0.29' + - '@opencode/cli-linux-x64-baseline-musl@2.0.29' + - '@opencode/cli-linux-x64-baseline@2.0.29' + - '@opencode/cli-linux-x64-musl@2.0.29' + - '@opencode/cli-linux-x64@2.0.29' + - '@opencode/cli-windows-arm64@2.0.29' + - '@opencode/cli-windows-x64-baseline@2.0.29' + - '@opencode/cli-windows-x64@2.0.29' + - '@opencode/cli@2.0.29' + - '@opencode/client@2.0.29' + - '@opencode/plugin@2.0.29' + - '@opencode/protocol@2.0.29' + - '@opencode/schema@2.0.29' + - '@opencode/util@2.0.29' diff --git a/scripts/test-router-integration.mjs b/scripts/test-router-integration.mjs index 703ef7c..58a7355 100644 --- a/scripts/test-router-integration.mjs +++ b/scripts/test-router-integration.mjs @@ -132,6 +132,9 @@ try { assert.ok(data.some(server => server.name === name), `missing ${name}`); return true; }); + // Without credentials, a dropped provider policy shows up as OpenCode's free models. + const models = (await request("/api/model")).data; + assert.ok(models.every(m => ["google", "github-copilot"].includes(m.providerID)), `policies hide other providers' models: ${models.map(m => m.providerID)}`); session = (await request("/api/session", { title: "V2 integration test", agent: "build", location: { directory } })).data; await request(`/api/session/${session.id}/command`, { name: "quota_announcements", text: "" });