subharness 0.0.3 → 0.0.5

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 (241) hide show
  1. package/README.md +39 -9
  2. package/dist/adapters/approval-context.d.ts +2 -0
  3. package/dist/adapters/approval-context.js +9 -0
  4. package/dist/adapters/approval-context.js.map +1 -0
  5. package/dist/adapters/approval-lifetime.d.ts +8 -0
  6. package/dist/adapters/approval-lifetime.js +50 -0
  7. package/dist/adapters/approval-lifetime.js.map +1 -0
  8. package/dist/adapters/claude-approvals.d.ts +4 -0
  9. package/dist/adapters/claude-approvals.js +32 -0
  10. package/dist/adapters/claude-approvals.js.map +1 -0
  11. package/dist/adapters/claude-permissions.js +1 -1
  12. package/dist/adapters/claude-permissions.js.map +1 -1
  13. package/dist/adapters/claude-process.d.ts +3 -0
  14. package/dist/adapters/claude-process.js +11 -1
  15. package/dist/adapters/claude-process.js.map +1 -1
  16. package/dist/adapters/claude-result.d.ts +2 -0
  17. package/dist/adapters/claude-result.js +22 -0
  18. package/dist/adapters/claude-result.js.map +1 -0
  19. package/dist/adapters/claude.js +60 -12
  20. package/dist/adapters/claude.js.map +1 -1
  21. package/dist/adapters/codex-approvals.d.ts +6 -0
  22. package/dist/adapters/codex-approvals.js +111 -0
  23. package/dist/adapters/codex-approvals.js.map +1 -0
  24. package/dist/adapters/codex.js +36 -3
  25. package/dist/adapters/codex.js.map +1 -1
  26. package/dist/adapters/copilot-permissions.d.ts +26 -0
  27. package/dist/adapters/copilot-permissions.js +121 -0
  28. package/dist/adapters/copilot-permissions.js.map +1 -0
  29. package/dist/adapters/copilot-tools.d.ts +12 -0
  30. package/dist/adapters/copilot-tools.js +61 -0
  31. package/dist/adapters/copilot-tools.js.map +1 -0
  32. package/dist/adapters/copilot.d.ts +108 -0
  33. package/dist/adapters/copilot.js +819 -0
  34. package/dist/adapters/copilot.js.map +1 -0
  35. package/dist/adapters/cursor-cli-approvals.d.ts +2 -0
  36. package/dist/adapters/cursor-cli-approvals.js +83 -0
  37. package/dist/adapters/cursor-cli-approvals.js.map +1 -0
  38. package/dist/adapters/cursor-cli-model.d.ts +4 -0
  39. package/dist/adapters/cursor-cli-model.js +64 -0
  40. package/dist/adapters/cursor-cli-model.js.map +1 -0
  41. package/dist/adapters/cursor-cli-session.d.ts +32 -0
  42. package/dist/adapters/cursor-cli-session.js +316 -0
  43. package/dist/adapters/cursor-cli-session.js.map +1 -0
  44. package/dist/adapters/cursor-cli-tools.d.ts +20 -0
  45. package/dist/adapters/cursor-cli-tools.js +181 -0
  46. package/dist/adapters/cursor-cli-tools.js.map +1 -0
  47. package/dist/adapters/cursor-cli.d.ts +2 -0
  48. package/dist/adapters/cursor-cli.js +306 -0
  49. package/dist/adapters/cursor-cli.js.map +1 -0
  50. package/dist/adapters/cursor-model.d.ts +7 -0
  51. package/dist/adapters/cursor-model.js +67 -0
  52. package/dist/adapters/cursor-model.js.map +1 -0
  53. package/dist/adapters/cursor-rpc.d.ts +42 -0
  54. package/dist/adapters/cursor-rpc.js +271 -0
  55. package/dist/adapters/cursor-rpc.js.map +1 -0
  56. package/dist/adapters/cursor-session.d.ts +4 -0
  57. package/dist/adapters/cursor-session.js +327 -0
  58. package/dist/adapters/cursor-session.js.map +1 -0
  59. package/dist/adapters/cursor-startup.d.ts +16 -0
  60. package/dist/adapters/cursor-startup.js +74 -0
  61. package/dist/adapters/cursor-startup.js.map +1 -0
  62. package/dist/adapters/cursor-tools.d.ts +11 -0
  63. package/dist/adapters/cursor-tools.js +49 -0
  64. package/dist/adapters/cursor-tools.js.map +1 -0
  65. package/dist/adapters/cursor.d.ts +6 -0
  66. package/dist/adapters/cursor.js +17 -0
  67. package/dist/adapters/cursor.js.map +1 -0
  68. package/dist/adapters/fx-approvals.d.ts +2 -0
  69. package/dist/adapters/fx-approvals.js +14 -0
  70. package/dist/adapters/fx-approvals.js.map +1 -0
  71. package/dist/adapters/fx-auth.d.ts +12 -2
  72. package/dist/adapters/fx-auth.js +51 -61
  73. package/dist/adapters/fx-auth.js.map +1 -1
  74. package/dist/adapters/fx-profile.d.ts +8 -0
  75. package/dist/adapters/fx-profile.js +101 -0
  76. package/dist/adapters/fx-profile.js.map +1 -0
  77. package/dist/adapters/fx-rpc.d.ts +2 -0
  78. package/dist/adapters/fx-rpc.js +30 -4
  79. package/dist/adapters/fx-rpc.js.map +1 -1
  80. package/dist/adapters/fx-status.d.ts +2 -0
  81. package/dist/adapters/fx-status.js +96 -0
  82. package/dist/adapters/fx-status.js.map +1 -0
  83. package/dist/adapters/fx.js +77 -30
  84. package/dist/adapters/fx.js.map +1 -1
  85. package/dist/adapters/opencode-access.d.ts +13 -0
  86. package/dist/adapters/opencode-access.js +76 -0
  87. package/dist/adapters/opencode-access.js.map +1 -0
  88. package/dist/adapters/opencode-config.d.ts +11 -0
  89. package/dist/adapters/opencode-config.js +238 -0
  90. package/dist/adapters/opencode-config.js.map +1 -0
  91. package/dist/adapters/opencode-http.d.ts +28 -0
  92. package/dist/adapters/opencode-http.js +297 -0
  93. package/dist/adapters/opencode-http.js.map +1 -0
  94. package/dist/adapters/opencode-tools.d.ts +19 -0
  95. package/dist/adapters/opencode-tools.js +127 -0
  96. package/dist/adapters/opencode-tools.js.map +1 -0
  97. package/dist/adapters/opencode.d.ts +2 -0
  98. package/dist/adapters/opencode.js +569 -0
  99. package/dist/adapters/opencode.js.map +1 -0
  100. package/dist/adapters/rpc.d.ts +3 -0
  101. package/dist/adapters/rpc.js +45 -4
  102. package/dist/adapters/rpc.js.map +1 -1
  103. package/dist/adapters/types.d.ts +7 -0
  104. package/dist/adapters/types.js.map +1 -1
  105. package/dist/approvals/schema.d.ts +4 -0
  106. package/dist/approvals/schema.js +70 -0
  107. package/dist/approvals/schema.js.map +1 -0
  108. package/dist/approvals/types.d.ts +47 -0
  109. package/dist/approvals/types.js +2 -0
  110. package/dist/approvals/types.js.map +1 -0
  111. package/dist/cli/args.d.ts +3 -2
  112. package/dist/cli/args.js +24 -3
  113. package/dist/cli/args.js.map +1 -1
  114. package/dist/cli/dashboard-client.d.ts +5 -1
  115. package/dist/cli/dashboard-client.js +162 -15
  116. package/dist/cli/dashboard-client.js.map +1 -1
  117. package/dist/cli/dashboard-controller.d.ts +7 -0
  118. package/dist/cli/dashboard-controller.js +27 -0
  119. package/dist/cli/dashboard-controller.js.map +1 -0
  120. package/dist/cli/dashboard-detail-view.d.ts +16 -0
  121. package/dist/cli/dashboard-detail-view.js +162 -0
  122. package/dist/cli/dashboard-detail-view.js.map +1 -0
  123. package/dist/cli/dashboard-history-view.d.ts +29 -0
  124. package/dist/cli/dashboard-history-view.js +211 -0
  125. package/dist/cli/dashboard-history-view.js.map +1 -0
  126. package/dist/cli/dashboard-input.d.ts +14 -0
  127. package/dist/cli/dashboard-input.js +128 -0
  128. package/dist/cli/dashboard-input.js.map +1 -0
  129. package/dist/cli/dashboard-layout.d.ts +12 -1
  130. package/dist/cli/dashboard-layout.js +32 -30
  131. package/dist/cli/dashboard-layout.js.map +1 -1
  132. package/dist/cli/dashboard-renderer.d.ts +30 -2
  133. package/dist/cli/dashboard-renderer.js +125 -7
  134. package/dist/cli/dashboard-renderer.js.map +1 -1
  135. package/dist/cli/dashboard-style.d.ts +9 -0
  136. package/dist/cli/dashboard-style.js +36 -0
  137. package/dist/cli/dashboard-style.js.map +1 -0
  138. package/dist/cli/dashboard.d.ts +5 -3
  139. package/dist/cli/dashboard.js +102 -12
  140. package/dist/cli/dashboard.js.map +1 -1
  141. package/dist/cli/help.d.ts +1 -1
  142. package/dist/cli/help.js +37 -12
  143. package/dist/cli/help.js.map +1 -1
  144. package/dist/cli/input.d.ts +1 -0
  145. package/dist/cli/input.js +23 -17
  146. package/dist/cli/input.js.map +1 -1
  147. package/dist/cli/main.js +6 -2
  148. package/dist/cli/main.js.map +1 -1
  149. package/dist/cli/output.js +17 -1
  150. package/dist/cli/output.js.map +1 -1
  151. package/dist/config/access-provenance.d.ts +10 -0
  152. package/dist/config/access-provenance.js +31 -0
  153. package/dist/config/access-provenance.js.map +1 -0
  154. package/dist/config/access.d.ts +12 -2
  155. package/dist/config/access.js +125 -27
  156. package/dist/config/access.js.map +1 -1
  157. package/dist/config/loader.js +1 -0
  158. package/dist/config/loader.js.map +1 -1
  159. package/dist/config/oidc.js +4 -2
  160. package/dist/config/oidc.js.map +1 -1
  161. package/dist/config/project.js +2 -1
  162. package/dist/config/project.js.map +1 -1
  163. package/dist/config/resolve-access.js +24 -10
  164. package/dist/config/resolve-access.js.map +1 -1
  165. package/dist/index.d.ts +2 -2
  166. package/dist/index.js +1 -1
  167. package/dist/index.js.map +1 -1
  168. package/dist/process-diagnostics.d.ts +2 -0
  169. package/dist/process-diagnostics.js +11 -0
  170. package/dist/process-diagnostics.js.map +1 -0
  171. package/dist/runtime/access-errors.d.ts +4 -0
  172. package/dist/runtime/access-errors.js +25 -0
  173. package/dist/runtime/access-errors.js.map +1 -0
  174. package/dist/runtime/approval-registry.d.ts +27 -0
  175. package/dist/runtime/approval-registry.js +126 -0
  176. package/dist/runtime/approval-registry.js.map +1 -0
  177. package/dist/runtime/client.js +54 -14
  178. package/dist/runtime/client.js.map +1 -1
  179. package/dist/runtime/coordinator.d.ts +17 -1
  180. package/dist/runtime/coordinator.js +124 -6
  181. package/dist/runtime/coordinator.js.map +1 -1
  182. package/dist/runtime/dashboard-sanitize.d.ts +2 -0
  183. package/dist/runtime/dashboard-sanitize.js +7 -0
  184. package/dist/runtime/dashboard-sanitize.js.map +1 -0
  185. package/dist/runtime/dashboard.d.ts +43 -1
  186. package/dist/runtime/dashboard.js +2 -3
  187. package/dist/runtime/dashboard.js.map +1 -1
  188. package/dist/runtime/definition.js +11 -1
  189. package/dist/runtime/definition.js.map +1 -1
  190. package/dist/runtime/select-native.d.ts +2 -1
  191. package/dist/runtime/select-native.js +28 -10
  192. package/dist/runtime/select-native.js.map +1 -1
  193. package/dist/runtime/service.js +24 -1
  194. package/dist/runtime/service.js.map +1 -1
  195. package/dist/runtime/types.d.ts +9 -1
  196. package/dist/runtime/types.js.map +1 -1
  197. package/dist/runtime/worker-approvals.d.ts +21 -0
  198. package/dist/runtime/worker-approvals.js +51 -0
  199. package/dist/runtime/worker-approvals.js.map +1 -0
  200. package/dist/runtime/worker-client.js +73 -20
  201. package/dist/runtime/worker-client.js.map +1 -1
  202. package/dist/runtime/worker-server.d.ts +2 -0
  203. package/dist/runtime/worker-server.js +39 -10
  204. package/dist/runtime/worker-server.js.map +1 -1
  205. package/dist/sdk/definitions.d.ts +4 -1
  206. package/dist/sdk/definitions.js +16 -2
  207. package/dist/sdk/definitions.js.map +1 -1
  208. package/dist/sdk/permission-validation.js +10 -1
  209. package/dist/sdk/permission-validation.js.map +1 -1
  210. package/dist/sdk/types.d.ts +29 -1
  211. package/dist/sdk/types.js.map +1 -1
  212. package/package.json +4 -1
  213. package/sdk/access-config.md +86 -4
  214. package/sdk/adapter-contract.md +7 -13
  215. package/sdk/additional-harnesses.md +43 -0
  216. package/sdk/agent-skill.md +7 -4
  217. package/sdk/agent.md +5 -3
  218. package/sdk/approvals.md +120 -0
  219. package/sdk/authentication.md +1 -1
  220. package/sdk/cli/dashboard-design.md +44 -4
  221. package/sdk/cli/dashboard-inspection.md +25 -0
  222. package/sdk/cli/index.md +20 -11
  223. package/sdk/cli/output.md +10 -4
  224. package/sdk/completion-notifications.md +2 -0
  225. package/sdk/config.md +1 -1
  226. package/sdk/copilot.md +53 -0
  227. package/sdk/cursor.md +68 -0
  228. package/sdk/diagnostics.md +29 -0
  229. package/sdk/distribution.md +53 -1
  230. package/sdk/evals.md +10 -4
  231. package/sdk/fx.md +51 -6
  232. package/sdk/harnesses.md +13 -13
  233. package/sdk/index.md +4 -2
  234. package/sdk/message-delivery.md +1 -1
  235. package/sdk/opencode.md +57 -0
  236. package/sdk/permissions.md +7 -5
  237. package/sdk/pr-integration.md +1 -1
  238. package/sdk/project-team.md +2 -0
  239. package/sdk/sessions.md +4 -1
  240. package/sdk/tools.md +1 -1
  241. package/sdk/v1-runtime.md +6 -6
package/README.md CHANGED
@@ -6,9 +6,9 @@
6
6
  <a href="https://github.com/vercel-labs/subharness/blob/main/LICENSE"><img alt="License: Apache-2.0" src="https://img.shields.io/badge/License-Apache--2.0-blue.svg?style=for-the-badge&amp;labelColor=000000" height="28"></a>
7
7
  </p>
8
8
 
9
- Stay with your favorite coding agent. Ask it to delegate tasks across Codex, Claude Code, and fx, and bring results back to one conversation. The main agent uses the local `subharness` CLI to start independent native sessions, check their status, read complete responses, and report the results.
9
+ Stay with your favorite coding agent. Ask it to delegate tasks across Codex, Claude Code, fx, OpenCode, GitHub Copilot, and Cursor, and bring results back to one conversation. The main agent uses the local `subharness` CLI to start independent native sessions, check their status, read complete responses, and report the results.
10
10
 
11
- TypeScript definitions are optional. Add them when your coding agent needs reusable specialists with shared instructions, tools, or harness alternatives. Codex and Claude Code use eligible native subscription logins or explicitly configured API access; fx uses an explicitly configured Vercel AI Gateway connection.
11
+ TypeScript definitions are optional. Add them when your coding agent needs reusable specialists with shared instructions, tools, or harness alternatives. Codex and Claude Code use eligible native subscription logins or explicitly configured API access. fx, OpenCode, and GitHub Copilot accept explicitly configured native logins, direct API keys, or Vercel AI Gateway access. Cursor uses an explicitly configured native CLI login or Cursor API key.
12
12
 
13
13
  The library coordinates sessions, queues, and subagents. Harnesses own model execution, native tools, and context. You supply the working directory and any sandbox or worktree isolation.
14
14
 
@@ -33,7 +33,7 @@ npx skills add vercel-labs/subharness
33
33
 
34
34
  The installer requires access to the subharness repository while the repository is internal. See the [agent-skill reference](sdk/agent-skill.md) for installation behavior and boundaries.
35
35
 
36
- See [package distribution](sdk/distribution.md) for development checkouts, local tarballs, and package boundaries. subharness uses the [Apache License 2.0](LICENSE).
36
+ See [package distribution](sdk/distribution.md) for development checkouts, local tarballs, and package boundaries. Maintainers publish through the [GitHub release procedure](sdk/distribution.md#github-release-publishing). subharness uses the [Apache License 2.0](LICENSE).
37
37
 
38
38
  ## Delegate from your coding agent
39
39
 
@@ -56,10 +56,13 @@ You can also invoke a harness manually:
56
56
  subharness run claude "Review the current diff."
57
57
  subharness run codex --cwd /path/to/worktree "Implement the documented feature."
58
58
  subharness run fx --model "provider/model" "Compare the proposed implementations."
59
+ subharness run opencode --model "creator/model" "Inspect the current implementation."
60
+ subharness run copilot --model "creator/model" "Review the current diff."
61
+ subharness run cursor --model "CURSOR_MODEL_ID" "Implement the documented change."
59
62
  subharness run claude --help
60
63
  ```
61
64
 
62
- Replace `provider/model` with an available Gateway model identifier. fx requires an explicit Gateway connection as described under Access below. Without `--model`, a direct target uses a verifiable native default for the authorized connection and retains that model for follow-ups. If the default cannot be resolved, the command asks for an explicit model. `--effort` uses the selected harness's supported values. These options do not override a TypeScript specialist.
65
+ Replace `provider/model` or `creator/model` with an available Gateway model identifier. fx, OpenCode, and Copilot require an explicit compatible connection as described under Access below. Non-Gateway routes use their documented native model identifiers. Cursor requires explicit subscription or Cursor API-key access. OpenCode, Copilot, and Cursor require `--model` and reject `--effort`. Codex, Claude Code, and fx use a verifiable native default when possible and accept their documented effort values. These options do not override a TypeScript specialist.
63
66
 
64
67
  Prompts can be one quoted argument, `--prompt`, or a UTF-8 file. `--prompt-file -` reads piped stdin explicitly. Exactly one prompt source is accepted, with a 1 MiB limit.
65
68
 
@@ -68,7 +71,7 @@ subharness run claude --prompt-file ./review-task.txt
68
71
  subharness run codex --prompt-file - < ./task.txt
69
72
  ```
70
73
 
71
- Use `subharness dashboard` in a terminal to watch agents managed by the local coordinator. The live view groups agents by repository/worktree, pins the checkout containing the launch directory first, and orders other groups by their latest agent update. Each group shows current agents followed by finished runs, with harness, task title, elapsed time, and status. Finished history is retained for the coordinator’s lifetime. It has compact group labels and no controls or application banner; Ctrl+C closes the view without stopping agents.
74
+ Use `subharness dashboard` in a terminal to watch agents managed by the local coordinator. The live view groups agents by repository/worktree, pins the checkout containing the launch directory first, and orders other groups by their latest agent update. Each group shows current agents followed by finished runs, with harness, task title, elapsed time, and status. Finished history is retained for the coordinator’s lifetime. Use Up/Down to select a run and Enter to open its agent session’s request history. Queued requests appear first, followed by remaining requests newest first. Enter expands a request’s prompt and response; Escape returns to the overview. Completed statuses are green, and a compact Sub-agents footer summarizes direct child agents. The overview has no application banner or footer. Ctrl+C closes the view without stopping agents.
72
75
 
73
76
  ## Define a reusable specialist
74
77
 
@@ -94,7 +97,7 @@ export default agent({
94
97
  });
95
98
  ```
96
99
 
97
- Replace the model placeholders with identifiers available through your native harnesses. Each file default-exports one definition. Global definitions live in `~/.subharness/agents/`; repository and global names never silently override one another. The bare targets `codex`, `claude`, and `fx` are reserved for harnesses; a specialist with one of those names requires a scope qualifier such as `repo:claude`.
100
+ Replace the model placeholders with identifiers available through your native harnesses. Each file default-exports one definition. Global definitions live in `~/.subharness/agents/`; repository and global names never silently override one another. The bare targets `codex`, `claude`, `fx`, `opencode`, `copilot`, and `cursor` are reserved for harnesses; a specialist with one of those names requires a scope qualifier such as `repo:claude`.
98
101
 
99
102
  ## Run and follow up
100
103
 
@@ -114,7 +117,7 @@ Long prompts can use `--prompt-file`. Output is compact text by default; `--form
114
117
 
115
118
  ## Access
116
119
 
117
- No project configuration is needed when an eligible native subscription login is available. Login remains with the native harness. Ambient API keys do not silently enable paid fallback.
120
+ Codex and Claude Code need no personal access configuration when an eligible native subscription login is available. Other harnesses require an explicit connection. Login remains with the native harness. Ambient API keys do not silently enable paid fallback.
118
121
 
119
122
  Personal access preferences can be placed in the ignored `.subharness/agents.local.json`. Linked worktrees read that file from the main checkout, while their agent definitions come from the selected worktree.
120
123
 
@@ -129,7 +132,7 @@ Personal access preferences can be placed in the ignored `.subharness/agents.loc
129
132
 
130
133
  Only credential references belong in that file. [Access configuration](sdk/access-config.md) also describes direct API keys, project OIDC, explicit connection fallback, and token-lifetime limits.
131
134
 
132
- For [fx](sdk/fx.md), select a Gateway connection explicitly:
135
+ For [fx](sdk/fx.md), select a connection explicitly. This example uses Gateway:
133
136
 
134
137
  ```json
135
138
  {
@@ -141,6 +144,33 @@ For [fx](sdk/fx.md), select a Gateway connection explicitly:
141
144
 
142
145
  Use `fx({ model: "google/gemini-3.8-flash" })` in the agent's `harness` field. Native fx must select the supplied environment credential instead of a saved login. Gateway model and provider restrictions remain effective; catalog availability alone does not establish access for a particular team.
143
146
 
147
+ OpenCode and Copilot use the same explicit Gateway connection types under their own access keys. Cursor accepts an explicit `subscription` connection for the current `cursor-agent login`, or an `api-key` connection that defaults to `CURSOR_API_KEY`. This example selects the local login:
148
+
149
+ ```json
150
+ {
151
+ "access": {
152
+ "opencode": [{ "type": "vercel-api-key" }],
153
+ "copilot": [{ "type": "vercel-oidc", "project": ".", "envFile": ".env.local" }],
154
+ "cursor": [{ "type": "subscription" }]
155
+ }
156
+ }
157
+ ```
158
+
159
+ Gateway is optional for OpenCode and Copilot. For example, select direct Anthropic access in OpenCode and a native GitHub login in Copilot:
160
+
161
+ ```json
162
+ {
163
+ "access": {
164
+ "opencode": [{ "type": "api-key", "provider": "anthropic", "env": "ANTHROPIC_API_KEY" }],
165
+ "copilot": [{ "type": "subscription" }]
166
+ }
167
+ }
168
+ ```
169
+
170
+ Copilot also supports explicit GitHub tokens and OpenAI, Anthropic, or Azure BYOK keys. fx supports its own saved Vercel, Codex, or Grok login and keys for native named Chat Completions connections. Model identifiers and required setup depend on the selected route.
171
+
172
+ See the [OpenCode](sdk/opencode.md), [Copilot](sdk/copilot.md), and [Cursor](sdk/cursor.md) adapter contracts for native behavior.
173
+
144
174
  ## Tools and delegation
145
175
 
146
176
  Agents can expose validated [custom tools](sdk/tools.md) and declare [subagents](sdk/plugins/sub-agents.md). A managed parent invokes its child with the same CLI:
@@ -155,7 +185,7 @@ This checkout includes six [repository roles](sdk/project-team.md): architecture
155
185
 
156
186
  ## Boundaries
157
187
 
158
- The local coordinator retains sessions and responses across command exits, but does not restore queues after coordinator or environment loss. External assistant reactivation depends on that assistant's host. Native requests needing interactive permission/input fail with actionable `INPUT_REQUIRED`; they are not automatically approved. CLI delegation requires the native shell to reach the coordinator over loopback HTTP; a sandbox that blocks local networking must be configured by the caller.
188
+ The local coordinator retains sessions and responses across command exits, but does not restore queues after coordinator or environment loss. External assistant reactivation depends on that assistant's host. Supported native permission requests return structured schemas and keep the original operation pending. The caller answers with `subharness respond <request-id> --content <json>` and observes the same task. See [permission request examples](sdk/approvals.md). Unsupported interactive input still fails with actionable `INPUT_REQUIRED`; no request is automatically approved. CLI delegation requires the native shell to reach the coordinator over loopback HTTP; a sandbox that blocks local networking must be configured by the caller.
159
189
 
160
190
  `resume` is available as a command, but v1 adapters report `RECOVERY_UNSUPPORTED` when prompt-free native recovery is unavailable. Failed work is not automatically replayed or migrated.
161
191
 
@@ -0,0 +1,2 @@
1
+ /** Native envelopes can include private configuration unrelated to the requested action. */
2
+ export declare function approvalContext(source: Record<string, unknown>, fields: readonly string[]): Record<string, unknown>;
@@ -0,0 +1,9 @@
1
+ /** Native envelopes can include private configuration unrelated to the requested action. */
2
+ export function approvalContext(source, fields) {
3
+ const result = {};
4
+ for (const key of fields)
5
+ if (Object.hasOwn(source, key) && source[key] !== undefined)
6
+ result[key] = structuredClone(source[key]);
7
+ return result;
8
+ }
9
+ //# sourceMappingURL=approval-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-context.js","sourceRoot":"","sources":["../../src/adapters/approval-context.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,MAAM,UAAU,eAAe,CAAC,MAA+B,EAAE,MAAyB;IACxF,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,GAAG,IAAI,MAAM;QAAE,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACjI,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["/** Native envelopes can include private configuration unrelated to the requested action. */\nexport function approvalContext(source: Record<string, unknown>, fields: readonly string[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const key of fields) if (Object.hasOwn(source,key) && source[key] !== undefined) result[key] = structuredClone(source[key]);\n return result;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { ApprovalContent, ApprovalHandler, NativeApprovalRequest } from "../approvals/types.js";
2
+ /** Owns callback lifetimes independently of an outstanding native turn. */
3
+ export declare class NativeApprovals {
4
+ private readonly pending;
5
+ request(id: string | number, request: NativeApprovalRequest, handler: ApprovalHandler, parent?: AbortSignal): Promise<ApprovalContent>;
6
+ withdraw(id: string | number): void;
7
+ clear(): void;
8
+ }
@@ -0,0 +1,50 @@
1
+ import { AgentError } from "../errors.js";
2
+ import { validateApprovalContent, validateApprovalSchema } from "../approvals/schema.js";
3
+ /** Owns callback lifetimes independently of an outstanding native turn. */
4
+ export class NativeApprovals {
5
+ pending = new Map();
6
+ async request(id, request, handler, parent) {
7
+ if (this.pending.has(id) || this.pending.size >= 32)
8
+ throw new AgentError("INPUT_REQUIRED", "The native permission request cannot be admitted.");
9
+ let snapshot;
10
+ try {
11
+ const serialized = JSON.stringify(request);
12
+ if (Buffer.byteLength(serialized) > 64 * 1024)
13
+ throw new Error();
14
+ snapshot = JSON.parse(serialized);
15
+ validateApprovalSchema(snapshot.requestedSchema);
16
+ }
17
+ catch {
18
+ throw new AgentError("INPUT_REQUIRED", "The native permission request is unsupported or exceeds the supported size.");
19
+ }
20
+ const schema = structuredClone(snapshot.requestedSchema);
21
+ const controller = new AbortController();
22
+ this.pending.set(id, controller);
23
+ const abort = () => controller.abort();
24
+ parent?.addEventListener("abort", abort, { once: true });
25
+ if (parent?.aborted)
26
+ abort();
27
+ let rejectAbort;
28
+ const withdrawn = new Promise((_resolve, reject) => {
29
+ rejectAbort = () => reject(new AgentError("REQUEST_EXPIRED", "The native permission request is no longer pending."));
30
+ controller.signal.addEventListener("abort", rejectAbort, { once: true });
31
+ });
32
+ try {
33
+ if (controller.signal.aborted)
34
+ throw new AgentError("REQUEST_EXPIRED", "The native permission request is no longer pending.");
35
+ const content = await Promise.race([handler(snapshot, controller.signal), withdrawn]);
36
+ if (controller.signal.aborted)
37
+ throw new AgentError("REQUEST_EXPIRED", "The native permission request is no longer pending.");
38
+ return validateApprovalContent(schema, content);
39
+ }
40
+ finally {
41
+ parent?.removeEventListener("abort", abort);
42
+ controller.signal.removeEventListener("abort", rejectAbort);
43
+ this.pending.delete(id);
44
+ }
45
+ }
46
+ withdraw(id) { this.pending.get(id)?.abort(); }
47
+ clear() { for (const controller of this.pending.values())
48
+ controller.abort(); }
49
+ }
50
+ //# sourceMappingURL=approval-lifetime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-lifetime.js","sourceRoot":"","sources":["../../src/adapters/approval-lifetime.ts"],"names":[],"mappings":"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","sourcesContent":["import { AgentError } from \"../errors.js\";\nimport { validateApprovalContent, validateApprovalSchema } from \"../approvals/schema.js\";\nimport type { ApprovalContent, ApprovalHandler, NativeApprovalRequest } from \"../approvals/types.js\";\n\n/** Owns callback lifetimes independently of an outstanding native turn. */\nexport class NativeApprovals {\n private readonly pending = new Map<string | number, AbortController>();\n\n async request(id: string | number, request: NativeApprovalRequest, handler: ApprovalHandler, parent?: AbortSignal): Promise<ApprovalContent> {\n if (this.pending.has(id) || this.pending.size >= 32) throw new AgentError(\"INPUT_REQUIRED\", \"The native permission request cannot be admitted.\");\n let snapshot: NativeApprovalRequest;\n try {\n const serialized = JSON.stringify(request);\n if (Buffer.byteLength(serialized) > 64 * 1024) throw new Error();\n snapshot = JSON.parse(serialized);\n validateApprovalSchema(snapshot.requestedSchema);\n } catch { throw new AgentError(\"INPUT_REQUIRED\", \"The native permission request is unsupported or exceeds the supported size.\"); }\n const schema = structuredClone(snapshot.requestedSchema);\n const controller = new AbortController();\n this.pending.set(id, controller);\n const abort = () => controller.abort();\n parent?.addEventListener(\"abort\", abort, { once: true });\n if (parent?.aborted) abort();\n let rejectAbort!: () => void;\n const withdrawn = new Promise<never>((_resolve, reject) => {\n rejectAbort = () => reject(new AgentError(\"REQUEST_EXPIRED\", \"The native permission request is no longer pending.\"));\n controller.signal.addEventListener(\"abort\", rejectAbort, { once: true });\n });\n try {\n if (controller.signal.aborted) throw new AgentError(\"REQUEST_EXPIRED\", \"The native permission request is no longer pending.\");\n const content = await Promise.race([handler(snapshot, controller.signal), withdrawn]);\n if (controller.signal.aborted) throw new AgentError(\"REQUEST_EXPIRED\", \"The native permission request is no longer pending.\");\n return validateApprovalContent(schema, content);\n } finally {\n parent?.removeEventListener(\"abort\", abort);\n controller.signal.removeEventListener(\"abort\", rejectAbort);\n this.pending.delete(id);\n }\n }\n\n withdraw(id: string | number): void { this.pending.get(id)?.abort(); }\n clear(): void { for (const controller of this.pending.values()) controller.abort(); }\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { CanUseTool, PermissionResult } from "@anthropic-ai/claude-agent-sdk";
2
+ import type { ApprovalHandler } from "../approvals/types.js";
3
+ import { NativeApprovals } from "./approval-lifetime.js";
4
+ export declare function claudeApproval(approvals: NativeApprovals, handler: ApprovalHandler, toolName: string, input: Record<string, unknown>, metadata: Parameters<CanUseTool>[2]): Promise<PermissionResult>;
@@ -0,0 +1,32 @@
1
+ import { approvalContext } from "./approval-context.js";
2
+ /** Only native session suggestions that add grants can be reused without changing policy. */
3
+ function reusable(suggestions) {
4
+ return !!suggestions?.length && suggestions.every(suggestion => suggestion.destination === "session"
5
+ && ((suggestion.type === "addRules" && suggestion.behavior === "allow" && suggestion.rules.length > 0)
6
+ || (suggestion.type === "addDirectories" && suggestion.directories.length > 0)));
7
+ }
8
+ export async function claudeApproval(approvals, handler, toolName, input, metadata) {
9
+ const originalInput = structuredClone(input);
10
+ const suggestions = metadata.suggestions && structuredClone(metadata.suggestions);
11
+ const session = !metadata.suppressAlwaysAllowRule && reusable(suggestions);
12
+ const request = {
13
+ kind: "permission", harness: "claudeCode", message: metadata.title ?? `Allow native tool ${toolName}?`,
14
+ requestedSchema: { type: "object", properties: { decision: { type: "string", oneOf: [
15
+ { const: "allow_once", title: "Allow once" },
16
+ ...(session ? [{ const: "allow_session", title: "Allow for this session using the suggested permissions" }] : []),
17
+ { const: "deny", title: "Deny" },
18
+ ] } }, required: ["decision"] },
19
+ context: { toolName, input: originalInput, ...approvalContext(metadata, ["blockedPath", "decisionReason", "title", "displayName", "description", "defaultToNo", "suppressAlwaysAllowRule", "toolUseID", "agentID", "requestId"]),
20
+ ...(metadata.matchedAskRule ? { matchedAskRule: approvalContext(metadata.matchedAskRule, ["source", "toolName", "ruleContent"]) } : {}),
21
+ ...(metadata.mcpServer ? { mcpServer: approvalContext(metadata.mcpServer, ["name", "source"]) } : {}),
22
+ ...(suggestions ? { suggestions: suggestions.map(suggestion => ({ ...approvalContext(suggestion, ["type", "destination", "behavior", "mode", "directories"]), ...("rules" in suggestion ? { rules: suggestion.rules.map(rule => approvalContext(rule, ["toolName", "ruleContent"])) } : {}) })) } : {}),
23
+ },
24
+ };
25
+ const content = await approvals.request(metadata.requestId, request, handler, metadata.signal);
26
+ if (metadata.signal.aborted)
27
+ return { behavior: "deny", message: "The permission request is no longer pending." };
28
+ if (content.decision === "deny")
29
+ return { behavior: "deny", message: "The caller denied permission for this tool." };
30
+ return { behavior: "allow", updatedInput: originalInput, ...(content.decision === "allow_session" ? { updatedPermissions: suggestions } : {}) };
31
+ }
32
+ //# sourceMappingURL=claude-approvals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-approvals.js","sourceRoot":"","sources":["../../src/adapters/claude-approvals.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CanUseTool, PermissionResult, PermissionUpdate } from \"@anthropic-ai/claude-agent-sdk\";\nimport type { ApprovalHandler, NativeApprovalRequest } from \"../approvals/types.js\";\nimport { approvalContext } from \"./approval-context.js\";\nimport { NativeApprovals } from \"./approval-lifetime.js\";\n\n/** Only native session suggestions that add grants can be reused without changing policy. */\nfunction reusable(suggestions: PermissionUpdate[] | undefined): suggestions is PermissionUpdate[] {\n return !!suggestions?.length && suggestions.every(suggestion => suggestion.destination === \"session\"\n && ((suggestion.type === \"addRules\" && suggestion.behavior === \"allow\" && suggestion.rules.length > 0)\n || (suggestion.type === \"addDirectories\" && suggestion.directories.length > 0)));\n}\nexport async function claudeApproval(\n approvals: NativeApprovals, handler: ApprovalHandler, toolName: string,\n input: Record<string, unknown>, metadata: Parameters<CanUseTool>[2],\n): Promise<PermissionResult> {\n const originalInput = structuredClone(input);\n const suggestions = metadata.suggestions && structuredClone(metadata.suggestions);\n const session = !metadata.suppressAlwaysAllowRule && reusable(suggestions);\n const request: NativeApprovalRequest = {\n kind: \"permission\", harness: \"claudeCode\", message: metadata.title ?? `Allow native tool ${toolName}?`,\n requestedSchema: {type:\"object\",properties:{decision:{type:\"string\",oneOf:[\n {const:\"allow_once\",title:\"Allow once\"},\n ...(session ? [{const:\"allow_session\",title:\"Allow for this session using the suggested permissions\"}] : []),\n {const:\"deny\",title:\"Deny\"},\n ]}},required:[\"decision\"]},\n context: {toolName,input:originalInput,...approvalContext(metadata,[\"blockedPath\",\"decisionReason\",\"title\",\"displayName\",\"description\",\"defaultToNo\",\"suppressAlwaysAllowRule\",\"toolUseID\",\"agentID\",\"requestId\"]),\n ...(metadata.matchedAskRule ? {matchedAskRule:approvalContext(metadata.matchedAskRule,[\"source\",\"toolName\",\"ruleContent\"])} : {}),\n ...(metadata.mcpServer ? {mcpServer:approvalContext(metadata.mcpServer,[\"name\",\"source\"])} : {}),\n ...(suggestions ? {suggestions:suggestions.map(suggestion=>({...approvalContext(suggestion,[\"type\",\"destination\",\"behavior\",\"mode\",\"directories\"]),...(\"rules\" in suggestion ? {rules:suggestion.rules.map(rule=>approvalContext(rule,[\"toolName\",\"ruleContent\"]))} : {})}))} : {}),\n },\n };\n const content = await approvals.request(metadata.requestId, request, handler, metadata.signal);\n if (metadata.signal.aborted) return {behavior:\"deny\",message:\"The permission request is no longer pending.\"};\n if (content.decision === \"deny\") return {behavior:\"deny\",message:\"The caller denied permission for this tool.\"};\n return {behavior:\"allow\",updatedInput:originalInput,...(content.decision === \"allow_session\" ? {updatedPermissions:suggestions} : {})};\n}\n"]}
@@ -17,7 +17,7 @@ export function claudeDelegationPermissions(options) {
17
17
  launchers.push(path, `"${path}"`);
18
18
  const commands = [
19
19
  ...names.map(name => `run subagent:${name}`),
20
- "list", "--help", "send", "wait", "status", "queue", "cancel", "resume",
20
+ "list", "--help", "send", "wait", "status", "queue", "cancel", "resume", "respond",
21
21
  ];
22
22
  return commands.flatMap(command => launchers.map(launcher => `Bash(${launcher} ${command} *)`));
23
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"claude-permissions.js","sourceRoot":"","sources":["../../src/adapters/claude-permissions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,oFAAoF;AACpF,MAAM,UAAU,2BAA2B,CAAC,OAAuB;IACjE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IACzD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACxC,8EAA8E;IAC9E,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,kHAAkH,CAAC,CAAC;IAC7J,CAAC;IACD,MAAM,SAAS,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,gFAAgF;IAChF,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG;QACf,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,gBAAgB,IAAI,EAAE,CAAC;QAC5C,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ;KACxE,CAAC;IACF,OAAO,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,QAAQ,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC;AAClG,CAAC","sourcesContent":["import type { AdapterOptions } from \"./types.js\";\nimport { shellQuote } from \"../shell.js\";\nimport { isAbsolute } from \"node:path\";\nimport { AgentError } from \"../errors.js\";\n\n/** Only the native permission evaluator decides whether a shell call is allowed. */\nexport function claudeDelegationPermissions(options: AdapterOptions): string[] {\n const names = Object.keys(options.agent.subagents ?? {});\n if (names.length === 0) return [];\n const path = options.env.AGENT_CLI_PATH;\n // Bash rules treat '*' as a wildcard even when it occurs inside shell quotes.\n if (!path || !isAbsolute(path) || /[\\x00-\\x1f\\x7f*]/u.test(path)) {\n throw new AgentError(\"INVALID_CONFIG\", \"The session launcher needs an absolute path without wildcards or control characters for Claude Code permissions.\");\n }\n const launchers = [shellQuote(path)];\n // Native matching is textual: harmless quote changes need exact separate rules.\n if (/^[A-Za-z0-9_./-]+$/u.test(path)) launchers.push(path, `\"${path}\"`);\n const commands = [\n ...names.map(name => `run subagent:${name}`),\n \"list\", \"--help\", \"send\", \"wait\", \"status\", \"queue\", \"cancel\", \"resume\",\n ];\n return commands.flatMap(command => launchers.map(launcher => `Bash(${launcher} ${command} *)`));\n}\n"]}
1
+ {"version":3,"file":"claude-permissions.js","sourceRoot":"","sources":["../../src/adapters/claude-permissions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,oFAAoF;AACpF,MAAM,UAAU,2BAA2B,CAAC,OAAuB;IACjE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IACzD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACxC,8EAA8E;IAC9E,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,kHAAkH,CAAC,CAAC;IAC7J,CAAC;IACD,MAAM,SAAS,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,gFAAgF;IAChF,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG;QACf,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,gBAAgB,IAAI,EAAE,CAAC;QAC5C,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS;KACnF,CAAC;IACF,OAAO,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,QAAQ,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC;AAClG,CAAC","sourcesContent":["import type { AdapterOptions } from \"./types.js\";\nimport { shellQuote } from \"../shell.js\";\nimport { isAbsolute } from \"node:path\";\nimport { AgentError } from \"../errors.js\";\n\n/** Only the native permission evaluator decides whether a shell call is allowed. */\nexport function claudeDelegationPermissions(options: AdapterOptions): string[] {\n const names = Object.keys(options.agent.subagents ?? {});\n if (names.length === 0) return [];\n const path = options.env.AGENT_CLI_PATH;\n // Bash rules treat '*' as a wildcard even when it occurs inside shell quotes.\n if (!path || !isAbsolute(path) || /[\\x00-\\x1f\\x7f*]/u.test(path)) {\n throw new AgentError(\"INVALID_CONFIG\", \"The session launcher needs an absolute path without wildcards or control characters for Claude Code permissions.\");\n }\n const launchers = [shellQuote(path)];\n // Native matching is textual: harmless quote changes need exact separate rules.\n if (/^[A-Za-z0-9_./-]+$/u.test(path)) launchers.push(path, `\"${path}\"`);\n const commands = [\n ...names.map(name => `run subagent:${name}`),\n \"list\", \"--help\", \"send\", \"wait\", \"status\", \"queue\", \"cancel\", \"resume\", \"respond\",\n ];\n return commands.flatMap(command => launchers.map(launcher => `Bash(${launcher} ${command} *)`));\n}\n"]}
@@ -4,7 +4,10 @@ export declare class ClaudeProcessOwner {
4
4
  private child?;
5
5
  private exited?;
6
6
  private closing?;
7
+ private exitCode;
8
+ private exitSignal;
7
9
  readonly spawn: (options: SpawnOptions) => SpawnedProcess;
10
+ exitDescription(): string;
8
11
  close(): Promise<void>;
9
12
  private stop;
10
13
  }
@@ -1,5 +1,6 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { AgentError } from '../errors.js';
3
+ import { processExitDescription } from '../process-diagnostics.js';
3
4
  const gracefulExitMs = 2_000;
4
5
  const terminatedExitMs = 5_000;
5
6
  const killedExitMs = 1_000;
@@ -14,6 +15,8 @@ export class ClaudeProcessOwner {
14
15
  child;
15
16
  exited;
16
17
  closing;
18
+ exitCode;
19
+ exitSignal;
17
20
  spawn = (options) => {
18
21
  if (this.child)
19
22
  throw new AgentError('HARNESS_FAILED', 'Claude Code attempted to start more than one native process.');
@@ -26,12 +29,19 @@ export class ClaudeProcessOwner {
26
29
  });
27
30
  this.child = child;
28
31
  this.exited = new Promise(resolve => {
29
- child.once('exit', () => resolve());
32
+ child.once('exit', (code, signal) => {
33
+ this.exitCode = code;
34
+ this.exitSignal = signal;
35
+ resolve();
36
+ });
30
37
  child.once('error', () => { if (child.pid === undefined)
31
38
  resolve(); });
32
39
  });
33
40
  return child;
34
41
  };
42
+ exitDescription() {
43
+ return processExitDescription(this.exitCode, this.exitSignal);
44
+ }
35
45
  close() {
36
46
  return this.closing ??= this.stop();
37
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"claude-process.js","sourceRoot":"","sources":["../../src/adapters/claude-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA4B,MAAM,oBAAoB,CAAC;AAGrE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,cAAc,GAAG,KAAK,CAAC;AAC7B,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,YAAY,GAAG,KAAK,CAAC;AAE3B,SAAS,WAAW,CAAC,MAAqB,EAAE,OAAe;IACzD,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAC,OAAO,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,MAAM,OAAO,kBAAkB;IACrB,KAAK,CAA+C;IACpD,MAAM,CAAiB;IACvB,OAAO,CAAiB;IAEvB,KAAK,GAAG,CAAC,OAAqB,EAAkB,EAAE;QACzD,IAAI,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,8DAA8D,CAAC,CAAC;QACtH,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,EAAC,OAAO,CAAC,IAAI,EAAC;YAC/C,GAAG,EAAC,OAAO,CAAC,GAAG;YACf,GAAG,EAAC,OAAO,CAAC,GAAG;YACf,MAAM,EAAC,OAAO,CAAC,MAAM;YACrB,KAAK,EAAC,CAAC,MAAM,EAAC,MAAM,EAAC,QAAQ,CAAC;YAC9B,WAAW,EAAC,IAAI;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;YAClC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAC,GAAG,EAAE,GAAG,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,KAAK;QACH,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;IACtC,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM;YAAE,OAAO;QAC9B,IAAI,CAAC;YAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,sCAAsC,CAAC,CAAC;QAC3E,IAAI,MAAM,WAAW,CAAC,MAAM,EAAC,cAAc,CAAC;YAAE,OAAO;QACrD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtB,IAAI,MAAM,WAAW,CAAC,MAAM,EAAC,gBAAgB,CAAC;YAAE,OAAO;QACvD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtB,IAAI,MAAM,WAAW,CAAC,MAAM,EAAC,YAAY,CAAC;YAAE,OAAO;QACnD,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,yDAAyD,CAAC,CAAC;IACnG,CAAC;CACF","sourcesContent":["import { spawn, type ChildProcessByStdio } from 'node:child_process';\nimport type { Readable, Writable } from 'node:stream';\nimport type { SpawnedProcess, SpawnOptions } from '@anthropic-ai/claude-agent-sdk';\nimport { AgentError } from '../errors.js';\n\nconst gracefulExitMs = 2_000;\nconst terminatedExitMs = 5_000;\nconst killedExitMs = 1_000;\n\nfunction exitsWithin(exited: Promise<void>, timeout: number): Promise<boolean> {\n return new Promise(resolve => {\n const timer = setTimeout(() => resolve(false),timeout);\n exited.then(() => { clearTimeout(timer); resolve(true); });\n });\n}\n\n/** Retains the concrete SDK subprocess until its termination is confirmed. */\nexport class ClaudeProcessOwner {\n private child?: ChildProcessByStdio<Writable,Readable,null>;\n private exited?: Promise<void>;\n private closing?: Promise<void>;\n\n readonly spawn = (options: SpawnOptions): SpawnedProcess => {\n if (this.child) throw new AgentError('HARNESS_FAILED','Claude Code attempted to start more than one native process.');\n const child = spawn(options.command,options.args,{\n cwd:options.cwd,\n env:options.env,\n signal:options.signal,\n stdio:['pipe','pipe','ignore'],\n windowsHide:true,\n });\n this.child = child;\n this.exited = new Promise(resolve => {\n child.once('exit',() => resolve());\n child.once('error',() => { if (child.pid === undefined) resolve(); });\n });\n return child;\n };\n\n close(): Promise<void> {\n return this.closing ??= this.stop();\n }\n\n private async stop(): Promise<void> {\n const child = this.child;\n const exited = this.exited;\n if (!child || !exited) return;\n try { child.stdin.end(); } catch { /* Continue to bounded termination. */ }\n if (await exitsWithin(exited,gracefulExitMs)) return;\n child.kill('SIGTERM');\n if (await exitsWithin(exited,terminatedExitMs)) return;\n child.kill('SIGKILL');\n if (await exitsWithin(exited,killedExitMs)) return;\n throw new AgentError('HARNESS_FAILED','Claude Code process termination could not be confirmed.');\n }\n}\n"]}
1
+ {"version":3,"file":"claude-process.js","sourceRoot":"","sources":["../../src/adapters/claude-process.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, type ChildProcessByStdio } from 'node:child_process';\nimport type { Readable, Writable } from 'node:stream';\nimport type { SpawnedProcess, SpawnOptions } from '@anthropic-ai/claude-agent-sdk';\nimport { AgentError } from '../errors.js';\nimport { processExitDescription } from '../process-diagnostics.js';\n\nconst gracefulExitMs = 2_000;\nconst terminatedExitMs = 5_000;\nconst killedExitMs = 1_000;\n\nfunction exitsWithin(exited: Promise<void>, timeout: number): Promise<boolean> {\n return new Promise(resolve => {\n const timer = setTimeout(() => resolve(false),timeout);\n exited.then(() => { clearTimeout(timer); resolve(true); });\n });\n}\n\n/** Retains the concrete SDK subprocess until its termination is confirmed. */\nexport class ClaudeProcessOwner {\n private child?: ChildProcessByStdio<Writable,Readable,null>;\n private exited?: Promise<void>;\n private closing?: Promise<void>;\n private exitCode: unknown;\n private exitSignal: unknown;\n\n readonly spawn = (options: SpawnOptions): SpawnedProcess => {\n if (this.child) throw new AgentError('HARNESS_FAILED','Claude Code attempted to start more than one native process.');\n const child = spawn(options.command,options.args,{\n cwd:options.cwd,\n env:options.env,\n signal:options.signal,\n stdio:['pipe','pipe','ignore'],\n windowsHide:true,\n });\n this.child = child;\n this.exited = new Promise(resolve => {\n child.once('exit',(code,signal) => {\n this.exitCode = code;\n this.exitSignal = signal;\n resolve();\n });\n child.once('error',() => { if (child.pid === undefined) resolve(); });\n });\n return child;\n };\n\n exitDescription(): string {\n return processExitDescription(this.exitCode,this.exitSignal);\n }\n\n close(): Promise<void> {\n return this.closing ??= this.stop();\n }\n\n private async stop(): Promise<void> {\n const child = this.child;\n const exited = this.exited;\n if (!child || !exited) return;\n try { child.stdin.end(); } catch { /* Continue to bounded termination. */ }\n if (await exitsWithin(exited,gracefulExitMs)) return;\n child.kill('SIGTERM');\n if (await exitsWithin(exited,terminatedExitMs)) return;\n child.kill('SIGKILL');\n if (await exitsWithin(exited,killedExitMs)) return;\n throw new AgentError('HARNESS_FAILED','Claude Code process termination could not be confirmed.');\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import { AgentError } from "../errors.js";
2
+ export declare function claudeResultFailure(subtype: unknown): AgentError;
@@ -0,0 +1,22 @@
1
+ import { AgentError } from "../errors.js";
2
+ export function claudeResultFailure(subtype) {
3
+ let message;
4
+ switch (subtype) {
5
+ case "error_max_turns":
6
+ message = "Claude Code reached its native turn limit.";
7
+ break;
8
+ case "error_max_budget_usd":
9
+ message = "Claude Code reached its native budget limit.";
10
+ break;
11
+ case "error_max_structured_output_retries":
12
+ message = "Claude Code exhausted its native structured-output retries.";
13
+ break;
14
+ case "error_during_execution":
15
+ message = "Claude Code reported an error during execution.";
16
+ break;
17
+ default:
18
+ message = "Claude Code could not complete the turn.";
19
+ }
20
+ return new AgentError("HARNESS_ERROR", message);
21
+ }
22
+ //# sourceMappingURL=claude-result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-result.js","sourceRoot":"","sources":["../../src/adapters/claude-result.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,IAAI,OAAe,CAAC;IACpB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,iBAAiB;YACpB,OAAO,GAAG,4CAA4C,CAAC;YACvD,MAAM;QACR,KAAK,sBAAsB;YACzB,OAAO,GAAG,8CAA8C,CAAC;YACzD,MAAM;QACR,KAAK,qCAAqC;YACxC,OAAO,GAAG,6DAA6D,CAAC;YACxE,MAAM;QACR,KAAK,wBAAwB;YAC3B,OAAO,GAAG,iDAAiD,CAAC;YAC5D,MAAM;QACR;YACE,OAAO,GAAG,0CAA0C,CAAC;IACzD,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;AAClD,CAAC","sourcesContent":["import { AgentError } from \"../errors.js\";\n\nexport function claudeResultFailure(subtype: unknown): AgentError {\n let message: string;\n switch (subtype) {\n case \"error_max_turns\":\n message = \"Claude Code reached its native turn limit.\";\n break;\n case \"error_max_budget_usd\":\n message = \"Claude Code reached its native budget limit.\";\n break;\n case \"error_max_structured_output_retries\":\n message = \"Claude Code exhausted its native structured-output retries.\";\n break;\n case \"error_during_execution\":\n message = \"Claude Code reported an error during execution.\";\n break;\n default:\n message = \"Claude Code could not complete the turn.\";\n }\n return new AgentError(\"HARNESS_ERROR\", message);\n}\n"]}