axexec 1.0.0 → 1.1.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.
- package/README.md +21 -0
- package/dist/agents/claude-code/types.d.ts +2 -2
- package/dist/agents/codex/adapter.js +8 -13
- package/dist/agents/gemini/types.d.ts +4 -4
- package/dist/build-agent-environment.d.ts +2 -0
- package/dist/build-agent-environment.js +19 -0
- package/dist/build-execution-metadata.d.ts +10 -0
- package/dist/build-execution-metadata.js +27 -0
- package/dist/build-permissions-config.d.ts +24 -0
- package/dist/build-permissions-config.js +48 -0
- package/dist/credentials/credentials.d.ts +39 -0
- package/dist/credentials/credentials.js +73 -0
- package/dist/credentials/get-credential-environment.d.ts +7 -5
- package/dist/credentials/get-credential-environment.js +44 -14
- package/dist/credentials/get-environment-trimmed.d.ts +5 -0
- package/dist/credentials/get-environment-trimmed.js +8 -0
- package/dist/credentials/install-credentials.d.ts +7 -6
- package/dist/credentials/install-credentials.js +26 -16
- package/dist/credentials/resolve-string-field.d.ts +7 -0
- package/dist/credentials/resolve-string-field.js +21 -0
- package/dist/credentials/types.d.ts +1 -10
- package/dist/credentials/write-agent-credentials.d.ts +28 -6
- package/dist/credentials/write-agent-credentials.js +88 -43
- package/dist/execute-agent.d.ts +12 -0
- package/dist/execute-agent.js +68 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +10 -0
- package/dist/parse-credentials.d.ts +17 -3
- package/dist/parse-credentials.js +146 -27
- package/dist/resolve-run-diagnostics.d.ts +9 -0
- package/dist/resolve-run-diagnostics.js +35 -0
- package/dist/run-agent.d.ts +4 -20
- package/dist/run-agent.js +67 -109
- package/dist/stream-agent.js +5 -15
- package/dist/types/run-result.d.ts +81 -0
- package/dist/types/run-result.js +4 -0
- package/package.json +10 -2
package/dist/run-agent.d.ts
CHANGED
|
@@ -1,32 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent execution with credential isolation and config generation.
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
5
|
-
import { type OutputFormat } from "./resolve-output-mode.js";
|
|
6
|
-
interface RunAgentOptions {
|
|
7
|
-
prompt: string;
|
|
8
|
-
model?: string;
|
|
9
|
-
allow?: string;
|
|
10
|
-
deny?: string;
|
|
11
|
-
format?: OutputFormat;
|
|
12
|
-
rawLog?: string;
|
|
13
|
-
debug?: boolean;
|
|
14
|
-
verbose?: boolean;
|
|
15
|
-
preserveGithubSha?: boolean;
|
|
16
|
-
}
|
|
17
|
-
interface RunResult {
|
|
18
|
-
events: AxexecEvent[];
|
|
19
|
-
success: boolean;
|
|
20
|
-
}
|
|
4
|
+
import type { RunAgentOptions, RunResult } from "./types/run-result.js";
|
|
21
5
|
/**
|
|
22
6
|
* Runs an agent with full isolation.
|
|
23
7
|
*
|
|
24
8
|
* 1. Validates the agent ID
|
|
25
|
-
* 2.
|
|
26
|
-
* 3.
|
|
9
|
+
* 2. Uses provided credentials or parses from environment
|
|
10
|
+
* 3. Creates isolated temp directories and installs credentials if provided
|
|
27
11
|
* 4. Builds config if permissions specified
|
|
28
12
|
* 5. Streams events from agent
|
|
29
|
-
* 6. Cleans up temp directory
|
|
13
|
+
* 6. Cleans up temp directory (unless preserveConfigDirectory is true)
|
|
30
14
|
*/
|
|
31
15
|
declare function runAgent(agentId: string, options: RunAgentOptions): Promise<RunResult>;
|
|
32
16
|
export { runAgent };
|
package/dist/run-agent.js
CHANGED
|
@@ -1,146 +1,104 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent execution with credential isolation and config generation.
|
|
3
3
|
*/
|
|
4
|
-
import { buildAgentConfig } from "axconfig";
|
|
5
|
-
import { isStreamableAdapter } from "./types/adapter.js";
|
|
6
4
|
import { installCredentials, cleanupCredentials, } from "./credentials/install-credentials.js";
|
|
7
|
-
import {
|
|
5
|
+
import { buildPermissionsConfig } from "./build-permissions-config.js";
|
|
8
6
|
import { validateAgent } from "./validate-agent.js";
|
|
9
|
-
import { resolveOutputMode } from "./resolve-output-mode.js";
|
|
10
|
-
import { createEventWriter } from "./write-event.js";
|
|
11
7
|
import { parseCredentialsFromEnvironment } from "./parse-credentials.js";
|
|
12
|
-
import {
|
|
8
|
+
import { buildExecutionMetadata } from "./build-execution-metadata.js";
|
|
9
|
+
import { executeAgent } from "./execute-agent.js";
|
|
10
|
+
import { resolveDiagnostics, resolveExitCodeSetter, } from "./resolve-run-diagnostics.js";
|
|
13
11
|
/**
|
|
14
12
|
* Runs an agent with full isolation.
|
|
15
13
|
*
|
|
16
14
|
* 1. Validates the agent ID
|
|
17
|
-
* 2.
|
|
18
|
-
* 3.
|
|
15
|
+
* 2. Uses provided credentials or parses from environment
|
|
16
|
+
* 3. Creates isolated temp directories and installs credentials if provided
|
|
19
17
|
* 4. Builds config if permissions specified
|
|
20
18
|
* 5. Streams events from agent
|
|
21
|
-
* 6. Cleans up temp directory
|
|
19
|
+
* 6. Cleans up temp directory (unless preserveConfigDirectory is true)
|
|
22
20
|
*/
|
|
23
21
|
async function runAgent(agentId, options) {
|
|
22
|
+
const diagnostics = resolveDiagnostics(options);
|
|
23
|
+
const setExitCode = resolveExitCodeSetter(options);
|
|
24
|
+
const preserveConfigDirectory = options.preserveConfigDirectory ?? false;
|
|
24
25
|
// Validate agent
|
|
25
26
|
const validation = validateAgent(agentId);
|
|
26
27
|
if (!validation.ok) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
diagnostics.error(validation.message);
|
|
29
|
+
setExitCode(validation.exitCode);
|
|
30
|
+
// Return minimal execution metadata for failed validation
|
|
31
|
+
return {
|
|
32
|
+
events: [],
|
|
33
|
+
success: false,
|
|
34
|
+
execution: { agent: "unknown", invalidAgentId: agentId },
|
|
35
|
+
};
|
|
30
36
|
}
|
|
31
37
|
const { adapter } = validation;
|
|
32
|
-
//
|
|
33
|
-
const
|
|
34
|
-
|
|
38
|
+
// Use provided credentials or parse from environment
|
|
39
|
+
const credentialsResult = options.credentials
|
|
40
|
+
? { ok: true, credentials: options.credentials }
|
|
41
|
+
: parseCredentialsFromEnvironment(validation.agentId, options.model);
|
|
42
|
+
if (!credentialsResult.ok) {
|
|
43
|
+
diagnostics.error(credentialsResult.message);
|
|
44
|
+
setExitCode(credentialsResult.exitCode);
|
|
45
|
+
return {
|
|
46
|
+
events: [],
|
|
47
|
+
success: false,
|
|
48
|
+
execution: { agent: validation.agentId, model: options.model },
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Credentials are optional; isolation still applies even when none are found.
|
|
52
|
+
const credentials = credentialsResult.credentials;
|
|
53
|
+
if (credentials && credentials.agent !== validation.agentId) {
|
|
54
|
+
diagnostics.error("Error: Credentials agent mismatch. " +
|
|
55
|
+
`Expected ${validation.agentId}, got ${credentials.agent}.`);
|
|
56
|
+
setExitCode(2);
|
|
57
|
+
return {
|
|
58
|
+
events: [],
|
|
59
|
+
success: false,
|
|
60
|
+
execution: { agent: validation.agentId, model: options.model },
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Always create isolated runtime directories; install credentials if provided.
|
|
35
64
|
let credentialResult;
|
|
36
65
|
try {
|
|
37
|
-
credentialResult = await installCredentials(validation.agentId, credentials);
|
|
66
|
+
credentialResult = await installCredentials(validation.agentId, credentials, diagnostics.warn);
|
|
38
67
|
}
|
|
39
68
|
catch (error) {
|
|
40
69
|
const message = error instanceof Error ? error.message : String(error);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return {
|
|
70
|
+
diagnostics.error(`Error installing credentials: ${message}`);
|
|
71
|
+
setExitCode(1);
|
|
72
|
+
return {
|
|
73
|
+
events: [],
|
|
74
|
+
success: false,
|
|
75
|
+
execution: { agent: validation.agentId, model: options.model },
|
|
76
|
+
};
|
|
44
77
|
}
|
|
45
78
|
// Build config if permissions specified
|
|
46
79
|
let configEnvironment = credentialResult.env;
|
|
47
80
|
if (options.allow || options.deny) {
|
|
48
|
-
const configResult =
|
|
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
|
-
});
|
|
81
|
+
const configResult = buildPermissionsConfig(validation.agentId, options, credentialResult);
|
|
70
82
|
if (!configResult.ok) {
|
|
71
|
-
|
|
72
|
-
|
|
83
|
+
for (const error of configResult.errors) {
|
|
84
|
+
diagnostics.error(error);
|
|
73
85
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
for (const error of configResult.errors) {
|
|
77
|
-
process.stderr.write(` - ${error.reason}\n`);
|
|
78
|
-
}
|
|
86
|
+
if (!preserveConfigDirectory) {
|
|
87
|
+
await cleanupCredentials(credentialResult.baseDirectory);
|
|
79
88
|
}
|
|
80
|
-
|
|
89
|
+
setExitCode(configResult.exitCode);
|
|
90
|
+
return {
|
|
91
|
+
events: [],
|
|
92
|
+
success: false,
|
|
93
|
+
execution: buildExecutionMetadata(validation.agentId, options, credentialResult, credentials, preserveConfigDirectory),
|
|
94
|
+
};
|
|
81
95
|
}
|
|
82
|
-
// Log warnings
|
|
83
96
|
for (const warning of configResult.warnings) {
|
|
84
|
-
|
|
97
|
+
diagnostics.warn(warning);
|
|
85
98
|
}
|
|
86
|
-
|
|
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);
|
|
99
|
+
configEnvironment = configResult.env;
|
|
144
100
|
}
|
|
101
|
+
// Execute agent
|
|
102
|
+
return executeAgent(validation.agentId, adapter, options, configEnvironment, credentialResult, credentials, preserveConfigDirectory, diagnostics.error);
|
|
145
103
|
}
|
|
146
104
|
export { runAgent };
|
package/dist/stream-agent.js
CHANGED
|
@@ -7,14 +7,7 @@
|
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
8
8
|
import { createWriteStream } from "node:fs";
|
|
9
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"];
|
|
10
|
+
import { buildBaseEnvironment } from "./build-agent-environment.js";
|
|
18
11
|
/** Error thrown when agent binary is not found */
|
|
19
12
|
class AgentNotFoundError extends Error {
|
|
20
13
|
bin;
|
|
@@ -56,13 +49,10 @@ async function* streamAgent(adapter, options) {
|
|
|
56
49
|
process.stderr.write(`Warning: raw log error: ${error.message}\n`);
|
|
57
50
|
});
|
|
58
51
|
}
|
|
59
|
-
// Build environment: start with process.env, exclude vault vars
|
|
60
|
-
// adapter-specified vars, then merge adapter
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
...(environmentExclusions ?? []),
|
|
64
|
-
]);
|
|
65
|
-
const baseEnvironment = Object.fromEntries(Object.entries(process.env).filter(([key]) => !allExclusions.has(key)));
|
|
52
|
+
// Build environment: start with process.env, exclude vault vars,
|
|
53
|
+
// AX_*_CREDENTIALS, and any adapter-specified vars, then merge adapter
|
|
54
|
+
// env and config env.
|
|
55
|
+
const baseEnvironment = buildBaseEnvironment(environmentExclusions ?? []);
|
|
66
56
|
const child = spawn(bin, args, {
|
|
67
57
|
env: { ...baseEnvironment, ...env, ...options.configEnv },
|
|
68
58
|
cwd: options.cwd,
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for run-agent results and options.
|
|
3
|
+
*/
|
|
4
|
+
import type { AgentCli, AxexecEvent } from "./events.js";
|
|
5
|
+
import type { OutputFormat } from "../resolve-output-mode.js";
|
|
6
|
+
import type { Credentials } from "../credentials/credentials.js";
|
|
7
|
+
interface RunAgentDiagnostics {
|
|
8
|
+
error: (message: string) => void;
|
|
9
|
+
warn: (message: string) => void;
|
|
10
|
+
}
|
|
11
|
+
interface RunAgentOptions {
|
|
12
|
+
prompt: string;
|
|
13
|
+
/**
|
|
14
|
+
* Credentials to use. If not provided, parses from environment variables.
|
|
15
|
+
* Accepts the canonical Credentials shape shared across ax* packages.
|
|
16
|
+
*/
|
|
17
|
+
credentials?: Credentials;
|
|
18
|
+
model?: string;
|
|
19
|
+
allow?: string;
|
|
20
|
+
deny?: string;
|
|
21
|
+
format?: OutputFormat;
|
|
22
|
+
rawLog?: string;
|
|
23
|
+
debug?: boolean;
|
|
24
|
+
verbose?: boolean;
|
|
25
|
+
preserveGithubSha?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Override diagnostic output (errors, warnings) emitted during setup.
|
|
28
|
+
* Messages include a trailing newline.
|
|
29
|
+
*/
|
|
30
|
+
diagnostics?: RunAgentDiagnostics;
|
|
31
|
+
/**
|
|
32
|
+
* When false, runAgent will not mutate process.exitCode on failures.
|
|
33
|
+
*/
|
|
34
|
+
setExitCode?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* When true, the temporary config directory is NOT cleaned up after execution.
|
|
37
|
+
* The caller is responsible for cleanup via `cleanupCredentials()`.
|
|
38
|
+
* Use this when you need to read files from the config directory after
|
|
39
|
+
* execution (e.g., refreshed credentials).
|
|
40
|
+
*/
|
|
41
|
+
preserveConfigDirectory?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Directory information from execution */
|
|
44
|
+
interface ExecutionDirectories {
|
|
45
|
+
/** Base temp directory (parent of config/data dirs) */
|
|
46
|
+
base: string;
|
|
47
|
+
/** Config directory where settings/credentials were installed */
|
|
48
|
+
config: string;
|
|
49
|
+
/** Data directory (may be same as config for some agents) */
|
|
50
|
+
data: string;
|
|
51
|
+
/** Whether directories were preserved (not cleaned up) */
|
|
52
|
+
preserved: boolean;
|
|
53
|
+
}
|
|
54
|
+
/** Credential information from execution */
|
|
55
|
+
interface ExecutionCredentials {
|
|
56
|
+
/** Type of credential used */
|
|
57
|
+
type: "api-key" | "oauth-credentials" | "oauth-token";
|
|
58
|
+
/** Provider (for multi-provider agents like OpenCode) */
|
|
59
|
+
provider?: string;
|
|
60
|
+
}
|
|
61
|
+
type ExecutionAgent = AgentCli | "unknown";
|
|
62
|
+
/** Execution metadata - always present in RunResult */
|
|
63
|
+
interface ExecutionMetadata {
|
|
64
|
+
/** Agent that was executed */
|
|
65
|
+
agent: ExecutionAgent;
|
|
66
|
+
/** Invalid agent ID when validation fails */
|
|
67
|
+
invalidAgentId?: string;
|
|
68
|
+
/** Temporary directory paths (present when isolation dirs were created) */
|
|
69
|
+
directories?: ExecutionDirectories;
|
|
70
|
+
/** Credential information (present if credentials were provided) */
|
|
71
|
+
credentials?: ExecutionCredentials;
|
|
72
|
+
/** Model used (if specified) */
|
|
73
|
+
model?: string;
|
|
74
|
+
}
|
|
75
|
+
interface RunResult {
|
|
76
|
+
events: AxexecEvent[];
|
|
77
|
+
success: boolean;
|
|
78
|
+
/** Execution metadata - always present */
|
|
79
|
+
execution: ExecutionMetadata;
|
|
80
|
+
}
|
|
81
|
+
export type { ExecutionCredentials, ExecutionDirectories, ExecutionMetadata, RunAgentDiagnostics, RunAgentOptions, RunResult, };
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "axexec",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.1.0",
|
|
6
6
|
"description": "Unified CLI runner for AI coding agents with normalized event streaming",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
"url": "https://github.com/Jercik/axexec/issues"
|
|
14
14
|
},
|
|
15
15
|
"type": "module",
|
|
16
|
+
"main": "dist/index.js",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
16
24
|
"bin": {
|
|
17
25
|
"axexec": "bin/axexec"
|
|
18
26
|
},
|
|
@@ -58,7 +66,7 @@
|
|
|
58
66
|
"dependencies": {
|
|
59
67
|
"@commander-js/extra-typings": "^14.0.0",
|
|
60
68
|
"axconfig": "^3.6.0",
|
|
61
|
-
"axshared": "^
|
|
69
|
+
"axshared": "^2.0.0",
|
|
62
70
|
"commander": "^14.0.2",
|
|
63
71
|
"zod": "^4.3.5"
|
|
64
72
|
},
|