genaicode 2.11.0 → 2.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +52 -1
  2. package/README.md +18 -16
  3. package/dist/agents/cli-agent.d.ts +6 -3
  4. package/dist/agents/cli-agent.js +57 -35
  5. package/dist/agents/cli-agent.js.map +1 -1
  6. package/dist/agents/drivers/antigravity.d.ts +7 -1
  7. package/dist/agents/drivers/antigravity.js +27 -2
  8. package/dist/agents/drivers/antigravity.js.map +1 -1
  9. package/dist/agents/drivers/claude-approvals.d.ts +86 -0
  10. package/dist/agents/drivers/claude-approvals.js +278 -0
  11. package/dist/agents/drivers/claude-approvals.js.map +1 -0
  12. package/dist/agents/drivers/claude.d.ts +12 -2
  13. package/dist/agents/drivers/claude.js +74 -11
  14. package/dist/agents/drivers/claude.js.map +1 -1
  15. package/dist/agents/drivers/codex-approvals.d.ts +11 -0
  16. package/dist/agents/drivers/codex-approvals.js +118 -0
  17. package/dist/agents/drivers/codex-approvals.js.map +1 -0
  18. package/dist/agents/drivers/codex-live.d.ts +12 -1
  19. package/dist/agents/drivers/codex-live.js +46 -32
  20. package/dist/agents/drivers/codex-live.js.map +1 -1
  21. package/dist/agents/drivers/codex.d.ts +10 -1
  22. package/dist/agents/drivers/codex.js +48 -2
  23. package/dist/agents/drivers/codex.js.map +1 -1
  24. package/dist/agents/drivers/copilot.d.ts +9 -1
  25. package/dist/agents/drivers/copilot.js +31 -1
  26. package/dist/agents/drivers/copilot.js.map +1 -1
  27. package/dist/agents/drivers/cursor.d.ts +10 -1
  28. package/dist/agents/drivers/cursor.js +48 -5
  29. package/dist/agents/drivers/cursor.js.map +1 -1
  30. package/dist/agents/drivers/gemini.d.ts +11 -1
  31. package/dist/agents/drivers/gemini.js +46 -2
  32. package/dist/agents/drivers/gemini.js.map +1 -1
  33. package/dist/agents/drivers/muse-approvals.d.ts +19 -0
  34. package/dist/agents/drivers/muse-approvals.js +157 -0
  35. package/dist/agents/drivers/muse-approvals.js.map +1 -0
  36. package/dist/agents/drivers/muse-live.d.ts +5 -1
  37. package/dist/agents/drivers/muse-live.js +21 -109
  38. package/dist/agents/drivers/muse-live.js.map +1 -1
  39. package/dist/agents/drivers/opencode.d.ts +7 -1
  40. package/dist/agents/drivers/opencode.js +28 -2
  41. package/dist/agents/drivers/opencode.js.map +1 -1
  42. package/dist/agents/drivers/permission-args.d.ts +14 -0
  43. package/dist/agents/drivers/permission-args.js +40 -0
  44. package/dist/agents/drivers/permission-args.js.map +1 -0
  45. package/dist/agents/drivers/vibe.d.ts +9 -1
  46. package/dist/agents/drivers/vibe.js +40 -2
  47. package/dist/agents/drivers/vibe.js.map +1 -1
  48. package/dist/agents/hosted.js +9 -0
  49. package/dist/agents/hosted.js.map +1 -1
  50. package/dist/agents/live-agent.d.ts +49 -4
  51. package/dist/agents/live-agent.js +84 -15
  52. package/dist/agents/live-agent.js.map +1 -1
  53. package/dist/agents/permissions.d.ts +27 -0
  54. package/dist/agents/permissions.js +79 -0
  55. package/dist/agents/permissions.js.map +1 -0
  56. package/dist/agents/prepare.d.ts +12 -1
  57. package/dist/agents/prepare.js +18 -3
  58. package/dist/agents/prepare.js.map +1 -1
  59. package/dist/agents/rpc.d.ts +13 -2
  60. package/dist/agents/rpc.js +20 -2
  61. package/dist/agents/rpc.js.map +1 -1
  62. package/dist/agents/runtime.d.ts +4 -0
  63. package/dist/agents/runtime.js +20 -0
  64. package/dist/agents/runtime.js.map +1 -1
  65. package/dist/agents/session.d.ts +4 -1
  66. package/dist/agents/session.js +31 -6
  67. package/dist/agents/session.js.map +1 -1
  68. package/dist/agents/types.d.ts +56 -7
  69. package/dist/agents.d.ts +21 -13
  70. package/dist/agents.js +14 -9
  71. package/dist/agents.js.map +1 -1
  72. package/dist/react/agent-chat.js +10 -2
  73. package/dist/react/agent-chat.js.map +1 -1
  74. package/dist/ui/index.js +69 -69
  75. package/dist/ui/web-client.js +9 -9
  76. package/docs/agents.md +129 -19
  77. package/package.json +5 -5
package/docs/agents.md CHANGED
@@ -119,19 +119,19 @@ session.send('Now cover it with a test'); // resumes the same agent session
119
119
 
120
120
  ## Drivers
121
121
 
122
- | Driver | Command | Mode | Notes |
123
- | --------------------- | -------------- | ---------------------------------------- | -------------------------------------------------------------------------------------- |
124
- | `claude(options?)` | `claude` | `-p --output-format stream-json` | `permissionMode` defaults to `acceptEdits`; `allowedTools` / `disallowedTools` |
125
- | `codex(options?)` | `codex` | `exec --json` | `sandbox` defaults to `workspace-write`; effort via `model_reasoning_effort` |
126
- | `muse(options?)` | `muse` | `exec --json --trust-workspace` | `maxTurns` maps to `--max-model-steps` |
127
- | `codexLive(options?)` | `codex` | `app-server` (JSON-RPC) | `steer()`, approvals, MCP. See [Live sessions](#live-sessions-steering-and-approvals) |
128
- | `museLive(options?)` | `muse` | `serve` (JSON-RPC) | `steer()`, approvals. See [Live sessions](#live-sessions-steering-and-approvals) |
129
- | `gemini(options?)` | `gemini` | `--output-format stream-json --prompt=…` | `approvalMode` defaults to `auto_edit`; `--skip-trust` unless `trustWorkspace: false` |
130
- | `cursor(options?)` | `cursor-agent` | `-p --output-format stream-json` | `--force --approve-mcps` by default (`--trust` if `force: false`); `partialOutput` |
131
- | `opencode(options?)` | `opencode` | `run --format json` | `model` is `provider/model`; `effort` maps to `--variant`; `autoApprove` adds `--auto` |
132
- | `copilot(options?)` | `copilot` | `--output-format json --prompt=…` | `--allow-all-tools --no-ask-user` by default; `allowTools` / `denyTools` patterns |
133
- | `vibe(options?)` | `vibe` | `--output streaming --prompt=…` | `agent` defaults to `accept-edits`; `--trust`; `model` via `VIBE_ACTIVE_MODEL` |
134
- | `antigravity(opts?)` | `agy` | `--output-format stream-json --print` | `mode` defaults to `accept-edits`; `--sandbox` unless `sandbox: false` |
122
+ | Driver | Command | Mode | Notes |
123
+ | --------------------- | -------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------- |
124
+ | `claude(options?)` | `claude` | `-p --output-format stream-json` | `permissionMode` defaults to `acceptEdits`; `allowedTools` / `disallowedTools`; approvals |
125
+ | `codex(options?)` | `codex` | `exec --json` | `sandbox` defaults to `workspace-write`; effort via `model_reasoning_effort` |
126
+ | `muse(options?)` | `muse` | `exec --json --trust-workspace` | `maxTurns` maps to `--max-model-steps` |
127
+ | `codexLive(options?)` | `codex` | `app-server` (JSON-RPC) | `steer()`, approvals, MCP. See [Live sessions](#live-sessions-steering-and-approvals) |
128
+ | `museLive(options?)` | `muse` | `serve` (JSON-RPC) | `steer()`, approvals. See [Live sessions](#live-sessions-steering-and-approvals) |
129
+ | `gemini(options?)` | `gemini` | `--output-format stream-json --prompt=…` | `approvalMode` defaults to `auto_edit`; `--skip-trust` unless `trustWorkspace: false` |
130
+ | `cursor(options?)` | `cursor-agent` | `-p --output-format stream-json` | `--force --approve-mcps` by default (`--trust` if `force: false`); `partialOutput` |
131
+ | `opencode(options?)` | `opencode` | `run --format json` | `model` is `provider/model`; `effort` maps to `--variant`; `autoApprove` adds `--auto` |
132
+ | `copilot(options?)` | `copilot` | `--output-format json --prompt=…` | `--allow-all-tools --no-ask-user` by default; `allowTools` / `denyTools` patterns |
133
+ | `vibe(options?)` | `vibe` | `--output streaming --prompt=…` | `agent` defaults to `accept-edits`; `--trust`; `model` via `VIBE_ACTIVE_MODEL` |
134
+ | `antigravity(opts?)` | `agy` | `--output-format stream-json --print` | `mode` defaults to `accept-edits`; `--sandbox` unless `sandbox: false` |
135
135
 
136
136
  Every driver accepts `command` to point at a specific executable. `task.extraArgs` is
137
137
  inserted before the prompt for flags that have no portable field.
@@ -160,15 +160,125 @@ const result = await run.result;
160
160
 
161
161
  - `steer(text)` resolves once the agent acknowledges the input. It rejects after the task has
162
162
  ended, and when no acknowledgement arrives (the input may or may not have reached the agent).
163
- - `onApproval` is asked for each permission request. It gets a `command`, `file-change` or
164
- `other` request and returns `'approve'` or `'deny'`. If `onApproval` is missing or throws, the
165
- request is denied. Codex runs with approval policy `never` when no `onApproval` is set.
166
- - `museLive()` answers each approval with one of the choices Muse offers: the `once`
167
- approve or deny choice where there is one. A multi-stage approval asks `onApproval` once
168
- per stage; later stages get ids like `ap-1/2`.
163
+ - `onApproval` answers permission requests; see [Approvals](#approvals).
169
164
  - The task ends when the agent reports its turn complete. The server is then stopped. An exit
170
165
  before that point is a failure, even with exit code 0.
171
166
 
167
+ ## Approvals
168
+
169
+ `onApproval(request, signal)` answers the agent's permission prompts on drivers with
170
+ `capabilities.approvals`: `claude`, `codexLive`, `museLive`. It returns `'approve'` or
171
+ `'deny'`.
172
+
173
+ ```ts
174
+ const run = claude().run({
175
+ prompt: 'Run the tests and fix what fails',
176
+ cwd: '/work/repo',
177
+ onApproval: (request, signal) => askUser(request, signal), // your UI
178
+ });
179
+ ```
180
+
181
+ - `request.kind` is `command`, `file-change` or `other`; `summary` is one line to show;
182
+ `detail` is the vendor's whole request (the command with its working directory, the tool
183
+ input, the requested permissions). Show `detail` before asking for a decision.
184
+ - `request.scope` says what approving grants. `once` (or absent): this one call. `turn`: the
185
+ permissions in `detail` until the agent's current turn ends (Codex permission profiles).
186
+ - `signal` aborts when the answer is no longer needed: the agent withdrew the request, the
187
+ turn ended, the process exited, or the task was stopped. Close the question then. A late
188
+ answer counts as `deny`.
189
+ - No handler, a handler that throws, and an aborted signal all deny. Nothing is approved
190
+ automatically unless `permissions.approval` says so (see [Permissions](#permissions)).
191
+ `approval-request` and `approval-resolved` events record each question.
192
+
193
+ Per agent:
194
+
195
+ - `claude()`: with `onApproval`, the driver serves Claude Code's `--permission-prompt-tool`
196
+ from a private MCP endpoint on 127.0.0.1 (random port, random bearer token), next to the
197
+ task's own `mcpServers`, and raises `MCP_TOOL_TIMEOUT` to a day unless `env` sets it. The
198
+ permission mode still applies first (`acceptEdits` by default): only what it does not allow
199
+ is asked. Approving allows exactly the input Claude asked about (`updatedInput` unchanged).
200
+ - `codexLive()`: runs with approval policy `on-request` when `onApproval` is set (`never`
201
+ otherwise). Commands and file changes are answered `accept` / `decline`. A permission
202
+ profile request (`item/permissions/requestApproval`) is asked with `scope: 'turn'`; approving
203
+ grants the requested categories (those that are not null) for the turn, denying grants none.
204
+ Requests from another thread or turn are rejected; `serverRequest/resolved` withdraws one.
205
+ - `museLive()`: answers with one of the choices Muse offers and the stage's requirement id.
206
+ Approving picks the `once` choice; a request that only offers session-wide approval is
207
+ denied. A multi-stage approval asks once per stage (later stages get ids like `ap-1/2`),
208
+ however often a stage is delivered. `approval/resolved` withdraws an open question.
209
+
210
+ The protocol handlers are exported for apps that run their own driver or MCP server:
211
+
212
+ - `codexApprovals(session, ids)` and `museApprovals(session, ids, options?)` take a
213
+ `LiveSession` and a function returning the current `{ session, turn }` ids. Hand them each
214
+ request and notification first (`request()` returns `undefined`, `notification()` false,
215
+ for methods they do not own) and call `close()` when the turn ends.
216
+ - `claudeApprovalTool(onApproval)` is the permission prompt tool as an MCP tool (`name`,
217
+ `description`, `inputSchema`, `call(args, signal)`) to serve from the app's own MCP server;
218
+ pass `claudeApprovalArgs(serverName)` to Claude and `claudeApprovalEnv(env)` in its env.
219
+ Abort `signal` when the MCP caller disconnects. `startClaudeApprovalServer(onApproval)`
220
+ serves the tool on its own endpoint instead.
221
+
222
+ ## Permissions
223
+
224
+ `task.permissions` picks the approval policy and the sandbox in one place, and each driver
225
+ translates it into the agent's own options. An omitted field keeps the driver's default (the
226
+ behavior described above); `'yolo'` is `{ approval: 'auto-approve', sandbox: 'unrestricted' }`.
227
+
228
+ ```ts
229
+ claude().run({ prompt, cwd, permissions: { approval: 'auto-approve', sandbox: 'workspace-write' } });
230
+ codexLive().run({ prompt, cwd, permissions: 'yolo' });
231
+ ```
232
+
233
+ - `approval`: `ask` sends prompts to `onApproval` (required then). `auto-approve` approves each
234
+ prompt without asking, for exactly the scope the agent asked for (one call, or a Codex
235
+ profile for the turn; never a session-wide grant). `deny` refuses whatever would need a
236
+ prompt and does not call `onApproval`.
237
+ - `sandbox`: `workspace-write` turns on the agent's own sandbox (writes limited to `cwd`;
238
+ network rules are the vendor's), `read-only` its read-only mode, `unrestricted` no sandbox,
239
+ even when the agent's settings enable one. `auto-approve` never grants a step outside the
240
+ sandbox. With `ask`, Claude refuses such steps before asking and Codex permission profiles
241
+ (which widen the sandbox) are denied; a Codex command or file-change approval stays the
242
+ person's call, as in Codex itself, so approving it may let that one step leave the sandbox.
243
+ - `capabilities.permissions` lists the values a driver accepts. Anything else, and any
244
+ combination the agent cannot honor, fails the run with `status: 'failed'` and an `error`
245
+ naming the value before the agent starts. Setting both a permissions field and the driver
246
+ option it replaces (`permissionMode`, `sandbox`, `approvalMode`, `force`...) is an error too.
247
+ - Where genaicode sees the prompt (Claude's prompt tool, Muse), `auto-approve` and policy
248
+ denials still emit `approval-request` and `approval-resolved` with `automatic: true`, and
249
+ `createAgentSession` shows them as transcript entries. Agents that approve by themselves
250
+ (Codex with policy `never`, Gemini `yolo`, Cursor `--force`...) report nothing to show.
251
+
252
+ | Driver | approval | sandbox | Translation |
253
+ | --------------- | ----------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
254
+ | `claude()` | ask, auto-approve, deny | workspace-write, read-only, unrestricted | `ask` / `auto-approve`: the prompt tool; `deny`: none. `workspace-write`: Claude's sandbox via `--settings` (required, no per-command escape), `acceptEdits`; `read-only`: `plan`; `unrestricted`: sandbox off |
255
+ | `codex()` | auto-approve, deny | workspace-write, read-only, unrestricted | `approval_policy="never"` (exec never asks); `--sandbox` read-only / workspace-write / danger-full-access |
256
+ | `codexLive()` | ask, auto-approve, deny | workspace-write, read-only, unrestricted | `ask`: policy `on-request`, otherwise `never`; `thread/start` sandbox as above |
257
+ | `museLive()` | ask, auto-approve, deny | unrestricted | `ask` / `auto-approve`: approval mode `onRequest` (the `once` choice); `deny`: `denyUnmatched`. Muse has no sandbox |
258
+ | `gemini()` | auto-approve, deny | workspace-write, read-only, unrestricted | `--approval-mode yolo` / `auto_edit`; `read-only`: `plan` (not with `auto-approve`); `--sandbox` / `--no-sandbox` plus `GEMINI_SANDBOX`, which overrides the flag in Gemini |
259
+ | `cursor()` | auto-approve, deny | workspace-write, read-only, unrestricted | `auto-approve`: `--force`, which runs commands unsandboxed, so only with `unrestricted`; `deny`: `--trust`; `--sandbox enabled` / `disabled`; `read-only`: `--mode ask` |
260
+ | `copilot()` | auto-approve | unrestricted | `--allow-all-tools` (prompt mode needs it); `--allow-all-paths --allow-all-urls`. Copilot's `--sandbox` lets a command opt out of it, so `workspace-write` is not offered |
261
+ | `opencode()` | auto-approve, deny | unrestricted | `--auto`; opencode has no sandbox |
262
+ | `vibe()` | auto-approve, deny | read-only, unrestricted | `--auto-approve`; `read-only`: `--agent plan` (not with `auto-approve`); no sandbox |
263
+ | `antigravity()` | none | workspace-write, unrestricted | `--sandbox` on or off |
264
+ | `muse()` | none | none | |
265
+
266
+ Claude in `read-only` writes nothing in the workspace, but plan mode may still save its plan
267
+ under `~/.claude/plans`. In `workspace-write`, Claude's sandbox covers Bash; edits through its
268
+ file tools are accepted inside `cwd` and denied outside it.
269
+
270
+ For apps that keep their own argument lists (an adapters file, say),
271
+ `applyPermissionArgs(agent, args, permissions)` returns `{ args, env }` with the flags the
272
+ translation owns replaced, using the same per-agent functions (`claudePermissionFlags`,
273
+ `codexPermissionFlags`, `geminiPermissionFlags`, `cursorPermissionFlags`,
274
+ `copilotPermissionFlags`, `opencodePermissionFlags`, `vibePermissionFlags`,
275
+ `antigravityPermissionFlags`; `codexThreadPolicy` for the app server). For Claude, `ask` and
276
+ `auto-approve` also need the prompt tool: `claudeApprovalTool(handler, { sandbox, cwd })`
277
+ denies requests outside the sandbox before asking, and `decideApproval(task, request, signal)`
278
+ applies the approval policy the way the drivers do.
279
+
280
+ ## Custom live agents
281
+
172
282
  For other JSON-RPC agents, `liveAgent({ name, command, args, drive })` provides the process,
173
283
  an `RpcPeer`, event emission, the approval flow, and `setSteer()`. `drive(session)` runs the
174
284
  protocol and resolves with `{ ok, error? }` when the turn ends.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genaicode",
3
- "version": "2.11.0",
3
+ "version": "2.13.2",
4
4
  "description": "A small, provider-neutral TypeScript toolkit for calling LLMs from backend code.",
5
5
  "author": "Grzegorz Tańczyk",
6
6
  "repository": {
@@ -86,8 +86,8 @@
86
86
  "@types/node": "^20.0.0",
87
87
  "@types/react": "^19.3.0",
88
88
  "@types/react-dom": "^19.3.0",
89
- "@typescript-eslint/eslint-plugin": "^7.17.0",
90
- "@typescript-eslint/parser": "^7.17.0",
89
+ "@typescript-eslint/eslint-plugin": "^8.71.1",
90
+ "@typescript-eslint/parser": "^8.71.1",
91
91
  "esbuild": "^0.28.2",
92
92
  "eslint": "^8.54.0",
93
93
  "eslint-config-prettier": "^9.0.0",
@@ -95,14 +95,14 @@
95
95
  "husky": "^9.1.1",
96
96
  "ink": "^6.8.0",
97
97
  "ink-testing-library": "^4.0.0",
98
- "lint-staged": "^15.2.7",
98
+ "lint-staged": "^16.4.0",
99
99
  "playwright": "^1.56.1",
100
100
  "prettier": "^3.1.0",
101
101
  "react": "^19.3.0",
102
102
  "react-dom": "^19.3.0",
103
103
  "typescript": "^5.0.0",
104
104
  "vite": "^6.4.3",
105
- "vitest": "^3.0.7"
105
+ "vitest": "^4.1.11"
106
106
  },
107
107
  "lint-staged": {
108
108
  "*.{js,ts,md}": "prettier --write"