axexec 1.0.0

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 (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +196 -0
  3. package/bin/axexec +17 -0
  4. package/dist/agents/claude-code/adapter.d.ts +6 -0
  5. package/dist/agents/claude-code/adapter.js +71 -0
  6. package/dist/agents/claude-code/parse-event.d.ts +16 -0
  7. package/dist/agents/claude-code/parse-event.js +185 -0
  8. package/dist/agents/claude-code/types.d.ts +180 -0
  9. package/dist/agents/claude-code/types.js +112 -0
  10. package/dist/agents/codex/adapter.d.ts +6 -0
  11. package/dist/agents/codex/adapter.js +62 -0
  12. package/dist/agents/codex/item-parsers.d.ts +17 -0
  13. package/dist/agents/codex/item-parsers.js +126 -0
  14. package/dist/agents/codex/parse-event.d.ts +38 -0
  15. package/dist/agents/codex/parse-event.js +141 -0
  16. package/dist/agents/codex/types.d.ts +407 -0
  17. package/dist/agents/codex/types.js +188 -0
  18. package/dist/agents/copilot/adapter.d.ts +11 -0
  19. package/dist/agents/copilot/adapter.js +81 -0
  20. package/dist/agents/copilot/parse-event.d.ts +20 -0
  21. package/dist/agents/copilot/parse-event.js +137 -0
  22. package/dist/agents/copilot/stream-session.d.ts +10 -0
  23. package/dist/agents/copilot/stream-session.js +120 -0
  24. package/dist/agents/copilot/tail-file.d.ts +11 -0
  25. package/dist/agents/copilot/tail-file.js +52 -0
  26. package/dist/agents/copilot/transform-event.d.ts +19 -0
  27. package/dist/agents/copilot/transform-event.js +100 -0
  28. package/dist/agents/copilot/types.d.ts +320 -0
  29. package/dist/agents/copilot/types.js +220 -0
  30. package/dist/agents/copilot/watch-session.d.ts +26 -0
  31. package/dist/agents/copilot/watch-session.js +186 -0
  32. package/dist/agents/gemini/adapter.d.ts +6 -0
  33. package/dist/agents/gemini/adapter.js +78 -0
  34. package/dist/agents/gemini/parse-event.d.ts +18 -0
  35. package/dist/agents/gemini/parse-event.js +144 -0
  36. package/dist/agents/gemini/types.d.ts +162 -0
  37. package/dist/agents/gemini/types.js +103 -0
  38. package/dist/agents/opencode/adapter.d.ts +16 -0
  39. package/dist/agents/opencode/adapter.js +142 -0
  40. package/dist/agents/opencode/cleanup-session.d.ts +17 -0
  41. package/dist/agents/opencode/cleanup-session.js +41 -0
  42. package/dist/agents/opencode/create-session-start-event.d.ts +18 -0
  43. package/dist/agents/opencode/create-session-start-event.js +24 -0
  44. package/dist/agents/opencode/detect-empty-session.d.ts +25 -0
  45. package/dist/agents/opencode/detect-empty-session.js +42 -0
  46. package/dist/agents/opencode/map-error-to-event.d.ts +10 -0
  47. package/dist/agents/opencode/map-error-to-event.js +55 -0
  48. package/dist/agents/opencode/parse-message-part.d.ts +24 -0
  49. package/dist/agents/opencode/parse-message-part.js +112 -0
  50. package/dist/agents/opencode/parse-sse-event.d.ts +23 -0
  51. package/dist/agents/opencode/parse-sse-event.js +125 -0
  52. package/dist/agents/opencode/process-sse-events.d.ts +24 -0
  53. package/dist/agents/opencode/process-sse-events.js +66 -0
  54. package/dist/agents/opencode/server-types.d.ts +509 -0
  55. package/dist/agents/opencode/server-types.js +293 -0
  56. package/dist/agents/opencode/session-api.d.ts +56 -0
  57. package/dist/agents/opencode/session-api.js +151 -0
  58. package/dist/agents/opencode/spawn-server.d.ts +29 -0
  59. package/dist/agents/opencode/spawn-server.js +95 -0
  60. package/dist/agents/opencode/sse-client.d.ts +33 -0
  61. package/dist/agents/opencode/sse-client.js +145 -0
  62. package/dist/agents/registry.d.ts +15 -0
  63. package/dist/agents/registry.js +24 -0
  64. package/dist/cli.d.ts +15 -0
  65. package/dist/cli.js +119 -0
  66. package/dist/credentials/get-credential-environment.d.ts +13 -0
  67. package/dist/credentials/get-credential-environment.js +46 -0
  68. package/dist/credentials/install-credentials.d.ts +27 -0
  69. package/dist/credentials/install-credentials.js +102 -0
  70. package/dist/credentials/save-json-file.d.ts +11 -0
  71. package/dist/credentials/save-json-file.js +21 -0
  72. package/dist/credentials/types.d.ts +24 -0
  73. package/dist/credentials/types.js +4 -0
  74. package/dist/credentials/write-agent-credentials.d.ts +36 -0
  75. package/dist/credentials/write-agent-credentials.js +91 -0
  76. package/dist/determine-session-success.d.ts +15 -0
  77. package/dist/determine-session-success.js +25 -0
  78. package/dist/format-event-tsv.d.ts +23 -0
  79. package/dist/format-event-tsv.js +136 -0
  80. package/dist/parse-credentials.d.ts +13 -0
  81. package/dist/parse-credentials.js +63 -0
  82. package/dist/parse-iso-timestamp.d.ts +21 -0
  83. package/dist/parse-iso-timestamp.js +37 -0
  84. package/dist/resolve-binary.d.ts +29 -0
  85. package/dist/resolve-binary.js +46 -0
  86. package/dist/resolve-output-mode.d.ts +39 -0
  87. package/dist/resolve-output-mode.js +39 -0
  88. package/dist/run-agent.d.ts +32 -0
  89. package/dist/run-agent.js +146 -0
  90. package/dist/stream-agent.d.ts +20 -0
  91. package/dist/stream-agent.js +207 -0
  92. package/dist/types/adapter.d.ts +101 -0
  93. package/dist/types/adapter.js +14 -0
  94. package/dist/types/events.d.ts +82 -0
  95. package/dist/types/events.js +13 -0
  96. package/dist/types/options.d.ts +41 -0
  97. package/dist/types/options.js +4 -0
  98. package/dist/validate-agent.d.ts +20 -0
  99. package/dist/validate-agent.js +50 -0
  100. package/dist/write-event.d.ts +23 -0
  101. package/dist/write-event.js +43 -0
  102. package/package.json +79 -0
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Agent execution with credential isolation and config generation.
3
+ */
4
+ import { buildAgentConfig } from "axconfig";
5
+ import { isStreamableAdapter } from "./types/adapter.js";
6
+ import { installCredentials, cleanupCredentials, } from "./credentials/install-credentials.js";
7
+ import { streamAgent } from "./stream-agent.js";
8
+ import { validateAgent } from "./validate-agent.js";
9
+ import { resolveOutputMode } from "./resolve-output-mode.js";
10
+ import { createEventWriter } from "./write-event.js";
11
+ import { parseCredentialsFromEnvironment } from "./parse-credentials.js";
12
+ import { DependencyError } from "./resolve-binary.js";
13
+ /**
14
+ * Runs an agent with full isolation.
15
+ *
16
+ * 1. Validates the agent ID
17
+ * 2. Parses credentials from environment
18
+ * 3. Installs credentials to temp directory
19
+ * 4. Builds config if permissions specified
20
+ * 5. Streams events from agent
21
+ * 6. Cleans up temp directory
22
+ */
23
+ async function runAgent(agentId, options) {
24
+ // Validate agent
25
+ const validation = validateAgent(agentId);
26
+ if (!validation.ok) {
27
+ process.stderr.write(validation.message + "\n");
28
+ process.exitCode = validation.exitCode;
29
+ return { events: [], success: false };
30
+ }
31
+ const { adapter } = validation;
32
+ // Parse credentials from environment
33
+ const credentials = parseCredentialsFromEnvironment(agentId);
34
+ // Install credentials to temp directory
35
+ let credentialResult;
36
+ try {
37
+ credentialResult = await installCredentials(validation.agentId, credentials);
38
+ }
39
+ catch (error) {
40
+ const message = error instanceof Error ? error.message : String(error);
41
+ process.stderr.write(`Error installing credentials: ${message}\n`);
42
+ process.exitCode = 1;
43
+ return { events: [], success: false };
44
+ }
45
+ // Build config if permissions specified
46
+ let configEnvironment = credentialResult.env;
47
+ if (options.allow || options.deny) {
48
+ const configResult = buildConfig(validation.agentId, options, credentialResult);
49
+ if (!configResult.ok) {
50
+ await cleanupCredentials(credentialResult.baseDirectory);
51
+ process.exitCode = configResult.exitCode;
52
+ return { events: [], success: false };
53
+ }
54
+ configEnvironment = configResult.env;
55
+ }
56
+ // Execute agent
57
+ return executeAgent(adapter, options, configEnvironment, credentialResult);
58
+ }
59
+ /**
60
+ * Builds agent config with permissions.
61
+ */
62
+ function buildConfig(agentId, options, credentialResult) {
63
+ try {
64
+ const configResult = buildAgentConfig({
65
+ agentId,
66
+ allow: options.allow,
67
+ deny: options.deny,
68
+ output: credentialResult.configDirectory,
69
+ });
70
+ if (!configResult.ok) {
71
+ if ("message" in configResult) {
72
+ process.stderr.write(`Error: ${configResult.message}\n`);
73
+ }
74
+ else {
75
+ process.stderr.write(`Error building config: permission errors\n`);
76
+ for (const error of configResult.errors) {
77
+ process.stderr.write(` - ${error.reason}\n`);
78
+ }
79
+ }
80
+ return { ok: false, exitCode: configResult.exitCode };
81
+ }
82
+ // Log warnings
83
+ for (const warning of configResult.warnings) {
84
+ process.stderr.write(`Warning: ${warning.reason}\n`);
85
+ }
86
+ // Merge config env with credential env (config env takes precedence)
87
+ return {
88
+ ok: true,
89
+ env: { ...credentialResult.env, ...configResult.env },
90
+ };
91
+ }
92
+ catch (error) {
93
+ const message = error instanceof Error ? error.message : String(error);
94
+ process.stderr.write(`Error parsing permissions: ${message}\n`);
95
+ return { ok: false, exitCode: 1 };
96
+ }
97
+ }
98
+ /**
99
+ * Executes agent and streams events.
100
+ */
101
+ async function executeAgent(adapter, options, configEnvironment, credentialResult) {
102
+ const runOptions = {
103
+ prompt: options.prompt,
104
+ verbose: options.verbose ?? false,
105
+ model: options.model,
106
+ rawLogPath: options.rawLog,
107
+ debug: options.debug,
108
+ configEnv: configEnvironment,
109
+ preserveGithubSha: options.preserveGithubSha,
110
+ };
111
+ const outputMode = resolveOutputMode(options.format, process.stdout.isTTY);
112
+ const writeEvent = createEventWriter(outputMode);
113
+ const events = [];
114
+ try {
115
+ const eventStream = isStreamableAdapter(adapter)
116
+ ? adapter.streamSession(runOptions)
117
+ : streamAgent(adapter, runOptions);
118
+ for await (const event of eventStream) {
119
+ events.push(event);
120
+ writeEvent(event);
121
+ }
122
+ const success = adapter.isSuccess(events);
123
+ return { events, success };
124
+ }
125
+ catch (error) {
126
+ if (error instanceof DependencyError) {
127
+ process.stderr.write(error.message + "\n");
128
+ return { events, success: false };
129
+ }
130
+ const message = error instanceof Error ? error.message : String(error);
131
+ const errorEvent = {
132
+ type: "session.error",
133
+ code: "SPAWN_ERROR",
134
+ message,
135
+ timestamp: Date.now(),
136
+ };
137
+ events.push(errorEvent);
138
+ writeEvent(errorEvent);
139
+ return { events, success: false };
140
+ }
141
+ finally {
142
+ // Safe to await - executeAgent is async so finally block can use await
143
+ await cleanupCredentials(credentialResult.baseDirectory);
144
+ }
145
+ }
146
+ export { runAgent };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Core runner for executing agents.
3
+ *
4
+ * This module is the imperative shell that handles all I/O:
5
+ * process spawning, streaming, and event collection.
6
+ */
7
+ import type { AgentAdapter } from "./types/adapter.js";
8
+ import type { AxexecEvent } from "./types/events.js";
9
+ import type { RunOptions } from "./types/options.js";
10
+ /**
11
+ * Runs an agent and streams normalized events.
12
+ *
13
+ * @param adapter - The agent adapter to use
14
+ * @param options - Run options including prompt and flags
15
+ * @yields Normalized events as they arrive from the agent
16
+ * @throws {AgentNotFoundError} If the agent binary is not found
17
+ * @throws {AgentSpawnError} If the process fails to start
18
+ */
19
+ declare function streamAgent(adapter: AgentAdapter, options: RunOptions): AsyncGenerator<AxexecEvent>;
20
+ export { streamAgent };
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Core runner for executing agents.
3
+ *
4
+ * This module is the imperative shell that handles all I/O:
5
+ * process spawning, streaming, and event collection.
6
+ */
7
+ import { spawn } from "node:child_process";
8
+ import { createWriteStream } from "node:fs";
9
+ import { createInterface } from "node:readline";
10
+ /**
11
+ * Environment variables to always exclude from agent subprocess.
12
+ *
13
+ * Vault credentials are excluded to prevent prompt injection attacks from
14
+ * exfiltrating secrets. The credentials are resolved before spawning and
15
+ * passed via agent-specific env vars (e.g., ANTHROPIC_API_KEY).
16
+ */
17
+ const VAULT_ENV_EXCLUSIONS = ["AXVAULT", "AXVAULT_URL", "AXVAULT_API_KEY"];
18
+ /** Error thrown when agent binary is not found */
19
+ class AgentNotFoundError extends Error {
20
+ bin;
21
+ constructor(bin, cause) {
22
+ super(`Agent binary not found: ${bin}`);
23
+ this.name = "AgentNotFoundError";
24
+ this.bin = bin;
25
+ this.cause = cause;
26
+ }
27
+ }
28
+ /** Error thrown when agent process fails to start */
29
+ class AgentSpawnError extends Error {
30
+ bin;
31
+ constructor(bin, cause) {
32
+ super(`Failed to spawn agent: ${bin}`);
33
+ this.name = "AgentSpawnError";
34
+ this.bin = bin;
35
+ this.cause = cause;
36
+ }
37
+ }
38
+ /**
39
+ * Runs an agent and streams normalized events.
40
+ *
41
+ * @param adapter - The agent adapter to use
42
+ * @param options - Run options including prompt and flags
43
+ * @yields Normalized events as they arrive from the agent
44
+ * @throws {AgentNotFoundError} If the agent binary is not found
45
+ * @throws {AgentSpawnError} If the process fails to start
46
+ */
47
+ async function* streamAgent(adapter, options) {
48
+ const { bin, args, env, envExclusions: environmentExclusions, } = adapter.prepareCommand(options);
49
+ const parseEvent = adapter.createParser(options);
50
+ // Open raw log file if requested.
51
+ // Errors are logged to stderr but don't interrupt the main stream.
52
+ let rawLogStream;
53
+ if (options.rawLogPath) {
54
+ rawLogStream = createWriteStream(options.rawLogPath, { flags: "w" });
55
+ rawLogStream.on("error", (error) => {
56
+ process.stderr.write(`Warning: raw log error: ${error.message}\n`);
57
+ });
58
+ }
59
+ // Build environment: start with process.env, exclude vault vars and any
60
+ // adapter-specified vars, then merge adapter env and config env.
61
+ const allExclusions = new Set([
62
+ ...VAULT_ENV_EXCLUSIONS,
63
+ ...(environmentExclusions ?? []),
64
+ ]);
65
+ const baseEnvironment = Object.fromEntries(Object.entries(process.env).filter(([key]) => !allExclusions.has(key)));
66
+ const child = spawn(bin, args, {
67
+ env: { ...baseEnvironment, ...env, ...options.configEnv },
68
+ cwd: options.cwd,
69
+ stdio: ["ignore", "pipe", "pipe"],
70
+ });
71
+ // Consume stderr to prevent pipe buffer deadlock.
72
+ // Capture output for error diagnostics when process fails.
73
+ // stderr is guaranteed non-null since stdio is set to "pipe".
74
+ let stderrBuffer = "";
75
+ const STDERR_LIMIT = 50 * 1024 * 1024; // 50 MB limit to prevent OOM
76
+ if (options.verbose) {
77
+ child.stderr.pipe(process.stderr);
78
+ }
79
+ else {
80
+ child.stderr.on("data", (chunk) => {
81
+ // Limit buffer size to prevent memory exhaustion from verbose agents
82
+ if (stderrBuffer.length < STDERR_LIMIT) {
83
+ stderrBuffer += chunk.toString();
84
+ if (stderrBuffer.length >= STDERR_LIMIT) {
85
+ stderrBuffer =
86
+ stderrBuffer.slice(0, STDERR_LIMIT) + "\n... (truncated)";
87
+ }
88
+ }
89
+ });
90
+ }
91
+ // Wait for spawn or error
92
+ await new Promise((resolve, reject) => {
93
+ child.once("error", (error) => {
94
+ if (error.code === "ENOENT") {
95
+ reject(new AgentNotFoundError(bin, error));
96
+ }
97
+ else {
98
+ reject(new AgentSpawnError(bin, error));
99
+ }
100
+ });
101
+ child.once("spawn", () => {
102
+ resolve();
103
+ });
104
+ });
105
+ // Forward termination signals to the child process.
106
+ // Registered after spawn succeeds to prevent handler leak on spawn failure.
107
+ const forwardSignal = (signal) => {
108
+ child.kill(signal);
109
+ };
110
+ process.on("SIGINT", forwardSignal);
111
+ process.on("SIGTERM", forwardSignal);
112
+ try {
113
+ // Stream stdout line-by-line.
114
+ // stdout is guaranteed non-null since stdio is set to "pipe".
115
+ const stdout = child.stdout;
116
+ // Handle stream errors that readline's for-await-of doesn't forward
117
+ let streamError;
118
+ stdout.on("error", (error) => {
119
+ streamError = error;
120
+ });
121
+ const rl = createInterface({ input: stdout });
122
+ for await (const line of rl) {
123
+ // Write raw line to log file if enabled
124
+ if (rawLogStream) {
125
+ rawLogStream.write(line + "\n");
126
+ }
127
+ const event = parseEvent(line);
128
+ if (event) {
129
+ yield event;
130
+ }
131
+ else if (options.debug && line.trim() !== "") {
132
+ // Log unknown events in debug mode
133
+ // Try to extract event type for better diagnostics
134
+ let eventType = "unknown";
135
+ try {
136
+ const parsed = JSON.parse(line);
137
+ if (typeof parsed.type === "string") {
138
+ eventType = parsed.type;
139
+ }
140
+ }
141
+ catch {
142
+ // Not valid JSON, use raw preview
143
+ eventType = `(invalid JSON: ${line.slice(0, 50)}...)`;
144
+ }
145
+ process.stderr.write(`[debug] Unhandled event type: ${eventType}\n`);
146
+ }
147
+ }
148
+ // Drain any buffered events from parsers that queue multiple events per line.
149
+ // Some parsers (e.g., OpenCode) produce multiple events from a single line
150
+ // but return them one at a time. Calling with empty string drains the queue.
151
+ let bufferedEvent;
152
+ while ((bufferedEvent = parseEvent("")) !== undefined) {
153
+ yield bufferedEvent;
154
+ }
155
+ // Check if we had a stream error during iteration
156
+ if (streamError) {
157
+ yield {
158
+ type: "session.error",
159
+ code: "STREAM_ERROR",
160
+ message: streamError.message,
161
+ timestamp: Date.now(),
162
+ };
163
+ }
164
+ // Wait for process to exit
165
+ const { exitCode, signal } = await new Promise((resolve) => {
166
+ child.once("close", (code, sig) => {
167
+ resolve({
168
+ exitCode: code ?? undefined,
169
+ signal: sig ?? undefined,
170
+ });
171
+ });
172
+ });
173
+ // If process was terminated by a signal, yield a signal error event
174
+ if (signal) {
175
+ yield {
176
+ type: "session.error",
177
+ code: "SIGNAL",
178
+ message: `Agent terminated by ${signal}`,
179
+ timestamp: Date.now(),
180
+ };
181
+ }
182
+ else if (exitCode !== 0 && exitCode !== undefined) {
183
+ // If process exited with non-zero, yield an exit-code error event.
184
+ // Note: This may emit after a stream error - consumers handle both.
185
+ const stderrTrimmed = stderrBuffer.trim();
186
+ const message = stderrTrimmed
187
+ ? `Agent exited with code ${exitCode}: ${stderrTrimmed}`
188
+ : `Agent exited with code ${exitCode}`;
189
+ yield {
190
+ type: "session.error",
191
+ code: "EXIT_CODE",
192
+ message,
193
+ timestamp: Date.now(),
194
+ };
195
+ }
196
+ }
197
+ finally {
198
+ // Clean up signal handlers - guaranteed to run even if consumer breaks early
199
+ process.off("SIGINT", forwardSignal);
200
+ process.off("SIGTERM", forwardSignal);
201
+ // Close raw log stream if open
202
+ if (rawLogStream) {
203
+ rawLogStream.end();
204
+ }
205
+ }
206
+ }
207
+ export { streamAgent };
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Adapter interface and related types.
3
+ *
4
+ * Each agent implements the {@link AgentAdapter} interface to provide
5
+ * a consistent way to prepare commands and parse events.
6
+ *
7
+ * Adapters may optionally implement {@link StreamableAdapter} to provide
8
+ * custom streaming behavior (e.g., for server-mode agents).
9
+ */
10
+ import type { AgentCli, AxexecEvent } from "./events.js";
11
+ import type { RunOptions } from "./options.js";
12
+ /** Metadata about an agent */
13
+ interface AgentInfo {
14
+ /** Unique identifier for the agent */
15
+ id: AgentCli;
16
+ /** Human-readable name */
17
+ name: string;
18
+ /** CLI package name (e.g., "@anthropic-ai/claude-code") */
19
+ package: string;
20
+ /** Detected version of the installed CLI, if available */
21
+ version?: string;
22
+ }
23
+ /** Command prepared for execution by spawn() */
24
+ interface PreparedCommand {
25
+ /** Binary to execute */
26
+ bin: string;
27
+ /** Arguments to pass to the binary */
28
+ args: string[];
29
+ /** Environment variables to set */
30
+ env: Record<string, string>;
31
+ /**
32
+ * Environment variables to exclude from process.env.
33
+ *
34
+ * These keys will be removed from the inherited environment before
35
+ * the adapter's env values are merged in. Useful for agents that need
36
+ * to work around CI environment variable conflicts.
37
+ */
38
+ envExclusions?: string[];
39
+ }
40
+ /** Function that parses a single JSONL line into a normalized event */
41
+ type EventParser = (line: string) => AxexecEvent | undefined;
42
+ /**
43
+ * Adapter interface that each agent must implement.
44
+ *
45
+ * Adapters are responsible for:
46
+ * - Providing agent metadata
47
+ * - Preparing the spawn command with appropriate flags
48
+ * - Parsing raw JSONL lines into normalized events
49
+ * - Determining task success from the event stream
50
+ */
51
+ interface AgentAdapter {
52
+ /** Returns agent metadata */
53
+ info(): AgentInfo;
54
+ /** Prepares the spawn command with environment and arguments */
55
+ prepareCommand(options: RunOptions): PreparedCommand;
56
+ /**
57
+ * Creates a parser for a single session.
58
+ *
59
+ * The returned function may maintain state across calls (e.g., to correlate
60
+ * tool calls with their results). A new parser should be created for each
61
+ * agent invocation.
62
+ *
63
+ * @param options - Run options (optional, for agents that need model info)
64
+ * @returns A function that parses JSONL lines into normalized events
65
+ */
66
+ createParser(options?: RunOptions): EventParser;
67
+ /**
68
+ * Determines if the task completed successfully from the event stream.
69
+ *
70
+ * Called after the process exits to interpret the final state.
71
+ */
72
+ isSuccess(events: AxexecEvent[]): boolean;
73
+ }
74
+ /**
75
+ * Extended adapter interface for agents that provide custom streaming.
76
+ *
77
+ * Agents implementing this interface handle their own execution flow
78
+ * (e.g., server-mode agents that use HTTP/SSE instead of stdout).
79
+ *
80
+ * When an adapter implements `streamSession`, the CLI will use it
81
+ * instead of the default spawn+parse pattern.
82
+ */
83
+ interface StreamableAdapter extends AgentAdapter {
84
+ /**
85
+ * Streams events from a custom execution flow.
86
+ *
87
+ * This method handles the full lifecycle:
88
+ * - Starting any required processes/servers
89
+ * - Connecting to event sources
90
+ * - Yielding normalized events
91
+ * - Cleanup on completion or error
92
+ *
93
+ * @param options - Run options including prompt and flags
94
+ * @yields Normalized events as they arrive
95
+ */
96
+ streamSession(options: RunOptions): AsyncGenerator<AxexecEvent>;
97
+ }
98
+ /** Type guard to check if an adapter implements StreamableAdapter */
99
+ declare function isStreamableAdapter(adapter: AgentAdapter): adapter is StreamableAdapter;
100
+ export type { AgentAdapter, AgentInfo, EventParser, PreparedCommand, StreamableAdapter, };
101
+ export { isStreamableAdapter };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Adapter interface and related types.
3
+ *
4
+ * Each agent implements the {@link AgentAdapter} interface to provide
5
+ * a consistent way to prepare commands and parse events.
6
+ *
7
+ * Adapters may optionally implement {@link StreamableAdapter} to provide
8
+ * custom streaming behavior (e.g., for server-mode agents).
9
+ */
10
+ /** Type guard to check if an adapter implements StreamableAdapter */
11
+ function isStreamableAdapter(adapter) {
12
+ return ("streamSession" in adapter && typeof adapter.streamSession === "function");
13
+ }
14
+ export { isStreamableAdapter };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Normalized event types for axexec.
3
+ *
4
+ * All agent adapters transform their raw JSONL events into these
5
+ * normalized types, providing a consistent interface regardless
6
+ * of which underlying agent is used.
7
+ *
8
+ * Events are grouped by semantic category:
9
+ * - session.*: Session lifecycle (start, complete, error)
10
+ * - agent.*: Agent content output (reasoning, message)
11
+ * - tool.*: Tool execution (call, result)
12
+ */
13
+ export type { AgentCli } from "axshared";
14
+ type AgentCli = import("axshared").AgentCli;
15
+ /** Statistics collected during session execution */
16
+ interface SessionStats {
17
+ durationMs: number;
18
+ costUsd?: number;
19
+ inputTokens?: number;
20
+ outputTokens?: number;
21
+ }
22
+ /** Emitted when a session begins */
23
+ interface SessionStartEvent {
24
+ type: "session.start";
25
+ /** Unique identifier for this session */
26
+ sessionId: string;
27
+ agent: AgentCli;
28
+ /** Model used for this session (e.g., "claude-sonnet-4-5-20250929", "gpt-4") */
29
+ model: string;
30
+ /** Provider of the model, if known (e.g., "anthropic", "openai", "google") */
31
+ provider?: string;
32
+ timestamp: number;
33
+ }
34
+ /** Emitted when a session completes successfully */
35
+ interface SessionCompleteEvent {
36
+ type: "session.complete";
37
+ stats: SessionStats;
38
+ timestamp: number;
39
+ }
40
+ /** Emitted when a session ends with an error */
41
+ interface SessionErrorEvent {
42
+ type: "session.error";
43
+ code: string;
44
+ message: string;
45
+ timestamp: number;
46
+ }
47
+ /** Emitted when the agent produces internal reasoning (chain-of-thought) */
48
+ interface AgentReasoningEvent {
49
+ type: "agent.reasoning";
50
+ content: string;
51
+ timestamp: number;
52
+ }
53
+ /** Emitted when the agent produces a message/response to the user */
54
+ interface AgentMessageEvent {
55
+ type: "agent.message";
56
+ content: string;
57
+ timestamp: number;
58
+ }
59
+ /** Emitted when the agent invokes a tool */
60
+ interface ToolCallEvent {
61
+ type: "tool.call";
62
+ /** Unique identifier for this tool invocation, used to correlate with result */
63
+ callId: string;
64
+ /** Human-readable tool name */
65
+ tool: string;
66
+ input: unknown;
67
+ timestamp: number;
68
+ }
69
+ /** Emitted when a tool returns its result */
70
+ interface ToolResultEvent {
71
+ type: "tool.result";
72
+ /** Matches the callId from the corresponding tool.call event */
73
+ callId: string;
74
+ /** Human-readable tool name (resolved via correlation with tool.call) */
75
+ tool: string;
76
+ output: unknown;
77
+ success: boolean;
78
+ timestamp: number;
79
+ }
80
+ /** Discriminated union of all normalized event types */
81
+ type AxexecEvent = SessionStartEvent | SessionCompleteEvent | SessionErrorEvent | AgentReasoningEvent | AgentMessageEvent | ToolCallEvent | ToolResultEvent;
82
+ export type { AxexecEvent };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Normalized event types for axexec.
3
+ *
4
+ * All agent adapters transform their raw JSONL events into these
5
+ * normalized types, providing a consistent interface regardless
6
+ * of which underlying agent is used.
7
+ *
8
+ * Events are grouped by semantic category:
9
+ * - session.*: Session lifecycle (start, complete, error)
10
+ * - agent.*: Agent content output (reasoning, message)
11
+ * - tool.*: Tool execution (call, result)
12
+ */
13
+ export {};
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Options types for running agents.
3
+ */
4
+ /** Options for running an agent */
5
+ interface RunOptions {
6
+ /** The prompt to send to the agent */
7
+ prompt: string;
8
+ /** Show verbose/debug output from the agent */
9
+ verbose: boolean;
10
+ /** Working directory for the agent process */
11
+ cwd?: string;
12
+ /** Path to write raw agent JSONL output for debugging/fixtures */
13
+ rawLogPath?: string;
14
+ /** Enable debug mode (logs unknown events, additional diagnostics) */
15
+ debug?: boolean;
16
+ /**
17
+ * Additional environment variables for agent configuration.
18
+ * Generated by ConfigBuilder to point to temp config files.
19
+ */
20
+ configEnv?: Record<string, string>;
21
+ /**
22
+ * Model to use. Format varies by agent:
23
+ * - Claude Code: aliases ('sonnet', 'opus', 'haiku') or full model names
24
+ * - Codex: model names ('o4-mini', 'gpt-5.1-codex')
25
+ * - Gemini: aliases ('pro', 'flash') or full names ('gemini-2.5-pro')
26
+ * - Copilot: model names ('gpt-5', 'claude-sonnet-4.5')
27
+ * - OpenCode: provider/model format ('anthropic/claude-sonnet-4')
28
+ */
29
+ model?: string;
30
+ /**
31
+ * Preserve GITHUB_SHA environment variable.
32
+ *
33
+ * When false (default), Gemini excludes GITHUB_SHA to work around a CLI bug
34
+ * where strict environment sanitization blocks GH_TOKEN from reaching shell
35
+ * commands when GITHUB_SHA is set.
36
+ *
37
+ * Set to true to preserve GITHUB_SHA in the child process environment.
38
+ */
39
+ preserveGithubSha?: boolean;
40
+ }
41
+ export type { RunOptions };
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Options types for running agents.
3
+ */
4
+ export {};
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Agent validation utilities.
3
+ */
4
+ import { type AgentCli } from "axshared";
5
+ import type { AgentAdapter } from "./types/adapter.js";
6
+ /** Result of validating an agent */
7
+ type ValidateAgentResult = {
8
+ ok: true;
9
+ agentId: AgentCli;
10
+ adapter: AgentAdapter;
11
+ } | {
12
+ ok: false;
13
+ exitCode: number;
14
+ message: string;
15
+ };
16
+ /**
17
+ * Validate that an agent ID is valid and the adapter is available.
18
+ */
19
+ declare function validateAgent(agentId: string | undefined): ValidateAgentResult;
20
+ export { validateAgent };