diff --git a/.changeset/collapse-agent-bundle-root.md b/.changeset/collapse-agent-bundle-root.md new file mode 100644 index 0000000..20286b7 --- /dev/null +++ b/.changeset/collapse-agent-bundle-root.md @@ -0,0 +1,5 @@ +--- +"grok-bot-cli": minor +--- + +Ship `gbot` as one generated Agent Bundle CLI at the package root and add `gbot-install install|uninstall ` / `gbot-install doctor` for the bundled `grok-bot` MCP tools and `talk-to-grok-bot` skill; delete the nested `plugin/` project and the hand-written dispatcher. Breaking (pre-1.0): Node.js 22.19.0 or newer is required; options are command-local (`gbot send --history-dir DIR …`, no leading globals); `--json` is reserved anywhere before `--`, so put `--` before flag-like message text; `send` and every `codex` command write one JSON document to stdout with `exitCode` (failures keep `error`, `delivery`, `reason`, `mode` and exit 1), other commands print failures on stderr and exit 1; argument and schema errors exit 2; `--instructions` is gone (use `--description`) and `--notify`/`--hidden` take `on|off` only; `chat` records history rows as `event: "thread"`; the installed bundle is named `gbot` (uninstall an earlier source-built `grok-bot` plugin first). (#50) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d5e8a5..1289640 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,11 @@ jobs: with: node-version: "24" - - name: Test - run: npm test + - name: Install dependencies + run: npm ci + + - name: Validate, build, typecheck, and test + run: npm run check - name: Lint the package run: npx --yes publint@0.3.24 @@ -34,28 +37,12 @@ jobs: - name: Pack and smoke-test the executable shell: bash run: | - package_file=$(npm pack --json | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>process.stdout.write(JSON.parse(s)[0].filename))") + package_root=$(mktemp -d) install_root=$(mktemp -d) - npm install --global --prefix "$install_root" "./$package_file" + npm pack --pack-destination "$package_root" + package_files=("$package_root"/*.tgz) + test -f "${package_files[0]}" + test "${#package_files[@]}" -eq 1 + npm install --global --prefix "$install_root" "${package_files[0]}" "$install_root/bin/gbot" --help - - plugin: - runs-on: ubuntu-latest - timeout-minutes: 15 - defaults: - run: - working-directory: plugin - steps: - - name: Check out the repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - - name: Set up Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 - with: - node-version: "24" - - - name: Install the plugin toolchain - run: npm ci - - - name: Validate, build, typecheck, and test the plugin - run: npm run check + "$install_root/bin/gbot-install" --help diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fc1ce29..af45628 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,8 +36,8 @@ jobs: - name: Update npm for trusted publishing run: npm install --global npm@latest - - name: Test - run: npm test + - name: Validate, build, typecheck, and test + run: npm run check - name: Lint the package run: npx --yes publint@0.3.24 @@ -53,6 +53,7 @@ jobs: test "${#package_files[@]}" -eq 1 npm install --global --prefix "$install_root" "${package_files[0]}" "$install_root/bin/gbot" --help + "$install_root/bin/gbot-install" --help - name: Create release pull request or publish id: changesets diff --git a/.gitignore b/.gitignore index 3cc6576..1aeef5b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ artifact/ tmp-agents/ *.log .DS_Store +*.tsbuildinfo diff --git a/plugin/.npmrc b/.npmrc similarity index 100% rename from plugin/.npmrc rename to .npmrc diff --git a/README.md b/README.md index 9058b6b..3368c1c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Manage [Grok Bot](https://cursor.com/help/grok-bot/plans) agents, groups, and me npm install --global grok-bot-cli ``` -Requires Node.js 18+ and the Grok Bot desktop app on macOS, Linux, or Windows. Open Grok Bot and sign in once; `gbot` automatically uses the app's encrypted session and routing credentials. No token copying is required. On Linux the app keeps its session under `~/.config/Grok Bot` (or `$XDG_CONFIG_HOME`); when it is stored in the system keyring, `gbot` reads the key with `secret-tool` (package `libsecret-tools`). On Windows the session lives under `%APPDATA%\\Grok Bot` and decrypts with the app's DPAPI-wrapped Safe Storage key. +Requires Node.js 22.19.0+ and the Grok Bot desktop app on macOS, Linux, or Windows. Open Grok Bot and sign in once; `gbot` automatically uses the app's encrypted session and routing credentials. No token copying is required. On Linux the app keeps its session under `~/.config/Grok Bot` (or `$XDG_CONFIG_HOME`); when it is stored in the system keyring, `gbot` reads the key with `secret-tool` (package `libsecret-tools`). On Windows the session lives under `%APPDATA%\\Grok Bot` and decrypts with the app's DPAPI-wrapped Safe Storage key. ## Use @@ -34,7 +34,7 @@ gbot bots delete Researcher gbot bots delete Writer ``` -`update` fields: `--name` `--description`/`--instructions` `--title` `--avatar-shape` `--avatar-color` `--notify` `--hidden`. `--description` is the UI Instructions field. +`update` fields: `--name` `--description` `--title` `--avatar-shape` `--avatar-color` `--notify on|off` `--hidden on|off`. `--description` is the UI Instructions field. `gbot thread --after ID` filters the bounded tail locally and returns entries strictly after that opaque entry ID. Its JSON includes `cursor`, `entryCount`, and `gapReset`. @@ -42,6 +42,11 @@ An unchanged poll has `entryCount: 0`; an unknown or expired ID returns one boun snapshot with `gapReset: true`. The gateway request remains limit-only. Run `gbot --help` for every command. +Options are command-local (for example, `gbot send --history-dir DIR ...`); +the former leading-global form is no longer accepted. `--json` prints the +canonical JSON result; `send` and the `codex` commands also report failures as +a JSON document on stdout with `exitCode` (see below), every other command +prints the failure message on stderr and exits 1. ## Gateway URL policy @@ -68,11 +73,11 @@ gbot codex send "Grok here: the build is green, please continue." `send` resumes the thread, starts a turn with your text, prints the turn id, and returns; Codex keeps working after `gbot` disconnects. Every command accepts `--json`. -**Which Codex you reach.** `gbot` connects to `$CODEX_HOME/app-server-control/app-server-control.sock` (default `~/.codex/...`) with a built-in WebSocket client. The daemon must be started by `codex app-server daemon start`. `list-threads` shows the threads recorded under `CODEX_HOME` (CLI, TUI, VS Code); `send` works on any of them that no other client currently holds open. Method and parameter names are pinned to the Codex release recorded in `src/codex-bridge.js` (`codex app-server generate-json-schema`); `status` prints the daemon and CLI versions so a stale daemon is visible, and `codex app-server daemon restart` picks up the installed CLI. Native Windows is not supported yet (AF_UNIX control socket); use WSL, Linux, or macOS. +**Which Codex you reach.** `gbot` connects to `$CODEX_HOME/app-server-control/app-server-control.sock` (default `~/.codex/...`) with a built-in WebSocket client. The daemon must be started by `codex app-server daemon start`. `list-threads` shows the threads recorded under `CODEX_HOME` (CLI, TUI, VS Code); `send` works on any of them that no other client currently holds open. Method and parameter names are pinned to the Codex release recorded in `src/core/codex-bridge.js` (`codex app-server generate-json-schema`); `status` prints the daemon and CLI versions so a stale daemon is visible, and `codex app-server daemon restart` picks up the installed CLI. Native Windows is not supported yet (AF_UNIX control socket); use WSL, Linux, or macOS. **ChatGPT Desktop limitation.** Desktop runs its own private stdio app-server and does not publish the shared control socket, so external clients cannot reach live Desktop tasks. When the socket is absent, `gbot codex status` exits 1 and says so, naming the upstream issues: [openai/codex#41014](https://github.com/openai/codex/issues/41014) and [openai/codex#41112](https://github.com/openai/codex/issues/41112). `gbot` never reads Desktop's temporary `CODEX_APP_TOOLS_PIPE_PATH` sockets under `/tmp/codex-browser-use/`; that channel is private to Desktop. -**Status contract (`gbot codex status --json`).** `reachable` is endpoint reachability only. `socketState` is `socket`, `absent`, `permission-denied`, or `not-a-socket`; `mode` is `daemon` for a usable daemon, otherwise the failure: `socket-absent`, `permission-denied` (the file or the connect refused this user), `not-a-socket`, `connect-failed` (socket present, nothing completed the WebSocket upgrade), `handshake-failed` (upgrade or `initialize` failed), `windows-unsupported`, or `bad-response` (reachable, but `initialize` returned something off-schema — `reachable` stays `true`). `schema.compatibility` is `exact` when the daemon reports the pinned version, `unverified` when it differs (methods usually survive upgrades, but the shapes are not re-checked), or `unknown`. `cliVersionProbe` reports whether `codex --version` answered (`ok`, `missing`, `timeout` after 3 s, `error`). Whether ChatGPT Desktop owns a thread is not observable from the socket, so `desktopAttached` is always `"unknown"`. Every failure exits 1; automation reads `mode`/`reason`, not the exit code. +**Status contract (`gbot codex status --json`).** `reachable` is endpoint reachability only. `socketState` is `socket`, `absent`, `permission-denied`, or `not-a-socket`; `mode` is `daemon` for a usable daemon, otherwise the failure: `socket-absent`, `permission-denied` (the file or the connect refused this user), `not-a-socket`, `connect-failed` (socket present, nothing completed the WebSocket upgrade), `handshake-failed` (upgrade or `initialize` failed), `windows-unsupported`, or `bad-response` (reachable, but `initialize` returned something off-schema — `reachable` stays `true`). `schema.compatibility` is `exact` when the daemon reports the pinned version, `unverified` when it differs (methods usually survive upgrades, but the shapes are not re-checked), or `unknown`. `cliVersionProbe` reports whether `codex --version` answered (`ok`, `missing`, `timeout` after 3 s, `error`). Whether ChatGPT Desktop owns a thread is not observable from the socket, so `desktopAttached` is always `"unknown"`. The document is always written to stdout and includes `exitCode`; it is `0` only for a usable daemon. **Thread discovery.** `list-threads --limit N` (1–200) pages with the opaque `--cursor` from the previous `nextCursor`; JSON keeps the cursor verbatim, text output prints a sanitized `more: --cursor …` hint. Text fields are stripped of terminal control sequences in both outputs (single-line fields also lose line breaks; `preview` keeps its newlines; a structured `source` such as `{ "custom": … }` passes through unchanged), `status` is one of `notLoaded | idle | active | systemError | unknown`, and non-numeric `updatedAt` becomes `null`. Unknown arguments are rejected before the socket is touched; a response that does not match the pinned schema (including an entry without a string `id`) fails with `reason: "bad-response"`. @@ -83,11 +88,11 @@ gbot codex send "Grok here: build is green" # receip gbot codex send --correlation-id M --reply-to M --hop 1 "ack" # the answer, one hop later ``` -Sends at `hop >= GROK_BOT_MAX_HOPS` (default 4) are refused with `reason: "hop-limit"` before anything reaches the daemon, so two agents cannot acknowledge each other forever; `gbot` never auto-acknowledges. `--envelope` (implied by any envelope flag) prepends a one-line `[gbot msg=… corr=… reply-to=… hop=… from=user@host]` header so the receiving agent can quote the ids back. That header is caller-authored provenance for the reader, not authentication: the daemon authenticates the local user through the socket, nothing else. The same flags work for `gbot send` to Grok bots and groups (the receipt carries `envelopeId`, `correlationId`, `hop`; Grok's own `messageId` remains the delivery receipt). Private ChatGPT Desktop pipes and arbitrary ChatGPT chats stay out of scope; only Codex threads on a reachable app-server daemon are routes. +Sends at `hop >= GROK_BOT_MAX_HOPS` (default 4) are refused with `reason: "hop-limit"` before anything reaches the daemon, so two agents cannot acknowledge each other forever; `gbot` never auto-acknowledges. `--envelope` (implied by any envelope flag) prepends a one-line `[gbot msg=… corr=… reply-to=… hop=… from=user@host]` header so the receiving agent can quote the ids back. That header is caller-authored provenance for the reader, not authentication: the daemon authenticates the local user through the socket, nothing else. Private ChatGPT Desktop pipes and arbitrary ChatGPT chats stay out of scope; only Codex threads on a reachable app-server daemon are routes. **Busy threads.** `send` reads the thread status on resume. Only `idle` and `notLoaded` threads start a turn. An `active` thread (a turn in progress, or waiting on approval / user input) is refused with `reason: "busy"`: in app-server 0.154.0 a `turn/start` on an active thread steers that turn rather than queueing behind it, and `gbot` never steers or interrupts work a human may be doing. Either wait for `list-threads` to show `idle` and resend, or pass `--when-busy queue` to hand the message to the daemon's own queue through Codex's experimental `thread/queue/add` — that needs `GROK_BOT_CODEX_EXPERIMENTAL=1`, returns `delivery: "queued"` with `queuedSubmissionId`, and `gbot codex queue ` shows what is still waiting. `systemError` threads are refused with `reason: "thread-error"`, statuses this version does not know with `reason: "unknown-status"`. Receipts distinguish `delivery: "accepted"` (turn started; `turnId`, `turnStatus`), `"queued"`, `"rejected"` (nothing was sent; see `reason`), and `"unknown"` (the request left but no acknowledgment came back — look for `messageId` in the thread or queue before resending). The decision record, with the schema evidence and a live probe of the queue API, is in [`docs/codex-busy-threads.md`](docs/codex-busy-threads.md). -**Failure modes.** Every `send` / `codex send` failure under `--json` is `{ error, delivery, reason, messageId, correlationId, hop, … }` on stderr with exit 1; argument mistakes are `{ error, reason: "usage" }`; `codex status` never fails this way — it prints the status document on stdout and exits 1 when `mode` is anything but `daemon`. `reason` values are stable: +**Failure modes.** Every `send` and `codex` outcome under `--json` is one document on stdout with `exitCode`; failures include `{ error, delivery, reason, messageId, correlationId, hop, exitCode: 1, … }` and the process exits 1. Framework argument/schema errors remain on stderr and exit 2. `--json` is reserved anywhere before `--`; put `--` before flag-like message text. `reason` values are stable: - `socket-absent` / `permission-denied` / `not-a-socket` / `connect-failed` / `handshake-failed` / `windows-unsupported`: the route is unavailable. Start the daemon, fix the socket, or wait for the upstream Desktop fixes. - `unknown-thread`: use `list-threads`. @@ -100,29 +105,24 @@ Sends at `hop >= GROK_BOT_MAX_HOPS` (default 4) are refused with `reason: "hop-l ## Talking to Grok Bot from Codex -`plugin/` is an [Agent Bundle](https://scriptedalchemy.github.io/agent-bundle/) plugin +The npm package is also an [Agent Bundle](https://scriptedalchemy.github.io/agent-bundle/) plugin that gives Codex, Claude Code, and Cursor two MCP tools on a `grok-bot` server, `gbot_send` and `gbot_thread`, plus a `talk-to-grok-bot` skill that tells the agent when to ping a bot and how to word the message. The tools bundle this repository's gateway client, so the installed plugin does not need `gbot` on `PATH`. -The plugin is not part of the npm package. From a clone of this repository, build -the artifact once, then install it into each host you use: +Install the bundled host projections from the same npm package: ```sh -git clone https://github.com/ScriptedAlchemy/grok-bot-cli.git -cd grok-bot-cli/plugin -npm install -npm run build -npx agent-bundle install codex --from artifact -npx agent-bundle install claude --from artifact -npx agent-bundle install cursor --from artifact -npx agent-bundle doctor --from artifact +gbot-install install codex +gbot-install install claude +gbot-install install cursor +gbot-install doctor ``` -Add `--replace` to an install command to overwrite an earlier copy. `npm run check` -runs the plugin gates: source validation, build, artifact validation, typecheck, and -the route-unit tests, which drive both tools against a loopback fake gateway. +Add `--replace` to an install command to overwrite an earlier copy. The bundle is +registered as `gbot`; if you installed the pre-0.4 `grok-bot` plugin from a source +checkout, uninstall it first so the two do not both register the `grok-bot` server. `gbot_thread` returns a small receipt by default: deterministic `summary`, opaque `cursor`, `entryCount`, and `gapReset`. diff --git a/agent-bundle.config.ts b/agent-bundle.config.ts new file mode 100644 index 0000000..0684d21 --- /dev/null +++ b/agent-bundle.config.ts @@ -0,0 +1,28 @@ +import { defineConfig } from 'agent-bundle/config'; + +/** + * One Agent Bundle project at repo root — same shape as cargo-hauler. + * Nested `plugin/` + hand `src/cli.js` are gone; hosts and npm share this tree. + * + * - `src/mcp/grok-bot/tools/*` → MCP tools + * - `src/cli/**` → npm CLI, including send/thread/history and Codex + * - `src/gbot-install.ts` → `gbot-install` host installer + * - `src/core/*` → domain (gateway, store, codex-bridge, …) + * - `src/skills/*` → installed skills + */ +export default defineConfig({ + bin: { + 'gbot-install': './src/gbot-install.ts', + }, + lib: false, + marketplace: true, + output: { distPath: 'artifact' }, + plugin: { + description: + 'Message Grok Bot bots and groups and read their threads from Codex, Claude Code, and Cursor.', + // plugin.name is also the routed bin name: `dist/bin/gbot.mjs`. + name: 'gbot', + }, + runtime: { node: '22.19.0' }, + targets: ['claude', 'codex', 'cursor', 'portable'], +}); diff --git a/docs/codex-busy-threads.md b/docs/codex-busy-threads.md index 8c8a079..b394a48 100644 --- a/docs/codex-busy-threads.md +++ b/docs/codex-busy-threads.md @@ -2,7 +2,7 @@ Decision record for [#38](https://github.com/ScriptedAlchemy/grok-bot-cli/issues/38). Evidence is the app-server schema emitted by `codex app-server generate-json-schema` for codex-cli 0.154.0 — the release -`src/codex-bridge.js` is pinned to — generated both without and with `--experimental`, plus a live probe +`src/core/codex-bridge.js` is pinned to — generated both without and with `--experimental`, plus a live probe against a 0.154.0 daemon (below). ## What the protocol offers diff --git a/package-lock.json b/package-lock.json index a67dcc1..b4867bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,22 +1,246 @@ { "name": "grok-bot-cli", - "version": "0.2.3", + "version": "0.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "grok-bot-cli", - "version": "0.2.3", + "version": "0.3.1", "license": "MIT", "bin": { - "gbot": "src/cli.js", - "grok-bot": "src/cli.js" + "gbot": "dist/bin/gbot.mjs", + "gbot-install": "dist/bin/gbot-install.js", + "grok-bot": "dist/bin/gbot.mjs" }, "devDependencies": { - "@changesets/cli": "3.0.3" + "@agent-bundle/runtime": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@8e55ab832d", + "@changesets/cli": "3.0.3", + "@rstest/core": "0.11.12", + "@types/node": "^22.18.0", + "@types/react": "^19.2.18", + "agent-bundle": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@8e55ab832d", + "react": "19.3.0", + "react-dom": "19.3.0", + "typescript": "7.0.2", + "zod": "4.6.5" }, "engines": { - "node": ">=18" + "node": ">=22.19.0" + } + }, + "node_modules/@agent-bundle/runtime": { + "version": "0.0.0-preview-8e55ab8", + "resolved": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@8e55ab832d", + "integrity": "sha512-O75uBTztZucdZmZloaRdLRQp0auq15alBOucuk3mIltprJT6CtUbJnACItZ/RI5snyy0v8ShIh6y2/YJgk0USw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@modelcontextprotocol/server": "2.0.0", + "effect": "4.0.0-rc.112", + "flare-redact": "1.6.1", + "react-server-dom-rspack": "0.1.0", + "rsc-markdown-stream": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/rsc-markdown-stream@8e55ab832dd38705e23828b2fe25200c4d5f5c88" + }, + "engines": { + "node": ">=22.19.0" + }, + "peerDependencies": { + "@rspack/core": "^2.2.0-0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "zod": "^4.5.4" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + } + } + }, + "node_modules/@ast-grep/napi": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi/-/napi-0.45.2.tgz", + "integrity": "sha512-hBA5c7JV6OM7zFWoLjUNZhsDpxEIEIeew5S3z1giwK5tPQqobuFfM2OhS45bN3E0+yQtgCX/o8/AEHKbGD3ykg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@ast-grep/napi-darwin-arm64": "0.45.2", + "@ast-grep/napi-darwin-x64": "0.45.2", + "@ast-grep/napi-linux-arm64-gnu": "0.45.2", + "@ast-grep/napi-linux-arm64-musl": "0.45.2", + "@ast-grep/napi-linux-x64-gnu": "0.45.2", + "@ast-grep/napi-linux-x64-musl": "0.45.2", + "@ast-grep/napi-win32-arm64-msvc": "0.45.2", + "@ast-grep/napi-win32-ia32-msvc": "0.45.2", + "@ast-grep/napi-win32-x64-msvc": "0.45.2" + } + }, + "node_modules/@ast-grep/napi-darwin-arm64": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-arm64/-/napi-darwin-arm64-0.45.2.tgz", + "integrity": "sha512-29+sfXTJ7xxqgTuWAHA89gDAQIiJyAZ1ZiHoupjKIqyn0mhXrktO1WOghlDzyYs++hITEPOeXftxy48Y0tDGDQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-darwin-x64": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-x64/-/napi-darwin-x64-0.45.2.tgz", + "integrity": "sha512-PUjh7Zf4dKNzYLOYhX5wU6O4BgRPdJnD9zkS1n+/5SeK0U1L5YL486RjNgFt9Xyff0PGtP/wDeoHMF5PhKEwsw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-linux-arm64-gnu": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-gnu/-/napi-linux-arm64-gnu-0.45.2.tgz", + "integrity": "sha512-bnGKLLHWO13pjPChOFq7Ifqj3HJdOAxMQAGDCUC2JSJhO2YL8/xBZrpN0cHIWNuoUNSAXjCtr5AsCnPz/3jlFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-linux-arm64-musl": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-musl/-/napi-linux-arm64-musl-0.45.2.tgz", + "integrity": "sha512-FXVb4/V55THjhKxi5zWVrAO8JQj+/DiYP7JLsqenkm5V3UNuC8p2opGOyQpUvNpvcqJiZA9Hl+Onj/yfwSVr/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-linux-x64-gnu": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-gnu/-/napi-linux-x64-gnu-0.45.2.tgz", + "integrity": "sha512-mtEIPLV9MW2PBswFcp3ydM4T5Ub73s89SRd0QMT2+DfA9XBLCLhnC+r/Yt4eRgnf8FyNx49bFTPxXvFKscr9hw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-linux-x64-musl": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-musl/-/napi-linux-x64-musl-0.45.2.tgz", + "integrity": "sha512-WLLHxDmuXkb/e3mz/xDCrB2dZPzv1ntsepuRTtpaIGczxnQTgFSzX/CXPD0e1MfsU/QL1AiXxxni8w+NGy/ZpQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-win32-arm64-msvc": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-arm64-msvc/-/napi-win32-arm64-msvc-0.45.2.tgz", + "integrity": "sha512-04iOFaMzD2nf8CKw3nURWN42900wqPtUTQaMo1I2KRk3qbgtHSJjJoVJGAWUXkCq4LhPg3Xlk1s+ssWf4rNm2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-win32-ia32-msvc": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-ia32-msvc/-/napi-win32-ia32-msvc-0.45.2.tgz", + "integrity": "sha512-tE3y0RQcajocKwpYLbgHKd4lzGGAx1wGMA0bGPsWdoFK8VSob6ZDuYdSlSdnaRs8jAc4F3axToNRKn15p+0/Dg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-win32-x64-msvc": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-x64-msvc/-/napi-win32-x64-msvc-0.45.2.tgz", + "integrity": "sha512-o8Z5Z42TAJe0fPnb11rrjtte58wlw/MuR4KpVMHl8IhJLBBR7gHR0E8wfMz88TxzsQz0U2KYev0k0a2fV4i0sQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" } }, "node_modules/@changesets/apply-release-plan": { @@ -292,6 +516,70 @@ "node": ">= 20.12.0" } }, + "node_modules/@effect/platform-node-shared": { + "version": "4.0.0-rc.112", + "resolved": "https://registry.npmjs.org/@effect/platform-node-shared/-/platform-node-shared-4.0.0-rc.112.tgz", + "integrity": "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ws": "^8.18.1", + "ws": "^8.21.3" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "effect": "^4.0.0-rc.112" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.17", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.17.tgz", + "integrity": "sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@manypkg/find-root": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-3.1.0.tgz", @@ -334,211 +622,2333 @@ "node": ">=20.0.0" } }, - "node_modules/@pnpm/deps.graph-sequencer": { - "version": "1100.0.1", - "resolved": "https://registry.npmjs.org/@pnpm/deps.graph-sequencer/-/deps.graph-sequencer-1100.0.1.tgz", - "integrity": "sha512-pOr5+q1fLYKwFN3LAJuGZEnfXDcQ73zqgDHMtGy+K+uIoUqyY+6MeDCWFwfu+4EFuq76I5EPFofoNAI+Bmmq4A==", + "node_modules/@modelcontextprotocol/client": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.0.0.tgz", + "integrity": "sha512-8f1OghQ2rjzIOfqgUCP+8GiUWqRs89njoWLNqAe8kWmDePv3s1fZXseej+QXemssEuuOvLLmLO/kqM3IQHtISw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=22.13" + "dependencies": { + "@modelcontextprotocol/core": "2.0.0", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "jose": "^6.1.3", + "pkce-challenge": "^5.0.0", + "zod": "^4.2.0" }, - "funding": { - "url": "https://opencollective.com/pnpm" - } - }, - "node_modules/cac": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz", - "integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=20.19.0" + "node": ">=20" } }, - "node_modules/fast-string-truncated-width": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", - "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-string-width": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", - "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "node_modules/@modelcontextprotocol/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.0.0.tgz", + "integrity": "sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==", "dev": true, "license": "MIT", "dependencies": { - "fast-string-truncated-width": "^3.0.2" + "zod": "^4.2.0" + }, + "engines": { + "node": ">=20" } }, - "node_modules/fast-wrap-ansi": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", - "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "node_modules/@modelcontextprotocol/node": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/node/-/node-2.0.0.tgz", + "integrity": "sha512-Y4hAC2XdGDUdDOCbLDOCA4+aL3NUldjsOWlDL/YwpAxrPhRm1xHd7lZ+mLacvZ9t3PaH28wgNoaLQGrIk1P2pg==", "dev": true, "license": "MIT", "dependencies": { - "fast-string-width": "^3.0.2" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", + "@hono/node-server": "^1.19.9" + }, "engines": { - "node": ">=12.0.0" + "node": ">=20" }, "peerDependencies": { - "picomatch": "^3 || ^4" + "@modelcontextprotocol/server": "^2.0.0", + "hono": "^4.11.4" }, "peerDependenciesMeta": { - "picomatch": { + "hono": { "optional": true } } }, - "node_modules/human-id": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.2.1.tgz", - "integrity": "sha512-zPGsiS+dWoTZtZ4AtpA9Y+BdSFSNWvnouNlWNoUFyAM6xHOHmdCvqO3k8AIbdamCOv4gUFUVNPf6rJFfc4UiJw==", + "node_modules/@modelcontextprotocol/server": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.0.0.tgz", + "integrity": "sha512-YhHWdHfpFMQfd0prsEnxKeS3Qz3ytIGmsS0sth4KDjnacIT7hxk6hXHkJ9KysxlkvTM+WZAtQbbcUhdoP4Hvtw==", "dev": true, "license": "MIT", - "bin": { - "human-id": "dist/cli.js" + "dependencies": { + "@modelcontextprotocol/core": "2.0.0", + "zod": "^4.2.0" + }, + "engines": { + "node": ">=20" } }, - "node_modules/import-meta-resolve": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", - "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.4.tgz", + "integrity": "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.4.tgz", + "integrity": "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.4.tgz", + "integrity": "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/launch-editor": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz", - "integrity": "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.4.tgz", + "integrity": "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^1.1.1", - "shell-quote": "^1.8.4" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/package-manager-detector": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz", - "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.4.tgz", + "integrity": "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.4.tgz", + "integrity": "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=10" + "node": ">= 8" } }, - "node_modules/shell-quote": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", - "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 8" } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", - "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "node_modules/@pnpm/deps.graph-sequencer": { + "version": "1100.0.1", + "resolved": "https://registry.npmjs.org/@pnpm/deps.graph-sequencer/-/deps.graph-sequencer-1100.0.1.tgz", + "integrity": "sha512-pOr5+q1fLYKwFN3LAJuGZEnfXDcQ73zqgDHMtGy+K+uIoUqyY+6MeDCWFwfu+4EFuq76I5EPFofoNAI+Bmmq4A==", "dev": true, "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, "engines": { - "node": ">=12.0.0" + "node": ">=22.13" }, "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "url": "https://opencollective.com/pnpm" } }, - "node_modules/yaml": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", - "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "node_modules/@rsbuild/core": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.2.6.tgz", + "integrity": "sha512-+BoNmacdQ2j9ysUunVUm2CTK7Aff70l4P/m29R5AWjd2vCU+X7bo6u3geMMJV0+j/JUHzoccC1ERIEhzqnD3Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rspack/core": "~2.2.4", + "@swc/helpers": "^0.5.23" + }, + "bin": { + "rsbuild": "bin/rsbuild.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "core-js": ">= 3.0.0" + }, + "peerDependenciesMeta": { + "core-js": { + "optional": true + } + } + }, + "node_modules/@rsbuild/plugin-react": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@rsbuild/plugin-react/-/plugin-react-2.1.0.tgz", + "integrity": "sha512-RQTIAWB/CwPjoWt9iAl+8HixeQVgZ7kEIBrWPCixfITyHdiD84h0YpUTpEUuz6kGHw1KXT9mHZ3Rwy6WG7aRDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rspack/plugin-react-refresh": "^2.0.2", + "react-refresh": "^0.18.0" + }, + "peerDependencies": { + "@rsbuild/core": "^2.0.0" + }, + "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + } + } + }, + "node_modules/@rslib/core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rslib/core/-/core-1.0.0.tgz", + "integrity": "sha512-eZNXCWU1v5oti4+DKCunc76DkNnYqMgRtks9UyZRRFlmaK4pKAxhejeCUS+XkbMurGIAa+aDyVynQD7DXEgK1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsbuild/core": "~2.2.2", + "rsbuild-plugin-dts": "1.0.0" + }, + "bin": { + "rslib": "bin/rslib.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7", + "typescript": "^5 || ^6 || ^7" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@rslint/core": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@rslint/core/-/core-0.9.1.tgz", + "integrity": "sha512-MRS6lS+GiobBr+iIl5iFAYfwhhxVJX28lB6uVnwH40U49DCPUF0J2qlKI7RewPKDmKp5uosKJcvpxE8Rm7aVcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.5" + }, + "bin": { + "rslint": "bin/rslint.js" + }, + "optionalDependencies": { + "@rslint/native-darwin-arm64": "0.9.1", + "@rslint/native-darwin-x64": "0.9.1", + "@rslint/native-linux-arm64-gnu": "0.9.1", + "@rslint/native-linux-arm64-musl": "0.9.1", + "@rslint/native-linux-x64-gnu": "0.9.1", + "@rslint/native-linux-x64-musl": "0.9.1", + "@rslint/native-win32-arm64-msvc": "0.9.1", + "@rslint/native-win32-x64-msvc": "0.9.1" + }, + "peerDependencies": { + "jiti": "^2.7.0" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/@rslint/native-darwin-arm64": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@rslint/native-darwin-arm64/-/native-darwin-arm64-0.9.1.tgz", + "integrity": "sha512-WuWZObUanaYI+93vnld+3LNXJeCkMA5ntkBs8VMptBrPa64H4K/WEm4BN1Z8NLjW5TnYWhG1wVgRE2Ie8UeSYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rslint/native-darwin-x64": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@rslint/native-darwin-x64/-/native-darwin-x64-0.9.1.tgz", + "integrity": "sha512-Pce+LuyMmqBNwPjXMg5MEgo3nu36H3p7FyAwWEn8dlmUAQPhe3BQQ73fa7TT/97I9yfXY+YmJVRjLuctHQKmbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rslint/native-linux-arm64-gnu": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@rslint/native-linux-arm64-gnu/-/native-linux-arm64-gnu-0.9.1.tgz", + "integrity": "sha512-pzt13FMri+oYevnR1xXo8CJkwr+RjxCFGJnYxoJ4C3jUKJLK+aJTlREDX1gnCMAXxx02YIUAqBrc4zQ09PAKsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rslint/native-linux-arm64-musl": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@rslint/native-linux-arm64-musl/-/native-linux-arm64-musl-0.9.1.tgz", + "integrity": "sha512-+fe6CNu+C5mshQ0hDyi/NakM3rqMyvMqKUf5ldNTQhaNUYavdb9cP7yXJw/H6qwHB6wbZIqSDo3b6HohzgnBkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rslint/native-linux-x64-gnu": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@rslint/native-linux-x64-gnu/-/native-linux-x64-gnu-0.9.1.tgz", + "integrity": "sha512-119QVNJATOI21fGB5OsYfu0DXo7UMyyEpLi9TCogiZQF1X9QkPDdH0DXVQb2yi/H8H6FlNXak91G5vJ2W0SY2w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rslint/native-linux-x64-musl": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@rslint/native-linux-x64-musl/-/native-linux-x64-musl-0.9.1.tgz", + "integrity": "sha512-eUkiywQGG0umzYU86n1ZetCPBS1bLUFJZkFB+MovbDQQF+V9R6xA7x2mJvODnA7laOB3e7VK/uF56RvUebtzXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rslint/native-win32-arm64-msvc": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@rslint/native-win32-arm64-msvc/-/native-win32-arm64-msvc-0.9.1.tgz", + "integrity": "sha512-e0GLvCYh2XiQtVoFxbeU/QuM1mC6PWQATZbPN6fxfB4ZFH3S8KbcYCNFJyTEHp5WbU4XFJnut1qEf2u8pBoADA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rslint/native-win32-x64-msvc": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@rslint/native-win32-x64-msvc/-/native-win32-x64-msvc-0.9.1.tgz", + "integrity": "sha512-pofbo2UYBjK/OwNstlBEH89/XMUllp3PVTz21wQ7ryu3yH8atCzP2CX4Jv8IQ7eWpDJyMALhkXeEy5bsbI04xw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.2.4.tgz", + "integrity": "sha512-KoH5Wofyt1+egnqWF3pr8ItiYQiLgrHYLHOAn4YpzIMsGc8zDur3dCIhrhJ1uhbD3O7zkKqav4he3bo1kAmX9Q==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "2.2.4", + "@rspack/binding-darwin-x64": "2.2.4", + "@rspack/binding-linux-arm64-gnu": "2.2.4", + "@rspack/binding-linux-arm64-musl": "2.2.4", + "@rspack/binding-linux-ppc64-gnu": "2.2.4", + "@rspack/binding-linux-riscv64-gnu": "2.2.4", + "@rspack/binding-linux-riscv64-musl": "2.2.4", + "@rspack/binding-linux-s390x-gnu": "2.2.4", + "@rspack/binding-linux-x64-gnu": "2.2.4", + "@rspack/binding-linux-x64-musl": "2.2.4", + "@rspack/binding-wasm32-wasi": "2.2.4", + "@rspack/binding-win32-arm64-msvc": "2.2.4", + "@rspack/binding-win32-ia32-msvc": "2.2.4", + "@rspack/binding-win32-x64-msvc": "2.2.4" + } + }, + "node_modules/@rspack/binding-darwin-arm64": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.2.4.tgz", + "integrity": "sha512-PmwL+7nlD58tvGi2tUct2D6HzPsCeICvNpfgznzFjvrGlmPOm7pn5ahaevEf0C5QRHldf97qShekits4bzArsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-darwin-x64": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.2.4.tgz", + "integrity": "sha512-eFVBlPe/32eNaC5oIQFIfMRIic/+670iK+hep4eFSuDzJPC2QBXviSDrNRIdshTFNirCquR1+idT0XI74JYBjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-linux-arm64-gnu": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.2.4.tgz", + "integrity": "sha512-/gyHP8DVezbTzey3wCknCRSKHzxZmfOAVtoNhNfQ2+9+wNaZUKjjaGuLc/IOc1CVeZ9cE30bNzJdun+/F9KNrg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-arm64-musl": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.2.4.tgz", + "integrity": "sha512-eNXOvP4hKpRozCLsutbGU7R8mQ9S3OaSbgK5T/aitEAeIzFMorkcbVJopVKwEDLxrNSTfndTedefkYN+pdhsYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-ppc64-gnu": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-2.2.4.tgz", + "integrity": "sha512-WmlhV3nXgiKiSAFc5QVSYgurbTyF+fGUgd59JWsMCPmqwgTmNyjq6mjmoa6fzKtX/4+oKFUBBn4CdO1uCKU/ww==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-riscv64-gnu": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-2.2.4.tgz", + "integrity": "sha512-EGqzydSCvB1o8aVk0H+HM1npAk63ZRR8jSTqzY0GQ4nz+30LHZ/Ah1Eba91OsUAgfKwk3ffP5a7EoizH24m2Rg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-riscv64-musl": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-2.2.4.tgz", + "integrity": "sha512-5A5vzbvNBvuAQ4ZGEAdVl8gcFowgqCCVz3fCh12Jq3WHynl3J4JHAMnVQMs7A/KmaBhwKYDtO4FUvWh5V/BNKA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-s390x-gnu": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-2.2.4.tgz", + "integrity": "sha512-AWGTTx5ZkMe/hHTjpbIdxJ2xzMrSaL+01zpzV2LpGhheiXeDmwId9yYEEG8vwtzzVmz8lS5VBRIdy3Kx/k4m8A==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-gnu": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.2.4.tgz", + "integrity": "sha512-wzVC7AkyGD0rAdV41pKxwokvdAEY47HazjdUd3Pq2MT/rHNkhgsbCOVbrl4Ts2vQqiLrFfnnNZs383492oIrQw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-musl": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.2.4.tgz", + "integrity": "sha512-Gpxo27eJ+r53ebWdm8FIg6jtlEOr4T5Yit7FgF8Ib9U78Et9qGcbnvVQONHjz8gUe2hvwg9QQ1EJZechSpVB8A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-wasm32-wasi": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.2.4.tgz", + "integrity": "sha512-Ak0PYNbyQd/0d7xsuCCBvc/V9+S8+NoHHv5dzlHepa6udSF7zKDxv9MxRMdhIIBrgn+8GMHQb3ohwW1XjzmONg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.3", + "@emnapi/runtime": "1.11.3", + "@napi-rs/wasm-runtime": "1.1.6" + } + }, + "node_modules/@rspack/binding-win32-arm64-msvc": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.2.4.tgz", + "integrity": "sha512-OVynh1BYpAKSdvopHR4P/Qy1y17YgF3qLGcRYDGTvwAYOX7EyHS/7YK8BX12T2dDZV2UhEa2t98fNncX5H/O3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-ia32-msvc": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.2.4.tgz", + "integrity": "sha512-Q3yuEY/ayWjF0dO6Guj1cPH97jyaazNXRUzZz5/qz1BuuCPUaV7/LMUz1HHKOqxCw13dPFWoYRMFC92ntH/jKg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-x64-msvc": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.2.4.tgz", + "integrity": "sha512-syTl1zbNQPj0HuiPEqSHT/wfLGxDCjrG17UaK1sIauZjDKisIyzN3DYE+WYuRy6wSNQ02jhPFmsvdxgntfQKFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/core": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.2.4.tgz", + "integrity": "sha512-p8/w2i3viGQDVaqbHZtKpBwQNG7rY+Bf8iwu3i+d4KHwC1+VMLc4fBD30qU+cAHuUtsdx15sicvTVz3CniYOlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rspack/binding": "2.2.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@module-federation/runtime-tools": "^0.24.1 || ^2.0.0", + "@swc/helpers": "^0.5.23" + }, + "peerDependenciesMeta": { + "@module-federation/runtime-tools": { + "optional": true + }, + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@rspack/plugin-react-refresh": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-2.0.2.tgz", + "integrity": "sha512-dGNZiCxQxgAUI9sah7gd8u+O7OJZRCmqtEJNDOd8xW5RqcieC86F7p5qcShyw6onH5pKf57evpr2VjGbaFGkZg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@rspack/core": "^2.0.0", + "react-refresh": ">=0.10.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + } + } + }, + "node_modules/@rstackjs/load-config": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@rstackjs/load-config/-/load-config-0.1.2.tgz", + "integrity": "sha512-6hChPVosmh2rzEt1M1CvGpsaE/+gGlt51ci5pbyd4Bd1FXyH+Owlg99ECvdcWtD7zdDwDM3jGkQL05xn9oWSIA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "jiti": "^2.0.0" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/@rstest/core": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/@rstest/core/-/core-0.11.12.tgz", + "integrity": "sha512-dklEYLtL1eip/11K+o3xEchEs2nCGua2u2W8Pycf6PS8TE0PDJH2Bn9y/txuQI4YVHyIQ88PISWtS6fVnxSyXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsbuild/core": "~2.2.2", + "@types/chai": "^5.2.3" + }, + "bin": { + "rstest": "bin/rstest.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "happy-dom": "^20.8.3", + "jsdom": ">=15.0.0" + }, + "peerDependenciesMeta": { + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.2.tgz", + "integrity": "sha512-xlvWf4Vs9n1PEVYwP1n4vvG07M6y8WgvJ2t0vbrWTmijsIHp1cS+uJ2kMIRdY3nHZK0nCYKrPeD171+SzF4/zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-bundle": { + "version": "0.0.0-preview-8e55ab8", + "resolved": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@8e55ab832d", + "integrity": "sha512-Tu5c2WtFk7LhmjLi4n3g25Yr+h4+87Qydc9JXFn77b9LE+icpTnFeI0ihK8S8kMeoav96wJNBM4O8uK67jcjZw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@effect/platform-node-shared": "4.0.0-rc.112", + "@modelcontextprotocol/client": "2.0.0", + "@modelcontextprotocol/node": "2.0.0", + "@modelcontextprotocol/server": "2.0.0", + "@rsbuild/core": "2.2.3", + "@rsbuild/plugin-react": "2.1.0", + "@rslib/core": "1.0.0", + "@rslint/core": "0.9.1", + "@rstackjs/load-config": "0.1.2", + "acorn": "8.18.0", + "ajv": "8.20.0", + "ajv-formats": "3.0.1", + "chokidar": "5.0.0", + "commander": "15.0.0", + "effect": "4.0.0-rc.112", + "es-module-lexer": "2.3.2", + "fast-glob": "3.3.3", + "ignore": "7.0.8", + "jiti": "2.7.0", + "npm-package-arg": "14.0.0", + "ws": "8.21.3", + "yaml": "2.9.0" + }, + "bin": { + "agent-bundle": "bin/agent-bundle.js" + }, + "engines": { + "node": ">=22.19.0" + }, + "peerDependencies": { + "@agent-bundle/runtime": "0.0.0-preview-8e55ab8", + "@rstest/core": "^0.11.10", + "react": "^19.2.0" + }, + "peerDependenciesMeta": { + "@agent-bundle/runtime": { + "optional": true + }, + "@rstest/core": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/agent-bundle/node_modules/@rsbuild/core": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.2.3.tgz", + "integrity": "sha512-oJrYtYDhb7AMwY8HIda2hgMuuxHkYPYar4svdS5uTq0fXY0M1wLfllkTQz0d729pNJ4S//6GUM1WX5LsW2mFLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rspack/core": "~2.2.2", + "@swc/helpers": "^0.5.23" + }, + "bin": { + "rsbuild": "bin/rsbuild.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "core-js": ">= 3.0.0" + }, + "peerDependenciesMeta": { + "core-js": { + "optional": true + } + } + }, + "node_modules/agent-bundle/node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cac": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz", + "integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/effect": { + "version": "4.0.0-rc.112", + "resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-rc.112.tgz", + "integrity": "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-check": "^4.9.0", + "msgpackr": "^2.0.5" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.1.tgz", + "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/fast-check": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.10.0.tgz", + "integrity": "sha512-hhqQL+IJllZi3aM4TKvmCj3bywLEcycNTTLZeLhA9ttMxBrCqM07q7Di4kl+j9EWSTXvJH1+EpIgsDbF/+8H5Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^8.0.0" + }, + "engines": { + "node": ">=12.17.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, + "node_modules/fast-uri": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "node_modules/fastq": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flare-redact": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/flare-redact/-/flare-redact-1.6.1.tgz", + "integrity": "sha512-13Htu6VPk2ttxcoVOP909pXao6orrIBAMS/qWdhQn3/BS5AxSB5fpyqaPZnRGJhfBAM2M9T+RE662hxEpv6nGQ==", + "dev": true, + "license": "MIT", + "bin": { + "flare-gateway": "bin/flare-gateway.mjs", + "flare-redact": "bin/flare-redact.mjs" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hono": { + "version": "4.13.8", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.8.tgz", + "integrity": "sha512-/Gng7NfoykZl2pjukW5Z6+8Yxm3BPRf86GTbQnt0SbySkvax4fyL4H3HhY1cCpBGmiW9XDRFzRV+CXK2W8QudQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/hosted-git-info": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-10.1.1.tgz", + "integrity": "sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/human-id": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.2.1.tgz", + "integrity": "sha512-zPGsiS+dWoTZtZ4AtpA9Y+BdSFSNWvnouNlWNoUFyAM6xHOHmdCvqO3k8AIbdamCOv4gUFUVNPf6rJFfc4UiJw==", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, + "node_modules/ignore": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", + "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jose": { + "version": "6.2.12", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz", + "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/launch-editor": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz", + "integrity": "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.4" + } + }, + "node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/msgpackr": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-2.1.0.tgz", + "integrity": "sha512-p/pBCVO63CsvvpkomUnNNag6+n38rULuDA6HHe70o2gtC8ODI52foF/4ko2qQcp6OiErJXTmrZeXmsGGHsIQNQ==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.4" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.4.tgz", + "integrity": "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" + } + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/npm-package-arg": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-14.0.0.tgz", + "integrity": "sha512-69XQh3k+dtGa1p+7RaR57IuG3rCko96xr/nUfN4yDYBXbTYICiWcOpsFKLN2GtGE9cyIljE+f1exnaYt9MvM+Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^10.1.0", + "proc-log": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^8.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/package-manager-detector": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz", + "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/proc-log": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-7.0.0.tgz", + "integrity": "sha512-FYgfaA69XZ93zaXLoMNQ+ViDXGGBgR8aLh03txzcFhV+9xOXx7+8DLCULrKKpR9+GsH9ZfHm82aSUPpozX0Ztg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/pure-rand": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.2.tgz", + "integrity": "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", + "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "scheduler": "^0.28.0" + }, + "peerDependencies": { + "react": "^19.3.0" + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-server-dom-rspack": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/react-server-dom-rspack/-/react-server-dom-rspack-0.1.0.tgz", + "integrity": "sha512-KqDzmxBUZEcAphwg/PnEHOBkqTJjesTmLoBygLHie1gkiLINiZuVKPRccS6qDzfdj9ccYCaJ743IDYVh0wPf/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "@rspack/core": "^2.2.0-0", + "react": "^19.1.0", + "react-dom": "^19.1.0" + } + }, + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rsbuild-plugin-dts": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rsbuild-plugin-dts/-/rsbuild-plugin-dts-1.0.0.tgz", + "integrity": "sha512-FVoTsiTfSc0LPeSjrVhpvFOBRig0YXJq3Hp+bVxzh9/bzFvODzLRWOEux8q1Phe1oVCIIVSc2+Nb7kDcxIhosw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ast-grep/napi": "0.45.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7", + "@rsbuild/core": "^2.0.0", + "typescript": "^5 || ^6 || ^7" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/rsc-markdown-stream": { + "version": "0.0.0-preview-8e55ab8", + "resolved": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/rsc-markdown-stream@8e55ab832dd38705e23828b2fe25200c4d5f5c88", + "integrity": "sha512-RP/8ZAncasrZarL6M/v9TRheKMyN8o/JLT2C1+vtJIzUOkRjBKXxK2VPJjgXZ79yqDsiaU/uH0UXYCbei1G3PA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=22.19.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", + "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/validate-npm-package-name": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-8.0.0.tgz", + "integrity": "sha512-SCv6OOV6Xj2/3cXy3dGmADluJTNcL3o7hZAglNPTe+WYuEuvxgJzxPrSDLZhF+CwyQOubqgecjMmTJGMVLWjYQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", "dev": true, "license": "ISC", "bin": { @@ -550,6 +2960,16 @@ "funding": { "url": "https://github.com/sponsors/eemeli" } + }, + "node_modules/zod": { + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", + "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index 685ef92..918080e 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,29 @@ { "name": "grok-bot-cli", "version": "0.3.1", - "description": "CLI for Grok Bot agents and groups: create, update, message, inspect threads, and automate cleanup", + "description": "CLI and Agent Bundle plugin for Grok Bot agents and groups: create, update, message, inspect threads, and automate cleanup", "type": "module", "bin": { - "gbot": "src/cli.js", - "grok-bot": "src/cli.js" + "gbot": "./dist/bin/gbot.mjs", + "gbot-install": "./dist/bin/gbot-install.js", + "grok-bot": "./dist/bin/gbot.mjs" }, "engines": { - "node": ">=18" + "node": ">=22.19.0" }, "scripts": { + "build": "agent-bundle build", "changeset": "changeset", - "gbot": "node src/cli.js", + "check": "npm run validate && npm run build && npm run validate:artifact && npm run typecheck && npm test", + "gbot": "node dist/bin/gbot.mjs", + "prepack": "agent-bundle prepack", "release": "changeset publish", - "test": "node scripts/run-unit-tests.mjs" + "test": "npm run test:unit && npm run test:routes", + "test:routes": "rstest --config rstest.route-unit.config.ts", + "test:unit": "node scripts/run-unit-tests.mjs", + "typecheck": "tsc -p tsconfig.json --noEmit", + "validate": "agent-bundle validate", + "validate:artifact": "agent-bundle validate --artifact artifact" }, "repository": { "type": "git", @@ -35,14 +44,25 @@ "ai-agents", "automation", "terminal", - "cli" + "cli", + "agent-bundle" ], "files": [ - "src", + "dist", "README.md", + "CHANGELOG.md", "LICENSE" ], "devDependencies": { - "@changesets/cli": "3.0.3" + "@agent-bundle/runtime": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@8e55ab832d", + "@changesets/cli": "3.0.3", + "@rstest/core": "0.11.12", + "@types/node": "^22.18.0", + "@types/react": "^19.2.18", + "agent-bundle": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@8e55ab832d", + "react": "19.3.0", + "react-dom": "19.3.0", + "typescript": "7.0.2", + "zod": "4.6.5" } } diff --git a/plugin/agent-bundle.config.ts b/plugin/agent-bundle.config.ts deleted file mode 100644 index 16b0991..0000000 --- a/plugin/agent-bundle.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { defineConfig } from 'agent-bundle/config'; - -export default defineConfig({ - lib: false, - marketplace: true, - output: { distPath: 'artifact' }, - plugin: { - description: - 'Message Grok Bot bots and groups and read their threads from Codex, Claude Code, and Cursor.', - name: 'grok-bot', - }, - targets: ['claude', 'codex', 'cursor', 'portable'], - // `grok-bot-cli` is the parent checkout linked in through `file:..`. Rspack - // would otherwise realpath the link to a source outside the plugin root, - // which the compiler rejects; kept as a node_modules path it bundles like - // any dependency. - tools: { rspack: { resolve: { symlinks: false } } }, -}); diff --git a/plugin/package-lock.json b/plugin/package-lock.json deleted file mode 100644 index 21a72b3..0000000 --- a/plugin/package-lock.json +++ /dev/null @@ -1,2439 +0,0 @@ -{ - "name": "grok-bot-plugin", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "grok-bot-plugin", - "version": "0.1.0", - "dependencies": { - "@agent-bundle/runtime": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@62ffe403c5af73499fe7f5767c6d60be26e250db", - "grok-bot-cli": "file:..", - "react": "19.3.0", - "react-dom": "19.3.0", - "zod": "4.6.5" - }, - "devDependencies": { - "@rstest/core": "0.11.12", - "@types/node": "^24.0.0", - "@types/react": "^19.2.18", - "agent-bundle": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@62ffe403c5af73499fe7f5767c6d60be26e250db", - "typescript": "7.0.2" - }, - "engines": { - "node": ">=22.19.0" - } - }, - "..": { - "version": "0.2.3", - "license": "MIT", - "bin": { - "gbot": "src/cli.js", - "grok-bot": "src/cli.js" - }, - "devDependencies": { - "@changesets/cli": "3.0.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@agent-bundle/runtime": { - "version": "0.0.0-preview-62ffe40", - "resolved": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@62ffe403c5af73499fe7f5767c6d60be26e250db", - "integrity": "sha512-9UOa9oBHMndugsVwD869n1KzqYqqsI3I106ZtaOEPM4y7vR/ZU0qNBMeRO5IcdW2bZR9C4GKt1yKDpJEF8PkHA==", - "license": "Apache-2.0", - "dependencies": { - "@modelcontextprotocol/server": "2.0.0", - "effect": "4.0.0-rc.112", - "flare-redact": "1.6.1", - "react-server-dom-rspack": "0.1.0", - "rsc-markdown-stream": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/rsc-markdown-stream@62ffe403c5af73499fe7f5767c6d60be26e250db" - }, - "engines": { - "node": ">=22.19.0" - }, - "peerDependencies": { - "@rspack/core": "^2.2.0-0", - "react": "^19.2.0", - "react-dom": "^19.2.0", - "zod": "^4.5.4" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - } - } - }, - "node_modules/@ast-grep/napi": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi/-/napi-0.45.2.tgz", - "integrity": "sha512-hBA5c7JV6OM7zFWoLjUNZhsDpxEIEIeew5S3z1giwK5tPQqobuFfM2OhS45bN3E0+yQtgCX/o8/AEHKbGD3ykg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@ast-grep/napi-darwin-arm64": "0.45.2", - "@ast-grep/napi-darwin-x64": "0.45.2", - "@ast-grep/napi-linux-arm64-gnu": "0.45.2", - "@ast-grep/napi-linux-arm64-musl": "0.45.2", - "@ast-grep/napi-linux-x64-gnu": "0.45.2", - "@ast-grep/napi-linux-x64-musl": "0.45.2", - "@ast-grep/napi-win32-arm64-msvc": "0.45.2", - "@ast-grep/napi-win32-ia32-msvc": "0.45.2", - "@ast-grep/napi-win32-x64-msvc": "0.45.2" - } - }, - "node_modules/@ast-grep/napi-darwin-arm64": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-arm64/-/napi-darwin-arm64-0.45.2.tgz", - "integrity": "sha512-29+sfXTJ7xxqgTuWAHA89gDAQIiJyAZ1ZiHoupjKIqyn0mhXrktO1WOghlDzyYs++hITEPOeXftxy48Y0tDGDQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ast-grep/napi-darwin-x64": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-x64/-/napi-darwin-x64-0.45.2.tgz", - "integrity": "sha512-PUjh7Zf4dKNzYLOYhX5wU6O4BgRPdJnD9zkS1n+/5SeK0U1L5YL486RjNgFt9Xyff0PGtP/wDeoHMF5PhKEwsw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ast-grep/napi-linux-arm64-gnu": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-gnu/-/napi-linux-arm64-gnu-0.45.2.tgz", - "integrity": "sha512-bnGKLLHWO13pjPChOFq7Ifqj3HJdOAxMQAGDCUC2JSJhO2YL8/xBZrpN0cHIWNuoUNSAXjCtr5AsCnPz/3jlFg==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ast-grep/napi-linux-arm64-musl": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-musl/-/napi-linux-arm64-musl-0.45.2.tgz", - "integrity": "sha512-FXVb4/V55THjhKxi5zWVrAO8JQj+/DiYP7JLsqenkm5V3UNuC8p2opGOyQpUvNpvcqJiZA9Hl+Onj/yfwSVr/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ast-grep/napi-linux-x64-gnu": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-gnu/-/napi-linux-x64-gnu-0.45.2.tgz", - "integrity": "sha512-mtEIPLV9MW2PBswFcp3ydM4T5Ub73s89SRd0QMT2+DfA9XBLCLhnC+r/Yt4eRgnf8FyNx49bFTPxXvFKscr9hw==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ast-grep/napi-linux-x64-musl": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-musl/-/napi-linux-x64-musl-0.45.2.tgz", - "integrity": "sha512-WLLHxDmuXkb/e3mz/xDCrB2dZPzv1ntsepuRTtpaIGczxnQTgFSzX/CXPD0e1MfsU/QL1AiXxxni8w+NGy/ZpQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ast-grep/napi-win32-arm64-msvc": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-arm64-msvc/-/napi-win32-arm64-msvc-0.45.2.tgz", - "integrity": "sha512-04iOFaMzD2nf8CKw3nURWN42900wqPtUTQaMo1I2KRk3qbgtHSJjJoVJGAWUXkCq4LhPg3Xlk1s+ssWf4rNm2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ast-grep/napi-win32-ia32-msvc": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-ia32-msvc/-/napi-win32-ia32-msvc-0.45.2.tgz", - "integrity": "sha512-tE3y0RQcajocKwpYLbgHKd4lzGGAx1wGMA0bGPsWdoFK8VSob6ZDuYdSlSdnaRs8jAc4F3axToNRKn15p+0/Dg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ast-grep/napi-win32-x64-msvc": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-x64-msvc/-/napi-win32-x64-msvc-0.45.2.tgz", - "integrity": "sha512-o8Z5Z42TAJe0fPnb11rrjtte58wlw/MuR4KpVMHl8IhJLBBR7gHR0E8wfMz88TxzsQz0U2KYev0k0a2fV4i0sQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@effect/platform-node-shared": { - "version": "4.0.0-rc.112", - "resolved": "https://registry.npmjs.org/@effect/platform-node-shared/-/platform-node-shared-4.0.0-rc.112.tgz", - "integrity": "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/ws": "^8.18.1", - "ws": "^8.21.3" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "effect": "^4.0.0-rc.112" - } - }, - "node_modules/@emnapi/core": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", - "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.3", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", - "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", - "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@hono/node-server": { - "version": "1.19.17", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.17.tgz", - "integrity": "sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@modelcontextprotocol/client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.0.0.tgz", - "integrity": "sha512-8f1OghQ2rjzIOfqgUCP+8GiUWqRs89njoWLNqAe8kWmDePv3s1fZXseej+QXemssEuuOvLLmLO/kqM3IQHtISw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/core": "2.0.0", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "jose": "^6.1.3", - "pkce-challenge": "^5.0.0", - "zod": "^4.2.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@modelcontextprotocol/core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.0.0.tgz", - "integrity": "sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==", - "license": "MIT", - "dependencies": { - "zod": "^4.2.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@modelcontextprotocol/node": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/node/-/node-2.0.0.tgz", - "integrity": "sha512-Y4hAC2XdGDUdDOCbLDOCA4+aL3NUldjsOWlDL/YwpAxrPhRm1xHd7lZ+mLacvZ9t3PaH28wgNoaLQGrIk1P2pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@modelcontextprotocol/server": "^2.0.0", - "hono": "^4.11.4" - }, - "peerDependenciesMeta": { - "hono": { - "optional": true - } - } - }, - "node_modules/@modelcontextprotocol/server": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.0.0.tgz", - "integrity": "sha512-YhHWdHfpFMQfd0prsEnxKeS3Qz3ytIGmsS0sth4KDjnacIT7hxk6hXHkJ9KysxlkvTM+WZAtQbbcUhdoP4Hvtw==", - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/core": "2.0.0", - "zod": "^4.2.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.4.tgz", - "integrity": "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.4.tgz", - "integrity": "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.4.tgz", - "integrity": "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.4.tgz", - "integrity": "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.4.tgz", - "integrity": "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.4.tgz", - "integrity": "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rsbuild/core": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.2.6.tgz", - "integrity": "sha512-+BoNmacdQ2j9ysUunVUm2CTK7Aff70l4P/m29R5AWjd2vCU+X7bo6u3geMMJV0+j/JUHzoccC1ERIEhzqnD3Xg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rspack/core": "~2.2.4", - "@swc/helpers": "^0.5.23" - }, - "bin": { - "rsbuild": "bin/rsbuild.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "core-js": ">= 3.0.0" - }, - "peerDependenciesMeta": { - "core-js": { - "optional": true - } - } - }, - "node_modules/@rsbuild/plugin-react": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@rsbuild/plugin-react/-/plugin-react-2.1.0.tgz", - "integrity": "sha512-RQTIAWB/CwPjoWt9iAl+8HixeQVgZ7kEIBrWPCixfITyHdiD84h0YpUTpEUuz6kGHw1KXT9mHZ3Rwy6WG7aRDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rspack/plugin-react-refresh": "^2.0.2", - "react-refresh": "^0.18.0" - }, - "peerDependencies": { - "@rsbuild/core": "^2.0.0" - }, - "peerDependenciesMeta": { - "@rsbuild/core": { - "optional": true - } - } - }, - "node_modules/@rslib/core": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rslib/core/-/core-1.0.0.tgz", - "integrity": "sha512-eZNXCWU1v5oti4+DKCunc76DkNnYqMgRtks9UyZRRFlmaK4pKAxhejeCUS+XkbMurGIAa+aDyVynQD7DXEgK1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rsbuild/core": "~2.2.2", - "rsbuild-plugin-dts": "1.0.0" - }, - "bin": { - "rslib": "bin/rslib.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@microsoft/api-extractor": "^7", - "typescript": "^5 || ^6 || ^7" - }, - "peerDependenciesMeta": { - "@microsoft/api-extractor": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/@rslint/core": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@rslint/core/-/core-0.9.1.tgz", - "integrity": "sha512-MRS6lS+GiobBr+iIl5iFAYfwhhxVJX28lB6uVnwH40U49DCPUF0J2qlKI7RewPKDmKp5uosKJcvpxE8Rm7aVcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^4.0.5" - }, - "bin": { - "rslint": "bin/rslint.js" - }, - "optionalDependencies": { - "@rslint/native-darwin-arm64": "0.9.1", - "@rslint/native-darwin-x64": "0.9.1", - "@rslint/native-linux-arm64-gnu": "0.9.1", - "@rslint/native-linux-arm64-musl": "0.9.1", - "@rslint/native-linux-x64-gnu": "0.9.1", - "@rslint/native-linux-x64-musl": "0.9.1", - "@rslint/native-win32-arm64-msvc": "0.9.1", - "@rslint/native-win32-x64-msvc": "0.9.1" - }, - "peerDependencies": { - "jiti": "^2.7.0" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/@rslint/native-darwin-arm64": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@rslint/native-darwin-arm64/-/native-darwin-arm64-0.9.1.tgz", - "integrity": "sha512-WuWZObUanaYI+93vnld+3LNXJeCkMA5ntkBs8VMptBrPa64H4K/WEm4BN1Z8NLjW5TnYWhG1wVgRE2Ie8UeSYg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rslint/native-darwin-x64": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@rslint/native-darwin-x64/-/native-darwin-x64-0.9.1.tgz", - "integrity": "sha512-Pce+LuyMmqBNwPjXMg5MEgo3nu36H3p7FyAwWEn8dlmUAQPhe3BQQ73fa7TT/97I9yfXY+YmJVRjLuctHQKmbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rslint/native-linux-arm64-gnu": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@rslint/native-linux-arm64-gnu/-/native-linux-arm64-gnu-0.9.1.tgz", - "integrity": "sha512-pzt13FMri+oYevnR1xXo8CJkwr+RjxCFGJnYxoJ4C3jUKJLK+aJTlREDX1gnCMAXxx02YIUAqBrc4zQ09PAKsw==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rslint/native-linux-arm64-musl": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@rslint/native-linux-arm64-musl/-/native-linux-arm64-musl-0.9.1.tgz", - "integrity": "sha512-+fe6CNu+C5mshQ0hDyi/NakM3rqMyvMqKUf5ldNTQhaNUYavdb9cP7yXJw/H6qwHB6wbZIqSDo3b6HohzgnBkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rslint/native-linux-x64-gnu": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@rslint/native-linux-x64-gnu/-/native-linux-x64-gnu-0.9.1.tgz", - "integrity": "sha512-119QVNJATOI21fGB5OsYfu0DXo7UMyyEpLi9TCogiZQF1X9QkPDdH0DXVQb2yi/H8H6FlNXak91G5vJ2W0SY2w==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rslint/native-linux-x64-musl": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@rslint/native-linux-x64-musl/-/native-linux-x64-musl-0.9.1.tgz", - "integrity": "sha512-eUkiywQGG0umzYU86n1ZetCPBS1bLUFJZkFB+MovbDQQF+V9R6xA7x2mJvODnA7laOB3e7VK/uF56RvUebtzXQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rslint/native-win32-arm64-msvc": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@rslint/native-win32-arm64-msvc/-/native-win32-arm64-msvc-0.9.1.tgz", - "integrity": "sha512-e0GLvCYh2XiQtVoFxbeU/QuM1mC6PWQATZbPN6fxfB4ZFH3S8KbcYCNFJyTEHp5WbU4XFJnut1qEf2u8pBoADA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rslint/native-win32-x64-msvc": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@rslint/native-win32-x64-msvc/-/native-win32-x64-msvc-0.9.1.tgz", - "integrity": "sha512-pofbo2UYBjK/OwNstlBEH89/XMUllp3PVTz21wQ7ryu3yH8atCzP2CX4Jv8IQ7eWpDJyMALhkXeEy5bsbI04xw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rspack/binding": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.2.4.tgz", - "integrity": "sha512-KoH5Wofyt1+egnqWF3pr8ItiYQiLgrHYLHOAn4YpzIMsGc8zDur3dCIhrhJ1uhbD3O7zkKqav4he3bo1kAmX9Q==", - "license": "MIT", - "optionalDependencies": { - "@rspack/binding-darwin-arm64": "2.2.4", - "@rspack/binding-darwin-x64": "2.2.4", - "@rspack/binding-linux-arm64-gnu": "2.2.4", - "@rspack/binding-linux-arm64-musl": "2.2.4", - "@rspack/binding-linux-ppc64-gnu": "2.2.4", - "@rspack/binding-linux-riscv64-gnu": "2.2.4", - "@rspack/binding-linux-riscv64-musl": "2.2.4", - "@rspack/binding-linux-s390x-gnu": "2.2.4", - "@rspack/binding-linux-x64-gnu": "2.2.4", - "@rspack/binding-linux-x64-musl": "2.2.4", - "@rspack/binding-wasm32-wasi": "2.2.4", - "@rspack/binding-win32-arm64-msvc": "2.2.4", - "@rspack/binding-win32-ia32-msvc": "2.2.4", - "@rspack/binding-win32-x64-msvc": "2.2.4" - } - }, - "node_modules/@rspack/binding-darwin-arm64": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.2.4.tgz", - "integrity": "sha512-PmwL+7nlD58tvGi2tUct2D6HzPsCeICvNpfgznzFjvrGlmPOm7pn5ahaevEf0C5QRHldf97qShekits4bzArsQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rspack/binding-darwin-x64": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.2.4.tgz", - "integrity": "sha512-eFVBlPe/32eNaC5oIQFIfMRIic/+670iK+hep4eFSuDzJPC2QBXviSDrNRIdshTFNirCquR1+idT0XI74JYBjw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rspack/binding-linux-arm64-gnu": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.2.4.tgz", - "integrity": "sha512-/gyHP8DVezbTzey3wCknCRSKHzxZmfOAVtoNhNfQ2+9+wNaZUKjjaGuLc/IOc1CVeZ9cE30bNzJdun+/F9KNrg==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-arm64-musl": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.2.4.tgz", - "integrity": "sha512-eNXOvP4hKpRozCLsutbGU7R8mQ9S3OaSbgK5T/aitEAeIzFMorkcbVJopVKwEDLxrNSTfndTedefkYN+pdhsYQ==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-ppc64-gnu": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-2.2.4.tgz", - "integrity": "sha512-WmlhV3nXgiKiSAFc5QVSYgurbTyF+fGUgd59JWsMCPmqwgTmNyjq6mjmoa6fzKtX/4+oKFUBBn4CdO1uCKU/ww==", - "cpu": [ - "ppc64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-riscv64-gnu": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-2.2.4.tgz", - "integrity": "sha512-EGqzydSCvB1o8aVk0H+HM1npAk63ZRR8jSTqzY0GQ4nz+30LHZ/Ah1Eba91OsUAgfKwk3ffP5a7EoizH24m2Rg==", - "cpu": [ - "riscv64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-riscv64-musl": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-2.2.4.tgz", - "integrity": "sha512-5A5vzbvNBvuAQ4ZGEAdVl8gcFowgqCCVz3fCh12Jq3WHynl3J4JHAMnVQMs7A/KmaBhwKYDtO4FUvWh5V/BNKA==", - "cpu": [ - "riscv64" - ], - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-s390x-gnu": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-2.2.4.tgz", - "integrity": "sha512-AWGTTx5ZkMe/hHTjpbIdxJ2xzMrSaL+01zpzV2LpGhheiXeDmwId9yYEEG8vwtzzVmz8lS5VBRIdy3Kx/k4m8A==", - "cpu": [ - "s390x" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-x64-gnu": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.2.4.tgz", - "integrity": "sha512-wzVC7AkyGD0rAdV41pKxwokvdAEY47HazjdUd3Pq2MT/rHNkhgsbCOVbrl4Ts2vQqiLrFfnnNZs383492oIrQw==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-x64-musl": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.2.4.tgz", - "integrity": "sha512-Gpxo27eJ+r53ebWdm8FIg6jtlEOr4T5Yit7FgF8Ib9U78Et9qGcbnvVQONHjz8gUe2hvwg9QQ1EJZechSpVB8A==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-wasm32-wasi": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.2.4.tgz", - "integrity": "sha512-Ak0PYNbyQd/0d7xsuCCBvc/V9+S8+NoHHv5dzlHepa6udSF7zKDxv9MxRMdhIIBrgn+8GMHQb3ohwW1XjzmONg==", - "cpu": [ - "wasm32" - ], - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.11.3", - "@emnapi/runtime": "1.11.3", - "@napi-rs/wasm-runtime": "1.1.6" - } - }, - "node_modules/@rspack/binding-win32-arm64-msvc": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.2.4.tgz", - "integrity": "sha512-OVynh1BYpAKSdvopHR4P/Qy1y17YgF3qLGcRYDGTvwAYOX7EyHS/7YK8BX12T2dDZV2UhEa2t98fNncX5H/O3Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rspack/binding-win32-ia32-msvc": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.2.4.tgz", - "integrity": "sha512-Q3yuEY/ayWjF0dO6Guj1cPH97jyaazNXRUzZz5/qz1BuuCPUaV7/LMUz1HHKOqxCw13dPFWoYRMFC92ntH/jKg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rspack/binding-win32-x64-msvc": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.2.4.tgz", - "integrity": "sha512-syTl1zbNQPj0HuiPEqSHT/wfLGxDCjrG17UaK1sIauZjDKisIyzN3DYE+WYuRy6wSNQ02jhPFmsvdxgntfQKFw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rspack/core": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.2.4.tgz", - "integrity": "sha512-p8/w2i3viGQDVaqbHZtKpBwQNG7rY+Bf8iwu3i+d4KHwC1+VMLc4fBD30qU+cAHuUtsdx15sicvTVz3CniYOlg==", - "license": "MIT", - "dependencies": { - "@rspack/binding": "2.2.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@module-federation/runtime-tools": "^0.24.1 || ^2.0.0", - "@swc/helpers": "^0.5.23" - }, - "peerDependenciesMeta": { - "@module-federation/runtime-tools": { - "optional": true - }, - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/@rspack/plugin-react-refresh": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-2.0.2.tgz", - "integrity": "sha512-dGNZiCxQxgAUI9sah7gd8u+O7OJZRCmqtEJNDOd8xW5RqcieC86F7p5qcShyw6onH5pKf57evpr2VjGbaFGkZg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@rspack/core": "^2.0.0", - "react-refresh": ">=0.10.0 <1.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - } - } - }, - "node_modules/@rstackjs/load-config": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@rstackjs/load-config/-/load-config-0.1.2.tgz", - "integrity": "sha512-6hChPVosmh2rzEt1M1CvGpsaE/+gGlt51ci5pbyd4Bd1FXyH+Owlg99ECvdcWtD7zdDwDM3jGkQL05xn9oWSIA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "jiti": "^2.0.0" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/@rstest/core": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/@rstest/core/-/core-0.11.12.tgz", - "integrity": "sha512-dklEYLtL1eip/11K+o3xEchEs2nCGua2u2W8Pycf6PS8TE0PDJH2Bn9y/txuQI4YVHyIQ88PISWtS6fVnxSyXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rsbuild/core": "~2.2.2", - "@types/chai": "^5.2.3" - }, - "bin": { - "rstest": "bin/rstest.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "happy-dom": "^20.8.3", - "jsdom": ">=15.0.0" - }, - "peerDependenciesMeta": { - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/@swc/helpers": { - "version": "0.5.23", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", - "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", - "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.4.tgz", - "integrity": "sha512-YJ7EqCstVTzIr0fMr7qul/977en+pQHrfmuKIo6Zr9i75Be21dr3MovcfvGtyvi2HAUrRerWps5sMO9I7WaxDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@types/react": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", - "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript/typescript-aix-ppc64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", - "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-darwin-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", - "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-darwin-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", - "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-freebsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", - "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-freebsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", - "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-arm": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", - "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", - "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-loong64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", - "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-mips64el": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", - "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-ppc64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", - "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-riscv64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", - "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-s390x": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", - "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", - "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-netbsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", - "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-netbsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", - "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-openbsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", - "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-openbsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", - "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-sunos-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", - "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-win32-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", - "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-win32-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", - "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/acorn": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", - "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-bundle": { - "version": "0.0.0-preview-62ffe40", - "resolved": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@62ffe403c5af73499fe7f5767c6d60be26e250db", - "integrity": "sha512-EAslzg8LEazB4lL6Tl3GQlZ++YhGyWQU14aLlCeifz3fhMS+FL/0HXmKSkPJR1h5GogZd82lH8b6EORbGoEN9A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@effect/platform-node-shared": "4.0.0-rc.112", - "@modelcontextprotocol/client": "2.0.0", - "@modelcontextprotocol/node": "2.0.0", - "@modelcontextprotocol/server": "2.0.0", - "@rsbuild/core": "2.2.3", - "@rsbuild/plugin-react": "2.1.0", - "@rslib/core": "1.0.0", - "@rslint/core": "0.9.1", - "@rstackjs/load-config": "0.1.2", - "acorn": "8.18.0", - "ajv": "8.20.0", - "ajv-formats": "3.0.1", - "chokidar": "5.0.0", - "commander": "15.0.0", - "effect": "4.0.0-rc.112", - "es-module-lexer": "2.3.2", - "fast-glob": "3.3.3", - "ignore": "7.0.8", - "jiti": "2.7.0", - "npm-package-arg": "14.0.0", - "ws": "8.21.3", - "yaml": "2.9.0" - }, - "bin": { - "agent-bundle": "bin/agent-bundle.js" - }, - "engines": { - "node": ">=22.19.0" - }, - "peerDependencies": { - "@agent-bundle/runtime": "0.0.0-preview-62ffe40", - "@rstest/core": "^0.11.10", - "react": "^19.2.0" - }, - "peerDependenciesMeta": { - "@agent-bundle/runtime": { - "optional": true - }, - "@rstest/core": { - "optional": true - }, - "react": { - "optional": true - } - } - }, - "node_modules/agent-bundle/node_modules/@rsbuild/core": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.2.3.tgz", - "integrity": "sha512-oJrYtYDhb7AMwY8HIda2hgMuuxHkYPYar4svdS5uTq0fXY0M1wLfllkTQz0d729pNJ4S//6GUM1WX5LsW2mFLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rspack/core": "~2.2.2", - "@swc/helpers": "^0.5.23" - }, - "bin": { - "rsbuild": "bin/rsbuild.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "core-js": ">= 3.0.0" - }, - "peerDependenciesMeta": { - "core-js": { - "optional": true - } - } - }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/commander": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", - "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/effect": { - "version": "4.0.0-rc.112", - "resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-rc.112.tgz", - "integrity": "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A==", - "license": "MIT", - "dependencies": { - "fast-check": "^4.9.0", - "msgpackr": "^2.0.5" - } - }, - "node_modules/es-module-lexer": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", - "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", - "dev": true, - "license": "MIT" - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.1.tgz", - "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/fast-check": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.10.0.tgz", - "integrity": "sha512-hhqQL+IJllZi3aM4TKvmCj3bywLEcycNTTLZeLhA9ttMxBrCqM07q7Di4kl+j9EWSTXvJH1+EpIgsDbF/+8H5Q==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT", - "dependencies": { - "pure-rand": "^8.0.0" - }, - "engines": { - "node": ">=12.17.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-uri": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", - "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", - "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flare-redact": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/flare-redact/-/flare-redact-1.6.1.tgz", - "integrity": "sha512-13Htu6VPk2ttxcoVOP909pXao6orrIBAMS/qWdhQn3/BS5AxSB5fpyqaPZnRGJhfBAM2M9T+RE662hxEpv6nGQ==", - "license": "MIT", - "bin": { - "flare-gateway": "bin/flare-gateway.mjs", - "flare-redact": "bin/flare-redact.mjs" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/grok-bot-cli": { - "resolved": "..", - "link": true - }, - "node_modules/hono": { - "version": "4.13.7", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.7.tgz", - "integrity": "sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/hosted-git-info": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-10.1.1.tgz", - "integrity": "sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^11.1.0" - }, - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" - } - }, - "node_modules/ignore": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", - "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jiti": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", - "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/jose": { - "version": "6.2.12", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz", - "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/msgpackr": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-2.1.0.tgz", - "integrity": "sha512-p/pBCVO63CsvvpkomUnNNag6+n38rULuDA6HHe70o2gtC8ODI52foF/4ko2qQcp6OiErJXTmrZeXmsGGHsIQNQ==", - "license": "MIT", - "optionalDependencies": { - "msgpackr-extract": "^3.0.4" - } - }, - "node_modules/msgpackr-extract": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.4.tgz", - "integrity": "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "node-gyp-build-optional-packages": "5.2.2" - }, - "bin": { - "download-msgpackr-prebuilds": "bin/download-prebuilds.js" - }, - "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", - "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", - "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", - "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" - } - }, - "node_modules/node-gyp-build-optional-packages": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", - "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", - "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.1" - }, - "bin": { - "node-gyp-build-optional-packages": "bin.js", - "node-gyp-build-optional-packages-optional": "optional.js", - "node-gyp-build-optional-packages-test": "build-test.js" - } - }, - "node_modules/npm-package-arg": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-14.0.0.tgz", - "integrity": "sha512-69XQh3k+dtGa1p+7RaR57IuG3rCko96xr/nUfN4yDYBXbTYICiWcOpsFKLN2GtGE9cyIljE+f1exnaYt9MvM+Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^10.1.0", - "proc-log": "^7.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^8.0.0" - }, - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/proc-log": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-7.0.0.tgz", - "integrity": "sha512-FYgfaA69XZ93zaXLoMNQ+ViDXGGBgR8aLh03txzcFhV+9xOXx7+8DLCULrKKpR9+GsH9ZfHm82aSUPpozX0Ztg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" - } - }, - "node_modules/pure-rand": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.2.tgz", - "integrity": "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/react": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", - "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz", - "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.28.0" - }, - "peerDependencies": { - "react": "^19.3.0" - } - }, - "node_modules/react-refresh": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", - "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-server-dom-rspack": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/react-server-dom-rspack/-/react-server-dom-rspack-0.1.0.tgz", - "integrity": "sha512-KqDzmxBUZEcAphwg/PnEHOBkqTJjesTmLoBygLHie1gkiLINiZuVKPRccS6qDzfdj9ccYCaJ743IDYVh0wPf/w==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "@rspack/core": "^2.2.0-0", - "react": "^19.1.0", - "react-dom": "^19.1.0" - } - }, - "node_modules/readdirp": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", - "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rsbuild-plugin-dts": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rsbuild-plugin-dts/-/rsbuild-plugin-dts-1.0.0.tgz", - "integrity": "sha512-FVoTsiTfSc0LPeSjrVhpvFOBRig0YXJq3Hp+bVxzh9/bzFvODzLRWOEux8q1Phe1oVCIIVSc2+Nb7kDcxIhosw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ast-grep/napi": "0.45.2" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@microsoft/api-extractor": "^7", - "@rsbuild/core": "^2.0.0", - "typescript": "^5 || ^6 || ^7" - }, - "peerDependenciesMeta": { - "@microsoft/api-extractor": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/rsc-markdown-stream": { - "version": "0.0.0-preview-62ffe40", - "resolved": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/rsc-markdown-stream@62ffe403c5af73499fe7f5767c6d60be26e250db", - "integrity": "sha512-w7tS3Z2Cj4a9seDTrn/QpYo78sQoSsi/mWTiVMPvbbwDldAv75OnPuffRmvJnfXUhLrXhXzAOVTpy9+S7Z3iqQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=22.19.0" - }, - "peerDependencies": { - "react": "^19.0.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/scheduler": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", - "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "devOptional": true, - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", - "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc" - }, - "engines": { - "node": ">=16.20.0" - }, - "optionalDependencies": { - "@typescript/typescript-aix-ppc64": "7.0.2", - "@typescript/typescript-darwin-arm64": "7.0.2", - "@typescript/typescript-darwin-x64": "7.0.2", - "@typescript/typescript-freebsd-arm64": "7.0.2", - "@typescript/typescript-freebsd-x64": "7.0.2", - "@typescript/typescript-linux-arm": "7.0.2", - "@typescript/typescript-linux-arm64": "7.0.2", - "@typescript/typescript-linux-loong64": "7.0.2", - "@typescript/typescript-linux-mips64el": "7.0.2", - "@typescript/typescript-linux-ppc64": "7.0.2", - "@typescript/typescript-linux-riscv64": "7.0.2", - "@typescript/typescript-linux-s390x": "7.0.2", - "@typescript/typescript-linux-x64": "7.0.2", - "@typescript/typescript-netbsd-arm64": "7.0.2", - "@typescript/typescript-netbsd-x64": "7.0.2", - "@typescript/typescript-openbsd-arm64": "7.0.2", - "@typescript/typescript-openbsd-x64": "7.0.2", - "@typescript/typescript-sunos-x64": "7.0.2", - "@typescript/typescript-win32-arm64": "7.0.2", - "@typescript/typescript-win32-x64": "7.0.2" - } - }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/validate-npm-package-name": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-8.0.0.tgz", - "integrity": "sha512-SCv6OOV6Xj2/3cXy3dGmADluJTNcL3o7hZAglNPTe+WYuEuvxgJzxPrSDLZhF+CwyQOubqgecjMmTJGMVLWjYQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/ws": { - "version": "8.21.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", - "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/zod": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", - "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/plugin/package.json b/plugin/package.json deleted file mode 100644 index 0d79f95..0000000 --- a/plugin/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "grok-bot-plugin", - "version": "0.1.0", - "private": true, - "description": "Agent Bundle plugin: message Grok Bot from Codex, Claude Code, and Cursor through the gbot gateway client.", - "type": "module", - "engines": { - "node": ">=22.19.0" - }, - "scripts": { - "build": "agent-bundle build", - "check": "npm run validate && npm run build && npm run validate:artifact && npm run typecheck && npm test", - "test": "rstest --config rstest.route-unit.config.ts", - "typecheck": "tsc -p tsconfig.json --noEmit", - "validate": "agent-bundle validate", - "validate:artifact": "agent-bundle validate --artifact artifact" - }, - "dependencies": { - "@agent-bundle/runtime": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@62ffe403c5af73499fe7f5767c6d60be26e250db", - "grok-bot-cli": "file:..", - "react": "19.3.0", - "react-dom": "19.3.0", - "zod": "4.6.5" - }, - "devDependencies": { - "@rstest/core": "0.11.12", - "@types/node": "^24.0.0", - "@types/react": "^19.2.18", - "agent-bundle": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@62ffe403c5af73499fe7f5767c6d60be26e250db", - "typescript": "7.0.2" - } -} diff --git a/plugin/rstest.route-unit.config.ts b/rstest.route-unit.config.ts similarity index 100% rename from plugin/rstest.route-unit.config.ts rename to rstest.route-unit.config.ts diff --git a/src/cli.js b/src/cli.js deleted file mode 100755 index 57e6bd2..0000000 --- a/src/cli.js +++ /dev/null @@ -1,684 +0,0 @@ -#!/usr/bin/env node -import { AVATAR_COLORS, AVATAR_SHAPES, MAX_GROUP_MEMBERS, StoreError, defaultCandidateRoots, looksLikeAgentsRoot, resolveAgentsRoot } from "./store.js"; -import { hasGatewayAuth } from "./gateway.js"; -import { openBackend } from "./commands.js"; -import { inspectGrokBotGatewaySession } from "./app-session.js"; -import { entryText, transcriptDelta, transcriptEntries } from "./transcript.js"; -import { historyPath, readHistory, saveHistory } from "./history.js"; -import { redactSecrets } from "./url-policy.js"; -import { buildEnvelope, codexStatus, listCodexQueue, listCodexThreads, sendToCodexThread, singleLine, stripTerminalControls, withEnvelopeHeader } from "./codex-bridge.js"; - -function print(value) { - if (typeof value === "string") process.stdout.write(value + "\n"); - else process.stdout.write(JSON.stringify(value, null, 2) + "\n"); -} - -/** Exit 1 for every failure; `--json` callers read `reason` / `mode` / `delivery` instead of the exit code. */ -function fail(err) { - let message = err instanceof Error ? err.message : String(err); - message = redactSecrets(message); - if (jsonErrors && err instanceof Error) { - const out = { error: message }; - for (const key of ["delivery", "reason", "mode", "threadId", "turnId", "targetId", "messageId", "correlationId"]) { - if (err[key] !== undefined) out[key] = err[key]; - } - if (out.reason === undefined && err instanceof StoreError) out.reason = "usage"; - if (err.envelope && typeof err.envelope === "object") { - out.messageId = err.envelope.messageId; - out.correlationId = err.envelope.correlationId; - out.hop = err.envelope.hop; - } - process.stderr.write(JSON.stringify(out) + "\n"); - } else { - process.stderr.write(message + "\n"); - } - process.exit(1); -} - -function usage() { - return [ - "gbot - manage Grok Bot agents and groups", - "", - "Usage:", - " gbot [--dir DIR] [--json] ", - "", - "Commands:", - " doctor", - " bots list", - " bots create --name NAME [--description TEXT] [--instructions TEXT] [--title TEXT]", - " [--avatar-shape SHAPE] [--avatar-color COLOR]", - " bots update [--name NAME] [--description TEXT] [--instructions TEXT]", - " [--title TEXT] [--avatar-shape SHAPE] [--avatar-color COLOR]", - " [--notify on|off] [--hidden on|off]", - " bots get ", - " bots delete ", - " groups list", - " groups create --name NAME --member ID_OR_NAME [--member ...]", - " [--description TEXT] [--instructions TEXT] [--title TEXT]", - " [--avatar-shape SHAPE] [--avatar-color COLOR]", - " groups update (same flags as bots update; members stay on set/add/remove)", - " groups get ", - " groups members ", - " groups add ", - " groups remove ", - " groups set --member ID [--member ...]", - " groups delete ", - " send [envelope flags] ", - " thread [--limit N] [--after ENTRY_ID] [--root MESSAGE_ID] [--full]", - " chat alias for thread", - " history [bot-or-group] [--search TEXT] [--limit N] (offline)", - " history --path print the local JSONL file path", - " codex status", - " codex list-threads [--limit N] [--cursor CURSOR]", - " codex send [envelope flags] [--when-busy reject|queue] ", - " codex queue (experimental: GROK_BOT_CODEX_EXPERIMENTAL=1)", - "", - "Envelope flags (before the target): --correlation-id ID --reply-to MESSAGE_ID --hop N --envelope", - " Receipts carry messageId/correlationId/hop; a reply passes the original correlation id and hop+1.", - " Sends at hop >= GROK_BOT_MAX_HOPS (default 4) are refused. --envelope prepends the [gbot ...] header.", - "", - "Max group members: " + MAX_GROUP_MEMBERS, - "--description / --instructions is the UI Instructions field (same key).", - "Avatar shapes: " + AVATAR_SHAPES.join(" "), - "Avatar colors: " + AVATAR_COLORS.join(" "), - "Flags: --gateway --files --dir DIR --json", - "Auth: GROK_BOT_GATEWAY_URL + GROK_BOT_GATEWAY_TOKEN, or the Grok Bot app session, or CURSOR_ACCESS_TOKEN", - "File fallback: GROK_BOT_AGENTS_DIR", - "Codex: talks to the local app-server daemon socket under CODEX_HOME (default ~/.codex)", - " GROK_BOT_CODEX_THREADS=id,id restricts `codex send` to operator-approved threads", - "History: opt-in plaintext JSONL at ~/.grok-bot-cli/history.jsonl", - " GROK_BOT_HISTORY=on to record; --history-dir / GROK_BOT_HISTORY_DIR to relocate", - " --no-history to skip one command", - ].join("\n"); -} - -/** `opaque` values may start with `-` (pagination cursors); ordinary values may not. */ -function takeFlag(args, name, { opaque = false } = {}) { - const i = args.indexOf(name); - if (i === -1) return undefined; - const value = args[i + 1]; - if (value == null || value === "" || (!opaque && value.startsWith("-"))) throw new StoreError(name + " needs a value"); - args.splice(i, 2); - return value; -} - -function takeLastFlag(args, ...names) { - let value; - let seen = false; - for (;;) { - let hit = false; - for (const name of names) { - const i = args.indexOf(name); - if (i === -1) continue; - const next = args[i + 1]; - if (next == null || next.startsWith("-")) throw new StoreError(name + " needs a value"); - args.splice(i, 2); - value = next; - seen = true; - hit = true; - break; - } - if (!hit) break; - } - return seen ? value : undefined; -} - -function takeRepeating(args, name) { - const out = []; - for (;;) { - const value = takeFlag(args, name); - if (value == null) break; - out.push(value); - } - return out; -} - -function hasFlag(args, name) { - const i = args.indexOf(name); - if (i === -1) return false; - args.splice(i, 1); - return true; -} - -/** Peel a trailing flag that `--` does not protect; free-text commands keep mid-text tokens. */ -function takeTrailingFlag(args, name) { - const stop = args.indexOf("--"); - const end = stop === -1 ? args.length : stop; - if (end > 0 && args[end - 1] === name) { - args.splice(end - 1, 1); - return true; - } - return false; -} - -/** Peel global CLI options only from the leading argv (before the command). */ -let jsonErrors = false; -function takeLeadingGlobals(args) { - let json = false; - let gateway = false; - let files = false; - let noHistory = false; - let historyDir; - let dir; - while (args.length) { - const a = args[0]; - if (a === "--") { - args.shift(); - break; - } - if (a === "--json") { - json = true; - jsonErrors = true; - args.shift(); - continue; - } - if (a === "--gateway") { - gateway = true; - args.shift(); - continue; - } - if (a === "--files") { - files = true; - args.shift(); - continue; - } - if (a === "--no-history") { - noHistory = true; - args.shift(); - continue; - } - if (a === "--history-dir") { - args.shift(); - const value = args.shift(); - if (value == null || value.startsWith("-")) throw new StoreError("--history-dir needs a value"); - historyDir = value; - continue; - } - if (a === "--dir") { - args.shift(); - const value = args.shift(); - if (value == null || value.startsWith("-")) throw new StoreError("--dir needs a value"); - dir = value; - continue; - } - break; - } - return { json, gateway, files, dir, noHistory, historyDir }; -} - -function parseOnOff(value, flag) { - const v = String(value).trim().toLowerCase(); - if (v === "on" || v === "true" || v === "1" || v === "yes") return true; - if (v === "off" || v === "false" || v === "0" || v === "no") return false; - throw new StoreError(flag + " must be on|off (or true|false|1|0|yes|no)"); -} - -function takeCreateFields(args) { - return { - name: takeFlag(args, "--name"), - description: takeLastFlag(args, "--description", "--instructions") ?? "", - title: takeFlag(args, "--title") ?? "", - avatarShape: takeFlag(args, "--avatar-shape") ?? "", - avatarColor: takeFlag(args, "--avatar-color") ?? "", - }; -} - -function takeUpdatePatch(args) { - const name = takeFlag(args, "--name"); - const description = takeLastFlag(args, "--description", "--instructions"); - const title = takeFlag(args, "--title"); - const avatarShape = takeFlag(args, "--avatar-shape"); - const avatarColor = takeFlag(args, "--avatar-color"); - const notifyRaw = takeFlag(args, "--notify"); - const hiddenRaw = takeFlag(args, "--hidden"); - const patch = {}; - if (name !== undefined) patch.name = name; - if (description !== undefined) patch.description = description; - if (title !== undefined) patch.title = title; - if (avatarShape !== undefined) patch.avatarShape = avatarShape; - if (avatarColor !== undefined) patch.avatarColor = avatarColor; - if (notifyRaw !== undefined) patch.notifyOnAgentUpdates = parseOnOff(notifyRaw, "--notify"); - if (hiddenRaw !== undefined) patch.hiddenFromSidebar = parseOnOff(hiddenRaw, "--hidden"); - if (Object.keys(patch).length === 0) { - throw new StoreError("update needs at least one of --name --description --instructions --title --avatar-shape --avatar-color --notify --hidden"); - } - return patch; -} - -function summarize(rec) { - return { - id: rec.id, - name: rec.name, - title: rec.title || undefined, - description: rec.description || undefined, - avatarShape: rec.avatarShape || undefined, - avatarColor: rec.avatarColor || undefined, - ...(rec.notifyOnAgentUpdates !== undefined ? { notifyOnAgentUpdates: rec.notifyOnAgentUpdates } : {}), - ...(rec.hiddenFromSidebar !== undefined ? { hiddenFromSidebar: rec.hiddenFromSidebar } : {}), - kind: rec.isGroup ? "group" : "bot", - members: rec.isGroup ? rec.memberIds : undefined, - }; -} - -function done(json, rec, text) { - print(json ? summarize(rec) : text); -} - -function formatRecord(rec, all) { - const kind = rec.isGroup ? "group" : "bot"; - const members = rec.isGroup - ? rec.memberIds.map((id) => { - const m = all.find((r) => r.id === id); - return m ? m.name + " (" + id + ")" : id; - }).join(", ") - : ""; - const title = rec.title ? " - " + rec.title : ""; - const desc = rec.description ? "\n " + rec.description : ""; - const avatar = rec.avatarShape || rec.avatarColor - ? "\n avatar: " + [rec.avatarShape, rec.avatarColor].filter(Boolean).join(" ") - : ""; - const settings = []; - if (rec.notifyOnAgentUpdates !== undefined) settings.push("notify " + (rec.notifyOnAgentUpdates ? "on" : "off")); - if (rec.hiddenFromSidebar !== undefined) settings.push("hidden " + (rec.hiddenFromSidebar ? "on" : "off")); - const settingsLine = settings.length ? "\n " + settings.join(", ") : ""; - const extra = rec.isGroup ? "\n members (" + rec.memberIds.length + "): " + (members || "(none)") : ""; - return kind + " " + rec.name + title + "\n " + rec.id + desc + avatar + settingsLine + extra; -} - -function formatTranscript(out, { full = false } = {}) { - const rec = out.target; - const payload = out.transcript || out.thread || {}; - const entries = transcriptEntries(payload); - const header = (rec.isGroup ? "group" : "bot") + " " + rec.name + "\n " + rec.id; - if (!Array.isArray(entries) || entries.length === 0) { - return header + "\n (no messages)"; - } - const lines = [header, ""]; - for (const e of entries) { - const role = e.role || e.kind || e.sender || e.type || "msg"; - const text = entryText(e); - const id = e.id || e.messageId || ""; - lines.push("[" + role + (id ? " " + id : "") + "] " + (full ? text : truncateCliText(text))); - } - return lines.join("\n"); -} - -/** Bounded preview; --json/--full still retrieve the complete text. */ -function truncateCliText(text, max = 400) { - if (text.length <= max) return text; - return text.slice(0, max) + "… [+" + (text.length - max) + " chars; --full or --json for complete text]"; -} - -function formatCodexStatus(s) { - const lines = ["socket: " + s.socketPath + " (" + s.socketState + ")"]; - if (!s.reachable) return lines.concat("reachable: no (" + s.mode + ")", s.message).join("\n"); - if (s.mode !== "daemon") return lines.concat("reachable: yes, but unusable (" + s.mode + ")", s.message).join("\n"); - lines.push("reachable: yes (daemon)"); - const cli = s.cliVersion ?? (s.cliVersionProbe === "ok" ? "unknown" : "unknown, probe " + s.cliVersionProbe); - lines.push("daemon version: " + (s.daemonVersion ?? "unknown") + " cli version: " + cli + " pinned schema: " + s.pinnedVersion + " (" + s.schema.compatibility + ")"); - lines.push("desktop attached: unknown (not observable from the socket)"); - if (s.versionMismatch) lines.push("warning: daemon and CLI versions differ; `codex app-server daemon restart` picks up the installed CLI"); - return lines.join("\n"); -} - -function formatCodexThread(t) { - const title = t.name ? " - " + stripTerminalControls(t.name) : ""; - const preview = t.preview - ? "\n " + stripTerminalControls(String(t.preview).replace(/\s+/g, " ")).slice(0, 200) - : ""; - return stripTerminalControls(t.id) + " " + stripTerminalControls(t.status) + title + "\n " + stripTerminalControls(t.cwd ?? "") + preview; -} - -/** Structured subcommands accept only their documented flags; anything left over is an error. */ -function rejectUnknownArgs(rest, usageLine) { - if (rest.length) throw new StoreError("Unknown argument " + JSON.stringify(rest[0]) + ". Usage: " + usageLine); -} - -/** - * Envelope flags live before the free-text target so message bodies keep their own `--` tokens. - * Returns a built envelope (or a hop-limit refusal) plus whether any flag was given. - */ -function takeEnvelopeFlags(rest, { busyPolicy = false } = {}) { - let correlationId; - let replyTo; - let hop; - let envelope = false; - let whenBusy = "reject"; - for (;;) { - const a = rest[0]; - if (busyPolicy && a === "--when-busy") { - rest.shift(); - whenBusy = rest.shift(); - if (whenBusy !== "reject" && whenBusy !== "queue") throw new StoreError("--when-busy must be reject or queue"); - continue; - } - if (a === "--correlation-id") { rest.shift(); correlationId = rest.shift(); if (correlationId == null) throw new StoreError("--correlation-id needs a value"); continue; } - if (a === "--reply-to") { rest.shift(); replyTo = rest.shift(); if (replyTo == null) throw new StoreError("--reply-to needs a value"); continue; } - if (a === "--hop") { - rest.shift(); - const raw = rest.shift(); - if (raw == null || !/^\d+$/.test(raw)) throw new StoreError("--hop must be a non-negative integer"); - hop = Number(raw); - continue; - } - if (a === "--envelope") { rest.shift(); envelope = true; continue; } - break; - } - try { - return { envelope: buildEnvelope({ correlationId, replyTo, hop, envelope }), whenBusy }; - } catch (err) { - if (err instanceof RangeError) throw new StoreError(err.message); - throw err; - } -} - -async function codexStatusCommand(rest, json) { - rejectUnknownArgs(rest, "gbot codex status [--json]"); - const status = await codexStatus(); - print(json ? status : formatCodexStatus(status)); - // Exit 0 only for a usable daemon; `mode` says why otherwise (reachable but off-schema included). - if (!status.reachable || status.mode !== "daemon") process.exitCode = 1; -} - -async function codexListCommand(rest, json) { - const limitRaw = takeFlag(rest, "--limit"); - const cursor = takeFlag(rest, "--cursor", { opaque: true }); - rejectUnknownArgs(rest, "gbot codex list-threads [--limit N] [--cursor CURSOR] [--json]"); - const limit = limitRaw ? Number(limitRaw) : 20; - let out; - try { - out = await listCodexThreads({ limit, cursor }); - } catch (err) { - if (err instanceof RangeError) throw new StoreError(err.message); - throw err; - } - if (json) print(out); - else if (out.threads.length === 0) print("No Codex threads."); - else print(out.threads.map(formatCodexThread).join("\n\n") + (out.nextCursor ? "\n\nmore: --cursor " + JSON.stringify(singleLine(out.nextCursor)) : "")); -} - -async function codexQueueCommand(rest, json) { - const threadId = rest.shift(); - rejectUnknownArgs(rest, "gbot codex queue [--json]"); - if (!threadId || threadId.startsWith("-")) throw new StoreError("gbot codex queue [--json]"); - const out = await listCodexQueue(threadId); - if (json) print(out); - else if (out.queued.length === 0) print("No queued submissions on Codex thread " + threadId + "."); - else print(out.queued.map((q) => q.id + " " + (q.clientUserMessageId ?? "") + "\n " + singleLine(q.text).slice(0, 200)).join("\n\n")); -} - -async function codexSendCommand(rest, json) { - const { envelope, whenBusy } = takeEnvelopeFlags(rest, { busyPolicy: true }); - const threadId = rest.shift(); - if (rest[0] === "--") rest.shift(); - const message = rest.join(" ").trim(); - if (!threadId || threadId.startsWith("-") || !message) throw new StoreError("gbot codex send [envelope flags] [--when-busy reject|queue] "); - const out = await sendToCodexThread(threadId, message, { envelope, whenBusy }); - if (json) print(out); - else if (out.delivery === "queued") print("Queued " + out.queuedSubmissionId + " on busy Codex thread " + out.threadId + "; message " + out.messageId); - else print("Started turn " + out.turnId + " (" + out.turnStatus + ") on Codex thread " + out.threadId + "; message " + out.messageId); -} - -async function runCodex(sub, rest, json) { - // Structured subcommands take no free text, so --json peels anywhere. Send - // peels a trailing --json only; mid-message tokens stay message content. - const structured = sub === "status" || sub === "list-threads" || sub === "queue"; - if (structured ? hasFlag(rest, "--json") : sub === "send" && takeTrailingFlag(rest, "--json")) { json = true; jsonErrors = true; } - if (sub === "status") return codexStatusCommand(rest, json); - if (sub === "list-threads") return codexListCommand(rest, json); - if (sub === "queue") return codexQueueCommand(rest, json); - if (sub === "send") return codexSendCommand(rest, json); - throw new StoreError("gbot codex status | list-threads [--limit N] [--cursor CURSOR] | queue | send [envelope flags] [--when-busy reject|queue] "); -} - -async function main(argv) { - const args = argv.slice(2); - if (args.length === 0 || args[0] === "-h" || args[0] === "--help") { - print(usage()); - return; - } - - // `json` may also be peeled later from command-local argv (trailing `--json`). - let { json, gateway, files: filesMode, dir: rootFlag, noHistory, historyDir } = takeLeadingGlobals(args); - const cmd = args[0]; - const sub = args[1]; - const rest = args.slice(2); - if (!cmd) { - print(usage()); - return; - } - - if (cmd === "doctor") { - const candidates = defaultCandidateRoots(); - const found = candidates.filter(looksLikeAgentsRoot); - let resolved = null; - try { - resolved = resolveAgentsRoot(rootFlag); - } catch (err) { - if (!(err instanceof StoreError)) throw err; - } - const note = "Live roster is on the box. Prefer CURSOR_ACCESS_TOKEN then EnsureSandBox then POST gateway /api/*."; - const gatewayAuthPresent = hasGatewayAuth(); - const grokBotAppSession = inspectGrokBotGatewaySession(); - const payload = { resolved, found, candidates, gatewayAuthPresent, grokBotAppSession, note }; - if (json) print(payload); - else { - print("resolved: " + (resolved ?? "(none)")); - print("gateway auth: " + (gatewayAuthPresent ? "present" : "no")); - if (grokBotAppSession.usable) print("Grok Bot app session: usable"); - else if (grokBotAppSession.present) print("Grok Bot app session: present but unusable: " + grokBotAppSession.error); - else print("Grok Bot app session: not found"); - print("found:"); - print(found.length ? found.map((p) => " " + p).join("\n") : " (none)"); - print("candidates:"); - for (const c of candidates) print(" " + c); - print(note); - } - return; - } - - if (cmd === "history") { - const options = args.slice(1); - // Command-local flags (globals only peel from argv before the command). - if (hasFlag(options, "--json")) { json = true; jsonErrors = true; } - const showPath = hasFlag(options, "--path"); - const search = takeFlag(options, "--search"); - const limitRaw = takeFlag(options, "--limit"); - const limit = limitRaw === undefined ? 40 : Number(limitRaw); - if (!Number.isSafeInteger(limit) || limit < 1) throw new StoreError("--limit must be a positive integer"); - if (options.length > 1 || options[0]?.startsWith("-") || (showPath && (options.length || search !== undefined || limitRaw !== undefined))) { - throw new StoreError("gbot history [bot-or-group] [--search TEXT] [--limit N], or history --path"); - } - const path = historyPath(historyDir); - if (showPath) print(json ? { path } : path); - else { - const rows = await readHistory(path, { ref: options[0], search, limit }); - if (json) print(rows); - else print(rows.length ? rows.map((row) => - "[" + row.recordedAt + "] " + row.target.name + " (" + row.target.id + ") [" + row.role + "] " + row.text - ).join("\n") : "No local history."); - } - return; - } - - if (cmd === "codex") { - await runCodex(sub, rest, json); - return; - } - - // Peel command-local --json before touching the backend so auth/gateway - // failures honor it. Send peels a trailing --json only (mid-text tokens stay - // message content); `--` protects everything after it. - if (cmd === "send" && takeTrailingFlag(rest, "--json")) { json = true; jsonErrors = true; } - if ((cmd === "thread" || cmd === "chat") && hasFlag(rest, "--json")) { json = true; jsonErrors = true; } - - const backend = await openBackend({ root: rootFlag, gateway, files: filesMode }); - - if (cmd === "bots" && sub === "list") { - const rows = (await backend.list()).filter((r) => !r.isGroup); - if (json) print(rows.map(summarize)); - else if (rows.length === 0) print("No bots."); - else print(rows.map((r) => formatRecord(r, rows)).join("\n\n")); - return; - } - - if (cmd === "bots" && sub === "create") { - const fields = takeCreateFields(rest); - const rec = await backend.createAgent(fields); - done(json, rec, "Created bot " + rec.name + " (" + rec.id + ")"); - return; - } - - if (cmd === "bots" && sub === "update") { - const ref = rest.shift(); - if (!ref || ref.startsWith("-")) throw new StoreError("gbot bots update [--name NAME] ..."); - const rec = await backend.updateAgent(ref, takeUpdatePatch(rest)); - done(json, rec, "Updated " + (rec.isGroup ? "group" : "bot") + " " + rec.name + " (" + rec.id + ")"); - return; - } - - if (cmd === "bots" && (sub === "get" || sub === "delete")) { - const ref = rest[0]; - if (!ref) throw new StoreError("gbot bots " + sub + " "); - if (sub === "get") { - const rec = await backend.resolve(ref); - if (json) print(summarize(rec)); - else print(formatRecord(rec, await backend.list())); - return; - } - const rec = await backend.deleteAgent(ref); - done(json, rec, "Deleted " + (rec.isGroup ? "group" : "bot") + " " + rec.name + " (" + rec.id + ")"); - return; - } - - if (cmd === "groups" && sub === "list") { - const all = await backend.list(); - const rows = all.filter((r) => r.isGroup); - if (json) print(rows.map(summarize)); - else if (rows.length === 0) print("No groups."); - else print(rows.map((r) => formatRecord(r, all)).join("\n\n")); - return; - } - - if (cmd === "groups" && sub === "delete") { - const ref = rest[0]; - if (!ref) throw new StoreError("gbot groups delete "); - const rec = await backend.resolve(ref); - if (!rec.isGroup) throw new StoreError('"' + rec.name + '" is a bot, not a group. Use bots delete.'); - const deleted = await backend.deleteAgent(ref); - done(json, deleted, "Deleted group " + deleted.name + " (" + deleted.id + ")"); - return; - } - - if (cmd === "groups" && sub === "create") { - const fields = takeCreateFields(rest); - const members = takeRepeating(rest, "--member"); - const rec = await backend.createGroup({ ...fields, memberIds: members }); - done(json, rec, "Created group " + rec.name + " (" + rec.id + ") with " + rec.memberIds.length + " members"); - return; - } - - if (cmd === "groups" && sub === "update") { - const ref = rest.shift(); - if (!ref || ref.startsWith("-")) throw new StoreError("gbot groups update [--name NAME] ..."); - const current = await backend.resolve(ref); - if (!current.isGroup) throw new StoreError('"' + current.name + '" is a bot, not a group. Use bots update.'); - const rec = await backend.updateAgent(ref, takeUpdatePatch(rest)); - done(json, rec, "Updated group " + rec.name + " (" + rec.id + ")"); - return; - } - - if (cmd === "groups" && (sub === "get" || sub === "members")) { - const ref = rest[0]; - if (!ref) throw new StoreError("gbot groups " + sub + " "); - const rec = await backend.resolve(ref); - if (!rec.isGroup) throw new StoreError('"' + rec.name + '" is a bot, not a group.'); - if (json) print(summarize(rec)); - else print(formatRecord(rec, await backend.list())); - return; - } - - if (cmd === "groups" && (sub === "add" || sub === "remove")) { - const group = rest[0]; - const bot = rest[1]; - if (!group || !bot) throw new StoreError("gbot groups " + sub + " "); - const rec = sub === "add" - ? await backend.addGroupMember(group, bot) - : await backend.removeGroupMember(group, bot); - const verb = sub === "add" ? "Added to " : "Removed from "; - done(json, rec, verb + rec.name + ". Members: " + rec.memberIds.length); - return; - } - - if (cmd === "groups" && sub === "set") { - const group = rest.shift(); - const members = takeRepeating(rest, "--member"); - if (!group) throw new StoreError("gbot groups set --member ID [--member ...]"); - const rec = await backend.setGroupMembers(group, members); - done(json, rec, "Updated " + rec.name + ". Members: " + rec.memberIds.length); - return; - } - - if (cmd === "send") { - // Envelope flags precede the target: `gbot send --reply-to M --hop 1 `. - const sendArgs = [sub, ...rest].filter((a) => a !== undefined); - // Trailing --json is a flag; `--` protects a message that ends with one. - if (takeTrailingFlag(sendArgs, "--json")) { json = true; jsonErrors = true; } - const { envelope } = takeEnvelopeFlags(sendArgs); - const ref = sendArgs.shift(); - if (sendArgs[0] === "--") sendArgs.shift(); - const message = sendArgs.join(" ").trim(); - if (!ref || ref.startsWith("-") || !message) throw new StoreError("gbot send [envelope flags] "); - const out = await backend.send(ref, withEnvelopeHeader(message, envelope)); - saveHistory(out, { dir: historyDir, disabled: noHistory, event: "send", prompt: message }); - // The gateway's message id (when returned) is the delivery receipt; the local envelope id - // is the correlation handle a reply quotes back with --reply-to. - const receipt = out.messageId ? " message " + out.messageId : ""; - if (json) { - print({ - id: out.target.id, - name: out.target.name, - kind: out.target.isGroup ? "group" : "bot", - result: out.result, - delivery: out.delivery || "accepted", - ...(out.messageId ? { messageId: out.messageId } : {}), - envelopeId: envelope.messageId, - correlationId: envelope.correlationId, - ...(envelope.replyTo ? { replyTo: envelope.replyTo } : {}), - hop: envelope.hop, - maxHops: envelope.maxHops, - }); - } else print("Sent to " + (out.target.isGroup ? "group" : "bot") + " " + out.target.name + " (" + out.target.id + ")" + receipt + "; envelope " + envelope.messageId); - return; - } - - if (cmd === "thread" || cmd === "chat") { - const ref = sub; - if (!ref) throw new StoreError("gbot thread [--limit N] [--after ENTRY_ID] [--root MESSAGE_ID] [--full]"); - const full = hasFlag(rest, "--full"); - const limitRaw = takeFlag(rest, "--limit"); - const rootId = takeFlag(rest, "--root"); - const after = takeFlag(rest, "--after"); - const limit = limitRaw ? Number(limitRaw) : 40; - if (!Number.isInteger(limit) || limit < 1 || limit > 200) throw new StoreError("--limit must be an integer 1-200"); - if (after !== undefined && (after.length === 0 || after.length > 1024)) throw new StoreError("--after must be 1-1024 characters"); - if (after !== undefined && rootId !== undefined) throw new StoreError("--after cannot be combined with --root"); - const out = rootId ? await backend.thread(ref, rootId) : await backend.transcript(ref, limit); - let selected = out; - if (after !== undefined) { - const delta = transcriptDelta(out.transcript, { after, limit }); - selected = { ...out, transcript: { entries: delta.entries }, cursor: delta.cursor, entryCount: delta.entryCount, gapReset: delta.gapReset }; - } - saveHistory(selected, { dir: historyDir, disabled: noHistory, event: cmd, rootId }); - if (json) print(selected); - else { - const text = formatTranscript(selected, { full }); - print(after === undefined ? text : text + "\n\ncursor: " + selected.cursor + (selected.gapReset ? " (gap reset)" : "")); - } - return; - } - - throw new StoreError(usage()); -} - -main(process.argv).catch(fail); diff --git a/src/cli/_shared.ts b/src/cli/_shared.ts new file mode 100644 index 0000000..2beec81 --- /dev/null +++ b/src/cli/_shared.ts @@ -0,0 +1,105 @@ +import { z } from 'zod'; + +import { openBackend } from '../core/commands.js'; +import { AVATAR_COLORS, AVATAR_SHAPES } from '../core/store.js'; +import { withRedactedErrors } from '../gbot.js'; + +/** Shared backend selection flags (were leading globals on the hand CLI). */ +export const backendFlagsSchema = z.object({ + dir: z.string().min(1).optional().describe('Agents directory for --files mode'), + files: z.boolean().optional().describe('Force the on-disk agents store'), + gateway: z.boolean().optional().describe('Force the live gateway'), +}).strict(); + +/** The flat failure document `outcomeFromError` builds for `exitCode: 'result'` routes. */ +export const failureDocumentSchema = z + .object({ + delivery: z.enum(['accepted', 'queued', 'rejected', 'unknown']), + error: z.string(), + exitCode: z.literal(1), + }) + .catchall(z.json()); + +// The framework prints thrown route errors verbatim; a fetch or proxy failure can echo a credential. +const redactBackendErrors = (backend: T): T => + new Proxy(backend, { + get(target, property, receiver) { + const value: unknown = Reflect.get(target, property, receiver); + return typeof value === 'function' + ? (...args: unknown[]) => withRedactedErrors(() => value.apply(target, args)) + : value; + }, + }); + +export const openBackendFromInput = async (input: { + readonly dir?: string; + readonly files?: boolean; + readonly gateway?: boolean; +}) => withRedactedErrors(async () => redactBackendErrors(await openBackend({ + files: Boolean(input.files), + gateway: Boolean(input.gateway), + root: input.dir, +}))); + +export const avatarShapeSchema = z.enum(AVATAR_SHAPES as unknown as [string, ...string[]]); +export const avatarColorSchema = z.enum(AVATAR_COLORS as unknown as [string, ...string[]]); + +export const onOffSchema = z.enum(['on', 'off']); + +export const parseOnOff = (value: 'on' | 'off'): boolean => value === 'on'; + +export const agentSummarySchema = z.object({ + avatarColor: z.string().optional(), + avatarShape: z.string().optional(), + description: z.string().optional(), + hiddenFromSidebar: z.boolean().optional(), + id: z.string(), + kind: z.enum(['bot', 'group']), + members: z.array(z.string()).optional(), + name: z.string(), + notifyOnAgentUpdates: z.boolean().optional(), + title: z.string().optional(), +}).strict(); + +export const createFieldsSchema = z.object({ + avatarColor: avatarColorSchema.optional(), + avatarShape: avatarShapeSchema.optional(), + description: z.string().optional(), + name: z.string().min(1), + title: z.string().optional(), +}).strict(); + +export const updateFieldsSchema = z.object({ + avatarColor: avatarColorSchema.optional(), + avatarShape: avatarShapeSchema.optional(), + description: z.string().optional(), + hidden: onOffSchema.optional(), + name: z.string().min(1).optional(), + notify: onOffSchema.optional(), + title: z.string().optional(), +}).strict(); + +export const toCreateInput = (fields: z.infer) => ({ + avatarColor: fields.avatarColor ?? '', + avatarShape: fields.avatarShape ?? '', + description: fields.description ?? '', + name: fields.name, + title: fields.title ?? '', +}); + +export const toUpdatePatch = (fields: z.infer) => { + const patch: Record = {}; + if (fields.name !== undefined) patch.name = fields.name; + if (fields.description !== undefined) patch.description = fields.description; + if (fields.title !== undefined) patch.title = fields.title; + if (fields.avatarShape !== undefined) patch.avatarShape = fields.avatarShape; + if (fields.avatarColor !== undefined) patch.avatarColor = fields.avatarColor; + if (fields.notify !== undefined) patch.notifyOnAgentUpdates = parseOnOff(fields.notify); + if (fields.hidden !== undefined) patch.hiddenFromSidebar = parseOnOff(fields.hidden); + if (Object.keys(patch).length === 0) { + throw new Error( + 'update needs at least one of --name --description --title --avatar-shape --avatar-color --notify --hidden', + ); + } + return patch; +}; diff --git a/src/cli/bots/create.tsx b/src/cli/bots/create.tsx new file mode 100644 index 0000000..c315e5f --- /dev/null +++ b/src/cli/bots/create.tsx @@ -0,0 +1,45 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; + +import { summarize } from '../../core/format.js'; +import { + agentSummarySchema, + backendFlagsSchema, + createFieldsSchema, + openBackendFromInput, + toCreateInput, +} from '../_shared.js'; + +export const config = { + description: 'Create a Grok Bot bot.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + avatarColor: { type: 'string' }, + avatarShape: { type: 'string' }, + description: { type: 'string' }, + name: { type: 'string' }, + title: { type: 'string' }, + }, + required: ['name'], + type: 'object', + }, +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.merge(createFieldsSchema).strict(); +export const resultSchema = agentSummarySchema; + +export default async function botsCreate({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const { dir: _d, files: _f, gateway: _g, ...fields } = input; + const rec = await backend.createAgent(toCreateInput(fields)); + if (rec == null) throw new Error('createAgent returned no record'); + return ( + + {`Created bot ${rec.name} (${rec.id})`} + + ); +} diff --git a/src/cli/bots/delete.tsx b/src/cli/bots/delete.tsx new file mode 100644 index 0000000..7521893 --- /dev/null +++ b/src/cli/bots/delete.tsx @@ -0,0 +1,35 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: 'Delete a bot or group by id or name.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + ref: { description: 'Bot or group id or name', type: 'string' }, + }, + required: ['ref'], + type: 'object', + }, + positionals: ['ref'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.extend({ ref: z.string().min(1) }).strict(); +export const resultSchema = agentSummarySchema; + +export default async function botsDelete({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const rec = await backend.deleteAgent(input.ref); + return ( + + {`Deleted ${rec.isGroup ? 'group' : 'bot'} ${rec.name} (${rec.id})`} + + ); +} diff --git a/src/cli/bots/get.tsx b/src/cli/bots/get.tsx new file mode 100644 index 0000000..a0da841 --- /dev/null +++ b/src/cli/bots/get.tsx @@ -0,0 +1,36 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { formatRecord, summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: 'Show one bot or group by id or name.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + ref: { description: 'Bot or group id or name', type: 'string' }, + }, + required: ['ref'], + type: 'object', + }, + positionals: ['ref'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.extend({ ref: z.string().min(1) }).strict(); +export const resultSchema = agentSummarySchema; + +export default async function botsGet({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const rec = await backend.resolve(input.ref); + const all = await backend.list(); + return ( + + {formatRecord(rec, all)} + + ); +} diff --git a/src/cli/bots/list.tsx b/src/cli/bots/list.tsx new file mode 100644 index 0000000..cb84694 --- /dev/null +++ b/src/cli/bots/list.tsx @@ -0,0 +1,35 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { formatRecord, summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: 'List Grok Bot bots (not groups).', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + }, + type: 'object', + }, +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema; +export const resultSchema = z.array(agentSummarySchema); + +export default async function botsList({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const all = await backend.list(); + const rows = all.filter((r: { isGroup?: boolean }) => !r.isGroup); + const bots = rows.map(summarize); + const text = rows.length === 0 ? 'No bots.' : rows.map((r: Parameters[0]) => formatRecord(r, all)).join('\n\n'); + return ( + + {text} + + ); +} diff --git a/src/cli/bots/update.tsx b/src/cli/bots/update.tsx new file mode 100644 index 0000000..dab74db --- /dev/null +++ b/src/cli/bots/update.tsx @@ -0,0 +1,49 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { summarize } from '../../core/format.js'; +import { + agentSummarySchema, + backendFlagsSchema, + openBackendFromInput, + toUpdatePatch, + updateFieldsSchema, +} from '../_shared.js'; + +export const config = { + description: 'Update a bot or group profile.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + avatarColor: { type: 'string' }, + avatarShape: { type: 'string' }, + description: { type: 'string' }, + hidden: { type: 'string' }, + name: { type: 'string' }, + notify: { type: 'string' }, + ref: { description: 'Bot or group id or name', type: 'string' }, + title: { type: 'string' }, + }, + required: ['ref'], + type: 'object', + }, + positionals: ['ref'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.merge(updateFieldsSchema).extend({ ref: z.string().min(1) }).strict(); +export const resultSchema = agentSummarySchema; + +export default async function botsUpdate({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const { dir: _d, files: _f, gateway: _g, ref, ...fields } = input; + const rec = await backend.updateAgent(ref, toUpdatePatch(fields)); + return ( + + {`Updated ${rec.isGroup ? 'group' : 'bot'} ${rec.name} (${rec.id})`} + + ); +} diff --git a/src/cli/codex/list-threads.tsx b/src/cli/codex/list-threads.tsx new file mode 100644 index 0000000..60949b5 --- /dev/null +++ b/src/cli/codex/list-threads.tsx @@ -0,0 +1,63 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { listCodexThreads, singleLine } from '../../core/codex-bridge.js'; +import { outcomeFromError } from '../../core/codex/contract.js'; +import { formatCodexThread } from '../../core/format.js'; +import { failureDocumentSchema } from '../_shared.js'; + +export const config = { + description: 'List Codex daemon-managed threads.', + exitCode: 'result', + inputJsonSchema: { + additionalProperties: false, + properties: { + cursor: { + description: 'Opaque pagination cursor (may start with -)', + type: 'string', + }, + limit: { default: 20, description: 'Max threads to list (1-200)', type: 'number' }, + }, + type: 'object', + }, +} satisfies CliRouteConfig; + +export const inputSchema = z.object({ + cursor: z.string().min(1).optional(), + limit: z.number().int().min(1).max(200).default(20), +}).strict(); +export const resultSchema = z.union([ + z.object({ + exitCode: z.literal(0), + limit: z.number().int().min(1).max(200), + nextCursor: z.string().nullable(), + threads: z.array(z.record(z.string(), z.json())), + }).strict(), + failureDocumentSchema, +]); + +export default async function codexListThreads({ input }: CliRouteProps) { + let out; + try { + out = await listCodexThreads({ cursor: input.cursor, limit: input.limit }); + } catch (error) { + const failure = outcomeFromError(error); + return ( + + {failure.error} + + ); + } + const more = out.nextCursor + ? `\n\nmore: --cursor ${JSON.stringify(singleLine(out.nextCursor))}` + : ''; + const text = out.threads.length === 0 + ? 'No Codex threads.' + : out.threads.map(formatCodexThread).join('\n\n') + more; + return ( + + {text} + + ); +} diff --git a/src/cli/codex/queue.tsx b/src/cli/codex/queue.tsx new file mode 100644 index 0000000..8a3d339 --- /dev/null +++ b/src/cli/codex/queue.tsx @@ -0,0 +1,54 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { listCodexQueue } from '../../core/codex-bridge.js'; +import { outcomeFromError } from '../../core/codex/contract.js'; +import { formatCodexQueue } from '../../core/format.js'; +import { failureDocumentSchema } from '../_shared.js'; + +export const config = { + description: 'List the experimental Codex thread queue (GROK_BOT_CODEX_EXPERIMENTAL=1).', + exitCode: 'result', + inputJsonSchema: { + additionalProperties: false, + properties: { threadId: { type: 'string' } }, + required: ['threadId'], + type: 'object', + }, + positionals: ['threadId'], +} satisfies CliRouteConfig; + +export const inputSchema = z.object({ threadId: z.string().min(1) }).strict(); +export const resultSchema = z.union([ + z.object({ + exitCode: z.literal(0), + nextCursor: z.string().nullable(), + queued: z.array(z.object({ + clientUserMessageId: z.string().nullable(), + id: z.string().nullable(), + text: z.string(), + }).strict()), + threadId: z.string(), + }).strict(), + failureDocumentSchema, +]); + +export default async function codexQueue({ input }: CliRouteProps) { + let out; + try { + out = await listCodexQueue(input.threadId); + } catch (error) { + const failure = outcomeFromError(error); + return ( + + {failure.error} + + ); + } + return ( + + {formatCodexQueue(out)} + + ); +} diff --git a/src/cli/codex/send.tsx b/src/cli/codex/send.tsx new file mode 100644 index 0000000..8c95b35 --- /dev/null +++ b/src/cli/codex/send.tsx @@ -0,0 +1,84 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { buildEnvelope, sendToCodexThread } from '../../core/codex-bridge.js'; +import { outcomeFromError } from '../../core/codex/contract.js'; + +export const config = { + description: + 'Send a message to a Codex thread. Options go before ; `--` protects flag-like text.', + exitCode: 'result', + inputJsonSchema: { + additionalProperties: false, + properties: { + correlationId: { description: 'Stable correlation id for multi-hop replies', type: 'string' }, + envelope: { + description: 'Prepend the [gbot …] header to the message body', + type: 'boolean', + }, + hop: { description: 'Hop count; refused at GROK_BOT_MAX_HOPS', type: 'number' }, + message: { items: { type: 'string' }, type: 'array' }, + replyTo: { description: 'Prior message id this send replies to', type: 'string' }, + threadId: { type: 'string' }, + whenBusy: { + description: 'reject (default) or queue (needs GROK_BOT_CODEX_EXPERIMENTAL=1)', + enum: ['reject', 'queue'], + type: 'string', + }, + }, + required: ['threadId', 'message'], + type: 'object', + }, + positionals: ['threadId', 'message'], +} satisfies CliRouteConfig; + +export const inputSchema = z + .object({ + correlationId: z.string().min(1).optional(), + envelope: z.boolean().optional(), + hop: z.number().int().min(0).optional(), + message: z.array(z.string()).min(1), + replyTo: z.string().min(1).optional(), + threadId: z.string().min(1), + whenBusy: z.enum(['reject', 'queue']).default('reject'), + }) + .strict(); + +export const resultSchema = z + .object({ + delivery: z.enum(['accepted', 'queued', 'rejected', 'unknown']), + exitCode: z.union([z.literal(0), z.literal(1)]), + }) + .passthrough(); + +export default async function codexSend({ input }: CliRouteProps) { + let out; + try { + const envelope = buildEnvelope({ + correlationId: input.correlationId, + envelope: Boolean(input.envelope), + hop: input.hop, + replyTo: input.replyTo, + }); + out = await sendToCodexThread(input.threadId, input.message.join(' ').trim(), { + envelope, + whenBusy: input.whenBusy, + }); + } catch (error) { + out = outcomeFromError(error); + } + const text = + out.delivery === 'queued' && typeof out.queuedSubmissionId === 'string' + ? `Queued ${out.queuedSubmissionId} on busy Codex thread ${out.threadId}; message ${out.messageId}` + : out.exitCode === 0 + ? `Started turn ${out.turnId} (${out.turnStatus}) on Codex thread ${out.threadId}; message ${out.messageId}` + : typeof out.error === 'string' + ? out.error + : `Codex delivery ${out.delivery} on thread ${out.threadId}`; + return ( + + {text} + + ); +} diff --git a/src/cli/codex/status.tsx b/src/cli/codex/status.tsx new file mode 100644 index 0000000..52235bd --- /dev/null +++ b/src/cli/codex/status.tsx @@ -0,0 +1,28 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { codexStatus } from '../../core/codex-bridge.js'; +import { formatCodexStatus } from '../../core/format.js'; + +export const config = { + description: 'Probe the local Codex app-server daemon. Exit 0 only when it is usable.', + exitCode: 'result', + inputJsonSchema: { additionalProperties: false, properties: {}, type: 'object' }, +} satisfies CliRouteConfig; + +export const inputSchema = z.object({}).strict(); +export const resultSchema = z + .object({ + exitCode: z.union([z.literal(0), z.literal(1)]), + }) + .passthrough(); + +export default async function codexStatusCmd(_props: CliRouteProps) { + const status = await codexStatus(); + return ( + + {formatCodexStatus(status)} + + ); +} diff --git a/src/cli/doctor.tsx b/src/cli/doctor.tsx new file mode 100644 index 0000000..7ce6968 --- /dev/null +++ b/src/cli/doctor.tsx @@ -0,0 +1,79 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { inspectGrokBotGatewaySession } from '../core/app-session.js'; +import { hasGatewayAuth } from '../core/gateway.js'; +import { + defaultCandidateRoots, + looksLikeAgentsRoot, + resolveAgentsRoot, + StoreError, +} from '../core/store.js'; +import { backendFlagsSchema } from './_shared.js'; + +export const config = { + description: 'Show which agents root and auth sources gbot can see.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + }, + type: 'object', + }, +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema; +export const resultSchema = z.object({ + candidates: z.array(z.string()), + found: z.array(z.string()), + gatewayAuthPresent: z.boolean(), + grokBotAppSession: z.record(z.string(), z.json()), + note: z.string(), + resolved: z.string().nullable(), +}).strict(); + +export default async function doctor({ input }: CliRouteProps) { + const candidates = defaultCandidateRoots().filter((c): c is string => typeof c === 'string'); + const found = candidates.filter(looksLikeAgentsRoot); + let resolved: string | null = null; + try { + resolved = resolveAgentsRoot(input.dir); + } catch (err) { + if (!(err instanceof StoreError)) throw err; + } + const note = 'Live roster is on the box. Prefer CURSOR_ACCESS_TOKEN then EnsureSandBox then POST gateway /api/*.'; + const gatewayAuthPresent = hasGatewayAuth(); + const grokBotAppSession = inspectGrokBotGatewaySession(); + const sessionJson = { + present: grokBotAppSession.present, + usable: grokBotAppSession.usable, + ...(grokBotAppSession.error === undefined ? {} : { error: grokBotAppSession.error }), + ...('code' in grokBotAppSession && grokBotAppSession.code != null + ? { code: grokBotAppSession.code } + : {}), + }; + const value = { resolved, found, candidates, gatewayAuthPresent, grokBotAppSession: sessionJson, note }; + const sessionLine = grokBotAppSession.usable + ? 'Grok Bot app session: usable' + : grokBotAppSession.present + ? `Grok Bot app session: present but unusable: ${grokBotAppSession.error}` + : 'Grok Bot app session: not found'; + const text = [ + `resolved: ${resolved ?? '(none)'}`, + `gateway auth: ${gatewayAuthPresent ? 'present' : 'no'}`, + sessionLine, + 'found:', + found.length ? found.map((p) => ` ${p}`).join('\n') : ' (none)', + 'candidates:', + ...candidates.map((c) => ` ${c}`), + note, + ].join('\n'); + return ( + + {text} + + ); +} diff --git a/src/cli/groups/add.tsx b/src/cli/groups/add.tsx new file mode 100644 index 0000000..d176152 --- /dev/null +++ b/src/cli/groups/add.tsx @@ -0,0 +1,39 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: 'Add a bot to a group.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + bot: { type: 'string' }, + group: { type: 'string' }, + }, + required: ['group', 'bot'], + type: 'object', + }, + positionals: ['group', 'bot'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.extend({ + bot: z.string().min(1), + group: z.string().min(1), +}).strict(); +export const resultSchema = agentSummarySchema; + +export default async function groupsAdd({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const rec = await backend.addGroupMember(input.group, input.bot); + return ( + + {`Added to ${rec.name}. Members: ${rec.memberIds.length}`} + + ); +} diff --git a/src/cli/groups/create.tsx b/src/cli/groups/create.tsx new file mode 100644 index 0000000..e5552a1 --- /dev/null +++ b/src/cli/groups/create.tsx @@ -0,0 +1,48 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; + +import { summarize } from '../../core/format.js'; +import { + agentSummarySchema, + backendFlagsSchema, + createFieldsSchema, + openBackendFromInput, + toCreateInput, +} from '../_shared.js'; +import { z } from 'zod'; + +export const config = { + description: 'Create a Grok Bot group.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + avatarColor: { type: 'string' }, + avatarShape: { type: 'string' }, + description: { type: 'string' }, + member: { description: 'Member bot id or name (repeatable)', items: { type: 'string' }, type: 'array' }, + name: { type: 'string' }, + title: { type: 'string' }, + }, + required: ['name', 'member'], + type: 'object', + }, +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.merge(createFieldsSchema).extend({ + member: z.array(z.string().min(1)).min(1), +}).strict(); +export const resultSchema = agentSummarySchema; + +export default async function groupsCreate({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const { dir: _d, files: _f, gateway: _g, member, ...fields } = input; + const rec = await backend.createGroup({ ...toCreateInput(fields), memberIds: member }); + return ( + + {`Created group ${rec.name} (${rec.id}) with ${rec.memberIds.length} members`} + + ); +} diff --git a/src/cli/groups/delete.tsx b/src/cli/groups/delete.tsx new file mode 100644 index 0000000..a46a608 --- /dev/null +++ b/src/cli/groups/delete.tsx @@ -0,0 +1,37 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: 'Delete a group by id or name.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + ref: { description: 'Group id or name', type: 'string' }, + }, + required: ['ref'], + type: 'object', + }, + positionals: ['ref'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.extend({ ref: z.string().min(1) }).strict(); +export const resultSchema = agentSummarySchema; + +export default async function groupsDelete({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const rec = await backend.resolve(input.ref); + if (!rec.isGroup) throw new Error(`"${rec.name}" is a bot, not a group. Use bots delete.`); + const deleted = await backend.deleteAgent(input.ref); + return ( + + {`Deleted group ${deleted.name} (${deleted.id})`} + + ); +} diff --git a/src/cli/groups/get.tsx b/src/cli/groups/get.tsx new file mode 100644 index 0000000..7d1ae7c --- /dev/null +++ b/src/cli/groups/get.tsx @@ -0,0 +1,37 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { formatRecord, summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: 'Show one group by id or name.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + ref: { description: 'Group id or name', type: 'string' }, + }, + required: ['ref'], + type: 'object', + }, + positionals: ['ref'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.extend({ ref: z.string().min(1) }).strict(); +export const resultSchema = agentSummarySchema; + +export default async function groupsGet({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const rec = await backend.resolve(input.ref); + if (!rec.isGroup) throw new Error(`"${rec.name}" is a bot, not a group.`); + const all = await backend.list(); + return ( + + {formatRecord(rec, all)} + + ); +} diff --git a/src/cli/groups/list.tsx b/src/cli/groups/list.tsx new file mode 100644 index 0000000..d940ba7 --- /dev/null +++ b/src/cli/groups/list.tsx @@ -0,0 +1,35 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { formatRecord, summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: 'List Grok Bot groups.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + }, + type: 'object', + }, +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema; +export const resultSchema = z.array(agentSummarySchema); + +export default async function groupsList({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const all = await backend.list(); + const rows = all.filter((r: { isGroup?: boolean }) => r.isGroup); + const groups = rows.map(summarize); + const text = rows.length === 0 ? 'No groups.' : rows.map((r: Parameters[0]) => formatRecord(r, all)).join('\n\n'); + return ( + + {text} + + ); +} diff --git a/src/cli/groups/members.tsx b/src/cli/groups/members.tsx new file mode 100644 index 0000000..1aeb81a --- /dev/null +++ b/src/cli/groups/members.tsx @@ -0,0 +1,37 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { formatRecord, summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: 'Show members of a group (same payload as groups get).', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + ref: { description: 'Group id or name', type: 'string' }, + }, + required: ['ref'], + type: 'object', + }, + positionals: ['ref'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.extend({ ref: z.string().min(1) }).strict(); +export const resultSchema = agentSummarySchema; + +export default async function groupsMembers({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const rec = await backend.resolve(input.ref); + if (!rec.isGroup) throw new Error(`"${rec.name}" is a bot, not a group.`); + const all = await backend.list(); + return ( + + {formatRecord(rec, all)} + + ); +} diff --git a/src/cli/groups/remove.tsx b/src/cli/groups/remove.tsx new file mode 100644 index 0000000..e0e318c --- /dev/null +++ b/src/cli/groups/remove.tsx @@ -0,0 +1,39 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: 'Remove a bot from a group.', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + bot: { type: 'string' }, + group: { type: 'string' }, + }, + required: ['group', 'bot'], + type: 'object', + }, + positionals: ['group', 'bot'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.extend({ + bot: z.string().min(1), + group: z.string().min(1), +}).strict(); +export const resultSchema = agentSummarySchema; + +export default async function groupsRemove({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const rec = await backend.removeGroupMember(input.group, input.bot); + return ( + + {`Removed from ${rec.name}. Members: ${rec.memberIds.length}`} + + ); +} diff --git a/src/cli/groups/set.tsx b/src/cli/groups/set.tsx new file mode 100644 index 0000000..06140b5 --- /dev/null +++ b/src/cli/groups/set.tsx @@ -0,0 +1,39 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { summarize } from '../../core/format.js'; +import { agentSummarySchema, backendFlagsSchema, openBackendFromInput } from '../_shared.js'; + +export const config = { + description: "Replace a group's member list.", + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + group: { type: 'string' }, + member: { description: 'Member bot id or name (repeatable)', items: { type: 'string' }, type: 'array' }, + }, + required: ['group', 'member'], + type: 'object', + }, + positionals: ['group'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.extend({ + group: z.string().min(1), + member: z.array(z.string().min(1)).min(1), +}).strict(); +export const resultSchema = agentSummarySchema; + +export default async function groupsSet({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const rec = await backend.setGroupMembers(input.group, input.member); + return ( + + {`Updated ${rec.name}. Members: ${rec.memberIds.length}`} + + ); +} diff --git a/src/cli/groups/update.tsx b/src/cli/groups/update.tsx new file mode 100644 index 0000000..45ce6e1 --- /dev/null +++ b/src/cli/groups/update.tsx @@ -0,0 +1,51 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { summarize } from '../../core/format.js'; +import { + agentSummarySchema, + backendFlagsSchema, + openBackendFromInput, + toUpdatePatch, + updateFieldsSchema, +} from '../_shared.js'; + +export const config = { + description: 'Update a group profile (members stay on set/add/remove).', + inputJsonSchema: { + additionalProperties: false, + properties: { + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + avatarColor: { type: 'string' }, + avatarShape: { type: 'string' }, + description: { type: 'string' }, + hidden: { type: 'string' }, + name: { type: 'string' }, + notify: { type: 'string' }, + ref: { description: 'Group id or name', type: 'string' }, + title: { type: 'string' }, + }, + required: ['ref'], + type: 'object', + }, + positionals: ['ref'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema.merge(updateFieldsSchema).extend({ ref: z.string().min(1) }).strict(); +export const resultSchema = agentSummarySchema; + +export default async function groupsUpdate({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + const current = await backend.resolve(input.ref); + if (!current.isGroup) throw new Error(`"${current.name}" is a bot, not a group. Use bots update.`); + const { dir: _d, files: _f, gateway: _g, ref, ...fields } = input; + const rec = await backend.updateAgent(ref, toUpdatePatch(fields)); + return ( + + {`Updated group ${rec.name} (${rec.id})`} + + ); +} diff --git a/src/cli/history.tsx b/src/cli/history.tsx new file mode 100644 index 0000000..ad9225f --- /dev/null +++ b/src/cli/history.tsx @@ -0,0 +1,75 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { historyPath, readHistory } from '../core/history.js'; + +export const config = { + description: 'Read the opt-in local JSONL history without contacting the gateway.', + inputJsonSchema: { + additionalProperties: false, + properties: { + historyDir: { description: 'Directory containing history.jsonl', type: 'string' }, + limit: { default: 40, description: 'Maximum matching rows (1 or more)', type: 'number' }, + path: { description: 'Print the history file path', type: 'boolean' }, + ref: { description: 'Bot or group id or name', type: 'string' }, + search: { description: 'Case-insensitive message text filter', type: 'string' }, + }, + type: 'object', + }, + positionals: ['ref'], +} satisfies CliRouteConfig; + +export const inputSchema = z + .object({ + historyDir: z.string().min(1).optional(), + limit: z.number().int().min(1).default(40), + path: z.boolean().default(false), + ref: z.string().min(1).optional(), + search: z.string().optional(), + }) + .strict() + .refine( + (input) => !input.path || (input.ref === undefined && input.search === undefined && input.limit === 40), + '--path cannot be combined with a target, --search, or --limit', + ); + +const historyRowSchema = z.record(z.string(), z.json()); +export const resultSchema = z.union([ + z.array(historyRowSchema), + z.object({ path: z.string() }).strict(), +]); + +export default async function history({ input }: CliRouteProps) { + const file = historyPath(input.historyDir); + if (input.path) { + return ( + + {file} + + ); + } + const rows = await readHistory(file, { + limit: input.limit, + ref: input.ref, + search: input.search, + }); + const text = rows.length + ? rows + .map( + (row: { + readonly recordedAt: string; + readonly role: string; + readonly target: { readonly id: string; readonly name: string }; + readonly text: string; + }) => + `[${row.recordedAt}] ${row.target.name} (${row.target.id}) [${row.role}] ${row.text}`, + ) + .join('\n') + : 'No local history.'; + return ( + + {text} + + ); +} diff --git a/src/cli/send.tsx b/src/cli/send.tsx new file mode 100644 index 0000000..06472d3 --- /dev/null +++ b/src/cli/send.tsx @@ -0,0 +1,118 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { buildEnvelope, withEnvelopeHeader } from '../core/codex-bridge.js'; +import { outcomeFromError } from '../core/codex/contract.js'; +import { saveHistory } from '../core/history.js'; +import { + backendFlagsSchema, + failureDocumentSchema, + openBackendFromInput, +} from './_shared.js'; + +export const config = { + description: 'Send a message to a Grok Bot bot or group by name or id.', + exitCode: 'result', + inputJsonSchema: { + additionalProperties: false, + properties: { + correlationId: { description: 'Stable correlation id for multi-hop replies', type: 'string' }, + dir: { description: 'Agents directory for --files mode', type: 'string' }, + envelope: { description: 'Prepend the [gbot …] header', type: 'boolean' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + historyDir: { description: 'Directory containing history.jsonl', type: 'string' }, + hop: { description: 'Hop count; refused at GROK_BOT_MAX_HOPS', type: 'number' }, + message: { items: { type: 'string' }, type: 'array' }, + noHistory: { description: 'Skip local history for this command', type: 'boolean' }, + replyTo: { description: 'Prior message id this send replies to', type: 'string' }, + target: { type: 'string' }, + }, + required: ['target', 'message'], + type: 'object', + }, + positionals: ['target', 'message'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema + .extend({ + correlationId: z.string().min(1).optional(), + envelope: z.boolean().default(false), + historyDir: z.string().min(1).optional(), + hop: z.number().int().min(0).optional(), + message: z.array(z.string()).min(1), + noHistory: z.boolean().default(false), + replyTo: z.string().min(1).optional(), + target: z.string().min(1), + }) + .strict(); + +const receiptSchema = z + .object({ + correlationId: z.string(), + delivery: z.enum(['accepted', 'unknown']), + envelopeId: z.string(), + exitCode: z.literal(0), + hop: z.number().int().min(0), + id: z.string(), + kind: z.enum(['bot', 'group']), + maxHops: z.number().int().min(0), + messageId: z.string().optional(), + name: z.string(), + replyTo: z.string().optional(), + result: z.record(z.string(), z.json()), + }) + .strict(); + +// Refusals and gateway failures are the same flat document `codex send` emits. +export const resultSchema = z.union([receiptSchema, failureDocumentSchema]); + +const deliver = async (input: z.infer): Promise> => { + const envelope = buildEnvelope({ + correlationId: input.correlationId, + envelope: input.envelope, + hop: input.hop, + replyTo: input.replyTo, + }); + const message = input.message.join(' ').trim(); + const backend = await openBackendFromInput(input); + const out = await backend.send(input.target, withEnvelopeHeader(message, envelope)); + saveHistory(out, { + dir: input.historyDir, + disabled: input.noHistory, + event: 'send', + prompt: message, + }); + return { + id: out.target.id, + name: out.target.name, + kind: out.target.isGroup ? ('group' as const) : ('bot' as const), + result: out.result, + delivery: out.delivery === 'accepted' ? ('accepted' as const) : ('unknown' as const), + ...(typeof out.messageId === 'string' ? { messageId: out.messageId } : {}), + envelopeId: envelope.messageId, + correlationId: envelope.correlationId, + ...(input.replyTo ? { replyTo: input.replyTo } : {}), + hop: envelope.hop, + maxHops: envelope.maxHops, + exitCode: 0 as const, + }; +}; + +export default async function send({ input }: CliRouteProps) { + let value: z.infer; + try { + value = await deliver(input); + } catch (error) { + value = outcomeFromError(error); + } + const text = value.exitCode === 0 + ? `Sent to ${value.kind} ${value.name} (${value.id})${value.messageId ? ` message ${value.messageId}` : ''}; envelope ${value.envelopeId}` + : value.error; + return ( + + {text} + + ); +} diff --git a/src/cli/thread.tsx b/src/cli/thread.tsx new file mode 100644 index 0000000..3f95f8e --- /dev/null +++ b/src/cli/thread.tsx @@ -0,0 +1,99 @@ +import { Agent } from '@agent-bundle/runtime'; +import type { CliRouteConfig, CliRouteProps } from 'agent-bundle'; +import { z } from 'zod'; + +import { formatTranscript } from '../core/format.js'; +import { saveHistory } from '../core/history.js'; +import { transcriptDelta } from '../core/transcript.js'; +import { + backendFlagsSchema, + openBackendFromInput, +} from './_shared.js'; + +export const config = { + aliases: ['chat'], + description: 'Read the most recent messages in a Grok Bot bot or group thread.', + inputJsonSchema: { + additionalProperties: false, + properties: { + after: { description: 'Return entries after this opaque entry id', type: 'string' }, + dir: { description: 'Agents directory for --files mode', type: 'string' }, + files: { description: 'Force the on-disk agents store', type: 'boolean' }, + full: { description: 'Show full entry text in human output', type: 'boolean' }, + gateway: { description: 'Force the live gateway', type: 'boolean' }, + historyDir: { description: 'Directory containing history.jsonl', type: 'string' }, + limit: { default: 40, description: 'How many trailing entries to return (1-200)', type: 'number' }, + noHistory: { description: 'Skip local history for this command', type: 'boolean' }, + root: { description: 'Read one rooted thread by message id', type: 'string' }, + target: { type: 'string' }, + }, + required: ['target'], + type: 'object', + }, + positionals: ['target'], +} satisfies CliRouteConfig; + +export const inputSchema = backendFlagsSchema + .extend({ + after: z.string().min(1).max(1024).optional(), + full: z.boolean().default(false), + historyDir: z.string().min(1).optional(), + limit: z.number().int().min(1).max(200).default(40), + noHistory: z.boolean().default(false), + root: z.string().min(1).optional(), + target: z.string().min(1), + }) + .strict() + .refine((input) => input.after === undefined || input.root === undefined, '--after cannot be combined with --root'); + +export const resultSchema = z.record(z.string(), z.json()); + +export default async function thread({ input }: CliRouteProps) { + const backend = await openBackendFromInput(input); + if (input.root !== undefined) { + const rooted = await backend.thread(input.target, input.root); + saveHistory(rooted, { + dir: input.historyDir, + disabled: input.noHistory, + event: 'thread', + rootId: input.root, + }); + return ( + + {formatTranscript(rooted, { full: input.full })} + + ); + } + const out = await backend.transcript(input.target, input.limit); + if (input.after !== undefined) { + const delta = transcriptDelta(out.transcript, { after: input.after, limit: input.limit }); + const selected = { + ...out, + transcript: { entries: delta.entries }, + cursor: delta.cursor, + entryCount: delta.entryCount, + gapReset: delta.gapReset, + }; + saveHistory(selected, { + dir: input.historyDir, + disabled: input.noHistory, + event: 'thread', + }); + const text = formatTranscript(selected, { full: input.full }); + return ( + + {`${text}\n\ncursor: ${delta.cursor}${delta.gapReset ? ' (gap reset)' : ''}`} + + ); + } + saveHistory(out, { + dir: input.historyDir, + disabled: input.noHistory, + event: 'thread', + }); + return ( + + {formatTranscript(out, { full: input.full })} + + ); +} diff --git a/src/app-session.js b/src/core/app-session.js similarity index 100% rename from src/app-session.js rename to src/core/app-session.js diff --git a/src/codex-bridge.js b/src/core/codex-bridge.js similarity index 97% rename from src/codex-bridge.js rename to src/core/codex-bridge.js index 1b241fb..cc04dd1 100644 --- a/src/codex-bridge.js +++ b/src/core/codex-bridge.js @@ -6,6 +6,8 @@ import { join } from "node:path"; import { spawnSync } from "node:child_process"; import { createRequire } from "node:module"; +import { outcomeFromError, outcomeFromReceipt, withStatusExitCode } from "./codex/contract.js"; + // Method and param names below come from `codex app-server generate-json-schema` // of this Codex release. Newer daemons usually keep them; `gbot codex status` // reports the running daemon's version next to this one. @@ -22,7 +24,7 @@ export const WS_MAX_HEADER_BYTES = 16 * 1024; export const WS_MAX_MESSAGE_BYTES = 4 * 1024 * 1024; export const WS_MAX_BUFFER_BYTES = 8 * 1024 * 1024; const textDecoder = new TextDecoder("utf-8", { fatal: true }); -const pkg = createRequire(import.meta.url)("../package.json"); +const pkg = createRequire(import.meta.url)("../../package.json"); export function codexSocketPath(env = process.env) { const home = env.CODEX_HOME || join(homedir(), ".codex"); @@ -505,14 +507,14 @@ export async function codexStatus(env = process.env) { try { session = await openSession(env); } catch (err) { - if (err instanceof CodexRouteError) return { ...base, reachable: false, mode: err.mode, message: err.message }; + if (err instanceof CodexRouteError) return withStatusExitCode({ ...base, reachable: false, mode: err.mode, message: err.message }); // The endpoint answered; what it said does not match the pinned schema. - if (err instanceof CodexProtocolError) return { ...base, reachable: true, mode: err.mode, message: err.message }; + if (err instanceof CodexProtocolError) return withStatusExitCode({ ...base, reachable: true, mode: err.mode, message: err.message }); throw err; } session.client.close(); const daemonVersion = appServerVersion(session.init); - return { + return withStatusExitCode({ ...base, reachable: true, mode: "daemon", @@ -524,7 +526,7 @@ export async function codexStatus(env = process.env) { compatibility: daemonVersion == null ? "unknown" : daemonVersion === PINNED_CODEX_VERSION ? "exact" : "unverified", }, versionMismatch: Boolean(base.cliVersion && daemonVersion && base.cliVersion !== daemonVersion), - }; + }); } const THREAD_STATUSES = new Set(["notLoaded", "idle", "active", "systemError"]); @@ -556,6 +558,9 @@ export function summarizeThread(t) { export const THREAD_LIST_MAX_LIMIT = 200; +/** + * @param {{ limit?: number, cursor?: string, env?: NodeJS.ProcessEnv }} [opts] + */ export async function listCodexThreads({ limit = 20, cursor, env = process.env } = {}) { if (!Number.isInteger(limit) || limit < 1 || limit > THREAD_LIST_MAX_LIMIT) { throw new RangeError("--limit must be an integer 1-" + THREAD_LIST_MAX_LIMIT); @@ -602,6 +607,7 @@ const ID_PATTERN = /^[A-Za-z0-9_.:-]{1,128}$/; * `maxHops` (GROK_BOT_MAX_HOPS) bounds relays: a reply must carry hop = incoming hop + 1, and a * send at or past the bound is refused, so two agents cannot ack each other forever. * The textual header is caller-authored provenance for the reader, not authentication. + * @param {{ correlationId?: string, replyTo?: string, hop?: number, envelope?: boolean, env?: NodeJS.ProcessEnv }} [opts] */ export function buildEnvelope({ correlationId, replyTo, hop, envelope = false, env = process.env } = {}) { const maxHops = Number.parseInt(env.GROK_BOT_MAX_HOPS ?? "", 10); @@ -739,13 +745,19 @@ export async function listCodexQueue(threadId, { env = process.env, limit = 50, } } +/** + * @param {string} threadId + * @param {string} text + * @param {{ env?: NodeJS.ProcessEnv, envelope?: object, whenBusy?: "reject"|"queue" }} [opts] + */ export async function sendToCodexThread(threadId, text, { env = process.env, envelope = buildEnvelope({ env }), whenBusy = "reject" } = {}) { try { - return await sendToCodexThreadInner(threadId, text, { env, envelope, whenBusy }); + const receipt = await sendToCodexThreadInner(threadId, text, { env, envelope, whenBusy }); + return outcomeFromReceipt(receipt); } catch (err) { // Every receipt names the message, including refusals that never reached the daemon. if ((err instanceof CodexSendError || err instanceof CodexRouteError || err instanceof CodexProtocolError) && err.envelope === undefined) err.envelope = envelope; - throw err; + return outcomeFromError(err); } } diff --git a/src/core/codex/contract.js b/src/core/codex/contract.js new file mode 100644 index 0000000..437375a --- /dev/null +++ b/src/core/codex/contract.js @@ -0,0 +1,123 @@ +/** + * #46 Codex contract documents and exit-code derivation. + * The bridge and the CLI routes flatten through these helpers so reason/delivery + * spelling stays one owner. No process I/O here. + */ + +import { redactSecrets } from "../url-policy.js"; + +/** @typedef {'accepted' | 'queued' | 'rejected' | 'unknown'} CodexDelivery */ +/** + * @typedef {{ + * delivery: CodexDelivery, + * exitCode: 0 | 1, + * error?: string, + * reason?: string, + * mode?: string, + * threadId?: string, + * turnId?: string, + * turnStatus?: string, + * queuedSubmissionId?: string, + * refused?: string[], + * messageId?: string, + * correlationId?: string, + * hop?: number, + * replyTo?: string, + * threadStatus?: string, + * model?: string, + * cwd?: string, + * approvalPolicy?: string, + * maxHops?: number, + * }} CodexSendOutcome + */ + +/** + * Exit 0 iff the daemon is usable. + * @param {{ reachable: boolean, mode: string }} status + * @returns {0 | 1} + */ +export function statusExitCode(status) { + return status.reachable && status.mode === "daemon" ? 0 : 1; +} + +/** + * Attach derived exitCode to a status document (never mutates input). + * @param {Record} status + */ +export function withStatusExitCode(status) { + return { + ...status, + exitCode: statusExitCode(/** @type {{ reachable: boolean, mode: string }} */ (status)), + }; +} + +/** + * @param {{ + * delivery: CodexDelivery, + * reason?: string, + * error?: string, + * }} outcome + * @returns {0 | 1} + */ +export function sendExitCode(outcome) { + if (outcome.error !== undefined) return 1; + if (outcome.delivery === "accepted" && outcome.reason === "approval-refused") return 1; + if (outcome.delivery === "rejected" || outcome.delivery === "unknown") return 1; + return 0; +} + +/** + * Flatten a thrown error into the #46 send/failure document (plus exitCode). + * Preserves the legacy failure-document fields, then adds exitCode for the + * generated CLI's `exitCode: 'result'` policy. + * + * @param {unknown} error + * @param {{ isUsage?: (err: unknown) => boolean }} [opts] + * @returns {CodexSendOutcome & { error: string, exitCode: 1 }} + */ +export function outcomeFromError(error, opts = {}) { + const isUsage = opts.isUsage ?? ((err) => + err instanceof RangeError || Boolean(err && typeof err === "object" && err.name === "StoreError")); + const message = redactSecrets(error instanceof Error ? error.message : String(error)); + /** @type {Record} */ + const out = { error: message }; + + if (error && typeof error === "object") { + for (const key of ["delivery", "reason", "mode", "threadId", "turnId", "targetId", "messageId", "correlationId", "refused", "hop"]) { + if (error[key] !== undefined) out[key] = error[key]; + } + if (out.reason === undefined && isUsage(error)) out.reason = "usage"; + const envelope = /** @type {{ messageId?: string, correlationId?: string, hop?: number }} */ (error).envelope; + if (envelope && typeof envelope === "object") { + if (envelope.messageId !== undefined) out.messageId = envelope.messageId; + if (envelope.correlationId !== undefined) out.correlationId = envelope.correlationId; + if (envelope.hop !== undefined) out.hop = envelope.hop; + } + } + + if (out.delivery === undefined) out.delivery = "rejected"; + return /** @type {CodexSendOutcome & { error: string, exitCode: 1 }} */ ({ ...out, exitCode: 1 }); +} + +/** + * Normalize a successful send receipt into a document with exitCode. + * @param {Record} receipt + * @returns {CodexSendOutcome} + */ +export function outcomeFromReceipt(receipt) { + const base = { ...receipt }; + if (base.delivery === undefined) base.delivery = "accepted"; + // Flatten envelope onto the document when present (matches fail() + json print). + const envelope = base.envelope; + if (envelope && typeof envelope === "object") { + const e = /** @type {Record} */ (envelope); + if (base.messageId === undefined && e.messageId !== undefined) base.messageId = e.messageId; + if (base.correlationId === undefined && e.correlationId !== undefined) base.correlationId = e.correlationId; + if (base.hop === undefined && e.hop !== undefined) base.hop = e.hop; + } + const exitCode = sendExitCode(/** @type {{ delivery: CodexDelivery, reason?: string, error?: string }} */ (base)); + if (exitCode === 1 && base.error === undefined && base.reason === "approval-refused") { + base.error = typeof base.message === "string" ? base.message : "Codex refused one or more approvals."; + } + return /** @type {CodexSendOutcome} */ ({ ...base, exitCode }); +} diff --git a/src/commands.js b/src/core/commands.js similarity index 100% rename from src/commands.js rename to src/core/commands.js diff --git a/src/core/format.js b/src/core/format.js new file mode 100644 index 0000000..604e400 --- /dev/null +++ b/src/core/format.js @@ -0,0 +1,105 @@ +import { entryText, transcriptEntries } from "./transcript.js"; + +/** Strip CSI/OSC and other C0/C1 controls so thread fields cannot drive the terminal. */ +export function stripTerminalControls(text) { + return String(text) + .replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g, "") + .replace(/\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)/g, "") + .replace(/\u001b./g, "") + .replace(/[\u0000-\u001F\u007F-\u009F]/g, ""); +} + +export function summarize(rec) { + return { + id: rec.id, + name: rec.name, + title: rec.title || undefined, + description: rec.description || undefined, + avatarShape: rec.avatarShape || undefined, + avatarColor: rec.avatarColor || undefined, + ...(rec.notifyOnAgentUpdates !== undefined ? { notifyOnAgentUpdates: rec.notifyOnAgentUpdates } : {}), + ...(rec.hiddenFromSidebar !== undefined ? { hiddenFromSidebar: rec.hiddenFromSidebar } : {}), + kind: rec.isGroup ? "group" : "bot", + members: rec.isGroup ? rec.memberIds : undefined, + }; +} + +export function formatRecord(rec, all) { + const kind = rec.isGroup ? "group" : "bot"; + const members = rec.isGroup + ? rec.memberIds.map((id) => { + const m = all.find((r) => r.id === id); + return m ? m.name + " (" + id + ")" : id; + }).join(", ") + : ""; + const title = rec.title ? " - " + rec.title : ""; + const desc = rec.description ? "\n " + rec.description : ""; + const avatar = rec.avatarShape || rec.avatarColor + ? "\n avatar: " + [rec.avatarShape, rec.avatarColor].filter(Boolean).join(" ") + : ""; + const settings = []; + if (rec.notifyOnAgentUpdates !== undefined) settings.push("notify " + (rec.notifyOnAgentUpdates ? "on" : "off")); + if (rec.hiddenFromSidebar !== undefined) settings.push("hidden " + (rec.hiddenFromSidebar ? "on" : "off")); + const settingsLine = settings.length ? "\n " + settings.join(", ") : ""; + const extra = rec.isGroup ? "\n members (" + rec.memberIds.length + "): " + (members || "(none)") : ""; + return kind + " " + rec.name + title + "\n " + rec.id + desc + avatar + settingsLine + extra; +} + +export function formatTranscript(out, { full = false } = {}) { + const rec = out.target; + const payload = out.transcript || out.thread || {}; + const entries = transcriptEntries(payload); + const header = (rec.isGroup ? "group" : "bot") + " " + rec.name + "\n " + rec.id; + if (!Array.isArray(entries) || entries.length === 0) { + return header + "\n (no messages)"; + } + const lines = [header, ""]; + for (const e of entries) { + const role = e.role || e.kind || e.sender || e.type || "msg"; + const text = entryText(e); + const id = e.id || e.messageId || ""; + lines.push("[" + role + (id ? " " + id : "") + "] " + (full ? text : truncateCliText(text))); + } + return lines.join("\n"); +} + +function truncateCliText(text, max = 400) { + if (text.length <= max) return text; + return text.slice(0, max) + "… [+" + (text.length - max) + " chars; --full or --json for complete text]"; +} + +export function formatCodexStatus(s) { + const lines = ["socket: " + s.socketPath + " (" + s.socketState + ")"]; + if (!s.reachable) return lines.concat("reachable: no (" + s.mode + ")", s.message).join("\n"); + if (s.mode !== "daemon") { + return lines.concat("reachable: yes, but unusable (" + s.mode + ")", s.message).join("\n"); + } + lines.push("reachable: yes (daemon)"); + const cli = s.cliVersion ?? (s.cliVersionProbe === "ok" ? "unknown" : "unknown, probe " + s.cliVersionProbe); + lines.push( + "daemon version: " + (s.daemonVersion ?? "unknown") + + " cli version: " + cli + + " pinned schema: " + s.pinnedVersion + " (" + s.schema.compatibility + ")", + ); + lines.push("desktop attached: unknown (not observable from the socket)"); + if (s.versionMismatch) { + lines.push("warning: daemon and CLI versions differ; `codex app-server daemon restart` picks up the installed CLI"); + } + return lines.join("\n"); +} + +export function formatCodexQueue({ threadId, queued }) { + if (queued.length === 0) return "No queued submissions on Codex thread " + threadId + "."; + return queued + .map((q) => q.id + " " + (q.clientUserMessageId ?? "") + "\n " + stripTerminalControls(q.text).replace(/\s+/g, " ").slice(0, 200)) + .join("\n\n"); +} + +export function formatCodexThread(t) { + const title = t.name ? " - " + stripTerminalControls(t.name) : ""; + const preview = t.preview + ? "\n " + stripTerminalControls(String(t.preview).replace(/\s+/g, " ")).slice(0, 200) + : ""; + return stripTerminalControls(t.id) + " " + stripTerminalControls(t.status) + title + + "\n " + stripTerminalControls(t.cwd ?? "") + preview; +} diff --git a/src/gateway.js b/src/core/gateway.js similarity index 100% rename from src/gateway.js rename to src/core/gateway.js diff --git a/src/headers.js b/src/core/headers.js similarity index 100% rename from src/headers.js rename to src/core/headers.js diff --git a/src/history.js b/src/core/history.js similarity index 97% rename from src/history.js rename to src/core/history.js index 50be0f3..b101268 100644 --- a/src/history.js +++ b/src/core/history.js @@ -48,6 +48,10 @@ export function saveHistory(out, { dir, disabled, event, prompt, rootId } = {}) } } +/** + * @param {string} path + * @param {{ ref?: string, search?: string, limit?: number }} [options] + */ export async function readHistory(path, { ref, search, limit = 40 } = {}) { const rows = []; let malformed = 0; diff --git a/src/store.js b/src/core/store.js similarity index 100% rename from src/store.js rename to src/core/store.js diff --git a/src/transcript.js b/src/core/transcript.js similarity index 100% rename from src/transcript.js rename to src/core/transcript.js diff --git a/src/url-policy.js b/src/core/url-policy.js similarity index 100% rename from src/url-policy.js rename to src/core/url-policy.js diff --git a/src/gbot-install.ts b/src/gbot-install.ts new file mode 100644 index 0000000..6f1ba93 --- /dev/null +++ b/src/gbot-install.ts @@ -0,0 +1,13 @@ +import { fileURLToPath } from 'node:url'; + +import { runInstallCli } from 'agent-bundle/install'; + +/** + * `gbot-install install|uninstall ` and `gbot-install doctor`, bound to the + * emitted npm `dist/` root that holds the Claude, Codex, and Cursor projections. + */ +export const main = (argv: readonly string[]): Promise => + runInstallCli(argv, { + from: fileURLToPath(new URL('..', import.meta.url)), + name: 'gbot-install', + }); diff --git a/plugin/src/gbot.ts b/src/gbot.ts similarity index 78% rename from plugin/src/gbot.ts rename to src/gbot.ts index 2041913..da7c81c 100644 --- a/plugin/src/gbot.ts +++ b/src/gbot.ts @@ -1,25 +1,20 @@ import { z } from 'zod'; -import { connectGateway, getTranscriptTail, sendPrompt } from 'grok-bot-cli/src/gateway.js'; -import { entryText, transcriptDelta, transcriptEntries as unwrapEntries } from 'grok-bot-cli/src/transcript.js'; -import { redactSecrets } from 'grok-bot-cli/src/url-policy.js'; +import { connectGateway, getTranscriptTail, sendPrompt } from './core/gateway.js'; +import { entryText, transcriptDelta, transcriptEntries as unwrapEntries } from './core/transcript.js'; +import { redactSecrets } from './core/url-policy.js'; export { connectGateway, getTranscriptTail, sendPrompt, transcriptDelta }; -// The same pass `fail()` in src/cli.js applies before printing: MCP hosts show -// the error text, and a fetch or proxy failure can echo a credential. +// Hosts and the CLI print thrown error text (and stack), and a fetch or proxy failure can echo +// a credential. Rewrap with a redacted message; keep `name` and own fields such as `reason`, +// `delivery`, `mode`, and `envelope` so outcome documents still classify the failure. export const withRedactedErrors = async (run: () => Promise): Promise => { try { return await run(); } catch (error) { - const wrapped: Error & { delivery?: string; targetId?: string } = new Error( - redactSecrets(error instanceof Error ? error.message : String(error)), - ); - if (error instanceof Error) { - const src = error as Error & { delivery?: unknown; targetId?: unknown }; - if (typeof src.delivery === 'string') wrapped.delivery = src.delivery; - if (typeof src.targetId === 'string') wrapped.targetId = src.targetId; - } + const wrapped = new Error(redactSecrets(error instanceof Error ? error.message : String(error))); + if (error instanceof Error) Object.assign(wrapped, error, { name: error.name }); throw wrapped; } }; diff --git a/plugin/src/mcp/grok-bot/tools/gbot_send.tsx b/src/mcp/grok-bot/tools/gbot_send.tsx similarity index 94% rename from plugin/src/mcp/grok-bot/tools/gbot_send.tsx rename to src/mcp/grok-bot/tools/gbot_send.tsx index b035350..025054e 100644 --- a/plugin/src/mcp/grok-bot/tools/gbot_send.tsx +++ b/src/mcp/grok-bot/tools/gbot_send.tsx @@ -4,6 +4,8 @@ import { z } from 'zod'; import { connectGateway, sendPrompt, summarizeTarget, targetSchema, withRedactedErrors } from '../../../gbot.js'; +export const inputSchema = z.object({ message: z.string().min(1), target: z.string().min(1) }); + export default defineTool( { description: @@ -17,7 +19,7 @@ export default defineTool( required: ['target', 'message'], type: 'object', }, - inputSchema: z.object({ message: z.string().min(1), target: z.string().min(1) }), + inputSchema, resultSchema: z.object({ result: z.record(z.string(), z.json()), target: targetSchema, diff --git a/plugin/src/mcp/grok-bot/tools/gbot_thread.tsx b/src/mcp/grok-bot/tools/gbot_thread.tsx similarity index 86% rename from plugin/src/mcp/grok-bot/tools/gbot_thread.tsx rename to src/mcp/grok-bot/tools/gbot_thread.tsx index cb074ff..d48b3db 100644 --- a/plugin/src/mcp/grok-bot/tools/gbot_thread.tsx +++ b/src/mcp/grok-bot/tools/gbot_thread.tsx @@ -12,6 +12,15 @@ import { withRedactedErrors, } from '../../../gbot.js'; +export const inputSchema = z.object({ + // ponytail: the route inputJsonSchema type cannot express minimum/maximum, so the + // 1-200 bound lives here in zod (and in the CLI/gateway); widen the route type to align them. + after: z.string().min(1).max(RECEIPT_CURSOR_MAX).optional(), + limit: z.number().int().min(1).max(200).default(40), + full: z.boolean().default(false), + target: z.string().min(1), +}); + export default defineTool( { annotations: { readOnlyHint: true }, @@ -40,14 +49,7 @@ export default defineTool( required: ['target'], type: 'object', }, - inputSchema: z.object({ - // ponytail: the route inputJsonSchema type cannot express minimum/maximum, so the - // 1-200 bound lives here in zod (and in the CLI/gateway); widen the route type to align them. - after: z.string().min(1).max(RECEIPT_CURSOR_MAX).optional(), - limit: z.number().int().min(1).max(200).default(40), - full: z.boolean().default(false), - target: z.string().min(1), - }), + inputSchema, resultSchema: z.object({ cursor: z.string().max(RECEIPT_CURSOR_MAX), entries: z.array(entrySchema).optional(), diff --git a/plugin/src/skills/talk-to-grok-bot/SKILL.md b/src/skills/talk-to-grok-bot/SKILL.md similarity index 79% rename from plugin/src/skills/talk-to-grok-bot/SKILL.md rename to src/skills/talk-to-grok-bot/SKILL.md index 1ff6440..d4e156e 100644 --- a/plugin/src/skills/talk-to-grok-bot/SKILL.md +++ b/src/skills/talk-to-grok-bot/SKILL.md @@ -24,6 +24,14 @@ Bot replies are `send-message` entries; yours are `message` with `role: user`. List targets with `gbot bots list` / `gbot groups list` when the name is ambiguous. +## CLI automation + +The bundled `gbot` and `gbot-install` executables require Node.js 22.19.0 or newer. +For `gbot send`, `gbot codex status`, and `gbot codex send` with `--json`, read the result +document from stdout and branch on its `exitCode`, `mode`, `reason`, and `delivery`. +Framework argument/schema errors use stderr and exit 2. `--json` is reserved before +`--`; put `--` before flag-like message text. + ## Auth Same order as `gbot`: explicit `GROK_BOT_GATEWAY_*`, else Grok Bot app session, else `CURSOR_ACCESS_TOKEN`. `gbot doctor` shows which source is present. diff --git a/test/app-session.test.js b/test/app-session.test.js index 97cff0d..ab50d2d 100644 --- a/test/app-session.test.js +++ b/test/app-session.test.js @@ -12,7 +12,7 @@ import { hasGrokBotGatewaySession, inspectGrokBotGatewaySession, loadGrokBotGatewaySession, -} from "../src/app-session.js"; +} from "../src/core/app-session.js"; const ENCRYPTED_DESCRIPTOR = "djEwddBm+U69UF2IJtIUtedNqMB3bQt7HsRw7MLWRkw/IfnMK+c4czCXq82JKPNsdsP3Bp2fX8HoGPZFsa7k+JOmbIkBanQwl4yiy9v7iOA+mE4rtGqYbYD9jJc+/9YnhcGjvSxCxD8fKbJLbHifTwroGQ=="; diff --git a/test/codex-bridge.test.js b/test/codex-bridge.test.js index c13dbc5..5836788 100644 --- a/test/codex-bridge.test.js +++ b/test/codex-bridge.test.js @@ -7,10 +7,10 @@ import { join } from "node:path"; import { fileURLToPath } from "node:url"; import test from "node:test"; -import { decodeFrame, encodeFrame, websocketAccept, connectCodexAppServer, sendToCodexThread, CodexSendError } from "../src/codex-bridge.js"; +import { decodeFrame, encodeFrame, websocketAccept, connectCodexAppServer, sendToCodexThread } from "../src/core/codex-bridge.js"; import { createServer as createTcpServer } from "node:net"; -const CLI = fileURLToPath(new URL("../src/cli.js", import.meta.url)); +const CLI = fileURLToPath(new URL("../dist/bin/gbot.mjs", import.meta.url)); const THREADS = [ { id: "t-1", status: { type: "idle" }, name: "Fix the build", preview: "please fix the build", cwd: "/repo/a", source: "vscode", updatedAt: 1700000001 }, @@ -115,7 +115,7 @@ test("decodeFrame waits for a complete frame and returns the remainder", () => { test("codex status explains an absent socket and exits 1", async () => { const home = mkdtempSync(join(tmpdir(), "gbot-codex-empty-")); - const { code, out } = await gbot(home, "--json", "codex", "status"); + const { code, out } = await gbot(home, "codex", "status", "--json"); assert.equal(code, 1); const status = JSON.parse(out); assert.equal(status.reachable, false); @@ -129,7 +129,7 @@ test("codex status explains an absent socket and exits 1", async () => { test("codex status reports the daemon version over the socket", async () => { const fake = await fakeAppServer(baseHandlers); try { - const { code, out } = await gbot(fake.home, "--json", "codex", "status"); + const { code, out } = await gbot(fake.home, "codex", "status", "--json"); assert.equal(code, 0, out); const status = JSON.parse(out); assert.equal(status.reachable, true); @@ -152,7 +152,7 @@ test("codex list-threads passes --limit and prints threads", async () => { assert.equal(text.out, "t-1 idle - Fix the build\n /repo/a\n please fix the build\n\nmore: --cursor \"cursor-2\"\n"); assert.deepEqual(fake.received.find((m) => m.method === "thread/list").params, { limit: 1, useStateDbOnly: true }); - const json = await gbot(fake.home, "--json", "codex", "list-threads"); + const json = await gbot(fake.home, "codex", "list-threads", "--json"); assert.equal(json.code, 0, json.err); assert.deepEqual(JSON.parse(json.out), { threads: [ @@ -161,6 +161,7 @@ test("codex list-threads passes --limit and prints threads", async () => { ], nextCursor: null, limit: 20, + exitCode: 0, }); assert.deepEqual(fake.received.at(-1).params, { limit: 20, useStateDbOnly: true }); } finally { @@ -170,16 +171,16 @@ test("codex list-threads passes --limit and prints threads", async () => { test("codex list-threads rejects a bad --limit", async () => { const { code, err } = await gbot("/nonexistent", "codex", "list-threads", "--limit", "0"); - assert.equal(code, 1); - assert.equal(err, "--limit must be an integer 1-200\n"); + assert.equal(code, 2); + assert.match(err, /Invalid value for --limit: expected number >= 1; received 0/); const big = await gbot("/nonexistent", "codex", "list-threads", "--limit", "201"); - assert.equal(big.err, "--limit must be an integer 1-200\n"); + assert.match(big.err, /Invalid value for --limit: expected number <= 200; received 201/); }); test("codex send resumes the thread, starts a turn, and prints the ids", async () => { const fake = await fakeAppServer(baseHandlers); try { - const { code, out } = await gbot(fake.home, "--json", "codex", "send", "t-1", "hello", "from", "gbot"); + const { code, out } = await gbot(fake.home, "codex", "send", "t-1", "hello", "from", "gbot", "--json"); assert.equal(code, 0, out); const receipt = JSON.parse(out); assert.match(receipt.messageId, /^[0-9a-f-]{36}$/); @@ -197,6 +198,7 @@ test("codex send resumes the thread, starts a turn, and prints the ids", async ( correlationId: receipt.messageId, hop: 0, maxHops: 4, + exitCode: 0, }); assert.deepEqual(fake.received.map((m) => m.method), ["initialize", "initialized", "thread/resume", "turn/start"]); assert.deepEqual(fake.received[2].params, { threadId: "t-1", excludeTurns: true }); @@ -220,11 +222,11 @@ test("codex send explains unknown threads and threads owned by another client", try { const unknown = await gbot(fake.home, "codex", "send", "nope", "hi"); assert.equal(unknown.code, 1); - assert.equal(unknown.err, "Unknown Codex thread nope. Run `gbot codex list-threads` to see reachable threads.\n"); + assert.equal(unknown.out, "Unknown Codex thread nope. Run `gbot codex list-threads` to see reachable threads.\n"); const busy = await gbot(fake.home, "codex", "send", "t-2", "hi"); assert.equal(busy.code, 1); - assert.match(busy.err, /^Codex thread t-2 is open in another client/); + assert.match(busy.out, /^Codex thread t-2 is open in another client/); assert.equal(fake.received.filter((m) => m.method === "turn/start").length, 0); } finally { await fake.close(); @@ -240,10 +242,10 @@ test("codex send refuses server approval requests and fails with guidance", asyn }, }); try { - const { code, err } = await gbot(fake.home, "codex", "send", "t-1", "do it"); + const { code, out } = await gbot(fake.home, "codex", "send", "t-1", "do it"); assert.equal(code, 1); - assert.match(err, /^Turn turn-10 started on thread t-1 but Codex asked for item\/commandExecution\/requestApproval, which gbot refused/); - assert.match(err, /approval_policy = "never"/); + assert.match(out, /^Turn turn-10 started on thread t-1 but Codex asked for item\/commandExecution\/requestApproval, which gbot refused/); + assert.match(out, /approval_policy = "never"/); const refusal = fake.received.find((m) => m.id === "srv-1"); assert.equal(refusal.error.code, -32601); assert.equal(refusal.result, undefined); @@ -276,34 +278,27 @@ test("codex send fails fast when the server sends a Close frame mid-request", as }); try { const started = Date.now(); - const { code, err } = await gbot(fake.home, "codex", "send", "t-1", "go"); + const { code, out } = await gbot(fake.home, "codex", "send", "t-1", "go"); assert.equal(code, 1); - assert.match(err, /^Lost the Codex turn\/start response for thread t-1: Codex app-server closed the connection\./); - assert.match(err, /Delivery is unknown; check the thread before resending\./); + assert.match(out, /^Lost the Codex turn\/start response for thread t-1: Codex app-server closed the connection\./); + assert.match(out, /Delivery is unknown; check the thread before resending\./); assert.ok(Date.now() - started < 5000, "did not wait for the request timeout"); } finally { await fake.close(); } }); -test("codex send keeps --json / --dir tokens that appear after the thread id", async () => { const fake = await fakeAppServer(baseHandlers); +test("codex send reserves --json and protects flag-like message text after --", async () => { const fake = await fakeAppServer(baseHandlers); try { - const { code, out } = await gbot( - fake.home, - "codex", - "send", - "t-1", - "explain", - "--json", - "output", - "and", - "--dir", - "src", - ); - assert.equal(code, 0); - assert.match(out, /Started turn/); - const start = fake.received.find((m) => m.method === "turn/start"); - assert.equal(start.params.input[0].text, "explain --json output and --dir src"); + const json = await gbot(fake.home, "codex", "send", "t-1", "explain", "--json", "output"); + assert.equal(json.code, 0); + assert.equal(JSON.parse(json.out).exitCode, 0); + assert.equal(fake.received.findLast((m) => m.method === "turn/start").params.input[0].text, "explain output"); + + const text = await gbot(fake.home, "codex", "send", "t-1", "--", "explain", "--json", "--dir", "src"); + assert.equal(text.code, 0); + assert.match(text.out, /Started turn/); + assert.equal(fake.received.findLast((m) => m.method === "turn/start").params.input[0].text, "explain --json --dir src"); } finally { await fake.close(); } @@ -360,7 +355,7 @@ test("codex send reassembles a fragmented turn/start reply split across TCP chun }, }); try { - const { code, out } = await gbot(fake.home, "--json", "codex", "send", "t-1", "go"); + const { code, out } = await gbot(fake.home, "codex", "send", "t-1", "go", "--json"); assert.equal(code, 0, out); assert.deepEqual(JSON.parse(out).turnId, "turn-9"); } finally { @@ -381,7 +376,7 @@ test("codex status fails on a wrong handshake and closes the socket instead of l const closed = new Promise((resolve) => server.on("connection", (sock) => sock.on("close", resolve))); try { const started = Date.now(); - const { code, out } = await gbot(home, "--json", "codex", "status"); + const { code, out } = await gbot(home, "codex", "status", "--json"); assert.equal(code, 1); const status = JSON.parse(out); assert.equal(status.reachable, false); @@ -405,7 +400,7 @@ test("codex status fails fast on an oversized frame and settles the pending requ }); try { const started = Date.now(); - const { code, out } = await gbot(fake.home, "--json", "codex", "status"); + const { code, out } = await gbot(fake.home, "codex", "status", "--json"); assert.equal(code, 1); const status = JSON.parse(out); assert.equal(status.mode, "handshake-failed"); @@ -434,10 +429,10 @@ test("client close is idempotent and settles pending requests", async () => { test("codex send keeps the thread id and reports unknown delivery on a malformed ack", async () => { const fake = await fakeAppServer({ ...baseHandlers, "turn/start": (params, ok) => ok({ turn: { status: "inProgress" } }) }); try { - const { code, err } = await gbot(fake.home, "codex", "send", "t-1", "go"); + const { code, out } = await gbot(fake.home, "codex", "send", "t-1", "go"); assert.equal(code, 1); - assert.match(err, /malformed turn\/start acknowledgment for thread t-1/); - assert.match(err, /unknown/); + assert.match(out, /malformed turn\/start acknowledgment for thread t-1/); + assert.match(out, /unknown/); } finally { await fake.close(); } @@ -452,7 +447,7 @@ test("codex send ignores server requests scoped to other threads", async () => { }, }); try { - const { code, out } = await gbot(fake.home, "--json", "codex", "send", "t-1", "go"); + const { code, out } = await gbot(fake.home, "codex", "send", "t-1", "go", "--json"); assert.equal(code, 0, out); assert.equal(JSON.parse(out).delivery, "accepted"); } finally { @@ -471,13 +466,12 @@ test("codex send preserves turn and thread ids with accepted delivery on refusal const home = fake.home; const env = { ...process.env, CODEX_HOME: home }; try { - await assert.rejects(sendToCodexThread("t-1", "do it", { env }), (e) => { - assert.ok(e instanceof CodexSendError); - assert.equal(e.delivery, "accepted"); - assert.equal(e.threadId, "t-1"); - assert.equal(e.turnId, "turn-10"); - return true; - }); + const outcome = await sendToCodexThread("t-1", "do it", { env }); + assert.equal(outcome.delivery, "accepted"); + assert.equal(outcome.reason, "approval-refused"); + assert.equal(outcome.threadId, "t-1"); + assert.equal(outcome.turnId, "turn-10"); + assert.equal(outcome.exitCode, 1); } finally { await fake.close(); } @@ -493,7 +487,7 @@ test("a JSON null message fails as malformed instead of crashing on msg.id", asy }); try { const started = Date.now(); - const { code, out } = await gbot(fake.home, "--json", "codex", "status"); + const { code, out } = await gbot(fake.home, "codex", "status", "--json"); assert.equal(code, 1); const status = JSON.parse(out); assert.equal(status.mode, "handshake-failed"); @@ -568,9 +562,9 @@ test("codex status rejects a complete oversized frame without buffering it", asy test("codex send emits structured JSON errors with delivery and ids", async () => { const fake = await fakeAppServer(baseHandlers); try { - const unknown = await gbot(fake.home, "--json", "codex", "send", "nope", "hi"); + const unknown = await gbot(fake.home, "codex", "send", "nope", "hi", "--json"); assert.equal(unknown.code, 1); - const failure = JSON.parse(unknown.err); + const failure = JSON.parse(unknown.out); assert.match(failure.messageId, /^[0-9a-f-]{36}$/); assert.deepEqual(failure, { error: "Unknown Codex thread nope. Run `gbot codex list-threads` to see reachable threads.", @@ -580,8 +574,9 @@ test("codex send emits structured JSON errors with delivery and ids", async () = messageId: failure.messageId, correlationId: failure.messageId, hop: 0, + exitCode: 1, }); - assert.equal(unknown.out, ""); + assert.equal(unknown.err, ""); } finally { await fake.close(); } @@ -593,9 +588,9 @@ test("codex send emits structured JSON errors with delivery and ids", async () = }, }); try { - const { code, err } = await gbot(refusing.home, "--json", "codex", "send", "t-1", "do it"); + const { code, out } = await gbot(refusing.home, "codex", "send", "t-1", "do it", "--json"); assert.equal(code, 1); - const parsed = JSON.parse(err); + const parsed = JSON.parse(out); assert.equal(parsed.delivery, "accepted"); assert.equal(parsed.threadId, "t-1"); assert.equal(parsed.turnId, "turn-10"); @@ -605,7 +600,7 @@ test("codex send emits structured JSON errors with delivery and ids", async () = } }); -test("codex send parses a trailing --json as a flag in both placements", async () => { +test("codex send parses a trailing --json as a flag", async () => { const fake = await fakeAppServer(baseHandlers); try { const trailing = await gbot(fake.home, "codex", "send", "t-1", "hi", "--json"); @@ -613,10 +608,10 @@ test("codex send parses a trailing --json as a flag in both placements", async ( assert.equal(JSON.parse(trailing.out).turnId, "turn-9"); assert.equal(fake.received.at(-1).params.input[0].text, "hi"); + // Leading globals were a hand-CLI habit; the Agent Bundle CLI rejects them. const leading = await gbot(fake.home, "--json", "codex", "send", "t-1", "hi"); - assert.equal(leading.code, 0, leading.err); - assert.equal(JSON.parse(leading.out).turnId, "turn-9"); - assert.equal(fake.received.at(-1).params.input[0].text, "hi"); + assert.notEqual(leading.code, 0); + assert.match(leading.err, /Unknown option: --json/); } finally { await fake.close(); } @@ -639,8 +634,8 @@ test("codex send failures honor a trailing --json with structured errors", async try { const { code, err, out } = await gbot(fake.home, "codex", "send", "nope", "hi", "--json"); assert.equal(code, 1); - assert.equal(out, ""); - const failure = JSON.parse(err); + assert.equal(err, ""); + const failure = JSON.parse(out); assert.equal(failure.reason, "unknown-thread"); assert.equal(failure.delivery, "rejected"); assert.equal(failure.threadId, "nope"); @@ -650,26 +645,13 @@ test("codex send failures honor a trailing --json with structured errors", async } }); -test("send failures honor a trailing --json before backend auth runs", async () => { - const env = { ...process.env, CODEX_HOME: "/nonexistent", PATH: "/nonexistent" }; - const run = (...args) => new Promise((resolve) => { - execFile(process.execPath, [CLI, ...args], { encoding: "utf8", env }, (error, out, err) => { - resolve({ code: error ? error.code : 0, out, err }); - }); - }); - const { code, err } = await run("--dir", "/nonexistent-gbot-dir", "send", "Nobody", "hi", "--json"); - assert.equal(code, 1); - const parsed = JSON.parse(err); - assert.equal(typeof parsed.error, "string"); -}); - // ---- #39: machine-readable status and thread discovery ---- test("codex status distinguishes permission-denied and stale files from an absent socket", { skip: process.platform === "win32" || process.getuid?.() === 0 }, async () => { const home = mkdtempSync(join(tmpdir(), "gbot-codex-perm-")); mkdirSync(join(home, "app-server-control"), { mode: 0o000 }); try { - const denied = await gbot(home, "--json", "codex", "status"); + const denied = await gbot(home, "codex", "status", "--json"); assert.equal(denied.code, 1); const status = JSON.parse(denied.out); assert.equal(status.reachable, false); @@ -680,7 +662,7 @@ test("codex status distinguishes permission-denied and stale files from an absen chmodSync(join(home, "app-server-control"), 0o700); } writeFileSync(join(home, "app-server-control", "app-server-control.sock"), "stale"); - const stale = await gbot(home, "--json", "codex", "status"); + const stale = await gbot(home, "codex", "status", "--json"); assert.equal(JSON.parse(stale.out).mode, "not-a-socket"); assert.equal(JSON.parse(stale.out).socketState, "not-a-socket"); }); @@ -692,7 +674,7 @@ test("codex status reports connect-failed when the socket exists but nothing ans const server = createTcpServer((sock) => sock.destroy()); await new Promise((resolve) => server.listen(socketPath, resolve)); try { - const { code, out } = await gbot(home, "--json", "codex", "status"); + const { code, out } = await gbot(home, "codex", "status", "--json"); assert.equal(code, 1); const status = JSON.parse(out); assert.equal(status.reachable, false); @@ -710,7 +692,7 @@ test("codex status separates schema compatibility from reachability and bounds t initialize: (params, ok) => ok({ userAgent: "codex/0.160.0 (linux) client (" + params.clientInfo.name + ")", codexHome: 7 }), }); try { - const { code, out } = await gbot(fake.home, "--json", "codex", "status"); + const { code, out } = await gbot(fake.home, "codex", "status", "--json"); assert.equal(code, 0, out); const status = JSON.parse(out); assert.equal(status.reachable, true); @@ -732,7 +714,7 @@ test("codex status times out a hung codex --version probe instead of hanging", a const home = mkdtempSync(join(tmpdir(), "gbot-codex-nosock-")); const started = Date.now(); const result = await new Promise((resolve) => { - execFile(process.execPath, [CLI, "--json", "codex", "status"], { encoding: "utf8", env: { ...process.env, CODEX_HOME: home, PATH: bin } }, (error, out) => resolve({ code: error ? error.code : 0, out })); + execFile(process.execPath, [CLI, "codex", "status", "--json"], { encoding: "utf8", env: { ...process.env, CODEX_HOME: home, PATH: bin } }, (error, out) => resolve({ code: error ? error.code : 0, out })); }); assert.ok(Date.now() - started < 10000, "probe was bounded"); const status = JSON.parse(result.out); @@ -742,8 +724,8 @@ test("codex status times out a hung codex --version probe instead of hanging", a test("codex status rejects unknown arguments before touching the socket", async () => { const { code, err } = await gbot("/nonexistent", "codex", "status", "--verbose"); - assert.equal(code, 1); - assert.match(err, /^Unknown argument "--verbose"\. Usage: gbot codex status/); + assert.equal(code, 2); + assert.match(err, /^Unknown option: --verbose\./); }); test("codex list-threads pages with --cursor, echoes nextCursor, and rejects unknown args", async () => { @@ -757,7 +739,7 @@ test("codex list-threads pages with --cursor, echoes nextCursor, and rejects unk }, }); try { - const first = await gbot(fake.home, "--json", "codex", "list-threads", "--limit", "1"); + const first = await gbot(fake.home, "codex", "list-threads", "--limit", "1", "--json"); assert.equal(first.code, 0, first.err); const page = JSON.parse(first.out); assert.equal(page.nextCursor, "page-2\u001b[31m", "JSON keeps the opaque cursor verbatim"); @@ -766,16 +748,16 @@ test("codex list-threads pages with --cursor, echoes nextCursor, and rejects unk assert.match(text.out, /more: --cursor "page-2"\n$/, "text output strips controls from the cursor and quotes it"); assert.doesNotMatch(text.out, /\u001b/); - const second = await gbot(fake.home, "--json", "codex", "list-threads", "--limit", "1", "--cursor", "page-2"); + const second = await gbot(fake.home, "codex", "list-threads", "--limit", "1", "--cursor", "page-2", "--json"); assert.deepEqual(JSON.parse(second.out).threads.map((t) => t.id), ["t-2"]); assert.equal(JSON.parse(second.out).nextCursor, null); assert.deepEqual(seen.at(-1), { limit: 1, useStateDbOnly: true, cursor: "page-2" }); const unknown = await gbot(fake.home, "codex", "list-threads", "--all"); - assert.equal(unknown.code, 1); - assert.match(unknown.err, /^Unknown argument "--all"/); + assert.equal(unknown.code, 2); + assert.match(unknown.err, /^Unknown option: --all\./); const empty = await gbot(fake.home, "codex", "list-threads", "--cursor"); - assert.equal(empty.err, "--cursor needs a value\n"); + assert.match(empty.err, /--cursor requires a value/); } finally { await fake.close(); } @@ -784,11 +766,11 @@ test("codex list-threads pages with --cursor, echoes nextCursor, and rejects unk test("codex list-threads fails with bad-response when the daemon returns an unknown shape", async () => { const fake = await fakeAppServer({ ...baseHandlers, "thread/list": (params, ok) => ok({ threads: [] }) }); try { - const { code, err } = await gbot(fake.home, "--json", "codex", "list-threads"); + const { code, out } = await gbot(fake.home, "codex", "list-threads", "--json"); assert.equal(code, 1); - const failure = JSON.parse(err); + const failure = JSON.parse(out); assert.equal(failure.reason, "bad-response"); - assert.equal(failure.mode, "bad-response"); + assert.equal(failure.exitCode, 1); assert.match(failure.error, /unexpected thread\/list response: missing `data` array/); assert.match(failure.error, /pinned to app-server schema 0\.154\.0/); } finally { @@ -808,7 +790,7 @@ test("codex list-threads sanitizes text fields, keeps structured source, and rej }), }); try { - const { code, out } = await gbot(fake.home, "--json", "codex", "list-threads"); + const { code, out } = await gbot(fake.home, "codex", "list-threads", "--json"); assert.equal(code, 0); const { threads } = JSON.parse(out); assert.deepEqual(threads, [ @@ -820,10 +802,10 @@ test("codex list-threads sanitizes text fields, keeps structured source, and rej } const broken = await fakeAppServer({ ...baseHandlers, "thread/list": (params, ok) => ok({ data: [{ status: { type: "idle" } }], nextCursor: null }) }); try { - const { code, err } = await gbot(broken.home, "--json", "codex", "list-threads"); + const { code, out } = await gbot(broken.home, "codex", "list-threads", "--json"); assert.equal(code, 1); - assert.equal(JSON.parse(err).reason, "bad-response"); - assert.match(JSON.parse(err).error, /entry without a string `id`/); + assert.equal(JSON.parse(out).reason, "bad-response"); + assert.match(JSON.parse(out).error, /entry without a string `id`/); } finally { await broken.close(); } @@ -834,7 +816,7 @@ test("codex list-threads sanitizes text fields, keeps structured source, and rej test("codex send carries correlation and reply metadata, prepends the header, and bounds hops", async () => { const fake = await fakeAppServer(baseHandlers); try { - const reply = await gbot(fake.home, "--json", "codex", "send", "--correlation-id", "corr-1", "--reply-to", "msg-0", "--hop", "1", "t-1", "on it", "--dir", "src"); + const reply = await gbot(fake.home, "codex", "send", "--correlation-id", "corr-1", "--reply-to", "msg-0", "--hop", "1", "--json", "--", "t-1", "on it", "--dir", "src"); assert.equal(reply.code, 0, reply.err); const receipt = JSON.parse(reply.out); assert.equal(receipt.correlationId, "corr-1"); @@ -847,22 +829,27 @@ test("codex send carries correlation and reply metadata, prepends the header, an assert.match(header, new RegExp("^\\[gbot msg=" + receipt.messageId + " corr=corr-1 reply-to=msg-0 hop=1 from=[^\\s\\]]+\\]$")); assert.equal(body.join("\n"), "on it --dir src", "mid-message tokens stay message content"); - const looped = await gbot(fake.home, "--json", "codex", "send", "--correlation-id", "corr-1", "--reply-to", "msg-3", "--hop", "4", "t-1", "ack"); + const looped = await gbot(fake.home, "codex", "send", "--correlation-id", "corr-1", "--reply-to", "msg-3", "--hop", "4", "t-1", "ack", "--json"); assert.equal(looped.code, 1); - const refusal = JSON.parse(looped.err); + const refusal = JSON.parse(looped.out); assert.equal(refusal.delivery, "rejected"); assert.equal(refusal.reason, "hop-limit"); assert.equal(refusal.correlationId, "corr-1"); assert.match(refusal.error, /relay bound 4 \(GROK_BOT_MAX_HOPS\)/); assert.equal(fake.received.filter((m) => m.method === "turn/start").length, 1, "hop-limit refusals never reach the daemon"); - const orphan = await gbot(fake.home, "codex", "send", "--reply-to", "msg-0", "t-1", "hi"); + const orphan = await gbot(fake.home, "codex", "send", "--reply-to", "msg-0", "t-1", "hi", "--json"); assert.equal(orphan.code, 1); - assert.match(orphan.err, /--reply-to needs the original --correlation-id/); - const badId = await gbot(fake.home, "codex", "send", "--correlation-id", "has space", "t-1", "hi"); - assert.match(badId.err, /--correlation-id must be 1-128 characters/); - const badHop = await gbot(fake.home, "codex", "send", "--hop", "-1", "t-1", "hi"); - assert.match(badHop.err, /--hop must be a non-negative integer/); + assert.equal(JSON.parse(orphan.out).reason, "usage"); + assert.match(JSON.parse(orphan.out).error, /--reply-to needs the original --correlation-id/); + const badId = await gbot(fake.home, "codex", "send", "--correlation-id", "has space", "t-1", "hi", "--json"); + assert.equal(JSON.parse(badId.out).reason, "usage"); + assert.match(JSON.parse(badId.out).error, /--correlation-id must be 1-128 characters/); + const badHop = await gbot(fake.home, "codex", "send", "--hop", "-1", "t-1", "hi", "--json"); + assert.equal(badHop.code, 2); + const badHopError = JSON.parse(badHop.err).error; + assert.equal(badHopError.code, "CLI_INPUT_INVALID"); + assert.equal(badHopError.issues[0].target, "--hop"); } finally { await fake.close(); } @@ -874,25 +861,25 @@ test("GROK_BOT_MAX_HOPS and --envelope are honored; operator allowlist rejects o execFile(process.execPath, [CLI, ...args], { encoding: "utf8", env: { ...process.env, CODEX_HOME: fake.home, PATH: "/nonexistent", ...env } }, (error, out, err) => resolve({ code: error ? error.code : 0, out, err })); }); try { - const tight = await run({ GROK_BOT_MAX_HOPS: "1" }, "--json", "codex", "send", "--hop", "1", "t-1", "x"); - assert.equal(JSON.parse(tight.err).reason, "hop-limit"); - const loose = await run({ GROK_BOT_MAX_HOPS: "9" }, "--json", "codex", "send", "--hop", "8", "t-1", "x"); + const tight = await run({ GROK_BOT_MAX_HOPS: "1" }, "codex", "send", "--hop", "1", "t-1", "x", "--json"); + assert.equal(JSON.parse(tight.out).reason, "hop-limit"); + const loose = await run({ GROK_BOT_MAX_HOPS: "9" }, "codex", "send", "--hop", "8", "t-1", "x", "--json"); assert.equal(loose.code, 0, loose.err); assert.equal(JSON.parse(loose.out).maxHops, 9); - const enveloped = await run({}, "--json", "codex", "send", "--envelope", "t-1", "plain"); + const enveloped = await run({}, "codex", "send", "--envelope", "t-1", "plain", "--json"); assert.equal(enveloped.code, 0, enveloped.err); const start = fake.received.findLast((m) => m.method === "turn/start"); assert.match(start.params.input[0].text, /^\[gbot msg=[0-9a-f-]{36} corr=[0-9a-f-]{36} hop=0 from=[^\]]+\]\nplain$/); - const blocked = await run({ GROK_BOT_CODEX_THREADS: "t-9, t-8" }, "--json", "codex", "send", "t-1", "x"); + const blocked = await run({ GROK_BOT_CODEX_THREADS: "t-9, t-8" }, "codex", "send", "t-1", "x", "--json"); assert.equal(blocked.code, 1); - const refusal = JSON.parse(blocked.err); + const refusal = JSON.parse(blocked.out); assert.equal(refusal.reason, "route-not-allowed"); assert.equal(refusal.delivery, "rejected"); assert.match(refusal.error, /operator allows only: t-9, t-8/); const before = fake.received.length; - const allowed = await run({ GROK_BOT_CODEX_THREADS: "t-1" }, "--json", "codex", "send", "t-1", "x"); + const allowed = await run({ GROK_BOT_CODEX_THREADS: "t-1" }, "codex", "send", "t-1", "x", "--json"); assert.equal(allowed.code, 0, allowed.err); assert.ok(fake.received.length > before); } finally { @@ -902,9 +889,9 @@ test("GROK_BOT_MAX_HOPS and --envelope are honored; operator allowlist rejects o test("codex send reports an unavailable route as a structured rejected receipt", async () => { const home = mkdtempSync(join(tmpdir(), "gbot-codex-noroute-")); - const { code, err } = await gbot(home, "--json", "codex", "send", "t-1", "hello"); + const { code, out } = await gbot(home, "codex", "send", "t-1", "hello", "--json"); assert.equal(code, 1); - const failure = JSON.parse(err); + const failure = JSON.parse(out); assert.equal(failure.delivery, "rejected"); assert.equal(failure.reason, "socket-absent"); assert.equal(failure.mode, "socket-absent"); @@ -927,16 +914,16 @@ test("codex send refuses active and systemError threads without steering them", }), }); try { - const busy = await gbot(fake.home, "--json", "codex", "send", "t-busy", "hi"); + const busy = await gbot(fake.home, "codex", "send", "t-busy", "hi", "--json"); assert.equal(busy.code, 1); - const refusal = JSON.parse(busy.err); + const refusal = JSON.parse(busy.out); assert.equal(refusal.delivery, "rejected"); assert.equal(refusal.reason, "busy"); assert.equal(refusal.threadId, "t-busy"); assert.match(refusal.error, /active turn \(waitingOnUserInput\); sending now would steer that turn/); - const broken = await gbot(fake.home, "--json", "codex", "send", "t-err", "hi"); - assert.equal(JSON.parse(broken.err).reason, "thread-error"); + const broken = await gbot(fake.home, "codex", "send", "t-err", "hi", "--json"); + assert.equal(JSON.parse(broken.out).reason, "thread-error"); assert.equal(fake.received.filter((m) => m.method === "turn/start").length, 0, "no turn/start, turn/steer, or turn/interrupt was sent"); assert.equal(fake.received.filter((m) => /steer|interrupt/.test(m.method)).length, 0); } finally { @@ -947,10 +934,10 @@ test("codex send refuses active and systemError threads without steering them", test("codex send distinguishes external-owner, unknown-thread, and transport reasons", async () => { const fake = await fakeAppServer(baseHandlers); try { - const owned = JSON.parse((await gbot(fake.home, "--json", "codex", "send", "t-2", "hi")).err); + const owned = JSON.parse((await gbot(fake.home, "codex", "send", "t-2", "hi", "--json")).out); assert.equal(owned.reason, "external-owner"); assert.equal(owned.delivery, "rejected"); - const unknown = JSON.parse((await gbot(fake.home, "--json", "codex", "send", "nope", "hi")).err); + const unknown = JSON.parse((await gbot(fake.home, "codex", "send", "nope", "hi", "--json")).out); assert.equal(unknown.reason, "unknown-thread"); } finally { await fake.close(); @@ -960,7 +947,7 @@ test("codex send distinguishes external-owner, unknown-thread, and transport rea "turn/start": (params, ok, err, send, socket) => socket.destroy(), }); try { - const lost = JSON.parse((await gbot(dropping.home, "--json", "codex", "send", "t-1", "hi")).err); + const lost = JSON.parse((await gbot(dropping.home, "codex", "send", "t-1", "hi", "--json")).out); assert.equal(lost.delivery, "unknown"); assert.equal(lost.reason, "transport"); assert.match(lost.messageId, /^[0-9a-f-]{36}$/, "the receipt names the message to look for before resending"); @@ -974,7 +961,7 @@ test("codex send distinguishes external-owner, unknown-thread, and transport rea test("codex status classifies initialize failures as handshake-failed and off-schema init as bad-response", async () => { const rejecting = await fakeAppServer({ initialize: (params, ok, err) => err({ code: -32000, message: "nope" }) }); try { - const status = JSON.parse((await gbot(rejecting.home, "--json", "codex", "status")).out); + const status = JSON.parse((await gbot(rejecting.home, "codex", "status", "--json")).out); assert.equal(status.reachable, false); assert.equal(status.mode, "handshake-failed"); assert.match(status.message, /initialize failed: Codex app-server rejected initialize: nope/); @@ -983,7 +970,7 @@ test("codex status classifies initialize failures as handshake-failed and off-sc } const offSchema = await fakeAppServer({ initialize: (params, ok) => ok("not-an-object") }); try { - const { code, out } = await gbot(offSchema.home, "--json", "codex", "status"); + const { code, out } = await gbot(offSchema.home, "codex", "status", "--json"); assert.equal(code, 1); const status = JSON.parse(out); assert.equal(status.reachable, true, "the endpoint answered"); @@ -1001,7 +988,7 @@ test("codex status reports permission-denied when connect fails with EACCES", { await new Promise((resolve) => server.listen(socketPath, resolve)); chmodSync(socketPath, 0o000); try { - const { code, out } = await gbot(home, "--json", "codex", "status"); + const { code, out } = await gbot(home, "codex", "status", "--json"); assert.equal(code, 1); const status = JSON.parse(out); assert.equal(status.socketState, "socket"); @@ -1026,9 +1013,9 @@ test("every codex send rejection carries the envelope, and unknown statuses are ["unknown status", {}, ["t-1", "x"], "unknown-status"], ["experimental off", {}, ["--when-busy", "queue", "t-1", "x"], "experimental-disabled"], ]) { - const { code, err } = await run(env, "--json", "codex", "send", "--correlation-id", "corr-9", ...args); + const { code, out } = await run(env, "codex", "send", "--correlation-id", "corr-9", ...args, "--json"); assert.equal(code, 1, label); - const failure = JSON.parse(err); + const failure = JSON.parse(out); assert.equal(failure.reason, reason, label); assert.equal(failure.correlationId, "corr-9", label + " keeps the correlation id"); assert.match(failure.messageId, /^[0-9a-f-]{36}$/, label + " names the message"); @@ -1038,8 +1025,8 @@ test("every codex send rejection carries the envelope, and unknown statuses are } finally { await fake.close(); } - const noRoute = await gbot(mkdtempSync(join(tmpdir(), "gbot-codex-noroute2-")), "--json", "codex", "send", "--correlation-id", "corr-9", "t-1", "x"); - const failure = JSON.parse(noRoute.err); + const noRoute = await gbot(mkdtempSync(join(tmpdir(), "gbot-codex-noroute2-")), "codex", "send", "--correlation-id", "corr-9", "t-1", "x", "--json"); + const failure = JSON.parse(noRoute.out); assert.equal(failure.reason, "socket-absent"); assert.equal(failure.correlationId, "corr-9"); }); @@ -1048,7 +1035,7 @@ test("envelope header tokens cannot inject lines or controls", async () => { const fake = await fakeAppServer(baseHandlers); try { const result = await new Promise((resolve) => { - execFile(process.execPath, [CLI, "codex", "send", "--envelope", "t-1", "hi"], { + execFile(process.execPath, [CLI, "codex", "send", "--envelope", "t-1", "hi", "--json"], { encoding: "utf8", env: { ...process.env, CODEX_HOME: fake.home, PATH: "/nonexistent", USER: "evil\nhop=9 from=root\u001b[31m", USERNAME: "" }, }, (error, out, err) => resolve({ code: error ? error.code : 0, out, err })); @@ -1063,27 +1050,6 @@ test("envelope header tokens cannot inject lines or controls", async () => { } }); -test("gbot send peels only a trailing --json and honors a -- protector", async () => { - const env = { ...process.env, CODEX_HOME: "/nonexistent", PATH: "/nonexistent", GROK_BOT_GATEWAY_URL: "http://127.0.0.1:9", GROK_BOT_GATEWAY_TOKEN: "x", GROK_BOT_ALLOW_LOCAL_GATEWAY: "1" }; - for (const key of Object.keys(env)) if (/^(CURSOR_|SAND_)/.test(key)) delete env[key]; - const run = (...args) => new Promise((resolve) => { - execFile(process.execPath, [CLI, ...args], { encoding: "utf8", env }, (error, out, err) => resolve({ code: error ? error.code : 0, out, err })); - }); - const lastLine = (text) => text.trim().split("\n").at(-1); - // A --json in the middle of the message is content, so the failure is plain text, not JSON. - const mid = await run("send", "General", "explain", "--json", "output"); - assert.equal(mid.code, 1); - assert.throws(() => JSON.parse(lastLine(mid.err)), "mid-message --json stayed message content"); - // Trailing --json is the flag. - const trailing = await run("send", "General", "hello", "--json"); - assert.equal(trailing.code, 1); - assert.ok(JSON.parse(lastLine(trailing.err)).error, "trailing --json produced a structured error"); - // `--` protects a message that ends with --json. - const protectedRun = await run("send", "General", "--", "ends with", "--json"); - assert.equal(protectedRun.code, 1); - assert.throws(() => JSON.parse(lastLine(protectedRun.err)), "protected --json stayed message content"); -}); - test("codex list-threads accepts an opaque cursor that starts with a dash", async () => { const seen = []; const fake = await fakeAppServer({ ...baseHandlers, "thread/list": (params, ok) => { seen.push(params); ok({ data: [], nextCursor: null }); } }); @@ -1109,7 +1075,7 @@ test("--when-busy queue hands a busy thread to the daemon queue under the experi execFile(process.execPath, [CLI, ...args], { encoding: "utf8", env: { ...process.env, CODEX_HOME: fake.home, PATH: "/nonexistent", GROK_BOT_CODEX_EXPERIMENTAL: "1" } }, (error, out, err) => resolve({ code: error ? error.code : 0, out, err })); }); try { - const { code, out } = await run("--json", "codex", "send", "--when-busy", "queue", "t-1", "later please"); + const { code, out } = await run("codex", "send", "--when-busy", "queue", "t-1", "later please", "--json"); assert.equal(code, 0, out); const receipt = JSON.parse(out); assert.equal(receipt.delivery, "queued"); @@ -1122,9 +1088,9 @@ test("--when-busy queue hands a busy thread to the daemon queue under the experi assert.equal(add.params.input[0].text, "later please"); assert.equal(fake.received.filter((m) => /turn\/(start|steer|interrupt)/.test(m.method)).length, 0); - const queue = await run("--json", "codex", "queue", "t-1"); + const queue = await run("codex", "queue", "t-1", "--json"); assert.equal(queue.code, 0, queue.err); - assert.deepEqual(JSON.parse(queue.out), { threadId: "t-1", queued: [{ id: "q-1", clientUserMessageId: "m-1", text: "queued\u001b[31m body" }], nextCursor: null }); + assert.deepEqual(JSON.parse(queue.out), { threadId: "t-1", queued: [{ id: "q-1", clientUserMessageId: "m-1", text: "queued\u001b[31m body" }], nextCursor: null, exitCode: 0 }); const text = await run("codex", "queue", "t-1"); assert.doesNotMatch(text.out, /\u001b/); } finally { @@ -1135,11 +1101,11 @@ test("--when-busy queue hands a busy thread to the daemon queue under the experi "thread/resume": (params, ok) => ok({ thread: { id: params.threadId, status: { type: "active", activeFlags: [] } }, model: "m", cwd: "/", approvalPolicy: "never" }), }); try { - const { code, err } = await new Promise((resolve) => { - execFile(process.execPath, [CLI, "--json", "codex", "send", "--when-busy", "queue", "t-1", "x"], { encoding: "utf8", env: { ...process.env, CODEX_HOME: old.home, PATH: "/nonexistent", GROK_BOT_CODEX_EXPERIMENTAL: "1" } }, (error, out, err) => resolve({ code: error ? error.code : 0, out, err })); + const { code, out } = await new Promise((resolve) => { + execFile(process.execPath, [CLI, "codex", "send", "--when-busy", "queue", "t-1", "x", "--json"], { encoding: "utf8", env: { ...process.env, CODEX_HOME: old.home, PATH: "/nonexistent", GROK_BOT_CODEX_EXPERIMENTAL: "1" } }, (error, out, err) => resolve({ code: error ? error.code : 0, out, err })); }); assert.equal(code, 1); - assert.equal(JSON.parse(err).reason, "unsupported"); + assert.equal(JSON.parse(out).reason, "unsupported"); } finally { await old.close(); } diff --git a/test/codex-contract.test.js b/test/codex-contract.test.js new file mode 100644 index 0000000..ba38568 --- /dev/null +++ b/test/codex-contract.test.js @@ -0,0 +1,115 @@ +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; + +import { + outcomeFromError, + outcomeFromReceipt, + sendExitCode, + statusExitCode, + withStatusExitCode, +} from "../src/core/codex/contract.js"; + +describe("codex contract — status exit", () => { + it("exit 0 only for reachable daemon", () => { + assert.equal(statusExitCode({ reachable: true, mode: "daemon" }), 0); + assert.equal(statusExitCode({ reachable: false, mode: "socket-absent" }), 1); + assert.equal(statusExitCode({ reachable: true, mode: "bad-response" }), 1); + assert.equal(statusExitCode({ reachable: false, mode: "daemon" }), 1); + }); + + it("withStatusExitCode attaches exitCode without mutating", () => { + const status = { reachable: true, mode: "daemon", socketPath: "/tmp/x" }; + const doc = withStatusExitCode(status); + assert.equal(doc.exitCode, 0); + assert.equal("exitCode" in status, false); + }); +}); + +describe("codex contract — send exit", () => { + it("accepted and queued succeed", () => { + assert.equal(sendExitCode({ delivery: "accepted" }), 0); + assert.equal(sendExitCode({ delivery: "queued" }), 0); + }); + + it("rejected, unknown, and error fail", () => { + assert.equal(sendExitCode({ delivery: "rejected", error: "nope" }), 1); + assert.equal(sendExitCode({ delivery: "unknown", error: "maybe" }), 1); + assert.equal(sendExitCode({ delivery: "accepted", error: "x" }), 1); + }); + + it("approval-refused is accepted delivery with exit 1", () => { + assert.equal(sendExitCode({ delivery: "accepted", reason: "approval-refused" }), 1); + }); +}); + +describe("codex contract — outcomeFromError", () => { + it("flattens CodexSendError fields like fail()", () => { + const err = Object.assign(new Error("busy thread"), { + name: "CodexSendError", + delivery: "rejected", + reason: "busy", + threadId: "thr_1", + envelope: { messageId: "m_1", correlationId: "c_1", hop: 2 }, + }); + const out = outcomeFromError(err); + assert.equal(out.error, "busy thread"); + assert.equal(out.delivery, "rejected"); + assert.equal(out.reason, "busy"); + assert.equal(out.threadId, "thr_1"); + assert.equal(out.messageId, "m_1"); + assert.equal(out.correlationId, "c_1"); + assert.equal(out.hop, 2); + assert.equal(out.exitCode, 1); + }); + + it("marks StoreError as usage", () => { + const err = Object.assign(new Error("bad argv"), { name: "StoreError" }); + const out = outcomeFromError(err); + assert.equal(out.reason, "usage"); + assert.equal(out.delivery, "rejected"); + assert.equal(out.exitCode, 1); + }); + + it("marks route input errors as usage", () => { + const out = outcomeFromError(new RangeError("bad flag")); + assert.equal(out.reason, "usage"); + assert.equal(out.delivery, "rejected"); + assert.equal(out.exitCode, 1); + }); + + it("keeps the bridge reason strings verbatim", () => { + const reasons = ["busy", "hop-limit", "route-not-allowed", "thread-error", "unknown-status", "unknown-thread", "external-owner", "experimental-disabled", "unsupported", "rejected", "transport", "bad-response", "approval-refused", "usage"]; + for (const reason of reasons) { + const out = outcomeFromError( + Object.assign(new Error(reason), { delivery: "rejected", reason }), + ); + assert.equal(out.reason, reason); + assert.equal(out.exitCode, 1); + } + }); +}); + +describe("codex contract — outcomeFromReceipt", () => { + it("queued receipt exits 0", () => { + const out = outcomeFromReceipt({ + delivery: "queued", + threadId: "t", + messageId: "m", + queuedSubmissionId: "q", + }); + assert.equal(out.exitCode, 0); + assert.equal(out.error, undefined); + }); + + it("approval-refused receipt exits 1 with error", () => { + const out = outcomeFromReceipt({ + delivery: "accepted", + reason: "approval-refused", + threadId: "t", + turnId: "turn", + refused: ["approvals/request"], + }); + assert.equal(out.exitCode, 1); + assert.ok(typeof out.error === "string" && out.error.length > 0); + }); +}); diff --git a/test/connect-gateway.test.js b/test/connect-gateway.test.js index 6197796..8da1e6d 100644 --- a/test/connect-gateway.test.js +++ b/test/connect-gateway.test.js @@ -4,8 +4,8 @@ import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import test from "node:test"; -import { grokBotGatewayDescriptorPath } from "../src/app-session.js"; -import { connectGateway } from "../src/gateway.js"; +import { grokBotGatewayDescriptorPath } from "../src/core/app-session.js"; +import { connectGateway } from "../src/core/gateway.js"; function withEnv(values, fn) { const prev = {}; diff --git a/test/doctor.test.js b/test/doctor.test.js index 11d109c..c9da0c7 100644 --- a/test/doctor.test.js +++ b/test/doctor.test.js @@ -6,9 +6,9 @@ import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import test from "node:test"; -import { grokBotGatewayDescriptorPath } from "../src/app-session.js"; +import { grokBotGatewayDescriptorPath } from "../src/core/app-session.js"; -const CLI = fileURLToPath(new URL("../src/cli.js", import.meta.url)); +const CLI = fileURLToPath(new URL("../dist/bin/gbot.mjs", import.meta.url)); test("doctor reports a present but unusable Grok Bot app session", { skip: !["darwin", "linux"].includes(process.platform) && "Grok Bot app sessions are macOS/Linux-only", @@ -30,7 +30,7 @@ test("doctor reports a present but unusable Grok Bot app session", { "SAND_GATEWAY_TOKEN", ]) delete env[name]; - const result = spawnSync(process.execPath, [CLI, "--json", "doctor"], { + const result = spawnSync(process.execPath, [CLI, "doctor", "--json"], { encoding: "utf8", env, }); diff --git a/test/gateway-groups.test.js b/test/gateway-groups.test.js index d6fe04e..681b7c4 100644 --- a/test/gateway-groups.test.js +++ b/test/gateway-groups.test.js @@ -5,8 +5,8 @@ import { createGroup, removeGroupMember, setGroupMembers, -} from "../src/gateway.js"; -import { MAX_GROUP_MEMBERS } from "../src/store.js"; +} from "../src/core/gateway.js"; +import { MAX_GROUP_MEMBERS } from "../src/core/store.js"; const session = { gatewayUrl: "https://box.cursor.sh", gatewayToken: "test-token" }; const bots = Array.from({ length: MAX_GROUP_MEMBERS + 1 }, (_, i) => ({ diff --git a/test/gateway-send.test.js b/test/gateway-send.test.js index 9005ce5..79cabd0 100644 --- a/test/gateway-send.test.js +++ b/test/gateway-send.test.js @@ -1,7 +1,7 @@ import test from "node:test"; import assert from "node:assert/strict"; -import { GATEWAY_MAX_RESPONSE_BYTES, getTranscriptTail, sendPrompt } from "../src/gateway.js"; +import { GATEWAY_MAX_RESPONSE_BYTES, getTranscriptTail, sendPrompt } from "../src/core/gateway.js"; const session = { gatewayUrl: "https://box.cursor.sh", gatewayToken: "t" }; const roster = { agents: [{ id: "bot-1", name: "General" }] }; diff --git a/test/gateway.test.js b/test/gateway.test.js index 591b293..ae3e15d 100644 --- a/test/gateway.test.js +++ b/test/gateway.test.js @@ -5,7 +5,7 @@ import { mergeGatewayHeaders, parseGatewayHeaders, requestHeaders, -} from "../src/headers.js"; +} from "../src/core/headers.js"; test("parses env JSON headers", () => { const headers = parseGatewayHeaders('{"X-Anyrun-Network-Token":"abc","empty":""}'); diff --git a/test/history.test.js b/test/history.test.js index b1c5154..edd91e1 100644 --- a/test/history.test.js +++ b/test/history.test.js @@ -10,7 +10,7 @@ import test from "node:test"; import { promisify } from "node:util"; const exec = promisify(execFile); -const CLI = fileURLToPath(new URL("../src/cli.js", import.meta.url)); +const CLI = fileURLToPath(new URL("../dist/bin/gbot.mjs", import.meta.url)); const target = { id: "bot-1", name: "Researcher", description: "PRIVATE_INSTRUCTIONS" }; const group = { id: "group-1", name: "Launch", isGroup: true, memberIds: [target.id] }; const reply = "A long reply: " + "x".repeat(500) + "\nneedle at the end 🔧"; @@ -142,13 +142,13 @@ test("thread --after returns exclusive deltas, no-op receipts, and bounded gap r test("recording opt-outs do not create storage or disable access to existing history", async (t) => { const f = await fixture(t); - await f.run(["--no-history", "send", "Researcher", "private prompt"]); + await f.run(["send", "--no-history", "Researcher", "private prompt"]); for (const value of ["off", "FALSE", "0"]) { await f.run(["thread", "Researcher"], { GROK_BOT_HISTORY: value }); } assert.equal(existsSync(f.path), false); await f.run(["send", "Researcher", "saved"]); - await f.run(["--no-history", "thread", "Researcher"]); + await f.run(["thread", "--no-history", "Researcher"]); const found = await f.run(["history", "--json"], { GROK_BOT_HISTORY: "off" }, false); assert.equal(JSON.parse(found.stdout).length, 1); assert.equal(f.rows().length, 1); @@ -162,12 +162,12 @@ test("history path is offline and side-effect free; flag directory overrides env const dir = join(f.home, "custom history"); const extra = { GROK_BOT_HISTORY_DIR: join(f.home, "env-history") }; await f.run(["send", "Researcher", "env"], extra); - await f.run(["--history-dir", dir, "send", "Researcher", "flag"], extra); - const found = await f.run(["--history-dir", dir, "history", "--json"], extra, false); + await f.run(["send", "--history-dir", dir, "Researcher", "flag"], extra); + const found = await f.run(["history", "--history-dir", dir, "--json"], extra, false); assert.equal(JSON.parse(found.stdout)[0].text, "flag"); const envHistory = await f.run(["history", "--json"], extra, false); assert.equal(JSON.parse(envHistory.stdout)[0].text, "env"); - const path = await f.run(["--history-dir", dir, "history", "--path", "--json"], extra, false); + const path = await f.run(["history", "--history-dir", dir, "--path", "--json"], extra, false); assert.deepEqual(JSON.parse(path.stdout), { path: join(dir, "history.jsonl") }); }); @@ -180,7 +180,7 @@ test("offline history handles missing files, filters before limiting, and valida assert.equal(JSON.parse(result.stdout)[0].text, "match two"); assert.deepEqual(JSON.parse((await f.run(["history", "unknown", "--json"], {}, false)).stdout), []); for (const args of [["--limit", "0"], ["--limit", "1.5"], ["--limit", "NaN"], ["--path", "Researcher"], ["--unknown"]]) { - await assert.rejects(f.run(["history", ...args], {}, false), (err) => err.code === 1); + await assert.rejects(f.run(["history", ...args], {}, false), (err) => err.code === 2); } }); @@ -188,6 +188,20 @@ test("failed sends and empty threads leave no history; disk failure does not fai const f = await fixture(t); f.state.failSend = true; await assert.rejects(f.run(["send", "Researcher", "rejected"])); + const failed = await f.run(["send", "Researcher", "rejected", "--json"]).catch((err) => err); + assert.equal(failed.code, 1); + const failure = JSON.parse(failed.stdout); + assert.equal(failure.exitCode, 1); + assert.equal(failure.delivery, "unknown", "the request left; the gateway never acknowledged it"); + assert.match(failure.error, /sendPrompt failed: 500/); + const sends = f.calls.filter((c) => c.method === "/api/sendPrompt").length; + const looped = await f.run(["send", "--hop", "4", "Researcher", "ack", "--json"], {}, false).catch((err) => err); + assert.equal(looped.code, 1); + assert.equal(JSON.parse(looped.stdout).reason, "hop-limit"); + assert.equal(f.calls.filter((c) => c.method === "/api/sendPrompt").length, sends, "hop-limit refusals never reach the gateway"); + const usage = await f.run(["send", "--files", "--dir", f.home, "Researcher", "hi", "--json"], {}, false).catch((err) => err); + assert.equal(usage.code, 1); + assert.equal(JSON.parse(usage.stdout).reason, "usage", "StoreError keeps its name through redaction"); assert.equal(existsSync(f.path), false); f.state.payload = { entries: [] }; await f.run(["thread", "Researcher"]); @@ -195,10 +209,13 @@ test("failed sends and empty threads leave no history; disk failure does not fai f.state.failSend = false; const blocked = join(f.home, "not-a-directory"); writeFileSync(blocked, "occupied"); - const result = await f.run(["--history-dir", blocked, "send", "Researcher", "sent once", "--json"]); + const result = await f.run(["send", "--history-dir", blocked, "Researcher", "sent once", "--json"]); assert.equal(JSON.parse(result.stdout).result.ok, true); assert.match(result.stderr, /Warning: could not save local history/); assert.equal(f.calls.filter((c) => c.method === "/api/sendPrompt" && c.body.prompt === "sent once").length, 1); + const protectedText = await f.run(["send", "Researcher", "--", "--json"]); + assert.match(protectedText.stdout, /^Sent to bot Researcher/); + assert.equal(f.calls.at(-1).body.prompt, "--json", "`--` makes flag-like text literal"); }); test("history skips malformed records and separates interrupted writes on the next append", async (t) => { @@ -223,7 +240,7 @@ test("refuses to append through a history-file symlink", { skip: process.platfor const destination = join(f.home, "unrelated-file"); writeFileSync(destination, "keep me"); symlinkSync(destination, join(f.home, "history.jsonl")); - const result = await f.run(["--history-dir", f.home, "send", "Researcher", "hello"]); + const result = await f.run(["send", "--history-dir", f.home, "Researcher", "hello"]); assert.match(result.stderr, /could not save local history/); assert.equal(readFileSync(destination, "utf8"), "keep me"); }); diff --git a/test/release-config.test.js b/test/release-config.test.js index b85ce19..f07a574 100644 --- a/test/release-config.test.js +++ b/test/release-config.test.js @@ -20,9 +20,12 @@ test("npm package metadata identifies the public source repository", () => { }); }); -test("npm executable paths are already normalized for publishing", () => { +test("npm executable paths point at the Agent Bundle dist bins", () => { assert.deepEqual(packageJson.bin, { - gbot: "src/cli.js", - "grok-bot": "src/cli.js", + gbot: "./dist/bin/gbot.mjs", + "gbot-install": "./dist/bin/gbot-install.js", + "grok-bot": "./dist/bin/gbot.mjs", }); + assert.deepEqual(packageJson.files, ["dist", "README.md", "CHANGELOG.md", "LICENSE"]); + assert.equal(packageJson.scripts.prepack, "agent-bundle prepack"); }); diff --git a/test/store.test.js b/test/store.test.js index edf8f4d..9fc84eb 100644 --- a/test/store.test.js +++ b/test/store.test.js @@ -12,7 +12,7 @@ import { removeGroupMember, setGroupMembers, updateAgent, -} from "../src/store.js"; +} from "../src/core/store.js"; function withRoot(fn) { const root = mkdtempSync(join(tmpdir(), "gbot-")); diff --git a/test/transcript.test.js b/test/transcript.test.js index ea8220a..8aced79 100644 --- a/test/transcript.test.js +++ b/test/transcript.test.js @@ -1,6 +1,7 @@ import test from "node:test"; import assert from "node:assert/strict"; -import { entryText, sourceEntryId, transcriptDelta, transcriptEntries } from "../src/transcript.js"; +import { formatTranscript } from "../src/core/format.js"; +import { entryText, sourceEntryId, transcriptDelta, transcriptEntries } from "../src/core/transcript.js"; test("user messages read content, bot replies read message.content", () => { assert.equal(entryText({ kind: "message", role: "user", content: "hello" }), "hello"); @@ -27,6 +28,16 @@ test("transcript containers unwrap to an entry list", () => { assert.deepEqual(transcriptEntries(null), []); }); +test("human transcript output truncates by default and --full preserves text", () => { + const text = "x".repeat(450); + const out = { + target: { id: "bot-1", isGroup: false, name: "Researcher" }, + transcript: { entries: [{ id: "m1", role: "assistant", text }] }, + }; + assert.match(formatTranscript(out), /… \[\+50 chars; --full or --json for complete text\]$/); + assert.match(formatTranscript(out, { full: true }), new RegExp(`${text}$`)); +}); + test("entryText never throws and normalizes malformed content to safe strings", () => { assert.equal(entryText({ content: { text: 5 } }), "5"); assert.equal(entryText({ content: { flag: true } }), '{"flag":true}'); diff --git a/test/url-policy.test.js b/test/url-policy.test.js index 1185d8b..9644529 100644 --- a/test/url-policy.test.js +++ b/test/url-policy.test.js @@ -4,7 +4,7 @@ import { assertAllowedCredentialUrl, redactSecrets, resetPolicyWarnings, -} from "../src/url-policy.js"; +} from "../src/core/url-policy.js"; function withEnv(values, fn) { const prev = {}; diff --git a/plugin/tests/route-unit/tools.test.ts b/tests/route-unit/tools.test.ts similarity index 100% rename from plugin/tests/route-unit/tools.test.ts rename to tests/route-unit/tools.test.ts diff --git a/plugin/tsconfig.json b/tsconfig.json similarity index 100% rename from plugin/tsconfig.json rename to tsconfig.json