@alpacakit/agents 0.2.0-beta.2 → 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.
Files changed (130) hide show
  1. package/README.md +21 -0
  2. package/dist/agents/builtin.d.ts +2 -2
  3. package/dist/agents/builtin.d.ts.map +1 -1
  4. package/dist/agents/builtin.js +6 -4
  5. package/dist/agents/claude/cli.d.ts +133 -0
  6. package/dist/agents/claude/cli.d.ts.map +1 -0
  7. package/dist/agents/{claude-stream.js → claude/cli.js} +81 -10
  8. package/dist/agents/claude/host.d.ts +14 -0
  9. package/dist/agents/claude/host.d.ts.map +1 -0
  10. package/dist/agents/{claude.js → claude/host.js} +51 -174
  11. package/dist/agents/{claude.d.ts → claude/index.d.ts} +10 -11
  12. package/dist/agents/claude/index.d.ts.map +1 -0
  13. package/dist/agents/claude/index.js +134 -0
  14. package/dist/agents/{claude-session.d.ts → claude/session.d.ts} +3 -15
  15. package/dist/agents/claude/session.d.ts.map +1 -0
  16. package/dist/agents/claude/session.js +321 -0
  17. package/dist/agents/codex/cli.d.ts +132 -0
  18. package/dist/agents/codex/cli.d.ts.map +1 -0
  19. package/dist/agents/codex/cli.js +110 -0
  20. package/dist/agents/codex/host.d.ts +14 -0
  21. package/dist/agents/codex/host.d.ts.map +1 -0
  22. package/dist/agents/codex/host.js +221 -0
  23. package/dist/agents/codex/index.d.ts +14 -0
  24. package/dist/agents/codex/index.d.ts.map +1 -0
  25. package/dist/agents/codex/index.js +127 -0
  26. package/dist/agents/codex/session.d.ts +21 -0
  27. package/dist/agents/codex/session.d.ts.map +1 -0
  28. package/dist/agents/codex/session.js +390 -0
  29. package/dist/agents/openai-compatible/fetch-engine.d.ts.map +1 -1
  30. package/dist/agents/openai-compatible/fetch-engine.js +3 -2
  31. package/dist/agents/openai-compatible/pi/engine.js +1 -1
  32. package/dist/agents/openai-compatible/pi/{session.d.ts → run.d.ts} +1 -1
  33. package/dist/agents/openai-compatible/pi/run.d.ts.map +1 -0
  34. package/dist/agents/openai-compatible/pi/sandbox.d.ts.map +1 -1
  35. package/dist/auth/login-probe.d.ts +6 -4
  36. package/dist/auth/login-probe.d.ts.map +1 -1
  37. package/dist/auth/login-probe.js +19 -13
  38. package/dist/auth/material.d.ts +1 -1
  39. package/dist/auth/material.d.ts.map +1 -1
  40. package/dist/codex/app-server.d.ts.map +1 -1
  41. package/dist/codex/app-server.js +13 -42
  42. package/dist/codex/index.d.ts +1 -1
  43. package/dist/codex/index.d.ts.map +1 -1
  44. package/dist/config/agent-config-validation.d.ts +1 -1
  45. package/dist/config/agent-config-validation.d.ts.map +1 -1
  46. package/dist/config/agent-configs.d.ts.map +1 -1
  47. package/dist/config/agent-configs.js +3 -3
  48. package/dist/config/compose.d.ts.map +1 -1
  49. package/dist/config/config.d.ts +1 -1
  50. package/dist/config/config.d.ts.map +1 -1
  51. package/dist/config/index.d.ts +2 -2
  52. package/dist/config/index.d.ts.map +1 -1
  53. package/dist/config/index.js +1 -1
  54. package/dist/config/model.d.ts +0 -1
  55. package/dist/config/model.d.ts.map +1 -1
  56. package/dist/config/schema.d.ts.map +1 -1
  57. package/dist/config/schema.js +1 -1
  58. package/dist/config/store.d.ts.map +1 -1
  59. package/dist/config/store.js +6 -24
  60. package/dist/config/support.d.ts +0 -1
  61. package/dist/config/support.d.ts.map +1 -1
  62. package/dist/config/support.js +0 -9
  63. package/dist/core/cli-child.d.ts +56 -0
  64. package/dist/core/cli-child.d.ts.map +1 -0
  65. package/dist/core/cli-child.js +105 -0
  66. package/dist/core/fs.d.ts +1 -1
  67. package/dist/core/fs.d.ts.map +1 -1
  68. package/dist/core/fs.js +10 -2
  69. package/dist/core/node-ports.d.ts.map +1 -1
  70. package/dist/core/node-ports.js +1 -5
  71. package/dist/core/session.d.ts +4 -0
  72. package/dist/core/session.d.ts.map +1 -1
  73. package/dist/fleet/store.d.ts.map +1 -1
  74. package/dist/fleet/store.js +4 -3
  75. package/dist/host/availability.d.ts +2 -1
  76. package/dist/host/availability.d.ts.map +1 -1
  77. package/dist/host/github-dir.d.ts.map +1 -1
  78. package/dist/host/github-dir.js +2 -1
  79. package/dist/host/mcp-list.d.ts.map +1 -1
  80. package/dist/host/mcp-list.js +5 -6
  81. package/dist/host/run-command.d.ts +2 -1
  82. package/dist/host/run-command.d.ts.map +1 -1
  83. package/dist/host/run-command.js +10 -19
  84. package/dist/host/session-files.d.ts +2 -1
  85. package/dist/host/session-files.d.ts.map +1 -1
  86. package/dist/host/session-files.js +2 -1
  87. package/dist/index.d.ts +6 -6
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +5 -5
  90. package/dist/kernel/classify.d.ts +1 -2
  91. package/dist/kernel/classify.d.ts.map +1 -1
  92. package/dist/kernel/classify.js +1 -1
  93. package/dist/kernel/cli-agent.d.ts.map +1 -1
  94. package/dist/kernel/cli-agent.js +26 -85
  95. package/dist/kernel/cli-login.d.ts.map +1 -1
  96. package/dist/kernel/cli-login.js +9 -30
  97. package/dist/kernel/facets.d.ts +1 -1
  98. package/dist/kernel/facets.d.ts.map +1 -1
  99. package/dist/kernel/login.d.ts.map +1 -1
  100. package/dist/kernel/login.js +2 -1
  101. package/dist/kernel/options.d.ts +1 -1
  102. package/dist/kernel/options.d.ts.map +1 -1
  103. package/dist/kernel/run.d.ts.map +1 -1
  104. package/dist/kernel/run.js +2 -1
  105. package/dist/kernel/session.d.ts +46 -39
  106. package/dist/kernel/session.d.ts.map +1 -1
  107. package/dist/kernel/session.js +128 -69
  108. package/dist/testing/fake-exec.d.ts +9 -10
  109. package/dist/testing/fake-exec.d.ts.map +1 -1
  110. package/dist/testing/fake-exec.js +14 -1
  111. package/dist/testing/index.d.ts +1 -1
  112. package/dist/testing/index.d.ts.map +1 -1
  113. package/dist/testing/index.js +1 -1
  114. package/package.json +2 -2
  115. package/dist/agents/claude-session.d.ts.map +0 -1
  116. package/dist/agents/claude-session.js +0 -419
  117. package/dist/agents/claude-stream.d.ts +0 -65
  118. package/dist/agents/claude-stream.d.ts.map +0 -1
  119. package/dist/agents/claude.d.ts.map +0 -1
  120. package/dist/agents/codex-session.d.ts +0 -52
  121. package/dist/agents/codex-session.d.ts.map +0 -1
  122. package/dist/agents/codex-session.js +0 -495
  123. package/dist/agents/codex.d.ts +0 -20
  124. package/dist/agents/codex.d.ts.map +0 -1
  125. package/dist/agents/codex.js +0 -379
  126. package/dist/agents/openai-compatible/pi/session.d.ts.map +0 -1
  127. package/dist/core/process-close.d.ts +0 -11
  128. package/dist/core/process-close.d.ts.map +0 -1
  129. package/dist/core/process-close.js +0 -27
  130. /package/dist/agents/openai-compatible/pi/{session.js → run.js} +0 -0
package/README.md CHANGED
@@ -408,6 +408,27 @@ installed skills and MCP servers remains in progress.
408
408
  | `/testing` | `fakeExec`, `fakeClock`, `fakeAgent`, `fakeSecretResolver` — no subprocess ever spawns |
409
409
  | `/codex` | codex app-server JSON-RPC client: typed requests, `incoming` notifications / server requests, `respond` (advanced) |
410
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
+
411
432
  ## Breaking changes in 0.2.0
412
433
 
413
434
  - `Agent.session` (and `AgentDefinition.session`) are new; `AgentDefinition`
@@ -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;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,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"}
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"}
@@ -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 { claude } from "./claude.js";
8
- import { codex } from "./codex.js";
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: "codex",
11
- claude: "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"}
@@ -1,11 +1,23 @@
1
1
  /**
2
- * Claude CLI stream-json vocabulary and line readers, shared by the
3
- * one-shot run adapter (`claude.ts`) and the long-lived session adapter
4
- * (`claude-session.ts`): one place spells the CLI's flags and the NDJSON
5
- * field names both of them read.
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.
6
7
  */
7
- import { readJsonRecord, readNumber, readRecord, readString, readUnknownRecord, } from "../core/json.js";
8
- import { AGENT_EVENT_TYPE } from "../core/run.js";
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
+ };
9
21
  export const CLAUDE = {
10
22
  id: "claude",
11
23
  command: "claude",
@@ -14,10 +26,16 @@ export const CLAUDE = {
14
26
  model: "--model",
15
27
  effort: "--effort",
16
28
  outputFormat: "--output-format",
29
+ inputFormat: "--input-format",
17
30
  streamJson: "stream-json",
18
31
  permissionMode: "--permission-mode",
19
- bypassPermissions: "bypassPermissions",
20
- defaultPermissionMode: "default",
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",
21
39
  verbose: "--verbose",
22
40
  tools: "--tools",
23
41
  allowedTools: "--allowedTools",
@@ -43,6 +61,7 @@ export const CLAUDE = {
43
61
  field: {
44
62
  type: "type",
45
63
  message: "message",
64
+ role: "role",
46
65
  content: "content",
47
66
  text: "text",
48
67
  name: "name",
@@ -51,19 +70,71 @@ export const CLAUDE = {
51
70
  inputTokens: "input_tokens",
52
71
  outputTokens: "output_tokens",
53
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",
54
84
  },
55
85
  type: {
86
+ user: "user",
56
87
  assistant: "assistant",
57
88
  result: "result",
58
89
  text: "text",
59
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",
60
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",
61
113
  },
62
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
+ }
63
131
  export function parseClaudeLine(line) {
64
132
  const record = readJsonRecord(line);
65
- if (record === null ||
66
- readString(record, CLAUDE.json.field.type) !== CLAUDE.json.type.assistant) {
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) {
67
138
  return [];
68
139
  }
69
140
  const message = readRecord(record, CLAUDE.json.field.message);
@@ -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"}
@@ -1,44 +1,36 @@
1
1
  /**
2
- * Built-in claude CLI contract:
3
- * `claude -p [--model m] [--effort e] --output-format stream-json
4
- * --permission-mode <mode> [tool args] --verbose`, prompt on stdin.
5
- * Read-only grants map to `--allowedTools` (`Bash(cmd:*)` for shell
6
- * grants, the bare tool name otherwise); no grants means `--tools ""`.
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()`.
7
6
  */
8
7
  import { cp, mkdir, readdir, readFile, rm, stat } from "node:fs/promises";
9
8
  import path from "node:path";
10
- import { LOGIN_METHOD } from "../auth/login.js";
11
- import { cliLoginProbe } from "../auth/login-probe.js";
12
- import { AUTH_MATERIAL_KIND, envVarAuthMaterial } from "../auth/material.js";
13
- import { requireSecret } from "../auth/secrets.js";
14
- import { AGENT_ERROR_CODE, AgentError } from "../core/error.js";
15
- import { isErrnoCode } from "../core/fs.js";
16
- import { readBoolean, readJsonRecord, readNumber, readRecord, readString, } from "../core/json.js";
17
- import { TEXT_ENCODING } from "../core/values.js";
18
- import { cliAvailability } from "../host/availability.js";
19
- import { INSTALL_STATUS, MCP_TRANSPORT, SKILL_SOURCE_KIND, } from "../host/capabilities.js";
20
- import { withStagedGithubDirectory, } from "../host/github-dir.js";
21
- import { listMcpServersViaCli } from "../host/mcp-list.js";
22
- import { hostCommandFailedError, runHostCommand, runHostCommandResult, } from "../host/run-command.js";
23
- import { parseEpochTimestamp, } from "../kernel/classify.js";
24
- import { defineCliAgent } from "../kernel/cli-agent.js";
25
- import { cliLoginCommand } from "../kernel/cli-login.js";
26
- import { GRANT_KIND, SANDBOX_MODE } from "../kernel/options.js";
27
- import { claudeSessions, } from "./claude-session.js";
28
- import { CLAUDE, parseClaudeLine, parseClaudeResult } from "./claude-stream.js";
29
- export const CLAUDE_CONFIG_DIR_ENV_VAR = "CLAUDE_CONFIG_DIR";
30
- export const CLAUDE_API_KEY_ENV_VAR = "ANTHROPIC_API_KEY";
9
+ import { LOGIN_METHOD, } from "../../auth/login.js";
10
+ import { cliLoginProbe } from "../../auth/login-probe.js";
11
+ import { AUTH_MATERIAL_KIND, envVarAuthMaterial } from "../../auth/material.js";
12
+ import { requireSecret } from "../../auth/secrets.js";
13
+ import { NO_FAILURE_EVIDENCE } from "../../core/cli-child.js";
14
+ import { AGENT_ERROR_CODE, AgentError } from "../../core/error.js";
15
+ import { isErrnoCode } from "../../core/fs.js";
16
+ import { TEXT_ENCODING } from "../../core/values.js";
17
+ import { INSTALL_STATUS, MCP_TRANSPORT, SKILL_SOURCE_KIND, } from "../../host/capabilities.js";
18
+ import { withStagedGithubDirectory, } from "../../host/github-dir.js";
19
+ import { listMcpServersViaCli } from "../../host/mcp-list.js";
20
+ import { hostCommandFailedError, runHostCommand, runHostCommandResult, } from "../../host/run-command.js";
21
+ import { cliLoginCommand } from "../../kernel/cli-login.js";
22
+ import { CLAUDE, CLAUDE_API_KEY_ENV_VAR, CLAUDE_CONFIG_DIR_ENV_VAR, } from "./cli.js";
31
23
  const COMPETING_TOKEN_VARS = [
32
- "ANTHROPIC_API_KEY",
24
+ CLAUDE_API_KEY_ENV_VAR,
33
25
  "ANTHROPIC_AUTH_TOKEN",
34
26
  "CLAUDE_CODE_OAUTH_TOKEN",
35
27
  ];
36
28
  const COMPETING_CONFIG_VARS = [
37
- "CLAUDE_CONFIG_DIR",
29
+ CLAUDE_CONFIG_DIR_ENV_VAR,
38
30
  "ANTHROPIC_AUTH_TOKEN",
39
31
  "CLAUDE_CODE_OAUTH_TOKEN",
40
32
  ];
41
- const CLAUDE_PROJECT_SKILL_ROOT = ".claude";
33
+ const CLAUDE_PROJECT_SKILL_ROOT = CLAUDE.files.root;
42
34
  const SKILLS_DIRECTORY = "skills";
43
35
  const SKILL_MARKDOWN = "SKILL.md";
44
36
  const PLUGIN_ALREADY_INSTALLED = /already installed/i;
@@ -46,71 +38,6 @@ const CLAUDE_SKILL_SOURCE = {
46
38
  project: "claude:project",
47
39
  user: "claude:user",
48
40
  };
49
- function grantToToolArg(grant) {
50
- return grant.kind === GRANT_KIND.shell
51
- ? `Bash(${grant.command}:*)`
52
- : grant.name;
53
- }
54
- function sharedArgs(ctx, customizations) {
55
- return [
56
- CLAUDE.cli.prompt,
57
- ...(ctx.model === null ? [] : [CLAUDE.cli.model, ctx.model]),
58
- ...(ctx.effort === null ? [] : [CLAUDE.cli.effort, ctx.effort]),
59
- CLAUDE.cli.outputFormat,
60
- CLAUDE.cli.streamJson,
61
- ...(customizations === "disabled"
62
- ? [
63
- CLAUDE.cli.safeMode,
64
- CLAUDE.cli.strictMcpConfig,
65
- CLAUDE.cli.noSessionPersistence,
66
- ]
67
- : []),
68
- ];
69
- }
70
- /**
71
- * Structured quota signals in Claude CLI NDJSON output (v1 F2), scanned
72
- * per line: rate_limit_event rejected (with resetsAt), api_error_status
73
- * 429, and error === "rate_limit". Exported for custom agents that speak
74
- * the same stream format.
75
- */
76
- export function structuredQuotaMatcher() {
77
- return (evidence) => {
78
- let fallbackCooldownUntil = null;
79
- for (const line of evidence.stdout.split(/\r?\n/)) {
80
- const record = readJsonRecord(line.trim());
81
- if (record === null) {
82
- continue;
83
- }
84
- const rateLimitInfo = readRecord(record, "rate_limit_info");
85
- const resetsAt = rateLimitInfo === null ? null : readNumber(rateLimitInfo, "resetsAt");
86
- const cooldownUntil = resetsAt === null ? null : parseEpochTimestamp(resetsAt);
87
- const rejected = rateLimitInfo !== null &&
88
- readString(rateLimitInfo, "status") === "rejected";
89
- if (readString(record, "type") === "rate_limit_event" && rejected) {
90
- return {
91
- code: AGENT_ERROR_CODE.quota,
92
- message: "Provider rejected the request for rate limiting",
93
- data: { cooldownUntil },
94
- };
95
- }
96
- if (cooldownUntil !== null) {
97
- fallbackCooldownUntil = cooldownUntil;
98
- }
99
- const apiError = readBoolean(record, "is_error") === true &&
100
- readNumber(record, "api_error_status") === 429;
101
- const rateLimitError = readString(record, "error") === "rate_limit" &&
102
- readString(record, "type") !== null;
103
- if (apiError || rateLimitError) {
104
- return {
105
- code: AGENT_ERROR_CODE.quota,
106
- message: "Provider reported a rate-limit error",
107
- data: { cooldownUntil: fallbackCooldownUntil },
108
- };
109
- }
110
- }
111
- return null;
112
- };
113
- }
114
41
  const homeDirHandler = envVarAuthMaterial({
115
42
  set: (material) => ({ [CLAUDE_CONFIG_DIR_ENV_VAR]: material.path }),
116
43
  unset: COMPETING_TOKEN_VARS,
@@ -135,7 +62,7 @@ const homeDirHandler = envVarAuthMaterial({
135
62
  * `--sso` are still browser flows), and declaring an unimplemented method
136
63
  * would make `agent.login.supports("device")` lie.
137
64
  */
138
- function claudeLogin(args) {
65
+ function claudeLoginCommand(args) {
139
66
  return (request, ctx) => cliLoginCommand({
140
67
  command: CLAUDE.command,
141
68
  args,
@@ -195,7 +122,7 @@ function skillListReadError(target, cause) {
195
122
  code: AGENT_ERROR_CODE.failed,
196
123
  classification: AgentError.agentFailure(AGENT_ERROR_CODE.failed),
197
124
  message: `Could not read installed claude skills: ${target}`,
198
- data: { exitCode: null, stdoutTail: null, stderrTail: null },
125
+ data: NO_FAILURE_EVIDENCE,
199
126
  cause,
200
127
  });
201
128
  }
@@ -361,82 +288,32 @@ async function removeClaudeMcp(ctx, name, options) {
361
288
  async function listClaudeMcp(ctx) {
362
289
  return listMcpServersViaCli(ctx, { command: CLAUDE.command });
363
290
  }
364
- export function claude(options = {}) {
365
- const customizations = options.customizations ?? "inherit";
366
- const definition = defineCliAgent({
367
- id: CLAUDE.id,
368
- command: CLAUDE.command,
369
- args: {
370
- [SANDBOX_MODE.full]: (_sandbox, ctx) => [
371
- ...sharedArgs(ctx, customizations),
372
- CLAUDE.cli.permissionMode,
373
- CLAUDE.cli.bypassPermissions,
374
- CLAUDE.cli.verbose,
375
- ],
376
- [SANDBOX_MODE.readOnly]: (sandbox, ctx) => [
377
- ...sharedArgs(ctx, customizations),
378
- CLAUDE.cli.permissionMode,
379
- CLAUDE.cli.defaultPermissionMode,
380
- ...(sandbox.grants.length === 0
381
- ? [CLAUDE.cli.tools, ""]
382
- : [
383
- CLAUDE.cli.allowedTools,
384
- sandbox.grants.map(grantToToolArg).join(","),
385
- ]),
386
- CLAUDE.cli.verbose,
387
- ],
388
- },
389
- parseLine: parseClaudeLine,
390
- parseResult: parseClaudeResult,
391
- classify: [structuredQuotaMatcher()],
392
- // F6: Claude CLI can report a structured quota rejection on exit 0.
393
- classifyOnSuccess: [structuredQuotaMatcher()],
394
- availability: cliAvailability({
395
- command: CLAUDE.command,
396
- commandMissingRemediation: {
397
- detail: "Install Claude Code and ensure `claude` is on PATH.",
398
- command: null,
399
- },
400
- authentication: {
401
- args: CLAUDE.auth.statusArgs,
402
- remediation: {
403
- detail: "Sign in to Claude Code.",
404
- command: {
405
- executable: CLAUDE.command,
406
- args: CLAUDE.auth.loginArgs,
407
- },
408
- },
409
- },
291
+ export const claudeAuth = {
292
+ [AUTH_MATERIAL_KIND.homeDir]: homeDirHandler,
293
+ [AUTH_MATERIAL_KIND.apiKey]: envVarAuthMaterial({
294
+ set: async (material, secrets) => ({
295
+ [CLAUDE_API_KEY_ENV_VAR]: await requireSecret(secrets, material.secret),
410
296
  }),
411
- auth: {
412
- [AUTH_MATERIAL_KIND.homeDir]: homeDirHandler,
413
- [AUTH_MATERIAL_KIND.apiKey]: envVarAuthMaterial({
414
- set: async (material, secrets) => ({
415
- [CLAUDE_API_KEY_ENV_VAR]: await requireSecret(secrets, material.secret),
416
- }),
417
- unset: COMPETING_CONFIG_VARS,
418
- }),
419
- },
420
- login: {
421
- methods: {
422
- [LOGIN_METHOD.oauth]: claudeLogin(CLAUDE.auth.loginArgs),
423
- },
424
- },
425
- skills: {
426
- list: listClaudeSkills,
427
- install: {
428
- [SKILL_SOURCE_KIND.localDir]: installLocalClaudeSkill,
429
- [SKILL_SOURCE_KIND.githubDir]: installGithubClaudeSkill,
430
- [SKILL_SOURCE_KIND.plugin]: installClaudePlugin,
431
- },
432
- },
433
- mcp: {
434
- list: listClaudeMcp,
435
- add: {
436
- [MCP_TRANSPORT.stdio]: addClaudeStdioMcp,
437
- },
438
- remove: removeClaudeMcp,
439
- },
440
- });
441
- return { ...definition, session: claudeSessions({ customizations }) };
442
- }
297
+ unset: COMPETING_CONFIG_VARS,
298
+ }),
299
+ };
300
+ export const claudeLogin = {
301
+ methods: {
302
+ [LOGIN_METHOD.oauth]: claudeLoginCommand(CLAUDE.auth.loginArgs),
303
+ },
304
+ };
305
+ export const claudeSkills = {
306
+ list: listClaudeSkills,
307
+ install: {
308
+ [SKILL_SOURCE_KIND.localDir]: installLocalClaudeSkill,
309
+ [SKILL_SOURCE_KIND.githubDir]: installGithubClaudeSkill,
310
+ [SKILL_SOURCE_KIND.plugin]: installClaudePlugin,
311
+ },
312
+ };
313
+ export const claudeMcp = {
314
+ list: listClaudeMcp,
315
+ add: {
316
+ [MCP_TRANSPORT.stdio]: addClaudeStdioMcp,
317
+ },
318
+ remove: removeClaudeMcp,
319
+ };
@@ -1,15 +1,14 @@
1
1
  /**
2
- * Built-in claude CLI contract:
3
- * `claude -p [--model m] [--effort e] --output-format stream-json
4
- * --permission-mode <mode> [tool args] --verbose`, prompt on stdin.
5
- * Read-only grants map to `--allowedTools` (`Bash(cmd:*)` for shell
6
- * grants, the bare tool name otherwise); no grants means `--tools ""`.
2
+ * The built-in claude agent: the one-shot run contract
3
+ * (`claude -p [--model m] [--effort e] --output-format stream-json
4
+ * --permission-mode <mode> [tool args] --verbose`, prompt on stdin;
5
+ * read-only grants map to `--allowedTools`, `Bash(cmd:*)` for shell
6
+ * grants, no grants means `--tools ""`) composed with the session adapter
7
+ * and the host plane. Vocabulary lives in `cli.ts`.
7
8
  */
8
- import { type FailureMatcher } from "../kernel/classify.js";
9
- import type { AgentDefinition } from "../kernel/definition.js";
10
- import { type ClaudeSessionPermissions } from "./claude-session.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";
9
+ import { type FailureMatcher } from "../../kernel/classify.js";
10
+ import type { AgentDefinition } from "../../kernel/definition.js";
11
+ import { type ClaudeSessionPermissions } from "./cli.js";
13
12
  /**
14
13
  * Structured quota signals in Claude CLI NDJSON output (v1 F2), scanned
15
14
  * per line: rate_limit_event rejected (with resetsAt), api_error_status
@@ -25,4 +24,4 @@ export type ClaudeOptions = {
25
24
  readonly customizations?: "inherit" | "disabled";
26
25
  };
27
26
  export declare function claude(options?: ClaudeOptions): AgentDefinition<"claude", ClaudeSessionPermissions>;
28
- //# sourceMappingURL=claude.d.ts.map
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agents/claude/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,OAAO,EACL,KAAK,cAAc,EAEpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,OAAO,EAGL,KAAK,wBAAwB,EAI9B,MAAM,UAAU,CAAC;AA8BlB;;;;;GAKG;AACH,wBAAgB,sBAAsB,IAAI,cAAc,CA0CvD;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;CAClD,CAAC;AAEF,wBAAgB,MAAM,CACpB,OAAO,GAAE,aAAkB,GAC1B,eAAe,CAAC,QAAQ,EAAE,wBAAwB,CAAC,CAmDrD"}