From 60645c451e6a8dd18f9983c5ade9afba6c057cbd Mon Sep 17 00:00:00 2001 From: chenchen Date: Tue, 3 Nov 2026 07:47:25 +0800 Subject: [PATCH 1/5] cli: one-command install for box (connect, doctor, remove) Adds @simular-ai/box (bin simular-box), which detects Claude Code, Codex, Cursor, OpenCode, Hermes, OpenClaw and VS Code, and writes the box MCP server into each app's native config. It merges without clobbering other entries, backs up each file and is idempotent. Claude Code reuses the claude/ plugin. Every app signs in with OAuth; Hermes and OpenClaw can use a personal key (--auth key) kept in the app's .env, with the gateway restarted when it changes. doctor checks config, endpoint and key; remove undoes connect. BOX_MCP_URL overrides the single URL constant. A cli-v* tag publishes to npm with provenance. Closes #3 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release-cli.yml | 36 +++ .github/workflows/test-cli.yml | 26 ++ README.md | 2 + cli/.gitignore | 1 + cli/README.md | 69 +++++ cli/bin/simular-box.js | 10 + cli/package-lock.json | 91 +++++++ cli/package.json | 51 ++++ cli/src/args.js | 38 +++ cli/src/cli.js | 341 ++++++++++++++++++++++++ cli/src/clients/claude-code.js | 141 ++++++++++ cli/src/clients/claude-desktop.js | 36 +++ cli/src/clients/codex.js | 66 +++++ cli/src/clients/cursor.js | 16 ++ cli/src/clients/hermes.js | 116 ++++++++ cli/src/clients/index.js | 18 ++ cli/src/clients/json-client.js | 87 ++++++ cli/src/clients/openclaw.js | 165 ++++++++++++ cli/src/clients/opencode.js | 25 ++ cli/src/clients/vscode.js | 20 ++ cli/src/constants.js | 43 +++ cli/src/context.js | 67 +++++ cli/src/formats.js | 235 ++++++++++++++++ cli/src/fsutil.js | 70 +++++ cli/src/probe.js | 97 +++++++ cli/test/cli.test.js | 106 ++++++++ cli/test/clients.test.js | 202 ++++++++++++++ cli/test/fixtures/broken.json | 1 + cli/test/fixtures/codex.after.toml | 12 + cli/test/fixtures/codex.before.toml | 19 ++ cli/test/fixtures/cursor.before.json | 7 + cli/test/fixtures/hermes.before.yaml | 7 + cli/test/fixtures/opencode.before.jsonc | 8 + cli/test/fixtures/vscode.before.json | 6 + cli/test/fsutil.test.js | 39 +++ cli/test/helpers.js | 81 ++++++ 36 files changed, 2355 insertions(+) create mode 100644 .github/workflows/release-cli.yml create mode 100644 .github/workflows/test-cli.yml create mode 100644 cli/.gitignore create mode 100644 cli/README.md create mode 100755 cli/bin/simular-box.js create mode 100644 cli/package-lock.json create mode 100644 cli/package.json create mode 100644 cli/src/args.js create mode 100644 cli/src/cli.js create mode 100644 cli/src/clients/claude-code.js create mode 100644 cli/src/clients/claude-desktop.js create mode 100644 cli/src/clients/codex.js create mode 100644 cli/src/clients/cursor.js create mode 100644 cli/src/clients/hermes.js create mode 100644 cli/src/clients/index.js create mode 100644 cli/src/clients/json-client.js create mode 100644 cli/src/clients/openclaw.js create mode 100644 cli/src/clients/opencode.js create mode 100644 cli/src/clients/vscode.js create mode 100644 cli/src/constants.js create mode 100644 cli/src/context.js create mode 100644 cli/src/formats.js create mode 100644 cli/src/fsutil.js create mode 100644 cli/src/probe.js create mode 100644 cli/test/cli.test.js create mode 100644 cli/test/clients.test.js create mode 100644 cli/test/fixtures/broken.json create mode 100644 cli/test/fixtures/codex.after.toml create mode 100644 cli/test/fixtures/codex.before.toml create mode 100644 cli/test/fixtures/cursor.before.json create mode 100644 cli/test/fixtures/hermes.before.yaml create mode 100644 cli/test/fixtures/opencode.before.jsonc create mode 100644 cli/test/fixtures/vscode.before.json create mode 100644 cli/test/fsutil.test.js create mode 100644 cli/test/helpers.js diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml new file mode 100644 index 0000000..2ab18ec --- /dev/null +++ b/.github/workflows/release-cli.yml @@ -0,0 +1,36 @@ +name: Release CLI + +# Push a tag `cli-vX.Y.Z` that matches cli/package.json's version. The workflow tests the CLI and +# publishes @simular-ai/box to npm with provenance, then creates a GitHub release. +# Needs the repository secret NPM_TOKEN (an npm automation token with publish rights on @simular-ai). +on: + push: + tags: ['cli-v*'] + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write # npm provenance + defaults: + run: + working-directory: cli + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + registry-url: https://registry.npmjs.org + - name: Tag matches cli/package.json + run: test "cli-v$(node -p "require('./package.json').version")" = "$GITHUB_REF_NAME" + - run: npm ci + - run: npm test + - name: Publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npm publish --provenance --access public + - name: Release + env: + GH_TOKEN: ${{ github.token }} + run: gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes "npx @simular-ai/box connect. See cli/README.md." --latest=false diff --git a/.github/workflows/test-cli.yml b/.github/workflows/test-cli.yml new file mode 100644 index 0000000..1cb5e76 --- /dev/null +++ b/.github/workflows/test-cli.yml @@ -0,0 +1,26 @@ +name: Test CLI + +on: + pull_request: + paths: ['cli/**', '.github/workflows/test-cli.yml'] + push: + branches: [main] + paths: ['cli/**'] + +jobs: + test: + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + node: [18, 24] + runs-on: ${{ matrix.os }} + defaults: + run: + working-directory: cli + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + - run: npm ci + - run: npm test diff --git a/README.md b/README.md index f88db24..ca6b014 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Most agents need no plugin: add the MCP server `https://relay.simular.cloud/mcp` | --- | --- | --- | --- | | Claude Code and Cowork | [`claude/`](claude/) | OAuth, once in the browser | `/plugin marketplace add simular-ai/box-plugin`, then `/plugin install box@simular-box` | | DeepSeek Harness (dsh) | [`dsh/`](dsh/) | Personal key (`cb_...`) | [dsh/README.md](dsh/README.md) | +| Any of Claude Code, Codex, Cursor, OpenCode, Hermes, OpenClaw, VS Code (and steps for Claude Desktop) | [`cli/`](cli/) | OAuth; personal key with `--auth key` for Hermes and OpenClaw | `npx @simular-ai/box connect` (check with `npx @simular-ai/box doctor`) | ## Adding an agent @@ -17,3 +18,4 @@ Add a folder named after the agent with its own manifest, MCP config and, where - `claude/`: bump `version` in `claude/.claude-plugin/plugin.json`; Claude Code picks it up from the marketplace. - `dsh/`: bump `version` in `dsh/package.json`, then push a tag `dsh-vX.Y.Z`. The release workflow attaches `dsh-box.tgz`. +- `cli/`: bump `version` in `cli/package.json`, then push a tag `cli-vX.Y.Z`. The release workflow tests it and publishes `@simular-ai/box` to npm with provenance (needs the `NPM_TOKEN` secret). When the box endpoint moves, change `DEFAULT_MCP_URL` in `cli/src/constants.js` and release. diff --git a/cli/.gitignore b/cli/.gitignore new file mode 100644 index 0000000..6b1d0bf --- /dev/null +++ b/cli/.gitignore @@ -0,0 +1 @@ +LICENSE diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 0000000..cacf868 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,69 @@ +# @simular-ai/box + +Connect [box](https://box.simular.ai) to your AI apps in one command. box gives your AI agent a computer of its own: a cloud Linux desktop with Chrome and a shell, driven over MCP. + +```bash +npx @simular-ai/box connect +``` + +The CLI finds the AI apps on this computer, asks which ones should use box, and adds the box MCP server (`https://relay.simular.cloud/mcp`) to each one in its own format. Other servers and settings in those files are left alone, each changed file gets a backup next to it (`*.box-backup-