@agentex/agent 0.0.1 → 0.0.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 (198) hide show
  1. package/README.md +358 -78
  2. package/dist/index.d.ts +16 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +10 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/providers/claude/execute.d.ts +1 -1
  7. package/dist/providers/claude/execute.d.ts.map +1 -1
  8. package/dist/providers/claude/execute.js +53 -20
  9. package/dist/providers/claude/execute.js.map +1 -1
  10. package/dist/providers/claude/index.d.ts +1 -1
  11. package/dist/providers/claude/index.d.ts.map +1 -1
  12. package/dist/providers/claude/index.js +40 -9
  13. package/dist/providers/claude/index.js.map +1 -1
  14. package/dist/providers/claude/parse.d.ts.map +1 -1
  15. package/dist/providers/claude/parse.js +2 -1
  16. package/dist/providers/claude/parse.js.map +1 -1
  17. package/dist/providers/claude/session.d.ts +10 -0
  18. package/dist/providers/claude/session.d.ts.map +1 -0
  19. package/dist/providers/claude/session.js +549 -0
  20. package/dist/providers/claude/session.js.map +1 -0
  21. package/dist/providers/claude/test.d.ts.map +1 -1
  22. package/dist/providers/claude/test.js +38 -11
  23. package/dist/providers/claude/test.js.map +1 -1
  24. package/dist/providers/codex/execute.d.ts +1 -1
  25. package/dist/providers/codex/execute.d.ts.map +1 -1
  26. package/dist/providers/codex/execute.js +114 -75
  27. package/dist/providers/codex/execute.js.map +1 -1
  28. package/dist/providers/codex/index.d.ts +1 -1
  29. package/dist/providers/codex/index.d.ts.map +1 -1
  30. package/dist/providers/codex/index.js +59 -3
  31. package/dist/providers/codex/index.js.map +1 -1
  32. package/dist/providers/codex/parse.d.ts.map +1 -1
  33. package/dist/providers/codex/parse.js +25 -3
  34. package/dist/providers/codex/parse.js.map +1 -1
  35. package/dist/providers/codex/session.d.ts +3 -0
  36. package/dist/providers/codex/session.d.ts.map +1 -0
  37. package/dist/providers/codex/session.js +553 -0
  38. package/dist/providers/codex/session.js.map +1 -0
  39. package/dist/providers/codex/test.d.ts.map +1 -1
  40. package/dist/providers/codex/test.js +28 -12
  41. package/dist/providers/codex/test.js.map +1 -1
  42. package/dist/providers/codex/usage-scanner.d.ts +18 -0
  43. package/dist/providers/codex/usage-scanner.d.ts.map +1 -0
  44. package/dist/providers/codex/usage-scanner.js +148 -0
  45. package/dist/providers/codex/usage-scanner.js.map +1 -0
  46. package/dist/providers/cursor/codec.d.ts +3 -0
  47. package/dist/providers/cursor/codec.d.ts.map +1 -0
  48. package/dist/providers/cursor/codec.js +43 -0
  49. package/dist/providers/cursor/codec.js.map +1 -0
  50. package/dist/providers/cursor/execute.d.ts +3 -0
  51. package/dist/providers/cursor/execute.d.ts.map +1 -0
  52. package/dist/providers/cursor/execute.js +248 -0
  53. package/dist/providers/cursor/execute.js.map +1 -0
  54. package/dist/providers/cursor/index.d.ts +3 -0
  55. package/dist/providers/cursor/index.d.ts.map +1 -0
  56. package/dist/providers/cursor/index.js +30 -0
  57. package/dist/providers/cursor/index.js.map +1 -0
  58. package/dist/providers/cursor/parse.d.ts +26 -0
  59. package/dist/providers/cursor/parse.d.ts.map +1 -0
  60. package/dist/providers/cursor/parse.js +224 -0
  61. package/dist/providers/cursor/parse.js.map +1 -0
  62. package/dist/providers/cursor/test.d.ts +3 -0
  63. package/dist/providers/cursor/test.d.ts.map +1 -0
  64. package/dist/providers/cursor/test.js +58 -0
  65. package/dist/providers/cursor/test.js.map +1 -0
  66. package/dist/providers/gemini/codec.d.ts +3 -0
  67. package/dist/providers/gemini/codec.d.ts.map +1 -0
  68. package/dist/providers/gemini/codec.js +47 -0
  69. package/dist/providers/gemini/codec.js.map +1 -0
  70. package/dist/providers/gemini/execute.d.ts +3 -0
  71. package/dist/providers/gemini/execute.d.ts.map +1 -0
  72. package/dist/providers/gemini/execute.js +236 -0
  73. package/dist/providers/gemini/execute.js.map +1 -0
  74. package/dist/providers/gemini/index.d.ts +3 -0
  75. package/dist/providers/gemini/index.d.ts.map +1 -0
  76. package/dist/providers/gemini/index.js +64 -0
  77. package/dist/providers/gemini/index.js.map +1 -0
  78. package/dist/providers/gemini/parse.d.ts +20 -0
  79. package/dist/providers/gemini/parse.d.ts.map +1 -0
  80. package/dist/providers/gemini/parse.js +207 -0
  81. package/dist/providers/gemini/parse.js.map +1 -0
  82. package/dist/providers/gemini/test.d.ts +3 -0
  83. package/dist/providers/gemini/test.d.ts.map +1 -0
  84. package/dist/providers/gemini/test.js +67 -0
  85. package/dist/providers/gemini/test.js.map +1 -0
  86. package/dist/providers/openclaw/execute.d.ts +1 -1
  87. package/dist/providers/openclaw/execute.d.ts.map +1 -1
  88. package/dist/providers/openclaw/execute.js +11 -6
  89. package/dist/providers/openclaw/execute.js.map +1 -1
  90. package/dist/providers/openclaw/index.d.ts +1 -1
  91. package/dist/providers/openclaw/index.d.ts.map +1 -1
  92. package/dist/providers/openclaw/index.js +13 -3
  93. package/dist/providers/openclaw/index.js.map +1 -1
  94. package/dist/providers/openclaw/test.d.ts.map +1 -1
  95. package/dist/providers/openclaw/test.js +4 -0
  96. package/dist/providers/openclaw/test.js.map +1 -1
  97. package/dist/providers/opencode/codec.d.ts +3 -0
  98. package/dist/providers/opencode/codec.d.ts.map +1 -0
  99. package/dist/providers/opencode/codec.js +47 -0
  100. package/dist/providers/opencode/codec.js.map +1 -0
  101. package/dist/providers/opencode/execute.d.ts +3 -0
  102. package/dist/providers/opencode/execute.d.ts.map +1 -0
  103. package/dist/providers/opencode/execute.js +225 -0
  104. package/dist/providers/opencode/execute.js.map +1 -0
  105. package/dist/providers/opencode/index.d.ts +3 -0
  106. package/dist/providers/opencode/index.d.ts.map +1 -0
  107. package/dist/providers/opencode/index.js +64 -0
  108. package/dist/providers/opencode/index.js.map +1 -0
  109. package/dist/providers/opencode/parse.d.ts +19 -0
  110. package/dist/providers/opencode/parse.d.ts.map +1 -0
  111. package/dist/providers/opencode/parse.js +145 -0
  112. package/dist/providers/opencode/parse.js.map +1 -0
  113. package/dist/providers/opencode/test.d.ts +3 -0
  114. package/dist/providers/opencode/test.d.ts.map +1 -0
  115. package/dist/providers/opencode/test.js +60 -0
  116. package/dist/providers/opencode/test.js.map +1 -0
  117. package/dist/providers/pi/codec.d.ts +7 -0
  118. package/dist/providers/pi/codec.d.ts.map +1 -0
  119. package/dist/providers/pi/codec.js +45 -0
  120. package/dist/providers/pi/codec.js.map +1 -0
  121. package/dist/providers/pi/execute.d.ts +3 -0
  122. package/dist/providers/pi/execute.d.ts.map +1 -0
  123. package/dist/providers/pi/execute.js +300 -0
  124. package/dist/providers/pi/execute.js.map +1 -0
  125. package/dist/providers/pi/index.d.ts +3 -0
  126. package/dist/providers/pi/index.d.ts.map +1 -0
  127. package/dist/providers/pi/index.js +66 -0
  128. package/dist/providers/pi/index.js.map +1 -0
  129. package/dist/providers/pi/parse.d.ts +18 -0
  130. package/dist/providers/pi/parse.d.ts.map +1 -0
  131. package/dist/providers/pi/parse.js +182 -0
  132. package/dist/providers/pi/parse.js.map +1 -0
  133. package/dist/providers/pi/test.d.ts +3 -0
  134. package/dist/providers/pi/test.d.ts.map +1 -0
  135. package/dist/providers/pi/test.js +60 -0
  136. package/dist/providers/pi/test.js.map +1 -0
  137. package/dist/providers/process/execute.d.ts +1 -1
  138. package/dist/providers/process/execute.d.ts.map +1 -1
  139. package/dist/providers/process/execute.js +46 -8
  140. package/dist/providers/process/execute.js.map +1 -1
  141. package/dist/providers/process/index.d.ts +1 -1
  142. package/dist/providers/process/index.d.ts.map +1 -1
  143. package/dist/providers/process/index.js +18 -4
  144. package/dist/providers/process/index.js.map +1 -1
  145. package/dist/registry.d.ts.map +1 -1
  146. package/dist/registry.js +16 -8
  147. package/dist/registry.js.map +1 -1
  148. package/dist/types.d.ts +325 -8
  149. package/dist/types.d.ts.map +1 -1
  150. package/dist/types.js +23 -1
  151. package/dist/types.js.map +1 -1
  152. package/dist/utils/ask-user-question.d.ts +50 -0
  153. package/dist/utils/ask-user-question.d.ts.map +1 -0
  154. package/dist/utils/ask-user-question.js +32 -0
  155. package/dist/utils/ask-user-question.js.map +1 -0
  156. package/dist/utils/auth.d.ts +29 -0
  157. package/dist/utils/auth.d.ts.map +1 -0
  158. package/dist/utils/auth.js +243 -0
  159. package/dist/utils/auth.js.map +1 -0
  160. package/dist/utils/binary.d.ts.map +1 -1
  161. package/dist/utils/binary.js +29 -6
  162. package/dist/utils/binary.js.map +1 -1
  163. package/dist/utils/env.d.ts.map +1 -1
  164. package/dist/utils/env.js +18 -0
  165. package/dist/utils/env.js.map +1 -1
  166. package/dist/utils/execute-all.d.ts +20 -0
  167. package/dist/utils/execute-all.d.ts.map +1 -0
  168. package/dist/utils/execute-all.js +46 -0
  169. package/dist/utils/execute-all.js.map +1 -0
  170. package/dist/utils/instructions.d.ts +7 -0
  171. package/dist/utils/instructions.d.ts.map +1 -0
  172. package/dist/utils/instructions.js +21 -0
  173. package/dist/utils/instructions.js.map +1 -0
  174. package/dist/utils/model-cache.d.ts +11 -0
  175. package/dist/utils/model-cache.d.ts.map +1 -0
  176. package/dist/utils/model-cache.js +17 -0
  177. package/dist/utils/model-cache.js.map +1 -0
  178. package/dist/utils/process.d.ts +4 -0
  179. package/dist/utils/process.d.ts.map +1 -1
  180. package/dist/utils/process.js +46 -5
  181. package/dist/utils/process.js.map +1 -1
  182. package/dist/utils/runtime-config.d.ts +34 -0
  183. package/dist/utils/runtime-config.d.ts.map +1 -0
  184. package/dist/utils/runtime-config.js +71 -0
  185. package/dist/utils/runtime-config.js.map +1 -0
  186. package/dist/utils/runtime-homes.d.ts +13 -0
  187. package/dist/utils/runtime-homes.d.ts.map +1 -0
  188. package/dist/utils/runtime-homes.js +41 -0
  189. package/dist/utils/runtime-homes.js.map +1 -0
  190. package/dist/utils/skills.d.ts +152 -1
  191. package/dist/utils/skills.d.ts.map +1 -1
  192. package/dist/utils/skills.js +352 -0
  193. package/dist/utils/skills.js.map +1 -1
  194. package/dist/utils/workspace.d.ts +55 -0
  195. package/dist/utils/workspace.d.ts.map +1 -0
  196. package/dist/utils/workspace.js +89 -0
  197. package/dist/utils/workspace.js.map +1 -0
  198. package/package.json +5 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @agentex/agent
2
2
 
3
- Programmatic execution of AI coding agents. Spawn and manage Claude Code, Codex, OpenClaw, or any CLI-based agent as a child process with streaming output, session resume, and a unified interface.
3
+ Programmatic execution of AI coding agents. Spawn and manage Claude Code, Codex, Gemini, Cursor, OpenCode, Pi, OpenClaw, or any CLI-based agent as a child process with streaming output, multi-turn sessions, auth detection, isolated workspaces, skill installation, and a unified interface.
4
4
 
5
5
  ## Install
6
6
 
@@ -8,6 +8,8 @@ Programmatic execution of AI coding agents. Spawn and manage Claude Code, Codex,
8
8
  npm install @agentex/agent
9
9
  ```
10
10
 
11
+ Node.js >= 18. Each provider requires its CLI to be installed and on `$PATH`.
12
+
11
13
  ## Quick Start
12
14
 
13
15
  ```typescript
@@ -28,21 +30,313 @@ const result = await claude.execute({
28
30
  },
29
31
  });
30
32
 
31
- console.log(result.exitCode); // 0
33
+ console.log(result.status); // "completed"
32
34
  console.log(result.summary); // "Added try/catch to all route handlers..."
33
35
  console.log(result.durationMs); // 12340
34
36
  console.log(result.costUsd); // 0.0342
35
- console.log(result.usage); // { inputTokens: 1200, outputTokens: 350, cachedInputTokens: 800 }
37
+ console.log(result.usage); // { "claude-sonnet-4-6": { inputTokens: 1200, outputTokens: 350, ... } }
36
38
  ```
37
39
 
38
40
  ## Built-in Providers
39
41
 
40
- | Provider | CLI | Description |
41
- | ---------- | ---------------- | ----------------------------------- |
42
- | `claude` | `claude` | Claude Code (Anthropic) |
43
- | `codex` | `codex` | Codex CLI (OpenAI) |
44
- | `openclaw` | `openclaw` | OpenClaw agent |
45
- | `process` | any executable | Generic process executor |
42
+ | Provider | CLI | Description |
43
+ | ---------- | ---------------- | ------------------------------------------- |
44
+ | `claude` | `claude` | Claude Code (Anthropic) |
45
+ | `codex` | `codex` | Codex CLI (OpenAI) |
46
+ | `gemini` | `gemini` | Gemini CLI (Google) |
47
+ | `cursor` | `agent` | Cursor CLI agent |
48
+ | `opencode` | `opencode` | OpenCode |
49
+ | `pi` | `pi` | Pi CLI |
50
+ | `openclaw` | gateway HTTP | OpenClaw HTTP-gateway agent |
51
+ | `process` | any executable | Generic process executor (arbitrary binary) |
52
+
53
+ Provider capabilities (sessions, skills, workspaces, MCP, model discovery, quota probing, instructions) are declared on each module's `capabilities` field — check `provider.capabilities` to branch on what's supported.
54
+
55
+ ## Execution Context
56
+
57
+ Only `prompt` is required. Everything else has sensible defaults.
58
+
59
+ ```typescript
60
+ interface ExecutionContext {
61
+ prompt: string;
62
+ model?: string;
63
+ runId?: string; // Auto-generated UUIDv7 if omitted
64
+ cwd?: string; // Defaults to process.cwd()
65
+ env?: Record<string, string>;
66
+ sessionParams?: Record<string, unknown> | null;
67
+ config?: ProviderConfig;
68
+ signal?: AbortSignal; // Cancellation — SIGTERM then SIGKILL after graceSec
69
+ onOutput?: (stream: "stdout" | "stderr", chunk: string) => void | Promise<void>;
70
+ onEvent?: (event: StreamEvent) => void | Promise<void>;
71
+ onStart?: (pid: number) => void;
72
+ onLifecycle?: (event: LifecycleEvent) => void;
73
+ }
74
+ ```
75
+
76
+ `ProviderConfig` covers the knobs most providers accept:
77
+
78
+ ```typescript
79
+ interface ProviderConfig {
80
+ command?: string; // Override CLI binary path
81
+ model?: string;
82
+ effort?: string;
83
+ maxTurns?: number;
84
+ timeoutSec?: number;
85
+ graceSec?: number;
86
+ skipPermissions?: boolean;
87
+ skillDirs?: string[];
88
+ instructionsFile?: string;
89
+ mcpServers?: McpServerConfig[];
90
+ extraArgs?: string[];
91
+ search?: boolean;
92
+ sandbox?: boolean;
93
+ thinking?: string;
94
+ mode?: string;
95
+ workspace?: { strategy: "worktree"; baseBranch?: string; branchName?: string };
96
+ }
97
+ ```
98
+
99
+ ## Execution Result
100
+
101
+ ```typescript
102
+ interface ExecutionResult {
103
+ runId: string;
104
+ exitCode: number | null;
105
+ signal: string | null;
106
+ status: ExecutionStatus; // "completed" | "failed" | "aborted" | "timeout" | "blocked"
107
+ startedAt: string; // ISO timestamp
108
+ completedAt: string;
109
+ durationMs: number;
110
+ errorMessage: string | null;
111
+ errorCode: string | null;
112
+ usage?: Record<string, TokenUsage>; // keyed by model ID
113
+ costUsd: number | null;
114
+ model: string | null;
115
+ summary: string | null;
116
+ sessionParams: Record<string, unknown> | null;
117
+ sessionDisplayId: string | null;
118
+ clearSession: boolean;
119
+ billingType: "api" | "subscription" | "metered_api" | null;
120
+ raw?: Record<string, unknown> | null;
121
+ workspace?: PreparedWorkspace; // Present if config.workspace was set
122
+ }
123
+ ```
124
+
125
+ Use `aggregateUsage(result.usage)` to collapse per-model usage into a single total.
126
+
127
+ ## Stream Events
128
+
129
+ Emitted during execution via `onEvent`. All events include `timestamp`.
130
+
131
+ - `system` — Session init (`sessionId`, `model`, `subtype`)
132
+ - `assistant` — Text output from the agent (`text`)
133
+ - `thinking` — Agent's internal reasoning (`text`)
134
+ - `tool_call` — Agent invoked a tool (`name`, `input`, `callId?`)
135
+ - `tool_result` — Tool returned a result (`toolCallId`, `content`, `isError`)
136
+ - `result` — Final result (`text`, `cost`, `isError`)
137
+
138
+ Lifecycle events (via `onLifecycle`) report phases: `preparing`, `spawning`, `running`, `waiting_for_input`, `completed`, `cancelled`, `error`.
139
+
140
+ ## Sessions (multi-turn)
141
+
142
+ Providers with `capabilities.sessions = true` (Claude, Codex) can host a persistent session where you send multiple user messages and reuse context across turns.
143
+
144
+ ```typescript
145
+ import { getProvider, parseAskUserQuestion } from "@agentex/agent";
146
+
147
+ const claude = getProvider("claude");
148
+ const session = await claude.createSession!({
149
+ cwd: process.cwd(),
150
+ onEvent: (e) => { /* stream events */ },
151
+ onUserInputRequest: async (req) => {
152
+ const q = parseAskUserQuestion(req);
153
+ if (q) return { allow: true, updatedInput: { answers: ["Yes"] } };
154
+ return { allow: true }; // auto-approve other tool calls
155
+ },
156
+ });
157
+
158
+ const first = await session.send("List the API routes in src/");
159
+ const followUp = await session.send("Now add rate limiting to each one.");
160
+
161
+ await session.close();
162
+ ```
163
+
164
+ `session.send()` returns a `TurnResult` with `summary`, `usage`, `costUsd`, and a `status` of `completed | failed | max_turns | max_budget | aborted`. Handle elicitations (MCP forms), hook callbacks, and interrupts through the corresponding `SessionContext` callbacks.
165
+
166
+ ## Auth
167
+
168
+ `@agentex/agent` models three billing modes explicitly — API key, Bedrock, and subscription — and refuses to collapse them into a single "is it ready?" boolean. Callers must name the mode they want so billing choices stay visible at the call site.
169
+
170
+ ```typescript
171
+ import { getProvider, hasSubscription, hasApiKey, hasBedrock } from "@agentex/agent";
172
+
173
+ const codex = getProvider("codex");
174
+
175
+ await hasSubscription(codex); // true — Codex authenticated via `codex login`
176
+ await hasApiKey(codex); // true — OPENAI_API_KEY is set (metered billing)
177
+ ```
178
+
179
+ ### Common cases
180
+
181
+ ```typescript
182
+ // 1. Just a Codex subscription (ChatGPT login, no metered billing)
183
+ const codex = getProvider("codex");
184
+ if (await hasSubscription(codex) && !(await hasApiKey(codex))) {
185
+ /* safe to run — no API charges */
186
+ }
187
+
188
+ // 2. Just a Claude Code subscription
189
+ const claude = getProvider("claude");
190
+ if (await hasSubscription(claude) && !(await hasApiKey(claude))) {
191
+ /* subscription-only */
192
+ }
193
+
194
+ // 3. API keys across providers
195
+ for (const p of [claude, codex, getProvider("gemini")]) {
196
+ if (await hasApiKey(p)) console.log(`${p.type} has API-key auth available`);
197
+ }
198
+
199
+ // 4. Full report when you need conflict detection, bedrock, or source paths
200
+ const report = await claude.resolveAuth();
201
+ // report.options = [
202
+ // { method: "api_key", source: { kind: "env", var: "ANTHROPIC_API_KEY" }, present: false },
203
+ // { method: "bedrock", source: { kind: "env_combo", vars: ["ANTHROPIC_BEDROCK_BASE_URL", "AWS_ACCESS_KEY_ID", "AWS_REGION"] }, present: false },
204
+ // { method: "subscription", source: { kind: "keychain", service: "Claude Code" }, present: "unknown" },
205
+ // ]
206
+ ```
207
+
208
+ ### What each provider reports
209
+
210
+ | Provider | API key source(s) | Other | Subscription source |
211
+ | --------- | ------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- |
212
+ | `codex` | `OPENAI_API_KEY` | — | `$CODEX_HOME/auth.json` (default `~/.codex/auth.json`) |
213
+ | `claude` | `ANTHROPIC_API_KEY` | Bedrock via `ANTHROPIC_BEDROCK_BASE_URL` or `AWS_ACCESS_KEY_ID`+`AWS_REGION` | macOS: Keychain `Claude Code` · Linux/Win: `$CLAUDE_CONFIG_DIR/.credentials.json` |
214
+ | `gemini` | `GEMINI_API_KEY`, `GOOGLE_API_KEY` | — | `$GEMINI_CONFIG_DIR/oauth_creds.json` (default `~/.gemini/oauth_creds.json`) |
215
+ | `cursor` | `CURSOR_API_KEY`, `OPENAI_API_KEY` | — | Detected at runtime |
216
+ | `opencode`| `OPENAI_API_KEY`, `ANTHROPIC_API_KEY` | — | — |
217
+ | `pi` | `OPENAI_API_KEY`, `ANTHROPIC_API_KEY` | — | — |
218
+
219
+ ### Safety notes
220
+
221
+ - Each sugar helper returns `true` only when a source is **confirmed** present. `"unknown"` presence (macOS Keychain — can't be checked without triggering an OS prompt) is treated as not-present.
222
+ - There is deliberately no blanket `canRun()` helper. If you want "any auth works," write it explicitly:
223
+ ```typescript
224
+ const anyReady = (await codex.resolveAuth()).options.some((o) => o.present === true);
225
+ ```
226
+ - `provider.testEnvironment()` additionally surfaces conflict checks — e.g., Codex or Claude emit a `warn` when both an API key and subscription credentials are present, since the API key will win and cause metered billing.
227
+
228
+ ### Auth types
229
+
230
+ ```typescript
231
+ type AuthMethod = "api_key" | "bedrock" | "subscription";
232
+
233
+ type AuthSource =
234
+ | { kind: "env"; var: string }
235
+ | { kind: "env_combo"; vars: string[] }
236
+ | { kind: "file"; path: string }
237
+ | { kind: "keychain"; service: string; account?: string };
238
+
239
+ interface AuthOption {
240
+ method: AuthMethod;
241
+ source: AuthSource;
242
+ present: boolean | "unknown";
243
+ }
244
+
245
+ interface AuthReport {
246
+ providerType: string;
247
+ options: AuthOption[];
248
+ }
249
+ ```
250
+
251
+ ## Environment Testing
252
+
253
+ `provider.testEnvironment()` is the heavyweight probe — binary resolution, auth presence, optional hello probe. It returns the same `AuthReport` as `resolveAuth()` plus human-readable `checks` for UI.
254
+
255
+ ```typescript
256
+ const result = await claude.testEnvironment({ providerType: "claude" });
257
+
258
+ result.status // "pass" | "warn" | "fail"
259
+ result.auth // AuthReport (same shape as provider.resolveAuth())
260
+ result.checks // [{ code, level: "info"|"warn"|"error", message, hint? }]
261
+ ```
262
+
263
+ Use `resolveAuth()` for cheap yes/no auth checks; use `testEnvironment()` when you need end-to-end confidence (e.g., on a first-run setup screen).
264
+
265
+ ## Workspaces (isolated git worktree)
266
+
267
+ Providers with `capabilities.workspace = true` can run in an isolated `git worktree`, letting you diff or discard the agent's changes without touching your main checkout.
268
+
269
+ ```typescript
270
+ import { prepareWorkspace } from "@agentex/agent";
271
+
272
+ const ws = await prepareWorkspace({ strategy: "worktree", baseBranch: "main" });
273
+ const result = await claude.execute({ prompt: "Refactor utils.ts", cwd: ws.cwd });
274
+
275
+ const patch = await ws.diff(); // all changes (default)
276
+ const summary = await ws.diff({ stat: true }); // --stat summary
277
+ const committed = await ws.diff({ scope: "committed" });
278
+
279
+ await ws.cleanup({ deleteBranch: true });
280
+ ```
281
+
282
+ Or pass `config.workspace` to `execute()` and the provider will prepare and attach it — the result's `workspace` field exposes the same handle.
283
+
284
+ ## Parallel Execution
285
+
286
+ ```typescript
287
+ import { executeAll } from "@agentex/agent";
288
+
289
+ const results = await executeAll(
290
+ [
291
+ { provider: "claude", ctx: { prompt: "Review server.ts" } },
292
+ { provider: "codex", ctx: { prompt: "Review db.ts" } },
293
+ ],
294
+ { cancelOnFailure: true },
295
+ );
296
+ ```
297
+
298
+ ## Skills
299
+
300
+ Install and remove reusable agent skills across multiple runtimes at once, into either the user's home or a workspace directory.
301
+
302
+ ```typescript
303
+ import { installSkills, listInstalledSkills, removeSkills } from "@agentex/agent";
304
+
305
+ await installSkills({
306
+ location: "global", // or "workspace" with cwd
307
+ includeNativeDirs: false, // true also installs into ~/.gemini/skills/, etc.
308
+ });
309
+
310
+ const installed = await listInstalledSkills({ location: "global" });
311
+ await removeSkills({ location: "global" });
312
+ ```
313
+
314
+ Channels and locations follow the emerging `.agents/skills/` + `.claude/skills/` convention — see the `SkillRuntime`, `SkillLocation`, and `SkillChannel` types.
315
+
316
+ ## Temporary Config Override
317
+
318
+ Run a CLI with a throwaway config directory (useful for injecting system prompts or custom settings without touching the user's real home).
319
+
320
+ ```typescript
321
+ import { withTempConfig } from "@agentex/agent";
322
+
323
+ const cfg = await withTempConfig({
324
+ runtime: "codex",
325
+ seedFromDefault: true, // optional: copy ~/.codex into the temp dir
326
+ overrides: { "config.toml": "model = \"o3\"\n" },
327
+ });
328
+
329
+ await codex.execute({ prompt: "...", env: cfg.env });
330
+ await cfg.cleanup();
331
+ ```
332
+
333
+ ## AskUserQuestion / Elicitation / Hooks
334
+
335
+ Sessions can surface three distinct user-input requests. Handle each via a `SessionContext` callback:
336
+
337
+ - `onUserInputRequest` — tool permission requests (and interactive tools like Claude's `AskUserQuestion`). Use `parseAskUserQuestion(req)` to detect structured question payloads and return answers via `updatedInput`.
338
+ - `onElicitation` — MCP servers asking the host to render a form or open a URL (`form` / `url` modes, with a JSON-Schema `requestedSchema`).
339
+ - `onHookCallback` — CLI requesting the host to run a registered hook.
46
340
 
47
341
  ## Custom Providers
48
342
 
@@ -52,6 +346,15 @@ import type { ProviderModule } from "@agentex/agent";
52
346
 
53
347
  const myProvider: ProviderModule = {
54
348
  type: "my-agent",
349
+ capabilities: {
350
+ sessions: false,
351
+ modelDiscovery: false,
352
+ quotaProbing: false,
353
+ mcp: false,
354
+ skills: false,
355
+ instructions: false,
356
+ workspace: false,
357
+ },
55
358
  async execute(ctx) {
56
359
  const startedAt = new Date().toISOString();
57
360
  // Spawn your agent, stream events via ctx.onEvent...
@@ -59,7 +362,7 @@ const myProvider: ProviderModule = {
59
362
  runId: ctx.runId ?? "generated-id",
60
363
  exitCode: 0,
61
364
  signal: null,
62
- timedOut: false,
365
+ status: "completed",
63
366
  startedAt,
64
367
  completedAt: new Date().toISOString(),
65
368
  durationMs: 0,
@@ -75,92 +378,69 @@ const myProvider: ProviderModule = {
75
378
  };
76
379
  },
77
380
  async testEnvironment(ctx) {
78
- return { providerType: ctx.providerType, status: "pass", checks: [], testedAt: new Date().toISOString() };
381
+ return {
382
+ providerType: ctx.providerType,
383
+ status: "pass",
384
+ auth: { providerType: ctx.providerType, options: [] },
385
+ checks: [],
386
+ testedAt: new Date().toISOString(),
387
+ };
388
+ },
389
+ async resolveAuth() {
390
+ return { providerType: "my-agent", options: [] };
79
391
  },
80
392
  };
81
393
 
82
394
  registerProvider(myProvider);
83
395
  ```
84
396
 
85
- ## API
86
-
87
- ### `getProvider(type: string): ProviderModule`
397
+ ## API Reference
88
398
 
89
- Returns a registered provider by name. Throws if not found.
399
+ ### Registry
400
+ - `getProvider(type)` — look up a registered provider. Throws if unknown.
401
+ - `listProviders()` — list all registered provider type names.
402
+ - `registerProvider(module)` — register a custom provider.
90
403
 
91
- ### `listProviders(): string[]`
404
+ ### Execution
405
+ - `provider.execute(ctx)` — run a single turn.
406
+ - `provider.createSession?(ctx)` — start a multi-turn session (when `capabilities.sessions`).
407
+ - `executeAll(tasks, { cancelOnFailure?, signal? })` — run multiple executions concurrently.
92
408
 
93
- Returns all registered provider type names.
409
+ ### Auth
410
+ - `provider.resolveAuth(ctx?)` — structured report of every auth path.
411
+ - `hasSubscription(provider, ctx?)` / `hasApiKey(provider, ctx?)` / `hasBedrock(provider, ctx?)` — presence sugar.
412
+ - `detectAuth(providerType, env)` — env-only auth classification used for billing hints.
94
413
 
95
- ### `registerProvider(provider: ProviderModule): void`
414
+ ### Environment
415
+ - `provider.testEnvironment(ctx)` — full probe: binary, auth, optional hello-probe.
416
+ - `provider.checkQuota?(ctx)` — rate-limit / quota status (when `capabilities.quotaProbing`).
417
+ - `provider.listModels?(opts?)` — enumerate models the binary can drive.
96
418
 
97
- Registers a custom provider, making it available via `getProvider()`.
419
+ ### Workspace
420
+ - `prepareWorkspace({ strategy, baseBranch?, branchName?, targetDir? })` → `PreparedWorkspace` with `cwd`, `diff()`, `cleanup()`.
98
421
 
99
- ### `renderTemplate(template: string, context: Record<string, string>): string`
100
-
101
- Renders a template string with `{{variable}}` interpolation.
102
-
103
- ### `redactEnvForLogs(env: Record<string, string>): Record<string, string>`
104
-
105
- Returns a copy of env vars with sensitive values redacted for safe logging.
106
-
107
- ## Execution Context
108
-
109
- Only `prompt` is required. Everything else has sensible defaults.
110
-
111
- ```typescript
112
- interface ExecutionContext {
113
- prompt: string; // The task to execute
114
- model?: string; // Model override (e.g. "claude-sonnet-4-20250514")
115
- runId?: string; // Auto-generated UUIDv7 if omitted
116
- cwd?: string; // Defaults to process.cwd()
117
- env?: Record<string, string>;
118
- sessionParams?: Record<string, unknown> | null;
119
- config?: ProviderConfig;
120
- onOutput?: (stream: "stdout" | "stderr", chunk: string) => void;
121
- onEvent?: (event: StreamEvent) => void;
122
- }
123
- ```
124
-
125
- ## Execution Result
126
-
127
- ```typescript
128
- interface ExecutionResult {
129
- runId: string;
130
- exitCode: number | null;
131
- signal: string | null;
132
- timedOut: boolean;
133
- startedAt: string; // ISO timestamp
134
- completedAt: string; // ISO timestamp
135
- durationMs: number; // Wall-clock duration
136
- errorMessage: string | null;
137
- errorCode: string | null;
138
- usage?: { inputTokens: number; outputTokens: number; cachedInputTokens?: number };
139
- costUsd: number | null;
140
- model: string | null;
141
- summary: string | null;
142
- sessionParams: Record<string, unknown> | null;
143
- sessionDisplayId: string | null;
144
- clearSession: boolean;
145
- billingType: "api" | "subscription" | null;
146
- }
147
- ```
148
-
149
- ## Stream Events
422
+ ### Skills
423
+ - `installSkills(opts)` / `removeSkills(opts)` / `listInstalledSkills(opts)`
424
+ - `resolveSkillsHome(channel)` / `resolveSkillsWorkspace(channel, cwd)`
425
+ - `resolveNativeSkillsHome(runtime)` / `resolveNativeSkillsWorkspace(runtime, cwd)`
426
+ - `ensureSkillSymlink(...)`
150
427
 
151
- Events emitted during execution via `onEvent`. All events include a `timestamp` field.
428
+ ### Runtime config
429
+ - `withTempConfig({ runtime, seedFromDefault?, overrides? })` → env + configDir + cleanup.
430
+ - `getRuntimeHomeEnvVar(runtime)` / `getDefaultRuntimeHome(runtime)` — introspect each CLI's home dir override.
152
431
 
153
- - `system` — Session init (`event.sessionId`, `event.model`)
154
- - `assistant` — Text output from the agent (`event.text`)
155
- - `thinking` — Agent's internal reasoning (`event.text`)
156
- - `tool_call` — Agent invoked a tool (`event.name`, `event.input`)
157
- - `tool_result` — Tool returned a result (`event.content`, `event.isError`)
158
- - `result` — Final result (`event.text`, `event.cost`)
432
+ ### Utilities
433
+ - `aggregateUsage(usage)` — collapse `Record<string, TokenUsage>` to a single total.
434
+ - `renderTemplate(template, ctx)` — `{{var}}` interpolation.
435
+ - `redactEnvForLogs(env)` — redact sensitive values before logging.
436
+ - `resolveInstructions(path?)` — read an instructions file, or `null` if no path.
437
+ - `parseAskUserQuestion(req)` — extract structured question/option data from a `UserInputRequest`.
159
438
 
160
439
  ## Requirements
161
440
 
162
441
  - Node.js >= 18
163
- - The CLI for each provider must be installed and on `$PATH` (e.g., `claude` for the Claude provider)
442
+ - Each provider's CLI installed and resolvable on `$PATH` (`claude`, `codex`, `gemini`, `agent` for Cursor, `opencode`, `pi`, or a reachable OpenClaw gateway)
443
+ - For subscription auth, the relevant CLI must already be logged in (`codex login`, `claude login`, `gemini auth login`, etc.)
164
444
 
165
445
  ## License
166
446
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,20 @@
1
1
  export { getProvider, listProviders, registerProvider } from "./registry.js";
2
2
  export { renderTemplate } from "./utils/template.js";
3
3
  export { redactEnvForLogs } from "./utils/env.js";
4
- export type { ProviderModule, ExecutionContext, ExecutionResult, ProviderConfig, McpServerConfig, StreamEvent, SessionCodec, EnvironmentTestContext, EnvironmentTestResult, EnvironmentCheck, ProviderModel, } from "./types.js";
4
+ export { parseAskUserQuestion } from "./utils/ask-user-question.js";
5
+ export { aggregateUsage } from "./types.js";
6
+ export { resolveInstructions } from "./utils/instructions.js";
7
+ export { getRuntimeHomeEnvVar, getDefaultRuntimeHome } from "./utils/runtime-homes.js";
8
+ export { detectAuth, resolveAuthForProvider, hasSubscription, hasApiKey, hasBedrock, } from "./utils/auth.js";
9
+ export type { ResolvedAuth } from "./utils/auth.js";
10
+ export { prepareWorkspace } from "./utils/workspace.js";
11
+ export type { WorkspaceOptions, PreparedWorkspace, DiffOptions } from "./utils/workspace.js";
12
+ export { withTempConfig } from "./utils/runtime-config.js";
13
+ export type { TempConfigResult, TempConfigOptions } from "./utils/runtime-config.js";
14
+ export { executeAll } from "./utils/execute-all.js";
15
+ export type { ExecuteAllOptions, ExecuteAllTask } from "./utils/execute-all.js";
16
+ export { installSkills, removeSkills, listInstalledSkills, resolveSkillsHome, resolveSkillsWorkspace, resolveNativeSkillsHome, resolveNativeSkillsWorkspace, ensureSkillSymlink, } from "./utils/skills.js";
17
+ export type { ProviderModule, ProviderCapabilities, ExecutionContext, ExecutionResult, ExecutionStatus, ProviderConfig, McpServerConfig, StreamEvent, SessionCodec, SessionState, TokenUsage, LifecycleEvent, QuotaStatus, QuotaContext, EnvironmentTestContext, EnvironmentTestResult, EnvironmentCheck, AuthMethod, AuthSource, AuthOption, AuthReport, AuthResolveContext, ProviderModel, SessionContext, AgentSession, TurnResult, UserInputRequest, UserInputResponse, ElicitationRequest, ElicitationResponse, HookCallbackRequest, HookCallbackResponse, } from "./types.js";
18
+ export type { AskUserQuestion, QuestionOption, } from "./utils/ask-user-question.js";
19
+ export type { SkillRuntime, SkillLocation, SkillChannel, InstallSkillsOptions, SkillInstallEntry, SkillInstallResult, RemoveSkillsOptions, SkillRemoveEntry, SkillRemoveResult, InstalledSkill, } from "./utils/skills.js";
5
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGlD,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,eAAe,EACf,WAAW,EACX,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACvF,OAAO,EACL,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,SAAS,EACT,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGhF,OAAO,EACL,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,EACvB,4BAA4B,EAC5B,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,cAAc,EACd,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,cAAc,EACd,WAAW,EACX,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,eAAe,EACf,cAAc,GACf,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,GACf,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -2,4 +2,14 @@
2
2
  export { getProvider, listProviders, registerProvider } from "./registry.js";
3
3
  export { renderTemplate } from "./utils/template.js";
4
4
  export { redactEnvForLogs } from "./utils/env.js";
5
+ export { parseAskUserQuestion } from "./utils/ask-user-question.js";
6
+ export { aggregateUsage } from "./types.js";
7
+ export { resolveInstructions } from "./utils/instructions.js";
8
+ export { getRuntimeHomeEnvVar, getDefaultRuntimeHome } from "./utils/runtime-homes.js";
9
+ export { detectAuth, resolveAuthForProvider, hasSubscription, hasApiKey, hasBedrock, } from "./utils/auth.js";
10
+ export { prepareWorkspace } from "./utils/workspace.js";
11
+ export { withTempConfig } from "./utils/runtime-config.js";
12
+ export { executeAll } from "./utils/execute-all.js";
13
+ // Skills
14
+ export { installSkills, removeSkills, listInstalledSkills, resolveSkillsHome, resolveSkillsWorkspace, resolveNativeSkillsHome, resolveNativeSkillsWorkspace, ensureSkillSymlink, } from "./utils/skills.js";
5
15
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY;AACZ,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY;AACZ,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACvF,OAAO,EACL,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,SAAS,EACT,UAAU,GACX,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,SAAS;AACT,OAAO,EACL,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,EACvB,4BAA4B,EAC5B,kBAAkB,GACnB,MAAM,mBAAmB,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import type { ExecutionContext, ExecutionResult } from "../../types.js";
2
- export declare function executeClaudeAdapter(ctx: ExecutionContext): Promise<ExecutionResult>;
2
+ export declare function executeClaudeProvider(ctx: ExecutionContext): Promise<ExecutionResult>;
3
3
  //# sourceMappingURL=execute.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/providers/claude/execute.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAaxE,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA4M1F"}
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/providers/claude/execute.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAWxE,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAgP3F"}