diff --git a/.claude/skills/evm-wallet-docker-e2e/SKILL.md b/.claude/skills/evm-wallet-docker-e2e/SKILL.md new file mode 100644 index 0000000000..bc0f97cf41 --- /dev/null +++ b/.claude/skills/evm-wallet-docker-e2e/SKILL.md @@ -0,0 +1,97 @@ +--- +name: evm-wallet-docker-e2e +description: Run the evm-wallet Docker e2e tests (build, start stack, wait for healthy, test, diagnose failures). +--- + +Run all commands from the repo root unless noted. + +## 1. Verify Docker is running + +```bash +docker info 2>&1 | head -5 +``` + +If it fails, tell the user Docker is not running and ask them to start Docker Desktop (or the daemon), then wait for confirmation before continuing. + +## 2. Build the repo and Docker images + +```bash +yarn workspace @ocap/evm-wallet-experiment docker:build 2>&1 | tail -30 +``` + +This builds the full monorepo then builds the Docker images. It may take a few minutes. Report any errors from the tail output. + +## 3. Tear down any existing stack, then start fresh + +Always bring the stack down first to avoid stale container state (e.g. spent delegation budgets from a previous run leaking into the new run). + +```bash +yarn workspace @ocap/evm-wallet-experiment docker:down 2>&1 | tail -10 +``` + +Then start the stack: + +```bash +yarn workspace @ocap/evm-wallet-experiment docker:ensure-logs && \ + yarn workspace @ocap/evm-wallet-experiment docker:compose up -d 2>&1 | tail -20 +``` + +## 4. Wait for all services to be healthy + +Poll every 10 seconds (up to 3 minutes / 18 attempts). All 8 services must reach `(healthy)` status before proceeding: + +- `evm`, `bundler` +- `kernel-home-bundler-7702`, `kernel-away-bundler-7702` +- `kernel-home-bundler-hybrid`, `kernel-away-bundler-hybrid` +- `kernel-home-peer-relay`, `kernel-away-peer-relay` + +```bash +i=0; while [ $i -lt 18 ]; do + i=$((i+1)) + ps_out=$(yarn workspace @ocap/evm-wallet-experiment docker:ps 2>&1) + healthy=$(echo "$ps_out" | grep -c "(healthy)" || true) + echo "Attempt $i/18: $healthy/8 healthy" + if [ "$healthy" -ge 8 ]; then echo "Stack ready."; break; fi + if [ "$i" -eq 18 ]; then echo "Timed out:"; echo "$ps_out"; exit 1; fi + sleep 10 +done +``` + +If the loop exits with a timeout, show the last `docker:ps` output and stop — do not proceed to the tests. + +## 5. Run the e2e tests + +```bash +yarn workspace @ocap/evm-wallet-experiment test:e2e:docker 2>&1 | tail -80 +``` + +The vitest reporter also writes structured results to `packages/evm-wallet-experiment/logs/test-results.json`. + +## 6. Diagnose failures + +If tests fail, investigate in this order: + +### Structured test results + +```bash +cat packages/evm-wallet-experiment/logs/test-results.json +``` + +Look at the `testResults` array for failed tests and their error messages. + +### Service logs + +Container logs are written to `packages/evm-wallet-experiment/logs/`. Check the service(s) relevant to the failing test mode first: + +```bash +tail -150 packages/evm-wallet-experiment/logs/.log +``` + +Service log files: + +- `evm.log` — Anvil chain (check for on-chain errors) +- `kernel-home-bundler-7702.log`, `kernel-away-bundler-7702.log` +- `kernel-home-bundler-hybrid.log`, `kernel-away-bundler-hybrid.log` +- `kernel-home-peer-relay.log`, `kernel-away-peer-relay.log` + +Start with the pair(s) involved in the failing test, then `evm.log` for on-chain issues. diff --git a/packages/evm-wallet-experiment/README.md b/packages/evm-wallet-experiment/README.md index 8d3d30b198..b7fae4307e 100644 --- a/packages/evm-wallet-experiment/README.md +++ b/packages/evm-wallet-experiment/README.md @@ -1,6 +1,6 @@ # @ocap/evm-wallet-experiment -A capability-driven EVM wallet implemented as an OCAP kernel subcluster. It uses the [MetaMask Delegation Framework (Gator)](https://github.com/MetaMask/delegation-framework) for delegated transaction authority. **Hybrid** smart accounts submit ERC-4337 UserOperations through a bundler; **stateless EIP-7702** home accounts (mnemonic path) redeem delegations with normal EIP-1559 transactions via your JSON-RPC provider (e.g. Infura), without a bundler. The wallet subcluster isolates key management, Ethereum RPC communication, and delegation lifecycle into separate vats, enforcing the principle of least authority across the entire signing pipeline. +A capability-driven EVM wallet, implemented as an OCAP kernel subcluster. It uses the [MetaMask Delegation Framework (Gator)](https://github.com/MetaMask/delegation-framework) for delegated transaction authority. **Hybrid** smart accounts submit ERC-4337 UserOperations through a bundler; **stateless EIP-7702** home accounts (mnemonic path) redeem delegations with normal EIP-1559 transactions via your JSON-RPC provider (e.g. Infura), without a bundler. The wallet subcluster isolates key management, Ethereum RPC communication, and delegation lifecycle into separate vats, enforcing the principle of least authority across the entire signing pipeline. For a deeper explanation of the components and data flow, see [How It Works](./docs/how-it-works.md). For deploying the wallet on a home device + VPS with OpenClaw, see the [Setup Guide](./docs/setup-guide.md). @@ -712,7 +712,7 @@ yarn workspace @ocap/evm-wallet-experiment build yarn workspace @ocap/evm-wallet-experiment lint:fix ``` -For Docker Compose setup (interactive simulation and E2E tests), see [docs/docker.md](./docs/docker.md). Docker Model Runner with `ai/qwen3.5:4B-UD-Q4_K_XL` is required for the interactive simulation's OpenClaw AI agent. +For Docker Compose setup (local demo and E2E tests), see [docs/docker.md](./docs/docker.md). Docker Model Runner with `ai/qwen3.5:4B-UD-Q4_K_XL` is required for the local demo's OpenClaw AI agent. ## Testing @@ -803,7 +803,7 @@ DELEGATION_MODE=bundler-7702 yarn workspace @ocap/evm-wallet-experiment test:e2e yarn workspace @ocap/evm-wallet-experiment docker:down ``` -Full home/away delegation flow across three delegation modes (`bundler-7702`, `bundler-hybrid`, `peer-relay`) running in parallel. The stack requires Docker Model Runner. See [docs/docker.md](./docs/docker.md) for prerequisites, stack details, and troubleshooting. For manual interactive simulation, see [docs/simulation.md](./docs/simulation.md). +Full home/away delegation flow across three delegation modes (`bundler-7702`, `bundler-hybrid`, `peer-relay`) running in parallel. The stack requires Docker Model Runner. See [docs/docker.md](./docs/docker.md) for prerequisites, stack details, and troubleshooting. For manual interactive simulation, see [docs/demo-local.md](./docs/demo-local.md). ## Supported Chains diff --git a/packages/evm-wallet-experiment/docker/.env.demo b/packages/evm-wallet-experiment/docker/.env.demo new file mode 100644 index 0000000000..7c2239e735 --- /dev/null +++ b/packages/evm-wallet-experiment/docker/.env.demo @@ -0,0 +1,3 @@ +# Used by `yarn docker:demo:up` (--env-file). Switches +# `kernel-away-bundler-7702` to the `demo` Dockerfile target (OpenClaw). +KERNEL_AWAY_7702_TARGET=demo diff --git a/packages/evm-wallet-experiment/docker/.env.interactive b/packages/evm-wallet-experiment/docker/.env.interactive deleted file mode 100644 index c475299070..0000000000 --- a/packages/evm-wallet-experiment/docker/.env.interactive +++ /dev/null @@ -1,3 +0,0 @@ -# Used by `yarn docker:compose:interactive` (--env-file). Switches -# `kernel-away-bundler-7702` to the `interactive` Dockerfile target (OpenClaw). -KERNEL_AWAY_7702_TARGET=interactive diff --git a/packages/evm-wallet-experiment/docker/Dockerfile.kernel-base b/packages/evm-wallet-experiment/docker/Dockerfile.kernel-base index c3d1ffc31f..5cc06bca37 100644 --- a/packages/evm-wallet-experiment/docker/Dockerfile.kernel-base +++ b/packages/evm-wallet-experiment/docker/Dockerfile.kernel-base @@ -62,11 +62,11 @@ COPY --from=builder /build /app RUN mkdir -p /logs /run/ocap # --------------------------------------------------------------------------- -# Target: interactive — kernel + OpenClaw + wallet plugin (used interactively) +# Target: demo — kernel + OpenClaw + wallet plugin (used in local demo) # --------------------------------------------------------------------------- -FROM kernel AS interactive +FROM kernel AS demo # OpenClaw loads local plugins as TypeScript via jiti (no extra TS runner in the image). -# `package.json` docker:interactive:setup starts the gateway via +# `package.json` docker:demo:setup starts the gateway via # `node /usr/local/lib/node_modules/openclaw/openclaw.mjs` (global bin PATH is unreliable under `docker exec`). RUN npm install -g openclaw@2026.4.1 diff --git a/packages/evm-wallet-experiment/docker/MAINTAINERS.md b/packages/evm-wallet-experiment/docker/MAINTAINERS.md index ac62092945..f303fe4448 100644 --- a/packages/evm-wallet-experiment/docker/MAINTAINERS.md +++ b/packages/evm-wallet-experiment/docker/MAINTAINERS.md @@ -1,6 +1,6 @@ # Docker stack — maintainer notes -Local E2E stack for `@ocap/evm-wallet-experiment`: Anvil + deployed contracts, Pimlico Alto, and six kernel containers (three `kernel-home-*` / `kernel-away-*` pairs). See `package.json` scripts (`docker:compose`, `test:e2e:docker`, etc.). Each pair is gated by a Compose **profile** (**`7702`**, **`4337`**, **`relay`**); **`yarn docker:up`** / **`docker:compose`** pass **all three** so Vitest Docker E2E and full-stack dev see every kernel. **`yarn docker:interactive:up`** enables **one** profile (default **`bundler-7702`** delegation mode → profile **`7702`**). Shared kernel **build / volumes / entrypoint / depends_on** live in root **`x-kernel-standard`**; **`x-kernel-build-core`** holds **`context`** / **`dockerfile`** so **`kernel-away-bundler-7702`** can set **`build.target`** from **`${KERNEL_AWAY_7702_TARGET:-kernel}`**. Per-pair **ports**, **`environment`**, and **`healthcheck.test`** stay explicit. +Local E2E stack for `@ocap/evm-wallet-experiment`: Anvil + deployed contracts, Pimlico Alto, and six kernel containers (three `kernel-home-*` / `kernel-away-*` pairs). See `package.json` scripts (`docker:compose`, `test:e2e:docker`, etc.). Each pair is gated by a Compose **profile** (**`7702`**, **`4337`**, **`relay`**); **`yarn docker:up`** / **`docker:compose`** pass **all three** so Vitest Docker E2E and full-stack dev see every kernel. **`yarn docker:demo:up`** enables **one** profile (default **`bundler-7702`** delegation mode → profile **`7702`**). Shared kernel **build / volumes / entrypoint / depends_on** live in root **`x-kernel-standard`**; **`x-kernel-build-core`** holds **`context`** / **`dockerfile`** so **`kernel-away-bundler-7702`** can set **`build.target`** from **`${KERNEL_AWAY_7702_TARGET:-kernel}`**. Per-pair **ports**, **`environment`**, and **`healthcheck.test`** stay explicit. ## Startup order @@ -30,7 +30,7 @@ Copy the top-level **Digest** (index), then set in `docker-compose.yml`: Keep the comment above that line in sync with the command you used. -### OpenClaw (interactive image only) +### OpenClaw (demo image only) `Dockerfile.kernel-base` installs a **fixed** global CLI version (`openclaw@…`). The gateway loads **`openclaw-plugin/index.ts`** via **jiti**; nothing in the image invokes `tsx`. Bump OpenClaw deliberately when you want new gateway behavior; avoid `@latest` here. @@ -62,16 +62,16 @@ Host-side scripts (e.g. `yarn docker:setup:wallets`) use the workspace **`tsx`** - **`yarn docker:up`** and **`yarn test:e2e:docker`** expect the full stack, including [**Compose `models`**](https://docs.docker.com/ai/compose/models-and-compose/) on each **`kernel-away-*`** service. That requires **Docker Compose v2.38+** and [**Docker Model Runner**](https://docs.docker.com/ai/model-runner/) enabled. - Top-level **`models.llm`** pins **`ai/qwen3.5:4B-UD-Q4_K_XL`** with **`context_size: 32768`** and **`runtime_flags: ['--ctx-size','32768']`** so llama.cpp does not stay at DMR’s 4096 default (OpenClaw + tools need more). Pull if needed: **`docker model pull ai/qwen3.5:4B-UD-Q4_K_XL`**. If requests still hit 4096, run **`docker model configure --context-size 32768 ai/qwen3.5:4B-UD-Q4_K_XL`** on the host and recreate containers. -- Vitest Docker E2E does **not** call the LLM today, but away containers still receive **`LLM_URL`** / **`LLM_MODEL`** for consistency with interactive OpenClaw and future tests. +- Vitest Docker E2E does **not** call the LLM today, but away containers still receive **`LLM_URL`** / **`LLM_MODEL`** for consistency with the demo OpenClaw stack and future tests. -## Interactive stack (`docker/.env.interactive` + one pair profile) +## Demo stack (`docker/.env.demo` + one pair profile) -- **`yarn docker:compose:interactive`** runs **`node docker/run-interactive-compose.mjs`**, which passes **`--env-file docker/.env.interactive`** ( **`KERNEL_AWAY_7702_TARGET=interactive`** for the 7702 away image) and **one** **`--profile`** (**`7702`**, **`4337`**, or **`relay`**). Default delegation mode is **`bundler-7702`** → profile **`7702`** (same mode strings as Docker E2E **`DELEGATION_MODE`**). -- **Choose the pair**: set **`OCAP_INTERACTIVE_PAIR`** to **`bundler-7702`**, **`bundler-hybrid`**, or **`peer-relay`**, or pass **`--pair `** before compose subcommands (after **`yarn … --`** if needed), e.g. **`yarn docker:interactive:up -- --pair bundler-hybrid`**. -- **`yarn docker:interactive:setup`** runs wallet setup; OpenClaw **`setup-openclaw.mjs`** + gateway run **only** when the pair is **`bundler-7702`** (the image with OpenClaw). Other pairs skip those steps with a short log line. -- OpenClaw UI history for 7702 lives under **`$HOME/.openclaw`** on the **`ocap-run`** volume; use **`yarn docker:interactive:reset-openclaw`** then **`yarn docker:interactive:setup`**, or **`docker compose … down -v`** for a full volume wipe. LLM wiring is **only** in **`docker-compose.yml`** (**`models:`**). +- **`yarn docker:compose:demo`** runs **`node docker/run-demo-compose.mjs`**, which passes **`--env-file docker/.env.demo`** ( **`KERNEL_AWAY_7702_TARGET=demo`** for the 7702 away image) and **one** **`--profile`** (**`7702`**, **`4337`**, or **`relay`**). Default delegation mode is **`bundler-7702`** → profile **`7702`** (same mode strings as Docker E2E **`DELEGATION_MODE`**). +- **Choose the pair**: set **`OCAP_DEMO_PAIR`** to **`bundler-7702`**, **`bundler-hybrid`**, or **`peer-relay`**, or pass **`--pair `** before compose subcommands (after **`yarn … --`** if needed), e.g. **`yarn docker:demo:up -- --pair bundler-hybrid`**. +- **`yarn docker:demo:setup`** runs wallet setup; OpenClaw **`setup-openclaw.mjs`** + gateway run **only** when the pair is **`bundler-7702`** (the image with OpenClaw). Other pairs skip those steps with a short log line. +- OpenClaw UI history for 7702 lives under **`$HOME/.openclaw`** on the **`ocap-run`** volume; use **`yarn docker:demo:reset-openclaw`** then **`yarn docker:demo:setup`**, or **`docker compose … down -v`** for a full volume wipe. LLM wiring is **only** in **`docker-compose.yml`** (**`models:`**). -**Raw `docker compose -f docker/docker-compose.yml up`** without **`--profile`** starts **evm** and **bundler** only (no kernels). Prefer **`yarn docker:up`** or the interactive scripts above. +**Raw `docker compose -f docker/docker-compose.yml up`** without **`--profile`** starts **evm** and **bundler** only (no kernels). Prefer **`yarn docker:up`** or the demo scripts above. ## `yarn docker:delegate` diff --git a/packages/evm-wallet-experiment/docker/attach.mjs b/packages/evm-wallet-experiment/docker/attach.mjs new file mode 100644 index 0000000000..3978756acc --- /dev/null +++ b/packages/evm-wallet-experiment/docker/attach.mjs @@ -0,0 +1,31 @@ +/* eslint-disable n/no-sync, n/no-process-env, n/no-process-exit */ +import { spawnSync } from 'node:child_process'; + +import { + awayServiceForDemoPair, + homeServiceForDemoPair, + demoDockerComposeArgs, + DEMO_PACKAGE_ROOT, +} from './demo-compose-lib.mjs'; + +const [side, ...rest] = process.argv.slice(2); + +if (side !== 'away' && side !== 'home') { + console.error(`Usage: attach.mjs [--pair ]`); + process.exit(1); +} + +const { pair, dockerArgs } = demoDockerComposeArgs(rest); +const service = + side === 'away' ? awayServiceForDemoPair(pair) : homeServiceForDemoPair(pair); + +const spawned = spawnSync( + 'docker', + [...dockerArgs, 'exec', '-it', service, 'bash'], + { + cwd: DEMO_PACKAGE_ROOT, + stdio: 'inherit', + env: process.env, + }, +); +process.exit(spawned.status ?? 1); diff --git a/packages/evm-wallet-experiment/docker/delegate.mjs b/packages/evm-wallet-experiment/docker/delegate.mjs new file mode 100644 index 0000000000..f4670cfb57 --- /dev/null +++ b/packages/evm-wallet-experiment/docker/delegate.mjs @@ -0,0 +1,46 @@ +/* eslint-disable n/no-sync, n/no-process-env, n/no-process-exit */ +import { spawnSync } from 'node:child_process'; + +import { + homeServiceForDemoPair, + demoDockerComposeArgs, + DEMO_PACKAGE_ROOT, +} from './demo-compose-lib.mjs'; + +const SCRIPT_ON_HOST = 'docker/create-delegation.mjs'; +const SCRIPT_IN_CONTAINER = + '/app/packages/evm-wallet-experiment/docker/create-delegation.mjs'; + +const argv = process.argv.slice(2); +const { pair, dockerArgs } = demoDockerComposeArgs(argv); +const home = homeServiceForDemoPair(pair); + +const cp = spawnSync( + 'docker', + [...dockerArgs, 'cp', SCRIPT_ON_HOST, `${home}:${SCRIPT_IN_CONTAINER}`], + { cwd: DEMO_PACKAGE_ROOT, stdio: 'inherit', env: process.env }, +); +if (cp.status !== 0) { + process.exit(cp.status ?? 1); +} + +const envArgs = ['--env', `DELEGATION_MODE=${pair}`]; +if (process.env.CAVEAT_ETH_LIMIT) { + envArgs.push('--env', `CAVEAT_ETH_LIMIT=${process.env.CAVEAT_ETH_LIMIT}`); +} + +const exec = spawnSync( + 'docker', + [ + ...dockerArgs, + 'exec', + ...envArgs, + home, + 'node', + '--conditions', + 'development', + SCRIPT_IN_CONTAINER, + ], + { cwd: DEMO_PACKAGE_ROOT, stdio: 'inherit', env: process.env }, +); +process.exit(exec.status ?? 1); diff --git a/packages/evm-wallet-experiment/docker/demo-compose-lib.mjs b/packages/evm-wallet-experiment/docker/demo-compose-lib.mjs new file mode 100644 index 0000000000..79d5890bd4 --- /dev/null +++ b/packages/evm-wallet-experiment/docker/demo-compose-lib.mjs @@ -0,0 +1,104 @@ +/* eslint-disable n/no-sync, n/no-process-env, n/no-process-exit, jsdoc/require-jsdoc */ +/** + * Shared parsing + `docker compose` argv for demo stack (one home/away pair). + * Keep delegation-mode keys in sync with `test/e2e/docker/helpers/docker-e2e-kernel-services.ts`. + */ +import { spawnSync } from 'node:child_process'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const dockerLibDir = dirname(fileURLToPath(import.meta.url)); +export const DEMO_PACKAGE_ROOT = join(dockerLibDir, '..'); + +const COMPOSE_FILE = join(DEMO_PACKAGE_ROOT, 'docker/docker-compose.yml'); +const ENV_FILE = join(DEMO_PACKAGE_ROOT, 'docker/.env.demo'); + +/** @type {Record} */ +export const DEMO_PAIR_TO_PROFILE = { + 'bundler-7702': '7702', + 'bundler-hybrid': '4337', + 'peer-relay': 'relay', +}; + +export const DEFAULT_DEMO_PAIR = 'bundler-7702'; + +export function awayServiceForDemoPair(pair) { + if (pair === 'bundler-7702') { + return 'kernel-away-bundler-7702'; + } + if (pair === 'bundler-hybrid') { + return 'kernel-away-bundler-hybrid'; + } + if (pair === 'peer-relay') { + return 'kernel-away-peer-relay'; + } + throw new Error(`Unknown demo pair: ${pair}`); +} + +export function homeServiceForDemoPair(pair) { + if (pair === 'bundler-7702') { + return 'kernel-home-bundler-7702'; + } + if (pair === 'bundler-hybrid') { + return 'kernel-home-bundler-hybrid'; + } + if (pair === 'peer-relay') { + return 'kernel-home-peer-relay'; + } + throw new Error(`Unknown demo pair: ${pair}`); +} + +export function parseDemoComposeArgv(argv) { + let pair = process.env.OCAP_DEMO_PAIR ?? DEFAULT_DEMO_PAIR; + const rest = [...argv]; + const i = rest.indexOf('--pair'); + if (i !== -1 && rest[i + 1]) { + pair = rest[i + 1]; + rest.splice(i, 2); + } + const profile = DEMO_PAIR_TO_PROFILE[pair]; + if (!profile) { + console.error( + `Unknown pair "${pair}". Use: ${Object.keys(DEMO_PAIR_TO_PROFILE).join(', ')} (env OCAP_DEMO_PAIR, or --pair before compose subcommands).`, + ); + process.exit(1); + } + return { pair, profile, rest }; +} + +export function demoDockerComposeArgs(argv) { + const { pair, profile, rest } = parseDemoComposeArgv(argv); + return { + pair, + profile, + rest, + dockerArgs: [ + 'compose', + '-f', + COMPOSE_FILE, + '--env-file', + ENV_FILE, + '--profile', + profile, + ...rest, + ], + }; +} + +export function runDemoCompose(argv) { + const { pair, profile, dockerArgs } = demoDockerComposeArgs(argv); + if (process.env.DEBUG_OCAP_DEMO_COMPOSE) { + console.error( + `[ocap demo compose] OCAP_DEMO_PAIR=${pair} profile=${profile}`, + ); + } + const spawned = spawnSync('docker', dockerArgs, { + cwd: DEMO_PACKAGE_ROOT, + stdio: 'inherit', + env: process.env, + }); + if (spawned.error) { + throw spawned.error; + } + process.exit(spawned.status ?? 1); +} diff --git a/packages/evm-wallet-experiment/docker/interactive-reset-openclaw.mjs b/packages/evm-wallet-experiment/docker/demo-reset-openclaw.mjs similarity index 63% rename from packages/evm-wallet-experiment/docker/interactive-reset-openclaw.mjs rename to packages/evm-wallet-experiment/docker/demo-reset-openclaw.mjs index 11d5f223e8..732b2a0512 100644 --- a/packages/evm-wallet-experiment/docker/interactive-reset-openclaw.mjs +++ b/packages/evm-wallet-experiment/docker/demo-reset-openclaw.mjs @@ -2,13 +2,13 @@ import { spawnSync } from 'node:child_process'; import { - awayServiceForInteractivePair, - interactiveDockerComposeArgs, - INTERACTIVE_PACKAGE_ROOT, -} from './interactive-compose-lib.mjs'; + awayServiceForDemoPair, + demoDockerComposeArgs, + DEMO_PACKAGE_ROOT, +} from './demo-compose-lib.mjs'; const argv = process.argv.slice(2); -const { pair, dockerArgs } = interactiveDockerComposeArgs(argv); +const { pair, dockerArgs } = demoDockerComposeArgs(argv); if (pair !== 'bundler-7702') { console.log( @@ -17,18 +17,18 @@ if (pair !== 'bundler-7702') { process.exit(0); } -const away = awayServiceForInteractivePair(pair); +const away = awayServiceForDemoPair(pair); const openclawDir = `/run/ocap/${away}/.openclaw`; const spawned = spawnSync( 'docker', [...dockerArgs, 'exec', away, 'rm', '-rf', openclawDir], - { cwd: INTERACTIVE_PACKAGE_ROOT, stdio: 'inherit', env: process.env }, + { cwd: DEMO_PACKAGE_ROOT, stdio: 'inherit', env: process.env }, ); if (spawned.status !== 0) { process.exit(spawned.status ?? 1); } console.log( - `OpenClaw state removed at ${openclawDir} on ocap-run volume. Run: yarn docker:interactive:setup`, + `OpenClaw state removed at ${openclawDir} on ocap-run volume. Run: yarn docker:demo:setup`, ); diff --git a/packages/evm-wallet-experiment/docker/interactive-setup.mjs b/packages/evm-wallet-experiment/docker/demo-setup.mjs similarity index 62% rename from packages/evm-wallet-experiment/docker/interactive-setup.mjs rename to packages/evm-wallet-experiment/docker/demo-setup.mjs index ed71d15ea3..a04ef56b07 100644 --- a/packages/evm-wallet-experiment/docker/interactive-setup.mjs +++ b/packages/evm-wallet-experiment/docker/demo-setup.mjs @@ -2,19 +2,19 @@ import { spawnSync } from 'node:child_process'; import { - awayServiceForInteractivePair, - interactiveDockerComposeArgs, - INTERACTIVE_PACKAGE_ROOT, -} from './interactive-compose-lib.mjs'; + awayServiceForDemoPair, + demoDockerComposeArgs, + DEMO_PACKAGE_ROOT, +} from './demo-compose-lib.mjs'; const argv = process.argv.slice(2); -const { pair, dockerArgs } = interactiveDockerComposeArgs(argv); +const { pair, dockerArgs } = demoDockerComposeArgs(argv); const wallets = spawnSync( 'yarn', ['tsx', 'test/e2e/docker/setup-wallets.ts', pair], { - cwd: INTERACTIVE_PACKAGE_ROOT, + cwd: DEMO_PACKAGE_ROOT, stdio: 'inherit', env: process.env, }, @@ -22,11 +22,11 @@ const wallets = spawnSync( if (wallets.status !== 0) { process.exit(wallets.status ?? 1); } -const away = awayServiceForInteractivePair(pair); +const away = awayServiceForDemoPair(pair); if (pair !== 'bundler-7702') { console.log( - 'OpenClaw setup skipped (interactive Dockerfile target + OpenClaw run only on kernel-away-bundler-7702).', + 'OpenClaw setup skipped (demo Dockerfile target + OpenClaw run only on kernel-away-bundler-7702).', ); process.exit(0); } @@ -40,7 +40,7 @@ const setupOpenclaw = spawnSync( 'node', '/app/packages/evm-wallet-experiment/docker/setup-openclaw.mjs', ], - { cwd: INTERACTIVE_PACKAGE_ROOT, stdio: 'inherit', env: process.env }, + { cwd: DEMO_PACKAGE_ROOT, stdio: 'inherit', env: process.env }, ); if (setupOpenclaw.status !== 0) { process.exit(setupOpenclaw.status ?? 1); @@ -57,12 +57,12 @@ const gateway = spawnSync( '/usr/local/lib/node_modules/openclaw/openclaw.mjs', 'gateway', ], - { cwd: INTERACTIVE_PACKAGE_ROOT, stdio: 'inherit', env: process.env }, + { cwd: DEMO_PACKAGE_ROOT, stdio: 'inherit', env: process.env }, ); if (gateway.status !== 0) { process.exit(gateway.status ?? 1); } console.log( - `OpenClaw configured + gateway started (${away}). Shell: OCAP_INTERACTIVE_PAIR=${pair} yarn docker:compose:interactive -- exec ${away} bash`, + `OpenClaw configured + gateway started (${away}). Shell: OCAP_DEMO_PAIR=${pair} yarn docker:demo:attach:away`, ); diff --git a/packages/evm-wallet-experiment/docker/docker-compose.yml b/packages/evm-wallet-experiment/docker/docker-compose.yml index c07d1ec2d1..8c1e6310ab 100644 --- a/packages/evm-wallet-experiment/docker/docker-compose.yml +++ b/packages/evm-wallet-experiment/docker/docker-compose.yml @@ -1,6 +1,6 @@ # Extension fields (ignored as services; hold YAML anchors for kernel DRY). # Three pairs: bundler-7702 (4011/4012), bundler-hybrid (4021/4022), peer-relay (4031/4032). -# Each pair is behind a Compose profile so `yarn docker:interactive:up` can start one pair; +# Each pair is behind a Compose profile so `yarn docker:demo:up` can start one pair; # E2E / `yarn docker:up` pass all three `--profile` flags: 7702, 4337, relay (see package.json `docker:compose`). x-kernel-build-core: &kernel-build-core context: ../../../ @@ -107,7 +107,7 @@ services: test: ['CMD', 'test', '-f', '/run/ocap/kernel-home-bundler-7702-ready.json'] - # Default target is `kernel` (E2E). Interactive: `docker/.env.interactive` sets KERNEL_AWAY_7702_TARGET=interactive. + # Default target is `kernel` (E2E). Demo: `docker/.env.demo` sets KERNEL_AWAY_7702_TARGET=demo. kernel-away-bundler-7702: <<: *kernel-standard profiles: diff --git a/packages/evm-wallet-experiment/docker/interactive-compose-lib.mjs b/packages/evm-wallet-experiment/docker/interactive-compose-lib.mjs deleted file mode 100644 index 7410d1c7bf..0000000000 --- a/packages/evm-wallet-experiment/docker/interactive-compose-lib.mjs +++ /dev/null @@ -1,94 +0,0 @@ -/* eslint-disable n/no-sync, n/no-process-env, n/no-process-exit, jsdoc/require-jsdoc */ -/** - * Shared parsing + `docker compose` argv for interactive stack (one home/away pair). - * Keep delegation-mode keys in sync with `test/e2e/docker/helpers/docker-e2e-kernel-services.ts`. - */ -import { spawnSync } from 'node:child_process'; -import { dirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const dockerLibDir = dirname(fileURLToPath(import.meta.url)); -export const INTERACTIVE_PACKAGE_ROOT = join(dockerLibDir, '..'); - -const COMPOSE_FILE = join( - INTERACTIVE_PACKAGE_ROOT, - 'docker/docker-compose.yml', -); -const ENV_FILE = join(INTERACTIVE_PACKAGE_ROOT, 'docker/.env.interactive'); - -/** @type {Record} */ -export const INTERACTIVE_PAIR_TO_PROFILE = { - 'bundler-7702': '7702', - 'bundler-hybrid': '4337', - 'peer-relay': 'relay', -}; - -export const DEFAULT_INTERACTIVE_PAIR = 'bundler-7702'; - -export function awayServiceForInteractivePair(pair) { - if (pair === 'bundler-7702') { - return 'kernel-away-bundler-7702'; - } - if (pair === 'bundler-hybrid') { - return 'kernel-away-bundler-hybrid'; - } - if (pair === 'peer-relay') { - return 'kernel-away-peer-relay'; - } - throw new Error(`Unknown interactive pair: ${pair}`); -} - -export function parseInteractiveComposeArgv(argv) { - let pair = process.env.OCAP_INTERACTIVE_PAIR ?? DEFAULT_INTERACTIVE_PAIR; - const rest = [...argv]; - const i = rest.indexOf('--pair'); - if (i !== -1 && rest[i + 1]) { - pair = rest[i + 1]; - rest.splice(i, 2); - } - const profile = INTERACTIVE_PAIR_TO_PROFILE[pair]; - if (!profile) { - console.error( - `Unknown pair "${pair}". Use: ${Object.keys(INTERACTIVE_PAIR_TO_PROFILE).join(', ')} (env OCAP_INTERACTIVE_PAIR, or --pair before compose subcommands).`, - ); - process.exit(1); - } - return { pair, profile, rest }; -} - -export function interactiveDockerComposeArgs(argv) { - const { pair, profile, rest } = parseInteractiveComposeArgv(argv); - return { - pair, - profile, - rest, - dockerArgs: [ - 'compose', - '-f', - COMPOSE_FILE, - '--env-file', - ENV_FILE, - '--profile', - profile, - ...rest, - ], - }; -} - -export function runInteractiveCompose(argv) { - const { pair, profile, dockerArgs } = interactiveDockerComposeArgs(argv); - if (process.env.DEBUG_OCAP_INTERACTIVE_COMPOSE) { - console.error( - `[ocap interactive compose] OCAP_INTERACTIVE_PAIR=${pair} profile=${profile}`, - ); - } - const spawned = spawnSync('docker', dockerArgs, { - cwd: INTERACTIVE_PACKAGE_ROOT, - stdio: 'inherit', - env: process.env, - }); - if (spawned.error) { - throw spawned.error; - } - process.exit(spawned.status ?? 1); -} diff --git a/packages/evm-wallet-experiment/docker/run-demo-compose.mjs b/packages/evm-wallet-experiment/docker/run-demo-compose.mjs new file mode 100644 index 0000000000..3a90d9dca4 --- /dev/null +++ b/packages/evm-wallet-experiment/docker/run-demo-compose.mjs @@ -0,0 +1,3 @@ +import { runDemoCompose } from './demo-compose-lib.mjs'; + +runDemoCompose(process.argv.slice(2)); diff --git a/packages/evm-wallet-experiment/docker/run-interactive-compose.mjs b/packages/evm-wallet-experiment/docker/run-interactive-compose.mjs deleted file mode 100644 index 6ce858da68..0000000000 --- a/packages/evm-wallet-experiment/docker/run-interactive-compose.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import { runInteractiveCompose } from './interactive-compose-lib.mjs'; - -runInteractiveCompose(process.argv.slice(2)); diff --git a/packages/evm-wallet-experiment/docs/simulation.md b/packages/evm-wallet-experiment/docs/demo-local.md similarity index 72% rename from packages/evm-wallet-experiment/docs/simulation.md rename to packages/evm-wallet-experiment/docs/demo-local.md index fa2f988e04..333400426d 100644 --- a/packages/evm-wallet-experiment/docs/simulation.md +++ b/packages/evm-wallet-experiment/docs/demo-local.md @@ -10,16 +10,16 @@ See [Docker setup](./docker.md) for prerequisites, build commands, and general t ```bash # 1. Start the stack (default pair: bundler-7702) -yarn workspace @ocap/evm-wallet-experiment docker:interactive:up +yarn workspace @ocap/evm-wallet-experiment docker:demo:up # 2. Initialize wallets and configure OpenClaw (once containers are healthy) -yarn workspace @ocap/evm-wallet-experiment docker:interactive:setup +yarn workspace @ocap/evm-wallet-experiment docker:demo:setup # 3. Create a delegation from home to away and push it over the peer connection yarn workspace @ocap/evm-wallet-experiment docker:delegate # 4. Stop everything -yarn workspace @ocap/evm-wallet-experiment docker:interactive:down +yarn workspace @ocap/evm-wallet-experiment docker:demo:down ``` --- @@ -35,18 +35,18 @@ The Docker Compose stack mimics a real deployment: Two modes of operation: -| Mode | What runs | When to use | -| --------------- | ------------------------------ | ------------------------------------------------ | -| **Interactive** | One home/away pair | Manual testing, development, AI agent simulation | -| **E2E test** | All three pairs simultaneously | `yarn test:e2e:docker` automated tests | +| Mode | What runs | When to use | +| ------------ | ------------------------------ | ------------------------------------------------ | +| **Demo** | One home/away pair | Manual testing, development, AI agent simulation | +| **E2E test** | All three pairs simultaneously | `yarn test:e2e:docker` automated tests | -This guide covers interactive mode. +This guide covers demo mode. --- ## Delegation modes -Interactive mode supports three delegation strategies. Choose one per session. +Demo mode supports three delegation strategies. Choose one per session. | Mode | Home account type | How away redeems | QUIC ports | | ------------------------ | ----------------------------------- | ----------------------------------------------- | ----------- | @@ -60,44 +60,44 @@ The OpenClaw AI agent is only available on the `bundler-7702` pair. ## Commands -### `docker:interactive:up` +### `docker:demo:up` ```bash -yarn workspace @ocap/evm-wallet-experiment docker:interactive:up +yarn workspace @ocap/evm-wallet-experiment docker:demo:up # or with a specific pair: -yarn workspace @ocap/evm-wallet-experiment docker:interactive:up -- --pair bundler-hybrid +yarn workspace @ocap/evm-wallet-experiment docker:demo:up -- --pair bundler-hybrid ``` Starts the EVM, bundler, and one home/away kernel pair. Builds containers if needed. -The away container for `bundler-7702` is built with the `interactive` Dockerfile target, which includes the OpenClaw CLI. +The away container for `bundler-7702` is built with the `demo` Dockerfile target, which includes the OpenClaw CLI. -Set `OCAP_INTERACTIVE_PAIR` to avoid passing `--pair` every time: +Set `OCAP_DEMO_PAIR` to avoid passing `--pair` every time: ```bash -export OCAP_INTERACTIVE_PAIR=peer-relay -yarn workspace @ocap/evm-wallet-experiment docker:interactive:up +export OCAP_DEMO_PAIR=peer-relay +yarn workspace @ocap/evm-wallet-experiment docker:demo:up ``` The `--pair` flag takes precedence over the environment variable. -### `docker:interactive:down` +### `docker:demo:down` ```bash -yarn workspace @ocap/evm-wallet-experiment docker:interactive:down +yarn workspace @ocap/evm-wallet-experiment docker:demo:down ``` -Stops and removes containers. The `ocap-run` (state) and `ocap-logs` volumes are preserved, so the next `docker:interactive:up` resumes where it left off. +Stops and removes containers. The `ocap-run` (state) and `ocap-logs` volumes are preserved, so the next `docker:demo:up` resumes where it left off. To do a full wipe including volumes: ```bash -docker compose -f packages/evm-wallet-experiment/docker/docker-compose.yml down -v +yarn workspace @ocap/evm-wallet-experiment docker:down:volumes ``` -### `docker:interactive:setup` +### `docker:demo:setup` ```bash -yarn workspace @ocap/evm-wallet-experiment docker:interactive:setup +yarn workspace @ocap/evm-wallet-experiment docker:demo:setup ``` Runs after containers are healthy. Does the following in order: @@ -118,7 +118,7 @@ yarn workspace @ocap/evm-wallet-experiment docker:delegate Copies `docker/create-delegation.mjs` into the home kernel container and executes it there. The script: -1. Reads the delegation context files written by `docker:interactive:setup` +1. Reads the delegation context files written by `docker:demo:setup` 2. Resolves the correct delegate address for the chosen mode: - `bundler-*`: away's smart account (or EOA fallback) - `peer-relay`: home's smart account (redeems on behalf of home) @@ -126,7 +126,7 @@ Copies `docker/create-delegation.mjs` into the home kernel container and execute 4. Calls `createDelegation()` on the home coordinator 5. Pushes the signed delegation to the away kernel over the live CapTP connection -Requires `docker:interactive:setup` to have been run first. +Requires `docker:demo:setup` to have been run first. ### `docker:setup:wallets` @@ -134,15 +134,15 @@ Requires `docker:interactive:setup` to have been run first. yarn workspace @ocap/evm-wallet-experiment docker:setup:wallets ``` -Runs only the wallet initialization step from `docker:interactive:setup` (no OpenClaw). Useful if you want to reinitialize wallet state without touching OpenClaw config. +Runs only the wallet initialization step from `docker:demo:setup` (no OpenClaw). Useful if you want to reinitialize wallet state without touching OpenClaw config. -### `docker:interactive:reset-openclaw` +### `docker:demo:reset-openclaw` ```bash -yarn workspace @ocap/evm-wallet-experiment docker:interactive:reset-openclaw +yarn workspace @ocap/evm-wallet-experiment docker:demo:reset-openclaw ``` -Removes the `.openclaw/` state directory from the away container (conversation history, agent workspace). Only applies to the `bundler-7702` pair; other pairs print a message and exit. Does not stop containers or touch wallet state. Re-run `docker:interactive:setup` after this to reinitialize. +Removes the `.openclaw/` state directory from the away container (conversation history, agent workspace). Only applies to the `bundler-7702` pair; other pairs print a message and exit. Does not stop containers or touch wallet state. Re-run `docker:demo:setup` after this to reinitialize. ### `docker:logs` @@ -158,13 +158,13 @@ Tails logs from all running Compose services. Useful for watching delegation red ```bash # Stop the current pair -yarn workspace @ocap/evm-wallet-experiment docker:interactive:down +yarn workspace @ocap/evm-wallet-experiment docker:demo:down # Start a different pair -yarn workspace @ocap/evm-wallet-experiment docker:interactive:up -- --pair peer-relay +yarn workspace @ocap/evm-wallet-experiment docker:demo:up -- --pair peer-relay # Re-initialize wallets for the new pair -yarn workspace @ocap/evm-wallet-experiment docker:interactive:setup +yarn workspace @ocap/evm-wallet-experiment docker:demo:setup # Create a delegation yarn workspace @ocap/evm-wallet-experiment docker:delegate @@ -176,7 +176,7 @@ Each pair uses a different BIP-44 address index on the shared test mnemonic (`te ## OpenClaw AI agent (`bundler-7702` only) -When the stack is started with `bundler-7702` (the default) and `docker:interactive:setup` has run, the away container hosts an OpenClaw gateway that exposes wallet operations as AI tools. +When the stack is started with `bundler-7702` (the default) and `docker:demo:setup` has run, the away container hosts an OpenClaw gateway that exposes wallet operations as AI tools. The OpenClaw gateway runs on `localhost:18789` inside the away container and uses the Docker Model Runner LLM (`ai/qwen3.5:4B-UD-Q4_K_XL` by default, injected via Compose's `models` feature). @@ -199,8 +199,8 @@ Available wallet tools via the OpenClaw plugin: To reset conversation history without restarting: ```bash -yarn workspace @ocap/evm-wallet-experiment docker:interactive:reset-openclaw -yarn workspace @ocap/evm-wallet-experiment docker:interactive:setup +yarn workspace @ocap/evm-wallet-experiment docker:demo:reset-openclaw +yarn workspace @ocap/evm-wallet-experiment docker:demo:setup ``` --- @@ -231,19 +231,19 @@ After setup, the `ocap-run` Docker volume (mounted at `/run/ocap` inside contain ## Troubleshooting -**`docker:interactive:setup` fails** +**`docker:demo:setup` fails** - Containers may still be starting up — wait until all services are healthy, then retry -- Check with: `docker compose -f packages/evm-wallet-experiment/docker/docker-compose.yml --profile 7702 ps` +- Check with: `yarn workspace @ocap/evm-wallet-experiment docker:ps` **`docker:delegate` fails with "context not found"** -- `docker:interactive:setup` must complete successfully before running `docker:delegate` +- `docker:demo:setup` must complete successfully before running `docker:delegate` - The context files (`docker-delegation-home.json`, `docker-delegation-away.json`) must exist in the shared volume **OpenClaw gateway not responding** - Only available on `bundler-7702`; other pairs do not start the gateway -- Run `docker:interactive:reset-openclaw` then `docker:interactive:setup` to reinitialize +- Run `docker:demo:reset-openclaw` then `docker:demo:setup` to reinitialize For general Docker issues (build failures, port conflicts, volume corruption), see [Docker setup](./docker.md#troubleshooting). diff --git a/packages/evm-wallet-experiment/docs/docker.md b/packages/evm-wallet-experiment/docs/docker.md index 5c34131211..302a80bbd3 100644 --- a/packages/evm-wallet-experiment/docs/docker.md +++ b/packages/evm-wallet-experiment/docs/docker.md @@ -1,6 +1,6 @@ # Docker Compose Setup -Reference for the Docker Compose stack used by both the [interactive simulation](./simulation.md) and the automated Docker E2E tests. +Reference for the Docker Compose stack used by both the [local demo](./demo-local.md) and the automated Docker E2E tests. --- @@ -8,7 +8,7 @@ Reference for the Docker Compose stack used by both the [interactive simulation] - **Docker** with Compose v2.38+ - **Node.js 22** and **Yarn** (for host-side setup commands) -- **Docker Model Runner** with `ai/qwen3.5:4B-UD-Q4_K_XL` pulled — required for the OpenClaw AI agent on the `bundler-7702` interactive pair +- **Docker Model Runner** with `ai/qwen3.5:4B-UD-Q4_K_XL` pulled — required for the OpenClaw AI agent on the `bundler-7702` demo pair ```bash docker model pull ai/qwen3.5:4B-UD-Q4_K_XL @@ -28,12 +28,12 @@ yarn workspace @ocap/evm-wallet-experiment docker:build:force The away kernel for `bundler-7702` has two Dockerfile targets: -| Target | Used by | Includes | -| ------------- | ------------------- | ---------------------------- | -| `kernel` | E2E tests (default) | Kernel daemon only | -| `interactive` | Interactive mode | Kernel daemon + OpenClaw CLI | +| Target | Used by | Includes | +| -------- | ------------------- | ---------------------------- | +| `kernel` | E2E tests (default) | Kernel daemon only | +| `demo` | Demo mode | Kernel daemon + OpenClaw CLI | -The `interactive` target is activated automatically by `docker:interactive:up` via `docker/.env.interactive`. +The `demo` target is activated automatically by `docker:demo:up` via `docker/.env.demo`. --- @@ -41,16 +41,16 @@ The `interactive` target is activated automatically by `docker:interactive:up` v ### Services -| Service | Image | Purpose | -| ---------------------------- | -------------------- | ----------------------------------------------------------------------------- | -| `evm` | Anvil (Foundry) | Local EVM chain; deploys Delegation Framework contracts on startup; port 8545 | -| `bundler` | Alto | ERC-4337 bundler pointing at `evm`; port 4337 | -| `kernel-home-bundler-7702` | kernel | Home kernel, SRP keyring, 7702 smart account; QUIC port 4011 | -| `kernel-away-bundler-7702` | kernel / interactive | Away kernel, throwaway keyring; QUIC port 4012 | -| `kernel-home-bundler-hybrid` | kernel | Home kernel, hybrid smart account; QUIC port 4021 | -| `kernel-away-bundler-hybrid` | kernel | Away kernel; QUIC port 4022 | -| `kernel-home-peer-relay` | kernel | Home kernel, 7702 smart account; QUIC port 4031 | -| `kernel-away-peer-relay` | kernel | Away kernel, no bundler (relays to home); QUIC port 4032 | +| Service | Image | Purpose | +| ---------------------------- | --------------- | ----------------------------------------------------------------------------- | +| `evm` | Anvil (Foundry) | Local EVM chain; deploys Delegation Framework contracts on startup; port 8545 | +| `bundler` | Alto | ERC-4337 bundler pointing at `evm`; port 4337 | +| `kernel-home-bundler-7702` | kernel | Home kernel, SRP keyring, 7702 smart account; QUIC port 4011 | +| `kernel-away-bundler-7702` | kernel / demo | Away kernel, throwaway keyring; QUIC port 4012 | +| `kernel-home-bundler-hybrid` | kernel | Home kernel, hybrid smart account; QUIC port 4021 | +| `kernel-away-bundler-hybrid` | kernel | Away kernel; QUIC port 4022 | +| `kernel-home-peer-relay` | kernel | Home kernel, 7702 smart account; QUIC port 4031 | +| `kernel-away-peer-relay` | kernel | Away kernel, no bundler (relays to home); QUIC port 4032 | ### Profiles @@ -62,7 +62,7 @@ Profiles control which home/away pair is started: | `4337` | bundler-hybrid | `--profile 4337` | | `relay` | peer-relay | `--profile relay` | -Interactive mode activates one profile at a time. E2E test mode (`docker:up`) activates all three simultaneously. +Demo mode activates one profile at a time. E2E test mode (`docker:up`) activates all three simultaneously. ### Volumes @@ -71,7 +71,7 @@ Interactive mode activates one profile at a time. E2E test mode (`docker:up`) ac | `ocap-run` (named volume) | `/run/ocap` | Kernel databases, daemon sockets, contract addresses, delegation context, OpenClaw state | | `packages/evm-wallet-experiment/logs/` (bind-mount) | `/logs` | Per-service log files (`.log`); persists across restarts and readable directly on the host | -The `logs/` directory is created automatically by `docker:up` and `docker:interactive:up` via the `docker:ensure-logs` script. Each container's entrypoint tees its stdout/stderr to `/logs/.log`. +The `logs/` directory is created automatically by `docker:up` and `docker:demo:up` via the `docker:ensure-logs` script. Each container's entrypoint tees its stdout/stderr to `/logs/.log`. --- @@ -108,14 +108,14 @@ The test suite covers: wallet setup on both kernels, delegation creation and tra ## Environment variables -| Variable | Default | Description | -| -------------------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------- | -| `OCAP_INTERACTIVE_PAIR` | `bundler-7702` | Which home/away pair to start in interactive mode; overridden by `--pair` flag | -| `DELEGATION_MODE` | `bundler-7702` | Which mode to run in `test:e2e:docker`; also controls delegate resolution in `docker:delegate` | -| `CAVEAT_ETH_LIMIT` | _(none)_ | Wei cap on native-token transfers when running `docker:delegate` (default setup uses 1000 ETH) | -| `LLM_URL` | _(injected by Compose models)_ | OpenAI-compatible LLM base URL for the OpenClaw gateway | -| `LLM_MODEL` | `ai/qwen3.5:4B-UD-Q4_K_XL` | Model ID written to the OpenClaw config | -| `DEBUG_OCAP_INTERACTIVE_COMPOSE` | _(unset)_ | Print pair and profile resolution details during interactive compose operations | +| Variable | Default | Description | +| ------------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------- | +| `OCAP_DEMO_PAIR` | `bundler-7702` | Which home/away pair to start in demo mode; overridden by `--pair` flag | +| `DELEGATION_MODE` | `bundler-7702` | Which mode to run in `test:e2e:docker`; also controls delegate resolution in `docker:delegate` | +| `CAVEAT_ETH_LIMIT` | _(none)_ | Wei cap on native-token transfers when running `docker:delegate` (default setup uses 1000 ETH) | +| `LLM_URL` | _(injected by Compose models)_ | OpenAI-compatible LLM base URL for the OpenClaw gateway | +| `LLM_MODEL` | `ai/qwen3.5:4B-UD-Q4_K_XL` | Model ID written to the OpenClaw config | +| `DEBUG_OCAP_DEMO_COMPOSE` | _(unset)_ | Print pair and profile resolution details during demo compose operations | --- @@ -132,7 +132,7 @@ cat packages/evm-wallet-experiment/logs/kernel-home-bundler-7702.log cat packages/evm-wallet-experiment/logs/test-results.json # Check container health -docker compose -f packages/evm-wallet-experiment/docker/docker-compose.yml --profile 7702 ps +yarn workspace @ocap/evm-wallet-experiment docker:ps ``` Kernel containers write a readiness JSON file to `/run/ocap/-ready.json` when the daemon is up. The host-side setup scripts poll this before proceeding. @@ -160,5 +160,5 @@ After `test:e2e:docker` completes, structured pass/fail results are written to ` **Volume state is corrupted or stale** -- Full wipe: `docker compose -f packages/evm-wallet-experiment/docker/docker-compose.yml down -v` +- Full wipe: `yarn workspace @ocap/evm-wallet-experiment docker:down:volumes` - Rebuild: `yarn workspace @ocap/evm-wallet-experiment docker:build:force` diff --git a/packages/evm-wallet-experiment/package.json b/packages/evm-wallet-experiment/package.json index 420a698933..d504f3f01b 100644 --- a/packages/evm-wallet-experiment/package.json +++ b/packages/evm-wallet-experiment/package.json @@ -57,18 +57,22 @@ "test:node:peer-e2e": "yarn build && node --conditions development test/e2e/run-peer-e2e.mjs", "test:node:spending-limits": "yarn build && node --conditions development test/e2e/run-spending-limits-e2e.mjs", "docker:compose": "docker compose -f docker/docker-compose.yml --profile 7702 --profile 4337 --profile relay", - "docker:compose:interactive": "node docker/run-interactive-compose.mjs", + "docker:compose:demo": "node docker/run-demo-compose.mjs", "docker:build": "yarn workspace @ocap/monorepo build && yarn docker:compose build", "docker:build:force": "yarn docker:compose build --no-cache", "docker:ensure-logs": "mkdir -p logs", "docker:up": "yarn docker:ensure-logs && yarn docker:compose up --build", "docker:down": "yarn docker:compose down", - "docker:interactive:up": "yarn docker:ensure-logs && node docker/run-interactive-compose.mjs up --build", - "docker:interactive:down": "node docker/run-interactive-compose.mjs down", + "docker:down:volumes": "yarn docker:compose down -v", + "docker:ps": "yarn docker:compose ps", + "docker:demo:up": "yarn docker:ensure-logs && node docker/run-demo-compose.mjs up --build", + "docker:demo:down": "node docker/run-demo-compose.mjs down", "docker:setup:wallets": "yarn tsx test/e2e/docker/setup-wallets.ts", - "docker:interactive:setup": "node docker/interactive-setup.mjs", - "docker:interactive:reset-openclaw": "node docker/interactive-reset-openclaw.mjs", - "docker:delegate": "yarn docker:compose cp docker/create-delegation.mjs kernel-home-bundler-7702:/app/packages/evm-wallet-experiment/docker/create-delegation.mjs && yarn docker:compose exec kernel-home-bundler-7702 node --conditions development /app/packages/evm-wallet-experiment/docker/create-delegation.mjs", + "docker:demo:setup": "node docker/demo-setup.mjs", + "docker:demo:reset-openclaw": "node docker/demo-reset-openclaw.mjs", + "docker:demo:attach:away": "node docker/attach.mjs away", + "docker:demo:attach:home": "node docker/attach.mjs home", + "docker:delegate": "node docker/delegate.mjs", "docker:logs": "yarn docker:compose logs -f --tail=100", "test:e2e:docker": "vitest run --config vitest.config.docker.ts" }, diff --git a/packages/evm-wallet-experiment/test/e2e/docker/helpers/docker-e2e-kernel-services.ts b/packages/evm-wallet-experiment/test/e2e/docker/helpers/docker-e2e-kernel-services.ts index 11973a1dc5..4ad546d0b5 100644 --- a/packages/evm-wallet-experiment/test/e2e/docker/helpers/docker-e2e-kernel-services.ts +++ b/packages/evm-wallet-experiment/test/e2e/docker/helpers/docker-e2e-kernel-services.ts @@ -2,7 +2,7 @@ * Compose service names for parallel Docker E2E kernels (one home/away pair per * DELEGATION_MODE). Shared `evm` + `bundler`; isolated QUIC ports per pair. * - * Delegation-mode strings match `docker/interactive-compose-lib.mjs` (`OCAP_INTERACTIVE_PAIR` / `--pair`). + * Delegation-mode strings match `docker/demo-compose-lib.mjs` (`OCAP_INTERACTIVE_PAIR` / `--pair`). */ export type DockerKernelServicePair = {