@alpacakit/agents 0.1.0-beta.39 → 0.2.0-beta.3
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.
- package/README.md +142 -1
- package/dist/agents/builtin.d.ts +2 -2
- package/dist/agents/builtin.d.ts.map +1 -1
- package/dist/agents/builtin.js +6 -4
- package/dist/agents/claude/cli.d.ts +133 -0
- package/dist/agents/claude/cli.d.ts.map +1 -0
- package/dist/agents/claude/cli.js +182 -0
- package/dist/agents/claude/host.d.ts +14 -0
- package/dist/agents/claude/host.d.ts.map +1 -0
- package/dist/agents/claude/host.js +319 -0
- package/dist/agents/{claude.d.ts → claude/index.d.ts} +11 -11
- package/dist/agents/claude/index.d.ts.map +1 -0
- package/dist/agents/claude/index.js +134 -0
- package/dist/agents/claude/session.d.ts +25 -0
- package/dist/agents/claude/session.d.ts.map +1 -0
- package/dist/agents/claude/session.js +321 -0
- package/dist/agents/codex/cli.d.ts +132 -0
- package/dist/agents/codex/cli.d.ts.map +1 -0
- package/dist/agents/codex/cli.js +110 -0
- package/dist/agents/codex/host.d.ts +14 -0
- package/dist/agents/codex/host.d.ts.map +1 -0
- package/dist/agents/codex/host.js +221 -0
- package/dist/agents/codex/index.d.ts +14 -0
- package/dist/agents/codex/index.d.ts.map +1 -0
- package/dist/agents/codex/index.js +127 -0
- package/dist/agents/codex/session.d.ts +21 -0
- package/dist/agents/codex/session.d.ts.map +1 -0
- package/dist/agents/codex/session.js +390 -0
- package/dist/agents/openai-compatible/fetch-engine.d.ts.map +1 -1
- package/dist/agents/openai-compatible/fetch-engine.js +3 -2
- package/dist/agents/openai-compatible/pi/engine.js +1 -1
- package/dist/agents/openai-compatible/pi/{session.d.ts → run.d.ts} +1 -1
- package/dist/agents/openai-compatible/pi/run.d.ts.map +1 -0
- package/dist/agents/openai-compatible/pi/sandbox.d.ts.map +1 -1
- package/dist/auth/login-probe.d.ts +6 -4
- package/dist/auth/login-probe.d.ts.map +1 -1
- package/dist/auth/login-probe.js +19 -13
- package/dist/auth/material.d.ts +1 -1
- package/dist/auth/material.d.ts.map +1 -1
- package/dist/codex/app-server.d.ts +50 -1
- package/dist/codex/app-server.d.ts.map +1 -1
- package/dist/codex/app-server.js +140 -66
- package/dist/codex/index.d.ts +3 -2
- package/dist/codex/index.d.ts.map +1 -1
- package/dist/codex/index.js +2 -1
- package/dist/codex/protocol.d.ts +101 -0
- package/dist/codex/protocol.d.ts.map +1 -1
- package/dist/codex/protocol.js +78 -0
- package/dist/config/agent-config-validation.d.ts +1 -1
- package/dist/config/agent-config-validation.d.ts.map +1 -1
- package/dist/config/agent-configs.d.ts.map +1 -1
- package/dist/config/agent-configs.js +3 -3
- package/dist/config/compose.d.ts.map +1 -1
- package/dist/config/config.d.ts +1 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/model.d.ts +0 -1
- package/dist/config/model.d.ts.map +1 -1
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +1 -1
- package/dist/config/store.d.ts.map +1 -1
- package/dist/config/store.js +6 -24
- package/dist/config/support.d.ts +0 -1
- package/dist/config/support.d.ts.map +1 -1
- package/dist/config/support.js +0 -9
- package/dist/core/cli-child.d.ts +56 -0
- package/dist/core/cli-child.d.ts.map +1 -0
- package/dist/core/cli-child.js +105 -0
- package/dist/core/fs.d.ts +1 -1
- package/dist/core/fs.d.ts.map +1 -1
- package/dist/core/fs.js +10 -2
- package/dist/core/node-ports.d.ts.map +1 -1
- package/dist/core/node-ports.js +1 -5
- package/dist/core/session.d.ts +104 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +29 -0
- package/dist/fleet/store.d.ts.map +1 -1
- package/dist/fleet/store.js +4 -3
- package/dist/host/availability.d.ts +2 -1
- package/dist/host/availability.d.ts.map +1 -1
- package/dist/host/github-dir.d.ts.map +1 -1
- package/dist/host/github-dir.js +2 -1
- package/dist/host/mcp-list.d.ts.map +1 -1
- package/dist/host/mcp-list.js +5 -6
- package/dist/host/run-command.d.ts +2 -1
- package/dist/host/run-command.d.ts.map +1 -1
- package/dist/host/run-command.js +10 -19
- package/dist/host/session-files.d.ts +23 -0
- package/dist/host/session-files.d.ts.map +1 -0
- package/dist/host/session-files.js +92 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/internal/controlled-process/supervisor-runtime.js +27 -1
- package/dist/kernel/classify.d.ts +1 -2
- package/dist/kernel/classify.d.ts.map +1 -1
- package/dist/kernel/classify.js +1 -1
- package/dist/kernel/cli-agent.d.ts.map +1 -1
- package/dist/kernel/cli-agent.js +26 -85
- package/dist/kernel/cli-login.d.ts.map +1 -1
- package/dist/kernel/cli-login.js +9 -30
- package/dist/kernel/definition.d.ts +11 -2
- package/dist/kernel/definition.d.ts.map +1 -1
- package/dist/kernel/facets.d.ts +38 -1
- package/dist/kernel/facets.d.ts.map +1 -1
- package/dist/kernel/facets.js +20 -0
- package/dist/kernel/login.d.ts.map +1 -1
- package/dist/kernel/login.js +2 -1
- package/dist/kernel/options.d.ts +1 -1
- package/dist/kernel/options.d.ts.map +1 -1
- package/dist/kernel/run.d.ts.map +1 -1
- package/dist/kernel/run.js +2 -1
- package/dist/kernel/runtime.d.ts +10 -6
- package/dist/kernel/runtime.d.ts.map +1 -1
- package/dist/kernel/runtime.js +4 -1
- package/dist/kernel/session.d.ts +104 -0
- package/dist/kernel/session.d.ts.map +1 -0
- package/dist/kernel/session.js +314 -0
- package/dist/testing/fake-exec.d.ts +10 -5
- package/dist/testing/fake-exec.d.ts.map +1 -1
- package/dist/testing/fake-exec.js +17 -2
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -1
- package/package.json +2 -2
- package/dist/agents/claude.d.ts.map +0 -1
- package/dist/agents/claude.js +0 -543
- package/dist/agents/codex.d.ts +0 -19
- package/dist/agents/codex.d.ts.map +0 -1
- package/dist/agents/codex.js +0 -377
- package/dist/agents/openai-compatible/pi/session.d.ts.map +0 -1
- /package/dist/agents/openai-compatible/pi/{session.js → run.js} +0 -0
package/README.md
CHANGED
|
@@ -150,6 +150,109 @@ Each recovery call performs one authenticated termination convergence. A
|
|
|
150
150
|
typed `pending` result invokes no lifecycle callback; the host owns the
|
|
151
151
|
cancellable retry cadence and calls `recover` again when appropriate.
|
|
152
152
|
|
|
153
|
+
## Sessions: hold a conversation and talk to it (`agent.session`)
|
|
154
|
+
|
|
155
|
+
`run()` is one prompt, one process, one answer. A **Session** is the other
|
|
156
|
+
shape a host offers: one Claude (`claude -p --input-format stream-json`) or
|
|
157
|
+
Codex (`codex app-server` thread) process held open across turns, which a
|
|
158
|
+
UI or an orchestrator keeps talking to. `agent.session` is `null` when the
|
|
159
|
+
definition has no session facet; `claude()` and `codex()` provide one.
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
const runtime = createAgentRuntime({ agents: [claude(), codex()], baseEnv: processEnv() });
|
|
163
|
+
const sessions = runtime.agent("codex").session!;
|
|
164
|
+
|
|
165
|
+
const session = await sessions.open({
|
|
166
|
+
workspace: "/work/repo",
|
|
167
|
+
permissions: {
|
|
168
|
+
approvalPolicy: "on-request",
|
|
169
|
+
approvalsReviewer: "user",
|
|
170
|
+
sandbox: { type: "read-only" },
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
void (async () => {
|
|
174
|
+
for await (const event of session.events) {
|
|
175
|
+
// turn_started / message / tool / approval_requested / turn_ended / exited
|
|
176
|
+
if (event.type === "approval_requested") await session.respond(event.requestId, "accept");
|
|
177
|
+
}
|
|
178
|
+
})();
|
|
179
|
+
const turn = await session.send("Summarize the failing tests."); // { turnId, outcome, text }
|
|
180
|
+
await session.steer("Also list the flaky ones."); // into the running turn
|
|
181
|
+
await session.interrupt(); // turn ends with outcome "interrupted"
|
|
182
|
+
await session.close(); // EOF, then signals; releases the host's lock
|
|
183
|
+
|
|
184
|
+
const facts = await sessions.inspect(session.id, { homeDir }); // { workspace, lastPermissions, owner, archived } | null
|
|
185
|
+
const again = await sessions.resume(session.id, { workspace: facts!.workspace, permissions: facts!.lastPermissions! });
|
|
186
|
+
// An archived Codex thread resumes only with `unarchive: true` (see below).
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`send()` starts one turn and resolves when the host ends it; exactly one
|
|
190
|
+
turn runs at a time (`send` needs idle — including while a Codex
|
|
191
|
+
`turn/start` is still unanswered — and `steer` / `interrupt` need a running
|
|
192
|
+
turn; anything else is a typed `invalid_input`). `Session.id` is the host's
|
|
193
|
+
own conversation id (Claude `session_id`, Codex thread id), so it is what
|
|
194
|
+
the host's files, `--resume`, and `thread/resume` know.
|
|
195
|
+
|
|
196
|
+
`approval_requested.decisions` is always `["accept", "decline"]`: Claude's
|
|
197
|
+
`can_use_tool` takes allow or deny, and Codex takes `decline` for every
|
|
198
|
+
request even when its own `availableDecisions` lists only `accept` plus
|
|
199
|
+
amendment / `cancel` variants. Requests belong to the turn that raised
|
|
200
|
+
them — once the turn ends, `respond` for them is an `invalid_input`; after
|
|
201
|
+
the session ended it is "session is closed" for both hosts.
|
|
202
|
+
|
|
203
|
+
Permissions are **per host**, never the neutral `Sandbox` of `run()`:
|
|
204
|
+
`ClaudeSessionPermissions { mode }` (spelled as the transcript's
|
|
205
|
+
`permissionMode`; the CLI flag spells `default` as `manual`, and
|
|
206
|
+
`bypassPermissions` also passes `--allow-dangerously-skip-permissions`;
|
|
207
|
+
every Claude session passes `--permission-prompt-tool stdio` so approval
|
|
208
|
+
prompts reach `events` instead of being auto-denied) and `CodexSessionPermissions
|
|
209
|
+
{ approvalPolicy, approvalsReviewer, sandbox }` with `sandbox` being
|
|
210
|
+
`read-only`, `danger-full-access`, or `workspace-write { writableRoots,
|
|
211
|
+
networkAccess, excludeTmpdirEnvVar, excludeSlashTmp }` (sent as config.toml
|
|
212
|
+
overrides on `thread/start` / `thread/resume`). `resume` always passes them
|
|
213
|
+
explicitly: a Codex `thread/resume` without `sandbox` ran as
|
|
214
|
+
danger-full-access in the lab.
|
|
215
|
+
|
|
216
|
+
Facts hosts write that `inspect` reads (through `HostLocation.homeDir`, never
|
|
217
|
+
`os.homedir()`): Claude `~/.claude/projects/*/<id>.jsonl` (first `cwd`, last
|
|
218
|
+
`permissionMode`) and `~/.claude/sessions/<pid>.json` (`owner.pid`,
|
|
219
|
+
`owner.entrypoint`); Codex `~/.codex/sessions/YYYY/MM/DD/rollout-*-<id>.jsonl`
|
|
220
|
+
or `archived_sessions/` (`archived`), `session_meta.cwd`, last
|
|
221
|
+
`turn_context`, and `thread-writer-locks/<id>.lock` (`owner` with `pid: null`
|
|
222
|
+
— the lock does not say who). `inspect` reports what is recorded; it does not
|
|
223
|
+
probe whether a recorded pid is alive.
|
|
224
|
+
|
|
225
|
+
**Codex trust note.** `open()` with a writable sandbox (`workspace-write`,
|
|
226
|
+
`danger-full-access`) makes Codex append a `trust_level` entry for the
|
|
227
|
+
workspace to `~/.codex/config.toml` (observed with codex 0.153.4);
|
|
228
|
+
`read-only` does not. Surface that before offering a writable `open()`.
|
|
229
|
+
Whether `resume()` with a writable sandbox appends the same entry is
|
|
230
|
+
**unverified** (the lab only resumed with `read-only`).
|
|
231
|
+
|
|
232
|
+
**Codex archive note.** `resume()` of an archived thread fails by default
|
|
233
|
+
with the server's "is archived" message (`inspect(id).archived` tells you
|
|
234
|
+
beforehand). Pass `unarchive: true` to `thread/unarchive` it first — that
|
|
235
|
+
also moves the thread back into the ChatGPT app's active list, which is
|
|
236
|
+
why it is opt-in. Claude has no archive; the option is ignored there.
|
|
237
|
+
|
|
238
|
+
Design conditions this facet keeps (T60 v3):
|
|
239
|
+
|
|
240
|
+
- C1 — permissions are host-typed; the neutral `Sandbox` never learns `workspace-write`.
|
|
241
|
+
- C2 — a Session holds a plain `Exec` child with `keepStdinOpen`; it does not go through `ControlledExec`. If the embedding process restarts, `resume` is the recovery path.
|
|
242
|
+
- C3 — the app-server client never kills the process on a request timeout; only that request fails. `close()` is the one place the process is ended.
|
|
243
|
+
- C4 — every host-file read goes through `HostLocation.homeDir`.
|
|
244
|
+
- C5 — Claude approvals were verified in the lab (`--permission-prompt-tool stdio` → `control_request` / `can_use_tool` → `control_response` allow/deny), so `respond` is supported for both hosts.
|
|
245
|
+
- C6 — consumers pin an exact version of this package and upgrade libs first, then the consumer, when a host CLI changes its protocol.
|
|
246
|
+
|
|
247
|
+
Not supported (by choice, or unverified):
|
|
248
|
+
|
|
249
|
+
- Claude control requests other than `can_use_tool` are ignored (logged) — if the CLI ever waits on one, that turn hangs until `interrupt()`; Codex server requests other than `item/commandExecution/requestApproval` and `item/fileChange/requestApproval` are refused with JSON-RPC -32601 so a turn never hangs on them. Neither case has been observed in the lab.
|
|
250
|
+
- Claude's stream carries no turn id, so a `steer()` that lands after the host has already ended the turn is taken by the CLI as the next turn's prompt; the following `send()` then resolves with that orphan turn's result. Steer only while a `tool` event has shown the turn is still working.
|
|
251
|
+
- Decisions are `accept` / `decline` only — no `acceptForSession`, execpolicy amendments, or `cancel`; Codex `approvalPolicy` is `untrusted` / `on-request` / `never` (the granular object form and `externalSandbox` decode to `lastPermissions: null` in `inspect`).
|
|
252
|
+
- No per-turn limits or guards on a Session; use `interrupt()`. `open()` takes no `AbortSignal`; use `close()`.
|
|
253
|
+
- `claude({ customizations: "disabled" })` sessions pass `--safe-mode --strict-mcp-config` but keep session persistence (a Session is the recorded conversation).
|
|
254
|
+
- The Claude child needs `USER` in `baseEnv` (keychain lookup); with only `PATH` / `HOME` the CLI reports "Not logged in".
|
|
255
|
+
|
|
153
256
|
## Structured output
|
|
154
257
|
|
|
155
258
|
Any Standard Schema validator (zod v4 etc.) works. Repair happens within
|
|
@@ -303,7 +406,45 @@ installed skills and MCP servers remains in progress.
|
|
|
303
406
|
| `/config/xdg` | XDG Base Directory config-root preset (general apps) |
|
|
304
407
|
| `/config/extension` | custom agent-config kinds (`defineAgentConfigType`) |
|
|
305
408
|
| `/testing` | `fakeExec`, `fakeClock`, `fakeAgent`, `fakeSecretResolver` — no subprocess ever spawns |
|
|
306
|
-
| `/codex` | codex app-server JSON-RPC client (advanced) |
|
|
409
|
+
| `/codex` | codex app-server JSON-RPC client: typed requests, `incoming` notifications / server requests, `respond` (advanced) |
|
|
410
|
+
|
|
411
|
+
## Changes in 0.2.0-beta.3
|
|
412
|
+
|
|
413
|
+
- `run()` with `sandbox: { mode: "read-only" }` passes
|
|
414
|
+
`--permission-mode manual` to claude (was `default`), and `run()` with
|
|
415
|
+
`mode: "full"` passes `--allow-dangerously-skip-permissions` next to
|
|
416
|
+
`bypassPermissions`, as sessions already did. One function
|
|
417
|
+
(`permissionModeArgs`) now decides how a mode reaches the CLI for run and
|
|
418
|
+
session alike; `manual` is the spelling `claude --help` (2.1.270) lists —
|
|
419
|
+
`default` is not among its choices — and the allow flag is what makes
|
|
420
|
+
`bypassPermissions` an option at all.
|
|
421
|
+
- `agent.auth.check` for a home-dir material answers `unknown` when the
|
|
422
|
+
probe cannot start (no binary on PATH, spawn fault) instead of throwing —
|
|
423
|
+
the same policy the availability probe already had.
|
|
424
|
+
- Internal structure (no API change): the facts of a CLI child process
|
|
425
|
+
(PATH resolution, output tails, redacted failure evidence, signal
|
|
426
|
+
escalation) live once in `core/cli-child.ts`; each built-in host spells
|
|
427
|
+
its vocabulary once in `agents/<host>/cli.ts`; the kernel drives every
|
|
428
|
+
Session (`kernel/session.ts`) and the host adapters only encode and
|
|
429
|
+
decode. `SessionEvent.turnId` is the host's turn id when it has one
|
|
430
|
+
(Codex) and a per-session counter otherwise (Claude).
|
|
431
|
+
|
|
432
|
+
## Breaking changes in 0.2.0
|
|
433
|
+
|
|
434
|
+
- `Agent.session` (and `AgentDefinition.session`) are new; `AgentDefinition`
|
|
435
|
+
and `Agent` gained a session-permissions type parameter, and `AgentRuntime`
|
|
436
|
+
a second parameter for the definition list so `runtime.agent(id).session`
|
|
437
|
+
is typed per agent (defaults keep existing annotations compiling).
|
|
438
|
+
`claude()` / `codex()` return definitions typed with their permission
|
|
439
|
+
shapes.
|
|
440
|
+
- `@alpacakit/agents/codex`: `CodexAppServer` gained `incoming`, `respond`,
|
|
441
|
+
`exit`, and `stderrTail`; a request timeout no longer kills the server
|
|
442
|
+
process; `close()` ends stdin and waits for the child to exit, escalating
|
|
443
|
+
to SIGTERM after 5 s and SIGKILL after another 5 s. Host-plane calls
|
|
444
|
+
(`agent.skills.list`, `agent.mcp.list` for codex) therefore take up to
|
|
445
|
+
10 s longer than before when the server hangs, instead of being killed at
|
|
446
|
+
once. `thread/*` and `turn/*` methods are registered.
|
|
447
|
+
- `run()` behavior is unchanged.
|
|
307
448
|
|
|
308
449
|
## Status
|
|
309
450
|
|
package/dist/agents/builtin.d.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* the config layer reuses `BUILTIN_AGENT_ID` for its agent-config kinds —
|
|
5
5
|
* so "codex"/"claude" is spelled once, not once per layer.
|
|
6
6
|
*/
|
|
7
|
-
import { claude } from "./claude.js";
|
|
8
|
-
import { codex } from "./codex.js";
|
|
7
|
+
import { claude } from "./claude/index.js";
|
|
8
|
+
import { codex } from "./codex/index.js";
|
|
9
9
|
export declare const BUILTIN_AGENT_ID: {
|
|
10
10
|
readonly codex: "codex";
|
|
11
11
|
readonly claude: "claude";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin.d.ts","sourceRoot":"","sources":["../../src/agents/builtin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"builtin.d.ts","sourceRoot":"","sources":["../../src/agents/builtin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,eAAO,MAAM,gBAAgB;;;CAGnB,CAAC;AAEX,MAAM,MAAM,cAAc,GACxB,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,OAAO,gBAAgB,CAAC,CAAC;AAE3D,wEAAwE;AACxE,eAAO,MAAM,qBAAqB;;;CAA6B,CAAC"}
|
package/dist/agents/builtin.js
CHANGED
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
* the config layer reuses `BUILTIN_AGENT_ID` for its agent-config kinds —
|
|
5
5
|
* so "codex"/"claude" is spelled once, not once per layer.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { CLAUDE } from "./claude/cli.js";
|
|
8
|
+
import { claude } from "./claude/index.js";
|
|
9
|
+
import { CODEX } from "./codex/cli.js";
|
|
10
|
+
import { codex } from "./codex/index.js";
|
|
9
11
|
export const BUILTIN_AGENT_ID = {
|
|
10
|
-
codex:
|
|
11
|
-
claude:
|
|
12
|
+
codex: CODEX.id,
|
|
13
|
+
claude: CLAUDE.id,
|
|
12
14
|
};
|
|
13
15
|
/** Keyed record, not a branch: adding a built-in is adding an entry. */
|
|
14
16
|
export const builtinAgentFactories = { claude, codex };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Claude CLI vocabulary, spelled once: command and flags, the
|
|
3
|
+
* permission-mode words and how the flag spells them, the stream-json
|
|
4
|
+
* record types and fields, and the host's own file names. The run adapter
|
|
5
|
+
* (`index.ts`), the session adapter (`session.ts`), and the host plane
|
|
6
|
+
* (`host.ts`) all read from here and never respell a word.
|
|
7
|
+
*/
|
|
8
|
+
import { type UnknownRecord } from "../../core/json.js";
|
|
9
|
+
import type { AgentEvent } from "../../core/run.js";
|
|
10
|
+
import type { CliResultCapture } from "../../kernel/cli-agent.js";
|
|
11
|
+
export declare const CLAUDE_CONFIG_DIR_ENV_VAR = "CLAUDE_CONFIG_DIR";
|
|
12
|
+
export declare const CLAUDE_API_KEY_ENV_VAR = "ANTHROPIC_API_KEY";
|
|
13
|
+
/** Spelled as the transcript's `permissionMode` records it. */
|
|
14
|
+
export declare const CLAUDE_PERMISSION_MODE: {
|
|
15
|
+
readonly default: "default";
|
|
16
|
+
readonly acceptEdits: "acceptEdits";
|
|
17
|
+
readonly auto: "auto";
|
|
18
|
+
readonly bypassPermissions: "bypassPermissions";
|
|
19
|
+
readonly dontAsk: "dontAsk";
|
|
20
|
+
readonly plan: "plan";
|
|
21
|
+
};
|
|
22
|
+
export type ClaudePermissionMode = (typeof CLAUDE_PERMISSION_MODE)[keyof typeof CLAUDE_PERMISSION_MODE];
|
|
23
|
+
export type ClaudeSessionPermissions = {
|
|
24
|
+
readonly mode: ClaudePermissionMode;
|
|
25
|
+
};
|
|
26
|
+
export declare const CLAUDE: {
|
|
27
|
+
readonly id: "claude";
|
|
28
|
+
readonly command: "claude";
|
|
29
|
+
readonly cli: {
|
|
30
|
+
readonly prompt: "-p";
|
|
31
|
+
readonly model: "--model";
|
|
32
|
+
readonly effort: "--effort";
|
|
33
|
+
readonly outputFormat: "--output-format";
|
|
34
|
+
readonly inputFormat: "--input-format";
|
|
35
|
+
readonly streamJson: "stream-json";
|
|
36
|
+
readonly permissionMode: "--permission-mode";
|
|
37
|
+
/** The flag spells the transcript's `default` mode `manual` (claude 2.1.270 `--help`). */
|
|
38
|
+
readonly manualPermissionMode: "manual";
|
|
39
|
+
readonly allowDangerouslySkipPermissions: "--allow-dangerously-skip-permissions";
|
|
40
|
+
readonly permissionPromptTool: "--permission-prompt-tool";
|
|
41
|
+
readonly stdio: "stdio";
|
|
42
|
+
readonly resume: "--resume";
|
|
43
|
+
readonly sessionId: "--session-id";
|
|
44
|
+
readonly verbose: "--verbose";
|
|
45
|
+
readonly tools: "--tools";
|
|
46
|
+
readonly allowedTools: "--allowedTools";
|
|
47
|
+
readonly safeMode: "--safe-mode";
|
|
48
|
+
readonly strictMcpConfig: "--strict-mcp-config";
|
|
49
|
+
readonly noSessionPersistence: "--no-session-persistence";
|
|
50
|
+
};
|
|
51
|
+
readonly auth: {
|
|
52
|
+
readonly statusArgs: readonly ["auth", "status", "--json"];
|
|
53
|
+
readonly loginArgs: readonly ["auth", "login", "--claudeai"];
|
|
54
|
+
};
|
|
55
|
+
readonly mcp: {
|
|
56
|
+
readonly addJson: "add-json";
|
|
57
|
+
readonly mcp: "mcp";
|
|
58
|
+
readonly remove: "remove";
|
|
59
|
+
readonly scope: "--scope";
|
|
60
|
+
};
|
|
61
|
+
readonly plugin: {
|
|
62
|
+
readonly plugin: "plugin";
|
|
63
|
+
readonly install: "install";
|
|
64
|
+
};
|
|
65
|
+
readonly json: {
|
|
66
|
+
readonly field: {
|
|
67
|
+
readonly type: "type";
|
|
68
|
+
readonly message: "message";
|
|
69
|
+
readonly role: "role";
|
|
70
|
+
readonly content: "content";
|
|
71
|
+
readonly text: "text";
|
|
72
|
+
readonly name: "name";
|
|
73
|
+
readonly usage: "usage";
|
|
74
|
+
readonly result: "result";
|
|
75
|
+
readonly inputTokens: "input_tokens";
|
|
76
|
+
readonly outputTokens: "output_tokens";
|
|
77
|
+
readonly totalCost: "total_cost_usd";
|
|
78
|
+
readonly request: "request";
|
|
79
|
+
readonly requestId: "request_id";
|
|
80
|
+
readonly response: "response";
|
|
81
|
+
readonly subtype: "subtype";
|
|
82
|
+
readonly error: "error";
|
|
83
|
+
readonly toolName: "tool_name";
|
|
84
|
+
readonly description: "description";
|
|
85
|
+
readonly input: "input";
|
|
86
|
+
readonly isError: "is_error";
|
|
87
|
+
readonly behavior: "behavior";
|
|
88
|
+
readonly updatedInput: "updatedInput";
|
|
89
|
+
};
|
|
90
|
+
readonly type: {
|
|
91
|
+
readonly user: "user";
|
|
92
|
+
readonly assistant: "assistant";
|
|
93
|
+
readonly result: "result";
|
|
94
|
+
readonly text: "text";
|
|
95
|
+
readonly toolUse: "tool_use";
|
|
96
|
+
readonly controlRequest: "control_request";
|
|
97
|
+
readonly controlResponse: "control_response";
|
|
98
|
+
};
|
|
99
|
+
readonly subtype: {
|
|
100
|
+
readonly interrupt: "interrupt";
|
|
101
|
+
readonly canUseTool: "can_use_tool";
|
|
102
|
+
readonly success: "success";
|
|
103
|
+
readonly error: "error";
|
|
104
|
+
};
|
|
105
|
+
readonly behavior: {
|
|
106
|
+
readonly allow: "allow";
|
|
107
|
+
readonly deny: "deny";
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
readonly files: {
|
|
111
|
+
readonly root: ".claude";
|
|
112
|
+
readonly projects: "projects";
|
|
113
|
+
readonly sessions: "sessions";
|
|
114
|
+
readonly transcriptExtension: ".jsonl";
|
|
115
|
+
readonly registryExtension: ".json";
|
|
116
|
+
readonly cwd: "cwd";
|
|
117
|
+
readonly permissionMode: "permissionMode";
|
|
118
|
+
readonly sessionId: "sessionId";
|
|
119
|
+
readonly pid: "pid";
|
|
120
|
+
readonly entrypoint: "entrypoint";
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* The one rule for how a permission mode reaches the CLI: the flag spells
|
|
125
|
+
* `default` as `manual`, and `bypassPermissions` is only an option once
|
|
126
|
+
* `--allow-dangerously-skip-permissions` enables it (`claude --help`).
|
|
127
|
+
*/
|
|
128
|
+
export declare function permissionModeArgs(mode: ClaudePermissionMode): string[];
|
|
129
|
+
export declare function parseClaudeLine(line: string): AgentEvent[];
|
|
130
|
+
/** Events carried by one already-parsed stream-json record (`assistant` only). */
|
|
131
|
+
export declare function parseClaudeRecord(record: UnknownRecord): AgentEvent[];
|
|
132
|
+
export declare function parseClaudeResult(line: string): CliResultCapture | null;
|
|
133
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/agents/claude/cli.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAML,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,mBAAmB,CAAC;AAE9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAC7D,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D,+DAA+D;AAC/D,eAAO,MAAM,sBAAsB;;;;;;;CAOzB,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAC9B,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,OAAO,sBAAsB,CAAC,CAAC;AAEvE,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,MAAM;;;;;;;;;;;QAWf,0FAA0F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkFpF,CAAC;AAEX;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAUvE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAG1D;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,EAAE,CAgCrE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAkBvE"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Claude CLI vocabulary, spelled once: command and flags, the
|
|
3
|
+
* permission-mode words and how the flag spells them, the stream-json
|
|
4
|
+
* record types and fields, and the host's own file names. The run adapter
|
|
5
|
+
* (`index.ts`), the session adapter (`session.ts`), and the host plane
|
|
6
|
+
* (`host.ts`) all read from here and never respell a word.
|
|
7
|
+
*/
|
|
8
|
+
import { readJsonRecord, readNumber, readRecord, readString, readUnknownRecord, } from "../../core/json.js";
|
|
9
|
+
import { AGENT_EVENT_TYPE } from "../../core/run.js";
|
|
10
|
+
export const CLAUDE_CONFIG_DIR_ENV_VAR = "CLAUDE_CONFIG_DIR";
|
|
11
|
+
export const CLAUDE_API_KEY_ENV_VAR = "ANTHROPIC_API_KEY";
|
|
12
|
+
/** Spelled as the transcript's `permissionMode` records it. */
|
|
13
|
+
export const CLAUDE_PERMISSION_MODE = {
|
|
14
|
+
default: "default",
|
|
15
|
+
acceptEdits: "acceptEdits",
|
|
16
|
+
auto: "auto",
|
|
17
|
+
bypassPermissions: "bypassPermissions",
|
|
18
|
+
dontAsk: "dontAsk",
|
|
19
|
+
plan: "plan",
|
|
20
|
+
};
|
|
21
|
+
export const CLAUDE = {
|
|
22
|
+
id: "claude",
|
|
23
|
+
command: "claude",
|
|
24
|
+
cli: {
|
|
25
|
+
prompt: "-p",
|
|
26
|
+
model: "--model",
|
|
27
|
+
effort: "--effort",
|
|
28
|
+
outputFormat: "--output-format",
|
|
29
|
+
inputFormat: "--input-format",
|
|
30
|
+
streamJson: "stream-json",
|
|
31
|
+
permissionMode: "--permission-mode",
|
|
32
|
+
/** The flag spells the transcript's `default` mode `manual` (claude 2.1.270 `--help`). */
|
|
33
|
+
manualPermissionMode: "manual",
|
|
34
|
+
allowDangerouslySkipPermissions: "--allow-dangerously-skip-permissions",
|
|
35
|
+
permissionPromptTool: "--permission-prompt-tool",
|
|
36
|
+
stdio: "stdio",
|
|
37
|
+
resume: "--resume",
|
|
38
|
+
sessionId: "--session-id",
|
|
39
|
+
verbose: "--verbose",
|
|
40
|
+
tools: "--tools",
|
|
41
|
+
allowedTools: "--allowedTools",
|
|
42
|
+
safeMode: "--safe-mode",
|
|
43
|
+
strictMcpConfig: "--strict-mcp-config",
|
|
44
|
+
noSessionPersistence: "--no-session-persistence",
|
|
45
|
+
},
|
|
46
|
+
auth: {
|
|
47
|
+
statusArgs: ["auth", "status", "--json"],
|
|
48
|
+
loginArgs: ["auth", "login", "--claudeai"],
|
|
49
|
+
},
|
|
50
|
+
mcp: {
|
|
51
|
+
addJson: "add-json",
|
|
52
|
+
mcp: "mcp",
|
|
53
|
+
remove: "remove",
|
|
54
|
+
scope: "--scope",
|
|
55
|
+
},
|
|
56
|
+
plugin: {
|
|
57
|
+
plugin: "plugin",
|
|
58
|
+
install: "install",
|
|
59
|
+
},
|
|
60
|
+
json: {
|
|
61
|
+
field: {
|
|
62
|
+
type: "type",
|
|
63
|
+
message: "message",
|
|
64
|
+
role: "role",
|
|
65
|
+
content: "content",
|
|
66
|
+
text: "text",
|
|
67
|
+
name: "name",
|
|
68
|
+
usage: "usage",
|
|
69
|
+
result: "result",
|
|
70
|
+
inputTokens: "input_tokens",
|
|
71
|
+
outputTokens: "output_tokens",
|
|
72
|
+
totalCost: "total_cost_usd",
|
|
73
|
+
request: "request",
|
|
74
|
+
requestId: "request_id",
|
|
75
|
+
response: "response",
|
|
76
|
+
subtype: "subtype",
|
|
77
|
+
error: "error",
|
|
78
|
+
toolName: "tool_name",
|
|
79
|
+
description: "description",
|
|
80
|
+
input: "input",
|
|
81
|
+
isError: "is_error",
|
|
82
|
+
behavior: "behavior",
|
|
83
|
+
updatedInput: "updatedInput",
|
|
84
|
+
},
|
|
85
|
+
type: {
|
|
86
|
+
user: "user",
|
|
87
|
+
assistant: "assistant",
|
|
88
|
+
result: "result",
|
|
89
|
+
text: "text",
|
|
90
|
+
toolUse: "tool_use",
|
|
91
|
+
controlRequest: "control_request",
|
|
92
|
+
controlResponse: "control_response",
|
|
93
|
+
},
|
|
94
|
+
subtype: {
|
|
95
|
+
interrupt: "interrupt",
|
|
96
|
+
canUseTool: "can_use_tool",
|
|
97
|
+
success: "success",
|
|
98
|
+
error: "error",
|
|
99
|
+
},
|
|
100
|
+
behavior: { allow: "allow", deny: "deny" },
|
|
101
|
+
},
|
|
102
|
+
files: {
|
|
103
|
+
root: ".claude",
|
|
104
|
+
projects: "projects",
|
|
105
|
+
sessions: "sessions",
|
|
106
|
+
transcriptExtension: ".jsonl",
|
|
107
|
+
registryExtension: ".json",
|
|
108
|
+
cwd: "cwd",
|
|
109
|
+
permissionMode: "permissionMode",
|
|
110
|
+
sessionId: "sessionId",
|
|
111
|
+
pid: "pid",
|
|
112
|
+
entrypoint: "entrypoint",
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* The one rule for how a permission mode reaches the CLI: the flag spells
|
|
117
|
+
* `default` as `manual`, and `bypassPermissions` is only an option once
|
|
118
|
+
* `--allow-dangerously-skip-permissions` enables it (`claude --help`).
|
|
119
|
+
*/
|
|
120
|
+
export function permissionModeArgs(mode) {
|
|
121
|
+
return [
|
|
122
|
+
CLAUDE.cli.permissionMode,
|
|
123
|
+
mode === CLAUDE_PERMISSION_MODE.default
|
|
124
|
+
? CLAUDE.cli.manualPermissionMode
|
|
125
|
+
: mode,
|
|
126
|
+
...(mode === CLAUDE_PERMISSION_MODE.bypassPermissions
|
|
127
|
+
? [CLAUDE.cli.allowDangerouslySkipPermissions]
|
|
128
|
+
: []),
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
export function parseClaudeLine(line) {
|
|
132
|
+
const record = readJsonRecord(line);
|
|
133
|
+
return record === null ? [] : parseClaudeRecord(record);
|
|
134
|
+
}
|
|
135
|
+
/** Events carried by one already-parsed stream-json record (`assistant` only). */
|
|
136
|
+
export function parseClaudeRecord(record) {
|
|
137
|
+
if (readString(record, CLAUDE.json.field.type) !== CLAUDE.json.type.assistant) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
const message = readRecord(record, CLAUDE.json.field.message);
|
|
141
|
+
const content = message?.[CLAUDE.json.field.content];
|
|
142
|
+
if (!Array.isArray(content)) {
|
|
143
|
+
return [{ type: AGENT_EVENT_TYPE.turn }];
|
|
144
|
+
}
|
|
145
|
+
const events = [{ type: AGENT_EVENT_TYPE.turn }];
|
|
146
|
+
for (const block of content) {
|
|
147
|
+
const blockRecord = readUnknownRecord(block);
|
|
148
|
+
if (blockRecord === null) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const blockType = readString(blockRecord, CLAUDE.json.field.type);
|
|
152
|
+
if (blockType === CLAUDE.json.type.text) {
|
|
153
|
+
const text = readString(blockRecord, CLAUDE.json.field.text);
|
|
154
|
+
if (text !== null) {
|
|
155
|
+
events.push({ type: AGENT_EVENT_TYPE.message, text });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (blockType === CLAUDE.json.type.toolUse) {
|
|
159
|
+
const name = readString(blockRecord, CLAUDE.json.field.name);
|
|
160
|
+
if (name !== null) {
|
|
161
|
+
events.push({ type: AGENT_EVENT_TYPE.tool, name });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return events;
|
|
166
|
+
}
|
|
167
|
+
export function parseClaudeResult(line) {
|
|
168
|
+
const record = readJsonRecord(line);
|
|
169
|
+
if (record === null ||
|
|
170
|
+
readString(record, CLAUDE.json.field.type) !== CLAUDE.json.type.result) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
const usageRecord = readRecord(record, CLAUDE.json.field.usage);
|
|
174
|
+
const usage = usageRecord === null
|
|
175
|
+
? null
|
|
176
|
+
: {
|
|
177
|
+
inputTokens: readNumber(usageRecord, CLAUDE.json.field.inputTokens),
|
|
178
|
+
outputTokens: readNumber(usageRecord, CLAUDE.json.field.outputTokens),
|
|
179
|
+
costUsd: readNumber(record, CLAUDE.json.field.totalCost),
|
|
180
|
+
};
|
|
181
|
+
return { text: readString(record, CLAUDE.json.field.result), usage };
|
|
182
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The claude host plane: auth materials and sign-in, installed skills
|
|
3
|
+
* (`~/.claude/skills`, project `.claude/skills`, plugins), and MCP
|
|
4
|
+
* registration through the CLI. Outside a run and a session; every path
|
|
5
|
+
* comes from `HostContext.location`, never `os.homedir()`.
|
|
6
|
+
*/
|
|
7
|
+
import { type LoginCapability } from "../../auth/login.js";
|
|
8
|
+
import type { MaterialHandlers } from "../../auth/material.js";
|
|
9
|
+
import { type McpCapability, type SkillsCapability } from "../../host/capabilities.js";
|
|
10
|
+
export declare const claudeAuth: MaterialHandlers;
|
|
11
|
+
export declare const claudeLogin: LoginCapability;
|
|
12
|
+
export declare const claudeSkills: SkillsCapability;
|
|
13
|
+
export declare const claudeMcp: McpCapability;
|
|
14
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../../src/agents/claude/host.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAmB,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAOhF,OAAO,EAML,KAAK,aAAa,EAKlB,KAAK,gBAAgB,EAEtB,MAAM,4BAA4B,CAAC;AA2WpC,eAAO,MAAM,UAAU,EAAE,gBAQxB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,eAIzB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,gBAO1B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,aAMvB,CAAC"}
|