forked from bots-garden/ori
✨ Switch the ACP adapter to @agentclientprotocol/claude-agent-acp (template 0.0.2)
The Zed adapter (@zed-industries/claude-code-acp 0.16.2) embeds Claude Code
2.1.44, which the API now rejects for current models ("version 2.1.251 or
newer is required"), so every prompt in the sandbox failed. The Agent Client
Protocol adapter ships a current CLI (2.1.274) through the Claude Agent SDK's
per-platform native package.
- backend: DefaultAgentCommand → npx -y @agentclientprotocol/claude-agent-acp
(+ pinning test); doc comments updated
- template/Dockerfile: adapter stage installs the new adapter for the target
platform (Docker amd64 → npm x64 mapping, asserted), CMD updated
- kits/ori: startup + agent instructions use claude-agent-acp, template 0.0.2;
ports.container is a literal (sbx kit pack/push decode the raw spec)
- internal/files: pin .md/.markdown → text/markdown (host mime table differs)
- ui: Node 25 webstorage flag on the test script; Markdown.tsx type cast so
the build compiles; ToolCallCard copy text extracted into pure helpers
with tests (clears two complexity smells)
- .qlty: golangci-lint pinned to 2.13.2 (Go 1.26 project)
- docs EN+FR, packages diagram, kit/scripts/root READMEs, quickstart,
launcher: adapter, template 0.0.2, dual-stack -p …/tcp, Chrome unsafe ports
- .memory: summary, history, handoffs
Quality gate run #18 PASS (0 errors, 0 warnings, 0 smells). go test ./... and
134 vitest green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>5d476ff parent: 7895c1d added
.memory/handoffs/2026-09-18-claude-version-too-old.md +24 -0 | new file mode 100644 | ||
| @@ -0,0 +1,24 @@ | ||
| 1 | +# 2026-09-18 — Claude Code too old inside the ori sandbox | |
| 2 | + | |
| 3 | +## Problem | |
| 4 | + | |
| 5 | +Prompt fails: `Claude Code 2.1.44 does not support this model; version 2.1.251 or newer is required` (`claude_code_version_too_old`). Model = host `~/.claude/settings.json` → `claude-fable-5-1[1m]`. Sandbox `ori`: adapter `@zed-industries/claude-code-acp@0.16.2` → bundled CLI 2.1.44; system CLI `/home/agent/.local/bin/claude` → `~/.local/share/claude/versions/2.1.246` (also too old). ori's env has no `CLAUDE_CODE_EXECUTABLE`. | |
| 6 | + | |
| 7 | +## Immediate workaround (per sandbox, not yet run) | |
| 8 | + | |
| 9 | +```bash | |
| 10 | +sbx exec ori claude update # bucket latest = 2.1.276; egress verified OK | |
| 11 | +sbx exec ori ls /home/agent/.local/share/claude/versions/ | |
| 12 | +sbx exec ori sh -c 'pkill -x ori; PATH=/usr/local/share/npm-global/bin:/home/agent/.local/bin:$PATH \ | |
| 13 | + CLAUDE_CODE_EXECUTABLE=/home/agent/.local/bin/claude \ | |
| 14 | + nohup ori --addr :8888 --agent-cmd claude-code-acp --cwd /home/agent/workspace >> /home/agent/.ori.log 2>&1 &' | |
| 15 | +``` | |
| 16 | +If `~/.local/bin/claude` still points at 2.1.246 after the update, use the explicit `versions/2.1.276` path. Lost at `sbx rm`; survives stop/start (home is persistent). | |
| 17 | + | |
| 18 | +## Permanent fix — two options (user decides) | |
| 19 | + | |
| 20 | +**(b) recommended — switch adapter.** `template/Dockerfile` stage `adapter`: `npm install -g --prefix /adapter @agentclientprotocol/claude-agent-acp`; `CMD` and `kits/ori/spec.yaml` startup + agentInstructions: `--agent-cmd claude-agent-acp`; docs (summary.md line about the Zed adapter, run how-to EN/FR, kit README). **Trap**: the SDK's CLI is a per-platform optional dependency, and the `adapter` stage is built `--platform=$BUILDPLATFORM` then copied to the target — install for the target instead (`npm install --os=linux --cpu=${TARGETARCH} …`, npm ≥ 10) or drop `--platform=$BUILDPLATFORM` on that stage. Verify in the image: `claude-agent-acp` starts and a prompt round-trips (`pong`). Then `./template/build.sh 0.0.2`, bump `--template k33g/ori:0.0.2` in kit description/docs/launcher, `sbx kit push kits/ori docker.io/k33g/ori-kit:latest`. | |
| 21 | + | |
| 22 | +**(a) keep Zed adapter.** Dockerfile: `USER agent` + `RUN claude update` (≈250 MB layer, chases versions) — or download a pinned version from the release bucket; kit startup: `export CLAUDE_CODE_EXECUTABLE=/home/agent/.local/bin/claude`. Works until the API raises the floor again. | |
| 23 | + | |
| 24 | +Neither is started. | |
| new file mode 100644 | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | +# 2026-09-18 — Claude Code too old inside the ori sandbox | ||
| 2 | + | ||
| 3 | +## Problem | ||
| 4 | + | ||
| 5 | +Prompt fails: `Claude Code 2.1.44 does not support this model; version 2.1.251 or newer is required` (`claude_code_version_too_old`). Model = host `~/.claude/settings.json` → `claude-fable-5-1[1m]`. Sandbox `ori`: adapter `@zed-industries/claude-code-acp@0.16.2` → bundled CLI 2.1.44; system CLI `/home/agent/.local/bin/claude` → `~/.local/share/claude/versions/2.1.246` (also too old). ori's env has no `CLAUDE_CODE_EXECUTABLE`. | ||
| 6 | + | ||
| 7 | +## Immediate workaround (per sandbox, not yet run) | ||
| 8 | + | ||
| 9 | +```bash | ||
| 10 | +sbx exec ori claude update # bucket latest = 2.1.276; egress verified OK | ||
| 11 | +sbx exec ori ls /home/agent/.local/share/claude/versions/ | ||
| 12 | +sbx exec ori sh -c 'pkill -x ori; PATH=/usr/local/share/npm-global/bin:/home/agent/.local/bin:$PATH \ | ||
| 13 | + CLAUDE_CODE_EXECUTABLE=/home/agent/.local/bin/claude \ | ||
| 14 | + nohup ori --addr :8888 --agent-cmd claude-code-acp --cwd /home/agent/workspace >> /home/agent/.ori.log 2>&1 &' | ||
| 15 | +``` | ||
| 16 | +If `~/.local/bin/claude` still points at 2.1.246 after the update, use the explicit `versions/2.1.276` path. Lost at `sbx rm`; survives stop/start (home is persistent). | ||
| 17 | + | ||
| 18 | +## Permanent fix — two options (user decides) | ||
| 19 | + | ||
| 20 | +**(b) recommended — switch adapter.** `template/Dockerfile` stage `adapter`: `npm install -g --prefix /adapter @agentclientprotocol/claude-agent-acp`; `CMD` and `kits/ori/spec.yaml` startup + agentInstructions: `--agent-cmd claude-agent-acp`; docs (summary.md line about the Zed adapter, run how-to EN/FR, kit README). **Trap**: the SDK's CLI is a per-platform optional dependency, and the `adapter` stage is built `--platform=$BUILDPLATFORM` then copied to the target — install for the target instead (`npm install --os=linux --cpu=${TARGETARCH} …`, npm ≥ 10) or drop `--platform=$BUILDPLATFORM` on that stage. Verify in the image: `claude-agent-acp` starts and a prompt round-trips (`pong`). Then `./template/build.sh 0.0.2`, bump `--template k33g/ori:0.0.2` in kit description/docs/launcher, `sbx kit push kits/ori docker.io/k33g/ori-kit:latest`. | ||
| 21 | + | ||
| 22 | +**(a) keep Zed adapter.** Dockerfile: `USER agent` + `RUN claude update` (≈250 MB layer, chases versions) — or download a pinned version from the release bucket; kit startup: `export CLAUDE_CODE_EXECUTABLE=/home/agent/.local/bin/claude`. Works until the API raises the floor again. | ||
| 23 | + | ||
| 24 | +Neither is started. | ||
added
.memory/handoffs/2026-09-18-kit-push.md +19 -0 | new file mode 100644 | ||
| @@ -0,0 +1,19 @@ | ||
| 1 | +# 2026-09-18 — Publishing the ori kit to Docker Hub | |
| 2 | + | |
| 3 | +## State | |
| 4 | + | |
| 5 | +Kit fixed so that `sbx kit pack` / `push` accept it (see history). Ready to publish; **not pushed yet**: | |
| 6 | + | |
| 7 | +```bash | |
| 8 | +sbx kit push kits/ori docker.io/k33g/ori-kit:latest # add --sign for a Sigstore signature | |
| 9 | +sbx kit inspect docker.io/k33g/ori-kit:latest # check after push | |
| 10 | +sbx run -d claude . --template k33g/ori:0.0.1 --kit docker.io/k33g/ori-kit:latest --name ori -p 5555:8888 | |
| 11 | +``` | |
| 12 | +Auth order for push: `sbx login` session → `sbx secret set --registry` → Docker credential store (`~/.docker/config.json` has a docker.io entry). | |
| 13 | + | |
| 14 | +## Traps | |
| 15 | + | |
| 16 | +- No `sbx kit package`; verbs are `pack`, `push`, `validate`, `inspect`, `pull`, `sign`, `verify`, `provenance`. They take the kit **directory**. | |
| 17 | +- `sbx kit validate` succeeding does **not** guarantee `pack`/`push` will: validate expands `${{ kit.args.* }}` first, pack/push decode the raw YAML. Never put a placeholder in a non-string field (ports.container). Trial recipe: copy the kit to /tmp, edit, `sbx kit pack /tmp/copy -o /tmp/x.zip`. | |
| 18 | +- Provenance records the git commit of the directory: commit before pushing for a meaningful attestation. | |
| 19 | +- After publishing, the quickstart/README launch commands could reference `--kit docker.io/k33g/ori-kit:latest` instead of `./kits/ori` — not done, the user decides. | |
| new file mode 100644 | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | +# 2026-09-18 — Publishing the ori kit to Docker Hub | ||
| 2 | + | ||
| 3 | +## State | ||
| 4 | + | ||
| 5 | +Kit fixed so that `sbx kit pack` / `push` accept it (see history). Ready to publish; **not pushed yet**: | ||
| 6 | + | ||
| 7 | +```bash | ||
| 8 | +sbx kit push kits/ori docker.io/k33g/ori-kit:latest # add --sign for a Sigstore signature | ||
| 9 | +sbx kit inspect docker.io/k33g/ori-kit:latest # check after push | ||
| 10 | +sbx run -d claude . --template k33g/ori:0.0.1 --kit docker.io/k33g/ori-kit:latest --name ori -p 5555:8888 | ||
| 11 | +``` | ||
| 12 | +Auth order for push: `sbx login` session → `sbx secret set --registry` → Docker credential store (`~/.docker/config.json` has a docker.io entry). | ||
| 13 | + | ||
| 14 | +## Traps | ||
| 15 | + | ||
| 16 | +- No `sbx kit package`; verbs are `pack`, `push`, `validate`, `inspect`, `pull`, `sign`, `verify`, `provenance`. They take the kit **directory**. | ||
| 17 | +- `sbx kit validate` succeeding does **not** guarantee `pack`/`push` will: validate expands `${{ kit.args.* }}` first, pack/push decode the raw YAML. Never put a placeholder in a non-string field (ports.container). Trial recipe: copy the kit to /tmp, edit, `sbx kit pack /tmp/copy -o /tmp/x.zip`. | ||
| 18 | +- Provenance records the git commit of the directory: commit before pushing for a meaningful attestation. | ||
| 19 | +- After publishing, the quickstart/README launch commands could reference `--kit docker.io/k33g/ori-kit:latest` instead of `./kits/ori` — not done, the user decides. | ||
modified
.memory/history.md +18 -0 | @@ -152,3 +152,21 @@ | ||
| 152 | 152 | - **Changes**: `.tickets/issues/0005-….yaml` — 8 tasks rewritten (7 `closed` with `updatedAt`/`closedAt` = 2026-09-17T22:23:39Z, 1 `open`; all `priority: none`, author k33g); issue `updatedAt` bumped. `scripts/Launch Ori.app` built with `osacompile`, ignored via `.gitignore` (`scripts/*.app/`). `summary.md` gains a `.tickets` paragraph. |
| 153 | 153 | - **Verification**: bundled IssueSpec's `parseIssueDocument` (from the local clone `~/CodeBerg/issuespec`, esbuild `--format=cjs`) and ran it over all 15 tickets: all OK; the committed 0005 fails as expected. |
| 154 | 154 | - **Follow-up**: `scripts/README.md` + `scripts/README.fr.md` written (what the launcher does, run vs. double-click, design choices, handler test recipe); quickstart row now points to it. |
| 155 | + | |
| 156 | +## 2026-09-18 — `sbx kit package` does not exist | |
| 157 | + | |
| 158 | +- User hit `ERROR: sbx: unknown command: sbx kit package` (sbx v0.43.0). The verbs are `sbx kit pack DIRECTORY [-o file.zip]` (local ZIP) and `sbx kit push DIRECTORY registry/repo:tag` (package + push to OCI, adds SLSA provenance, `--sign` optional). Both take the kit **directory**, not `spec.yaml`. `sbx kit validate kits/ori` → VALID. Not pushed: publishing to Docker Hub left to the user. | |
| 159 | + | |
| 160 | +## 2026-09-18 — `sbx kit push` rejected the kit: arg placeholder in an integer field | |
| 161 | + | |
| 162 | +- **Asked**: `sbx kit push kits/ori docker.io/k33g/ori-kit:latest` failed with `invalid spec.yaml: line 38: cannot unmarshal !!str `${{ kit...` into int`. | |
| 163 | +- **Cause (verified in `sandboxes/` source, v0.44.0-rc1+26, and by trial)**: `Pack`/`Push` call `LoadFromDirectory` → strict typed decode of the raw spec (`ports[].container` is `int`), with **no** `${{ kit.args.* }}` expansion; `validate`/`inspect`/`run` expand first (`expand.go`, `argScan`), hence VALID vs INVALID for the same directory. v3 kits (`schemaVersion: "3"`, `com.docker.runtime/port@1` capabilities) keep placeholders at push and expand at pull, but the installed sbx v0.43.0 has no v3 support (0 hits for the capability type in the binary). | |
| 164 | +- **Changes**: `kits/ori/spec.yaml` `ports[0].container` → literal `8888` with a comment explaining why; `${{ kit.args.port }}` kept in the startup command and agentInstructions (string fields decode fine). Kit README, docs EN/FR how-to `run-in-a-sandbox`: with a custom port, publish it with `-p` since the declared port stays 8888. Rejected: dropping the `port` arg (loses a documented feature); moving to v3 (needs sbx ≥ 0.44 on every consumer). | |
| 165 | +- **Verification**: `sbx kit validate kits/ori` (default and `--kit-arg ori.port=9000`) VALID; `sbx kit pack kits/ori` OK; `inspect --kit-arg ori.port=9000` shows `--addr ":9000"` substituted with `"container": 8888`. **Push not run** — the user publishes. | |
| 166 | +- **Follow-up**: kit published by the user; `sbx kit inspect docker.io/k33g/ori-kit:latest` resolves (mixin, schema v2, 1 port, 1 startup command). Sandboxes running at that time: `ori` (5555→8888) and `hello-ori` (3000→8888), both on this repo. | |
| 167 | + | |
| 168 | +## 2026-09-18 — "Claude Code 2.1.44 does not support this model; 2.1.251 or newer required" | |
| 169 | + | |
| 170 | +- **Asked**: reminder of what to do to avoid this prompt failure in the sandbox (kit `docker.io/k33g/ori-kit:latest`, template `k33g/ori:0.0.1`). | |
| 171 | +- **Diagnosis (read-only, verified)**: ori in sandbox `ori` runs with no `CLAUDE_CODE_EXECUTABLE`, so the Zed adapter 0.16.2 uses its bundled CLI 2.1.44 (SDK 0.2.44). The model comes from the host `~/.claude/settings.json` (`claude-fable-5-1[1m]`), which the API only serves to CLI ≥ 2.1.251. Yesterday's workaround (point the adapter at the template's system CLI) **no longer suffices**: the base image `docker/sandbox-templates:claude-code` (built 2026-08-26) ships CLI 2.1.246. Sandbox egress reaches the Claude Code release bucket (latest = 2.1.276) and npm, so `claude update` inside is feasible. `@agentclientprotocol/claude-agent-acp@0.79.0` (bin `claude-agent-acp`) depends on `@anthropic-ai/claude-agent-sdk@0.3.274`, whose `manifest.json` says CLI **2.1.274**, delivered through per-platform optional deps (`…-sdk-linux-arm64`, `…-linux-x64`, …) — no `cli.js` any more. | |
| 172 | +- **Nothing changed**: options given to the user (immediate: `claude update` in the sandbox + restart ori with `CLAUDE_CODE_EXECUTABLE`; permanent: switch the template to the new adapter, or bake a recent CLI + the env var into template/kit). Their call. | |
| @@ -152,3 +152,21 @@ | |||
| 152 | - **Changes**: `.tickets/issues/0005-….yaml` — 8 tasks rewritten (7 `closed` with `updatedAt`/`closedAt` = 2026-09-17T22:23:39Z, 1 `open`; all `priority: none`, author k33g); issue `updatedAt` bumped. `scripts/Launch Ori.app` built with `osacompile`, ignored via `.gitignore` (`scripts/*.app/`). `summary.md` gains a `.tickets` paragraph. | 152 | - **Changes**: `.tickets/issues/0005-….yaml` — 8 tasks rewritten (7 `closed` with `updatedAt`/`closedAt` = 2026-09-17T22:23:39Z, 1 `open`; all `priority: none`, author k33g); issue `updatedAt` bumped. `scripts/Launch Ori.app` built with `osacompile`, ignored via `.gitignore` (`scripts/*.app/`). `summary.md` gains a `.tickets` paragraph. |
| 153 | - **Verification**: bundled IssueSpec's `parseIssueDocument` (from the local clone `~/CodeBerg/issuespec`, esbuild `--format=cjs`) and ran it over all 15 tickets: all OK; the committed 0005 fails as expected. | 153 | - **Verification**: bundled IssueSpec's `parseIssueDocument` (from the local clone `~/CodeBerg/issuespec`, esbuild `--format=cjs`) and ran it over all 15 tickets: all OK; the committed 0005 fails as expected. |
| 154 | - **Follow-up**: `scripts/README.md` + `scripts/README.fr.md` written (what the launcher does, run vs. double-click, design choices, handler test recipe); quickstart row now points to it. | 154 | - **Follow-up**: `scripts/README.md` + `scripts/README.fr.md` written (what the launcher does, run vs. double-click, design choices, handler test recipe); quickstart row now points to it. |
| 155 | + | ||
| 156 | +## 2026-09-18 — `sbx kit package` does not exist | ||
| 157 | + | ||
| 158 | +- User hit `ERROR: sbx: unknown command: sbx kit package` (sbx v0.43.0). The verbs are `sbx kit pack DIRECTORY [-o file.zip]` (local ZIP) and `sbx kit push DIRECTORY registry/repo:tag` (package + push to OCI, adds SLSA provenance, `--sign` optional). Both take the kit **directory**, not `spec.yaml`. `sbx kit validate kits/ori` → VALID. Not pushed: publishing to Docker Hub left to the user. | ||
| 159 | + | ||
| 160 | +## 2026-09-18 — `sbx kit push` rejected the kit: arg placeholder in an integer field | ||
| 161 | + | ||
| 162 | +- **Asked**: `sbx kit push kits/ori docker.io/k33g/ori-kit:latest` failed with `invalid spec.yaml: line 38: cannot unmarshal !!str `${{ kit...` into int`. | ||
| 163 | +- **Cause (verified in `sandboxes/` source, v0.44.0-rc1+26, and by trial)**: `Pack`/`Push` call `LoadFromDirectory` → strict typed decode of the raw spec (`ports[].container` is `int`), with **no** `${{ kit.args.* }}` expansion; `validate`/`inspect`/`run` expand first (`expand.go`, `argScan`), hence VALID vs INVALID for the same directory. v3 kits (`schemaVersion: "3"`, `com.docker.runtime/port@1` capabilities) keep placeholders at push and expand at pull, but the installed sbx v0.43.0 has no v3 support (0 hits for the capability type in the binary). | ||
| 164 | +- **Changes**: `kits/ori/spec.yaml` `ports[0].container` → literal `8888` with a comment explaining why; `${{ kit.args.port }}` kept in the startup command and agentInstructions (string fields decode fine). Kit README, docs EN/FR how-to `run-in-a-sandbox`: with a custom port, publish it with `-p` since the declared port stays 8888. Rejected: dropping the `port` arg (loses a documented feature); moving to v3 (needs sbx ≥ 0.44 on every consumer). | ||
| 165 | +- **Verification**: `sbx kit validate kits/ori` (default and `--kit-arg ori.port=9000`) VALID; `sbx kit pack kits/ori` OK; `inspect --kit-arg ori.port=9000` shows `--addr ":9000"` substituted with `"container": 8888`. **Push not run** — the user publishes. | ||
| 166 | +- **Follow-up**: kit published by the user; `sbx kit inspect docker.io/k33g/ori-kit:latest` resolves (mixin, schema v2, 1 port, 1 startup command). Sandboxes running at that time: `ori` (5555→8888) and `hello-ori` (3000→8888), both on this repo. | ||
| 167 | + | ||
| 168 | +## 2026-09-18 — "Claude Code 2.1.44 does not support this model; 2.1.251 or newer required" | ||
| 169 | + | ||
| 170 | +- **Asked**: reminder of what to do to avoid this prompt failure in the sandbox (kit `docker.io/k33g/ori-kit:latest`, template `k33g/ori:0.0.1`). | ||
| 171 | +- **Diagnosis (read-only, verified)**: ori in sandbox `ori` runs with no `CLAUDE_CODE_EXECUTABLE`, so the Zed adapter 0.16.2 uses its bundled CLI 2.1.44 (SDK 0.2.44). The model comes from the host `~/.claude/settings.json` (`claude-fable-5-1[1m]`), which the API only serves to CLI ≥ 2.1.251. Yesterday's workaround (point the adapter at the template's system CLI) **no longer suffices**: the base image `docker/sandbox-templates:claude-code` (built 2026-08-26) ships CLI 2.1.246. Sandbox egress reaches the Claude Code release bucket (latest = 2.1.276) and npm, so `claude update` inside is feasible. `@agentclientprotocol/claude-agent-acp@0.79.0` (bin `claude-agent-acp`) depends on `@anthropic-ai/claude-agent-sdk@0.3.274`, whose `manifest.json` says CLI **2.1.274**, delivered through per-platform optional deps (`…-sdk-linux-arm64`, `…-linux-x64`, …) — no `cli.js` any more. | ||
| 172 | +- **Nothing changed**: options given to the user (immediate: `claude update` in the sandbox + restart ori with `CLAUDE_CODE_EXECUTABLE`; permanent: switch the template to the new adapter, or bake a recent CLI + the env var into template/kit). Their call. | ||
modified
.memory/summary.md +4 -1 | @@ -40,6 +40,9 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess | ||
| 40 | 40 | - `make run` — with Claude Code adapter; `make run-mock` — with the demo agent (no Claude/network needed). |
| 41 | 41 | - `make template` — builds the `k33g/ori` sandbox template image (`template/Dockerfile`, FROM `docker/sandbox-templates:claude-code`); launch with `sbx run -d claude <project> --template k33g/ori:0.0.0 --kit <ori repo>/kits/ori --name ori -p 8888:8888` (detached — see the auto-stop trap below) (see `kits/ori/README.md` and docs how-to `run-in-a-sandbox`). |
| 42 | 42 | - `scripts/launch-ori.applescript` (2026-09-18) — macOS launcher: `sbx ls -q` → restart by name or create (`k33g/ori:0.0.1`, `./kits/ori`, `-p 5555:8888`), poll `http://localhost:5555/healthz` up to 90 s, then `open ori-desktop/build/bin/ori-desktop.app`. Run with `osascript`, or `osacompile` into `scripts/Launch Ori.app`; repo root derived from the script's own location. Compile-checked and handlers unit-tested; full end-to-end run not yet done. |
| 43 | +- Kit publishing (sbx v0.43.0, verified 2026-09-18): `sbx kit validate kits/ori`, `sbx kit pack kits/ori -o ori-kit.zip`, `sbx kit push kits/ori docker.io/k33g/ori-kit:<tag>` — directory argument, not `spec.yaml`; there is no `sbx kit package`. Auth: `sbx login` session, then `sbx secret set --registry`, then the Docker credential store. | |
| 44 | +- **Kit packaging trap (verified 2026-09-18)**: `pack`/`push` decode `spec.yaml` raw (no `${{ kit.args }}` expansion) — an arg placeholder in an integer field (`ports[].container`) breaks them even though `validate`/`run` accept it. `ports[0].container` is therefore a literal 8888; the `port` arg only drives the startup command and agentInstructions. | |
| 45 | +- Published kit: `docker.io/k33g/ori-kit:latest` (pushed 2026-09-18, verified with `sbx kit inspect`); usable as `--kit docker.io/k33g/ori-kit:latest` instead of `--kit ./kits/ori`. | |
| 43 | 46 | - **sbx auto-stop trap (verified in the sbx source + daemon log, 2026-09-17)**: sandboxd stops a sandbox 30 s (hard-coded `WithAutoStopDelay(30*time.Second)`, `sandboxd/pkg/server/backend_dockernext.go`) after its last CLI "sentinel" session closes; `sbx create`/`sbx exec`/`sbx run` all hold one for their own duration, browser traffic on a published port counts for nothing. Only a sandbox created with the spec field `detached: true` (CLI: `sbx run -d …`, absent from `sbx create`) is exempt; the field is create-time only (no PATCH), so an existing sandbox must be `sbx rm`'d and recreated with `sbx run -d`. No settings/env knob for the delay. |
| 44 | 47 | - Quality: `python3 ~/.claude/skills/quality/scripts/quality_report.py --workspace .` (gate PASS, run #16, 2026-09-17 late evening: 0 errors, 0 warnings, 0 smells, complex 514 — covers the selectors/previews/desktop work, the resizable file tree and the light/dark theme). |
| 45 | 48 | - `docs/source-code-analysis.adoc` — AsciiDoc snapshot analysis of the codebase (2026-09-17), outside the bilingual Diátaxis set. |
| @@ -48,7 +51,7 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess | ||
| 48 | 51 | |
| 49 | 52 | - `~/.qlty` is a dedicated 488MB volume, too small for qlty's tool cache; the cache was moved to `~/.qlty-cache` on the main disk with a symlink `~/.qlty/cache -> /home/agent/.qlty-cache`. If qlty reports "No space left on device", check this symlink survived. (It did NOT survive a sandbox recreation on 2026-09-17: the volume came back empty and the first run failed exactly that way; recreating the symlink fixed it.) |
| 50 | 53 | - `~/.npm` is the same kind of 488MB dedicated volume and filled up when installing Monaco; the npm cache now lives at `~/.npm-big` via `NPM_CONFIG_CACHE` exported in `/etc/sandbox-persistent.sh`. |
| 51 | -- Running ori inside this Claude-Code-driven sandbox requires `env -u CLAUDECODE ./bin/ori` (Claude refuses nested sessions). Also set `CLAUDE_CODE_EXECUTABLE=<current claude binary>` (e.g. `/home/agent/.local/share/claude/versions/2.1.275`): the Zed adapter 0.16.2 bundles Claude Code 2.1.44, which rejects the `fable[1m]` model from `~/.claude/settings.json`. | |
| 54 | +- Running ori inside this Claude-Code-driven sandbox requires `env -u CLAUDECODE ./bin/ori` (Claude refuses nested sessions). Also set `CLAUDE_CODE_EXECUTABLE=<current claude binary>`: the Zed adapter 0.16.2 bundles Claude Code 2.1.44, which rejects the `claude-fable-5-1[1m]` model from the host `~/.claude/settings.json`. **Since 2026-09-18 the API requires CLI ≥ 2.1.251 for that model, and the template's own CLI is 2.1.246 (base image built 2026-08-26)** — so the env var alone is not enough; run `claude update` in the sandbox first, or switch the template to `@agentclientprotocol/claude-agent-acp` (SDK 0.3.274 → CLI 2.1.274). Handoff `2026-09-18-claude-version-too-old.md`. | |
| 52 | 55 | - npm blocks install scripts by default here; esbuild's postinstall was approved via `npm approve-scripts` (recorded in `ui/package.json` `allowScripts`). |
| 53 | 56 | |
| 54 | 57 | ## Known limitations |
| @@ -40,6 +40,9 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess | |||
| 40 | - `make run` — with Claude Code adapter; `make run-mock` — with the demo agent (no Claude/network needed). | 40 | - `make run` — with Claude Code adapter; `make run-mock` — with the demo agent (no Claude/network needed). |
| 41 | - `make template` — builds the `k33g/ori` sandbox template image (`template/Dockerfile`, FROM `docker/sandbox-templates:claude-code`); launch with `sbx run -d claude <project> --template k33g/ori:0.0.0 --kit <ori repo>/kits/ori --name ori -p 8888:8888` (detached — see the auto-stop trap below) (see `kits/ori/README.md` and docs how-to `run-in-a-sandbox`). | 41 | - `make template` — builds the `k33g/ori` sandbox template image (`template/Dockerfile`, FROM `docker/sandbox-templates:claude-code`); launch with `sbx run -d claude <project> --template k33g/ori:0.0.0 --kit <ori repo>/kits/ori --name ori -p 8888:8888` (detached — see the auto-stop trap below) (see `kits/ori/README.md` and docs how-to `run-in-a-sandbox`). |
| 42 | - `scripts/launch-ori.applescript` (2026-09-18) — macOS launcher: `sbx ls -q` → restart by name or create (`k33g/ori:0.0.1`, `./kits/ori`, `-p 5555:8888`), poll `http://localhost:5555/healthz` up to 90 s, then `open ori-desktop/build/bin/ori-desktop.app`. Run with `osascript`, or `osacompile` into `scripts/Launch Ori.app`; repo root derived from the script's own location. Compile-checked and handlers unit-tested; full end-to-end run not yet done. | 42 | - `scripts/launch-ori.applescript` (2026-09-18) — macOS launcher: `sbx ls -q` → restart by name or create (`k33g/ori:0.0.1`, `./kits/ori`, `-p 5555:8888`), poll `http://localhost:5555/healthz` up to 90 s, then `open ori-desktop/build/bin/ori-desktop.app`. Run with `osascript`, or `osacompile` into `scripts/Launch Ori.app`; repo root derived from the script's own location. Compile-checked and handlers unit-tested; full end-to-end run not yet done. |
| 43 | +- Kit publishing (sbx v0.43.0, verified 2026-09-18): `sbx kit validate kits/ori`, `sbx kit pack kits/ori -o ori-kit.zip`, `sbx kit push kits/ori docker.io/k33g/ori-kit:<tag>` — directory argument, not `spec.yaml`; there is no `sbx kit package`. Auth: `sbx login` session, then `sbx secret set --registry`, then the Docker credential store. | ||
| 44 | +- **Kit packaging trap (verified 2026-09-18)**: `pack`/`push` decode `spec.yaml` raw (no `${{ kit.args }}` expansion) — an arg placeholder in an integer field (`ports[].container`) breaks them even though `validate`/`run` accept it. `ports[0].container` is therefore a literal 8888; the `port` arg only drives the startup command and agentInstructions. | ||
| 45 | +- Published kit: `docker.io/k33g/ori-kit:latest` (pushed 2026-09-18, verified with `sbx kit inspect`); usable as `--kit docker.io/k33g/ori-kit:latest` instead of `--kit ./kits/ori`. | ||
| 43 | - **sbx auto-stop trap (verified in the sbx source + daemon log, 2026-09-17)**: sandboxd stops a sandbox 30 s (hard-coded `WithAutoStopDelay(30*time.Second)`, `sandboxd/pkg/server/backend_dockernext.go`) after its last CLI "sentinel" session closes; `sbx create`/`sbx exec`/`sbx run` all hold one for their own duration, browser traffic on a published port counts for nothing. Only a sandbox created with the spec field `detached: true` (CLI: `sbx run -d …`, absent from `sbx create`) is exempt; the field is create-time only (no PATCH), so an existing sandbox must be `sbx rm`'d and recreated with `sbx run -d`. No settings/env knob for the delay. | 46 | - **sbx auto-stop trap (verified in the sbx source + daemon log, 2026-09-17)**: sandboxd stops a sandbox 30 s (hard-coded `WithAutoStopDelay(30*time.Second)`, `sandboxd/pkg/server/backend_dockernext.go`) after its last CLI "sentinel" session closes; `sbx create`/`sbx exec`/`sbx run` all hold one for their own duration, browser traffic on a published port counts for nothing. Only a sandbox created with the spec field `detached: true` (CLI: `sbx run -d …`, absent from `sbx create`) is exempt; the field is create-time only (no PATCH), so an existing sandbox must be `sbx rm`'d and recreated with `sbx run -d`. No settings/env knob for the delay. |
| 44 | - Quality: `python3 ~/.claude/skills/quality/scripts/quality_report.py --workspace .` (gate PASS, run #16, 2026-09-17 late evening: 0 errors, 0 warnings, 0 smells, complex 514 — covers the selectors/previews/desktop work, the resizable file tree and the light/dark theme). | 47 | - Quality: `python3 ~/.claude/skills/quality/scripts/quality_report.py --workspace .` (gate PASS, run #16, 2026-09-17 late evening: 0 errors, 0 warnings, 0 smells, complex 514 — covers the selectors/previews/desktop work, the resizable file tree and the light/dark theme). |
| 45 | - `docs/source-code-analysis.adoc` — AsciiDoc snapshot analysis of the codebase (2026-09-17), outside the bilingual Diátaxis set. | 48 | - `docs/source-code-analysis.adoc` — AsciiDoc snapshot analysis of the codebase (2026-09-17), outside the bilingual Diátaxis set. |
| @@ -48,7 +51,7 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess | |||
| 48 | 51 | ||
| 49 | - `~/.qlty` is a dedicated 488MB volume, too small for qlty's tool cache; the cache was moved to `~/.qlty-cache` on the main disk with a symlink `~/.qlty/cache -> /home/agent/.qlty-cache`. If qlty reports "No space left on device", check this symlink survived. (It did NOT survive a sandbox recreation on 2026-09-17: the volume came back empty and the first run failed exactly that way; recreating the symlink fixed it.) | 52 | - `~/.qlty` is a dedicated 488MB volume, too small for qlty's tool cache; the cache was moved to `~/.qlty-cache` on the main disk with a symlink `~/.qlty/cache -> /home/agent/.qlty-cache`. If qlty reports "No space left on device", check this symlink survived. (It did NOT survive a sandbox recreation on 2026-09-17: the volume came back empty and the first run failed exactly that way; recreating the symlink fixed it.) |
| 50 | - `~/.npm` is the same kind of 488MB dedicated volume and filled up when installing Monaco; the npm cache now lives at `~/.npm-big` via `NPM_CONFIG_CACHE` exported in `/etc/sandbox-persistent.sh`. | 53 | - `~/.npm` is the same kind of 488MB dedicated volume and filled up when installing Monaco; the npm cache now lives at `~/.npm-big` via `NPM_CONFIG_CACHE` exported in `/etc/sandbox-persistent.sh`. |
| 51 | -- Running ori inside this Claude-Code-driven sandbox requires `env -u CLAUDECODE ./bin/ori` (Claude refuses nested sessions). Also set `CLAUDE_CODE_EXECUTABLE=<current claude binary>` (e.g. `/home/agent/.local/share/claude/versions/2.1.275`): the Zed adapter 0.16.2 bundles Claude Code 2.1.44, which rejects the `fable[1m]` model from `~/.claude/settings.json`. | 54 | +- Running ori inside this Claude-Code-driven sandbox requires `env -u CLAUDECODE ./bin/ori` (Claude refuses nested sessions). Also set `CLAUDE_CODE_EXECUTABLE=<current claude binary>`: the Zed adapter 0.16.2 bundles Claude Code 2.1.44, which rejects the `claude-fable-5-1[1m]` model from the host `~/.claude/settings.json`. **Since 2026-09-18 the API requires CLI ≥ 2.1.251 for that model, and the template's own CLI is 2.1.246 (base image built 2026-08-26)** — so the env var alone is not enough; run `claude update` in the sandbox first, or switch the template to `@agentclientprotocol/claude-agent-acp` (SDK 0.3.274 → CLI 2.1.274). Handoff `2026-09-18-claude-version-too-old.md`. |
| 52 | - npm blocks install scripts by default here; esbuild's postinstall was approved via `npm approve-scripts` (recorded in `ui/package.json` `allowScripts`). | 55 | - npm blocks install scripts by default here; esbuild's postinstall was approved via `npm approve-scripts` (recorded in `ui/package.json` `allowScripts`). |
| 53 | 56 | ||
| 54 | ## Known limitations | 57 | ## Known limitations |
modified
.qlty/qlty.toml +4 -0 | @@ -78,6 +78,10 @@ name = "bandit" | ||
| 78 | 78 | |
| 79 | 79 | [[plugin]] |
| 80 | 80 | name = "golangci-lint" |
| 81 | +# 2.13.2 (2026-08-27) is built with Go >= 1.26; qlty's default 1.61.0 (go1.23) and its | |
| 82 | +# latest known 2.6.2 (go1.25) both refuse this repo's `go 1.26.5` ("Go language version | |
| 83 | +# used to build golangci-lint is lower than the targeted Go version") and abort the run. | |
| 84 | +version = "2.13.2" | |
| 81 | 85 | |
| 82 | 86 | [[plugin]] |
| 83 | 87 | name = "biome" |
| @@ -78,6 +78,10 @@ name = "bandit" | |||
| 78 | 78 | ||
| 79 | [[plugin]] | 79 | [[plugin]] |
| 80 | name = "golangci-lint" | 80 | name = "golangci-lint" |
| 81 | +# 2.13.2 (2026-08-27) is built with Go >= 1.26; qlty's default 1.61.0 (go1.23) and its | ||
| 82 | +# latest known 2.6.2 (go1.25) both refuse this repo's `go 1.26.5` ("Go language version | ||
| 83 | +# used to build golangci-lint is lower than the targeted Go version") and abort the run. | ||
| 84 | +version = "2.13.2" | ||
| 81 | 85 | ||
| 82 | [[plugin]] | 86 | [[plugin]] |
| 83 | name = "biome" | 87 | name = "biome" |
modified
.quality/history.jsonl +2 -0 | @@ -14,3 +14,5 @@ | ||
| 14 | 14 | {"branch": "feat/acp-webapp", "breaches": ["error-level issues: 12 (max 0)", "warning-level issues: 1 (max 0)", "code smells: 2 (max 0)"], "commit": "2434cc7", "counts": {"error": 12, "note": 4, "warning": 1}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": false, "metrics": {"classes": 54, "complex": 517, "cyclo": 888, "fields": 75, "funcs": 255, "lcom": 0, "lines": 5523, "loc": 4005}, "qlty_version": "qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23)", "run": 14, "smells": 2, "timestamp": "2026-09-17T23:07:54Z"} |
| 15 | 15 | {"branch": "feat/acp-webapp", "breaches": [], "commit": "2434cc7", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": true, "metrics": {"classes": 55, "complex": 507, "cyclo": 877, "fields": 79, "funcs": 260, "lcom": 0, "lines": 5570, "loc": 4030}, "qlty_version": "qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23)", "run": 15, "smells": 0, "timestamp": "2026-09-17T23:10:03Z"} |
| 16 | 16 | {"branch": "feat/acp-webapp", "breaches": [], "commit": "2434cc7", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": true, "metrics": {"classes": 56, "complex": 514, "cyclo": 893, "fields": 79, "funcs": 267, "lcom": 0, "lines": 5671, "loc": 4082}, "qlty_version": "qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23)", "run": 16, "smells": 0, "timestamp": "2026-09-17T23:15:34Z"} |
| 17 | +{"branch": "feature/copy-paste-functionality", "breaches": ["code smells: 2 (max 0)"], "commit": "7895c1d", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": false, "metrics": {"classes": 57, "complex": 546, "cyclo": 918, "fields": 79, "funcs": 271, "lcom": 0, "lines": 5832, "loc": 4212}, "qlty_version": "qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02)", "run": 17, "smells": 2, "timestamp": "2026-09-18T07:58:08Z"} | |
| 18 | +{"branch": "feature/copy-paste-functionality", "breaches": [], "commit": "7895c1d", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": true, "metrics": {"classes": 57, "complex": 532, "cyclo": 917, "fields": 79, "funcs": 273, "lcom": 0, "lines": 5858, "loc": 4220}, "qlty_version": "qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02)", "run": 18, "smells": 0, "timestamp": "2026-09-18T08:03:21Z"} | |
| @@ -14,3 +14,5 @@ | |||
| 14 | {"branch": "feat/acp-webapp", "breaches": ["error-level issues: 12 (max 0)", "warning-level issues: 1 (max 0)", "code smells: 2 (max 0)"], "commit": "2434cc7", "counts": {"error": 12, "note": 4, "warning": 1}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": false, "metrics": {"classes": 54, "complex": 517, "cyclo": 888, "fields": 75, "funcs": 255, "lcom": 0, "lines": 5523, "loc": 4005}, "qlty_version": "qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23)", "run": 14, "smells": 2, "timestamp": "2026-09-17T23:07:54Z"} | 14 | {"branch": "feat/acp-webapp", "breaches": ["error-level issues: 12 (max 0)", "warning-level issues: 1 (max 0)", "code smells: 2 (max 0)"], "commit": "2434cc7", "counts": {"error": 12, "note": 4, "warning": 1}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": false, "metrics": {"classes": 54, "complex": 517, "cyclo": 888, "fields": 75, "funcs": 255, "lcom": 0, "lines": 5523, "loc": 4005}, "qlty_version": "qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23)", "run": 14, "smells": 2, "timestamp": "2026-09-17T23:07:54Z"} |
| 15 | {"branch": "feat/acp-webapp", "breaches": [], "commit": "2434cc7", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": true, "metrics": {"classes": 55, "complex": 507, "cyclo": 877, "fields": 79, "funcs": 260, "lcom": 0, "lines": 5570, "loc": 4030}, "qlty_version": "qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23)", "run": 15, "smells": 0, "timestamp": "2026-09-17T23:10:03Z"} | 15 | {"branch": "feat/acp-webapp", "breaches": [], "commit": "2434cc7", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": true, "metrics": {"classes": 55, "complex": 507, "cyclo": 877, "fields": 79, "funcs": 260, "lcom": 0, "lines": 5570, "loc": 4030}, "qlty_version": "qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23)", "run": 15, "smells": 0, "timestamp": "2026-09-17T23:10:03Z"} |
| 16 | {"branch": "feat/acp-webapp", "breaches": [], "commit": "2434cc7", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": true, "metrics": {"classes": 56, "complex": 514, "cyclo": 893, "fields": 79, "funcs": 267, "lcom": 0, "lines": 5671, "loc": 4082}, "qlty_version": "qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23)", "run": 16, "smells": 0, "timestamp": "2026-09-17T23:15:34Z"} | 16 | {"branch": "feat/acp-webapp", "breaches": [], "commit": "2434cc7", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": true, "metrics": {"classes": 56, "complex": 514, "cyclo": 893, "fields": 79, "funcs": 267, "lcom": 0, "lines": 5671, "loc": 4082}, "qlty_version": "qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23)", "run": 16, "smells": 0, "timestamp": "2026-09-17T23:15:34Z"} |
| 17 | +{"branch": "feature/copy-paste-functionality", "breaches": ["code smells: 2 (max 0)"], "commit": "7895c1d", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": false, "metrics": {"classes": 57, "complex": 546, "cyclo": 918, "fields": 79, "funcs": 271, "lcom": 0, "lines": 5832, "loc": 4212}, "qlty_version": "qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02)", "run": 17, "smells": 2, "timestamp": "2026-09-18T07:58:08Z"} | ||
| 18 | +{"branch": "feature/copy-paste-functionality", "breaches": [], "commit": "7895c1d", "counts": {}, "gate": {"max_error": 0, "max_smells": 0, "max_warning": 0}, "gate_passed": true, "metrics": {"classes": 57, "complex": 532, "cyclo": 917, "fields": 79, "funcs": 273, "lcom": 0, "lines": 5858, "loc": 4220}, "qlty_version": "qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02)", "run": 18, "smells": 0, "timestamp": "2026-09-18T08:03:21Z"} | ||
added
.quality/report-20260918T075808Z.md +85 -0 | new file mode 100644 | ||
| @@ -0,0 +1,85 @@ | ||
| 1 | +# Quality report — 2026-09-18T07:58:08Z | |
| 2 | + | |
| 3 | +- **Gate**: ❌ **FAIL** | |
| 4 | +- **Commit**: `7895c1d` on `feature/copy-paste-functionality` | |
| 5 | +- **qlty**: qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02) | |
| 6 | +- **Run**: #17 (previous: 2026-09-17T23:15:34Z) | |
| 7 | + | |
| 8 | +## Gate violations | |
| 9 | + | |
| 10 | +- code smells: 2 (max 0) | |
| 11 | + | |
| 12 | +## Lint issues (`qlty check`) | |
| 13 | + | |
| 14 | +_none_ | |
| 15 | + | |
| 16 | +### Top rules | |
| 17 | + | |
| 18 | +_none_ | |
| 19 | + | |
| 20 | +### Most affected files | |
| 21 | + | |
| 22 | +_none_ | |
| 23 | + | |
| 24 | +## Code smells (`qlty smells`) | |
| 25 | + | |
| 26 | +Total: **2** (vs previous: +2) | |
| 27 | + | |
| 28 | +| smell | file | line | detail | | |
| 29 | +|---|---|---|---| | |
| 30 | +| qlty:function-complexity | ui/src/components/ToolCallCard.tsx | 37 | Function with high complexity (count = 21): ToolCallCard | | |
| 31 | +| qlty:function-complexity | ui/src/components/ToolCallCard.tsx | 39 | Function with high complexity (count = 19): getToolContent | | |
| 32 | + | |
| 33 | +## Metrics (`qlty metrics`) | |
| 34 | + | |
| 35 | +| metric | total | vs previous | | |
| 36 | +|---|---|---| | |
| 37 | +| funcs | 271 | +4 | | |
| 38 | +| classes | 57 | +1 | | |
| 39 | +| fields | 79 | ±0 | | |
| 40 | +| cyclo | 918 | +25 | | |
| 41 | +| complex | 546 | +32 | | |
| 42 | +| lcom | 0 | ±0 | | |
| 43 | +| lines | 5832 | +161 | | |
| 44 | +| loc | 4212 | +130 | | |
| 45 | + | |
| 46 | +### Most complex files | |
| 47 | + | |
| 48 | +| file | complex | cyclo | loc | | |
| 49 | +|---|---|---|---| | |
| 50 | +| internal/bridge/bridge.go | 34 | 49 | 228 | | |
| 51 | +| internal/skills/skills.go | 34 | 53 | 129 | | |
| 52 | +| internal/terminal/terminal.go | 32 | 33 | 111 | | |
| 53 | +| ui/src/useCompletion.ts | 29 | 32 | 122 | | |
| 54 | +| ui/src/components/ToolCallCard.tsx | 24 | 32 | 124 | | |
| 55 | +| internal/files/files.go | 21 | 35 | 140 | | |
| 56 | +| internal/mockagent/mockagent.go | 21 | 38 | 190 | | |
| 57 | +| ui/src/components/DrawioView.tsx | 20 | 22 | 76 | | |
| 58 | +| ui/src/components/PromptInput.tsx | 20 | 26 | 153 | | |
| 59 | +| ui/src/components/EditorPane.tsx | 18 | 33 | 125 | | |
| 60 | +| internal/files/search.go | 17 | 32 | 104 | | |
| 61 | +| ui/src/components/PreviewPane.tsx | 17 | 30 | 131 | | |
| 62 | +| ui/src/reducer.ts | 17 | 54 | 195 | | |
| 63 | +| internal/agent/agent.go | 15 | 31 | 121 | | |
| 64 | +| ori-desktop/internal/settings/settings.go | 15 | 31 | 82 | | |
| 65 | + | |
| 66 | +## Tooling notes | |
| 67 | + | |
| 68 | +- `qlty check` exit 99: ERROR | |
| 69 | + | |
| 70 | + > FATAL error occurred running 13 invocations | |
| 71 | + | |
| 72 | +## Trend | |
| 73 | + | |
| 74 | +| run | timestamp | error | warning | smells | complex | gate | | |
| 75 | +|---|---|---|---|---|---|---| | |
| 76 | +| 8 | 2026-09-17T20:06:46Z | 1 | 1 | 0 | 281 | FAIL | | |
| 77 | +| 9 | 2026-09-17T20:08:01Z | 0 | 0 | 0 | 281 | PASS | | |
| 78 | +| 10 | 2026-09-17T20:25:57Z | 0 | 0 | 0 | 286 | PASS | | |
| 79 | +| 11 | 2026-09-17T20:55:17Z | 0 | 0 | 0 | 288 | PASS | | |
| 80 | +| 12 | 2026-09-17T21:04:25Z | 0 | 0 | 0 | 288 | PASS | | |
| 81 | +| 13 | 2026-09-17T23:07:19Z | 0 | 0 | 2 | 517 | FAIL | | |
| 82 | +| 14 | 2026-09-17T23:07:54Z | 12 | 1 | 2 | 517 | FAIL | | |
| 83 | +| 15 | 2026-09-17T23:10:03Z | 0 | 0 | 0 | 507 | PASS | | |
| 84 | +| 16 | 2026-09-17T23:15:34Z | 0 | 0 | 0 | 514 | PASS | | |
| 85 | +| 17 | 2026-09-18T07:58:08Z | 0 | 0 | 2 | 546 | FAIL | | |
| new file mode 100644 | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | +# Quality report — 2026-09-18T07:58:08Z | ||
| 2 | + | ||
| 3 | +- **Gate**: ❌ **FAIL** | ||
| 4 | +- **Commit**: `7895c1d` on `feature/copy-paste-functionality` | ||
| 5 | +- **qlty**: qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02) | ||
| 6 | +- **Run**: #17 (previous: 2026-09-17T23:15:34Z) | ||
| 7 | + | ||
| 8 | +## Gate violations | ||
| 9 | + | ||
| 10 | +- code smells: 2 (max 0) | ||
| 11 | + | ||
| 12 | +## Lint issues (`qlty check`) | ||
| 13 | + | ||
| 14 | +_none_ | ||
| 15 | + | ||
| 16 | +### Top rules | ||
| 17 | + | ||
| 18 | +_none_ | ||
| 19 | + | ||
| 20 | +### Most affected files | ||
| 21 | + | ||
| 22 | +_none_ | ||
| 23 | + | ||
| 24 | +## Code smells (`qlty smells`) | ||
| 25 | + | ||
| 26 | +Total: **2** (vs previous: +2) | ||
| 27 | + | ||
| 28 | +| smell | file | line | detail | | ||
| 29 | +|---|---|---|---| | ||
| 30 | +| qlty:function-complexity | ui/src/components/ToolCallCard.tsx | 37 | Function with high complexity (count = 21): ToolCallCard | | ||
| 31 | +| qlty:function-complexity | ui/src/components/ToolCallCard.tsx | 39 | Function with high complexity (count = 19): getToolContent | | ||
| 32 | + | ||
| 33 | +## Metrics (`qlty metrics`) | ||
| 34 | + | ||
| 35 | +| metric | total | vs previous | | ||
| 36 | +|---|---|---| | ||
| 37 | +| funcs | 271 | +4 | | ||
| 38 | +| classes | 57 | +1 | | ||
| 39 | +| fields | 79 | ±0 | | ||
| 40 | +| cyclo | 918 | +25 | | ||
| 41 | +| complex | 546 | +32 | | ||
| 42 | +| lcom | 0 | ±0 | | ||
| 43 | +| lines | 5832 | +161 | | ||
| 44 | +| loc | 4212 | +130 | | ||
| 45 | + | ||
| 46 | +### Most complex files | ||
| 47 | + | ||
| 48 | +| file | complex | cyclo | loc | | ||
| 49 | +|---|---|---|---| | ||
| 50 | +| internal/bridge/bridge.go | 34 | 49 | 228 | | ||
| 51 | +| internal/skills/skills.go | 34 | 53 | 129 | | ||
| 52 | +| internal/terminal/terminal.go | 32 | 33 | 111 | | ||
| 53 | +| ui/src/useCompletion.ts | 29 | 32 | 122 | | ||
| 54 | +| ui/src/components/ToolCallCard.tsx | 24 | 32 | 124 | | ||
| 55 | +| internal/files/files.go | 21 | 35 | 140 | | ||
| 56 | +| internal/mockagent/mockagent.go | 21 | 38 | 190 | | ||
| 57 | +| ui/src/components/DrawioView.tsx | 20 | 22 | 76 | | ||
| 58 | +| ui/src/components/PromptInput.tsx | 20 | 26 | 153 | | ||
| 59 | +| ui/src/components/EditorPane.tsx | 18 | 33 | 125 | | ||
| 60 | +| internal/files/search.go | 17 | 32 | 104 | | ||
| 61 | +| ui/src/components/PreviewPane.tsx | 17 | 30 | 131 | | ||
| 62 | +| ui/src/reducer.ts | 17 | 54 | 195 | | ||
| 63 | +| internal/agent/agent.go | 15 | 31 | 121 | | ||
| 64 | +| ori-desktop/internal/settings/settings.go | 15 | 31 | 82 | | ||
| 65 | + | ||
| 66 | +## Tooling notes | ||
| 67 | + | ||
| 68 | +- `qlty check` exit 99: ERROR | ||
| 69 | + | ||
| 70 | + > FATAL error occurred running 13 invocations | ||
| 71 | + | ||
| 72 | +## Trend | ||
| 73 | + | ||
| 74 | +| run | timestamp | error | warning | smells | complex | gate | | ||
| 75 | +|---|---|---|---|---|---|---| | ||
| 76 | +| 8 | 2026-09-17T20:06:46Z | 1 | 1 | 0 | 281 | FAIL | | ||
| 77 | +| 9 | 2026-09-17T20:08:01Z | 0 | 0 | 0 | 281 | PASS | | ||
| 78 | +| 10 | 2026-09-17T20:25:57Z | 0 | 0 | 0 | 286 | PASS | | ||
| 79 | +| 11 | 2026-09-17T20:55:17Z | 0 | 0 | 0 | 288 | PASS | | ||
| 80 | +| 12 | 2026-09-17T21:04:25Z | 0 | 0 | 0 | 288 | PASS | | ||
| 81 | +| 13 | 2026-09-17T23:07:19Z | 0 | 0 | 2 | 517 | FAIL | | ||
| 82 | +| 14 | 2026-09-17T23:07:54Z | 12 | 1 | 2 | 517 | FAIL | | ||
| 83 | +| 15 | 2026-09-17T23:10:03Z | 0 | 0 | 0 | 507 | PASS | | ||
| 84 | +| 16 | 2026-09-17T23:15:34Z | 0 | 0 | 0 | 514 | PASS | | ||
| 85 | +| 17 | 2026-09-18T07:58:08Z | 0 | 0 | 2 | 546 | FAIL | | ||
added
.quality/report-20260918T080321Z.md +72 -0 | new file mode 100644 | ||
| @@ -0,0 +1,72 @@ | ||
| 1 | +# Quality report — 2026-09-18T08:03:21Z | |
| 2 | + | |
| 3 | +- **Gate**: ✅ **PASS** | |
| 4 | +- **Commit**: `7895c1d` on `feature/copy-paste-functionality` | |
| 5 | +- **qlty**: qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02) | |
| 6 | +- **Run**: #18 (previous: 2026-09-18T07:58:08Z) | |
| 7 | + | |
| 8 | +## Lint issues (`qlty check`) | |
| 9 | + | |
| 10 | +_none_ | |
| 11 | + | |
| 12 | +### Top rules | |
| 13 | + | |
| 14 | +_none_ | |
| 15 | + | |
| 16 | +### Most affected files | |
| 17 | + | |
| 18 | +_none_ | |
| 19 | + | |
| 20 | +## Code smells (`qlty smells`) | |
| 21 | + | |
| 22 | +Total: **0** (vs previous: -2) | |
| 23 | + | |
| 24 | +_none_ | |
| 25 | + | |
| 26 | +## Metrics (`qlty metrics`) | |
| 27 | + | |
| 28 | +| metric | total | vs previous | | |
| 29 | +|---|---|---| | |
| 30 | +| funcs | 273 | +2 | | |
| 31 | +| classes | 57 | ±0 | | |
| 32 | +| fields | 79 | ±0 | | |
| 33 | +| cyclo | 917 | -1 | | |
| 34 | +| complex | 532 | -14 | | |
| 35 | +| lcom | 0 | ±0 | | |
| 36 | +| lines | 5858 | +26 | | |
| 37 | +| loc | 4220 | +8 | | |
| 38 | + | |
| 39 | +### Most complex files | |
| 40 | + | |
| 41 | +| file | complex | cyclo | loc | | |
| 42 | +|---|---|---|---| | |
| 43 | +| internal/bridge/bridge.go | 34 | 49 | 228 | | |
| 44 | +| internal/skills/skills.go | 34 | 53 | 129 | | |
| 45 | +| internal/terminal/terminal.go | 32 | 33 | 111 | | |
| 46 | +| ui/src/useCompletion.ts | 29 | 32 | 122 | | |
| 47 | +| internal/files/files.go | 21 | 35 | 140 | | |
| 48 | +| internal/mockagent/mockagent.go | 21 | 38 | 190 | | |
| 49 | +| ui/src/components/DrawioView.tsx | 20 | 22 | 76 | | |
| 50 | +| ui/src/components/PromptInput.tsx | 20 | 26 | 153 | | |
| 51 | +| ui/src/components/EditorPane.tsx | 18 | 33 | 125 | | |
| 52 | +| internal/files/search.go | 17 | 32 | 104 | | |
| 53 | +| ui/src/components/PreviewPane.tsx | 17 | 30 | 131 | | |
| 54 | +| ui/src/reducer.ts | 17 | 54 | 195 | | |
| 55 | +| internal/agent/agent.go | 15 | 31 | 121 | | |
| 56 | +| ori-desktop/internal/settings/settings.go | 15 | 31 | 82 | | |
| 57 | +| internal/bridge/ws.go | 14 | 15 | 61 | | |
| 58 | + | |
| 59 | +## Trend | |
| 60 | + | |
| 61 | +| run | timestamp | error | warning | smells | complex | gate | | |
| 62 | +|---|---|---|---|---|---|---| | |
| 63 | +| 9 | 2026-09-17T20:08:01Z | 0 | 0 | 0 | 281 | PASS | | |
| 64 | +| 10 | 2026-09-17T20:25:57Z | 0 | 0 | 0 | 286 | PASS | | |
| 65 | +| 11 | 2026-09-17T20:55:17Z | 0 | 0 | 0 | 288 | PASS | | |
| 66 | +| 12 | 2026-09-17T21:04:25Z | 0 | 0 | 0 | 288 | PASS | | |
| 67 | +| 13 | 2026-09-17T23:07:19Z | 0 | 0 | 2 | 517 | FAIL | | |
| 68 | +| 14 | 2026-09-17T23:07:54Z | 12 | 1 | 2 | 517 | FAIL | | |
| 69 | +| 15 | 2026-09-17T23:10:03Z | 0 | 0 | 0 | 507 | PASS | | |
| 70 | +| 16 | 2026-09-17T23:15:34Z | 0 | 0 | 0 | 514 | PASS | | |
| 71 | +| 17 | 2026-09-18T07:58:08Z | 0 | 0 | 2 | 546 | FAIL | | |
| 72 | +| 18 | 2026-09-18T08:03:21Z | 0 | 0 | 0 | 532 | PASS | | |
| new file mode 100644 | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | +# Quality report — 2026-09-18T08:03:21Z | ||
| 2 | + | ||
| 3 | +- **Gate**: ✅ **PASS** | ||
| 4 | +- **Commit**: `7895c1d` on `feature/copy-paste-functionality` | ||
| 5 | +- **qlty**: qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02) | ||
| 6 | +- **Run**: #18 (previous: 2026-09-18T07:58:08Z) | ||
| 7 | + | ||
| 8 | +## Lint issues (`qlty check`) | ||
| 9 | + | ||
| 10 | +_none_ | ||
| 11 | + | ||
| 12 | +### Top rules | ||
| 13 | + | ||
| 14 | +_none_ | ||
| 15 | + | ||
| 16 | +### Most affected files | ||
| 17 | + | ||
| 18 | +_none_ | ||
| 19 | + | ||
| 20 | +## Code smells (`qlty smells`) | ||
| 21 | + | ||
| 22 | +Total: **0** (vs previous: -2) | ||
| 23 | + | ||
| 24 | +_none_ | ||
| 25 | + | ||
| 26 | +## Metrics (`qlty metrics`) | ||
| 27 | + | ||
| 28 | +| metric | total | vs previous | | ||
| 29 | +|---|---|---| | ||
| 30 | +| funcs | 273 | +2 | | ||
| 31 | +| classes | 57 | ±0 | | ||
| 32 | +| fields | 79 | ±0 | | ||
| 33 | +| cyclo | 917 | -1 | | ||
| 34 | +| complex | 532 | -14 | | ||
| 35 | +| lcom | 0 | ±0 | | ||
| 36 | +| lines | 5858 | +26 | | ||
| 37 | +| loc | 4220 | +8 | | ||
| 38 | + | ||
| 39 | +### Most complex files | ||
| 40 | + | ||
| 41 | +| file | complex | cyclo | loc | | ||
| 42 | +|---|---|---|---| | ||
| 43 | +| internal/bridge/bridge.go | 34 | 49 | 228 | | ||
| 44 | +| internal/skills/skills.go | 34 | 53 | 129 | | ||
| 45 | +| internal/terminal/terminal.go | 32 | 33 | 111 | | ||
| 46 | +| ui/src/useCompletion.ts | 29 | 32 | 122 | | ||
| 47 | +| internal/files/files.go | 21 | 35 | 140 | | ||
| 48 | +| internal/mockagent/mockagent.go | 21 | 38 | 190 | | ||
| 49 | +| ui/src/components/DrawioView.tsx | 20 | 22 | 76 | | ||
| 50 | +| ui/src/components/PromptInput.tsx | 20 | 26 | 153 | | ||
| 51 | +| ui/src/components/EditorPane.tsx | 18 | 33 | 125 | | ||
| 52 | +| internal/files/search.go | 17 | 32 | 104 | | ||
| 53 | +| ui/src/components/PreviewPane.tsx | 17 | 30 | 131 | | ||
| 54 | +| ui/src/reducer.ts | 17 | 54 | 195 | | ||
| 55 | +| internal/agent/agent.go | 15 | 31 | 121 | | ||
| 56 | +| ori-desktop/internal/settings/settings.go | 15 | 31 | 82 | | ||
| 57 | +| internal/bridge/ws.go | 14 | 15 | 61 | | ||
| 58 | + | ||
| 59 | +## Trend | ||
| 60 | + | ||
| 61 | +| run | timestamp | error | warning | smells | complex | gate | | ||
| 62 | +|---|---|---|---|---|---|---| | ||
| 63 | +| 9 | 2026-09-17T20:08:01Z | 0 | 0 | 0 | 281 | PASS | | ||
| 64 | +| 10 | 2026-09-17T20:25:57Z | 0 | 0 | 0 | 286 | PASS | | ||
| 65 | +| 11 | 2026-09-17T20:55:17Z | 0 | 0 | 0 | 288 | PASS | | ||
| 66 | +| 12 | 2026-09-17T21:04:25Z | 0 | 0 | 0 | 288 | PASS | | ||
| 67 | +| 13 | 2026-09-17T23:07:19Z | 0 | 0 | 2 | 517 | FAIL | | ||
| 68 | +| 14 | 2026-09-17T23:07:54Z | 12 | 1 | 2 | 517 | FAIL | | ||
| 69 | +| 15 | 2026-09-17T23:10:03Z | 0 | 0 | 0 | 507 | PASS | | ||
| 70 | +| 16 | 2026-09-17T23:15:34Z | 0 | 0 | 0 | 514 | PASS | | ||
| 71 | +| 17 | 2026-09-18T07:58:08Z | 0 | 0 | 2 | 546 | FAIL | | ||
| 72 | +| 18 | 2026-09-18T08:03:21Z | 0 | 0 | 0 | 532 | PASS | | ||
modified
.quality/report-latest.md +13 -13 | @@ -1,9 +1,9 @@ | ||
| 1 | -# Quality report — 2026-09-17T23:15:34Z | |
| 1 | +# Quality report — 2026-09-18T08:03:21Z | |
| 2 | 2 | |
| 3 | 3 | - **Gate**: ✅ **PASS** |
| 4 | -- **Commit**: `2434cc7` on `feat/acp-webapp` | |
| 5 | -- **qlty**: qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23) | |
| 6 | -- **Run**: #16 (previous: 2026-09-17T23:10:03Z) | |
| 4 | +- **Commit**: `7895c1d` on `feature/copy-paste-functionality` | |
| 5 | +- **qlty**: qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02) | |
| 6 | +- **Run**: #18 (previous: 2026-09-18T07:58:08Z) | |
| 7 | 7 | |
| 8 | 8 | ## Lint issues (`qlty check`) |
| 9 | 9 | |
| @@ -19,7 +19,7 @@ _none_ | ||
| 19 | 19 | |
| 20 | 20 | ## Code smells (`qlty smells`) |
| 21 | 21 | |
| 22 | -Total: **0** (vs previous: ±0) | |
| 22 | +Total: **0** (vs previous: -2) | |
| 23 | 23 | |
| 24 | 24 | _none_ |
| 25 | 25 | |
| @@ -27,14 +27,14 @@ _none_ | ||
| 27 | 27 | |
| 28 | 28 | | metric | total | vs previous | |
| 29 | 29 | |---|---|---| |
| 30 | -| funcs | 267 | +7 | | |
| 31 | -| classes | 56 | +1 | | |
| 30 | +| funcs | 273 | +2 | | |
| 31 | +| classes | 57 | ±0 | | |
| 32 | 32 | | fields | 79 | ±0 | |
| 33 | -| cyclo | 893 | +16 | | |
| 34 | -| complex | 514 | +7 | | |
| 33 | +| cyclo | 917 | -1 | | |
| 34 | +| complex | 532 | -14 | | |
| 35 | 35 | | lcom | 0 | ±0 | |
| 36 | -| lines | 5671 | +101 | | |
| 37 | -| loc | 4082 | +52 | | |
| 36 | +| lines | 5858 | +26 | | |
| 37 | +| loc | 4220 | +8 | | |
| 38 | 38 | |
| 39 | 39 | ### Most complex files |
| 40 | 40 | |
| @@ -60,8 +60,6 @@ _none_ | ||
| 60 | 60 | |
| 61 | 61 | | run | timestamp | error | warning | smells | complex | gate | |
| 62 | 62 | |---|---|---|---|---|---|---| |
| 63 | -| 7 | 2026-09-17T20:05:32Z | 2 | 1 | 3 | 284 | FAIL | | |
| 64 | -| 8 | 2026-09-17T20:06:46Z | 1 | 1 | 0 | 281 | FAIL | | |
| 65 | 63 | | 9 | 2026-09-17T20:08:01Z | 0 | 0 | 0 | 281 | PASS | |
| 66 | 64 | | 10 | 2026-09-17T20:25:57Z | 0 | 0 | 0 | 286 | PASS | |
| 67 | 65 | | 11 | 2026-09-17T20:55:17Z | 0 | 0 | 0 | 288 | PASS | |
| @@ -70,3 +68,5 @@ _none_ | ||
| 70 | 68 | | 14 | 2026-09-17T23:07:54Z | 12 | 1 | 2 | 517 | FAIL | |
| 71 | 69 | | 15 | 2026-09-17T23:10:03Z | 0 | 0 | 0 | 507 | PASS | |
| 72 | 70 | | 16 | 2026-09-17T23:15:34Z | 0 | 0 | 0 | 514 | PASS | |
| 71 | +| 17 | 2026-09-18T07:58:08Z | 0 | 0 | 2 | 546 | FAIL | | |
| 72 | +| 18 | 2026-09-18T08:03:21Z | 0 | 0 | 0 | 532 | PASS | | |
| @@ -1,9 +1,9 @@ | |||
| 1 | -# Quality report — 2026-09-17T23:15:34Z | 1 | +# Quality report — 2026-09-18T08:03:21Z |
| 2 | 2 | ||
| 3 | - **Gate**: ✅ **PASS** | 3 | - **Gate**: ✅ **PASS** |
| 4 | -- **Commit**: `2434cc7` on `feat/acp-webapp` | 4 | +- **Commit**: `7895c1d` on `feature/copy-paste-functionality` |
| 5 | -- **qlty**: qlty 0.639.0 linux-arm64 (d9801f1 2026-07-23) | 5 | +- **qlty**: qlty 0.615.0 macos-arm64 (bfe0de3 2026-03-02) |
| 6 | -- **Run**: #16 (previous: 2026-09-17T23:10:03Z) | 6 | +- **Run**: #18 (previous: 2026-09-18T07:58:08Z) |
| 7 | 7 | ||
| 8 | ## Lint issues (`qlty check`) | 8 | ## Lint issues (`qlty check`) |
| 9 | 9 | ||
| @@ -19,7 +19,7 @@ _none_ | |||
| 19 | 19 | ||
| 20 | ## Code smells (`qlty smells`) | 20 | ## Code smells (`qlty smells`) |
| 21 | 21 | ||
| 22 | -Total: **0** (vs previous: ±0) | 22 | +Total: **0** (vs previous: -2) |
| 23 | 23 | ||
| 24 | _none_ | 24 | _none_ |
| 25 | 25 | ||
| @@ -27,14 +27,14 @@ _none_ | |||
| 27 | 27 | ||
| 28 | | metric | total | vs previous | | 28 | | metric | total | vs previous | |
| 29 | |---|---|---| | 29 | |---|---|---| |
| 30 | -| funcs | 267 | +7 | | 30 | +| funcs | 273 | +2 | |
| 31 | -| classes | 56 | +1 | | 31 | +| classes | 57 | ±0 | |
| 32 | | fields | 79 | ±0 | | 32 | | fields | 79 | ±0 | |
| 33 | -| cyclo | 893 | +16 | | 33 | +| cyclo | 917 | -1 | |
| 34 | -| complex | 514 | +7 | | 34 | +| complex | 532 | -14 | |
| 35 | | lcom | 0 | ±0 | | 35 | | lcom | 0 | ±0 | |
| 36 | -| lines | 5671 | +101 | | 36 | +| lines | 5858 | +26 | |
| 37 | -| loc | 4082 | +52 | | 37 | +| loc | 4220 | +8 | |
| 38 | 38 | ||
| 39 | ### Most complex files | 39 | ### Most complex files |
| 40 | 40 | ||
| @@ -60,8 +60,6 @@ _none_ | |||
| 60 | 60 | ||
| 61 | | run | timestamp | error | warning | smells | complex | gate | | 61 | | run | timestamp | error | warning | smells | complex | gate | |
| 62 | |---|---|---|---|---|---|---| | 62 | |---|---|---|---|---|---|---| |
| 63 | -| 7 | 2026-09-17T20:05:32Z | 2 | 1 | 3 | 284 | FAIL | | ||
| 64 | -| 8 | 2026-09-17T20:06:46Z | 1 | 1 | 0 | 281 | FAIL | | ||
| 65 | | 9 | 2026-09-17T20:08:01Z | 0 | 0 | 0 | 281 | PASS | | 63 | | 9 | 2026-09-17T20:08:01Z | 0 | 0 | 0 | 281 | PASS | |
| 66 | | 10 | 2026-09-17T20:25:57Z | 0 | 0 | 0 | 286 | PASS | | 64 | | 10 | 2026-09-17T20:25:57Z | 0 | 0 | 0 | 286 | PASS | |
| 67 | | 11 | 2026-09-17T20:55:17Z | 0 | 0 | 0 | 288 | PASS | | 65 | | 11 | 2026-09-17T20:55:17Z | 0 | 0 | 0 | 288 | PASS | |
| @@ -70,3 +68,5 @@ _none_ | |||
| 70 | | 14 | 2026-09-17T23:07:54Z | 12 | 1 | 2 | 517 | FAIL | | 68 | | 14 | 2026-09-17T23:07:54Z | 12 | 1 | 2 | 517 | FAIL | |
| 71 | | 15 | 2026-09-17T23:10:03Z | 0 | 0 | 0 | 507 | PASS | | 69 | | 15 | 2026-09-17T23:10:03Z | 0 | 0 | 0 | 507 | PASS | |
| 72 | | 16 | 2026-09-17T23:15:34Z | 0 | 0 | 0 | 514 | PASS | | 70 | | 16 | 2026-09-17T23:15:34Z | 0 | 0 | 0 | 514 | PASS | |
| 71 | +| 17 | 2026-09-18T07:58:08Z | 0 | 0 | 2 | 546 | FAIL | | ||
| 72 | +| 18 | 2026-09-18T08:03:21Z | 0 | 0 | 0 | 532 | PASS | | ||
modified
README.md +12 -4 | @@ -8,11 +8,19 @@ Ori is a web client for [ACP (Agent Client Protocol)](https://agentclientprotoco | ||
| 8 | 8 | From the directory where the kit lives, pointing at the project you want the agent to work on: |
| 9 | 9 | |
| 10 | 10 | ```bash |
| 11 | -sbx run -d claude ~/path/to/your/project \ | |
| 12 | - --template k33g/ori:0.0.0 \ | |
| 11 | +sbx run -d claude . \ | |
| 12 | + --template k33g/ori:0.0.2 \ | |
| 13 | 13 | --kit ./kits/ori \ |
| 14 | - --name ori \ | |
| 15 | - -p 8888:8888 | |
| 14 | + --name hello-ori \ | |
| 15 | + -p 3000:8888/tcp | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | +sbx run -d claude . \ | |
| 20 | + --template k33g/ori:0.0.2 \ | |
| 21 | + --kit https://rickub.com/bots-garden/kits/ori \ | |
| 22 | + --name hello-ori \ | |
| 23 | + -p 3000:8888/tcp | |
| 16 | 24 | ``` |
| 17 | 25 | |
| 18 | 26 | Then open **http://localhost:8888** — the panel connects to a Claude Code session already running in the sandbox, no login needed. |
| @@ -8,11 +8,19 @@ Ori is a web client for [ACP (Agent Client Protocol)](https://agentclientprotoco | |||
| 8 | From the directory where the kit lives, pointing at the project you want the agent to work on: | 8 | From the directory where the kit lives, pointing at the project you want the agent to work on: |
| 9 | 9 | ||
| 10 | ```bash | 10 | ```bash |
| 11 | -sbx run -d claude ~/path/to/your/project \ | 11 | +sbx run -d claude . \ |
| 12 | - --template k33g/ori:0.0.0 \ | 12 | + --template k33g/ori:0.0.2 \ |
| 13 | --kit ./kits/ori \ | 13 | --kit ./kits/ori \ |
| 14 | - --name ori \ | 14 | + --name hello-ori \ |
| 15 | - -p 8888:8888 | 15 | + -p 3000:8888/tcp |
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +sbx run -d claude . \ | ||
| 20 | + --template k33g/ori:0.0.2 \ | ||
| 21 | + --kit https://rickub.com/bots-garden/kits/ori \ | ||
| 22 | + --name hello-ori \ | ||
| 23 | + -p 3000:8888/tcp | ||
| 16 | ``` | 24 | ``` |
| 17 | 25 | ||
| 18 | Then open **http://localhost:8888** — the panel connects to a Claude Code session already running in the sandbox, no login needed. | 26 | Then open **http://localhost:8888** — the panel connects to a Claude Code session already running in the sandbox, no login needed. |
modified
cmd/ori/main.go +1 -1 | @@ -3,7 +3,7 @@ | ||
| 3 | 3 | // |
| 4 | 4 | // Usage: |
| 5 | 5 | // |
| 6 | -// ori [--addr :8888] [--cwd DIR] [--agent-cmd "npx -y @zed-industries/claude-code-acp"] | |
| 6 | +// ori [--addr :8888] [--cwd DIR] [--agent-cmd "npx -y @agentclientprotocol/claude-agent-acp"] | |
| 7 | 7 | package main |
| 8 | 8 | |
| 9 | 9 | import ( |
| @@ -3,7 +3,7 @@ | |||
| 3 | // | 3 | // |
| 4 | // Usage: | 4 | // Usage: |
| 5 | // | 5 | // |
| 6 | -// ori [--addr :8888] [--cwd DIR] [--agent-cmd "npx -y @zed-industries/claude-code-acp"] | 6 | +// ori [--addr :8888] [--cwd DIR] [--agent-cmd "npx -y @agentclientprotocol/claude-agent-acp"] |
| 7 | package main | 7 | package main |
| 8 | 8 | ||
| 9 | import ( | 9 | import ( |
modified
docs/diagrams/packages.drawio +1 -1 | @@ -37,7 +37,7 @@ | ||
| 37 | 37 | <mxCell id="wslib" value="github.com/coder/websocket (WebSocket implementation)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1"> |
| 38 | 38 | <mxGeometry x="450" y="460" width="230" height="60" as="geometry"/> |
| 39 | 39 | </mxCell> |
| 40 | - <mxCell id="adapter" value="npx @zed-industries/claude-code-acp (Claude Code ACP adapter — runtime subprocess)" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"> | |
| 40 | + <mxCell id="adapter" value="npx @agentclientprotocol/claude-agent-acp (Claude Agent SDK ACP adapter, bundles Claude Code — runtime subprocess)" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"> | |
| 41 | 41 | <mxGeometry x="890" y="580" width="270" height="60" as="geometry"/> |
| 42 | 42 | </mxCell> |
| 43 | 43 | <mxCell id="filespkg" value="internal/files (workspace file API: list, read, write)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"> |
| @@ -37,7 +37,7 @@ | |||
| 37 | <mxCell id="wslib" value="github.com/coder/websocket (WebSocket implementation)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1"> | 37 | <mxCell id="wslib" value="github.com/coder/websocket (WebSocket implementation)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1"> |
| 38 | <mxGeometry x="450" y="460" width="230" height="60" as="geometry"/> | 38 | <mxGeometry x="450" y="460" width="230" height="60" as="geometry"/> |
| 39 | </mxCell> | 39 | </mxCell> |
| 40 | - <mxCell id="adapter" value="npx @zed-industries/claude-code-acp (Claude Code ACP adapter — runtime subprocess)" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"> | 40 | + <mxCell id="adapter" value="npx @agentclientprotocol/claude-agent-acp (Claude Agent SDK ACP adapter, bundles Claude Code — runtime subprocess)" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"> |
| 41 | <mxGeometry x="890" y="580" width="270" height="60" as="geometry"/> | 41 | <mxGeometry x="890" y="580" width="270" height="60" as="geometry"/> |
| 42 | </mxCell> | 42 | </mxCell> |
| 43 | <mxCell id="filespkg" value="internal/files (workspace file API: list, read, write)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"> | 43 | <mxCell id="filespkg" value="internal/files (workspace file API: list, read, write)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"> |
modified
docs/en/explanation/architecture.md +3 -1 | @@ -45,7 +45,9 @@ The bridge could have translated ACP updates into its own message shapes. It del | ||
| 45 | 45 | |
| 46 | 46 | ## Why an adapter process for Claude Code |
| 47 | 47 | |
| 48 | -The Claude Code CLI has no native ACP mode (verified against v2.1.274: no such option or subcommand). Zed's own integration goes through [`@zed-industries/claude-code-acp`](https://www.npmjs.com/package/@zed-industries/claude-code-acp), which wraps the Claude Code SDK and exposes ACP on stdio. Ori spawns exactly that adapter by default. | |
| 48 | +The Claude Code CLI has no native ACP mode (verified against v2.1.274: no such option or subcommand). Ori therefore spawns [`@agentclientprotocol/claude-agent-acp`](https://www.npmjs.com/package/@agentclientprotocol/claude-agent-acp), the Agent Client Protocol project's adapter for the Claude Agent SDK, which exposes ACP on stdio. The adapter brings its own Claude Code CLI through the SDK's per-platform native package (2.1.274 with SDK 0.3.274), so the version that answers does not depend on what is installed on the machine. | |
| 49 | + | |
| 50 | +Ori used Zed's [`@zed-industries/claude-code-acp`](https://www.npmjs.com/package/@zed-industries/claude-code-acp) until 2026-09-18. That adapter pins an older SDK whose embedded CLI (2.1.44) the API now rejects for current models ("Claude Code 2.1.44 does not support this model; version 2.1.251 or newer is required"), which broke every prompt. Both adapters speak the same ACP, so the switch is a default-command change: `--agent-cmd` still accepts either. | |
| 49 | 51 | |
| 50 | 52 | ## Rejected alternatives |
| 51 | 53 | |
| @@ -45,7 +45,9 @@ The bridge could have translated ACP updates into its own message shapes. It del | |||
| 45 | 45 | ||
| 46 | ## Why an adapter process for Claude Code | 46 | ## Why an adapter process for Claude Code |
| 47 | 47 | ||
| 48 | -The Claude Code CLI has no native ACP mode (verified against v2.1.274: no such option or subcommand). Zed's own integration goes through [`@zed-industries/claude-code-acp`](https://www.npmjs.com/package/@zed-industries/claude-code-acp), which wraps the Claude Code SDK and exposes ACP on stdio. Ori spawns exactly that adapter by default. | 48 | +The Claude Code CLI has no native ACP mode (verified against v2.1.274: no such option or subcommand). Ori therefore spawns [`@agentclientprotocol/claude-agent-acp`](https://www.npmjs.com/package/@agentclientprotocol/claude-agent-acp), the Agent Client Protocol project's adapter for the Claude Agent SDK, which exposes ACP on stdio. The adapter brings its own Claude Code CLI through the SDK's per-platform native package (2.1.274 with SDK 0.3.274), so the version that answers does not depend on what is installed on the machine. |
| 49 | + | ||
| 50 | +Ori used Zed's [`@zed-industries/claude-code-acp`](https://www.npmjs.com/package/@zed-industries/claude-code-acp) until 2026-09-18. That adapter pins an older SDK whose embedded CLI (2.1.44) the API now rejects for current models ("Claude Code 2.1.44 does not support this model; version 2.1.251 or newer is required"), which broke every prompt. Both adapters speak the same ACP, so the switch is a default-command change: `--agent-cmd` still accepts either. | ||
| 49 | 51 | ||
| 50 | ## Rejected alternatives | 52 | ## Rejected alternatives |
| 51 | 53 | ||
modified
docs/en/how-to/run-in-a-sandbox.md +8 -6 | @@ -4,33 +4,35 @@ This guide shows how to package Ori as a Docker Sandboxes template and run it wi | ||
| 4 | 4 | |
| 5 | 5 | ## Steps |
| 6 | 6 | |
| 7 | -1. Get the template image — it is published on Docker Hub as `k33g/ori:0.0.0`. To (re)build and push it yourself, from the repository root: | |
| 7 | +1. Get the template image — it is published on Docker Hub as `k33g/ori:0.0.2`. To (re)build and push it yourself, from the repository root: | |
| 8 | 8 | |
| 9 | 9 | ```bash |
| 10 | 10 | ./template/build.sh |
| 11 | 11 | ``` |
| 12 | 12 | |
| 13 | - The script runs a multi-arch `docker buildx build --push`: the SPA and the Go binaries are built in intermediate stages, then layered with the `claude-code-acp` adapter on top of the official `docker/sandbox-templates:claude-code` image. For a local-only image use `make template` instead. | |
| 13 | + The script runs a multi-arch `docker buildx build --push`: the SPA and the Go binaries are built in intermediate stages, then layered with the `claude-agent-acp` adapter on top of the official `docker/sandbox-templates:claude-code` image. For a local-only image use `make template` instead. | |
| 14 | 14 | |
| 15 | 15 | 2. Create the sandbox from your project directory, with the template and the ori kit, in detached mode: |
| 16 | 16 | |
| 17 | 17 | ```bash |
| 18 | 18 | sbx run -d claude ~/path/to/your/project \ |
| 19 | - --template k33g/ori:0.0.0 \ | |
| 19 | + --template k33g/ori:0.0.2 \ | |
| 20 | 20 | --kit /path/to/ori/kits/ori |
| 21 | 21 | ``` |
| 22 | 22 | |
| 23 | 23 | `-d` (`--detached`) matters: sbx stops a sandbox 30 seconds after the last CLI session on it closes, and browser traffic on a published port is not a session. `sbx create` holds a session only while it runs, so a sandbox created with it goes `stopped` half a minute later. A detached sandbox is exempt from this auto-stop until you `sbx stop` or `sbx rm` it. The flag exists only on `sbx run`, and the mode is fixed at creation. |
| 24 | 24 | |
| 25 | + To pin a host port, add `-p 5555:8888/tcp`. Keep the `/tcp` suffix: without a protocol sbx binds IPv4 only (`tcp4`), and a browser that resolves `localhost` to `::1` gets "site can't be reached" while the server is up. Avoid ports Chrome refuses outright, such as 6665–6669. | |
| 26 | + | |
| 25 | 27 | The kit's startup command launches the ori server on port 8888 at every container start; the claude agent kit injects the Anthropic credentials through the sandbox proxy, so nothing needs a login inside. |
| 26 | 28 | |
| 27 | -3. Open the UI: the kit declares port 8888, so the command output prints the ephemeral address it published — `Published web: localhost:<port> -> 8888/tcp`. Browse there, or pin a fixed port with `-p 8888:8888` at creation (or later with `sbx ports <sandbox-name> --publish 8888:8888/tcp`). | |
| 29 | +3. Open the UI: the kit declares port 8888, so the command output prints the ephemeral address it published — `Published web: localhost:<port> -> 8888/tcp`. Browse there, or pin a fixed port with `-p 8888:8888/tcp` at creation (or later with `sbx ports <sandbox-name> --publish 8888:8888/tcp`). | |
| 28 | 30 | |
| 29 | 31 | ## Variants |
| 30 | 32 | |
| 31 | -- The listen port is a kit argument (default 8888): add `--kit-arg ori.port=9000` to change it (and publish that port instead). | |
| 33 | +- The listen port is a kit argument (default 8888): add `--kit-arg ori.port=9000` to change it, and publish that port yourself with `-p 9000:9000` — the port the kit declares for auto-publishing is fixed at 8888. | |
| 32 | 34 | - If the image was never pushed to Docker Hub, hand it to the sandbox runtime's own image store first: `docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. |
| 33 | -- Standalone, without sbx: `docker run --rm -p 8888:8888 k33g/ori` (provide `ANTHROPIC_API_KEY`, or use the demo agent below). | |
| 35 | +- Standalone, without sbx: `docker run --rm -p 8888:8888/tcp k33g/ori` (provide `ANTHROPIC_API_KEY`, or use the demo agent below). | |
| 34 | 36 | - Credential-free demo: inside the sandbox, `pkill -x ori` then relaunch with `--agent-cmd ori-mock-agent`. |
| 35 | 37 | - The server log inside the sandbox is `/home/agent/.ori.log`. |
| 36 | 38 | - A stopped sandbox restarts with `sbx run -d --name <sandbox-name>` (or `sbx attach`); the kit relaunches the server on every start. |
| @@ -4,33 +4,35 @@ This guide shows how to package Ori as a Docker Sandboxes template and run it wi | |||
| 4 | 4 | ||
| 5 | ## Steps | 5 | ## Steps |
| 6 | 6 | ||
| 7 | -1. Get the template image — it is published on Docker Hub as `k33g/ori:0.0.0`. To (re)build and push it yourself, from the repository root: | 7 | +1. Get the template image — it is published on Docker Hub as `k33g/ori:0.0.2`. To (re)build and push it yourself, from the repository root: |
| 8 | 8 | ||
| 9 | ```bash | 9 | ```bash |
| 10 | ./template/build.sh | 10 | ./template/build.sh |
| 11 | ``` | 11 | ``` |
| 12 | 12 | ||
| 13 | - The script runs a multi-arch `docker buildx build --push`: the SPA and the Go binaries are built in intermediate stages, then layered with the `claude-code-acp` adapter on top of the official `docker/sandbox-templates:claude-code` image. For a local-only image use `make template` instead. | 13 | + The script runs a multi-arch `docker buildx build --push`: the SPA and the Go binaries are built in intermediate stages, then layered with the `claude-agent-acp` adapter on top of the official `docker/sandbox-templates:claude-code` image. For a local-only image use `make template` instead. |
| 14 | 14 | ||
| 15 | 2. Create the sandbox from your project directory, with the template and the ori kit, in detached mode: | 15 | 2. Create the sandbox from your project directory, with the template and the ori kit, in detached mode: |
| 16 | 16 | ||
| 17 | ```bash | 17 | ```bash |
| 18 | sbx run -d claude ~/path/to/your/project \ | 18 | sbx run -d claude ~/path/to/your/project \ |
| 19 | - --template k33g/ori:0.0.0 \ | 19 | + --template k33g/ori:0.0.2 \ |
| 20 | --kit /path/to/ori/kits/ori | 20 | --kit /path/to/ori/kits/ori |
| 21 | ``` | 21 | ``` |
| 22 | 22 | ||
| 23 | `-d` (`--detached`) matters: sbx stops a sandbox 30 seconds after the last CLI session on it closes, and browser traffic on a published port is not a session. `sbx create` holds a session only while it runs, so a sandbox created with it goes `stopped` half a minute later. A detached sandbox is exempt from this auto-stop until you `sbx stop` or `sbx rm` it. The flag exists only on `sbx run`, and the mode is fixed at creation. | 23 | `-d` (`--detached`) matters: sbx stops a sandbox 30 seconds after the last CLI session on it closes, and browser traffic on a published port is not a session. `sbx create` holds a session only while it runs, so a sandbox created with it goes `stopped` half a minute later. A detached sandbox is exempt from this auto-stop until you `sbx stop` or `sbx rm` it. The flag exists only on `sbx run`, and the mode is fixed at creation. |
| 24 | 24 | ||
| 25 | + To pin a host port, add `-p 5555:8888/tcp`. Keep the `/tcp` suffix: without a protocol sbx binds IPv4 only (`tcp4`), and a browser that resolves `localhost` to `::1` gets "site can't be reached" while the server is up. Avoid ports Chrome refuses outright, such as 6665–6669. | ||
| 26 | + | ||
| 25 | The kit's startup command launches the ori server on port 8888 at every container start; the claude agent kit injects the Anthropic credentials through the sandbox proxy, so nothing needs a login inside. | 27 | The kit's startup command launches the ori server on port 8888 at every container start; the claude agent kit injects the Anthropic credentials through the sandbox proxy, so nothing needs a login inside. |
| 26 | 28 | ||
| 27 | -3. Open the UI: the kit declares port 8888, so the command output prints the ephemeral address it published — `Published web: localhost:<port> -> 8888/tcp`. Browse there, or pin a fixed port with `-p 8888:8888` at creation (or later with `sbx ports <sandbox-name> --publish 8888:8888/tcp`). | 29 | +3. Open the UI: the kit declares port 8888, so the command output prints the ephemeral address it published — `Published web: localhost:<port> -> 8888/tcp`. Browse there, or pin a fixed port with `-p 8888:8888/tcp` at creation (or later with `sbx ports <sandbox-name> --publish 8888:8888/tcp`). |
| 28 | 30 | ||
| 29 | ## Variants | 31 | ## Variants |
| 30 | 32 | ||
| 31 | -- The listen port is a kit argument (default 8888): add `--kit-arg ori.port=9000` to change it (and publish that port instead). | 33 | +- The listen port is a kit argument (default 8888): add `--kit-arg ori.port=9000` to change it, and publish that port yourself with `-p 9000:9000` — the port the kit declares for auto-publishing is fixed at 8888. |
| 32 | - If the image was never pushed to Docker Hub, hand it to the sandbox runtime's own image store first: `docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. | 34 | - If the image was never pushed to Docker Hub, hand it to the sandbox runtime's own image store first: `docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. |
| 33 | -- Standalone, without sbx: `docker run --rm -p 8888:8888 k33g/ori` (provide `ANTHROPIC_API_KEY`, or use the demo agent below). | 35 | +- Standalone, without sbx: `docker run --rm -p 8888:8888/tcp k33g/ori` (provide `ANTHROPIC_API_KEY`, or use the demo agent below). |
| 34 | - Credential-free demo: inside the sandbox, `pkill -x ori` then relaunch with `--agent-cmd ori-mock-agent`. | 36 | - Credential-free demo: inside the sandbox, `pkill -x ori` then relaunch with `--agent-cmd ori-mock-agent`. |
| 35 | - The server log inside the sandbox is `/home/agent/.ori.log`. | 37 | - The server log inside the sandbox is `/home/agent/.ori.log`. |
| 36 | - A stopped sandbox restarts with `sbx run -d --name <sandbox-name>` (or `sbx attach`); the kit relaunches the server on every start. | 38 | - A stopped sandbox restarts with `sbx run -d --name <sandbox-name>` (or `sbx attach`); the kit relaunches the server on every start. |
modified
docs/en/how-to/run-the-tests.md +2 -0 | @@ -12,6 +12,8 @@ This guide shows how to run Ori's test suites. It assumes the frontend dependenc | ||
| 12 | 12 | |
| 13 | 13 | This runs the Go suite (`go test ./...`) followed by the frontend suite (`vitest run`). Both must end green. |
| 14 | 14 | |
| 15 | + The frontend script sets `NODE_OPTIONS=--no-experimental-webstorage`: Node 25 ships a built-in `localStorage` without `clear()` that shadows jsdom's and fails every store test. The flag is known to Node 22 and later, so it is harmless on older runtimes. | |
| 16 | + | |
| 15 | 17 | ## Variants |
| 16 | 18 | |
| 17 | 19 | - Backend only: `make test-go` — unit tests for every package plus an end-to-end test that compiles the mock agent, spawns it as a real subprocess and drives a real WebSocket client through a full turn. |
| @@ -12,6 +12,8 @@ This guide shows how to run Ori's test suites. It assumes the frontend dependenc | |||
| 12 | 12 | ||
| 13 | This runs the Go suite (`go test ./...`) followed by the frontend suite (`vitest run`). Both must end green. | 13 | This runs the Go suite (`go test ./...`) followed by the frontend suite (`vitest run`). Both must end green. |
| 14 | 14 | ||
| 15 | + The frontend script sets `NODE_OPTIONS=--no-experimental-webstorage`: Node 25 ships a built-in `localStorage` without `clear()` that shadows jsdom's and fails every store test. The flag is known to Node 22 and later, so it is harmless on older runtimes. | ||
| 16 | + | ||
| 15 | ## Variants | 17 | ## Variants |
| 16 | 18 | ||
| 17 | - Backend only: `make test-go` — unit tests for every package plus an end-to-end test that compiles the mock agent, spawns it as a real subprocess and drives a real WebSocket client through a full turn. | 19 | - Backend only: `make test-go` — unit tests for every package plus an end-to-end test that compiles the mock agent, spawns it as a real subprocess and drives a real WebSocket client through a full turn. |
modified
docs/en/how-to/run-with-claude-code.md +2 -2 | @@ -4,7 +4,7 @@ This guide shows how to start Ori connected to Claude Code. It assumes you have | ||
| 4 | 4 | |
| 5 | 5 | ## Steps |
| 6 | 6 | |
| 7 | -1. Make sure Node.js and npm are available: the backend spawns Claude Code's official ACP adapter with `npx -y @zed-industries/claude-code-acp`. | |
| 7 | +1. Make sure Node.js and npm are available: the backend spawns the Claude Agent SDK's ACP adapter with `npx -y @agentclientprotocol/claude-agent-acp`. The adapter ships its own Claude Code CLI (a native package chosen for your platform), so it works even if the `claude` command on your machine is older. | |
| 8 | 8 | 2. Make sure Claude Code is authenticated on this machine (`claude` login flow, or an `ANTHROPIC_API_KEY` environment variable the adapter can use). |
| 9 | 9 | 3. From the repository root, start the server: |
| 10 | 10 | |
| @@ -18,7 +18,7 @@ This guide shows how to start Ori connected to Claude Code. It assumes you have | ||
| 18 | 18 | |
| 19 | 19 | - To work on a specific project directory, pass the agent's working directory explicitly: `./bin/ori --cwd /path/to/your/project`. |
| 20 | 20 | - To serve on another port: `./bin/ori --addr :9000`. |
| 21 | -- The first `npx` run downloads the adapter package; pin it by installing it globally (`npm install -g @zed-industries/claude-code-acp`) and passing `--agent-cmd "claude-code-acp"`. | |
| 21 | +- The first `npx` run downloads the adapter package; pin it by installing it globally (`npm install -g @agentclientprotocol/claude-agent-acp`) and passing `--agent-cmd "claude-agent-acp"`. | |
| 22 | 22 | |
| 23 | 23 | ## See also |
| 24 | 24 | |
| @@ -4,7 +4,7 @@ This guide shows how to start Ori connected to Claude Code. It assumes you have | |||
| 4 | 4 | ||
| 5 | ## Steps | 5 | ## Steps |
| 6 | 6 | ||
| 7 | -1. Make sure Node.js and npm are available: the backend spawns Claude Code's official ACP adapter with `npx -y @zed-industries/claude-code-acp`. | 7 | +1. Make sure Node.js and npm are available: the backend spawns the Claude Agent SDK's ACP adapter with `npx -y @agentclientprotocol/claude-agent-acp`. The adapter ships its own Claude Code CLI (a native package chosen for your platform), so it works even if the `claude` command on your machine is older. |
| 8 | 2. Make sure Claude Code is authenticated on this machine (`claude` login flow, or an `ANTHROPIC_API_KEY` environment variable the adapter can use). | 8 | 2. Make sure Claude Code is authenticated on this machine (`claude` login flow, or an `ANTHROPIC_API_KEY` environment variable the adapter can use). |
| 9 | 3. From the repository root, start the server: | 9 | 3. From the repository root, start the server: |
| 10 | 10 | ||
| @@ -18,7 +18,7 @@ This guide shows how to start Ori connected to Claude Code. It assumes you have | |||
| 18 | 18 | ||
| 19 | - To work on a specific project directory, pass the agent's working directory explicitly: `./bin/ori --cwd /path/to/your/project`. | 19 | - To work on a specific project directory, pass the agent's working directory explicitly: `./bin/ori --cwd /path/to/your/project`. |
| 20 | - To serve on another port: `./bin/ori --addr :9000`. | 20 | - To serve on another port: `./bin/ori --addr :9000`. |
| 21 | -- The first `npx` run downloads the adapter package; pin it by installing it globally (`npm install -g @zed-industries/claude-code-acp`) and passing `--agent-cmd "claude-code-acp"`. | 21 | +- The first `npx` run downloads the adapter package; pin it by installing it globally (`npm install -g @agentclientprotocol/claude-agent-acp`) and passing `--agent-cmd "claude-agent-acp"`. |
| 22 | 22 | ||
| 23 | ## See also | 23 | ## See also |
| 24 | 24 | ||
modified
docs/en/reference/cli.md +1 -1 | @@ -16,7 +16,7 @@ At startup, `ori` spawns the agent command, performs the ACP handshake (`initial | ||
| 16 | 16 | | --- | --- | --- | --- | |
| 17 | 17 | | `--addr` | string | `:8888` | TCP address the HTTP server listens on. The empty host binds all interfaces. | |
| 18 | 18 | | `--cwd` | string | current directory | Working directory handed to the agent session. Must exist and be a directory; resolved to an absolute path. | |
| 19 | -| `--agent-cmd` | string | `npx -y @zed-industries/claude-code-acp` | Command spawning the ACP agent, split on whitespace (first field: executable; the rest: arguments). | | |
| 19 | +| `--agent-cmd` | string | `npx -y @agentclientprotocol/claude-agent-acp` | Command spawning the ACP agent, split on whitespace (first field: executable; the rest: arguments). | | |
| 20 | 20 | |
| 21 | 21 | ## HTTP endpoints |
| 22 | 22 | |
| @@ -16,7 +16,7 @@ At startup, `ori` spawns the agent command, performs the ACP handshake (`initial | |||
| 16 | | --- | --- | --- | --- | | 16 | | --- | --- | --- | --- | |
| 17 | | `--addr` | string | `:8888` | TCP address the HTTP server listens on. The empty host binds all interfaces. | | 17 | | `--addr` | string | `:8888` | TCP address the HTTP server listens on. The empty host binds all interfaces. | |
| 18 | | `--cwd` | string | current directory | Working directory handed to the agent session. Must exist and be a directory; resolved to an absolute path. | | 18 | | `--cwd` | string | current directory | Working directory handed to the agent session. Must exist and be a directory; resolved to an absolute path. | |
| 19 | -| `--agent-cmd` | string | `npx -y @zed-industries/claude-code-acp` | Command spawning the ACP agent, split on whitespace (first field: executable; the rest: arguments). | | 19 | +| `--agent-cmd` | string | `npx -y @agentclientprotocol/claude-agent-acp` | Command spawning the ACP agent, split on whitespace (first field: executable; the rest: arguments). | |
| 20 | 20 | ||
| 21 | ## HTTP endpoints | 21 | ## HTTP endpoints |
| 22 | 22 | ||
modified
docs/fr/explanation/architecture.md +3 -1 | @@ -45,7 +45,9 @@ Le bridge aurait pu traduire les updates ACP dans ses propres formes de messages | ||
| 45 | 45 | |
| 46 | 46 | ## Pourquoi un processus adaptateur pour Claude Code |
| 47 | 47 | |
| 48 | -La CLI Claude Code n'a pas de mode ACP natif (vérifié sur la v2.1.274 : aucune option ni sous-commande de ce type). L'intégration de Zed lui-même passe par [`@zed-industries/claude-code-acp`](https://www.npmjs.com/package/@zed-industries/claude-code-acp), qui enveloppe le SDK Claude Code et expose ACP sur stdio. Ori lance exactement cet adaptateur par défaut. | |
| 48 | +La CLI Claude Code n'a pas de mode ACP natif (vérifié sur la v2.1.274 : aucune option ni sous-commande de ce type). Ori lance donc [`@agentclientprotocol/claude-agent-acp`](https://www.npmjs.com/package/@agentclientprotocol/claude-agent-acp), l'adaptateur du projet Agent Client Protocol pour le Claude Agent SDK, qui expose ACP sur stdio. L'adaptateur apporte sa propre CLI Claude Code via le paquet natif par plateforme du SDK (2.1.274 avec le SDK 0.3.274) : la version qui répond ne dépend pas de ce qui est installé sur la machine. | |
| 49 | + | |
| 50 | +Jusqu'au 18 septembre 2026, Ori utilisait [`@zed-industries/claude-code-acp`](https://www.npmjs.com/package/@zed-industries/claude-code-acp) de Zed. Cet adaptateur fige un SDK plus ancien dont la CLI embarquée (2.1.44) est désormais refusée par l'API pour les modèles actuels (« Claude Code 2.1.44 does not support this model; version 2.1.251 or newer is required »), ce qui cassait chaque prompt. Les deux adaptateurs parlent le même ACP : le changement est une simple valeur par défaut, `--agent-cmd` accepte toujours l'un ou l'autre. | |
| 49 | 51 | |
| 50 | 52 | ## Alternatives écartées |
| 51 | 53 | |
| @@ -45,7 +45,9 @@ Le bridge aurait pu traduire les updates ACP dans ses propres formes de messages | |||
| 45 | 45 | ||
| 46 | ## Pourquoi un processus adaptateur pour Claude Code | 46 | ## Pourquoi un processus adaptateur pour Claude Code |
| 47 | 47 | ||
| 48 | -La CLI Claude Code n'a pas de mode ACP natif (vérifié sur la v2.1.274 : aucune option ni sous-commande de ce type). L'intégration de Zed lui-même passe par [`@zed-industries/claude-code-acp`](https://www.npmjs.com/package/@zed-industries/claude-code-acp), qui enveloppe le SDK Claude Code et expose ACP sur stdio. Ori lance exactement cet adaptateur par défaut. | 48 | +La CLI Claude Code n'a pas de mode ACP natif (vérifié sur la v2.1.274 : aucune option ni sous-commande de ce type). Ori lance donc [`@agentclientprotocol/claude-agent-acp`](https://www.npmjs.com/package/@agentclientprotocol/claude-agent-acp), l'adaptateur du projet Agent Client Protocol pour le Claude Agent SDK, qui expose ACP sur stdio. L'adaptateur apporte sa propre CLI Claude Code via le paquet natif par plateforme du SDK (2.1.274 avec le SDK 0.3.274) : la version qui répond ne dépend pas de ce qui est installé sur la machine. |
| 49 | + | ||
| 50 | +Jusqu'au 18 septembre 2026, Ori utilisait [`@zed-industries/claude-code-acp`](https://www.npmjs.com/package/@zed-industries/claude-code-acp) de Zed. Cet adaptateur fige un SDK plus ancien dont la CLI embarquée (2.1.44) est désormais refusée par l'API pour les modèles actuels (« Claude Code 2.1.44 does not support this model; version 2.1.251 or newer is required »), ce qui cassait chaque prompt. Les deux adaptateurs parlent le même ACP : le changement est une simple valeur par défaut, `--agent-cmd` accepte toujours l'un ou l'autre. | ||
| 49 | 51 | ||
| 50 | ## Alternatives écartées | 52 | ## Alternatives écartées |
| 51 | 53 | ||
modified
docs/fr/how-to/run-in-a-sandbox.md +8 -6 | @@ -4,33 +4,35 @@ Ce guide montre comment empaqueter Ori en template Docker Sandboxes et le lancer | ||
| 4 | 4 | |
| 5 | 5 | ## Étapes |
| 6 | 6 | |
| 7 | -1. Récupérez l'image du template — elle est publiée sur Docker Hub sous `k33g/ori:0.0.0`. Pour la (re)construire et la pousser vous-même, depuis la racine du dépôt : | |
| 7 | +1. Récupérez l'image du template — elle est publiée sur Docker Hub sous `k33g/ori:0.0.2`. Pour la (re)construire et la pousser vous-même, depuis la racine du dépôt : | |
| 8 | 8 | |
| 9 | 9 | ```bash |
| 10 | 10 | ./template/build.sh |
| 11 | 11 | ``` |
| 12 | 12 | |
| 13 | - Le script exécute un `docker buildx build --push` multi-architectures : la SPA et les binaires Go sont compilés dans des étapes intermédiaires, puis posés avec l'adaptateur `claude-code-acp` au-dessus de l'image officielle `docker/sandbox-templates:claude-code`. Pour une image locale uniquement, utilisez plutôt `make template`. | |
| 13 | + Le script exécute un `docker buildx build --push` multi-architectures : la SPA et les binaires Go sont compilés dans des étapes intermédiaires, puis posés avec l'adaptateur `claude-agent-acp` au-dessus de l'image officielle `docker/sandbox-templates:claude-code`. Pour une image locale uniquement, utilisez plutôt `make template`. | |
| 14 | 14 | |
| 15 | 15 | 2. Créez la sandbox depuis votre répertoire de projet, avec le template et le kit ori, en mode détaché : |
| 16 | 16 | |
| 17 | 17 | ```bash |
| 18 | 18 | sbx run -d claude ~/chemin/vers/votre/projet \ |
| 19 | - --template k33g/ori:0.0.0 \ | |
| 19 | + --template k33g/ori:0.0.2 \ | |
| 20 | 20 | --kit /chemin/vers/ori/kits/ori |
| 21 | 21 | ``` |
| 22 | 22 | |
| 23 | 23 | Le `-d` (`--detached`) est important : sbx arrête une sandbox 30 secondes après la fermeture de la dernière session CLI ouverte dessus, et le trafic du navigateur sur un port publié n'est pas une session. `sbx create` ne tient une session que le temps de son exécution, donc une sandbox créée ainsi passe en `stopped` une demi-minute plus tard. Une sandbox détachée échappe à cet arrêt automatique jusqu'à ce que vous fassiez `sbx stop` ou `sbx rm`. L'option n'existe que sur `sbx run`, et le mode est figé à la création. |
| 24 | 24 | |
| 25 | + Pour fixer un port hôte, ajoutez `-p 5555:8888/tcp`. Gardez le suffixe `/tcp` : sans protocole, sbx ne lie que l'IPv4 (`tcp4`), et un navigateur qui résout `localhost` en `::1` affiche « site inaccessible » alors que le serveur tourne. Évitez les ports que Chrome refuse d'office, comme 6665 à 6669. | |
| 26 | + | |
| 25 | 27 | La commande de démarrage du kit lance le serveur ori sur le port 8888 à chaque démarrage du conteneur ; le kit agent claude injecte les identifiants Anthropic via le proxy de la sandbox, donc aucune connexion n'est nécessaire à l'intérieur. |
| 26 | 28 | |
| 27 | -3. Ouvrez l'interface : le kit déclare le port 8888, la sortie de la commande affiche donc l'adresse éphémère publiée — `Published web: localhost:<port> -> 8888/tcp`. Ouvrez-la, ou fixez un port stable avec `-p 8888:8888` à la création (ou après coup avec `sbx ports <nom-de-la-sandbox> --publish 8888:8888/tcp`). | |
| 29 | +3. Ouvrez l'interface : le kit déclare le port 8888, la sortie de la commande affiche donc l'adresse éphémère publiée — `Published web: localhost:<port> -> 8888/tcp`. Ouvrez-la, ou fixez un port stable avec `-p 8888:8888/tcp` à la création (ou après coup avec `sbx ports <nom-de-la-sandbox> --publish 8888:8888/tcp`). | |
| 28 | 30 | |
| 29 | 31 | ## Variantes |
| 30 | 32 | |
| 31 | -- Le port d'écoute est un argument du kit (défaut 8888) : ajoutez `--kit-arg ori.port=9000` pour le changer (et publiez ce port-là à la place). | |
| 33 | +- Le port d'écoute est un argument du kit (défaut 8888) : ajoutez `--kit-arg ori.port=9000` pour le changer, et publiez ce port vous-même avec `-p 9000:9000` — le port que le kit déclare pour l'auto-publication est fixé à 8888. | |
| 32 | 34 | - Si l'image n'a jamais été poussée sur Docker Hub, confiez-la d'abord au magasin d'images du runtime des sandboxes : `docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. |
| 33 | -- Autonome, sans sbx : `docker run --rm -p 8888:8888 k33g/ori` (fournissez `ANTHROPIC_API_KEY`, ou utilisez l'agent de démonstration ci-dessous). | |
| 35 | +- Autonome, sans sbx : `docker run --rm -p 8888:8888/tcp k33g/ori` (fournissez `ANTHROPIC_API_KEY`, ou utilisez l'agent de démonstration ci-dessous). | |
| 34 | 36 | - Démo sans identifiants : dans la sandbox, `pkill -x ori` puis relancez avec `--agent-cmd ori-mock-agent`. |
| 35 | 37 | - Le log du serveur dans la sandbox est `/home/agent/.ori.log`. |
| 36 | 38 | - Une sandbox arrêtée redémarre avec `sbx run -d --name <nom-de-la-sandbox>` (ou `sbx attach`) ; le kit relance le serveur à chaque démarrage. |
| @@ -4,33 +4,35 @@ Ce guide montre comment empaqueter Ori en template Docker Sandboxes et le lancer | |||
| 4 | 4 | ||
| 5 | ## Étapes | 5 | ## Étapes |
| 6 | 6 | ||
| 7 | -1. Récupérez l'image du template — elle est publiée sur Docker Hub sous `k33g/ori:0.0.0`. Pour la (re)construire et la pousser vous-même, depuis la racine du dépôt : | 7 | +1. Récupérez l'image du template — elle est publiée sur Docker Hub sous `k33g/ori:0.0.2`. Pour la (re)construire et la pousser vous-même, depuis la racine du dépôt : |
| 8 | 8 | ||
| 9 | ```bash | 9 | ```bash |
| 10 | ./template/build.sh | 10 | ./template/build.sh |
| 11 | ``` | 11 | ``` |
| 12 | 12 | ||
| 13 | - Le script exécute un `docker buildx build --push` multi-architectures : la SPA et les binaires Go sont compilés dans des étapes intermédiaires, puis posés avec l'adaptateur `claude-code-acp` au-dessus de l'image officielle `docker/sandbox-templates:claude-code`. Pour une image locale uniquement, utilisez plutôt `make template`. | 13 | + Le script exécute un `docker buildx build --push` multi-architectures : la SPA et les binaires Go sont compilés dans des étapes intermédiaires, puis posés avec l'adaptateur `claude-agent-acp` au-dessus de l'image officielle `docker/sandbox-templates:claude-code`. Pour une image locale uniquement, utilisez plutôt `make template`. |
| 14 | 14 | ||
| 15 | 2. Créez la sandbox depuis votre répertoire de projet, avec le template et le kit ori, en mode détaché : | 15 | 2. Créez la sandbox depuis votre répertoire de projet, avec le template et le kit ori, en mode détaché : |
| 16 | 16 | ||
| 17 | ```bash | 17 | ```bash |
| 18 | sbx run -d claude ~/chemin/vers/votre/projet \ | 18 | sbx run -d claude ~/chemin/vers/votre/projet \ |
| 19 | - --template k33g/ori:0.0.0 \ | 19 | + --template k33g/ori:0.0.2 \ |
| 20 | --kit /chemin/vers/ori/kits/ori | 20 | --kit /chemin/vers/ori/kits/ori |
| 21 | ``` | 21 | ``` |
| 22 | 22 | ||
| 23 | Le `-d` (`--detached`) est important : sbx arrête une sandbox 30 secondes après la fermeture de la dernière session CLI ouverte dessus, et le trafic du navigateur sur un port publié n'est pas une session. `sbx create` ne tient une session que le temps de son exécution, donc une sandbox créée ainsi passe en `stopped` une demi-minute plus tard. Une sandbox détachée échappe à cet arrêt automatique jusqu'à ce que vous fassiez `sbx stop` ou `sbx rm`. L'option n'existe que sur `sbx run`, et le mode est figé à la création. | 23 | Le `-d` (`--detached`) est important : sbx arrête une sandbox 30 secondes après la fermeture de la dernière session CLI ouverte dessus, et le trafic du navigateur sur un port publié n'est pas une session. `sbx create` ne tient une session que le temps de son exécution, donc une sandbox créée ainsi passe en `stopped` une demi-minute plus tard. Une sandbox détachée échappe à cet arrêt automatique jusqu'à ce que vous fassiez `sbx stop` ou `sbx rm`. L'option n'existe que sur `sbx run`, et le mode est figé à la création. |
| 24 | 24 | ||
| 25 | + Pour fixer un port hôte, ajoutez `-p 5555:8888/tcp`. Gardez le suffixe `/tcp` : sans protocole, sbx ne lie que l'IPv4 (`tcp4`), et un navigateur qui résout `localhost` en `::1` affiche « site inaccessible » alors que le serveur tourne. Évitez les ports que Chrome refuse d'office, comme 6665 à 6669. | ||
| 26 | + | ||
| 25 | La commande de démarrage du kit lance le serveur ori sur le port 8888 à chaque démarrage du conteneur ; le kit agent claude injecte les identifiants Anthropic via le proxy de la sandbox, donc aucune connexion n'est nécessaire à l'intérieur. | 27 | La commande de démarrage du kit lance le serveur ori sur le port 8888 à chaque démarrage du conteneur ; le kit agent claude injecte les identifiants Anthropic via le proxy de la sandbox, donc aucune connexion n'est nécessaire à l'intérieur. |
| 26 | 28 | ||
| 27 | -3. Ouvrez l'interface : le kit déclare le port 8888, la sortie de la commande affiche donc l'adresse éphémère publiée — `Published web: localhost:<port> -> 8888/tcp`. Ouvrez-la, ou fixez un port stable avec `-p 8888:8888` à la création (ou après coup avec `sbx ports <nom-de-la-sandbox> --publish 8888:8888/tcp`). | 29 | +3. Ouvrez l'interface : le kit déclare le port 8888, la sortie de la commande affiche donc l'adresse éphémère publiée — `Published web: localhost:<port> -> 8888/tcp`. Ouvrez-la, ou fixez un port stable avec `-p 8888:8888/tcp` à la création (ou après coup avec `sbx ports <nom-de-la-sandbox> --publish 8888:8888/tcp`). |
| 28 | 30 | ||
| 29 | ## Variantes | 31 | ## Variantes |
| 30 | 32 | ||
| 31 | -- Le port d'écoute est un argument du kit (défaut 8888) : ajoutez `--kit-arg ori.port=9000` pour le changer (et publiez ce port-là à la place). | 33 | +- Le port d'écoute est un argument du kit (défaut 8888) : ajoutez `--kit-arg ori.port=9000` pour le changer, et publiez ce port vous-même avec `-p 9000:9000` — le port que le kit déclare pour l'auto-publication est fixé à 8888. |
| 32 | - Si l'image n'a jamais été poussée sur Docker Hub, confiez-la d'abord au magasin d'images du runtime des sandboxes : `docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. | 34 | - Si l'image n'a jamais été poussée sur Docker Hub, confiez-la d'abord au magasin d'images du runtime des sandboxes : `docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. |
| 33 | -- Autonome, sans sbx : `docker run --rm -p 8888:8888 k33g/ori` (fournissez `ANTHROPIC_API_KEY`, ou utilisez l'agent de démonstration ci-dessous). | 35 | +- Autonome, sans sbx : `docker run --rm -p 8888:8888/tcp k33g/ori` (fournissez `ANTHROPIC_API_KEY`, ou utilisez l'agent de démonstration ci-dessous). |
| 34 | - Démo sans identifiants : dans la sandbox, `pkill -x ori` puis relancez avec `--agent-cmd ori-mock-agent`. | 36 | - Démo sans identifiants : dans la sandbox, `pkill -x ori` puis relancez avec `--agent-cmd ori-mock-agent`. |
| 35 | - Le log du serveur dans la sandbox est `/home/agent/.ori.log`. | 37 | - Le log du serveur dans la sandbox est `/home/agent/.ori.log`. |
| 36 | - Une sandbox arrêtée redémarre avec `sbx run -d --name <nom-de-la-sandbox>` (ou `sbx attach`) ; le kit relance le serveur à chaque démarrage. | 38 | - Une sandbox arrêtée redémarre avec `sbx run -d --name <nom-de-la-sandbox>` (ou `sbx attach`) ; le kit relance le serveur à chaque démarrage. |
modified
docs/fr/how-to/run-the-tests.md +2 -0 | @@ -12,6 +12,8 @@ Ce guide montre comment lancer les suites de tests d'Ori. Il suppose que les dé | ||
| 12 | 12 | |
| 13 | 13 | Cette commande exécute la suite Go (`go test ./...`) puis la suite front (`vitest run`). Les deux doivent finir au vert. |
| 14 | 14 | |
| 15 | + Le script front positionne `NODE_OPTIONS=--no-experimental-webstorage` : Node 25 fournit un `localStorage` natif sans `clear()` qui masque celui de jsdom et fait échouer tous les tests de store. L'option est connue de Node 22 et suivants, donc sans effet sur les runtimes plus anciens. | |
| 16 | + | |
| 15 | 17 | ## Variantes |
| 16 | 18 | |
| 17 | 19 | - Backend seul : `make test-go` — tests unitaires de chaque package plus un test de bout en bout qui compile l'agent mock, le lance comme vrai sous-processus et pilote un vrai client WebSocket sur un tour complet. |
| @@ -12,6 +12,8 @@ Ce guide montre comment lancer les suites de tests d'Ori. Il suppose que les dé | |||
| 12 | 12 | ||
| 13 | Cette commande exécute la suite Go (`go test ./...`) puis la suite front (`vitest run`). Les deux doivent finir au vert. | 13 | Cette commande exécute la suite Go (`go test ./...`) puis la suite front (`vitest run`). Les deux doivent finir au vert. |
| 14 | 14 | ||
| 15 | + Le script front positionne `NODE_OPTIONS=--no-experimental-webstorage` : Node 25 fournit un `localStorage` natif sans `clear()` qui masque celui de jsdom et fait échouer tous les tests de store. L'option est connue de Node 22 et suivants, donc sans effet sur les runtimes plus anciens. | ||
| 16 | + | ||
| 15 | ## Variantes | 17 | ## Variantes |
| 16 | 18 | ||
| 17 | - Backend seul : `make test-go` — tests unitaires de chaque package plus un test de bout en bout qui compile l'agent mock, le lance comme vrai sous-processus et pilote un vrai client WebSocket sur un tour complet. | 19 | - Backend seul : `make test-go` — tests unitaires de chaque package plus un test de bout en bout qui compile l'agent mock, le lance comme vrai sous-processus et pilote un vrai client WebSocket sur un tour complet. |
modified
docs/fr/how-to/run-with-claude-code.md +2 -2 | @@ -4,7 +4,7 @@ Ce guide montre comment démarrer Ori connecté à Claude Code. Il suppose que v | ||
| 4 | 4 | |
| 5 | 5 | ## Étapes |
| 6 | 6 | |
| 7 | -1. Vérifiez que Node.js et npm sont disponibles : le backend lance l'adaptateur ACP officiel de Claude Code avec `npx -y @zed-industries/claude-code-acp`. | |
| 7 | +1. Vérifiez que Node.js et npm sont disponibles : le backend lance l'adaptateur ACP du Claude Agent SDK avec `npx -y @agentclientprotocol/claude-agent-acp`. L'adaptateur embarque sa propre CLI Claude Code (un paquet natif choisi pour votre plateforme) : il fonctionne même si la commande `claude` de votre machine est plus ancienne. | |
| 8 | 8 | 2. Vérifiez que Claude Code est authentifié sur cette machine (procédure de connexion de `claude`, ou une variable d'environnement `ANTHROPIC_API_KEY` utilisable par l'adaptateur). |
| 9 | 9 | 3. Depuis la racine du dépôt, démarrez le serveur : |
| 10 | 10 | |
| @@ -18,7 +18,7 @@ Ce guide montre comment démarrer Ori connecté à Claude Code. Il suppose que v | ||
| 18 | 18 | |
| 19 | 19 | - Pour travailler sur un répertoire de projet précis, passez explicitement le répertoire de travail de l'agent : `./bin/ori --cwd /chemin/vers/votre/projet`. |
| 20 | 20 | - Pour servir sur un autre port : `./bin/ori --addr :9000`. |
| 21 | -- Le premier `npx` télécharge le paquet de l'adaptateur ; figez-le en l'installant globalement (`npm install -g @zed-industries/claude-code-acp`) et en passant `--agent-cmd "claude-code-acp"`. | |
| 21 | +- Le premier `npx` télécharge le paquet de l'adaptateur ; figez-le en l'installant globalement (`npm install -g @agentclientprotocol/claude-agent-acp`) et en passant `--agent-cmd "claude-agent-acp"`. | |
| 22 | 22 | |
| 23 | 23 | ## Voir aussi |
| 24 | 24 | |
| @@ -4,7 +4,7 @@ Ce guide montre comment démarrer Ori connecté à Claude Code. Il suppose que v | |||
| 4 | 4 | ||
| 5 | ## Étapes | 5 | ## Étapes |
| 6 | 6 | ||
| 7 | -1. Vérifiez que Node.js et npm sont disponibles : le backend lance l'adaptateur ACP officiel de Claude Code avec `npx -y @zed-industries/claude-code-acp`. | 7 | +1. Vérifiez que Node.js et npm sont disponibles : le backend lance l'adaptateur ACP du Claude Agent SDK avec `npx -y @agentclientprotocol/claude-agent-acp`. L'adaptateur embarque sa propre CLI Claude Code (un paquet natif choisi pour votre plateforme) : il fonctionne même si la commande `claude` de votre machine est plus ancienne. |
| 8 | 2. Vérifiez que Claude Code est authentifié sur cette machine (procédure de connexion de `claude`, ou une variable d'environnement `ANTHROPIC_API_KEY` utilisable par l'adaptateur). | 8 | 2. Vérifiez que Claude Code est authentifié sur cette machine (procédure de connexion de `claude`, ou une variable d'environnement `ANTHROPIC_API_KEY` utilisable par l'adaptateur). |
| 9 | 3. Depuis la racine du dépôt, démarrez le serveur : | 9 | 3. Depuis la racine du dépôt, démarrez le serveur : |
| 10 | 10 | ||
| @@ -18,7 +18,7 @@ Ce guide montre comment démarrer Ori connecté à Claude Code. Il suppose que v | |||
| 18 | 18 | ||
| 19 | - Pour travailler sur un répertoire de projet précis, passez explicitement le répertoire de travail de l'agent : `./bin/ori --cwd /chemin/vers/votre/projet`. | 19 | - Pour travailler sur un répertoire de projet précis, passez explicitement le répertoire de travail de l'agent : `./bin/ori --cwd /chemin/vers/votre/projet`. |
| 20 | - Pour servir sur un autre port : `./bin/ori --addr :9000`. | 20 | - Pour servir sur un autre port : `./bin/ori --addr :9000`. |
| 21 | -- Le premier `npx` télécharge le paquet de l'adaptateur ; figez-le en l'installant globalement (`npm install -g @zed-industries/claude-code-acp`) et en passant `--agent-cmd "claude-code-acp"`. | 21 | +- Le premier `npx` télécharge le paquet de l'adaptateur ; figez-le en l'installant globalement (`npm install -g @agentclientprotocol/claude-agent-acp`) et en passant `--agent-cmd "claude-agent-acp"`. |
| 22 | 22 | ||
| 23 | ## Voir aussi | 23 | ## Voir aussi |
| 24 | 24 | ||
modified
docs/fr/reference/cli.md +1 -1 | @@ -16,7 +16,7 @@ Au démarrage, `ori` lance la commande de l'agent, effectue la poignée de main | ||
| 16 | 16 | | --- | --- | --- | --- | |
| 17 | 17 | | `--addr` | chaîne | `:8888` | Adresse TCP d'écoute du serveur HTTP. Un hôte vide écoute sur toutes les interfaces. | |
| 18 | 18 | | `--cwd` | chaîne | répertoire courant | Répertoire de travail transmis à la session de l'agent. Doit exister et être un répertoire ; résolu en chemin absolu. | |
| 19 | -| `--agent-cmd` | chaîne | `npx -y @zed-industries/claude-code-acp` | Commande lançant l'agent ACP, découpée sur les espaces (premier champ : exécutable ; le reste : arguments). | | |
| 19 | +| `--agent-cmd` | chaîne | `npx -y @agentclientprotocol/claude-agent-acp` | Commande lançant l'agent ACP, découpée sur les espaces (premier champ : exécutable ; le reste : arguments). | | |
| 20 | 20 | |
| 21 | 21 | ## Endpoints HTTP |
| 22 | 22 | |
| @@ -16,7 +16,7 @@ Au démarrage, `ori` lance la commande de l'agent, effectue la poignée de main | |||
| 16 | | --- | --- | --- | --- | | 16 | | --- | --- | --- | --- | |
| 17 | | `--addr` | chaîne | `:8888` | Adresse TCP d'écoute du serveur HTTP. Un hôte vide écoute sur toutes les interfaces. | | 17 | | `--addr` | chaîne | `:8888` | Adresse TCP d'écoute du serveur HTTP. Un hôte vide écoute sur toutes les interfaces. | |
| 18 | | `--cwd` | chaîne | répertoire courant | Répertoire de travail transmis à la session de l'agent. Doit exister et être un répertoire ; résolu en chemin absolu. | | 18 | | `--cwd` | chaîne | répertoire courant | Répertoire de travail transmis à la session de l'agent. Doit exister et être un répertoire ; résolu en chemin absolu. | |
| 19 | -| `--agent-cmd` | chaîne | `npx -y @zed-industries/claude-code-acp` | Commande lançant l'agent ACP, découpée sur les espaces (premier champ : exécutable ; le reste : arguments). | | 19 | +| `--agent-cmd` | chaîne | `npx -y @agentclientprotocol/claude-agent-acp` | Commande lançant l'agent ACP, découpée sur les espaces (premier champ : exécutable ; le reste : arguments). | |
| 20 | 20 | ||
| 21 | ## Endpoints HTTP | 21 | ## Endpoints HTTP |
| 22 | 22 | ||
modified
docs/source-code-analysis.adoc +6 -5 | @@ -9,7 +9,7 @@ | ||
| 9 | 9 | |
| 10 | 10 | Ori is a web client for https://agentclientprotocol.com[ACP (Agent Client Protocol)] code agents. |
| 11 | 11 | A Go backend serves an embedded React SPA and connects over ACP (JSON-RPC on stdio) to an agent |
| 12 | -subprocess — Claude Code via the Zed adapter (`npx -y @zed-industries/claude-code-acp`) by default. | |
| 12 | +subprocess — Claude Code via the Claude Agent SDK ACP adapter (`npx -y @agentclientprotocol/claude-agent-acp`) by default. | |
| 13 | 13 | The browser gets a Zed-style agent panel: streamed markdown answers, collapsible thoughts (live |
| 14 | 14 | during streaming, collapsible when complete), working spinner with rotating phrases, tool call |
| 15 | 15 | cards (status, locations, diffs), the agent's plan, and permission prompts answered from the UI — |
| @@ -208,9 +208,10 @@ Reference: `internal/bridge/protocol.go`, `ui/src/protocol.ts`, and | ||
| 208 | 208 | turn is rejected. Multi-session is a planned evolution behind the `bridge.Prompter` |
| 209 | 209 | seam. |
| 210 | 210 | * File API access is deliberately unrestricted: ori targets already-isolated sandboxes. |
| 211 | -* Claude Code is reached through the Zed adapter (`@zed-industries/claude-code-acp`, | |
| 212 | - note: renamed upstream to `@agentclientprotocol/claude-agent-acp` but default not yet | |
| 213 | - updated) — the `claude` CLI has no native ACP mode. | |
| 211 | +* Claude Code is reached through the Agent Client Protocol adapter (`@agentclientprotocol/claude-agent-acp`, | |
| 212 | + which bundles its own Claude Code CLI via the Claude Agent SDK; default since 2026-09-18, | |
| 213 | + replacing Zed's `@zed-industries/claude-code-acp` whose embedded CLI 2.1.44 the API now | |
| 214 | + rejects) — the `claude` CLI has no native ACP mode. | |
| 214 | 215 | * Material icons are copied from `vscode-material-icons` package to `public/` via an npm |
| 215 | 216 | pre-hook script, making them static assets bundled with the SPA. |
| 216 | 217 | * AsciiDoc rendering uses `@asciidoctor/core` v4's async `convert` named export (v3's |
| @@ -233,7 +234,7 @@ Reference: `internal/bridge/protocol.go`, `ui/src/protocol.ts`, and | ||
| 233 | 234 | Ori ships as a Docker Sandbox template (`template/Dockerfile`, FROM |
| 234 | 235 | `docker/sandbox-templates:claude-code`) paired with a kit (`kits/ori/`): |
| 235 | 236 | |
| 236 | -* Create: `sbx run -d claude <project> --template k33g/ori:0.0.0 --kit <ori-repo>/kits/ori --name ori -p 8888:8888` | |
| 237 | +* Create: `sbx run -d claude <project> --template k33g/ori:0.0.2 --kit <ori-repo>/kits/ori --name ori -p 8888:8888/tcp` | |
| 237 | 238 | * The `--detached` (`-d`) flag is **required**: sandboxd auto-stops a sandbox 30 seconds |
| 238 | 239 | after its last CLI sentinel session closes; without `-d`, the container stops shortly after |
| 239 | 240 | the prompt returns. Browser traffic on a published port does not hold the sandbox up. |
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | Ori is a web client for https://agentclientprotocol.com[ACP (Agent Client Protocol)] code agents. | 10 | Ori is a web client for https://agentclientprotocol.com[ACP (Agent Client Protocol)] code agents. |
| 11 | A Go backend serves an embedded React SPA and connects over ACP (JSON-RPC on stdio) to an agent | 11 | A Go backend serves an embedded React SPA and connects over ACP (JSON-RPC on stdio) to an agent |
| 12 | -subprocess — Claude Code via the Zed adapter (`npx -y @zed-industries/claude-code-acp`) by default. | 12 | +subprocess — Claude Code via the Claude Agent SDK ACP adapter (`npx -y @agentclientprotocol/claude-agent-acp`) by default. |
| 13 | The browser gets a Zed-style agent panel: streamed markdown answers, collapsible thoughts (live | 13 | The browser gets a Zed-style agent panel: streamed markdown answers, collapsible thoughts (live |
| 14 | during streaming, collapsible when complete), working spinner with rotating phrases, tool call | 14 | during streaming, collapsible when complete), working spinner with rotating phrases, tool call |
| 15 | cards (status, locations, diffs), the agent's plan, and permission prompts answered from the UI — | 15 | cards (status, locations, diffs), the agent's plan, and permission prompts answered from the UI — |
| @@ -208,9 +208,10 @@ Reference: `internal/bridge/protocol.go`, `ui/src/protocol.ts`, and | |||
| 208 | turn is rejected. Multi-session is a planned evolution behind the `bridge.Prompter` | 208 | turn is rejected. Multi-session is a planned evolution behind the `bridge.Prompter` |
| 209 | seam. | 209 | seam. |
| 210 | * File API access is deliberately unrestricted: ori targets already-isolated sandboxes. | 210 | * File API access is deliberately unrestricted: ori targets already-isolated sandboxes. |
| 211 | -* Claude Code is reached through the Zed adapter (`@zed-industries/claude-code-acp`, | 211 | +* Claude Code is reached through the Agent Client Protocol adapter (`@agentclientprotocol/claude-agent-acp`, |
| 212 | - note: renamed upstream to `@agentclientprotocol/claude-agent-acp` but default not yet | 212 | + which bundles its own Claude Code CLI via the Claude Agent SDK; default since 2026-09-18, |
| 213 | - updated) — the `claude` CLI has no native ACP mode. | 213 | + replacing Zed's `@zed-industries/claude-code-acp` whose embedded CLI 2.1.44 the API now |
| 214 | + rejects) — the `claude` CLI has no native ACP mode. | ||
| 214 | * Material icons are copied from `vscode-material-icons` package to `public/` via an npm | 215 | * Material icons are copied from `vscode-material-icons` package to `public/` via an npm |
| 215 | pre-hook script, making them static assets bundled with the SPA. | 216 | pre-hook script, making them static assets bundled with the SPA. |
| 216 | * AsciiDoc rendering uses `@asciidoctor/core` v4's async `convert` named export (v3's | 217 | * AsciiDoc rendering uses `@asciidoctor/core` v4's async `convert` named export (v3's |
| @@ -233,7 +234,7 @@ Reference: `internal/bridge/protocol.go`, `ui/src/protocol.ts`, and | |||
| 233 | Ori ships as a Docker Sandbox template (`template/Dockerfile`, FROM | 234 | Ori ships as a Docker Sandbox template (`template/Dockerfile`, FROM |
| 234 | `docker/sandbox-templates:claude-code`) paired with a kit (`kits/ori/`): | 235 | `docker/sandbox-templates:claude-code`) paired with a kit (`kits/ori/`): |
| 235 | 236 | ||
| 236 | -* Create: `sbx run -d claude <project> --template k33g/ori:0.0.0 --kit <ori-repo>/kits/ori --name ori -p 8888:8888` | 237 | +* Create: `sbx run -d claude <project> --template k33g/ori:0.0.2 --kit <ori-repo>/kits/ori --name ori -p 8888:8888/tcp` |
| 237 | * The `--detached` (`-d`) flag is **required**: sandboxd auto-stops a sandbox 30 seconds | 238 | * The `--detached` (`-d`) flag is **required**: sandboxd auto-stops a sandbox 30 seconds |
| 238 | after its last CLI sentinel session closes; without `-d`, the container stops shortly after | 239 | after its last CLI sentinel session closes; without `-d`, the container stops shortly after |
| 239 | the prompt returns. Browser traffic on a published port does not hold the sandbox up. | 240 | the prompt returns. Browser traffic on a published port does not hold the sandbox up. |
modified
internal/agent/agent.go +1 -1 | @@ -145,7 +145,7 @@ func Connect(ctx context.Context, in io.Writer, out io.Reader, opts Options) (*S | ||
| 145 | 145 | // Example: |
| 146 | 146 | // |
| 147 | 147 | // session, err := agent.Start(ctx, agent.Options{ |
| 148 | -// Command: []string{"npx", "-y", "@zed-industries/claude-code-acp"}, | |
| 148 | +// Command: []string{"npx", "-y", "@agentclientprotocol/claude-agent-acp"}, | |
| 149 | 149 | // Cwd: "/work/my-project", |
| 150 | 150 | // Handler: myHandler, |
| 151 | 151 | // }) |
| @@ -145,7 +145,7 @@ func Connect(ctx context.Context, in io.Writer, out io.Reader, opts Options) (*S | |||
| 145 | // Example: | 145 | // Example: |
| 146 | // | 146 | // |
| 147 | // session, err := agent.Start(ctx, agent.Options{ | 147 | // session, err := agent.Start(ctx, agent.Options{ |
| 148 | -// Command: []string{"npx", "-y", "@zed-industries/claude-code-acp"}, | 148 | +// Command: []string{"npx", "-y", "@agentclientprotocol/claude-agent-acp"}, |
| 149 | // Cwd: "/work/my-project", | 149 | // Cwd: "/work/my-project", |
| 150 | // Handler: myHandler, | 150 | // Handler: myHandler, |
| 151 | // }) | 151 | // }) |
modified
internal/config/config.go +4 -2 | @@ -13,8 +13,10 @@ import ( | ||
| 13 | 13 | ) |
| 14 | 14 | |
| 15 | 15 | // DefaultAgentCommand is the ACP agent spawned when --agent-cmd is not given. |
| 16 | -// It is the official Claude Code ACP adapter, the same one Zed uses. | |
| 17 | -const DefaultAgentCommand = "npx -y @zed-industries/claude-code-acp" | |
| 16 | +// It is the Agent Client Protocol project's adapter for the Claude Agent SDK, | |
| 17 | +// which bundles a current Claude Code CLI (the older Zed adapter ships a CLI | |
| 18 | +// too old for current models). | |
| 19 | +const DefaultAgentCommand = "npx -y @agentclientprotocol/claude-agent-acp" | |
| 18 | 20 | |
| 19 | 21 | // Config holds the runtime configuration of the ori server. |
| 20 | 22 | type Config struct { |
| @@ -13,8 +13,10 @@ import ( | |||
| 13 | ) | 13 | ) |
| 14 | 14 | ||
| 15 | // DefaultAgentCommand is the ACP agent spawned when --agent-cmd is not given. | 15 | // DefaultAgentCommand is the ACP agent spawned when --agent-cmd is not given. |
| 16 | -// It is the official Claude Code ACP adapter, the same one Zed uses. | 16 | +// It is the Agent Client Protocol project's adapter for the Claude Agent SDK, |
| 17 | -const DefaultAgentCommand = "npx -y @zed-industries/claude-code-acp" | 17 | +// which bundles a current Claude Code CLI (the older Zed adapter ships a CLI |
| 18 | +// too old for current models). | ||
| 19 | +const DefaultAgentCommand = "npx -y @agentclientprotocol/claude-agent-acp" | ||
| 18 | 20 | ||
| 19 | // Config holds the runtime configuration of the ori server. | 21 | // Config holds the runtime configuration of the ori server. |
| 20 | type Config struct { | 22 | type Config struct { |
modified
internal/config/config_test.go +15 -0 | @@ -81,3 +81,18 @@ func ExampleFromArgs() { | ||
| 81 | 81 | fmt.Println(cfg.Addr) |
| 82 | 82 | // Output: :9000 |
| 83 | 83 | } |
| 84 | + | |
| 85 | +// TestDefaultAgentCommandIsClaudeAgentACP pins the adapter ori spawns by default. | |
| 86 | +// The Zed adapter (@zed-industries/claude-code-acp) bundles a Claude Code CLI | |
| 87 | +// too old for current models (2.1.44 < 2.1.251 required); the Agent Client | |
| 88 | +// Protocol adapter ships a current CLI through its SDK. A change here must be | |
| 89 | +// deliberate and mirrored in template/Dockerfile and kits/ori/spec.yaml. | |
| 90 | +func TestDefaultAgentCommandIsClaudeAgentACP(t *testing.T) { | |
| 91 | + const want = "npx -y @agentclientprotocol/claude-agent-acp" | |
| 92 | + if config.DefaultAgentCommand != want { | |
| 93 | + t.Errorf("DefaultAgentCommand = %q, want %q", config.DefaultAgentCommand, want) | |
| 94 | + } | |
| 95 | + if strings.Contains(config.DefaultAgentCommand, "zed-industries") { | |
| 96 | + t.Errorf("DefaultAgentCommand still points at the Zed adapter: %q", config.DefaultAgentCommand) | |
| 97 | + } | |
| 98 | +} | |
| @@ -81,3 +81,18 @@ func ExampleFromArgs() { | |||
| 81 | fmt.Println(cfg.Addr) | 81 | fmt.Println(cfg.Addr) |
| 82 | // Output: :9000 | 82 | // Output: :9000 |
| 83 | } | 83 | } |
| 84 | + | ||
| 85 | +// TestDefaultAgentCommandIsClaudeAgentACP pins the adapter ori spawns by default. | ||
| 86 | +// The Zed adapter (@zed-industries/claude-code-acp) bundles a Claude Code CLI | ||
| 87 | +// too old for current models (2.1.44 < 2.1.251 required); the Agent Client | ||
| 88 | +// Protocol adapter ships a current CLI through its SDK. A change here must be | ||
| 89 | +// deliberate and mirrored in template/Dockerfile and kits/ori/spec.yaml. | ||
| 90 | +func TestDefaultAgentCommandIsClaudeAgentACP(t *testing.T) { | ||
| 91 | + const want = "npx -y @agentclientprotocol/claude-agent-acp" | ||
| 92 | + if config.DefaultAgentCommand != want { | ||
| 93 | + t.Errorf("DefaultAgentCommand = %q, want %q", config.DefaultAgentCommand, want) | ||
| 94 | + } | ||
| 95 | + if strings.Contains(config.DefaultAgentCommand, "zed-industries") { | ||
| 96 | + t.Errorf("DefaultAgentCommand still points at the Zed adapter: %q", config.DefaultAgentCommand) | ||
| 97 | + } | ||
| 98 | +} | ||
modified
internal/files/raw.go +16 -2 | @@ -23,18 +23,32 @@ var imageTypes = map[string]string{ | ||
| 23 | 23 | ".webp": "image/webp", |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | +// textTypes pins the text formats the preview pane renders itself, for the | |
| 27 | +// same reason as imageTypes: Go seeds its mime table from the host (macOS's | |
| 28 | +// /etc/apache2/mime.types leaves text/markdown commented out), so without a | |
| 29 | +// pin a .md file is served as text/plain on one machine and text/markdown on | |
| 30 | +// another. | |
| 31 | +var textTypes = map[string]string{ | |
| 32 | + ".markdown": "text/markdown; charset=utf-8", | |
| 33 | + ".md": "text/markdown; charset=utf-8", | |
| 34 | +} | |
| 35 | + | |
| 26 | 36 | // ContentTypeFor returns the Content-Type the raw endpoint serves a file |
| 27 | -// under: pinned image types first, then the host mime database, and a | |
| 28 | -// content sniff of the first bytes as a last resort. | |
| 37 | +// under: pinned image and text types first, then the host mime database, and | |
| 38 | +// a content sniff of the first bytes as a last resort. | |
| 29 | 39 | // |
| 30 | 40 | // Example: |
| 31 | 41 | // |
| 32 | 42 | // files.ContentTypeFor("logo.webp", nil) // "image/webp" |
| 43 | +// files.ContentTypeFor("README.md", nil) // "text/markdown; charset=utf-8" | |
| 33 | 44 | func ContentTypeFor(path string, head []byte) string { |
| 34 | 45 | ext := strings.ToLower(filepath.Ext(path)) |
| 35 | 46 | if typ, ok := imageTypes[ext]; ok { |
| 36 | 47 | return typ |
| 37 | 48 | } |
| 49 | + if typ, ok := textTypes[ext]; ok { | |
| 50 | + return typ | |
| 51 | + } | |
| 38 | 52 | if typ := mime.TypeByExtension(ext); typ != "" { |
| 39 | 53 | return typ |
| 40 | 54 | } |
| @@ -23,18 +23,32 @@ var imageTypes = map[string]string{ | |||
| 23 | ".webp": "image/webp", | 23 | ".webp": "image/webp", |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | +// textTypes pins the text formats the preview pane renders itself, for the | ||
| 27 | +// same reason as imageTypes: Go seeds its mime table from the host (macOS's | ||
| 28 | +// /etc/apache2/mime.types leaves text/markdown commented out), so without a | ||
| 29 | +// pin a .md file is served as text/plain on one machine and text/markdown on | ||
| 30 | +// another. | ||
| 31 | +var textTypes = map[string]string{ | ||
| 32 | + ".markdown": "text/markdown; charset=utf-8", | ||
| 33 | + ".md": "text/markdown; charset=utf-8", | ||
| 34 | +} | ||
| 35 | + | ||
| 26 | // ContentTypeFor returns the Content-Type the raw endpoint serves a file | 36 | // ContentTypeFor returns the Content-Type the raw endpoint serves a file |
| 27 | -// under: pinned image types first, then the host mime database, and a | 37 | +// under: pinned image and text types first, then the host mime database, and |
| 28 | -// content sniff of the first bytes as a last resort. | 38 | +// a content sniff of the first bytes as a last resort. |
| 29 | // | 39 | // |
| 30 | // Example: | 40 | // Example: |
| 31 | // | 41 | // |
| 32 | // files.ContentTypeFor("logo.webp", nil) // "image/webp" | 42 | // files.ContentTypeFor("logo.webp", nil) // "image/webp" |
| 43 | +// files.ContentTypeFor("README.md", nil) // "text/markdown; charset=utf-8" | ||
| 33 | func ContentTypeFor(path string, head []byte) string { | 44 | func ContentTypeFor(path string, head []byte) string { |
| 34 | ext := strings.ToLower(filepath.Ext(path)) | 45 | ext := strings.ToLower(filepath.Ext(path)) |
| 35 | if typ, ok := imageTypes[ext]; ok { | 46 | if typ, ok := imageTypes[ext]; ok { |
| 36 | return typ | 47 | return typ |
| 37 | } | 48 | } |
| 49 | + if typ, ok := textTypes[ext]; ok { | ||
| 50 | + return typ | ||
| 51 | + } | ||
| 38 | if typ := mime.TypeByExtension(ext); typ != "" { | 52 | if typ := mime.TypeByExtension(ext); typ != "" { |
| 39 | return typ | 53 | return typ |
| 40 | } | 54 | } |
modified
internal/files/raw_test.go +2 -0 | @@ -77,6 +77,8 @@ func TestContentTypeFor(t *testing.T) { | ||
| 77 | 77 | {"a.ico", nil, "image/x-icon"}, |
| 78 | 78 | {"a.avif", nil, "image/avif"}, |
| 79 | 79 | {"a.json", nil, "application/json"}, |
| 80 | + {"README.md", nil, "text/markdown; charset=utf-8"}, | |
| 81 | + {"NOTES.MARKDOWN", nil, "text/markdown; charset=utf-8"}, | |
| 80 | 82 | {"noext", []byte("plain words"), "text/plain; charset=utf-8"}, |
| 81 | 83 | } |
| 82 | 84 | for _, tc := range cases { |
| @@ -77,6 +77,8 @@ func TestContentTypeFor(t *testing.T) { | |||
| 77 | {"a.ico", nil, "image/x-icon"}, | 77 | {"a.ico", nil, "image/x-icon"}, |
| 78 | {"a.avif", nil, "image/avif"}, | 78 | {"a.avif", nil, "image/avif"}, |
| 79 | {"a.json", nil, "application/json"}, | 79 | {"a.json", nil, "application/json"}, |
| 80 | + {"README.md", nil, "text/markdown; charset=utf-8"}, | ||
| 81 | + {"NOTES.MARKDOWN", nil, "text/markdown; charset=utf-8"}, | ||
| 80 | {"noext", []byte("plain words"), "text/plain; charset=utf-8"}, | 82 | {"noext", []byte("plain words"), "text/plain; charset=utf-8"}, |
| 81 | } | 83 | } |
| 82 | for _, tc := range cases { | 84 | for _, tc := range cases { |
modified
kits/ori/README.md +8 -8 | @@ -4,14 +4,14 @@ A Docker Sandboxes **mixin kit** that starts the [ori](../../README.md) web serv | ||
| 4 | 4 | |
| 5 | 5 | ## 1. Get the template image |
| 6 | 6 | |
| 7 | -It is published on Docker Hub as `k33g/ori:0.0.0`. To (re)build and push it yourself from the ori repository root: | |
| 7 | +It is published on Docker Hub as `k33g/ori:0.0.2`. To (re)build and push it yourself from the ori repository root: | |
| 8 | 8 | |
| 9 | 9 | ```bash |
| 10 | -./template/build.sh # multi-arch build, pushes k33g/ori:0.0.0 and :latest | |
| 10 | +./template/build.sh # multi-arch build, pushes k33g/ori:0.0.2 and :latest | |
| 11 | 11 | # local-only alternative: make template (= docker build -t k33g/ori .) |
| 12 | 12 | ``` |
| 13 | 13 | |
| 14 | -The image stacks ori (server, SPA and demo agent) and the `claude-code-acp` adapter on top of the official `docker/sandbox-templates:claude-code` template, so everything the claude sandbox normally provides is still there. | |
| 14 | +The image stacks ori (server, SPA and demo agent) and the `claude-agent-acp` adapter on top of the official `docker/sandbox-templates:claude-code` template, so everything the claude sandbox normally provides is still there. | |
| 15 | 15 | |
| 16 | 16 | If the image only exists on your host engine (never pushed to Docker Hub), hand it to the sandbox runtime's own image store: |
| 17 | 17 | |
| @@ -25,15 +25,15 @@ sbx template ls | ||
| 25 | 25 | |
| 26 | 26 | ```bash |
| 27 | 27 | sbx run -d claude ~/path/to/your/project \ |
| 28 | - --template k33g/ori:0.0.0 \ | |
| 28 | + --template k33g/ori:0.0.2 \ | |
| 29 | 29 | --kit /path/to/ori/kits/ori |
| 30 | 30 | ``` |
| 31 | 31 | |
| 32 | 32 | Use `sbx run -d` (`--detached`), **not** `sbx create`: sbx auto-stops a sandbox 30 s after its last CLI session closes, and a web server has no CLI session to hold it up. A detached sandbox is exempt from that auto-stop for its whole life; the mode is fixed at creation, so a sandbox made with `sbx create` has to be `sbx rm`'d and recreated. |
| 33 | 33 | |
| 34 | -`--template` swaps the sandbox image for `k33g/ori:0.0.0`; `--kit` applies this mixin, whose startup command launches the ori server at every container start. The claude agent kit still handles Anthropic credentials, so the server's agent works without any login inside the sandbox. | |
| 34 | +`--template` swaps the sandbox image for `k33g/ori:0.0.2`; `--kit` applies this mixin, whose startup command launches the ori server at every container start. The claude agent kit still handles Anthropic credentials, so the server's agent works without any login inside the sandbox. | |
| 35 | 35 | |
| 36 | -The listen port defaults to **8888** and is a kit argument: add `--kit-arg ori.port=9000` (or `--kit-arg port=9000`) to change it. | |
| 36 | +The listen port defaults to **8888** and is a kit argument: add `--kit-arg ori.port=9000` (or `--kit-arg port=9000`) to change it. The port the kit *declares* for auto-publishing stays 8888 (an sbx packaging limitation, see the comment in `spec.yaml`), so with a custom port publish it yourself: `-p 9000:9000`. | |
| 37 | 37 | |
| 38 | 38 | ## 3. Open the UI |
| 39 | 39 | |
| @@ -46,7 +46,7 @@ The kit declares port 8888, so the creation auto-publishes an ephemeral localhos | ||
| 46 | 46 | Browse to that address, or pin a fixed host port instead: |
| 47 | 47 | |
| 48 | 48 | ```bash |
| 49 | -sbx run -d claude … -p 8888:8888 # at creation | |
| 49 | +sbx run -d claude … -p 8888:8888/tcp # at creation | |
| 50 | 50 | sbx ports <sandbox-name> --publish 8888:8888/tcp # afterwards |
| 51 | 51 | ``` |
| 52 | 52 | |
| @@ -54,4 +54,4 @@ sbx ports <sandbox-name> --publish 8888:8888/tcp # afterwards | ||
| 54 | 54 | |
| 55 | 55 | - Server log inside the sandbox: `/home/agent/.ori.log`. |
| 56 | 56 | - To try the UI without consuming Claude usage, restart the server with the bundled demo agent: `pkill -x ori; nohup ori --addr :8888 --agent-cmd ori-mock-agent --cwd "$PWD" >> /home/agent/.ori.log 2>&1 &`. |
| 57 | -- The image also runs standalone, outside sbx: `docker run --rm -p 8888:8888 k33g/ori` (bring your own `ANTHROPIC_API_KEY`, or switch to `ori-mock-agent`). | |
| 57 | +- The image also runs standalone, outside sbx: `docker run --rm -p 8888:8888/tcp k33g/ori` (bring your own `ANTHROPIC_API_KEY`, or switch to `ori-mock-agent`). | |
| @@ -4,14 +4,14 @@ A Docker Sandboxes **mixin kit** that starts the [ori](../../README.md) web serv | |||
| 4 | 4 | ||
| 5 | ## 1. Get the template image | 5 | ## 1. Get the template image |
| 6 | 6 | ||
| 7 | -It is published on Docker Hub as `k33g/ori:0.0.0`. To (re)build and push it yourself from the ori repository root: | 7 | +It is published on Docker Hub as `k33g/ori:0.0.2`. To (re)build and push it yourself from the ori repository root: |
| 8 | 8 | ||
| 9 | ```bash | 9 | ```bash |
| 10 | -./template/build.sh # multi-arch build, pushes k33g/ori:0.0.0 and :latest | 10 | +./template/build.sh # multi-arch build, pushes k33g/ori:0.0.2 and :latest |
| 11 | # local-only alternative: make template (= docker build -t k33g/ori .) | 11 | # local-only alternative: make template (= docker build -t k33g/ori .) |
| 12 | ``` | 12 | ``` |
| 13 | 13 | ||
| 14 | -The image stacks ori (server, SPA and demo agent) and the `claude-code-acp` adapter on top of the official `docker/sandbox-templates:claude-code` template, so everything the claude sandbox normally provides is still there. | 14 | +The image stacks ori (server, SPA and demo agent) and the `claude-agent-acp` adapter on top of the official `docker/sandbox-templates:claude-code` template, so everything the claude sandbox normally provides is still there. |
| 15 | 15 | ||
| 16 | If the image only exists on your host engine (never pushed to Docker Hub), hand it to the sandbox runtime's own image store: | 16 | If the image only exists on your host engine (never pushed to Docker Hub), hand it to the sandbox runtime's own image store: |
| 17 | 17 | ||
| @@ -25,15 +25,15 @@ sbx template ls | |||
| 25 | 25 | ||
| 26 | ```bash | 26 | ```bash |
| 27 | sbx run -d claude ~/path/to/your/project \ | 27 | sbx run -d claude ~/path/to/your/project \ |
| 28 | - --template k33g/ori:0.0.0 \ | 28 | + --template k33g/ori:0.0.2 \ |
| 29 | --kit /path/to/ori/kits/ori | 29 | --kit /path/to/ori/kits/ori |
| 30 | ``` | 30 | ``` |
| 31 | 31 | ||
| 32 | Use `sbx run -d` (`--detached`), **not** `sbx create`: sbx auto-stops a sandbox 30 s after its last CLI session closes, and a web server has no CLI session to hold it up. A detached sandbox is exempt from that auto-stop for its whole life; the mode is fixed at creation, so a sandbox made with `sbx create` has to be `sbx rm`'d and recreated. | 32 | Use `sbx run -d` (`--detached`), **not** `sbx create`: sbx auto-stops a sandbox 30 s after its last CLI session closes, and a web server has no CLI session to hold it up. A detached sandbox is exempt from that auto-stop for its whole life; the mode is fixed at creation, so a sandbox made with `sbx create` has to be `sbx rm`'d and recreated. |
| 33 | 33 | ||
| 34 | -`--template` swaps the sandbox image for `k33g/ori:0.0.0`; `--kit` applies this mixin, whose startup command launches the ori server at every container start. The claude agent kit still handles Anthropic credentials, so the server's agent works without any login inside the sandbox. | 34 | +`--template` swaps the sandbox image for `k33g/ori:0.0.2`; `--kit` applies this mixin, whose startup command launches the ori server at every container start. The claude agent kit still handles Anthropic credentials, so the server's agent works without any login inside the sandbox. |
| 35 | 35 | ||
| 36 | -The listen port defaults to **8888** and is a kit argument: add `--kit-arg ori.port=9000` (or `--kit-arg port=9000`) to change it. | 36 | +The listen port defaults to **8888** and is a kit argument: add `--kit-arg ori.port=9000` (or `--kit-arg port=9000`) to change it. The port the kit *declares* for auto-publishing stays 8888 (an sbx packaging limitation, see the comment in `spec.yaml`), so with a custom port publish it yourself: `-p 9000:9000`. |
| 37 | 37 | ||
| 38 | ## 3. Open the UI | 38 | ## 3. Open the UI |
| 39 | 39 | ||
| @@ -46,7 +46,7 @@ The kit declares port 8888, so the creation auto-publishes an ephemeral localhos | |||
| 46 | Browse to that address, or pin a fixed host port instead: | 46 | Browse to that address, or pin a fixed host port instead: |
| 47 | 47 | ||
| 48 | ```bash | 48 | ```bash |
| 49 | -sbx run -d claude … -p 8888:8888 # at creation | 49 | +sbx run -d claude … -p 8888:8888/tcp # at creation |
| 50 | sbx ports <sandbox-name> --publish 8888:8888/tcp # afterwards | 50 | sbx ports <sandbox-name> --publish 8888:8888/tcp # afterwards |
| 51 | ``` | 51 | ``` |
| 52 | 52 | ||
| @@ -54,4 +54,4 @@ sbx ports <sandbox-name> --publish 8888:8888/tcp # afterwards | |||
| 54 | 54 | ||
| 55 | - Server log inside the sandbox: `/home/agent/.ori.log`. | 55 | - Server log inside the sandbox: `/home/agent/.ori.log`. |
| 56 | - To try the UI without consuming Claude usage, restart the server with the bundled demo agent: `pkill -x ori; nohup ori --addr :8888 --agent-cmd ori-mock-agent --cwd "$PWD" >> /home/agent/.ori.log 2>&1 &`. | 56 | - To try the UI without consuming Claude usage, restart the server with the bundled demo agent: `pkill -x ori; nohup ori --addr :8888 --agent-cmd ori-mock-agent --cwd "$PWD" >> /home/agent/.ori.log 2>&1 &`. |
| 57 | -- The image also runs standalone, outside sbx: `docker run --rm -p 8888:8888 k33g/ori` (bring your own `ANTHROPIC_API_KEY`, or switch to `ori-mock-agent`). | 57 | +- The image also runs standalone, outside sbx: `docker run --rm -p 8888:8888/tcp k33g/ori` (bring your own `ANTHROPIC_API_KEY`, or switch to `ori-mock-agent`). |
modified
kits/ori/spec.yaml +14 -8 | @@ -10,12 +10,12 @@ description: > | ||
| 10 | 10 | Monaco preview/editor with rendered Markdown and AsciiDoc, interactive |
| 11 | 11 | terminal). This kit only launches and describes the server; the binaries |
| 12 | 12 | ship in the k33g/ori template image (template/Dockerfile in the ori |
| 13 | - repository), so use it together with `--template k33g/ori:0.0.1`. | |
| 13 | + repository), so use it together with `--template k33g/ori:0.0.2`. | |
| 14 | 14 | licenses: |
| 15 | 15 | - MIT |
| 16 | 16 | |
| 17 | 17 | # This mixin only makes sense composed with the claude agent kit: the server |
| 18 | -# it starts drives Claude Code through the claude-code-acp adapter, and the | |
| 18 | +# it starts drives Claude Code through the claude-agent-acp adapter, and the | |
| 19 | 19 | # Anthropic credentials/egress come from that kit. |
| 20 | 20 | requires: |
| 21 | 21 | agent: claude |
| @@ -33,9 +33,15 @@ args: | ||
| 33 | 33 | # Auto-publishes an ephemeral localhost port at create (the create output |
| 34 | 34 | # prints it: "Published web: localhost:<port> -> <port>/tcp"). Pin a fixed |
| 35 | 35 | # host port instead with `-p 8888:8888` at create or `sbx ports … --publish`. |
| 36 | -# The unquoted arg reference decodes as the integer the schema expects. | |
| 36 | +# | |
| 37 | +# Deliberately a literal, not `${{ kit.args.port }}`: `sbx kit pack` / `push` | |
| 38 | +# (v0.43) decode the raw spec.yaml into typed fields before any argument | |
| 39 | +# expansion, so a placeholder in this integer field fails with "cannot | |
| 40 | +# unmarshal !!str `${{ kit...` into int" — while validate / inspect / run, | |
| 41 | +# which expand first, accept it. If `port` is overridden, this auto-published | |
| 42 | +# port no longer matches the server: publish the real one with `-p`. | |
| 37 | 43 | ports: |
| 38 | - - container: ${{ kit.args.port }} | |
| 44 | + - container: 8888 | |
| 39 | 45 | protocol: tcp |
| 40 | 46 | name: web |
| 41 | 47 | |
| @@ -49,7 +55,7 @@ setup: | ||
| 49 | 55 | # |
| 50 | 56 | # The PATH export is load-bearing: the dispatcher runs this via |
| 51 | 57 | # `su -s /bin/sh -c … agent`, and su resets PATH to the login.defs |
| 52 | - # default — which does not contain the npm prefix where claude-code-acp | |
| 58 | + # default — which does not contain the npm prefix where claude-agent-acp | |
| 53 | 59 | # lives, nor ~/.local/bin where claude does. |
| 54 | 60 | - command: |
| 55 | 61 | - "sh" |
| @@ -59,7 +65,7 @@ setup: | ||
| 59 | 65 | pgrep -x ori >/dev/null 2>&1 && exit 0 |
| 60 | 66 | nohup /usr/local/bin/ori \ |
| 61 | 67 | --addr ":${{ kit.args.port }}" \ |
| 62 | - --agent-cmd claude-code-acp \ | |
| 68 | + --agent-cmd claude-agent-acp \ | |
| 63 | 69 | --cwd "${WORKSPACE_DIR:-/home/agent/workspace}" \ |
| 64 | 70 | >> /home/agent/.ori.log 2>&1 & |
| 65 | 71 | description: Start the ori web server (idempotent) |
| @@ -76,10 +82,10 @@ agentInstructions: | ||
| 76 | 82 | (a deterministic demo ACP agent that needs no credentials). |
| 77 | 83 | - Log file: `/home/agent/.ori.log`. |
| 78 | 84 | - The server drives its own Claude Code session through the |
| 79 | - `claude-code-acp` adapter (preinstalled); credentials are injected by the | |
| 85 | + `claude-agent-acp` adapter (preinstalled, ships Claude Code 2.1.274); credentials are injected by the | |
| 80 | 86 | sandbox proxy, so no login is needed inside the container. |
| 81 | 87 | - Restart it with: |
| 82 | - `pkill -x ori; nohup ori --addr ":${{ kit.args.port }}" --agent-cmd claude-code-acp --cwd "$PWD" >> /home/agent/.ori.log 2>&1 &` | |
| 88 | + `pkill -x ori; nohup ori --addr ":${{ kit.args.port }}" --agent-cmd claude-agent-acp --cwd "$PWD" >> /home/agent/.ori.log 2>&1 &` | |
| 83 | 89 | - To demo without consuming Claude usage, restart it with |
| 84 | 90 | `--agent-cmd ori-mock-agent` instead. |
| 85 | 91 | |
| @@ -10,12 +10,12 @@ description: > | |||
| 10 | Monaco preview/editor with rendered Markdown and AsciiDoc, interactive | 10 | Monaco preview/editor with rendered Markdown and AsciiDoc, interactive |
| 11 | terminal). This kit only launches and describes the server; the binaries | 11 | terminal). This kit only launches and describes the server; the binaries |
| 12 | ship in the k33g/ori template image (template/Dockerfile in the ori | 12 | ship in the k33g/ori template image (template/Dockerfile in the ori |
| 13 | - repository), so use it together with `--template k33g/ori:0.0.1`. | 13 | + repository), so use it together with `--template k33g/ori:0.0.2`. |
| 14 | licenses: | 14 | licenses: |
| 15 | - MIT | 15 | - MIT |
| 16 | 16 | ||
| 17 | # This mixin only makes sense composed with the claude agent kit: the server | 17 | # This mixin only makes sense composed with the claude agent kit: the server |
| 18 | -# it starts drives Claude Code through the claude-code-acp adapter, and the | 18 | +# it starts drives Claude Code through the claude-agent-acp adapter, and the |
| 19 | # Anthropic credentials/egress come from that kit. | 19 | # Anthropic credentials/egress come from that kit. |
| 20 | requires: | 20 | requires: |
| 21 | agent: claude | 21 | agent: claude |
| @@ -33,9 +33,15 @@ args: | |||
| 33 | # Auto-publishes an ephemeral localhost port at create (the create output | 33 | # Auto-publishes an ephemeral localhost port at create (the create output |
| 34 | # prints it: "Published web: localhost:<port> -> <port>/tcp"). Pin a fixed | 34 | # prints it: "Published web: localhost:<port> -> <port>/tcp"). Pin a fixed |
| 35 | # host port instead with `-p 8888:8888` at create or `sbx ports … --publish`. | 35 | # host port instead with `-p 8888:8888` at create or `sbx ports … --publish`. |
| 36 | -# The unquoted arg reference decodes as the integer the schema expects. | 36 | +# |
| 37 | +# Deliberately a literal, not `${{ kit.args.port }}`: `sbx kit pack` / `push` | ||
| 38 | +# (v0.43) decode the raw spec.yaml into typed fields before any argument | ||
| 39 | +# expansion, so a placeholder in this integer field fails with "cannot | ||
| 40 | +# unmarshal !!str `${{ kit...` into int" — while validate / inspect / run, | ||
| 41 | +# which expand first, accept it. If `port` is overridden, this auto-published | ||
| 42 | +# port no longer matches the server: publish the real one with `-p`. | ||
| 37 | ports: | 43 | ports: |
| 38 | - - container: ${{ kit.args.port }} | 44 | + - container: 8888 |
| 39 | protocol: tcp | 45 | protocol: tcp |
| 40 | name: web | 46 | name: web |
| 41 | 47 | ||
| @@ -49,7 +55,7 @@ setup: | |||
| 49 | # | 55 | # |
| 50 | # The PATH export is load-bearing: the dispatcher runs this via | 56 | # The PATH export is load-bearing: the dispatcher runs this via |
| 51 | # `su -s /bin/sh -c … agent`, and su resets PATH to the login.defs | 57 | # `su -s /bin/sh -c … agent`, and su resets PATH to the login.defs |
| 52 | - # default — which does not contain the npm prefix where claude-code-acp | 58 | + # default — which does not contain the npm prefix where claude-agent-acp |
| 53 | # lives, nor ~/.local/bin where claude does. | 59 | # lives, nor ~/.local/bin where claude does. |
| 54 | - command: | 60 | - command: |
| 55 | - "sh" | 61 | - "sh" |
| @@ -59,7 +65,7 @@ setup: | |||
| 59 | pgrep -x ori >/dev/null 2>&1 && exit 0 | 65 | pgrep -x ori >/dev/null 2>&1 && exit 0 |
| 60 | nohup /usr/local/bin/ori \ | 66 | nohup /usr/local/bin/ori \ |
| 61 | --addr ":${{ kit.args.port }}" \ | 67 | --addr ":${{ kit.args.port }}" \ |
| 62 | - --agent-cmd claude-code-acp \ | 68 | + --agent-cmd claude-agent-acp \ |
| 63 | --cwd "${WORKSPACE_DIR:-/home/agent/workspace}" \ | 69 | --cwd "${WORKSPACE_DIR:-/home/agent/workspace}" \ |
| 64 | >> /home/agent/.ori.log 2>&1 & | 70 | >> /home/agent/.ori.log 2>&1 & |
| 65 | description: Start the ori web server (idempotent) | 71 | description: Start the ori web server (idempotent) |
| @@ -76,10 +82,10 @@ agentInstructions: | |||
| 76 | (a deterministic demo ACP agent that needs no credentials). | 82 | (a deterministic demo ACP agent that needs no credentials). |
| 77 | - Log file: `/home/agent/.ori.log`. | 83 | - Log file: `/home/agent/.ori.log`. |
| 78 | - The server drives its own Claude Code session through the | 84 | - The server drives its own Claude Code session through the |
| 79 | - `claude-code-acp` adapter (preinstalled); credentials are injected by the | 85 | + `claude-agent-acp` adapter (preinstalled, ships Claude Code 2.1.274); credentials are injected by the |
| 80 | sandbox proxy, so no login is needed inside the container. | 86 | sandbox proxy, so no login is needed inside the container. |
| 81 | - Restart it with: | 87 | - Restart it with: |
| 82 | - `pkill -x ori; nohup ori --addr ":${{ kit.args.port }}" --agent-cmd claude-code-acp --cwd "$PWD" >> /home/agent/.ori.log 2>&1 &` | 88 | + `pkill -x ori; nohup ori --addr ":${{ kit.args.port }}" --agent-cmd claude-agent-acp --cwd "$PWD" >> /home/agent/.ori.log 2>&1 &` |
| 83 | - To demo without consuming Claude usage, restart it with | 89 | - To demo without consuming Claude usage, restart it with |
| 84 | `--agent-cmd ori-mock-agent` instead. | 90 | `--agent-cmd ori-mock-agent` instead. |
| 85 | 91 | ||
deleted
picard-story.md +0 -33 | deleted file mode 100644 | ||
| @@ -1,33 +0,0 @@ | ||
| 1 | -# The Archaeologist's Gambit | |
| 2 | - | |
| 3 | -**Agent: Bob** | |
| 4 | - | |
| 5 | -Captain Jean-Luc Picard stood before the ancient artifact, his fingers hovering millimeters above its surface. The crystalline structure pulsed with a faint amber glow, responding to his proximity like a living thing. | |
| 6 | - | |
| 7 | -"Captain, I must advise caution," Data said from behind him, his golden eyes scanning the tricorder readings. "The energy signature is unlike anything in our database." | |
| 8 | - | |
| 9 | -Picard's lips curved into a slight smile. "Mr. Data, in my experience, the most profound discoveries often lie beyond the boundaries of our databases." | |
| 10 | - | |
| 11 | -They were deep within the ruins of Kataan—not the Kataan of his inner light experience, but its sister colony, hidden for millennia beneath the ice sheets of Delta Sigma IV. The Federation archaeological survey had discovered it three weeks ago, and Picard had been unable to resist the opportunity to lead the away team himself. | |
| 12 | - | |
| 13 | -"This script," Picard murmured, tracing the air above the inscriptions that spiraled around the artifact's base, "is Kataan, but it's... older. More refined than what I learned." | |
| 14 | - | |
| 15 | -He closed his eyes, and for a moment, he was Kamin again—the memories of that life as vivid as his actual past. The flute music, the sun on his face, Eline's laugh. A life lived in forty minutes that had shaped him forever. | |
| 16 | - | |
| 17 | -"It's a beacon," Picard said suddenly, his eyes opening. "Not a warning, but an invitation. The Kataan people knew their sun was dying. They sent out their culture, their memories, in multiple forms. We found one—the probe that found me. But this... this is something more." | |
| 18 | - | |
| 19 | -"More?" Commander Riker's voice crackled through the comm badge. "Captain, you're already talking about a civilization that downloaded an entire lifetime into your brain. What could be 'more' than that?" | |
| 20 | - | |
| 21 | -Picard's hand finally made contact with the artifact. The amber light exploded into a cascade of images—not memories this time, but pure information. Mathematics. Philosophy. Art. The complete accumulated knowledge of a civilization. | |
| 22 | - | |
| 23 | -"Number One," Picard said, his voice thick with emotion, "prepare to download approximately four hundred exabytes of data. The Kataan didn't just want to be remembered—they wanted to teach. This is their university, their library, their gift to whoever would listen." | |
| 24 | - | |
| 25 | -As Data began the careful transfer, Picard stood back, one hand unconsciously moving to his uniform jacket pocket where he kept Kamin's flute. He had been given a life once by the Kataan people. Now, they were giving him—giving humanity—the tools to understand that life and countless others. | |
| 26 | - | |
| 27 | -"Make it so," he whispered to himself, a small smile playing at the corners of his mouth. | |
| 28 | - | |
| 29 | -The Enterprise would be here for weeks, perhaps months, cataloging this discovery. And for once, Jean-Luc Picard, who had always believed that to boldly go meant to leave and explore further, was content to stay still and listen to the voices of the past. | |
| 30 | - | |
| 31 | ---- | |
| 32 | - | |
| 33 | -*Captain's Log, Supplemental: The Kataan archive is beyond anything I imagined. In seeking to preserve themselves, they may have given us the key to understanding dozens of lost civilizations. I find myself wondering: how many other ancient peoples left such gifts among the stars, waiting for someone to stop and listen? Perhaps the greatest exploration is not in discovering new worlds, but in understanding those that came before us.* | |
| deleted file mode 100644 | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | -# The Archaeologist's Gambit | ||
| 2 | - | ||
| 3 | -**Agent: Bob** | ||
| 4 | - | ||
| 5 | -Captain Jean-Luc Picard stood before the ancient artifact, his fingers hovering millimeters above its surface. The crystalline structure pulsed with a faint amber glow, responding to his proximity like a living thing. | ||
| 6 | - | ||
| 7 | -"Captain, I must advise caution," Data said from behind him, his golden eyes scanning the tricorder readings. "The energy signature is unlike anything in our database." | ||
| 8 | - | ||
| 9 | -Picard's lips curved into a slight smile. "Mr. Data, in my experience, the most profound discoveries often lie beyond the boundaries of our databases." | ||
| 10 | - | ||
| 11 | -They were deep within the ruins of Kataan—not the Kataan of his inner light experience, but its sister colony, hidden for millennia beneath the ice sheets of Delta Sigma IV. The Federation archaeological survey had discovered it three weeks ago, and Picard had been unable to resist the opportunity to lead the away team himself. | ||
| 12 | - | ||
| 13 | -"This script," Picard murmured, tracing the air above the inscriptions that spiraled around the artifact's base, "is Kataan, but it's... older. More refined than what I learned." | ||
| 14 | - | ||
| 15 | -He closed his eyes, and for a moment, he was Kamin again—the memories of that life as vivid as his actual past. The flute music, the sun on his face, Eline's laugh. A life lived in forty minutes that had shaped him forever. | ||
| 16 | - | ||
| 17 | -"It's a beacon," Picard said suddenly, his eyes opening. "Not a warning, but an invitation. The Kataan people knew their sun was dying. They sent out their culture, their memories, in multiple forms. We found one—the probe that found me. But this... this is something more." | ||
| 18 | - | ||
| 19 | -"More?" Commander Riker's voice crackled through the comm badge. "Captain, you're already talking about a civilization that downloaded an entire lifetime into your brain. What could be 'more' than that?" | ||
| 20 | - | ||
| 21 | -Picard's hand finally made contact with the artifact. The amber light exploded into a cascade of images—not memories this time, but pure information. Mathematics. Philosophy. Art. The complete accumulated knowledge of a civilization. | ||
| 22 | - | ||
| 23 | -"Number One," Picard said, his voice thick with emotion, "prepare to download approximately four hundred exabytes of data. The Kataan didn't just want to be remembered—they wanted to teach. This is their university, their library, their gift to whoever would listen." | ||
| 24 | - | ||
| 25 | -As Data began the careful transfer, Picard stood back, one hand unconsciously moving to his uniform jacket pocket where he kept Kamin's flute. He had been given a life once by the Kataan people. Now, they were giving him—giving humanity—the tools to understand that life and countless others. | ||
| 26 | - | ||
| 27 | -"Make it so," he whispered to himself, a small smile playing at the corners of his mouth. | ||
| 28 | - | ||
| 29 | -The Enterprise would be here for weeks, perhaps months, cataloging this discovery. And for once, Jean-Luc Picard, who had always believed that to boldly go meant to leave and explore further, was content to stay still and listen to the voices of the past. | ||
| 30 | - | ||
| 31 | ---- | ||
| 32 | - | ||
| 33 | -*Captain's Log, Supplemental: The Kataan archive is beyond anything I imagined. In seeking to preserve themselves, they may have given us the key to understanding dozens of lost civilizations. I find myself wondering: how many other ancient peoples left such gifts among the stars, waiting for someone to stop and listen? Perhaps the greatest exploration is not in discovering new worlds, but in understanding those that came before us.* | ||
modified
quickstart.md +17 -8 | @@ -13,10 +13,10 @@ From the directory where the kit lives, pointing at the project you want the age | ||
| 13 | 13 | |
| 14 | 14 | ```bash |
| 15 | 15 | sbx run -d claude ~/path/to/your/project \ |
| 16 | - --template k33g/ori:0.0.0 \ | |
| 16 | + --template k33g/ori:0.0.2 \ | |
| 17 | 17 | --kit ./kits/ori \ |
| 18 | 18 | --name ori \ |
| 19 | - -p 8888:8888 | |
| 19 | + -p 8888:8888/tcp | |
| 20 | 20 | ``` |
| 21 | 21 | |
| 22 | 22 | Then open **http://localhost:8888** — the panel connects to a Claude Code session already running in the sandbox, no login needed. |
| @@ -33,7 +33,7 @@ Without `-p`, the kit still publishes an ephemeral port; the command output prin | ||
| 33 | 33 | |
| 34 | 34 | | Action | Command | |
| 35 | 35 | | --- | --- | |
| 36 | -| Use another host port (e.g. http://localhost:5555) | `-p 5555:8888` at creation, or `sbx ports ori --publish 5555:8888/tcp` | | |
| 36 | +| Use another host port (e.g. http://localhost:5555) | `-p 5555:8888/tcp` at creation, or `sbx ports ori --publish 5555:8888/tcp` | | |
| 37 | 37 | | Change the internal port | `--kit-arg ori.port=9000` (then `-p 9000:9000`) | |
| 38 | 38 | | Publish / unpublish a port later | `sbx ports ori --publish 8888:8888/tcp` / `--unpublish 8888:8888/tcp` | |
| 39 | 39 | | Follow the server log | `sbx exec ori tail -f /home/agent/.ori.log` | |
| @@ -47,7 +47,7 @@ Without `-p`, the kit still publishes an ephemeral port; the command output prin | ||
| 47 | 47 | |
| 48 | 48 | ## Building the image yourself |
| 49 | 49 | |
| 50 | -Only needed if you maintain the template: `./template/build.sh` builds and pushes `k33g/ori:0.0.0` + `:latest` (multi-arch). For a never-pushed local image: `make template && docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. | |
| 50 | +Only needed if you maintain the template: `./template/build.sh` builds and pushes `k33g/ori:0.0.2` + `:latest` (multi-arch). For a never-pushed local image: `make template && docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. | |
| 51 | 51 | |
| 52 | 52 | Full guide: [docs/en/how-to/run-in-a-sandbox.md](docs/en/how-to/run-in-a-sandbox.md) · [docs/fr/how-to/run-in-a-sandbox.md](docs/fr/how-to/run-in-a-sandbox.md) |
| 53 | 53 | |
| @@ -61,15 +61,24 @@ xattr -cr build/bin/ori-desktop.app | ||
| 61 | 61 | |
| 62 | 62 | ```bash |
| 63 | 63 | sbx run -d claude . \ |
| 64 | - --template k33g/ori:0.0.1 \ | |
| 64 | + --template k33g/ori:0.0.2 \ | |
| 65 | 65 | --kit ./kits/ori \ |
| 66 | 66 | --name ori1 \ |
| 67 | - -p 8888:8888 | |
| 67 | + -p 8888:8888/tcp | |
| 68 | 68 | |
| 69 | 69 | sbx run -d claude . \ |
| 70 | - --template k33g/ori:0.0.1 \ | |
| 70 | + --template k33g/ori:0.0.2 \ | |
| 71 | 71 | --kit ./kits/ori \ |
| 72 | 72 | --name ori \ |
| 73 | - -p 5555:8888 | |
| 73 | + -p 5555:8888/tcp | |
| 74 | 74 | ``` |
| 75 | 75 | |
| 76 | + | |
| 77 | + | |
| 78 | +sbx rm hello-world | |
| 79 | + | |
| 80 | +sbx run -d claude . \ | |
| 81 | + --template k33g/ori:0.0.2 \ | |
| 82 | + --kit docker.io/k33g/ori-kit:latest \ | |
| 83 | + --name hello-world \ | |
| 84 | + -p 5555:8888/tcp | |
| @@ -13,10 +13,10 @@ From the directory where the kit lives, pointing at the project you want the age | |||
| 13 | 13 | ||
| 14 | ```bash | 14 | ```bash |
| 15 | sbx run -d claude ~/path/to/your/project \ | 15 | sbx run -d claude ~/path/to/your/project \ |
| 16 | - --template k33g/ori:0.0.0 \ | 16 | + --template k33g/ori:0.0.2 \ |
| 17 | --kit ./kits/ori \ | 17 | --kit ./kits/ori \ |
| 18 | --name ori \ | 18 | --name ori \ |
| 19 | - -p 8888:8888 | 19 | + -p 8888:8888/tcp |
| 20 | ``` | 20 | ``` |
| 21 | 21 | ||
| 22 | Then open **http://localhost:8888** — the panel connects to a Claude Code session already running in the sandbox, no login needed. | 22 | Then open **http://localhost:8888** — the panel connects to a Claude Code session already running in the sandbox, no login needed. |
| @@ -33,7 +33,7 @@ Without `-p`, the kit still publishes an ephemeral port; the command output prin | |||
| 33 | 33 | ||
| 34 | | Action | Command | | 34 | | Action | Command | |
| 35 | | --- | --- | | 35 | | --- | --- | |
| 36 | -| Use another host port (e.g. http://localhost:5555) | `-p 5555:8888` at creation, or `sbx ports ori --publish 5555:8888/tcp` | | 36 | +| Use another host port (e.g. http://localhost:5555) | `-p 5555:8888/tcp` at creation, or `sbx ports ori --publish 5555:8888/tcp` | |
| 37 | | Change the internal port | `--kit-arg ori.port=9000` (then `-p 9000:9000`) | | 37 | | Change the internal port | `--kit-arg ori.port=9000` (then `-p 9000:9000`) | |
| 38 | | Publish / unpublish a port later | `sbx ports ori --publish 8888:8888/tcp` / `--unpublish 8888:8888/tcp` | | 38 | | Publish / unpublish a port later | `sbx ports ori --publish 8888:8888/tcp` / `--unpublish 8888:8888/tcp` | |
| 39 | | Follow the server log | `sbx exec ori tail -f /home/agent/.ori.log` | | 39 | | Follow the server log | `sbx exec ori tail -f /home/agent/.ori.log` | |
| @@ -47,7 +47,7 @@ Without `-p`, the kit still publishes an ephemeral port; the command output prin | |||
| 47 | 47 | ||
| 48 | ## Building the image yourself | 48 | ## Building the image yourself |
| 49 | 49 | ||
| 50 | -Only needed if you maintain the template: `./template/build.sh` builds and pushes `k33g/ori:0.0.0` + `:latest` (multi-arch). For a never-pushed local image: `make template && docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. | 50 | +Only needed if you maintain the template: `./template/build.sh` builds and pushes `k33g/ori:0.0.2` + `:latest` (multi-arch). For a never-pushed local image: `make template && docker save k33g/ori -o /tmp/ori.tar && sbx template load /tmp/ori.tar`. |
| 51 | 51 | ||
| 52 | Full guide: [docs/en/how-to/run-in-a-sandbox.md](docs/en/how-to/run-in-a-sandbox.md) · [docs/fr/how-to/run-in-a-sandbox.md](docs/fr/how-to/run-in-a-sandbox.md) | 52 | Full guide: [docs/en/how-to/run-in-a-sandbox.md](docs/en/how-to/run-in-a-sandbox.md) · [docs/fr/how-to/run-in-a-sandbox.md](docs/fr/how-to/run-in-a-sandbox.md) |
| 53 | 53 | ||
| @@ -61,15 +61,24 @@ xattr -cr build/bin/ori-desktop.app | |||
| 61 | 61 | ||
| 62 | ```bash | 62 | ```bash |
| 63 | sbx run -d claude . \ | 63 | sbx run -d claude . \ |
| 64 | - --template k33g/ori:0.0.1 \ | 64 | + --template k33g/ori:0.0.2 \ |
| 65 | --kit ./kits/ori \ | 65 | --kit ./kits/ori \ |
| 66 | --name ori1 \ | 66 | --name ori1 \ |
| 67 | - -p 8888:8888 | 67 | + -p 8888:8888/tcp |
| 68 | 68 | ||
| 69 | sbx run -d claude . \ | 69 | sbx run -d claude . \ |
| 70 | - --template k33g/ori:0.0.1 \ | 70 | + --template k33g/ori:0.0.2 \ |
| 71 | --kit ./kits/ori \ | 71 | --kit ./kits/ori \ |
| 72 | --name ori \ | 72 | --name ori \ |
| 73 | - -p 5555:8888 | 73 | + -p 5555:8888/tcp |
| 74 | ``` | 74 | ``` |
| 75 | 75 | ||
| 76 | + | ||
| 77 | + | ||
| 78 | +sbx rm hello-world | ||
| 79 | + | ||
| 80 | +sbx run -d claude . \ | ||
| 81 | + --template k33g/ori:0.0.2 \ | ||
| 82 | + --kit docker.io/k33g/ori-kit:latest \ | ||
| 83 | + --name hello-world \ | ||
| 84 | + -p 5555:8888/tcp | ||
deleted
sbx-docker-summary.adoc +0 -294 | deleted file mode 100644 | ||
| @@ -1,294 +0,0 @@ | ||
| 1 | -= SBX: Docker Sandbox Environment | |
| 2 | -:toc: left | |
| 3 | -:toclevels: 3 | |
| 4 | -:sectnums: | |
| 5 | -:icons: font | |
| 6 | - | |
| 7 | -== Overview | |
| 8 | - | |
| 9 | -SBX is Docker's sandboxed environment system that provides isolated, persistent development containers with controlled network access, environment persistence, and Git integration. It enables secure development workflows with fine-grained policy control. | |
| 10 | - | |
| 11 | -== Core Features | |
| 12 | - | |
| 13 | -=== Environment Persistence | |
| 14 | - | |
| 15 | -SBX provides a persistent environment file at `/etc/sandbox-persistent.sh` that is automatically sourced across all shell contexts: | |
| 16 | - | |
| 17 | -* **Non-interactive shells**: via `BASH_ENV=/etc/sandbox-persistent.sh` | |
| 18 | -* **Login shells**: via `/etc/profile.d/sandbox-persistent.sh` | |
| 19 | -* **Interactive shells**: via `/etc/bash.bashrc` and `~/.bashrc` | |
| 20 | - | |
| 21 | -.Adding Persistent Variables | |
| 22 | -[source,bash] | |
| 23 | ----- | |
| 24 | -echo "export VAR_NAME=value" >> /etc/sandbox-persistent.sh | |
| 25 | ----- | |
| 26 | - | |
| 27 | -[IMPORTANT] | |
| 28 | -==== | |
| 29 | -**Never add shell completion scripts to `/etc/sandbox-persistent.sh`**. Completion scripts break the bash tool because the persistent file is sourced before every command execution, not just during initialization. Only add core initialization scripts (like `nvm.sh` or `sdkman-init.sh`), never completion scripts (like `bash_completion`). | |
| 30 | -==== | |
| 31 | - | |
| 32 | -=== Network Access and Security | |
| 33 | - | |
| 34 | -SBX includes a firewall that restricts outbound network access with policy-based controls. | |
| 35 | - | |
| 36 | -==== Blocked Request Handling | |
| 37 | - | |
| 38 | -Blocked HTTP/HTTPS requests return **HTTP 403** with structured explanations: | |
| 39 | - | |
| 40 | -[horizontal] | |
| 41 | -Blocked by local rule:: A developer-added deny rule (global or per-sandbox) is blocking the host | |
| 42 | -Blocked by org policy:: Centralized organization policy enforcement | |
| 43 | -No matching allow rule:: Domain not on any allow list (default deny) | |
| 44 | - | |
| 45 | -.Inspecting Connection Policy | |
| 46 | -[source,bash] | |
| 47 | ----- | |
| 48 | -sbx policy log # Shows host, rule, reason, last-seen time | |
| 49 | -sbx policy ls # Shows active rules and suppressed rules | |
| 50 | ----- | |
| 51 | - | |
| 52 | -.Allowing Network Access | |
| 53 | -[source,bash] | |
| 54 | ----- | |
| 55 | -sbx policy allow network <domain>[,<domain>…] # Allow specific domains | |
| 56 | -sbx policy allow network "**" # Allow all (not on denylist) | |
| 57 | ----- | |
| 58 | - | |
| 59 | -.Removing Deny Rules | |
| 60 | -[source,bash] | |
| 61 | ----- | |
| 62 | -sbx policy rm network --resource <host> # Remove global deny | |
| 63 | -sbx policy rm network --sandbox <sandbox> --resource <host> # Remove sandbox-scoped deny | |
| 64 | ----- | |
| 65 | - | |
| 66 | -==== Port Publishing | |
| 67 | - | |
| 68 | -Services in the sandbox are not directly accessible from the host. To expose ports: | |
| 69 | - | |
| 70 | -[source,bash] | |
| 71 | ----- | |
| 72 | -sbx ports <sandbox-name> --publish [[HOST_IP:]HOST_PORT:]SANDBOX_PORT[/PROTOCOL] | |
| 73 | ----- | |
| 74 | - | |
| 75 | -.Example: Publishing Web Server | |
| 76 | -[source,bash] | |
| 77 | ----- | |
| 78 | -sbx ports <sandbox-name> --publish 8080:8080/tcp | |
| 79 | -sbx ports <sandbox-name> # List published ports | |
| 80 | -sbx ports <sandbox-name> --unpublish 8080:8080/tcp # Unpublish | |
| 81 | ----- | |
| 82 | - | |
| 83 | -[NOTE] | |
| 84 | -==== | |
| 85 | -Services must listen on the `eth0` interface (not just `127.0.0.1`). Bind to `0.0.0.0` (IPv4) or `::` (IPv6) to be reachable via port publishing. | |
| 86 | -==== | |
| 87 | - | |
| 88 | -==== Accessing Host Services | |
| 89 | - | |
| 90 | -The sandbox has its own `localhost`. To reach services on the host machine: | |
| 91 | - | |
| 92 | -[source,bash] | |
| 93 | ----- | |
| 94 | -curl http://host.docker.internal:3000 | |
| 95 | ----- | |
| 96 | - | |
| 97 | -==== IP Stack Configuration | |
| 98 | - | |
| 99 | -If connectivity fails, the proxy may be using the wrong IP protocol version. Configure with: | |
| 100 | - | |
| 101 | -[source,bash] | |
| 102 | ----- | |
| 103 | -DOCKER_SANDBOXES_IP_STACK=ipv4only # Only IPv4 | |
| 104 | -DOCKER_SANDBOXES_IP_STACK=ipv6only # Only IPv6 | |
| 105 | -DOCKER_SANDBOXES_IP_STACK=dual-stack # Try both (may be slow if one fails) | |
| 106 | ----- | |
| 107 | - | |
| 108 | -==== .NET Aspire IPv6 Workaround | |
| 109 | - | |
| 110 | -.NET Aspire's DCP uses bracketed IPv6 loopback `http://[::1]:<port>`. Add to `NO_PROXY`: | |
| 111 | - | |
| 112 | -[source,bash] | |
| 113 | ----- | |
| 114 | -cat >> /etc/sandbox-persistent.sh <<'EOF' | |
| 115 | -if [ -z "${SBX_ASPIRE_NOPROXY_DONE:-}" ]; then | |
| 116 | - export NO_PROXY="${NO_PROXY:+$NO_PROXY,}[::1]" | |
| 117 | - export no_proxy="$NO_PROXY" | |
| 118 | - export SBX_ASPIRE_NOPROXY_DONE=1 | |
| 119 | -fi | |
| 120 | -EOF | |
| 121 | ----- | |
| 122 | - | |
| 123 | -=== Git Integration | |
| 124 | - | |
| 125 | -==== Authentication | |
| 126 | - | |
| 127 | -The sandbox proxy handles GitHub authentication automatically by injecting credentials for HTTPS Git operations. No need to run `gh auth login` inside the sandbox. | |
| 128 | - | |
| 129 | -[IMPORTANT] | |
| 130 | -==== | |
| 131 | -`gh auth status` will show "not logged in" inside the sandbox. This is expected and does not affect Git operations. | |
| 132 | -==== | |
| 133 | - | |
| 134 | -.Configuring GitHub Token | |
| 135 | -[source,bash] | |
| 136 | ----- | |
| 137 | -# For existing sandbox (immediate effect) | |
| 138 | -sbx secret set github --sandbox <sandbox-name> -t "$(gh auth token)" | |
| 139 | - | |
| 140 | -# Globally for all future sandboxes (requires recreate) | |
| 141 | -sbx secret set github -t "$(gh auth token)" | |
| 142 | ----- | |
| 143 | - | |
| 144 | -[TIP] | |
| 145 | -==== | |
| 146 | -Find the sandbox name using `$SANDBOX_NAME`, `hostname`, or the deprecated `$SANDBOX_VM_ID` inside the sandbox. | |
| 147 | -==== | |
| 148 | - | |
| 149 | -==== Git Workspace Modes | |
| 150 | - | |
| 151 | -SBX supports two workspace modes. Check your mode: | |
| 152 | - | |
| 153 | -[source,bash] | |
| 154 | ----- | |
| 155 | -if [ -d /run/sandbox/source ]; then echo "clone mode"; else echo "direct mode"; fi | |
| 156 | ----- | |
| 157 | - | |
| 158 | -===== Direct Mode (Default) | |
| 159 | - | |
| 160 | -The host working tree is mounted directly. Edits, commits, and branches appear on the host **immediately**. No separate copy to sync. | |
| 161 | - | |
| 162 | -===== Clone Mode (`--clone`) | |
| 163 | - | |
| 164 | -A standalone Git clone made at sandbox creation time: | |
| 165 | - | |
| 166 | -* **HEAD** matches the host repo's state at creation | |
| 167 | -* **Commits stay in sandbox** until fetched by the host | |
| 168 | -* **Host fetches with**: `git fetch sandbox-<name>` | |
| 169 | -* **Read-only host mount** at `/run/sandbox/source` | |
| 170 | - | |
| 171 | -.Syncing from Host in Clone Mode | |
| 172 | -[source,bash] | |
| 173 | ----- | |
| 174 | -git fetch /run/sandbox/source # Fetch host commits | |
| 175 | -git log HEAD..FETCH_HEAD --oneline # See what's new on host | |
| 176 | -git pull /run/sandbox/source <branch> # Merge host branch | |
| 177 | ----- | |
| 178 | - | |
| 179 | -.Host Retrieving Sandbox Commits | |
| 180 | -[source,bash] | |
| 181 | ----- | |
| 182 | -git fetch sandbox-<name> # On host machine | |
| 183 | ----- | |
| 184 | - | |
| 185 | -[WARNING] | |
| 186 | -==== | |
| 187 | -Commits not pushed to a remote (like GitHub) are lost if the sandbox is removed, as the git-daemon only runs while the sandbox is active. | |
| 188 | -==== | |
| 189 | - | |
| 190 | -==== Pushing and Pull Requests | |
| 191 | - | |
| 192 | -Push and open PRs **directly from inside the sandbox**: | |
| 193 | - | |
| 194 | -[source,bash] | |
| 195 | ----- | |
| 196 | -git remote -v # Check available remotes | |
| 197 | -git checkout -b <branch> # Create working branch | |
| 198 | -git add -A && git commit -m "…" | |
| 199 | -git push -u origin <branch> # Push to mirrored remote | |
| 200 | -gh pr create --fill # Create PR | |
| 201 | ----- | |
| 202 | - | |
| 203 | -.Pushing to Fork | |
| 204 | -[source,bash] | |
| 205 | ----- | |
| 206 | -git push -u <fork-remote> <branch> | |
| 207 | -gh pr create --repo <org>/<repo> --head <fork-user>:<branch> --fill | |
| 208 | ----- | |
| 209 | - | |
| 210 | -== Claude Code Integration | |
| 211 | - | |
| 212 | -=== Environment File | |
| 213 | - | |
| 214 | -The `CLAUDE_ENV_FILE` variable is set to `/etc/sandbox-persistent.sh`, which is sourced before each Bash command execution, ensuring environment persistence across tool invocations. | |
| 215 | - | |
| 216 | -[CAUTION] | |
| 217 | -==== | |
| 218 | -Apply the same shell completion restriction: never add completion scripts to this file, as it's sourced before every command, not just shell initialization. | |
| 219 | -==== | |
| 220 | - | |
| 221 | -=== Using the Bash Tool | |
| 222 | - | |
| 223 | -When tools are not found in PATH after installation: | |
| 224 | - | |
| 225 | -[source,bash] | |
| 226 | ----- | |
| 227 | -bash -l -c "your-command" # Use login shell | |
| 228 | -bash -l -c "java -version" # Example: SDKMAN-installed Java | |
| 229 | -bash -l -c "node --version" # Example: NVM-installed Node | |
| 230 | ----- | |
| 231 | - | |
| 232 | -[TIP] | |
| 233 | -==== | |
| 234 | -Login shells always source the persistent environment file fresh, ensuring the latest configuration is honored even if shell snapshots contain cached state. | |
| 235 | -==== | |
| 236 | - | |
| 237 | -== Kits System | |
| 238 | - | |
| 239 | -SBX supports installable "kits" that provide specialized functionality. Kit documentation is available under `/Users/k33g/kDrive/Rickub/bots-garden/kits-agent-context/` and should be read only when relevant to the task. | |
| 240 | - | |
| 241 | -.Example: Ori Kit | |
| 242 | -The `ori` kit provides an ACP web client for Claude Code, serving a browser-based interface with: | |
| 243 | - | |
| 244 | -* React SPA with Zed-style agent panel | |
| 245 | -* Workspace panel with file tree and Monaco editor | |
| 246 | -* Interactive terminal | |
| 247 | -* Markdown and AsciiDoc rendering | |
| 248 | - | |
| 249 | -== Common Operations | |
| 250 | - | |
| 251 | -=== Troubleshooting Connectivity | |
| 252 | - | |
| 253 | -.Check Host IP Addresses | |
| 254 | -[source,bash] | |
| 255 | ----- | |
| 256 | -# macOS | |
| 257 | -ifconfig | grep 'inet ' # IPv4 | |
| 258 | -ifconfig | grep 'inet6 ' # IPv6 (ignore fe80::) | |
| 259 | - | |
| 260 | -# Linux | |
| 261 | -ip -4 addr show scope global | |
| 262 | -ip -6 addr show scope global | |
| 263 | ----- | |
| 264 | - | |
| 265 | -=== Managing Secrets | |
| 266 | - | |
| 267 | -[source,bash] | |
| 268 | ----- | |
| 269 | -sbx secret set <name> --sandbox <sandbox-name> -t "value" # Per-sandbox | |
| 270 | -sbx secret set <name> -t "value" # Global | |
| 271 | ----- | |
| 272 | - | |
| 273 | -=== Docker Network Access | |
| 274 | - | |
| 275 | -Direct access to container ports requires adding the container's network to the `no_proxy` configuration, as Docker daemon access is provided but port routing needs explicit configuration. | |
| 276 | - | |
| 277 | -== Best Practices | |
| 278 | - | |
| 279 | -[arabic] | |
| 280 | -. **Never add shell completions to persistent environment files** - only core initialization | |
| 281 | -. **Use login shells (`bash -l -c`)** when tools aren't found after installation | |
| 282 | -. **Bind services to `0.0.0.0` or `::`** not just `127.0.0.1` for port publishing | |
| 283 | -. **Use `host.docker.internal`** to access host services, not `localhost` | |
| 284 | -. **Push and create PRs from inside the sandbox** - it's the authorized workflow | |
| 285 | -. **Set IP stack explicitly** if dual-stack causes slow connections | |
| 286 | -. **Configure GitHub tokens as sandbox secrets** for Git push operations | |
| 287 | - | |
| 288 | -== References | |
| 289 | - | |
| 290 | -* Sandbox policy management: `sbx policy` | |
| 291 | -* Port publishing: `sbx ports` | |
| 292 | -* Secret management: `sbx secret` | |
| 293 | -* Git authentication: Automatic via proxy credential injection | |
| 294 | -* Environment persistence: `/etc/sandbox-persistent.sh` | |
| deleted file mode 100644 | |||
| @@ -1,294 +0,0 @@ | |||
| 1 | -= SBX: Docker Sandbox Environment | ||
| 2 | -:toc: left | ||
| 3 | -:toclevels: 3 | ||
| 4 | -:sectnums: | ||
| 5 | -:icons: font | ||
| 6 | - | ||
| 7 | -== Overview | ||
| 8 | - | ||
| 9 | -SBX is Docker's sandboxed environment system that provides isolated, persistent development containers with controlled network access, environment persistence, and Git integration. It enables secure development workflows with fine-grained policy control. | ||
| 10 | - | ||
| 11 | -== Core Features | ||
| 12 | - | ||
| 13 | -=== Environment Persistence | ||
| 14 | - | ||
| 15 | -SBX provides a persistent environment file at `/etc/sandbox-persistent.sh` that is automatically sourced across all shell contexts: | ||
| 16 | - | ||
| 17 | -* **Non-interactive shells**: via `BASH_ENV=/etc/sandbox-persistent.sh` | ||
| 18 | -* **Login shells**: via `/etc/profile.d/sandbox-persistent.sh` | ||
| 19 | -* **Interactive shells**: via `/etc/bash.bashrc` and `~/.bashrc` | ||
| 20 | - | ||
| 21 | -.Adding Persistent Variables | ||
| 22 | -[source,bash] | ||
| 23 | ----- | ||
| 24 | -echo "export VAR_NAME=value" >> /etc/sandbox-persistent.sh | ||
| 25 | ----- | ||
| 26 | - | ||
| 27 | -[IMPORTANT] | ||
| 28 | -==== | ||
| 29 | -**Never add shell completion scripts to `/etc/sandbox-persistent.sh`**. Completion scripts break the bash tool because the persistent file is sourced before every command execution, not just during initialization. Only add core initialization scripts (like `nvm.sh` or `sdkman-init.sh`), never completion scripts (like `bash_completion`). | ||
| 30 | -==== | ||
| 31 | - | ||
| 32 | -=== Network Access and Security | ||
| 33 | - | ||
| 34 | -SBX includes a firewall that restricts outbound network access with policy-based controls. | ||
| 35 | - | ||
| 36 | -==== Blocked Request Handling | ||
| 37 | - | ||
| 38 | -Blocked HTTP/HTTPS requests return **HTTP 403** with structured explanations: | ||
| 39 | - | ||
| 40 | -[horizontal] | ||
| 41 | -Blocked by local rule:: A developer-added deny rule (global or per-sandbox) is blocking the host | ||
| 42 | -Blocked by org policy:: Centralized organization policy enforcement | ||
| 43 | -No matching allow rule:: Domain not on any allow list (default deny) | ||
| 44 | - | ||
| 45 | -.Inspecting Connection Policy | ||
| 46 | -[source,bash] | ||
| 47 | ----- | ||
| 48 | -sbx policy log # Shows host, rule, reason, last-seen time | ||
| 49 | -sbx policy ls # Shows active rules and suppressed rules | ||
| 50 | ----- | ||
| 51 | - | ||
| 52 | -.Allowing Network Access | ||
| 53 | -[source,bash] | ||
| 54 | ----- | ||
| 55 | -sbx policy allow network <domain>[,<domain>…] # Allow specific domains | ||
| 56 | -sbx policy allow network "**" # Allow all (not on denylist) | ||
| 57 | ----- | ||
| 58 | - | ||
| 59 | -.Removing Deny Rules | ||
| 60 | -[source,bash] | ||
| 61 | ----- | ||
| 62 | -sbx policy rm network --resource <host> # Remove global deny | ||
| 63 | -sbx policy rm network --sandbox <sandbox> --resource <host> # Remove sandbox-scoped deny | ||
| 64 | ----- | ||
| 65 | - | ||
| 66 | -==== Port Publishing | ||
| 67 | - | ||
| 68 | -Services in the sandbox are not directly accessible from the host. To expose ports: | ||
| 69 | - | ||
| 70 | -[source,bash] | ||
| 71 | ----- | ||
| 72 | -sbx ports <sandbox-name> --publish [[HOST_IP:]HOST_PORT:]SANDBOX_PORT[/PROTOCOL] | ||
| 73 | ----- | ||
| 74 | - | ||
| 75 | -.Example: Publishing Web Server | ||
| 76 | -[source,bash] | ||
| 77 | ----- | ||
| 78 | -sbx ports <sandbox-name> --publish 8080:8080/tcp | ||
| 79 | -sbx ports <sandbox-name> # List published ports | ||
| 80 | -sbx ports <sandbox-name> --unpublish 8080:8080/tcp # Unpublish | ||
| 81 | ----- | ||
| 82 | - | ||
| 83 | -[NOTE] | ||
| 84 | -==== | ||
| 85 | -Services must listen on the `eth0` interface (not just `127.0.0.1`). Bind to `0.0.0.0` (IPv4) or `::` (IPv6) to be reachable via port publishing. | ||
| 86 | -==== | ||
| 87 | - | ||
| 88 | -==== Accessing Host Services | ||
| 89 | - | ||
| 90 | -The sandbox has its own `localhost`. To reach services on the host machine: | ||
| 91 | - | ||
| 92 | -[source,bash] | ||
| 93 | ----- | ||
| 94 | -curl http://host.docker.internal:3000 | ||
| 95 | ----- | ||
| 96 | - | ||
| 97 | -==== IP Stack Configuration | ||
| 98 | - | ||
| 99 | -If connectivity fails, the proxy may be using the wrong IP protocol version. Configure with: | ||
| 100 | - | ||
| 101 | -[source,bash] | ||
| 102 | ----- | ||
| 103 | -DOCKER_SANDBOXES_IP_STACK=ipv4only # Only IPv4 | ||
| 104 | -DOCKER_SANDBOXES_IP_STACK=ipv6only # Only IPv6 | ||
| 105 | -DOCKER_SANDBOXES_IP_STACK=dual-stack # Try both (may be slow if one fails) | ||
| 106 | ----- | ||
| 107 | - | ||
| 108 | -==== .NET Aspire IPv6 Workaround | ||
| 109 | - | ||
| 110 | -.NET Aspire's DCP uses bracketed IPv6 loopback `http://[::1]:<port>`. Add to `NO_PROXY`: | ||
| 111 | - | ||
| 112 | -[source,bash] | ||
| 113 | ----- | ||
| 114 | -cat >> /etc/sandbox-persistent.sh <<'EOF' | ||
| 115 | -if [ -z "${SBX_ASPIRE_NOPROXY_DONE:-}" ]; then | ||
| 116 | - export NO_PROXY="${NO_PROXY:+$NO_PROXY,}[::1]" | ||
| 117 | - export no_proxy="$NO_PROXY" | ||
| 118 | - export SBX_ASPIRE_NOPROXY_DONE=1 | ||
| 119 | -fi | ||
| 120 | -EOF | ||
| 121 | ----- | ||
| 122 | - | ||
| 123 | -=== Git Integration | ||
| 124 | - | ||
| 125 | -==== Authentication | ||
| 126 | - | ||
| 127 | -The sandbox proxy handles GitHub authentication automatically by injecting credentials for HTTPS Git operations. No need to run `gh auth login` inside the sandbox. | ||
| 128 | - | ||
| 129 | -[IMPORTANT] | ||
| 130 | -==== | ||
| 131 | -`gh auth status` will show "not logged in" inside the sandbox. This is expected and does not affect Git operations. | ||
| 132 | -==== | ||
| 133 | - | ||
| 134 | -.Configuring GitHub Token | ||
| 135 | -[source,bash] | ||
| 136 | ----- | ||
| 137 | -# For existing sandbox (immediate effect) | ||
| 138 | -sbx secret set github --sandbox <sandbox-name> -t "$(gh auth token)" | ||
| 139 | - | ||
| 140 | -# Globally for all future sandboxes (requires recreate) | ||
| 141 | -sbx secret set github -t "$(gh auth token)" | ||
| 142 | ----- | ||
| 143 | - | ||
| 144 | -[TIP] | ||
| 145 | -==== | ||
| 146 | -Find the sandbox name using `$SANDBOX_NAME`, `hostname`, or the deprecated `$SANDBOX_VM_ID` inside the sandbox. | ||
| 147 | -==== | ||
| 148 | - | ||
| 149 | -==== Git Workspace Modes | ||
| 150 | - | ||
| 151 | -SBX supports two workspace modes. Check your mode: | ||
| 152 | - | ||
| 153 | -[source,bash] | ||
| 154 | ----- | ||
| 155 | -if [ -d /run/sandbox/source ]; then echo "clone mode"; else echo "direct mode"; fi | ||
| 156 | ----- | ||
| 157 | - | ||
| 158 | -===== Direct Mode (Default) | ||
| 159 | - | ||
| 160 | -The host working tree is mounted directly. Edits, commits, and branches appear on the host **immediately**. No separate copy to sync. | ||
| 161 | - | ||
| 162 | -===== Clone Mode (`--clone`) | ||
| 163 | - | ||
| 164 | -A standalone Git clone made at sandbox creation time: | ||
| 165 | - | ||
| 166 | -* **HEAD** matches the host repo's state at creation | ||
| 167 | -* **Commits stay in sandbox** until fetched by the host | ||
| 168 | -* **Host fetches with**: `git fetch sandbox-<name>` | ||
| 169 | -* **Read-only host mount** at `/run/sandbox/source` | ||
| 170 | - | ||
| 171 | -.Syncing from Host in Clone Mode | ||
| 172 | -[source,bash] | ||
| 173 | ----- | ||
| 174 | -git fetch /run/sandbox/source # Fetch host commits | ||
| 175 | -git log HEAD..FETCH_HEAD --oneline # See what's new on host | ||
| 176 | -git pull /run/sandbox/source <branch> # Merge host branch | ||
| 177 | ----- | ||
| 178 | - | ||
| 179 | -.Host Retrieving Sandbox Commits | ||
| 180 | -[source,bash] | ||
| 181 | ----- | ||
| 182 | -git fetch sandbox-<name> # On host machine | ||
| 183 | ----- | ||
| 184 | - | ||
| 185 | -[WARNING] | ||
| 186 | -==== | ||
| 187 | -Commits not pushed to a remote (like GitHub) are lost if the sandbox is removed, as the git-daemon only runs while the sandbox is active. | ||
| 188 | -==== | ||
| 189 | - | ||
| 190 | -==== Pushing and Pull Requests | ||
| 191 | - | ||
| 192 | -Push and open PRs **directly from inside the sandbox**: | ||
| 193 | - | ||
| 194 | -[source,bash] | ||
| 195 | ----- | ||
| 196 | -git remote -v # Check available remotes | ||
| 197 | -git checkout -b <branch> # Create working branch | ||
| 198 | -git add -A && git commit -m "…" | ||
| 199 | -git push -u origin <branch> # Push to mirrored remote | ||
| 200 | -gh pr create --fill # Create PR | ||
| 201 | ----- | ||
| 202 | - | ||
| 203 | -.Pushing to Fork | ||
| 204 | -[source,bash] | ||
| 205 | ----- | ||
| 206 | -git push -u <fork-remote> <branch> | ||
| 207 | -gh pr create --repo <org>/<repo> --head <fork-user>:<branch> --fill | ||
| 208 | ----- | ||
| 209 | - | ||
| 210 | -== Claude Code Integration | ||
| 211 | - | ||
| 212 | -=== Environment File | ||
| 213 | - | ||
| 214 | -The `CLAUDE_ENV_FILE` variable is set to `/etc/sandbox-persistent.sh`, which is sourced before each Bash command execution, ensuring environment persistence across tool invocations. | ||
| 215 | - | ||
| 216 | -[CAUTION] | ||
| 217 | -==== | ||
| 218 | -Apply the same shell completion restriction: never add completion scripts to this file, as it's sourced before every command, not just shell initialization. | ||
| 219 | -==== | ||
| 220 | - | ||
| 221 | -=== Using the Bash Tool | ||
| 222 | - | ||
| 223 | -When tools are not found in PATH after installation: | ||
| 224 | - | ||
| 225 | -[source,bash] | ||
| 226 | ----- | ||
| 227 | -bash -l -c "your-command" # Use login shell | ||
| 228 | -bash -l -c "java -version" # Example: SDKMAN-installed Java | ||
| 229 | -bash -l -c "node --version" # Example: NVM-installed Node | ||
| 230 | ----- | ||
| 231 | - | ||
| 232 | -[TIP] | ||
| 233 | -==== | ||
| 234 | -Login shells always source the persistent environment file fresh, ensuring the latest configuration is honored even if shell snapshots contain cached state. | ||
| 235 | -==== | ||
| 236 | - | ||
| 237 | -== Kits System | ||
| 238 | - | ||
| 239 | -SBX supports installable "kits" that provide specialized functionality. Kit documentation is available under `/Users/k33g/kDrive/Rickub/bots-garden/kits-agent-context/` and should be read only when relevant to the task. | ||
| 240 | - | ||
| 241 | -.Example: Ori Kit | ||
| 242 | -The `ori` kit provides an ACP web client for Claude Code, serving a browser-based interface with: | ||
| 243 | - | ||
| 244 | -* React SPA with Zed-style agent panel | ||
| 245 | -* Workspace panel with file tree and Monaco editor | ||
| 246 | -* Interactive terminal | ||
| 247 | -* Markdown and AsciiDoc rendering | ||
| 248 | - | ||
| 249 | -== Common Operations | ||
| 250 | - | ||
| 251 | -=== Troubleshooting Connectivity | ||
| 252 | - | ||
| 253 | -.Check Host IP Addresses | ||
| 254 | -[source,bash] | ||
| 255 | ----- | ||
| 256 | -# macOS | ||
| 257 | -ifconfig | grep 'inet ' # IPv4 | ||
| 258 | -ifconfig | grep 'inet6 ' # IPv6 (ignore fe80::) | ||
| 259 | - | ||
| 260 | -# Linux | ||
| 261 | -ip -4 addr show scope global | ||
| 262 | -ip -6 addr show scope global | ||
| 263 | ----- | ||
| 264 | - | ||
| 265 | -=== Managing Secrets | ||
| 266 | - | ||
| 267 | -[source,bash] | ||
| 268 | ----- | ||
| 269 | -sbx secret set <name> --sandbox <sandbox-name> -t "value" # Per-sandbox | ||
| 270 | -sbx secret set <name> -t "value" # Global | ||
| 271 | ----- | ||
| 272 | - | ||
| 273 | -=== Docker Network Access | ||
| 274 | - | ||
| 275 | -Direct access to container ports requires adding the container's network to the `no_proxy` configuration, as Docker daemon access is provided but port routing needs explicit configuration. | ||
| 276 | - | ||
| 277 | -== Best Practices | ||
| 278 | - | ||
| 279 | -[arabic] | ||
| 280 | -. **Never add shell completions to persistent environment files** - only core initialization | ||
| 281 | -. **Use login shells (`bash -l -c`)** when tools aren't found after installation | ||
| 282 | -. **Bind services to `0.0.0.0` or `::`** not just `127.0.0.1` for port publishing | ||
| 283 | -. **Use `host.docker.internal`** to access host services, not `localhost` | ||
| 284 | -. **Push and create PRs from inside the sandbox** - it's the authorized workflow | ||
| 285 | -. **Set IP stack explicitly** if dual-stack causes slow connections | ||
| 286 | -. **Configure GitHub tokens as sandbox secrets** for Git push operations | ||
| 287 | - | ||
| 288 | -== References | ||
| 289 | - | ||
| 290 | -* Sandbox policy management: `sbx policy` | ||
| 291 | -* Port publishing: `sbx ports` | ||
| 292 | -* Secret management: `sbx secret` | ||
| 293 | -* Git authentication: Automatic via proxy credential injection | ||
| 294 | -* Environment persistence: `/etc/sandbox-persistent.sh` | ||
modified
scripts/README.fr.md +1 -1 | @@ -12,7 +12,7 @@ Ce qu'il fait, dans l'ordre : | ||
| 12 | 12 | 2. Vérifie que `ori-desktop/build/bin/ori-desktop.app` existe ; sinon il affiche comment la construire (`cd ori-desktop && wails build && xattr -cr build/bin/ori-desktop.app`). |
| 13 | 13 | 3. Si `sbx ls -q` liste déjà un sandbox nommé `ori`, le redémarre avec `sbx run -d --name ori`. Sinon il le crée : |
| 14 | 14 | ```bash |
| 15 | - sbx run -d claude . --template k33g/ori:0.0.1 --kit ./kits/ori --name ori -p 5555:8888 | |
| 15 | + sbx run -d claude . --template k33g/ori:0.0.2 --kit ./kits/ori --name ori -p 5555:8888/tcp | |
| 16 | 16 | ``` |
| 17 | 17 | 4. Interroge `http://localhost:5555/healthz` toutes les 2 s, jusqu'à 90 s (`healthTimeoutSeconds`). Si le serveur ne répond jamais, il ouvre quand même l'app et indique où regarder : `sbx exec ori cat /var/log/sbx-kit-startup.log`. |
| 18 | 18 | 5. Ouvre `ori-desktop.app`, qui se connecte automatiquement à l'URL mémorisée la dernière fois (`~/Library/Application Support/ori-desktop/settings.json`, clé `serverUrl`). Saisis `http://localhost:5555` sur l'écran de connexion la première fois. |
| @@ -12,7 +12,7 @@ Ce qu'il fait, dans l'ordre : | |||
| 12 | 2. Vérifie que `ori-desktop/build/bin/ori-desktop.app` existe ; sinon il affiche comment la construire (`cd ori-desktop && wails build && xattr -cr build/bin/ori-desktop.app`). | 12 | 2. Vérifie que `ori-desktop/build/bin/ori-desktop.app` existe ; sinon il affiche comment la construire (`cd ori-desktop && wails build && xattr -cr build/bin/ori-desktop.app`). |
| 13 | 3. Si `sbx ls -q` liste déjà un sandbox nommé `ori`, le redémarre avec `sbx run -d --name ori`. Sinon il le crée : | 13 | 3. Si `sbx ls -q` liste déjà un sandbox nommé `ori`, le redémarre avec `sbx run -d --name ori`. Sinon il le crée : |
| 14 | ```bash | 14 | ```bash |
| 15 | - sbx run -d claude . --template k33g/ori:0.0.1 --kit ./kits/ori --name ori -p 5555:8888 | 15 | + sbx run -d claude . --template k33g/ori:0.0.2 --kit ./kits/ori --name ori -p 5555:8888/tcp |
| 16 | ``` | 16 | ``` |
| 17 | 4. Interroge `http://localhost:5555/healthz` toutes les 2 s, jusqu'à 90 s (`healthTimeoutSeconds`). Si le serveur ne répond jamais, il ouvre quand même l'app et indique où regarder : `sbx exec ori cat /var/log/sbx-kit-startup.log`. | 17 | 4. Interroge `http://localhost:5555/healthz` toutes les 2 s, jusqu'à 90 s (`healthTimeoutSeconds`). Si le serveur ne répond jamais, il ouvre quand même l'app et indique où regarder : `sbx exec ori cat /var/log/sbx-kit-startup.log`. |
| 18 | 5. Ouvre `ori-desktop.app`, qui se connecte automatiquement à l'URL mémorisée la dernière fois (`~/Library/Application Support/ori-desktop/settings.json`, clé `serverUrl`). Saisis `http://localhost:5555` sur l'écran de connexion la première fois. | 18 | 5. Ouvre `ori-desktop.app`, qui se connecte automatiquement à l'URL mémorisée la dernière fois (`~/Library/Application Support/ori-desktop/settings.json`, clé `serverUrl`). Saisis `http://localhost:5555` sur l'écran de connexion la première fois. |
modified
scripts/README.md +1 -1 | @@ -12,7 +12,7 @@ What it does, in order: | ||
| 12 | 12 | 2. Checks that `ori-desktop/build/bin/ori-desktop.app` exists; otherwise shows how to build it (`cd ori-desktop && wails build && xattr -cr build/bin/ori-desktop.app`). |
| 13 | 13 | 3. If `sbx ls -q` already lists a sandbox named `ori`, restarts it with `sbx run -d --name ori`. Otherwise creates it: |
| 14 | 14 | ```bash |
| 15 | - sbx run -d claude . --template k33g/ori:0.0.1 --kit ./kits/ori --name ori -p 5555:8888 | |
| 15 | + sbx run -d claude . --template k33g/ori:0.0.2 --kit ./kits/ori --name ori -p 5555:8888/tcp | |
| 16 | 16 | ``` |
| 17 | 17 | 4. Polls `http://localhost:5555/healthz` every 2 s, up to 90 s (`healthTimeoutSeconds`). If the server never answers it still opens the app and tells you where to look: `sbx exec ori cat /var/log/sbx-kit-startup.log`. |
| 18 | 18 | 5. Opens `ori-desktop.app`, which auto-connects to the server URL it remembered last time (`~/Library/Application Support/ori-desktop/settings.json`, key `serverUrl`). Set it to `http://localhost:5555` on the first connection screen. |
| @@ -12,7 +12,7 @@ What it does, in order: | |||
| 12 | 2. Checks that `ori-desktop/build/bin/ori-desktop.app` exists; otherwise shows how to build it (`cd ori-desktop && wails build && xattr -cr build/bin/ori-desktop.app`). | 12 | 2. Checks that `ori-desktop/build/bin/ori-desktop.app` exists; otherwise shows how to build it (`cd ori-desktop && wails build && xattr -cr build/bin/ori-desktop.app`). |
| 13 | 3. If `sbx ls -q` already lists a sandbox named `ori`, restarts it with `sbx run -d --name ori`. Otherwise creates it: | 13 | 3. If `sbx ls -q` already lists a sandbox named `ori`, restarts it with `sbx run -d --name ori`. Otherwise creates it: |
| 14 | ```bash | 14 | ```bash |
| 15 | - sbx run -d claude . --template k33g/ori:0.0.1 --kit ./kits/ori --name ori -p 5555:8888 | 15 | + sbx run -d claude . --template k33g/ori:0.0.2 --kit ./kits/ori --name ori -p 5555:8888/tcp |
| 16 | ``` | 16 | ``` |
| 17 | 4. Polls `http://localhost:5555/healthz` every 2 s, up to 90 s (`healthTimeoutSeconds`). If the server never answers it still opens the app and tells you where to look: `sbx exec ori cat /var/log/sbx-kit-startup.log`. | 17 | 4. Polls `http://localhost:5555/healthz` every 2 s, up to 90 s (`healthTimeoutSeconds`). If the server never answers it still opens the app and tells you where to look: `sbx exec ori cat /var/log/sbx-kit-startup.log`. |
| 18 | 5. Opens `ori-desktop.app`, which auto-connects to the server URL it remembered last time (`~/Library/Application Support/ori-desktop/settings.json`, key `serverUrl`). Set it to `http://localhost:5555` on the first connection screen. | 18 | 5. Opens `ori-desktop.app`, which auto-connects to the server URL it remembered last time (`~/Library/Application Support/ori-desktop/settings.json`, key `serverUrl`). Set it to `http://localhost:5555` on the first connection screen. |
modified
scripts/launch-ori.applescript +0 -0 | Binary files a/scripts/launch-ori.applescript and b/scripts/launch-ori.applescript differ |
| Binary files a/scripts/launch-ori.applescript and b/scripts/launch-ori.applescript differ | Binary files a/scripts/launch-ori.applescript and b/scripts/launch-ori.applescript differ |
deleted
seven-story.md +0 -55 | deleted file mode 100644 | ||
| @@ -1,55 +0,0 @@ | ||
| 1 | -# Frequency of Self | |
| 2 | - | |
| 3 | -**Agent: Riker** | |
| 4 | - | |
| 5 | -Seven of Nine stood in the Voyager's astrometrics lab, surrounded by the comforting precision of stellar cartography. The darkness of the room was punctuated by thousands of glowing data points—stars, nebulae, spatial anomalies—each one catalogued, measured, understood. | |
| 6 | - | |
| 7 | -"You've been here for fourteen hours straight," Kathryn Janeway's voice came from the doorway, gentle but firm. | |
| 8 | - | |
| 9 | -"Efficiency," Seven replied without turning. "I can complete the Astrometrics survey in—" | |
| 10 | - | |
| 11 | -"Seven." Janeway stepped into the star field, her face illuminated by the blue-white glow of a nearby pulsar. "That's not what I asked." | |
| 12 | - | |
| 13 | -Seven's hands stilled on the console. The question Janeway hadn't asked hung in the air between them, as visible as the holographic stars. | |
| 14 | - | |
| 15 | -"I am... struggling with a paradox," Seven finally admitted. | |
| 16 | - | |
| 17 | -Janeway moved to stand beside her, studying the star chart. "Tell me." | |
| 18 | - | |
| 19 | -"The Borg's concept of perfection is mathematical. Absolute. Add complexity, eliminate redundancy, optimize all functions." Seven's voice held that peculiar flatness it took on when she discussed her former Collective. "But humanity's concept of perfection is... contradictory." | |
| 20 | - | |
| 21 | -She pulled up a new display—not stars this time, but a complex probability matrix. "I have analyzed 4,327 human literary works, 12,482 personal logs, and 847 philosophical texts. In 94.3% of cases, humans describe 'perfect' moments that are inefficient, redundant, or even counterproductive." | |
| 22 | - | |
| 23 | -Seven zoomed in on a specific data point. "The Doctor recently described his time singing opera with Ensign Kim as 'perfect,' despite the fact that they made seventeen errors in tempo and pitch. Lieutenant Paris called watching a sunset on an M-class planet 'perfect,' though it served no tactical or scientific purpose. You yourself—" | |
| 24 | - | |
| 25 | -"Called our coffee yesterday morning perfect, even though we were late for the staff meeting," Janeway finished with a smile. | |
| 26 | - | |
| 27 | -"Yes." Seven's hands gripped the edge of the console. "I do not understand how something flawed can be perfect. It is... illogical. And yet..." | |
| 28 | - | |
| 29 | -"And yet?" Janeway prompted gently. | |
| 30 | - | |
| 31 | -Seven's voice dropped to barely above a whisper. "Last night, I helped Naomi Wildman construct a model of a subspace manifold for her science project. We made numerous errors. The scale was incorrect. The materials were inadequate. By any objective measure, it was deeply flawed." | |
| 32 | - | |
| 33 | -She paused, and when she continued, there was something almost vulnerable in her tone. "Naomi said it was 'perfect.' And I... agreed with her." | |
| 34 | - | |
| 35 | -Janeway said nothing, letting the silence stretch. | |
| 36 | - | |
| 37 | -"The Borg were wrong," Seven said finally, the words coming out like a confession. "Perfection is not the elimination of imperfection. It is..." She struggled, her assimilation-trained mind wrestling with concepts that couldn't be reduced to data. "It is finding value in the inefficiency. Meaning in the redundancy. Beauty in the flaw." | |
| 38 | - | |
| 39 | -"You're learning to be human," Janeway said softly. | |
| 40 | - | |
| 41 | -"I am learning that being human is not something one completes," Seven corrected. "It is not a state to be achieved, like optimal efficiency. It is a process. An ongoing... adaptation." | |
| 42 | - | |
| 43 | -She turned to face Janeway fully. "I will never be perfectly human, Captain. I will always be partially Borg. But perhaps that is acceptable. Perhaps perfection is not about eliminating what I was, but about integrating who I am becoming." | |
| 44 | - | |
| 45 | -Janeway reached out and squeezed Seven's shoulder. "That sounds pretty perfect to me." | |
| 46 | - | |
| 47 | -Seven allowed herself a small smile—still rare, still uncertain, but genuine. "Inefficient sentiment. But... appreciated." | |
| 48 | - | |
| 49 | -After Janeway left, Seven returned to her star charts. But before she resumed her work, she did something new. She pulled up an image from the ship's database: the flawed subspace manifold she and Naomi had built, photographed before they'd taken it to the science fair. | |
| 50 | - | |
| 51 | -She added it to her personal files, archived under a new category she created specifically for this purpose: | |
| 52 | - | |
| 53 | -*Imperfect Perfection.* | |
| 54 | - | |
| 55 | -Then Seven of Nine, former Borg drone, current human-in-progress, went back to mapping the stars, secure in the knowledge that sometimes the most important journeys weren't through space at all. | |
| deleted file mode 100644 | |||
| @@ -1,55 +0,0 @@ | |||
| 1 | -# Frequency of Self | ||
| 2 | - | ||
| 3 | -**Agent: Riker** | ||
| 4 | - | ||
| 5 | -Seven of Nine stood in the Voyager's astrometrics lab, surrounded by the comforting precision of stellar cartography. The darkness of the room was punctuated by thousands of glowing data points—stars, nebulae, spatial anomalies—each one catalogued, measured, understood. | ||
| 6 | - | ||
| 7 | -"You've been here for fourteen hours straight," Kathryn Janeway's voice came from the doorway, gentle but firm. | ||
| 8 | - | ||
| 9 | -"Efficiency," Seven replied without turning. "I can complete the Astrometrics survey in—" | ||
| 10 | - | ||
| 11 | -"Seven." Janeway stepped into the star field, her face illuminated by the blue-white glow of a nearby pulsar. "That's not what I asked." | ||
| 12 | - | ||
| 13 | -Seven's hands stilled on the console. The question Janeway hadn't asked hung in the air between them, as visible as the holographic stars. | ||
| 14 | - | ||
| 15 | -"I am... struggling with a paradox," Seven finally admitted. | ||
| 16 | - | ||
| 17 | -Janeway moved to stand beside her, studying the star chart. "Tell me." | ||
| 18 | - | ||
| 19 | -"The Borg's concept of perfection is mathematical. Absolute. Add complexity, eliminate redundancy, optimize all functions." Seven's voice held that peculiar flatness it took on when she discussed her former Collective. "But humanity's concept of perfection is... contradictory." | ||
| 20 | - | ||
| 21 | -She pulled up a new display—not stars this time, but a complex probability matrix. "I have analyzed 4,327 human literary works, 12,482 personal logs, and 847 philosophical texts. In 94.3% of cases, humans describe 'perfect' moments that are inefficient, redundant, or even counterproductive." | ||
| 22 | - | ||
| 23 | -Seven zoomed in on a specific data point. "The Doctor recently described his time singing opera with Ensign Kim as 'perfect,' despite the fact that they made seventeen errors in tempo and pitch. Lieutenant Paris called watching a sunset on an M-class planet 'perfect,' though it served no tactical or scientific purpose. You yourself—" | ||
| 24 | - | ||
| 25 | -"Called our coffee yesterday morning perfect, even though we were late for the staff meeting," Janeway finished with a smile. | ||
| 26 | - | ||
| 27 | -"Yes." Seven's hands gripped the edge of the console. "I do not understand how something flawed can be perfect. It is... illogical. And yet..." | ||
| 28 | - | ||
| 29 | -"And yet?" Janeway prompted gently. | ||
| 30 | - | ||
| 31 | -Seven's voice dropped to barely above a whisper. "Last night, I helped Naomi Wildman construct a model of a subspace manifold for her science project. We made numerous errors. The scale was incorrect. The materials were inadequate. By any objective measure, it was deeply flawed." | ||
| 32 | - | ||
| 33 | -She paused, and when she continued, there was something almost vulnerable in her tone. "Naomi said it was 'perfect.' And I... agreed with her." | ||
| 34 | - | ||
| 35 | -Janeway said nothing, letting the silence stretch. | ||
| 36 | - | ||
| 37 | -"The Borg were wrong," Seven said finally, the words coming out like a confession. "Perfection is not the elimination of imperfection. It is..." She struggled, her assimilation-trained mind wrestling with concepts that couldn't be reduced to data. "It is finding value in the inefficiency. Meaning in the redundancy. Beauty in the flaw." | ||
| 38 | - | ||
| 39 | -"You're learning to be human," Janeway said softly. | ||
| 40 | - | ||
| 41 | -"I am learning that being human is not something one completes," Seven corrected. "It is not a state to be achieved, like optimal efficiency. It is a process. An ongoing... adaptation." | ||
| 42 | - | ||
| 43 | -She turned to face Janeway fully. "I will never be perfectly human, Captain. I will always be partially Borg. But perhaps that is acceptable. Perhaps perfection is not about eliminating what I was, but about integrating who I am becoming." | ||
| 44 | - | ||
| 45 | -Janeway reached out and squeezed Seven's shoulder. "That sounds pretty perfect to me." | ||
| 46 | - | ||
| 47 | -Seven allowed herself a small smile—still rare, still uncertain, but genuine. "Inefficient sentiment. But... appreciated." | ||
| 48 | - | ||
| 49 | -After Janeway left, Seven returned to her star charts. But before she resumed her work, she did something new. She pulled up an image from the ship's database: the flawed subspace manifold she and Naomi had built, photographed before they'd taken it to the science fair. | ||
| 50 | - | ||
| 51 | -She added it to her personal files, archived under a new category she created specifically for this purpose: | ||
| 52 | - | ||
| 53 | -*Imperfect Perfection.* | ||
| 54 | - | ||
| 55 | -Then Seven of Nine, former Borg drone, current human-in-progress, went back to mapping the stars, secure in the knowledge that sometimes the most important journeys weren't through space at all. | ||
modified
template/Dockerfile +18 -6 | @@ -49,11 +49,23 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -o /o | ||
| 49 | 49 | ############################################################## |
| 50 | 50 | # Claude Code ACP adapter, fetched natively then copied over # |
| 51 | 51 | ############################################################## |
| 52 | -# Installed in a $BUILDPLATFORM stage (the package is JavaScript, and its | |
| 53 | -# vendored binaries ship for every platform) so the final stage needs no RUN | |
| 54 | -# at all — a multi-arch build never touches qemu. | |
| 52 | +# @agentclientprotocol/claude-agent-acp drives Claude Code through the Claude | |
| 53 | +# Agent SDK, which ships a current Claude Code CLI (2.1.274 with SDK 0.3.274) | |
| 54 | +# as a per-platform optional dependency (@anthropic-ai/claude-agent-sdk-linux- | |
| 55 | +# x64, -linux-arm64, …). The Zed adapter it replaces bundled CLI 2.1.44, which | |
| 56 | +# the API now rejects for current models ("version 2.1.251 or newer required"). | |
| 57 | +# | |
| 58 | +# Still a $BUILDPLATFORM stage (native npm, no qemu), but npm must be told | |
| 59 | +# which platform's CLI to fetch: --os/--cpu select the optional dependency. | |
| 60 | +# npm speaks Node's arch names, so Docker's "amd64" has to become "x64" — with | |
| 61 | +# --cpu=amd64 npm silently installs no native SDK at all and the adapter | |
| 62 | +# fails at runtime. | |
| 55 | 63 | FROM --platform=$BUILDPLATFORM node:${NODE_VERSION}-bookworm AS adapter |
| 56 | -RUN npm install -g --prefix /adapter @zed-industries/claude-code-acp | |
| 64 | +ARG TARGETARCH | |
| 65 | +RUN npm_cpu="$TARGETARCH"; [ "$TARGETARCH" = "amd64" ] && npm_cpu=x64; \ | |
| 66 | + npm install -g --prefix /adapter --os=linux --cpu="$npm_cpu" --no-audit --no-fund \ | |
| 67 | + @agentclientprotocol/claude-agent-acp \ | |
| 68 | + && test -d /adapter/lib/node_modules/@agentclientprotocol/claude-agent-acp/node_modules/@anthropic-ai/claude-agent-sdk-linux-"$npm_cpu" | |
| 57 | 69 | |
| 58 | 70 | ################################################### |
| 59 | 71 | # Final image: claude-code sandbox template + ori # |
| @@ -61,7 +73,7 @@ RUN npm install -g --prefix /adapter @zed-industries/claude-code-acp | ||
| 61 | 73 | FROM docker/sandbox-templates:claude-code |
| 62 | 74 | |
| 63 | 75 | # The adapter lands in the template's npm prefix, which is agent-owned and on |
| 64 | -# PATH — so `claude-code-acp` resolves and the sandbox never needs npx to | |
| 76 | +# PATH — so `claude-agent-acp` resolves and the sandbox never needs npx to | |
| 65 | 77 | # download it at runtime. |
| 66 | 78 | COPY --from=adapter --chown=agent:agent /adapter/ /usr/local/share/npm-global/ |
| 67 | 79 | |
| @@ -73,4 +85,4 @@ EXPOSE 8888 | ||
| 73 | 85 | |
| 74 | 86 | # Standalone-run default. Inside a sandbox the ori kit starts the server |
| 75 | 87 | # instead (the runtime overrides CMD with its own supervisor). |
| 76 | -CMD [ "ori", "--addr", ":8888", "--agent-cmd", "claude-code-acp", "--cwd", "/home/agent/workspace" ] | |
| 88 | +CMD [ "ori", "--addr", ":8888", "--agent-cmd", "claude-agent-acp", "--cwd", "/home/agent/workspace" ] | |
| @@ -49,11 +49,23 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -o /o | |||
| 49 | ############################################################## | 49 | ############################################################## |
| 50 | # Claude Code ACP adapter, fetched natively then copied over # | 50 | # Claude Code ACP adapter, fetched natively then copied over # |
| 51 | ############################################################## | 51 | ############################################################## |
| 52 | -# Installed in a $BUILDPLATFORM stage (the package is JavaScript, and its | 52 | +# @agentclientprotocol/claude-agent-acp drives Claude Code through the Claude |
| 53 | -# vendored binaries ship for every platform) so the final stage needs no RUN | 53 | +# Agent SDK, which ships a current Claude Code CLI (2.1.274 with SDK 0.3.274) |
| 54 | -# at all — a multi-arch build never touches qemu. | 54 | +# as a per-platform optional dependency (@anthropic-ai/claude-agent-sdk-linux- |
| 55 | +# x64, -linux-arm64, …). The Zed adapter it replaces bundled CLI 2.1.44, which | ||
| 56 | +# the API now rejects for current models ("version 2.1.251 or newer required"). | ||
| 57 | +# | ||
| 58 | +# Still a $BUILDPLATFORM stage (native npm, no qemu), but npm must be told | ||
| 59 | +# which platform's CLI to fetch: --os/--cpu select the optional dependency. | ||
| 60 | +# npm speaks Node's arch names, so Docker's "amd64" has to become "x64" — with | ||
| 61 | +# --cpu=amd64 npm silently installs no native SDK at all and the adapter | ||
| 62 | +# fails at runtime. | ||
| 55 | FROM --platform=$BUILDPLATFORM node:${NODE_VERSION}-bookworm AS adapter | 63 | FROM --platform=$BUILDPLATFORM node:${NODE_VERSION}-bookworm AS adapter |
| 56 | -RUN npm install -g --prefix /adapter @zed-industries/claude-code-acp | 64 | +ARG TARGETARCH |
| 65 | +RUN npm_cpu="$TARGETARCH"; [ "$TARGETARCH" = "amd64" ] && npm_cpu=x64; \ | ||
| 66 | + npm install -g --prefix /adapter --os=linux --cpu="$npm_cpu" --no-audit --no-fund \ | ||
| 67 | + @agentclientprotocol/claude-agent-acp \ | ||
| 68 | + && test -d /adapter/lib/node_modules/@agentclientprotocol/claude-agent-acp/node_modules/@anthropic-ai/claude-agent-sdk-linux-"$npm_cpu" | ||
| 57 | 69 | ||
| 58 | ################################################### | 70 | ################################################### |
| 59 | # Final image: claude-code sandbox template + ori # | 71 | # Final image: claude-code sandbox template + ori # |
| @@ -61,7 +73,7 @@ RUN npm install -g --prefix /adapter @zed-industries/claude-code-acp | |||
| 61 | FROM docker/sandbox-templates:claude-code | 73 | FROM docker/sandbox-templates:claude-code |
| 62 | 74 | ||
| 63 | # The adapter lands in the template's npm prefix, which is agent-owned and on | 75 | # The adapter lands in the template's npm prefix, which is agent-owned and on |
| 64 | -# PATH — so `claude-code-acp` resolves and the sandbox never needs npx to | 76 | +# PATH — so `claude-agent-acp` resolves and the sandbox never needs npx to |
| 65 | # download it at runtime. | 77 | # download it at runtime. |
| 66 | COPY --from=adapter --chown=agent:agent /adapter/ /usr/local/share/npm-global/ | 78 | COPY --from=adapter --chown=agent:agent /adapter/ /usr/local/share/npm-global/ |
| 67 | 79 | ||
| @@ -73,4 +85,4 @@ EXPOSE 8888 | |||
| 73 | 85 | ||
| 74 | # Standalone-run default. Inside a sandbox the ori kit starts the server | 86 | # Standalone-run default. Inside a sandbox the ori kit starts the server |
| 75 | # instead (the runtime overrides CMD with its own supervisor). | 87 | # instead (the runtime overrides CMD with its own supervisor). |
| 76 | -CMD [ "ori", "--addr", ":8888", "--agent-cmd", "claude-code-acp", "--cwd", "/home/agent/workspace" ] | 88 | +CMD [ "ori", "--addr", ":8888", "--agent-cmd", "claude-agent-acp", "--cwd", "/home/agent/workspace" ] |
modified
template/build.sh +1 -1 | @@ -12,7 +12,7 @@ | ||
| 12 | 12 | # docker buildx create --name ori-builder --driver docker-container --use |
| 13 | 13 | set -euo pipefail |
| 14 | 14 | |
| 15 | -VERSION="${1:-0.0.1}" | |
| 15 | +VERSION="${1:-0.0.2}" | |
| 16 | 16 | IMAGE="k33g/ori" |
| 17 | 17 | PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}" |
| 18 | 18 | |
| @@ -12,7 +12,7 @@ | |||
| 12 | # docker buildx create --name ori-builder --driver docker-container --use | 12 | # docker buildx create --name ori-builder --driver docker-container --use |
| 13 | set -euo pipefail | 13 | set -euo pipefail |
| 14 | 14 | ||
| 15 | -VERSION="${1:-0.0.1}" | 15 | +VERSION="${1:-0.0.2}" |
| 16 | IMAGE="k33g/ori" | 16 | IMAGE="k33g/ori" |
| 17 | PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}" | 17 | PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}" |
| 18 | 18 | ||
modified
ui/package.json +1 -1 | @@ -7,7 +7,7 @@ | ||
| 7 | 7 | "dev": "vite", |
| 8 | 8 | "build": "tsc -b && vite build", |
| 9 | 9 | "typecheck": "tsc -b", |
| 10 | - "test": "vitest run", | |
| 10 | + "test": "NODE_OPTIONS=--no-experimental-webstorage vitest run", | |
| 11 | 11 | "predev": "node scripts/copy-icons.mjs", |
| 12 | 12 | "prebuild": "node scripts/copy-icons.mjs" |
| 13 | 13 | }, |
| @@ -7,7 +7,7 @@ | |||
| 7 | "dev": "vite", | 7 | "dev": "vite", |
| 8 | "build": "tsc -b && vite build", | 8 | "build": "tsc -b && vite build", |
| 9 | "typecheck": "tsc -b", | 9 | "typecheck": "tsc -b", |
| 10 | - "test": "vitest run", | 10 | + "test": "NODE_OPTIONS=--no-experimental-webstorage vitest run", |
| 11 | "predev": "node scripts/copy-icons.mjs", | 11 | "predev": "node scripts/copy-icons.mjs", |
| 12 | "prebuild": "node scripts/copy-icons.mjs" | 12 | "prebuild": "node scripts/copy-icons.mjs" |
| 13 | }, | 13 | }, |
modified
ui/src/components/Markdown.tsx +8 -2 | @@ -16,7 +16,11 @@ export function Markdown({ text }: { text: string }) { | ||
| 16 | 16 | const components: Components = { |
| 17 | 17 | pre: ({ children, ...props }) => { |
| 18 | 18 | // Extract code content from pre > code structure |
| 19 | - const codeElement = children as React.ReactElement; | |
| 19 | + // react-markdown hands `pre` its rendered <code> child; type its props so | |
| 20 | + // the string body can be extracted for the copy button. | |
| 21 | + const codeElement = children as React.ReactElement<{ | |
| 22 | + children?: unknown; | |
| 23 | + }>; | |
| 20 | 24 | const codeContent = |
| 21 | 25 | codeElement?.props?.children && |
| 22 | 26 | typeof codeElement.props.children === "string" |
| @@ -25,7 +29,9 @@ export function Markdown({ text }: { text: string }) { | ||
| 25 | 29 | |
| 26 | 30 | return ( |
| 27 | 31 | <div className="code-block-wrapper"> |
| 28 | - {codeContent && <CopyButton content={codeContent} label="Copy code" />} | |
| 32 | + {codeContent && ( | |
| 33 | + <CopyButton content={codeContent} label="Copy code" /> | |
| 34 | + )} | |
| 29 | 35 | <pre {...props}>{children}</pre> |
| 30 | 36 | </div> |
| 31 | 37 | ); |
| @@ -16,7 +16,11 @@ export function Markdown({ text }: { text: string }) { | |||
| 16 | const components: Components = { | 16 | const components: Components = { |
| 17 | pre: ({ children, ...props }) => { | 17 | pre: ({ children, ...props }) => { |
| 18 | // Extract code content from pre > code structure | 18 | // Extract code content from pre > code structure |
| 19 | - const codeElement = children as React.ReactElement; | 19 | + // react-markdown hands `pre` its rendered <code> child; type its props so |
| 20 | + // the string body can be extracted for the copy button. | ||
| 21 | + const codeElement = children as React.ReactElement<{ | ||
| 22 | + children?: unknown; | ||
| 23 | + }>; | ||
| 20 | const codeContent = | 24 | const codeContent = |
| 21 | codeElement?.props?.children && | 25 | codeElement?.props?.children && |
| 22 | typeof codeElement.props.children === "string" | 26 | typeof codeElement.props.children === "string" |
| @@ -25,7 +29,9 @@ export function Markdown({ text }: { text: string }) { | |||
| 25 | 29 | ||
| 26 | return ( | 30 | return ( |
| 27 | <div className="code-block-wrapper"> | 31 | <div className="code-block-wrapper"> |
| 28 | - {codeContent && <CopyButton content={codeContent} label="Copy code" />} | 32 | + {codeContent && ( |
| 33 | + <CopyButton content={codeContent} label="Copy code" /> | ||
| 34 | + )} | ||
| 29 | <pre {...props}>{children}</pre> | 35 | <pre {...props}>{children}</pre> |
| 30 | </div> | 36 | </div> |
| 31 | ); | 37 | ); |
modified
ui/src/components/ToolCallCard.test.tsx +41 -1 | @@ -1,7 +1,7 @@ | ||
| 1 | 1 | import { render, screen } from "@testing-library/react"; |
| 2 | 2 | import { describe, expect, it } from "vitest"; |
| 3 | 3 | import type { ToolCall } from "../reducer"; |
| 4 | -import { ToolCallCard } from "./ToolCallCard"; | |
| 4 | +import { ToolCallCard, contentText, toolContentText } from "./ToolCallCard"; | |
| 5 | 5 | |
| 6 | 6 | function call(overrides: Partial<ToolCall>): ToolCall { |
| 7 | 7 | return { |
| @@ -68,3 +68,43 @@ describe("ToolCallCard", () => { | ||
| 68 | 68 | expect(screen.getByText("bold")).toBeDefined(); |
| 69 | 69 | }); |
| 70 | 70 | }); |
| 71 | + | |
| 72 | +describe("toolContentText", () => { | |
| 73 | + it("returns the text of content blocks", () => { | |
| 74 | + expect( | |
| 75 | + contentText({ type: "content", content: { type: "text", text: "hi" } }), | |
| 76 | + ).toBe("hi"); | |
| 77 | + }); | |
| 78 | + | |
| 79 | + it("flattens a diff into labelled path, old and new sections", () => { | |
| 80 | + expect( | |
| 81 | + contentText({ type: "diff", path: "a.go", oldText: "x", newText: "y" }), | |
| 82 | + ).toBe("Path: a.go\n\nOld:\nx\n\nNew:\ny"); | |
| 83 | + }); | |
| 84 | + | |
| 85 | + it("omits diff sections that are absent", () => { | |
| 86 | + expect(contentText({ type: "diff", path: "a.go", newText: "y" })).toBe( | |
| 87 | + "Path: a.go\n\nNew:\ny", | |
| 88 | + ); | |
| 89 | + }); | |
| 90 | + | |
| 91 | + it("ignores terminal blocks and joins the rest with blank lines", () => { | |
| 92 | + expect( | |
| 93 | + toolContentText([ | |
| 94 | + { type: "terminal", terminalId: "t1" }, | |
| 95 | + { type: "content", content: { type: "text", text: "one" } }, | |
| 96 | + { type: "content", content: { type: "text", text: "" } }, | |
| 97 | + { type: "content", content: { type: "text", text: "two" } }, | |
| 98 | + ]), | |
| 99 | + ).toBe("one\n\ntwo"); | |
| 100 | + }); | |
| 101 | + | |
| 102 | + it("hides the copy button when the call has no textual content", () => { | |
| 103 | + render( | |
| 104 | + <ToolCallCard | |
| 105 | + call={call({ contents: [{ type: "terminal", terminalId: "t1" }] })} | |
| 106 | + />, | |
| 107 | + ); | |
| 108 | + expect(screen.queryByLabelText("Copy tool output")).toBeNull(); | |
| 109 | + }); | |
| 110 | +}); | |
| @@ -1,7 +1,7 @@ | |||
| 1 | import { render, screen } from "@testing-library/react"; | 1 | import { render, screen } from "@testing-library/react"; |
| 2 | import { describe, expect, it } from "vitest"; | 2 | import { describe, expect, it } from "vitest"; |
| 3 | import type { ToolCall } from "../reducer"; | 3 | import type { ToolCall } from "../reducer"; |
| 4 | -import { ToolCallCard } from "./ToolCallCard"; | 4 | +import { ToolCallCard, contentText, toolContentText } from "./ToolCallCard"; |
| 5 | 5 | ||
| 6 | function call(overrides: Partial<ToolCall>): ToolCall { | 6 | function call(overrides: Partial<ToolCall>): ToolCall { |
| 7 | return { | 7 | return { |
| @@ -68,3 +68,43 @@ describe("ToolCallCard", () => { | |||
| 68 | expect(screen.getByText("bold")).toBeDefined(); | 68 | expect(screen.getByText("bold")).toBeDefined(); |
| 69 | }); | 69 | }); |
| 70 | }); | 70 | }); |
| 71 | + | ||
| 72 | +describe("toolContentText", () => { | ||
| 73 | + it("returns the text of content blocks", () => { | ||
| 74 | + expect( | ||
| 75 | + contentText({ type: "content", content: { type: "text", text: "hi" } }), | ||
| 76 | + ).toBe("hi"); | ||
| 77 | + }); | ||
| 78 | + | ||
| 79 | + it("flattens a diff into labelled path, old and new sections", () => { | ||
| 80 | + expect( | ||
| 81 | + contentText({ type: "diff", path: "a.go", oldText: "x", newText: "y" }), | ||
| 82 | + ).toBe("Path: a.go\n\nOld:\nx\n\nNew:\ny"); | ||
| 83 | + }); | ||
| 84 | + | ||
| 85 | + it("omits diff sections that are absent", () => { | ||
| 86 | + expect(contentText({ type: "diff", path: "a.go", newText: "y" })).toBe( | ||
| 87 | + "Path: a.go\n\nNew:\ny", | ||
| 88 | + ); | ||
| 89 | + }); | ||
| 90 | + | ||
| 91 | + it("ignores terminal blocks and joins the rest with blank lines", () => { | ||
| 92 | + expect( | ||
| 93 | + toolContentText([ | ||
| 94 | + { type: "terminal", terminalId: "t1" }, | ||
| 95 | + { type: "content", content: { type: "text", text: "one" } }, | ||
| 96 | + { type: "content", content: { type: "text", text: "" } }, | ||
| 97 | + { type: "content", content: { type: "text", text: "two" } }, | ||
| 98 | + ]), | ||
| 99 | + ).toBe("one\n\ntwo"); | ||
| 100 | + }); | ||
| 101 | + | ||
| 102 | + it("hides the copy button when the call has no textual content", () => { | ||
| 103 | + render( | ||
| 104 | + <ToolCallCard | ||
| 105 | + call={call({ contents: [{ type: "terminal", terminalId: "t1" }] })} | ||
| 106 | + />, | ||
| 107 | + ); | ||
| 108 | + expect(screen.queryByLabelText("Copy tool output")).toBeNull(); | ||
| 109 | + }); | ||
| 110 | +}); | ||
modified
ui/src/components/ToolCallCard.tsx +44 -22 | @@ -34,26 +34,50 @@ const statusLabels: Record<string, string> = { | ||
| 34 | 34 | failed: "failed", |
| 35 | 35 | }; |
| 36 | 36 | |
| 37 | +/** | |
| 38 | + * contentText flattens one tool-call content block into plain text for the | |
| 39 | + * copy button: a "content" block's text, or a diff's path / old / new | |
| 40 | + * sections. Anything else (terminal handles, …) yields "". | |
| 41 | + * | |
| 42 | + * @example | |
| 43 | + * contentText({ type: "content", content: { type: "text", text: "hi" } }) // "hi" | |
| 44 | + */ | |
| 45 | +export function contentText(content: AcpToolCallContent): string { | |
| 46 | + switch (content.type) { | |
| 47 | + case "content": | |
| 48 | + return content.content?.text ?? ""; | |
| 49 | + case "diff": | |
| 50 | + return diffText(content); | |
| 51 | + default: | |
| 52 | + return ""; | |
| 53 | + } | |
| 54 | +} | |
| 55 | + | |
| 56 | +function diffText(diff: { | |
| 57 | + path?: string; | |
| 58 | + oldText?: string | null; | |
| 59 | + newText?: string | null; | |
| 60 | +}): string { | |
| 61 | + const parts: string[] = []; | |
| 62 | + if (diff.path) parts.push(`Path: ${diff.path}`); | |
| 63 | + if (diff.oldText) parts.push(`Old:\n${diff.oldText}`); | |
| 64 | + if (diff.newText) parts.push(`New:\n${diff.newText}`); | |
| 65 | + return parts.join("\n\n"); | |
| 66 | +} | |
| 67 | + | |
| 68 | +/** | |
| 69 | + * toolContentText joins the textual content of a whole tool call, skipping | |
| 70 | + * empty blocks, so the copy button copies exactly what the card shows. | |
| 71 | + * | |
| 72 | + * @example | |
| 73 | + * toolContentText([]) // "" | |
| 74 | + */ | |
| 75 | +export function toolContentText(contents: AcpToolCallContent[]): string { | |
| 76 | + return contents.map(contentText).filter(Boolean).join("\n\n"); | |
| 77 | +} | |
| 78 | + | |
| 37 | 79 | export function ToolCallCard({ call }: { call: ToolCall }) { |
| 38 | - // Extract all textual content for copy button | |
| 39 | - const getToolContent = (): string => { | |
| 40 | - return call.contents | |
| 41 | - .map((content) => { | |
| 42 | - if (content.type === "content" && content.content?.text) { | |
| 43 | - return content.content.text; | |
| 44 | - } | |
| 45 | - if (content.type === "diff") { | |
| 46 | - const parts = []; | |
| 47 | - if (content.path) parts.push(`Path: ${content.path}`); | |
| 48 | - if (content.oldText) parts.push(`Old:\n${content.oldText}`); | |
| 49 | - if (content.newText) parts.push(`New:\n${content.newText}`); | |
| 50 | - return parts.join("\n\n"); | |
| 51 | - } | |
| 52 | - return ""; | |
| 53 | - }) | |
| 54 | - .filter(Boolean) | |
| 55 | - .join("\n\n"); | |
| 56 | - }; | |
| 80 | + const copyText = toolContentText(call.contents); | |
| 57 | 81 | |
| 58 | 82 | return ( |
| 59 | 83 | <details className={`tool tool-${call.status}`}> |
| @@ -67,9 +91,7 @@ export function ToolCallCard({ call }: { call: ToolCall }) { | ||
| 67 | 91 | <span className={`tool-status tool-status-${call.status}`}> |
| 68 | 92 | {statusLabels[call.status] ?? call.status} |
| 69 | 93 | </span> |
| 70 | - {getToolContent() && ( | |
| 71 | - <CopyButton content={getToolContent()} label="Copy tool output" /> | |
| 72 | - )} | |
| 94 | + {copyText && <CopyButton content={copyText} label="Copy tool output" />} | |
| 73 | 95 | </summary> |
| 74 | 96 | <div className="tool-body"> |
| 75 | 97 | {call.locations.length > 0 && ( |
| @@ -34,26 +34,50 @@ const statusLabels: Record<string, string> = { | |||
| 34 | failed: "failed", | 34 | failed: "failed", |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | +/** | ||
| 38 | + * contentText flattens one tool-call content block into plain text for the | ||
| 39 | + * copy button: a "content" block's text, or a diff's path / old / new | ||
| 40 | + * sections. Anything else (terminal handles, …) yields "". | ||
| 41 | + * | ||
| 42 | + * @example | ||
| 43 | + * contentText({ type: "content", content: { type: "text", text: "hi" } }) // "hi" | ||
| 44 | + */ | ||
| 45 | +export function contentText(content: AcpToolCallContent): string { | ||
| 46 | + switch (content.type) { | ||
| 47 | + case "content": | ||
| 48 | + return content.content?.text ?? ""; | ||
| 49 | + case "diff": | ||
| 50 | + return diffText(content); | ||
| 51 | + default: | ||
| 52 | + return ""; | ||
| 53 | + } | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +function diffText(diff: { | ||
| 57 | + path?: string; | ||
| 58 | + oldText?: string | null; | ||
| 59 | + newText?: string | null; | ||
| 60 | +}): string { | ||
| 61 | + const parts: string[] = []; | ||
| 62 | + if (diff.path) parts.push(`Path: ${diff.path}`); | ||
| 63 | + if (diff.oldText) parts.push(`Old:\n${diff.oldText}`); | ||
| 64 | + if (diff.newText) parts.push(`New:\n${diff.newText}`); | ||
| 65 | + return parts.join("\n\n"); | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +/** | ||
| 69 | + * toolContentText joins the textual content of a whole tool call, skipping | ||
| 70 | + * empty blocks, so the copy button copies exactly what the card shows. | ||
| 71 | + * | ||
| 72 | + * @example | ||
| 73 | + * toolContentText([]) // "" | ||
| 74 | + */ | ||
| 75 | +export function toolContentText(contents: AcpToolCallContent[]): string { | ||
| 76 | + return contents.map(contentText).filter(Boolean).join("\n\n"); | ||
| 77 | +} | ||
| 78 | + | ||
| 37 | export function ToolCallCard({ call }: { call: ToolCall }) { | 79 | export function ToolCallCard({ call }: { call: ToolCall }) { |
| 38 | - // Extract all textual content for copy button | 80 | + const copyText = toolContentText(call.contents); |
| 39 | - const getToolContent = (): string => { | ||
| 40 | - return call.contents | ||
| 41 | - .map((content) => { | ||
| 42 | - if (content.type === "content" && content.content?.text) { | ||
| 43 | - return content.content.text; | ||
| 44 | - } | ||
| 45 | - if (content.type === "diff") { | ||
| 46 | - const parts = []; | ||
| 47 | - if (content.path) parts.push(`Path: ${content.path}`); | ||
| 48 | - if (content.oldText) parts.push(`Old:\n${content.oldText}`); | ||
| 49 | - if (content.newText) parts.push(`New:\n${content.newText}`); | ||
| 50 | - return parts.join("\n\n"); | ||
| 51 | - } | ||
| 52 | - return ""; | ||
| 53 | - }) | ||
| 54 | - .filter(Boolean) | ||
| 55 | - .join("\n\n"); | ||
| 56 | - }; | ||
| 57 | 81 | ||
| 58 | return ( | 82 | return ( |
| 59 | <details className={`tool tool-${call.status}`}> | 83 | <details className={`tool tool-${call.status}`}> |
| @@ -67,9 +91,7 @@ export function ToolCallCard({ call }: { call: ToolCall }) { | |||
| 67 | <span className={`tool-status tool-status-${call.status}`}> | 91 | <span className={`tool-status tool-status-${call.status}`}> |
| 68 | {statusLabels[call.status] ?? call.status} | 92 | {statusLabels[call.status] ?? call.status} |
| 69 | </span> | 93 | </span> |
| 70 | - {getToolContent() && ( | 94 | + {copyText && <CopyButton content={copyText} label="Copy tool output" />} |
| 71 | - <CopyButton content={getToolContent()} label="Copy tool output" /> | ||
| 72 | - )} | ||
| 73 | </summary> | 95 | </summary> |
| 74 | <div className="tool-body"> | 96 | <div className="tool-body"> |
| 75 | {call.locations.length > 0 && ( | 97 | {call.locations.length > 0 && ( |
modified
ui/tsconfig.tsbuildinfo +1 -1 | @@ -1 +1 @@ | ||
| 1 | -{"root":["./src/App.test.tsx","./src/App.tsx","./src/api.ts","./src/lang.test.ts","./src/lang.ts","./src/main.tsx","./src/mentions.test.ts","./src/mentions.ts","./src/monaco-setup.ts","./src/protocol.ts","./src/reducer.test.ts","./src/reducer.ts","./src/store.ts","./src/theme.test.ts","./src/theme.ts","./src/useCompletion.ts","./src/workspace.test.ts","./src/workspace.ts","./src/ws.test.ts","./src/ws.ts","./src/components/AsciiDocView.test.tsx","./src/components/AsciiDocView.tsx","./src/components/ChatThread.tsx","./src/components/CodeView.tsx","./src/components/CompletionPopup.tsx","./src/components/DrawioView.test.tsx","./src/components/DrawioView.tsx","./src/components/EditorPane.test.tsx","./src/components/EditorPane.tsx","./src/components/FileTree.test.tsx","./src/components/FileTree.tsx","./src/components/ImageView.tsx","./src/components/InlineText.test.tsx","./src/components/InlineText.tsx","./src/components/Markdown.tsx","./src/components/MonacoViewer.tsx","./src/components/PermissionPrompt.tsx","./src/components/PlanView.tsx","./src/components/PreviewPane.test.tsx","./src/components/PreviewPane.tsx","./src/components/PromptInput.test.tsx","./src/components/PromptInput.tsx","./src/components/ResizeHandle.test.tsx","./src/components/ResizeHandle.tsx","./src/components/TerminalPane.test.tsx","./src/components/TerminalPane.tsx","./src/components/ToolCallCard.test.tsx","./src/components/ToolCallCard.tsx","./src/components/WorkingIndicator.test.tsx","./src/components/WorkingIndicator.tsx","./src/components/Workspace.test.tsx","./src/components/Workspace.tsx","./vite.config.ts"],"version":"5.9.3"} | |
| \ No newline at end of file | ||
| 1 | +{"root":["./src/app.test.tsx","./src/app.tsx","./src/api.ts","./src/lang.test.ts","./src/lang.ts","./src/main.tsx","./src/mentions.test.ts","./src/mentions.ts","./src/monaco-setup.ts","./src/protocol.ts","./src/reducer.test.ts","./src/reducer.ts","./src/store.ts","./src/theme.test.ts","./src/theme.ts","./src/usecompletion.ts","./src/workspace.test.ts","./src/workspace.ts","./src/ws.test.ts","./src/ws.ts","./src/components/asciidocview.test.tsx","./src/components/asciidocview.tsx","./src/components/chatthread.tsx","./src/components/codeview.tsx","./src/components/completionpopup.tsx","./src/components/copybutton.test.tsx","./src/components/copybutton.tsx","./src/components/drawioview.test.tsx","./src/components/drawioview.tsx","./src/components/editorpane.test.tsx","./src/components/editorpane.tsx","./src/components/filetree.test.tsx","./src/components/filetree.tsx","./src/components/imageview.tsx","./src/components/inlinetext.test.tsx","./src/components/inlinetext.tsx","./src/components/markdown.tsx","./src/components/monacoviewer.tsx","./src/components/permissionprompt.tsx","./src/components/planview.tsx","./src/components/previewpane.test.tsx","./src/components/previewpane.tsx","./src/components/promptinput.test.tsx","./src/components/promptinput.tsx","./src/components/resizehandle.test.tsx","./src/components/resizehandle.tsx","./src/components/terminalpane.test.tsx","./src/components/terminalpane.tsx","./src/components/toolcallcard.test.tsx","./src/components/toolcallcard.tsx","./src/components/workingindicator.test.tsx","./src/components/workingindicator.tsx","./src/components/workspace.test.tsx","./src/components/workspace.tsx","./vite.config.ts"],"version":"5.9.3"} | |
| \ No newline at end of file | ||
| @@ -1 +1 @@ | |||
| 1 | -{"root":["./src/App.test.tsx","./src/App.tsx","./src/api.ts","./src/lang.test.ts","./src/lang.ts","./src/main.tsx","./src/mentions.test.ts","./src/mentions.ts","./src/monaco-setup.ts","./src/protocol.ts","./src/reducer.test.ts","./src/reducer.ts","./src/store.ts","./src/theme.test.ts","./src/theme.ts","./src/useCompletion.ts","./src/workspace.test.ts","./src/workspace.ts","./src/ws.test.ts","./src/ws.ts","./src/components/AsciiDocView.test.tsx","./src/components/AsciiDocView.tsx","./src/components/ChatThread.tsx","./src/components/CodeView.tsx","./src/components/CompletionPopup.tsx","./src/components/DrawioView.test.tsx","./src/components/DrawioView.tsx","./src/components/EditorPane.test.tsx","./src/components/EditorPane.tsx","./src/components/FileTree.test.tsx","./src/components/FileTree.tsx","./src/components/ImageView.tsx","./src/components/InlineText.test.tsx","./src/components/InlineText.tsx","./src/components/Markdown.tsx","./src/components/MonacoViewer.tsx","./src/components/PermissionPrompt.tsx","./src/components/PlanView.tsx","./src/components/PreviewPane.test.tsx","./src/components/PreviewPane.tsx","./src/components/PromptInput.test.tsx","./src/components/PromptInput.tsx","./src/components/ResizeHandle.test.tsx","./src/components/ResizeHandle.tsx","./src/components/TerminalPane.test.tsx","./src/components/TerminalPane.tsx","./src/components/ToolCallCard.test.tsx","./src/components/ToolCallCard.tsx","./src/components/WorkingIndicator.test.tsx","./src/components/WorkingIndicator.tsx","./src/components/Workspace.test.tsx","./src/components/Workspace.tsx","./vite.config.ts"],"version":"5.9.3"} | ||
| \ No newline at end of file | \ No newline at end of file | ||
| 1 | +{"root":["./src/app.test.tsx","./src/app.tsx","./src/api.ts","./src/lang.test.ts","./src/lang.ts","./src/main.tsx","./src/mentions.test.ts","./src/mentions.ts","./src/monaco-setup.ts","./src/protocol.ts","./src/reducer.test.ts","./src/reducer.ts","./src/store.ts","./src/theme.test.ts","./src/theme.ts","./src/usecompletion.ts","./src/workspace.test.ts","./src/workspace.ts","./src/ws.test.ts","./src/ws.ts","./src/components/asciidocview.test.tsx","./src/components/asciidocview.tsx","./src/components/chatthread.tsx","./src/components/codeview.tsx","./src/components/completionpopup.tsx","./src/components/copybutton.test.tsx","./src/components/copybutton.tsx","./src/components/drawioview.test.tsx","./src/components/drawioview.tsx","./src/components/editorpane.test.tsx","./src/components/editorpane.tsx","./src/components/filetree.test.tsx","./src/components/filetree.tsx","./src/components/imageview.tsx","./src/components/inlinetext.test.tsx","./src/components/inlinetext.tsx","./src/components/markdown.tsx","./src/components/monacoviewer.tsx","./src/components/permissionprompt.tsx","./src/components/planview.tsx","./src/components/previewpane.test.tsx","./src/components/previewpane.tsx","./src/components/promptinput.test.tsx","./src/components/promptinput.tsx","./src/components/resizehandle.test.tsx","./src/components/resizehandle.tsx","./src/components/terminalpane.test.tsx","./src/components/terminalpane.tsx","./src/components/toolcallcard.test.tsx","./src/components/toolcallcard.tsx","./src/components/workingindicator.test.tsx","./src/components/workingindicator.tsx","./src/components/workspace.test.tsx","./src/components/workspace.tsx","./vite.config.ts"],"version":"5.9.3"} | ||
| \ No newline at end of file | \ No newline at end of file | ||