subharness 0.0.1

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 (168) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +158 -0
  3. package/dist/adapters/claude-auth.d.ts +7 -0
  4. package/dist/adapters/claude-auth.js +87 -0
  5. package/dist/adapters/claude-auth.js.map +1 -0
  6. package/dist/adapters/claude-config.d.ts +6 -0
  7. package/dist/adapters/claude-config.js +37 -0
  8. package/dist/adapters/claude-config.js.map +1 -0
  9. package/dist/adapters/claude-input.d.ts +9 -0
  10. package/dist/adapters/claude-input.js +32 -0
  11. package/dist/adapters/claude-input.js.map +1 -0
  12. package/dist/adapters/claude-permissions.d.ts +3 -0
  13. package/dist/adapters/claude-permissions.js +24 -0
  14. package/dist/adapters/claude-permissions.js.map +1 -0
  15. package/dist/adapters/claude-settings.d.ts +14 -0
  16. package/dist/adapters/claude-settings.js +43 -0
  17. package/dist/adapters/claude-settings.js.map +1 -0
  18. package/dist/adapters/claude-tools.d.ts +9 -0
  19. package/dist/adapters/claude-tools.js +47 -0
  20. package/dist/adapters/claude-tools.js.map +1 -0
  21. package/dist/adapters/claude.d.ts +22 -0
  22. package/dist/adapters/claude.js +295 -0
  23. package/dist/adapters/claude.js.map +1 -0
  24. package/dist/adapters/codex-config.d.ts +25 -0
  25. package/dist/adapters/codex-config.js +66 -0
  26. package/dist/adapters/codex-config.js.map +1 -0
  27. package/dist/adapters/codex.d.ts +2 -0
  28. package/dist/adapters/codex.js +238 -0
  29. package/dist/adapters/codex.js.map +1 -0
  30. package/dist/adapters/fx-auth.d.ts +4 -0
  31. package/dist/adapters/fx-auth.js +116 -0
  32. package/dist/adapters/fx-auth.js.map +1 -0
  33. package/dist/adapters/fx-rpc.d.ts +29 -0
  34. package/dist/adapters/fx-rpc.js +124 -0
  35. package/dist/adapters/fx-rpc.js.map +1 -0
  36. package/dist/adapters/fx-tools.d.ts +19 -0
  37. package/dist/adapters/fx-tools.js +119 -0
  38. package/dist/adapters/fx-tools.js.map +1 -0
  39. package/dist/adapters/fx.d.ts +3 -0
  40. package/dist/adapters/fx.js +302 -0
  41. package/dist/adapters/fx.js.map +1 -0
  42. package/dist/adapters/mcp-tool-content.d.ts +12 -0
  43. package/dist/adapters/mcp-tool-content.js +8 -0
  44. package/dist/adapters/mcp-tool-content.js.map +1 -0
  45. package/dist/adapters/rpc.d.ts +28 -0
  46. package/dist/adapters/rpc.js +101 -0
  47. package/dist/adapters/rpc.js.map +1 -0
  48. package/dist/adapters/types.d.ts +28 -0
  49. package/dist/adapters/types.js +2 -0
  50. package/dist/adapters/types.js.map +1 -0
  51. package/dist/cli/args.d.ts +18 -0
  52. package/dist/cli/args.js +118 -0
  53. package/dist/cli/args.js.map +1 -0
  54. package/dist/cli/catalog-worker.d.ts +1 -0
  55. package/dist/cli/catalog-worker.js +22 -0
  56. package/dist/cli/catalog-worker.js.map +1 -0
  57. package/dist/cli/catalog.d.ts +26 -0
  58. package/dist/cli/catalog.js +41 -0
  59. package/dist/cli/catalog.js.map +1 -0
  60. package/dist/cli/help.d.ts +3 -0
  61. package/dist/cli/help.js +68 -0
  62. package/dist/cli/help.js.map +1 -0
  63. package/dist/cli/input.d.ts +5 -0
  64. package/dist/cli/input.js +69 -0
  65. package/dist/cli/input.js.map +1 -0
  66. package/dist/cli/main.d.ts +2 -0
  67. package/dist/cli/main.js +105 -0
  68. package/dist/cli/main.js.map +1 -0
  69. package/dist/cli/output.d.ts +7 -0
  70. package/dist/cli/output.js +43 -0
  71. package/dist/cli/output.js.map +1 -0
  72. package/dist/config/access.d.ts +21 -0
  73. package/dist/config/access.js +97 -0
  74. package/dist/config/access.js.map +1 -0
  75. package/dist/config/loader.d.ts +13 -0
  76. package/dist/config/loader.js +80 -0
  77. package/dist/config/loader.js.map +1 -0
  78. package/dist/config/oidc.d.ts +1 -0
  79. package/dist/config/oidc.js +53 -0
  80. package/dist/config/oidc.js.map +1 -0
  81. package/dist/config/project.d.ts +5 -0
  82. package/dist/config/project.js +56 -0
  83. package/dist/config/project.js.map +1 -0
  84. package/dist/config/resolve-access.d.ts +4 -0
  85. package/dist/config/resolve-access.js +42 -0
  86. package/dist/config/resolve-access.js.map +1 -0
  87. package/dist/errors.d.ts +9 -0
  88. package/dist/errors.js +14 -0
  89. package/dist/errors.js.map +1 -0
  90. package/dist/index.d.ts +4 -0
  91. package/dist/index.js +3 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/runtime/client.d.ts +9 -0
  94. package/dist/runtime/client.js +91 -0
  95. package/dist/runtime/client.js.map +1 -0
  96. package/dist/runtime/coordinator.d.ts +61 -0
  97. package/dist/runtime/coordinator.js +296 -0
  98. package/dist/runtime/coordinator.js.map +1 -0
  99. package/dist/runtime/daemon.d.ts +1 -0
  100. package/dist/runtime/daemon.js +28 -0
  101. package/dist/runtime/daemon.js.map +1 -0
  102. package/dist/runtime/definition.d.ts +6 -0
  103. package/dist/runtime/definition.js +19 -0
  104. package/dist/runtime/definition.js.map +1 -0
  105. package/dist/runtime/native-owner.d.ts +8 -0
  106. package/dist/runtime/native-owner.js +25 -0
  107. package/dist/runtime/native-owner.js.map +1 -0
  108. package/dist/runtime/observation.d.ts +1 -0
  109. package/dist/runtime/observation.js +15 -0
  110. package/dist/runtime/observation.js.map +1 -0
  111. package/dist/runtime/select-native.d.ts +3 -0
  112. package/dist/runtime/select-native.js +34 -0
  113. package/dist/runtime/select-native.js.map +1 -0
  114. package/dist/runtime/service.d.ts +5 -0
  115. package/dist/runtime/service.js +90 -0
  116. package/dist/runtime/service.js.map +1 -0
  117. package/dist/runtime/session-launcher.d.ts +6 -0
  118. package/dist/runtime/session-launcher.js +29 -0
  119. package/dist/runtime/session-launcher.js.map +1 -0
  120. package/dist/runtime/state.d.ts +14 -0
  121. package/dist/runtime/state.js +69 -0
  122. package/dist/runtime/state.js.map +1 -0
  123. package/dist/runtime/types.d.ts +81 -0
  124. package/dist/runtime/types.js +2 -0
  125. package/dist/runtime/types.js.map +1 -0
  126. package/dist/runtime/worker-client.d.ts +3 -0
  127. package/dist/runtime/worker-client.js +81 -0
  128. package/dist/runtime/worker-client.js.map +1 -0
  129. package/dist/runtime/worker.d.ts +1 -0
  130. package/dist/runtime/worker.js +67 -0
  131. package/dist/runtime/worker.js.map +1 -0
  132. package/dist/sdk/definitions.d.ts +6 -0
  133. package/dist/sdk/definitions.js +72 -0
  134. package/dist/sdk/definitions.js.map +1 -0
  135. package/dist/sdk/tool-result.d.ts +23 -0
  136. package/dist/sdk/tool-result.js +95 -0
  137. package/dist/sdk/tool-result.js.map +1 -0
  138. package/dist/sdk/tools.d.ts +9 -0
  139. package/dist/sdk/tools.js +73 -0
  140. package/dist/sdk/tools.js.map +1 -0
  141. package/dist/sdk/types.d.ts +49 -0
  142. package/dist/sdk/types.js +2 -0
  143. package/dist/sdk/types.js.map +1 -0
  144. package/dist/sdk/validation.d.ts +5 -0
  145. package/dist/sdk/validation.js +20 -0
  146. package/dist/sdk/validation.js.map +1 -0
  147. package/dist/shell.d.ts +2 -0
  148. package/dist/shell.js +5 -0
  149. package/dist/shell.js.map +1 -0
  150. package/package.json +61 -0
  151. package/sdk/access-config.md +52 -0
  152. package/sdk/adapter-contract.md +33 -0
  153. package/sdk/agent.md +52 -0
  154. package/sdk/authentication.md +11 -0
  155. package/sdk/cli/index.md +67 -0
  156. package/sdk/cli/output.md +28 -0
  157. package/sdk/completion-notifications.md +29 -0
  158. package/sdk/config.md +41 -0
  159. package/sdk/distribution.md +31 -0
  160. package/sdk/fx.md +71 -0
  161. package/sdk/harnesses.md +32 -0
  162. package/sdk/index.md +22 -0
  163. package/sdk/message-delivery.md +39 -0
  164. package/sdk/plugins/sub-agents.md +57 -0
  165. package/sdk/project-team.md +57 -0
  166. package/sdk/sessions.md +31 -0
  167. package/sdk/tools.md +73 -0
  168. package/sdk/v1-runtime.md +63 -0
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ import { readFile, realpath, stat } from 'node:fs/promises';
3
+ import { parseArgs } from './args.js';
4
+ import { renderHelp } from './help.js';
5
+ import { renderText, exitCode } from './output.js';
6
+ import { loadCatalog, loadDeclaredChildren } from './catalog.js';
7
+ import { AgentError, errorInfo } from '../errors.js';
8
+ import { connect, request } from '../runtime/client.js';
9
+ import { harnessReference } from '../runtime/definition.js';
10
+ const valueOptions = new Set(['cwd', 'prompt', 'prompt-file', 'model', 'effort', 'delivery', 'after']);
11
+ function parseErrorFormat(argv) {
12
+ for (let index = 1; index < argv.length; index++) {
13
+ const argument = argv[index];
14
+ if (argument === '--')
15
+ break;
16
+ if (argument === '--format')
17
+ return argv[index + 1] === 'jsonl' ? 'jsonl' : 'text';
18
+ if (argument.startsWith('--') && valueOptions.has(argument.slice(2)))
19
+ index++;
20
+ }
21
+ return 'text';
22
+ }
23
+ async function main() {
24
+ let format = parseErrorFormat(process.argv.slice(2));
25
+ const emit = (record) => {
26
+ const text = format === 'jsonl' ? JSON.stringify(record) : renderText(record);
27
+ (record.type === 'error' && format === 'text' ? process.stderr : process.stdout).write(text + '\n');
28
+ process.exitCode = exitCode(record);
29
+ };
30
+ try {
31
+ const args = await parseArgs(process.argv.slice(2));
32
+ format = args.format;
33
+ if (args.command === 'help') {
34
+ process.stdout.write(renderHelp(args.harness));
35
+ return;
36
+ }
37
+ if (args.command === 'version') {
38
+ const manifest = JSON.parse(await readFile(new URL('../../package.json', import.meta.url), 'utf8'));
39
+ process.stdout.write(`${manifest.version}\n`);
40
+ return;
41
+ }
42
+ const parentToken = process.env.AGENT_PARENT_TOKEN;
43
+ let reference;
44
+ if (args.command === 'list' || args.command === 'run') {
45
+ const requestedCwd = args.cwd;
46
+ try {
47
+ args.cwd = await realpath(requestedCwd);
48
+ if (!(await stat(args.cwd)).isDirectory())
49
+ throw new Error();
50
+ }
51
+ catch {
52
+ throw new AgentError('INVALID_CONFIG', `Execution directory is not accessible: ${requestedCwd}`);
53
+ }
54
+ if (args.command === 'run' && args.harness) {
55
+ reference = harnessReference(args.harness, args.model, args.effort);
56
+ }
57
+ else {
58
+ let parent;
59
+ if (parentToken) {
60
+ const endpoint = await connect(false);
61
+ for await (const record of request(endpoint, { command: 'parent', parentToken })) {
62
+ if (record.type === 'error')
63
+ throw new AgentError(record.error.code, record.error.message);
64
+ parent = record;
65
+ }
66
+ }
67
+ if (args.command === 'run' && args.id.startsWith('subagent:')) {
68
+ const name = args.id.slice(9);
69
+ if (!parent || !('file' in parent.reference))
70
+ throw new AgentError('INVALID_PARENT', 'This subagent is not available in the active parent context.');
71
+ const children = await loadDeclaredChildren(args.cwd, parent.reference);
72
+ if (!children.some(child => child.name === name))
73
+ throw new AgentError('INVALID_PARENT', 'This subagent is not available in the active parent context.');
74
+ reference = { file: parent.reference.file, subagents: [...parent.reference.subagents, name] };
75
+ }
76
+ else {
77
+ const { entries, children } = await loadCatalog(args.cwd, parent?.reference);
78
+ if (args.command === 'list') {
79
+ emit({ version: 1, type: 'agents', agents: [
80
+ { id: 'codex', name: 'codex', description: 'Run the native Codex harness.', scope: 'harness' },
81
+ { id: 'claude', name: 'claude', description: 'Run the native Claude Code harness.', scope: 'harness' },
82
+ { id: 'fx', name: 'fx', description: 'Run the native fx harness through AI Gateway.', scope: 'harness' },
83
+ ...entries.map(({ id, name, description, scope }) => ({ id, name, description, scope })),
84
+ ...children.map(({ name, description }) => ({ id: `subagent:${name}`, name, description, scope: 'subagent' })),
85
+ ] });
86
+ return;
87
+ }
88
+ const matches = entries.filter(entry => entry.id === args.id || entry.name === args.id);
89
+ if (matches.length !== 1)
90
+ throw new AgentError(matches.length ? 'AMBIGUOUS_AGENT' : 'UNKNOWN_AGENT', matches.length ? `Choose ${matches.map(entry => entry.id).join(' or ')}.` : 'Agent not found. Use subharness list.');
91
+ reference = { file: matches[0].file, subagents: [] };
92
+ }
93
+ }
94
+ }
95
+ const endpoint = await connect(args.command === 'run');
96
+ const body = args.command === 'run' ? { command: 'run', input: { reference, cwd: args.cwd, env: process.env, prompt: args.prompt, parentToken } } : { ...args, parentToken };
97
+ for await (const record of request(endpoint, body))
98
+ emit(record);
99
+ }
100
+ catch (error) {
101
+ emit({ version: 1, type: 'error', error: errorInfo(error) });
102
+ }
103
+ }
104
+ await main();
105
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { readFile, realpath, stat } from 'node:fs/promises';\nimport { parseArgs } from './args.js';\nimport { renderHelp } from './help.js';\nimport { renderText, exitCode, type OutputRecord } from './output.js';\nimport { loadCatalog, loadDeclaredChildren } from './catalog.js';\nimport { AgentError, errorInfo } from '../errors.js';\nimport { connect, request } from '../runtime/client.js';\nimport type { ExecutionReference } from '../runtime/types.js';\nimport { harnessReference } from '../runtime/definition.js';\n\nconst valueOptions = new Set(['cwd', 'prompt', 'prompt-file', 'model', 'effort', 'delivery', 'after']);\n\nfunction parseErrorFormat(argv: string[]): 'text' | 'jsonl' {\n for (let index = 1; index < argv.length; index++) {\n const argument = argv[index]!;\n if (argument === '--') break;\n if (argument === '--format') return argv[index + 1] === 'jsonl' ? 'jsonl' : 'text';\n if (argument.startsWith('--') && valueOptions.has(argument.slice(2))) index++;\n }\n return 'text';\n}\n\nasync function main() {\n let format = parseErrorFormat(process.argv.slice(2));\n const emit = (record: OutputRecord) => {\n const text = format === 'jsonl' ? JSON.stringify(record) : renderText(record);\n (record.type === 'error' && format === 'text' ? process.stderr : process.stdout).write(text + '\\n');\n process.exitCode = exitCode(record);\n };\n try {\n const args = await parseArgs(process.argv.slice(2)); format = args.format;\n if (args.command === 'help') { process.stdout.write(renderHelp(args.harness)); return; }\n if (args.command === 'version') {\n const manifest = JSON.parse(await readFile(new URL('../../package.json', import.meta.url), 'utf8')) as { version: string };\n process.stdout.write(`${manifest.version}\\n`);\n return;\n }\n const parentToken = process.env.AGENT_PARENT_TOKEN;\n let reference: ExecutionReference | undefined;\n if (args.command === 'list' || args.command === 'run') {\n const requestedCwd = args.cwd;\n try {\n args.cwd = await realpath(requestedCwd);\n if (!(await stat(args.cwd)).isDirectory()) throw new Error();\n } catch {\n throw new AgentError('INVALID_CONFIG', `Execution directory is not accessible: ${requestedCwd}`);\n }\n if (args.command === 'run' && args.harness) {\n reference = harnessReference(args.harness, args.model, args.effort);\n } else {\n let parent: {reference:ExecutionReference}|undefined;\n if (parentToken) {\n const endpoint = await connect(false);\n for await (const record of request(endpoint,{command:'parent',parentToken})) {\n if (record.type === 'error') throw new AgentError((record.error as any).code,(record.error as any).message);\n parent = record as unknown as {reference:ExecutionReference};\n }\n }\n if (args.command === 'run' && args.id!.startsWith('subagent:')) {\n const name = args.id!.slice(9);\n if (!parent || !('file' in parent.reference)) throw new AgentError('INVALID_PARENT','This subagent is not available in the active parent context.');\n const children = await loadDeclaredChildren(args.cwd, parent.reference);\n if (!children.some(child => child.name === name)) throw new AgentError('INVALID_PARENT','This subagent is not available in the active parent context.');\n reference = {file:parent.reference.file,subagents:[...parent.reference.subagents,name]};\n } else {\n const { entries, children } = await loadCatalog(args.cwd, parent?.reference);\n if (args.command === 'list') {\n emit({version:1,type:'agents',agents:[\n {id:'codex',name:'codex',description:'Run the native Codex harness.',scope:'harness'},\n {id:'claude',name:'claude',description:'Run the native Claude Code harness.',scope:'harness'},\n {id:'fx',name:'fx',description:'Run the native fx harness through AI Gateway.',scope:'harness'},\n ...entries.map(({id,name,description,scope})=>({id,name,description,scope})),\n ...children.map(({name,description})=>({id:`subagent:${name}`,name,description,scope:'subagent'})),\n ]}); return;\n }\n const matches = entries.filter(entry=>entry.id===args.id || entry.name===args.id);\n if (matches.length !== 1) throw new AgentError(matches.length ? 'AMBIGUOUS_AGENT':'UNKNOWN_AGENT',matches.length ? `Choose ${matches.map(entry=>entry.id).join(' or ')}.` : 'Agent not found. Use subharness list.');\n reference = {file:matches[0]!.file,subagents:[]};\n }\n }\n }\n const endpoint = await connect(args.command === 'run');\n const body = args.command === 'run' ? {command:'run',input:{reference,cwd:args.cwd,env:process.env,prompt:args.prompt,parentToken}} : {...args,parentToken};\n for await (const record of request(endpoint,body)) emit(record);\n } catch (error) { emit({version:1,type:'error',error:errorInfo(error)}); }\n}\nawait main();\n"]}
@@ -0,0 +1,7 @@
1
+ export type OutputRecord = {
2
+ version: number;
3
+ type: string;
4
+ [key: string]: unknown;
5
+ };
6
+ export declare function renderText(record: OutputRecord): string;
7
+ export declare function exitCode(record: OutputRecord): number;
@@ -0,0 +1,43 @@
1
+ export function renderText(record) {
2
+ const header = `Session: ${record.sessionId}\nTask: ${record.taskId}`;
3
+ switch (record.type) {
4
+ case 'started': return `${header}\nState: ${record.state}${record.delivery ? `\nDelivery: ${record.delivery}` : ''}`;
5
+ case 'response': return `${header}\nResponse: ${record.responseId}\nState: ${record.state}\n\n${record.text}` +
6
+ (record.state === 'waiting' || record.state === 'running' ? `\n\nNext response: subharness wait ${record.taskId} --after ${record.responseId}` : '');
7
+ case 'terminal': return `${header}\nState: ${record.state}${record.error ? `\n${errorText(record.error)}` : ''}`;
8
+ case 'error': return errorText(record.error);
9
+ case 'accepted': return `${header}\nDelivery: steer (accepted)`;
10
+ case 'cancelled': return `${header}\nState: ${record.state}`;
11
+ case 'agents': {
12
+ const entries = record.agents;
13
+ return entries.length ? entries.map(entry => `${entry.id} — ${entry.description}`).join('\n') : 'No agents found.';
14
+ }
15
+ case 'status': {
16
+ const response = record.response;
17
+ return `${header}\nState: ${record.state}${record.error ? `\n${errorText(record.error)}` : ''}` +
18
+ (response ? `\nResponse: ${response.responseId}\n\n${response.text}${response.truncated ? '\n[Preview truncated; use status --full.]' : ''}` : '');
19
+ }
20
+ case 'queue': {
21
+ const active = record.active;
22
+ const tasks = record.tasks;
23
+ return `Session: ${record.sessionId}\nPaused: ${record.paused}\nActive: ${active ? `${active.taskId} (${active.state})` : 'none'}\n` +
24
+ (tasks.length ? tasks.map(task => `${task.taskId} — ${task.description}`).join('\n') : 'Queue empty.');
25
+ }
26
+ default: return JSON.stringify(record);
27
+ }
28
+ }
29
+ function errorText(error) {
30
+ const value = error;
31
+ return `${value.code}: ${value.message}`;
32
+ }
33
+ export function exitCode(record) {
34
+ if (record.type === 'cancelled')
35
+ return 0;
36
+ if (record.state === 'cancelled' || record.state === 'interrupted')
37
+ return 130;
38
+ const error = record.error;
39
+ if (!error && record.state !== 'failed')
40
+ return 0;
41
+ return /^(INVALID_|UNKNOWN_|AMBIGUOUS_|NOT_FAILED|NO_ACTIVE_TASK)/.test(error?.code ?? '') ? 2 : 1;
42
+ }
43
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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","sourcesContent":["export type OutputRecord = {version: number; type: string; [key: string]: unknown};\n\nexport function renderText(record: OutputRecord): string {\n const header = `Session: ${record.sessionId}\\nTask: ${record.taskId}`;\n switch (record.type) {\n case 'started': return `${header}\\nState: ${record.state}${record.delivery ? `\\nDelivery: ${record.delivery}` : ''}`;\n case 'response': return `${header}\\nResponse: ${record.responseId}\\nState: ${record.state}\\n\\n${record.text}` +\n (record.state === 'waiting' || record.state === 'running' ? `\\n\\nNext response: subharness wait ${record.taskId} --after ${record.responseId}` : '');\n case 'terminal': return `${header}\\nState: ${record.state}${record.error ? `\\n${errorText(record.error)}` : ''}`;\n case 'error': return errorText(record.error);\n case 'accepted': return `${header}\\nDelivery: steer (accepted)`;\n case 'cancelled': return `${header}\\nState: ${record.state}`;\n case 'agents': {\n const entries = record.agents as {id:string;description:string}[];\n return entries.length ? entries.map(entry => `${entry.id} — ${entry.description}`).join('\\n') : 'No agents found.';\n }\n case 'status': {\n const response = record.response as {responseId:string;text:string;truncated:boolean}|undefined;\n return `${header}\\nState: ${record.state}${record.error ? `\\n${errorText(record.error)}` : ''}` +\n (response ? `\\nResponse: ${response.responseId}\\n\\n${response.text}${response.truncated ? '\\n[Preview truncated; use status --full.]' : ''}` : '');\n }\n case 'queue': {\n const active = record.active as {taskId:string;state:string}|undefined;\n const tasks = record.tasks as {taskId:string;description:string}[];\n return `Session: ${record.sessionId}\\nPaused: ${record.paused}\\nActive: ${active ? `${active.taskId} (${active.state})` : 'none'}\\n` +\n (tasks.length ? tasks.map(task => `${task.taskId} — ${task.description}`).join('\\n') : 'Queue empty.');\n }\n default: return JSON.stringify(record);\n }\n}\nfunction errorText(error: unknown) {\n const value = error as {code:string;message:string};\n return `${value.code}: ${value.message}`;\n}\nexport function exitCode(record: OutputRecord): number {\n if (record.type === 'cancelled') return 0;\n if (record.state === 'cancelled' || record.state === 'interrupted') return 130;\n const error = record.error as {code?:string}|undefined;\n if (!error && record.state !== 'failed') return 0;\n return /^(INVALID_|UNKNOWN_|AMBIGUOUS_|NOT_FAILED|NO_ACTIVE_TASK)/.test(error?.code ?? '') ? 2 : 1;\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import type { HarnessKind } from "../sdk/types.js";
2
+ export { resolveAccess } from "./resolve-access.js";
3
+ export type AccessConnection = {
4
+ type: "subscription";
5
+ } | {
6
+ type: "api-key" | "vercel-api-key";
7
+ env?: string;
8
+ envFile?: string;
9
+ } | {
10
+ type: "vercel-oidc";
11
+ env?: string;
12
+ envFile?: string;
13
+ project?: string;
14
+ };
15
+ export interface AccessConfig {
16
+ access?: Partial<Record<HarnessKind, AccessConnection[]>>;
17
+ }
18
+ export declare function configError(message: string): never;
19
+ export declare function parseConnection(value: unknown): AccessConnection;
20
+ export declare function parseAccess(value: unknown): AccessConfig;
21
+ export declare function loadAccess(cwd: string): Promise<AccessConfig>;
@@ -0,0 +1,97 @@
1
+ import { appendFile, mkdir, readFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { AgentError } from "../errors.js";
4
+ import { git, resolveProject } from "./project.js";
5
+ export { resolveAccess } from "./resolve-access.js";
6
+ export function configError(message) {
7
+ throw new AgentError("INVALID_CONFIG", message);
8
+ }
9
+ function record(value) {
10
+ return value !== null && typeof value === "object" && !Array.isArray(value);
11
+ }
12
+ export function parseConnection(value) {
13
+ if (!record(value) || !["subscription", "api-key", "vercel-api-key", "vercel-oidc"].includes(value.type))
14
+ configError("Unknown access connection type.");
15
+ const allowed = value.type === "subscription" ? ["type"] : ["type", "env", "envFile", ...(value.type === "vercel-oidc" ? ["project"] : [])];
16
+ if (Object.keys(value).some((key) => !allowed.includes(key)))
17
+ configError("Unknown access connection field; secrets must be supplied through environment references.");
18
+ if (value.env !== undefined && (typeof value.env !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value.env)))
19
+ configError("Invalid credential variable name.");
20
+ for (const field of ["envFile", "project"]) {
21
+ if (value[field] !== undefined && (typeof value[field] !== "string" || !value[field].trim()))
22
+ configError(`${field} must be a nonempty path.`);
23
+ }
24
+ return value;
25
+ }
26
+ export function parseAccess(value) {
27
+ if (!record(value) || Object.keys(value).some((key) => key !== "access"))
28
+ configError("Personal settings must contain only an optional access map.");
29
+ if (value.access === undefined)
30
+ return {};
31
+ if (!record(value.access))
32
+ configError("access must be an object.");
33
+ for (const [kind, connections] of Object.entries(value.access)) {
34
+ if (kind !== "codex" && kind !== "claudeCode" && kind !== "fx")
35
+ configError("Unsupported harness in personal access settings.");
36
+ if (!Array.isArray(connections))
37
+ configError("Each harness access selection must be an array.");
38
+ connections.forEach(parseConnection);
39
+ }
40
+ return value;
41
+ }
42
+ async function ensureExcluded(mainRoot) {
43
+ try {
44
+ await git(mainRoot, ["rev-parse", "--git-dir"]);
45
+ }
46
+ catch (error) {
47
+ if (error instanceof Error && error.message.includes("not a git repository"))
48
+ return;
49
+ configError("Cannot inspect Git configuration for personal settings.");
50
+ }
51
+ let tracked = false;
52
+ try {
53
+ tracked = !!await git(mainRoot, ["ls-files", "--", ".agents/agents.local.json"]);
54
+ }
55
+ catch {
56
+ configError("Cannot inspect whether personal access settings are tracked by Git.");
57
+ }
58
+ if (tracked)
59
+ configError("Personal access settings are tracked. Remove .agents/agents.local.json from the Git index before using it.");
60
+ const exclude = await git(mainRoot, ["rev-parse", "--path-format=absolute", "--git-path", "info/exclude"]);
61
+ let contents = "";
62
+ try {
63
+ contents = await readFile(exclude, "utf8");
64
+ }
65
+ catch (error) {
66
+ if (error.code !== "ENOENT")
67
+ configError("Cannot read Git's local exclude file.");
68
+ }
69
+ const pattern = "/.agents/agents.local.json";
70
+ if (!contents.split(/\r?\n/).includes(pattern)) {
71
+ await mkdir(dirname(exclude), { recursive: true });
72
+ await appendFile(exclude, `${contents.endsWith("\n") || !contents ? "" : "\n"}${pattern}\n`);
73
+ }
74
+ }
75
+ export async function loadAccess(cwd) {
76
+ const { mainRoot } = await resolveProject(cwd);
77
+ const file = join(mainRoot, ".agents", "agents.local.json");
78
+ let contents;
79
+ try {
80
+ contents = await readFile(file, "utf8");
81
+ }
82
+ catch (error) {
83
+ if (error.code === "ENOENT")
84
+ return {};
85
+ configError(`Cannot read personal settings: ${file}`);
86
+ }
87
+ await ensureExcluded(mainRoot);
88
+ let value;
89
+ try {
90
+ value = JSON.parse(contents);
91
+ }
92
+ catch {
93
+ configError(`Invalid JSON in personal settings: ${file}`);
94
+ }
95
+ return parseAccess(value);
96
+ }
97
+ //# sourceMappingURL=access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../../src/config/access.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { AgentError } from \"../errors.js\";\nimport type { HarnessKind } from \"../sdk/types.js\";\nimport { git, resolveProject } from \"./project.js\";\nexport { resolveAccess } from \"./resolve-access.js\";\n\nexport type AccessConnection =\n | { type: \"subscription\" }\n | { type: \"api-key\" | \"vercel-api-key\"; env?: string; envFile?: string }\n | { type: \"vercel-oidc\"; env?: string; envFile?: string; project?: string };\n\nexport interface AccessConfig {\n access?: Partial<Record<HarnessKind, AccessConnection[]>>;\n}\n\nexport function configError(message: string): never {\n throw new AgentError(\"INVALID_CONFIG\", message);\n}\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function parseConnection(value: unknown): AccessConnection {\n if (!record(value) || ![\"subscription\", \"api-key\", \"vercel-api-key\", \"vercel-oidc\"].includes(value.type as string)) configError(\"Unknown access connection type.\");\n const allowed = value.type === \"subscription\" ? [\"type\"] : [\"type\", \"env\", \"envFile\", ...(value.type === \"vercel-oidc\" ? [\"project\"] : [])];\n if (Object.keys(value).some((key) => !allowed.includes(key))) configError(\"Unknown access connection field; secrets must be supplied through environment references.\");\n if (value.env !== undefined && (typeof value.env !== \"string\" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value.env))) configError(\"Invalid credential variable name.\");\n for (const field of [\"envFile\", \"project\"]) {\n if (value[field] !== undefined && (typeof value[field] !== \"string\" || !value[field].trim())) configError(`${field} must be a nonempty path.`);\n }\n return value as AccessConnection;\n}\n\nexport function parseAccess(value: unknown): AccessConfig {\n if (!record(value) || Object.keys(value).some((key) => key !== \"access\")) configError(\"Personal settings must contain only an optional access map.\");\n if (value.access === undefined) return {};\n if (!record(value.access)) configError(\"access must be an object.\");\n for (const [kind, connections] of Object.entries(value.access)) {\n if (kind !== \"codex\" && kind !== \"claudeCode\" && kind !== \"fx\") configError(\"Unsupported harness in personal access settings.\");\n if (!Array.isArray(connections)) configError(\"Each harness access selection must be an array.\");\n connections.forEach(parseConnection);\n }\n return value as AccessConfig;\n}\n\nasync function ensureExcluded(mainRoot: string): Promise<void> {\n try { await git(mainRoot, [\"rev-parse\", \"--git-dir\"]); }\n catch (error) {\n if (error instanceof Error && error.message.includes(\"not a git repository\")) return;\n configError(\"Cannot inspect Git configuration for personal settings.\");\n }\n let tracked = false;\n try { tracked = !!await git(mainRoot, [\"ls-files\", \"--\", \".agents/agents.local.json\"]); }\n catch { configError(\"Cannot inspect whether personal access settings are tracked by Git.\"); }\n if (tracked) configError(\"Personal access settings are tracked. Remove .agents/agents.local.json from the Git index before using it.\");\n const exclude = await git(mainRoot, [\"rev-parse\", \"--path-format=absolute\", \"--git-path\", \"info/exclude\"]);\n let contents = \"\";\n try { contents = await readFile(exclude, \"utf8\"); }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") configError(\"Cannot read Git's local exclude file.\"); }\n const pattern = \"/.agents/agents.local.json\";\n if (!contents.split(/\\r?\\n/).includes(pattern)) {\n await mkdir(dirname(exclude), { recursive: true });\n await appendFile(exclude, `${contents.endsWith(\"\\n\") || !contents ? \"\" : \"\\n\"}${pattern}\\n`);\n }\n}\n\nexport async function loadAccess(cwd: string): Promise<AccessConfig> {\n const { mainRoot } = await resolveProject(cwd);\n const file = join(mainRoot, \".agents\", \"agents.local.json\");\n let contents: string;\n try { contents = await readFile(file, \"utf8\"); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n configError(`Cannot read personal settings: ${file}`);\n }\n await ensureExcluded(mainRoot);\n let value: unknown;\n try { value = JSON.parse(contents); }\n catch { configError(`Invalid JSON in personal settings: ${file}`); }\n return parseAccess(value);\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import type { AgentDefinition } from "../sdk/types.js";
2
+ export interface CatalogEntry {
3
+ id: string;
4
+ name: string;
5
+ description: string;
6
+ scope: "repo" | "global";
7
+ file: string;
8
+ definition: AgentDefinition;
9
+ }
10
+ export declare function loadDefinition(file: string, subagents?: string[]): Promise<AgentDefinition>;
11
+ export declare function discover(cwd: string, options?: {
12
+ home?: string;
13
+ }): Promise<CatalogEntry[]>;
@@ -0,0 +1,80 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join, resolve } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { tsImport } from "tsx/esm/api";
6
+ import { AgentError } from "../errors.js";
7
+ import { agent } from "../sdk/definitions.js";
8
+ import { resolveProject } from "./project.js";
9
+ // Only fixed SDK diagnostics may cross the module-evaluation boundary.
10
+ // User exceptions can contain credential values, including exceptions named AgentError.
11
+ const safeDiagnostics = new Set([
12
+ "Expected a configuration object.", "Unknown configuration field.",
13
+ "Names must start with a letter and contain at most 64 letters, digits, underscores, or hyphens.",
14
+ "fast must be a boolean.", "Unsupported harness kind.", "At least one harness is required.",
15
+ "Claude effort must be low, medium, high, xhigh, or max.",
16
+ "Subagent definitions cannot contain recursive references.",
17
+ "Tools require a Zod 4 object schema.", "Tool execute must be a function.",
18
+ "Tool input schema cannot be represented as JSON Schema.",
19
+ ...["Model", "Effort", "Description", "Instructions", "Tool description"].map(label => `${label} must be a nonempty string.`),
20
+ ]);
21
+ export async function loadDefinition(file, subagents = []) {
22
+ let definition;
23
+ try {
24
+ const url = pathToFileURL(resolve(file));
25
+ url.searchParams.set("load", crypto.randomUUID());
26
+ const loaded = await tsImport(url.href, import.meta.url);
27
+ const exported = loaded.default?.__esModule ? loaded.default.default : loaded.default;
28
+ definition = agent(exported);
29
+ }
30
+ catch (error) {
31
+ const reason = error instanceof Error && safeDiagnostics.has(error.message)
32
+ && error.code === "INVALID_DEFINITION" ? error.message
33
+ : "Definition could not be loaded. Check its imports, dependencies, and module initialization.";
34
+ throw new AgentError("INVALID_DEFINITION", `${file}: ${reason}`);
35
+ }
36
+ for (const name of subagents) {
37
+ const children = definition.subagents ?? {};
38
+ const child = Object.hasOwn(children, name) ? children[name] : undefined;
39
+ if (!child)
40
+ throw new AgentError("INVALID_DEFINITION", `${file}: Subagent '${name}' is not declared.`);
41
+ definition = child;
42
+ }
43
+ return definition;
44
+ }
45
+ async function files(directory) {
46
+ let entries;
47
+ try {
48
+ entries = await readdir(directory, { withFileTypes: true });
49
+ }
50
+ catch (error) {
51
+ if (error.code === "ENOENT")
52
+ return [];
53
+ throw new AgentError("INVALID_CONFIG", `Cannot read agent directory: ${directory}`);
54
+ }
55
+ const found = [];
56
+ for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
57
+ const file = join(directory, entry.name);
58
+ if (entry.isDirectory())
59
+ found.push(...await files(file));
60
+ else if (entry.isFile() && entry.name.endsWith(".agent.ts"))
61
+ found.push(file);
62
+ }
63
+ return found;
64
+ }
65
+ export async function discover(cwd, options = {}) {
66
+ const { root } = await resolveProject(cwd);
67
+ const entries = [];
68
+ for (const [scope, base] of [["repo", root], ["global", options.home ?? homedir()]]) {
69
+ const names = new Set();
70
+ for (const file of await files(join(base, ".agents", "agents"))) {
71
+ const definition = await loadDefinition(file);
72
+ if (names.has(definition.name))
73
+ throw new AgentError("INVALID_DEFINITION", `${file}: Duplicate agent name '${definition.name}' in ${scope} scope.`);
74
+ names.add(definition.name);
75
+ entries.push({ id: `${scope}:${definition.name}`, name: definition.name, description: definition.description, scope, file, definition });
76
+ }
77
+ }
78
+ return entries;
79
+ }
80
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { tsImport } from \"tsx/esm/api\";\nimport { AgentError } from \"../errors.js\";\nimport { agent } from \"../sdk/definitions.js\";\nimport type { AgentDefinition } from \"../sdk/types.js\";\nimport { resolveProject } from \"./project.js\";\n\nexport interface CatalogEntry {\n id: string;\n name: string;\n description: string;\n scope: \"repo\" | \"global\";\n file: string;\n definition: AgentDefinition;\n}\n\n// Only fixed SDK diagnostics may cross the module-evaluation boundary.\n// User exceptions can contain credential values, including exceptions named AgentError.\nconst safeDiagnostics = new Set([\n \"Expected a configuration object.\", \"Unknown configuration field.\",\n \"Names must start with a letter and contain at most 64 letters, digits, underscores, or hyphens.\",\n \"fast must be a boolean.\", \"Unsupported harness kind.\", \"At least one harness is required.\",\n \"Claude effort must be low, medium, high, xhigh, or max.\",\n \"Subagent definitions cannot contain recursive references.\",\n \"Tools require a Zod 4 object schema.\", \"Tool execute must be a function.\",\n \"Tool input schema cannot be represented as JSON Schema.\",\n ...[\"Model\", \"Effort\", \"Description\", \"Instructions\", \"Tool description\"].map(label => `${label} must be a nonempty string.`),\n]);\n\nexport async function loadDefinition(file: string, subagents: string[] = []): Promise<AgentDefinition> {\n let definition: AgentDefinition;\n try {\n const url = pathToFileURL(resolve(file));\n url.searchParams.set(\"load\", crypto.randomUUID());\n const loaded = await tsImport(url.href, import.meta.url);\n const exported = loaded.default?.__esModule ? loaded.default.default : loaded.default;\n definition = agent(exported);\n } catch (error) {\n const reason = error instanceof Error && safeDiagnostics.has(error.message)\n && (error as AgentError).code === \"INVALID_DEFINITION\" ? error.message\n : \"Definition could not be loaded. Check its imports, dependencies, and module initialization.\";\n throw new AgentError(\"INVALID_DEFINITION\", `${file}: ${reason}`);\n }\n for (const name of subagents) {\n const children = definition.subagents ?? {};\n const child = Object.hasOwn(children, name) ? children[name] : undefined;\n if (!child) throw new AgentError(\"INVALID_DEFINITION\", `${file}: Subagent '${name}' is not declared.`);\n definition = child;\n }\n return definition;\n}\n\nasync function files(directory: string): Promise<string[]> {\n let entries;\n try { entries = await readdir(directory, { withFileTypes: true }); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw new AgentError(\"INVALID_CONFIG\", `Cannot read agent directory: ${directory}`);\n }\n const found: string[] = [];\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n const file = join(directory, entry.name);\n if (entry.isDirectory()) found.push(...await files(file));\n else if (entry.isFile() && entry.name.endsWith(\".agent.ts\")) found.push(file);\n }\n return found;\n}\n\nexport async function discover(cwd: string, options: { home?: string } = {}): Promise<CatalogEntry[]> {\n const { root } = await resolveProject(cwd);\n const entries: CatalogEntry[] = [];\n for (const [scope, base] of [[\"repo\", root], [\"global\", options.home ?? homedir()]] as const) {\n const names = new Set<string>();\n for (const file of await files(join(base, \".agents\", \"agents\"))) {\n const definition = await loadDefinition(file);\n if (names.has(definition.name)) throw new AgentError(\"INVALID_DEFINITION\", `${file}: Duplicate agent name '${definition.name}' in ${scope} scope.`);\n names.add(definition.name);\n entries.push({ id: `${scope}:${definition.name}`, name: definition.name, description: definition.description, scope, file, definition });\n }\n }\n return entries;\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function validateOidc(token: string, mainRoot: string, project: string | undefined, env: NodeJS.ProcessEnv): Promise<void>;
@@ -0,0 +1,53 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { configError } from "./access.js";
4
+ async function projectIdentity(mainRoot, project, env) {
5
+ let content;
6
+ try {
7
+ content = await readFile(resolve(mainRoot, project ?? ".", ".vercel/project.json"), "utf8");
8
+ }
9
+ catch (error) {
10
+ if (project === undefined && error.code === "ENOENT" && env.VERCEL_PROJECT_ID && env.VERCEL_ORG_ID) {
11
+ return { projectId: env.VERCEL_PROJECT_ID, orgId: env.VERCEL_ORG_ID };
12
+ }
13
+ configError("Selected OIDC project requires accessible .vercel/project.json linkage.");
14
+ }
15
+ let identity;
16
+ try {
17
+ identity = JSON.parse(content);
18
+ }
19
+ catch {
20
+ configError("Selected Vercel project linkage is not valid JSON.");
21
+ }
22
+ if (typeof identity?.projectId !== "string" || !identity.projectId || typeof identity.orgId !== "string" || !identity.orgId) {
23
+ configError("Selected Vercel project linkage requires projectId and orgId.");
24
+ }
25
+ return identity;
26
+ }
27
+ export async function validateOidc(token, mainRoot, project, env) {
28
+ const parts = token.split(".");
29
+ if (parts.length !== 3 || parts.some((part) => !/^[A-Za-z0-9_-]+$/.test(part)))
30
+ configError("Configured OIDC token is malformed.");
31
+ let claims;
32
+ try {
33
+ const header = JSON.parse(Buffer.from(parts[0], "base64url").toString("utf8"));
34
+ if (!header || typeof header !== "object" || Array.isArray(header))
35
+ throw new Error();
36
+ claims = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
37
+ }
38
+ catch {
39
+ configError("Configured OIDC token is malformed.");
40
+ }
41
+ const now = Date.now() / 1000;
42
+ if (!claims || typeof claims !== "object" || Array.isArray(claims)
43
+ || typeof claims.exp !== "number" || !Number.isFinite(claims.exp)
44
+ || (claims.nbf !== undefined && (typeof claims.nbf !== "number" || !Number.isFinite(claims.nbf)))) {
45
+ configError("Configured OIDC token has invalid validity claims.");
46
+ }
47
+ if (claims.exp <= now || (claims.nbf !== undefined && claims.nbf > now))
48
+ configError("Configured OIDC token is expired or not yet valid; refresh its credential source.");
49
+ const expected = await projectIdentity(mainRoot, project, env);
50
+ if (claims.project_id !== expected.projectId || claims.owner_id !== expected.orgId)
51
+ configError("Configured OIDC token does not match the selected Vercel project and organization.");
52
+ }
53
+ //# sourceMappingURL=oidc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oidc.js","sourceRoot":"","sources":["../../src/config/oidc.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { configError } from \"./access.js\";\n\ninterface ProjectIdentity { projectId: string; orgId: string }\n\nasync function projectIdentity(mainRoot: string, project: string | undefined, env: NodeJS.ProcessEnv): Promise<ProjectIdentity> {\n let content: string;\n try { content = await readFile(resolve(mainRoot, project ?? \".\", \".vercel/project.json\"), \"utf8\"); }\n catch (error) {\n if (project === undefined && (error as NodeJS.ErrnoException).code === \"ENOENT\" && env.VERCEL_PROJECT_ID && env.VERCEL_ORG_ID) {\n return { projectId: env.VERCEL_PROJECT_ID, orgId: env.VERCEL_ORG_ID };\n }\n configError(\"Selected OIDC project requires accessible .vercel/project.json linkage.\");\n }\n let identity;\n try { identity = JSON.parse(content); }\n catch { configError(\"Selected Vercel project linkage is not valid JSON.\"); }\n if (typeof identity?.projectId !== \"string\" || !identity.projectId || typeof identity.orgId !== \"string\" || !identity.orgId) {\n configError(\"Selected Vercel project linkage requires projectId and orgId.\");\n }\n return identity;\n}\n\nexport async function validateOidc(token: string, mainRoot: string, project: string | undefined, env: NodeJS.ProcessEnv): Promise<void> {\n const parts = token.split(\".\");\n if (parts.length !== 3 || parts.some((part) => !/^[A-Za-z0-9_-]+$/.test(part))) configError(\"Configured OIDC token is malformed.\");\n let claims;\n try {\n const header = JSON.parse(Buffer.from(parts[0]!, \"base64url\").toString(\"utf8\"));\n if (!header || typeof header !== \"object\" || Array.isArray(header)) throw new Error();\n claims = JSON.parse(Buffer.from(parts[1]!, \"base64url\").toString(\"utf8\"));\n } catch { configError(\"Configured OIDC token is malformed.\"); }\n const now = Date.now() / 1000;\n if (!claims || typeof claims !== \"object\" || Array.isArray(claims)\n || typeof claims.exp !== \"number\" || !Number.isFinite(claims.exp)\n || (claims.nbf !== undefined && (typeof claims.nbf !== \"number\" || !Number.isFinite(claims.nbf)))) {\n configError(\"Configured OIDC token has invalid validity claims.\");\n }\n if (claims.exp <= now || (claims.nbf !== undefined && claims.nbf > now)) configError(\"Configured OIDC token is expired or not yet valid; refresh its credential source.\");\n const expected = await projectIdentity(mainRoot, project, env);\n if (claims.project_id !== expected.projectId || claims.owner_id !== expected.orgId) configError(\"Configured OIDC token does not match the selected Vercel project and organization.\");\n}\n"]}
@@ -0,0 +1,5 @@
1
+ export declare function git(cwd: string, args: string[]): Promise<string>;
2
+ export declare function resolveProject(cwd: string): Promise<{
3
+ root: string;
4
+ mainRoot: string;
5
+ }>;
@@ -0,0 +1,56 @@
1
+ import { execFile } from "node:child_process";
2
+ import { realpath, stat } from "node:fs/promises";
3
+ import { promisify } from "node:util";
4
+ import { AgentError } from "../errors.js";
5
+ const execute = promisify(execFile);
6
+ // These variables describe a caller's repository, not the explicit execution directory.
7
+ // Keep normal user/system Git configuration and leave the caller's environment untouched.
8
+ const repositoryVariables = new Set([
9
+ "GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "GIT_IMPLICIT_WORK_TREE",
10
+ "GIT_INDEX_FILE", "GIT_OBJECT_DIRECTORY", "GIT_ALTERNATE_OBJECT_DIRECTORIES",
11
+ "GIT_GRAFT_FILE", "GIT_SHALLOW_FILE", "GIT_NAMESPACE", "GIT_QUARANTINE_PATH",
12
+ "GIT_PREFIX", "GIT_INTERNAL_SUPER_PREFIX", "GIT_NO_REPLACE_OBJECTS", "GIT_REPLACE_REF_BASE",
13
+ "GIT_CEILING_DIRECTORIES", "GIT_DISCOVERY_ACROSS_FILESYSTEM", "GIT_REFERENCE_BACKEND",
14
+ "GIT_CONFIG", "GIT_CONFIG_PARAMETERS", "GIT_CONFIG_COUNT",
15
+ ]);
16
+ export async function git(cwd, args) {
17
+ const env = { ...process.env };
18
+ for (const key of Object.keys(env)) {
19
+ if (repositoryVariables.has(key) || /^GIT_CONFIG_(KEY|VALUE)_\d+$/.test(key))
20
+ delete env[key];
21
+ }
22
+ const { stdout } = await execute("git", ["-C", cwd, ...args], { env, maxBuffer: 1024 * 1024 });
23
+ return stdout.trim();
24
+ }
25
+ export async function resolveProject(cwd) {
26
+ let directory;
27
+ try {
28
+ directory = await realpath(cwd);
29
+ if (!(await stat(directory)).isDirectory())
30
+ throw new Error();
31
+ }
32
+ catch {
33
+ throw new AgentError("INVALID_CONFIG", `Execution directory is not accessible: ${cwd}`);
34
+ }
35
+ try {
36
+ if ((await git(directory, ["rev-parse", "--is-bare-repository"])) === "true") {
37
+ throw new AgentError("INVALID_CONFIG", "Bare repositories are unsupported execution directories.");
38
+ }
39
+ const root = await git(directory, ["rev-parse", "--show-toplevel"]);
40
+ const worktrees = await git(directory, ["worktree", "list", "--porcelain", "-z"]);
41
+ const first = worktrees.split("\0").find((line) => line.startsWith("worktree "));
42
+ if (!first)
43
+ throw new Error();
44
+ const mainRoot = await realpath(first.slice("worktree ".length));
45
+ return { root: await realpath(root), mainRoot };
46
+ }
47
+ catch (error) {
48
+ if (error instanceof AgentError)
49
+ throw error;
50
+ const message = error instanceof Error ? error.message : "";
51
+ if (message.includes("not a git repository"))
52
+ return { root: directory, mainRoot: directory };
53
+ throw new AgentError("INVALID_CONFIG", "The Git project or its main checkout cannot be accessed.");
54
+ }
55
+ }
56
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/config/project.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { realpath, stat } from \"node:fs/promises\";\nimport { promisify } from \"node:util\";\nimport { AgentError } from \"../errors.js\";\n\nconst execute = promisify(execFile);\n\n// These variables describe a caller's repository, not the explicit execution directory.\n// Keep normal user/system Git configuration and leave the caller's environment untouched.\nconst repositoryVariables = new Set([\n \"GIT_DIR\", \"GIT_WORK_TREE\", \"GIT_COMMON_DIR\", \"GIT_IMPLICIT_WORK_TREE\",\n \"GIT_INDEX_FILE\", \"GIT_OBJECT_DIRECTORY\", \"GIT_ALTERNATE_OBJECT_DIRECTORIES\",\n \"GIT_GRAFT_FILE\", \"GIT_SHALLOW_FILE\", \"GIT_NAMESPACE\", \"GIT_QUARANTINE_PATH\",\n \"GIT_PREFIX\", \"GIT_INTERNAL_SUPER_PREFIX\", \"GIT_NO_REPLACE_OBJECTS\", \"GIT_REPLACE_REF_BASE\",\n \"GIT_CEILING_DIRECTORIES\", \"GIT_DISCOVERY_ACROSS_FILESYSTEM\", \"GIT_REFERENCE_BACKEND\",\n \"GIT_CONFIG\", \"GIT_CONFIG_PARAMETERS\", \"GIT_CONFIG_COUNT\",\n]);\n\nexport async function git(cwd: string, args: string[]): Promise<string> {\n const env = { ...process.env };\n for (const key of Object.keys(env)) {\n if (repositoryVariables.has(key) || /^GIT_CONFIG_(KEY|VALUE)_\\d+$/.test(key)) delete env[key];\n }\n const { stdout } = await execute(\"git\", [\"-C\", cwd, ...args], { env, maxBuffer: 1024 * 1024 });\n return stdout.trim();\n}\n\nexport async function resolveProject(cwd: string): Promise<{ root: string; mainRoot: string }> {\n let directory: string;\n try {\n directory = await realpath(cwd);\n if (!(await stat(directory)).isDirectory()) throw new Error();\n } catch {\n throw new AgentError(\"INVALID_CONFIG\", `Execution directory is not accessible: ${cwd}`);\n }\n try {\n if ((await git(directory, [\"rev-parse\", \"--is-bare-repository\"])) === \"true\") {\n throw new AgentError(\"INVALID_CONFIG\", \"Bare repositories are unsupported execution directories.\");\n }\n const root = await git(directory, [\"rev-parse\", \"--show-toplevel\"]);\n const worktrees = await git(directory, [\"worktree\", \"list\", \"--porcelain\", \"-z\"]);\n const first = worktrees.split(\"\\0\").find((line) => line.startsWith(\"worktree \"));\n if (!first) throw new Error();\n const mainRoot = await realpath(first.slice(\"worktree \".length));\n return { root: await realpath(root), mainRoot };\n } catch (error) {\n if (error instanceof AgentError) throw error;\n const message = error instanceof Error ? error.message : \"\";\n if (message.includes(\"not a git repository\")) return { root: directory, mainRoot: directory };\n throw new AgentError(\"INVALID_CONFIG\", \"The Git project or its main checkout cannot be accessed.\");\n }\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { ResolvedAccess } from "../adapters/types.js";
2
+ import type { HarnessConfig, HarnessKind } from "../sdk/types.js";
3
+ import { type AccessConnection } from "./access.js";
4
+ export declare function resolveAccess(connection: AccessConnection, harness: HarnessKind | HarnessConfig, cwd: string, env?: NodeJS.ProcessEnv): Promise<ResolvedAccess>;