axconfig 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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +249 -0
  3. package/bin/axconfig +17 -0
  4. package/dist/agents/claude-code.d.ts +14 -0
  5. package/dist/agents/claude-code.js +98 -0
  6. package/dist/agents/codex.d.ts +15 -0
  7. package/dist/agents/codex.js +164 -0
  8. package/dist/agents/gemini.d.ts +14 -0
  9. package/dist/agents/gemini.js +156 -0
  10. package/dist/agents/opencode.d.ts +14 -0
  11. package/dist/agents/opencode.js +152 -0
  12. package/dist/auth/agents/claude-code.d.ts +9 -0
  13. package/dist/auth/agents/claude-code.js +106 -0
  14. package/dist/auth/agents/codex.d.ts +9 -0
  15. package/dist/auth/agents/codex.js +75 -0
  16. package/dist/auth/agents/gemini.d.ts +9 -0
  17. package/dist/auth/agents/gemini.js +97 -0
  18. package/dist/auth/agents/opencode.d.ts +9 -0
  19. package/dist/auth/agents/opencode.js +62 -0
  20. package/dist/auth/check-auth.d.ts +13 -0
  21. package/dist/auth/check-auth.js +24 -0
  22. package/dist/auth/extract-credentials.d.ts +11 -0
  23. package/dist/auth/extract-credentials.js +20 -0
  24. package/dist/auth/get-access-token.d.ts +35 -0
  25. package/dist/auth/get-access-token.js +116 -0
  26. package/dist/auth/types.d.ts +19 -0
  27. package/dist/auth/types.js +4 -0
  28. package/dist/build-agent-config.d.ts +41 -0
  29. package/dist/build-agent-config.js +79 -0
  30. package/dist/builder.d.ts +19 -0
  31. package/dist/builder.js +27 -0
  32. package/dist/cli.d.ts +10 -0
  33. package/dist/cli.js +79 -0
  34. package/dist/commands/auth.d.ts +19 -0
  35. package/dist/commands/auth.js +87 -0
  36. package/dist/commands/create.d.ts +14 -0
  37. package/dist/commands/create.js +101 -0
  38. package/dist/crypto.d.ts +39 -0
  39. package/dist/crypto.js +78 -0
  40. package/dist/index.d.ts +51 -0
  41. package/dist/index.js +53 -0
  42. package/dist/parse-permissions.d.ts +50 -0
  43. package/dist/parse-permissions.js +125 -0
  44. package/dist/types.d.ts +85 -0
  45. package/dist/types.js +8 -0
  46. package/package.json +93 -0
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Create command - generates agent-specific configuration.
3
+ */
4
+ interface CreateOptions {
5
+ agent: string;
6
+ output: string;
7
+ allow?: string;
8
+ deny?: string;
9
+ format: string;
10
+ withCredentials?: string;
11
+ }
12
+ /** Handle create command */
13
+ declare function handleCreate(options: CreateOptions): Promise<void>;
14
+ export { handleCreate };
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Create command - generates agent-specific configuration.
3
+ */
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import promptPassword from "@inquirer/password";
6
+ import { credentialsToEnvironment } from "../auth/get-access-token.js";
7
+ import { buildAgentConfig, formatPermissionErrors, formatPermissionWarnings, } from "../build-agent-config.js";
8
+ import { fromBase64, tryDecrypt } from "../crypto.js";
9
+ import { AGENT_IDS } from "../types.js";
10
+ /** Handle create command */
11
+ async function handleCreate(options) {
12
+ const { agent } = options;
13
+ // Validate agent
14
+ if (!AGENT_IDS.includes(agent)) {
15
+ console.error(`Error: Unknown agent '${agent}'`);
16
+ console.error(`Supported agents: ${AGENT_IDS.join(", ")}`);
17
+ process.exitCode = 2;
18
+ return;
19
+ }
20
+ // Handle credentials file
21
+ let credentialEnvironment = {};
22
+ if (options.withCredentials) {
23
+ const result = await loadCredentials(options.withCredentials, agent);
24
+ if (!result.ok) {
25
+ process.exitCode = result.exitCode;
26
+ return;
27
+ }
28
+ credentialEnvironment = result.environment;
29
+ }
30
+ const result = buildAgentConfig({
31
+ agentId: agent,
32
+ allow: options.allow,
33
+ deny: options.deny,
34
+ output: options.output,
35
+ });
36
+ if (!result.ok) {
37
+ if ("errors" in result) {
38
+ console.error(formatPermissionErrors(result.errors));
39
+ }
40
+ else {
41
+ console.error(`Error: ${result.message}`);
42
+ }
43
+ process.exitCode = result.exitCode;
44
+ return;
45
+ }
46
+ // Merge credential env vars with config env vars
47
+ const environment = { ...credentialEnvironment, ...result.env };
48
+ // Show warnings
49
+ if (result.warnings.length > 0) {
50
+ console.error(formatPermissionWarnings(result.warnings));
51
+ }
52
+ // Output based on format
53
+ if (options.format === "json") {
54
+ console.log(JSON.stringify({ env: environment }, undefined, 2));
55
+ }
56
+ else {
57
+ // env format (default)
58
+ for (const [key, value] of Object.entries(environment)) {
59
+ console.log(`export ${key}="${value}"`);
60
+ }
61
+ }
62
+ }
63
+ /** Load and decrypt credentials file */
64
+ async function loadCredentials(filePath, expectedAgent) {
65
+ if (!existsSync(filePath)) {
66
+ console.error(`Error: Credentials file not found: ${filePath}`);
67
+ return { ok: false, exitCode: 1 };
68
+ }
69
+ try {
70
+ const fileContent = JSON.parse(readFileSync(filePath, "utf8"));
71
+ // Verify agent matches
72
+ if (fileContent.agent !== expectedAgent) {
73
+ console.error(`Error: Credentials file is for '${fileContent.agent}', not '${expectedAgent}'`);
74
+ return { ok: false, exitCode: 1 };
75
+ }
76
+ // Decrypt credentials (tries default password first)
77
+ const decrypted = await tryDecrypt(fromBase64(fileContent), () => promptPassword({ message: "Decryption password" }));
78
+ const creds = JSON.parse(decrypted);
79
+ // Convert credentials to env vars
80
+ const environment = credentialsToEnvironment(creds);
81
+ // Warn if credentials couldn't be converted to env vars
82
+ if (Object.keys(environment).length === 0) {
83
+ const warnings = {
84
+ codex: "Codex OAuth tokens require auth.json; use API key instead",
85
+ gemini: "Gemini OAuth requires oauth_creds.json; use API key instead",
86
+ opencode: "OpenCode credentials require auth.json file",
87
+ };
88
+ const warning = warnings[creds.agent];
89
+ if (warning) {
90
+ console.error(`Warning: ${warning}`);
91
+ }
92
+ }
93
+ return { ok: true, environment };
94
+ }
95
+ catch (error) {
96
+ const message = error instanceof Error ? error.message : String(error);
97
+ console.error(`Error: Failed to decrypt credentials: ${message}`);
98
+ return { ok: false, exitCode: 1 };
99
+ }
100
+ }
101
+ export { handleCreate };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Encryption utilities for credential export/import.
3
+ *
4
+ * Uses AES-256-GCM with PBKDF2 key derivation.
5
+ */
6
+ /**
7
+ * Derive default password from predictable seed.
8
+ * Provides obfuscation, not security - attacker would need to understand derivation logic.
9
+ */
10
+ declare const DEFAULT_PASSWORD: string;
11
+ /** Encrypted data structure */
12
+ interface EncryptedData {
13
+ ciphertext: Buffer;
14
+ salt: Buffer;
15
+ iv: Buffer;
16
+ tag: Buffer;
17
+ }
18
+ /** Serialized encrypted file format */
19
+ interface EncryptedFile {
20
+ version: 1;
21
+ agent: string;
22
+ ciphertext: string;
23
+ salt: string;
24
+ iv: string;
25
+ tag: string;
26
+ }
27
+ /** Encrypt data with password */
28
+ declare function encrypt(data: string, password: string): EncryptedData;
29
+ /** Convert encrypted data to base64 for JSON serialization */
30
+ declare function toBase64(encrypted: EncryptedData): Omit<EncryptedFile, "version" | "agent">;
31
+ /** Convert base64 strings back to buffers */
32
+ declare function fromBase64(file: Omit<EncryptedFile, "version" | "agent">): EncryptedData;
33
+ /**
34
+ * Try decrypting with default password first, then prompt for custom.
35
+ * Returns decrypted string on success.
36
+ */
37
+ declare function tryDecrypt(encrypted: EncryptedData, promptFunction: () => Promise<string>): Promise<string>;
38
+ export { DEFAULT_PASSWORD, encrypt, fromBase64, toBase64, tryDecrypt };
39
+ export type { EncryptedFile };
package/dist/crypto.js ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Encryption utilities for credential export/import.
3
+ *
4
+ * Uses AES-256-GCM with PBKDF2 key derivation.
5
+ */
6
+ import { createCipheriv, createDecipheriv, createHash, pbkdf2Sync, randomBytes, } from "node:crypto";
7
+ const ALGORITHM = "aes-256-gcm";
8
+ const ITERATIONS = 100_000;
9
+ const KEY_LENGTH = 32;
10
+ const SALT_LENGTH = 16;
11
+ const IV_LENGTH = 12;
12
+ const TAG_LENGTH = 16;
13
+ /**
14
+ * Derive default password from predictable seed.
15
+ * Provides obfuscation, not security - attacker would need to understand derivation logic.
16
+ */
17
+ const DEFAULT_PASSWORD = createHash("sha256")
18
+ .update(["axconfig", "credentials", "default", "v1"].join("."))
19
+ .digest("base64")
20
+ .slice(0, 32);
21
+ /** Encrypt data with password */
22
+ function encrypt(data, password) {
23
+ const salt = randomBytes(SALT_LENGTH);
24
+ const key = pbkdf2Sync(password, salt, ITERATIONS, KEY_LENGTH, "sha256");
25
+ const iv = randomBytes(IV_LENGTH);
26
+ const cipher = createCipheriv(ALGORITHM, key, iv, {
27
+ authTagLength: TAG_LENGTH,
28
+ });
29
+ const ciphertext = Buffer.concat([
30
+ cipher.update(data, "utf8"),
31
+ cipher.final(),
32
+ ]);
33
+ return { ciphertext, salt, iv, tag: cipher.getAuthTag() };
34
+ }
35
+ /** Decrypt data with password. Throws on wrong password. */
36
+ function decrypt(encrypted, password) {
37
+ const key = pbkdf2Sync(password, encrypted.salt, ITERATIONS, KEY_LENGTH, "sha256");
38
+ const decipher = createDecipheriv(ALGORITHM, key, encrypted.iv, {
39
+ authTagLength: TAG_LENGTH,
40
+ });
41
+ decipher.setAuthTag(encrypted.tag);
42
+ return (decipher.update(encrypted.ciphertext).toString("utf8") +
43
+ decipher.final("utf8"));
44
+ }
45
+ /** Convert encrypted data to base64 for JSON serialization */
46
+ function toBase64(encrypted) {
47
+ return {
48
+ ciphertext: encrypted.ciphertext.toString("base64"),
49
+ salt: encrypted.salt.toString("base64"),
50
+ iv: encrypted.iv.toString("base64"),
51
+ tag: encrypted.tag.toString("base64"),
52
+ };
53
+ }
54
+ /** Convert base64 strings back to buffers */
55
+ function fromBase64(file) {
56
+ return {
57
+ ciphertext: Buffer.from(file.ciphertext, "base64"),
58
+ salt: Buffer.from(file.salt, "base64"),
59
+ iv: Buffer.from(file.iv, "base64"),
60
+ tag: Buffer.from(file.tag, "base64"),
61
+ };
62
+ }
63
+ /**
64
+ * Try decrypting with default password first, then prompt for custom.
65
+ * Returns decrypted string on success.
66
+ */
67
+ async function tryDecrypt(encrypted, promptFunction) {
68
+ // Try default password first
69
+ try {
70
+ return decrypt(encrypted, DEFAULT_PASSWORD);
71
+ }
72
+ catch {
73
+ // Default password failed, prompt user
74
+ const password = await promptFunction();
75
+ return decrypt(encrypted, password);
76
+ }
77
+ }
78
+ export { DEFAULT_PASSWORD, encrypt, fromBase64, toBase64, tryDecrypt };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * axconfig - Configuration management library for AI coding agents.
3
+ *
4
+ * @example
5
+ * // Build agent-specific config
6
+ * import { buildAgentConfig } from "axconfig";
7
+ *
8
+ * const result = buildAgentConfig({
9
+ * agentId: "claude-code",
10
+ * allow: "read,glob",
11
+ * deny: "bash:rm *",
12
+ * output: "/tmp/axconfig",
13
+ * });
14
+ *
15
+ * if (result.ok) {
16
+ * // Use result.env for agent environment
17
+ * }
18
+ *
19
+ * @example
20
+ * // Get access token for an agent
21
+ * import { getAgentAccessToken, checkAuth } from "axconfig";
22
+ *
23
+ * const token = getAgentAccessToken("claude-code");
24
+ * if (token) {
25
+ * // Use token for API calls
26
+ * }
27
+ *
28
+ * // Or check auth status first
29
+ * const status = checkAuth("claude-code");
30
+ * if (status.authenticated) {
31
+ * console.log(`Authenticated via ${status.method}`);
32
+ * }
33
+ */
34
+ export type { AgentCapabilities, AgentId, AxrunConfig, BuildResult, CanonicalTool, ConfigBuilder, PermissionConfig, PermissionIssue, PermissionRule, } from "./types.js";
35
+ export { AGENT_IDS } from "./types.js";
36
+ export type { AuthStatus } from "./auth/check-auth.js";
37
+ export { checkAuth, checkAllAuth } from "./auth/check-auth.js";
38
+ export type { Credentials } from "./auth/extract-credentials.js";
39
+ export { extractCredentials } from "./auth/extract-credentials.js";
40
+ export { credentialsToEnvironment, getAccessToken, getAgentAccessToken, } from "./auth/get-access-token.js";
41
+ export { formatRule, parsePermissions, parseRule, parseRuleList, } from "./parse-permissions.js";
42
+ export { getConfigBuilder, registerConfigBuilder } from "./builder.js";
43
+ export { buildAgentConfig, formatPermissionErrors, formatPermissionWarnings, } from "./build-agent-config.js";
44
+ import "./agents/claude-code.js";
45
+ import "./agents/codex.js";
46
+ import "./agents/gemini.js";
47
+ import "./agents/opencode.js";
48
+ export { claudeCodeConfigBuilder } from "./agents/claude-code.js";
49
+ export { codexConfigBuilder } from "./agents/codex.js";
50
+ export { geminiConfigBuilder } from "./agents/gemini.js";
51
+ export { openCodeConfigBuilder } from "./agents/opencode.js";
package/dist/index.js ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * axconfig - Configuration management library for AI coding agents.
3
+ *
4
+ * @example
5
+ * // Build agent-specific config
6
+ * import { buildAgentConfig } from "axconfig";
7
+ *
8
+ * const result = buildAgentConfig({
9
+ * agentId: "claude-code",
10
+ * allow: "read,glob",
11
+ * deny: "bash:rm *",
12
+ * output: "/tmp/axconfig",
13
+ * });
14
+ *
15
+ * if (result.ok) {
16
+ * // Use result.env for agent environment
17
+ * }
18
+ *
19
+ * @example
20
+ * // Get access token for an agent
21
+ * import { getAgentAccessToken, checkAuth } from "axconfig";
22
+ *
23
+ * const token = getAgentAccessToken("claude-code");
24
+ * if (token) {
25
+ * // Use token for API calls
26
+ * }
27
+ *
28
+ * // Or check auth status first
29
+ * const status = checkAuth("claude-code");
30
+ * if (status.authenticated) {
31
+ * console.log(`Authenticated via ${status.method}`);
32
+ * }
33
+ */
34
+ export { AGENT_IDS } from "./types.js";
35
+ export { checkAuth, checkAllAuth } from "./auth/check-auth.js";
36
+ export { extractCredentials } from "./auth/extract-credentials.js";
37
+ export { credentialsToEnvironment, getAccessToken, getAgentAccessToken, } from "./auth/get-access-token.js";
38
+ // Permission parsing
39
+ export { formatRule, parsePermissions, parseRule, parseRuleList, } from "./parse-permissions.js";
40
+ // Config builder registry
41
+ export { getConfigBuilder, registerConfigBuilder } from "./builder.js";
42
+ // High-level API
43
+ export { buildAgentConfig, formatPermissionErrors, formatPermissionWarnings, } from "./build-agent-config.js";
44
+ // Import agent modules to trigger self-registration
45
+ import "./agents/claude-code.js";
46
+ import "./agents/codex.js";
47
+ import "./agents/gemini.js";
48
+ import "./agents/opencode.js";
49
+ // Export agent builders for direct access
50
+ export { claudeCodeConfigBuilder } from "./agents/claude-code.js";
51
+ export { codexConfigBuilder } from "./agents/codex.js";
52
+ export { geminiConfigBuilder } from "./agents/gemini.js";
53
+ export { openCodeConfigBuilder } from "./agents/opencode.js";
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Permission syntax parser.
3
+ *
4
+ * Parses --allow and --deny CLI arguments into PermissionConfig.
5
+ *
6
+ * @example
7
+ * parsePermissions(
8
+ * ["read,glob,bash:git *"],
9
+ * ["bash:rm *"]
10
+ * )
11
+ * // Returns:
12
+ * // {
13
+ * // allow: [
14
+ * // { type: "tool", name: "read" },
15
+ * // { type: "tool", name: "glob" },
16
+ * // { type: "bash", pattern: "git *" }
17
+ * // ],
18
+ * // deny: [
19
+ * // { type: "bash", pattern: "rm *" }
20
+ * // ]
21
+ * // }
22
+ */
23
+ import type { PermissionConfig, PermissionRule } from "./types.js";
24
+ /**
25
+ * Parse a single permission rule string.
26
+ *
27
+ * Supported formats:
28
+ * - "read" → { type: "tool", name: "read" }
29
+ * - "bash:git *" → { type: "bash", pattern: "git *" }
30
+ * - "read:src/**" → { type: "path", tool: "read", pattern: "src/**" }
31
+ */
32
+ declare function parseRule(rule: string): PermissionRule;
33
+ /**
34
+ * Parse a comma-separated list of permission rules.
35
+ */
36
+ declare function parseRuleList(input: string): PermissionRule[];
37
+ /**
38
+ * Parse --allow and --deny arguments into PermissionConfig.
39
+ *
40
+ * @param allow - Array of comma-separated allow rules
41
+ * @param deny - Array of comma-separated deny rules
42
+ * @returns Parsed permission configuration
43
+ * @throws Error if any rule is invalid
44
+ */
45
+ declare function parsePermissions(allow?: string[], deny?: string[]): PermissionConfig;
46
+ /**
47
+ * Format a permission rule for display.
48
+ */
49
+ declare function formatRule(rule: PermissionRule): string;
50
+ export { formatRule, parsePermissions, parseRule, parseRuleList };
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Permission syntax parser.
3
+ *
4
+ * Parses --allow and --deny CLI arguments into PermissionConfig.
5
+ *
6
+ * @example
7
+ * parsePermissions(
8
+ * ["read,glob,bash:git *"],
9
+ * ["bash:rm *"]
10
+ * )
11
+ * // Returns:
12
+ * // {
13
+ * // allow: [
14
+ * // { type: "tool", name: "read" },
15
+ * // { type: "tool", name: "glob" },
16
+ * // { type: "bash", pattern: "git *" }
17
+ * // ],
18
+ * // deny: [
19
+ * // { type: "bash", pattern: "rm *" }
20
+ * // ]
21
+ * // }
22
+ */
23
+ /** Valid canonical tool names */
24
+ const CANONICAL_TOOLS = new Set([
25
+ "read",
26
+ "write",
27
+ "edit",
28
+ "bash",
29
+ "glob",
30
+ "grep",
31
+ "web",
32
+ ]);
33
+ /** Tools that support path restrictions */
34
+ const PATH_TOOLS = new Set(["read", "write", "edit"]);
35
+ /**
36
+ * Parse a single permission rule string.
37
+ *
38
+ * Supported formats:
39
+ * - "read" → { type: "tool", name: "read" }
40
+ * - "bash:git *" → { type: "bash", pattern: "git *" }
41
+ * - "read:src/**" → { type: "path", tool: "read", pattern: "src/**" }
42
+ */
43
+ function parseRule(rule) {
44
+ const trimmed = rule.trim();
45
+ if (trimmed === "") {
46
+ throw new Error("Empty permission rule");
47
+ }
48
+ // Check for bash pattern: "bash:git *"
49
+ if (trimmed.startsWith("bash:")) {
50
+ const pattern = trimmed.slice(5);
51
+ if (pattern === "") {
52
+ throw new Error('Invalid bash pattern: "bash:" requires a command pattern');
53
+ }
54
+ return { type: "bash", pattern };
55
+ }
56
+ // Check for path restriction: "read:src/**"
57
+ const colonIndex = trimmed.indexOf(":");
58
+ if (colonIndex > 0) {
59
+ const tool = trimmed.slice(0, colonIndex);
60
+ const pattern = trimmed.slice(colonIndex + 1);
61
+ if (PATH_TOOLS.has(tool)) {
62
+ if (pattern === "") {
63
+ throw new Error(`Invalid path pattern: "${tool}:" requires a path pattern`);
64
+ }
65
+ return {
66
+ type: "path",
67
+ tool: tool,
68
+ pattern,
69
+ };
70
+ }
71
+ // Unknown tool with colon - might be a typo
72
+ if (!CANONICAL_TOOLS.has(tool)) {
73
+ throw new Error(`Unknown tool "${tool}" in "${trimmed}". ` +
74
+ `Valid tools: ${[...CANONICAL_TOOLS].join(", ")}`);
75
+ }
76
+ // Tool doesn't support path restrictions
77
+ throw new Error(`Tool "${tool}" does not support path restrictions. ` +
78
+ `Only ${[...PATH_TOOLS].join(", ")} support patterns like "${tool}:path/**"`);
79
+ }
80
+ // Simple tool name: "read", "glob", etc.
81
+ if (!CANONICAL_TOOLS.has(trimmed)) {
82
+ throw new Error(`Unknown tool "${trimmed}". Valid tools: ${[...CANONICAL_TOOLS].join(", ")}`);
83
+ }
84
+ return { type: "tool", name: trimmed };
85
+ }
86
+ /**
87
+ * Parse a comma-separated list of permission rules.
88
+ */
89
+ function parseRuleList(input) {
90
+ if (input.trim() === "") {
91
+ return [];
92
+ }
93
+ return input.split(",").map((part) => parseRule(part));
94
+ }
95
+ /**
96
+ * Parse --allow and --deny arguments into PermissionConfig.
97
+ *
98
+ * @param allow - Array of comma-separated allow rules
99
+ * @param deny - Array of comma-separated deny rules
100
+ * @returns Parsed permission configuration
101
+ * @throws Error if any rule is invalid
102
+ */
103
+ function parsePermissions(allow = [], deny = []) {
104
+ return {
105
+ allow: allow.flatMap((input) => parseRuleList(input)),
106
+ deny: deny.flatMap((input) => parseRuleList(input)),
107
+ };
108
+ }
109
+ /**
110
+ * Format a permission rule for display.
111
+ */
112
+ function formatRule(rule) {
113
+ switch (rule.type) {
114
+ case "tool": {
115
+ return rule.name;
116
+ }
117
+ case "bash": {
118
+ return `bash:${rule.pattern}`;
119
+ }
120
+ case "path": {
121
+ return `${rule.tool}:${rule.pattern}`;
122
+ }
123
+ }
124
+ }
125
+ export { formatRule, parsePermissions, parseRule, parseRuleList };
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Core types for axconfig.
3
+ *
4
+ * Defines the unified permission model and config builder interfaces.
5
+ */
6
+ /** Supported agent identifiers */
7
+ declare const AGENT_IDS: readonly ["claude-code", "codex", "gemini", "opencode"];
8
+ type AgentId = (typeof AGENT_IDS)[number];
9
+ /** Canonical tool names used in axrun permissions */
10
+ type CanonicalTool = "read" | "write" | "edit" | "bash" | "glob" | "grep" | "web";
11
+ /** Tools that support path restrictions */
12
+ type PathRestrictedTool = "read" | "write" | "edit";
13
+ /** Permission rule for a tool (e.g., "read", "bash") */
14
+ interface ToolPermissionRule {
15
+ type: "tool";
16
+ name: CanonicalTool;
17
+ }
18
+ /** Permission rule for a bash command pattern (e.g., "git *") */
19
+ interface BashPatternRule {
20
+ type: "bash";
21
+ pattern: string;
22
+ }
23
+ /** Permission rule for a path pattern (e.g., "src/**") */
24
+ interface PathPatternRule {
25
+ type: "path";
26
+ tool: PathRestrictedTool;
27
+ pattern: string;
28
+ }
29
+ /** Union of all permission rule types */
30
+ type PermissionRule = ToolPermissionRule | BashPatternRule | PathPatternRule;
31
+ /** Parsed permission configuration */
32
+ interface PermissionConfig {
33
+ allow: PermissionRule[];
34
+ deny: PermissionRule[];
35
+ }
36
+ /** Full axrun configuration */
37
+ interface AxrunConfig {
38
+ permissions?: PermissionConfig;
39
+ }
40
+ /** Describes what permission features an agent supports */
41
+ interface AgentCapabilities {
42
+ /** Whether the agent supports per-tool permissions (read, write, etc.) */
43
+ toolPermissions: boolean;
44
+ /** Whether the agent supports bash command patterns */
45
+ bashPatterns: boolean;
46
+ /** Whether the agent supports path restrictions (read:src/**) */
47
+ pathRestrictions: boolean;
48
+ /** Whether the agent can deny read access (some use sandboxes that always allow reads) */
49
+ canDenyRead: boolean;
50
+ }
51
+ /** Issue with a permission rule (warning or error) */
52
+ interface PermissionIssue {
53
+ rule: PermissionRule;
54
+ reason: string;
55
+ suggestions: string[];
56
+ }
57
+ /** Successful build result */
58
+ interface BuildSuccess {
59
+ ok: true;
60
+ /** Environment variables to pass to the agent */
61
+ env: Record<string, string>;
62
+ /** CLI arguments to pass to the agent */
63
+ args?: string[];
64
+ /** Warnings about dropped rules (for --allow) */
65
+ warnings: PermissionIssue[];
66
+ }
67
+ /** Failed build result */
68
+ interface BuildFailure {
69
+ ok: false;
70
+ /** Errors that prevent running (for --deny) */
71
+ errors: PermissionIssue[];
72
+ }
73
+ /** Result of building agent-specific config */
74
+ type BuildResult = BuildSuccess | BuildFailure;
75
+ /** Interface for agent-specific config builders */
76
+ interface ConfigBuilder {
77
+ /** Agent this builder is for */
78
+ agentId: AgentId;
79
+ /** What this agent supports */
80
+ capabilities: AgentCapabilities;
81
+ /** Build agent-specific config from axrun config */
82
+ build: (config: AxrunConfig, output: string) => BuildResult;
83
+ }
84
+ export { AGENT_IDS };
85
+ export type { AgentCapabilities, AgentId, AxrunConfig, BuildResult, CanonicalTool, ConfigBuilder, PermissionConfig, PermissionIssue, PermissionRule, };
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Core types for axconfig.
3
+ *
4
+ * Defines the unified permission model and config builder interfaces.
5
+ */
6
+ /** Supported agent identifiers */
7
+ const AGENT_IDS = ["claude-code", "codex", "gemini", "opencode"];
8
+ export { AGENT_IDS };