subharness 0.0.3 → 0.0.4

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 (110) hide show
  1. package/README.md +3 -3
  2. package/dist/adapters/approval-context.d.ts +2 -0
  3. package/dist/adapters/approval-context.js +9 -0
  4. package/dist/adapters/approval-context.js.map +1 -0
  5. package/dist/adapters/approval-lifetime.d.ts +8 -0
  6. package/dist/adapters/approval-lifetime.js +50 -0
  7. package/dist/adapters/approval-lifetime.js.map +1 -0
  8. package/dist/adapters/claude-approvals.d.ts +4 -0
  9. package/dist/adapters/claude-approvals.js +32 -0
  10. package/dist/adapters/claude-approvals.js.map +1 -0
  11. package/dist/adapters/claude-permissions.js +1 -1
  12. package/dist/adapters/claude-permissions.js.map +1 -1
  13. package/dist/adapters/claude.js +30 -1
  14. package/dist/adapters/claude.js.map +1 -1
  15. package/dist/adapters/codex-approvals.d.ts +6 -0
  16. package/dist/adapters/codex-approvals.js +111 -0
  17. package/dist/adapters/codex-approvals.js.map +1 -0
  18. package/dist/adapters/codex.js +32 -2
  19. package/dist/adapters/codex.js.map +1 -1
  20. package/dist/adapters/fx-approvals.d.ts +2 -0
  21. package/dist/adapters/fx-approvals.js +14 -0
  22. package/dist/adapters/fx-approvals.js.map +1 -0
  23. package/dist/adapters/fx.js +49 -18
  24. package/dist/adapters/fx.js.map +1 -1
  25. package/dist/adapters/types.d.ts +2 -0
  26. package/dist/adapters/types.js.map +1 -1
  27. package/dist/approvals/schema.d.ts +4 -0
  28. package/dist/approvals/schema.js +70 -0
  29. package/dist/approvals/schema.js.map +1 -0
  30. package/dist/approvals/types.d.ts +47 -0
  31. package/dist/approvals/types.js +2 -0
  32. package/dist/approvals/types.js.map +1 -0
  33. package/dist/cli/args.d.ts +2 -1
  34. package/dist/cli/args.js +20 -2
  35. package/dist/cli/args.js.map +1 -1
  36. package/dist/cli/dashboard-client.d.ts +5 -1
  37. package/dist/cli/dashboard-client.js +161 -14
  38. package/dist/cli/dashboard-client.js.map +1 -1
  39. package/dist/cli/dashboard-detail-view.d.ts +16 -0
  40. package/dist/cli/dashboard-detail-view.js +163 -0
  41. package/dist/cli/dashboard-detail-view.js.map +1 -0
  42. package/dist/cli/dashboard-history-view.d.ts +29 -0
  43. package/dist/cli/dashboard-history-view.js +211 -0
  44. package/dist/cli/dashboard-history-view.js.map +1 -0
  45. package/dist/cli/dashboard-input.d.ts +14 -0
  46. package/dist/cli/dashboard-input.js +118 -0
  47. package/dist/cli/dashboard-input.js.map +1 -0
  48. package/dist/cli/dashboard-layout.d.ts +12 -1
  49. package/dist/cli/dashboard-layout.js +29 -27
  50. package/dist/cli/dashboard-layout.js.map +1 -1
  51. package/dist/cli/dashboard-renderer.d.ts +30 -2
  52. package/dist/cli/dashboard-renderer.js +125 -7
  53. package/dist/cli/dashboard-renderer.js.map +1 -1
  54. package/dist/cli/dashboard-style.d.ts +9 -0
  55. package/dist/cli/dashboard-style.js +36 -0
  56. package/dist/cli/dashboard-style.js.map +1 -0
  57. package/dist/cli/dashboard.d.ts +3 -1
  58. package/dist/cli/dashboard.js +127 -12
  59. package/dist/cli/dashboard.js.map +1 -1
  60. package/dist/cli/help.js +7 -0
  61. package/dist/cli/help.js.map +1 -1
  62. package/dist/cli/input.d.ts +1 -0
  63. package/dist/cli/input.js +23 -17
  64. package/dist/cli/input.js.map +1 -1
  65. package/dist/cli/main.js +1 -1
  66. package/dist/cli/main.js.map +1 -1
  67. package/dist/cli/output.js +17 -1
  68. package/dist/cli/output.js.map +1 -1
  69. package/dist/runtime/approval-registry.d.ts +27 -0
  70. package/dist/runtime/approval-registry.js +126 -0
  71. package/dist/runtime/approval-registry.js.map +1 -0
  72. package/dist/runtime/coordinator.d.ts +17 -1
  73. package/dist/runtime/coordinator.js +124 -6
  74. package/dist/runtime/coordinator.js.map +1 -1
  75. package/dist/runtime/dashboard.d.ts +42 -0
  76. package/dist/runtime/dashboard.js.map +1 -1
  77. package/dist/runtime/select-native.d.ts +2 -1
  78. package/dist/runtime/select-native.js +2 -2
  79. package/dist/runtime/select-native.js.map +1 -1
  80. package/dist/runtime/service.js +24 -1
  81. package/dist/runtime/service.js.map +1 -1
  82. package/dist/runtime/types.d.ts +9 -1
  83. package/dist/runtime/types.js.map +1 -1
  84. package/dist/runtime/worker-approvals.d.ts +21 -0
  85. package/dist/runtime/worker-approvals.js +51 -0
  86. package/dist/runtime/worker-approvals.js.map +1 -0
  87. package/dist/runtime/worker-client.js +35 -7
  88. package/dist/runtime/worker-client.js.map +1 -1
  89. package/dist/runtime/worker-server.d.ts +2 -0
  90. package/dist/runtime/worker-server.js +39 -10
  91. package/dist/runtime/worker-server.js.map +1 -1
  92. package/package.json +1 -1
  93. package/sdk/access-config.md +28 -0
  94. package/sdk/adapter-contract.md +2 -10
  95. package/sdk/agent-skill.md +6 -3
  96. package/sdk/approvals.md +118 -0
  97. package/sdk/cli/dashboard-design.md +38 -4
  98. package/sdk/cli/dashboard-inspection.md +25 -0
  99. package/sdk/cli/index.md +11 -5
  100. package/sdk/cli/output.md +7 -3
  101. package/sdk/completion-notifications.md +2 -0
  102. package/sdk/distribution.md +52 -0
  103. package/sdk/evals.md +9 -3
  104. package/sdk/fx.md +1 -1
  105. package/sdk/index.md +1 -0
  106. package/sdk/message-delivery.md +1 -1
  107. package/sdk/permissions.md +4 -4
  108. package/sdk/pr-integration.md +1 -1
  109. package/sdk/sessions.md +4 -1
  110. package/sdk/v1-runtime.md +3 -3
@@ -1,8 +1,8 @@
1
- import { setTimeout as delay } from 'node:timers/promises';
2
1
  import { AgentError } from '../errors.js';
3
2
  import { resolveDashboardWorkspace } from '../runtime/dashboard-workspace.js';
4
3
  import { readEndpoint, stateDirectory } from '../runtime/state.js';
5
- import { fetchDashboardSnapshot } from './dashboard-client.js';
4
+ import { fetchDashboardDetail, fetchDashboardSession, fetchDashboardSnapshot } from './dashboard-client.js';
5
+ import { DashboardKeyDecoder } from './dashboard-input.js';
6
6
  import { DashboardRenderer } from './dashboard-renderer.js';
7
7
  export async function runDashboard(options = {}) {
8
8
  const output = options.output ?? process.stdout;
@@ -16,21 +16,106 @@ export async function runDashboard(options = {}) {
16
16
  const signals = options.signals ?? process;
17
17
  const discover = options.discover ?? (() => readEndpoint(stateDirectory()));
18
18
  const snapshot = options.snapshot ?? fetchDashboardSnapshot;
19
+ const detail = options.detail ?? fetchDashboardDetail;
20
+ const session = options.session ?? fetchDashboardSession;
19
21
  const interval = options.intervalMs ?? 1_000;
20
22
  const abort = new AbortController();
21
- const renderer = new DashboardRenderer(output, await resolveDashboardWorkspace(options.cwd ?? process.cwd()));
23
+ const workspace = await resolveDashboardWorkspace(options.cwd ?? process.cwd());
22
24
  let rows = [];
23
25
  let endpoint;
24
26
  let exitCode = 0;
25
27
  let outputError;
26
- const interrupt = () => { exitCode = 130; abort.abort(); };
27
- const terminate = () => { exitCode = 143; abort.abort(); };
28
- const keys = (chunk) => {
29
- if (typeof chunk === 'string' ? chunk.includes('\u0003') : chunk.includes(3))
28
+ let detailAbort;
29
+ let wake;
30
+ const stop = (code) => {
31
+ exitCode = code;
32
+ detailAbort?.abort();
33
+ abort.abort();
34
+ wake?.();
35
+ };
36
+ const failedOutput = (error) => {
37
+ outputError ??= error;
38
+ detailAbort?.abort();
39
+ abort.abort();
40
+ wake?.();
41
+ };
42
+ // Event listeners and the decoder's Escape timer run outside the polling try/finally.
43
+ const guarded = (callback) => (...args) => {
44
+ if (abort.signal.aborted)
45
+ return;
46
+ try {
47
+ callback(...args);
48
+ }
49
+ catch (error) {
50
+ failedOutput(error);
51
+ }
52
+ };
53
+ const renderer = new DashboardRenderer(output, workspace, !process.env.NO_COLOR, failedOutput);
54
+ const interrupt = () => stop(130);
55
+ const terminate = () => stop(143);
56
+ const key = (pressed) => {
57
+ if (pressed === 'interrupt') {
30
58
  interrupt();
59
+ return;
60
+ }
61
+ if (pressed === 'escape') {
62
+ if (renderer.leaveDetail()) {
63
+ detailAbort?.abort();
64
+ detailAbort = undefined;
65
+ wake?.();
66
+ }
67
+ return;
68
+ }
69
+ if (pressed === 'enter') {
70
+ if (renderer.inspecting ? renderer.toggleExpansion() : renderer.openDetail()) {
71
+ detailAbort?.abort();
72
+ detailAbort = new AbortController();
73
+ wake?.();
74
+ }
75
+ return;
76
+ }
77
+ if (pressed === 'up' || pressed === 'down') {
78
+ if (renderer.inspecting) {
79
+ const expanded = renderer.expandedTaskId;
80
+ renderer.scrollDetail(pressed);
81
+ if (expanded !== renderer.expandedTaskId) {
82
+ detailAbort?.abort();
83
+ detailAbort = new AbortController();
84
+ wake?.();
85
+ }
86
+ }
87
+ else
88
+ renderer.moveSelection(pressed === 'up' ? -1 : 1);
89
+ return;
90
+ }
91
+ if (renderer.inspecting)
92
+ renderer.scrollDetail(pressed);
93
+ };
94
+ const decoder = new DashboardKeyDecoder(guarded(key));
95
+ const keys = guarded((chunk) => decoder.push(chunk));
96
+ const resize = guarded(() => renderer.render(rows, Date.now()));
97
+ const waitForRefresh = (milliseconds) => {
98
+ if (abort.signal.aborted)
99
+ return Promise.resolve();
100
+ return new Promise(resolve => {
101
+ let timer;
102
+ const done = () => {
103
+ if (timer)
104
+ clearTimeout(timer);
105
+ abort.signal.removeEventListener('abort', done);
106
+ if (wake === done)
107
+ wake = undefined;
108
+ resolve();
109
+ };
110
+ abort.signal.addEventListener('abort', done, { once: true });
111
+ if (abort.signal.aborted) {
112
+ done();
113
+ return;
114
+ }
115
+ timer = setTimeout(done, milliseconds);
116
+ wake = done;
117
+ });
31
118
  };
32
- const resize = () => renderer.render(rows, Date.now());
33
- const failedOutput = (error) => { outputError = error; abort.abort(); };
34
119
  signals.on('SIGINT', interrupt);
35
120
  signals.on('SIGTERM', terminate);
36
121
  output.on('resize', resize);
@@ -48,12 +133,35 @@ export async function runDashboard(options = {}) {
48
133
  endpoint ??= await discover();
49
134
  if (abort.signal.aborted)
50
135
  break;
51
- if (endpoint)
136
+ if (endpoint && !renderer.inspecting)
52
137
  rows = (await snapshot(endpoint, abort.signal)).sessions;
53
138
  if (abort.signal.aborted)
54
139
  break;
55
140
  renderer.render(rows, Date.now());
56
- await delay(Math.max(0, next - Date.now()), undefined, { signal: abort.signal });
141
+ const inspectionId = renderer.inspectedTaskId;
142
+ const inspectionAbort = detailAbort;
143
+ if (endpoint && inspectionId && inspectionAbort) {
144
+ try {
145
+ const signal = AbortSignal.any([abort.signal, inspectionAbort.signal]);
146
+ const history = await session(endpoint, inspectionId, signal);
147
+ if (abort.signal.aborted || detailAbort !== inspectionAbort || renderer.inspectedTaskId !== inspectionId)
148
+ continue;
149
+ renderer.updateSession(history);
150
+ const expandedId = renderer.expandedTaskId;
151
+ if (expandedId) {
152
+ const record = await detail(endpoint, expandedId, signal, !renderer.detailLoaded, renderer.knownResponseId);
153
+ if (!abort.signal.aborted && detailAbort === inspectionAbort && renderer.expandedTaskId === expandedId) {
154
+ renderer.updateDetail(record);
155
+ }
156
+ }
157
+ }
158
+ catch (error) {
159
+ if (detailAbort !== inspectionAbort || renderer.inspectedTaskId !== inspectionId)
160
+ continue;
161
+ throw error;
162
+ }
163
+ }
164
+ await waitForRefresh(Math.max(0, next - Date.now()));
57
165
  }
58
166
  }
59
167
  catch (error) {
@@ -62,7 +170,14 @@ export async function runDashboard(options = {}) {
62
170
  }
63
171
  finally {
64
172
  abort.abort();
65
- renderer.close();
173
+ detailAbort?.abort();
174
+ decoder.close();
175
+ try {
176
+ renderer.close();
177
+ }
178
+ catch (error) {
179
+ outputError ??= error;
180
+ }
66
181
  if (inputEnabled) {
67
182
  input.off('data', keys);
68
183
  input.setRawMode(wasRaw);
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/cli/dashboard.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EventEmitter } from 'node:events';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { AgentError } from '../errors.js';\nimport type { DashboardRow, DashboardSnapshot } from '../runtime/dashboard.js';\nimport { resolveDashboardWorkspace } from '../runtime/dashboard-workspace.js';\nimport { readEndpoint, stateDirectory, type Endpoint } from '../runtime/state.js';\nimport { fetchDashboardSnapshot } from './dashboard-client.js';\nimport { DashboardRenderer, type DashboardOutput } from './dashboard-renderer.js';\n\ninterface Terminal extends DashboardOutput {\n isTTY?: boolean;\n on(event: 'drain' | 'resize' | 'error', listener: (...args: any[]) => void): unknown;\n off(event: 'drain' | 'resize' | 'error', listener: (...args: any[]) => void): unknown;\n}\ninterface Keyboard {\n isTTY?: boolean;\n isRaw?: boolean;\n readableFlowing: boolean | null;\n setRawMode(enabled: boolean): unknown;\n resume(): unknown;\n pause(): unknown;\n on(event: 'data', listener: (chunk: Buffer | string) => void): unknown;\n off(event: 'data', listener: (chunk: Buffer | string) => void): unknown;\n}\ninterface DashboardOptions {\n cwd?: string;\n output?: Terminal;\n input?: Keyboard;\n signals?: Pick<EventEmitter, 'on' | 'off'>;\n term?: string;\n intervalMs?: number;\n discover?: () => Promise<Endpoint | undefined>;\n snapshot?: (endpoint: Endpoint, signal: AbortSignal) => Promise<DashboardSnapshot>;\n}\n\nexport async function runDashboard(options: DashboardOptions = {}): Promise<number> {\n const output = options.output ?? process.stdout;\n if (!output.isTTY || (options.term ?? process.env.TERM) === 'dumb') {\n throw new AgentError('INVALID_ARGUMENT', 'The dashboard requires terminal stdout with cursor control.');\n }\n const input = options.input ?? process.stdin;\n const wasRaw = input.isRaw ?? false;\n const wasFlowing = input.readableFlowing === true;\n let inputEnabled = false;\n const signals = options.signals ?? process;\n const discover = options.discover ?? (() => readEndpoint(stateDirectory()));\n const snapshot = options.snapshot ?? fetchDashboardSnapshot;\n const interval = options.intervalMs ?? 1_000;\n const abort = new AbortController();\n const renderer = new DashboardRenderer(output, await resolveDashboardWorkspace(options.cwd ?? process.cwd()));\n let rows: DashboardRow[] = [];\n let endpoint: Endpoint | undefined;\n let exitCode = 0;\n let outputError: unknown;\n const interrupt = () => { exitCode = 130; abort.abort(); };\n const terminate = () => { exitCode = 143; abort.abort(); };\n const keys = (chunk: Buffer | string) => {\n if (typeof chunk === 'string' ? chunk.includes('\\u0003') : chunk.includes(3)) interrupt();\n };\n const resize = () => renderer.render(rows, Date.now());\n const failedOutput = (error: unknown) => { outputError = error; abort.abort(); };\n signals.on('SIGINT', interrupt);\n signals.on('SIGTERM', terminate);\n output.on('resize', resize);\n output.on('error', failedOutput);\n try {\n if (input.isTTY) {\n input.setRawMode(true);\n inputEnabled = true;\n input.on('data', keys);\n input.resume();\n }\n renderer.start();\n while (!abort.signal.aborted) {\n const next = Date.now() + interval;\n endpoint ??= await discover();\n if (abort.signal.aborted) break;\n if (endpoint) rows = (await snapshot(endpoint, abort.signal)).sessions;\n if (abort.signal.aborted) break;\n renderer.render(rows, Date.now());\n await delay(Math.max(0, next - Date.now()), undefined, {signal: abort.signal});\n }\n } catch (error) {\n if (!abort.signal.aborted) throw error;\n } finally {\n abort.abort();\n renderer.close();\n if (inputEnabled) {\n input.off('data', keys);\n input.setRawMode(wasRaw);\n if (!wasFlowing) input.pause();\n }\n signals.off('SIGINT', interrupt);\n signals.off('SIGTERM', terminate);\n output.off('resize', resize);\n output.off('error', failedOutput);\n }\n if (outputError) throw new AgentError('INTERNAL', 'The dashboard terminal output failed.');\n return exitCode;\n}\n"]}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/cli/dashboard.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EventEmitter } from 'node:events';\nimport { AgentError } from '../errors.js';\nimport type { DashboardDetail, DashboardRow, DashboardSession, DashboardSnapshot } from '../runtime/dashboard.js';\nimport { resolveDashboardWorkspace } from '../runtime/dashboard-workspace.js';\nimport { readEndpoint, stateDirectory, type Endpoint } from '../runtime/state.js';\nimport { fetchDashboardDetail, fetchDashboardSession, fetchDashboardSnapshot } from './dashboard-client.js';\nimport { DashboardKeyDecoder, type DashboardKey } from './dashboard-input.js';\nimport { DashboardRenderer, type DashboardOutput } from './dashboard-renderer.js';\n\ninterface Terminal extends DashboardOutput {\n isTTY?: boolean;\n on(event: 'drain' | 'resize' | 'error', listener: (...args: any[]) => void): unknown;\n off(event: 'drain' | 'resize' | 'error', listener: (...args: any[]) => void): unknown;\n}\ninterface Keyboard {\n isTTY?: boolean;\n isRaw?: boolean;\n readableFlowing: boolean | null;\n setRawMode(enabled: boolean): unknown;\n resume(): unknown;\n pause(): unknown;\n on(event: 'data', listener: (chunk: Buffer | string) => void): unknown;\n off(event: 'data', listener: (chunk: Buffer | string) => void): unknown;\n}\ninterface DashboardOptions {\n cwd?: string;\n output?: Terminal;\n input?: Keyboard;\n signals?: Pick<EventEmitter, 'on' | 'off'>;\n term?: string;\n intervalMs?: number;\n discover?: () => Promise<Endpoint | undefined>;\n snapshot?: (endpoint: Endpoint, signal: AbortSignal) => Promise<DashboardSnapshot>;\n session?: (endpoint: Endpoint, id: string, signal: AbortSignal) => Promise<DashboardSession>;\n detail?: (\n endpoint: Endpoint,\n id: string,\n signal: AbortSignal,\n includePrompt?: boolean,\n knownResponseId?: string,\n ) => Promise<DashboardDetail>;\n}\n\nexport async function runDashboard(options: DashboardOptions = {}): Promise<number> {\n const output = options.output ?? process.stdout;\n if (!output.isTTY || (options.term ?? process.env.TERM) === 'dumb') {\n throw new AgentError('INVALID_ARGUMENT', 'The dashboard requires terminal stdout with cursor control.');\n }\n const input = options.input ?? process.stdin;\n const wasRaw = input.isRaw ?? false;\n const wasFlowing = input.readableFlowing === true;\n let inputEnabled = false;\n const signals = options.signals ?? process;\n const discover = options.discover ?? (() => readEndpoint(stateDirectory()));\n const snapshot = options.snapshot ?? fetchDashboardSnapshot;\n const detail = options.detail ?? fetchDashboardDetail;\n const session = options.session ?? fetchDashboardSession;\n const interval = options.intervalMs ?? 1_000;\n const abort = new AbortController();\n const workspace = await resolveDashboardWorkspace(options.cwd ?? process.cwd());\n let rows: DashboardRow[] = [];\n let endpoint: Endpoint | undefined;\n let exitCode = 0;\n let outputError: unknown;\n let detailAbort: AbortController | undefined;\n let wake: (() => void) | undefined;\n const stop = (code: number) => {\n exitCode = code;\n detailAbort?.abort();\n abort.abort();\n wake?.();\n };\n const failedOutput = (error: unknown) => {\n outputError ??= error;\n detailAbort?.abort();\n abort.abort();\n wake?.();\n };\n // Event listeners and the decoder's Escape timer run outside the polling try/finally.\n const guarded = <Arguments extends unknown[]>(callback: (...args: Arguments) => void) => (...args: Arguments) => {\n if (abort.signal.aborted) return;\n try { callback(...args); } catch (error) { failedOutput(error); }\n };\n const renderer = new DashboardRenderer(output, workspace, !process.env.NO_COLOR, failedOutput);\n const interrupt = () => stop(130);\n const terminate = () => stop(143);\n const key = (pressed: DashboardKey) => {\n if (pressed === 'interrupt') { interrupt(); return; }\n if (pressed === 'escape') {\n if (renderer.leaveDetail()) {\n detailAbort?.abort();\n detailAbort = undefined;\n wake?.();\n }\n return;\n }\n if (pressed === 'enter') {\n if (renderer.inspecting ? renderer.toggleExpansion() : renderer.openDetail()) {\n detailAbort?.abort();\n detailAbort = new AbortController();\n wake?.();\n }\n return;\n }\n if (pressed === 'up' || pressed === 'down') {\n if (renderer.inspecting) {\n const expanded = renderer.expandedTaskId;\n renderer.scrollDetail(pressed);\n if (expanded !== renderer.expandedTaskId) {\n detailAbort?.abort(); detailAbort = new AbortController(); wake?.();\n }\n }\n else renderer.moveSelection(pressed === 'up' ? -1 : 1);\n return;\n }\n if (renderer.inspecting) renderer.scrollDetail(pressed);\n };\n const decoder = new DashboardKeyDecoder(guarded(key));\n const keys = guarded((chunk: Buffer | string) => decoder.push(chunk));\n const resize = guarded(() => renderer.render(rows, Date.now()));\n const waitForRefresh = (milliseconds: number): Promise<void> => {\n if (abort.signal.aborted) return Promise.resolve();\n return new Promise<void>(resolve => {\n let timer: NodeJS.Timeout | undefined;\n const done = () => {\n if (timer) clearTimeout(timer);\n abort.signal.removeEventListener('abort', done);\n if (wake === done) wake = undefined;\n resolve();\n };\n abort.signal.addEventListener('abort', done, {once: true});\n if (abort.signal.aborted) { done(); return; }\n timer = setTimeout(done, milliseconds);\n wake = done;\n });\n };\n signals.on('SIGINT', interrupt);\n signals.on('SIGTERM', terminate);\n output.on('resize', resize);\n output.on('error', failedOutput);\n try {\n if (input.isTTY) {\n input.setRawMode(true);\n inputEnabled = true;\n input.on('data', keys);\n input.resume();\n }\n renderer.start();\n while (!abort.signal.aborted) {\n const next = Date.now() + interval;\n endpoint ??= await discover();\n if (abort.signal.aborted) break;\n if (endpoint && !renderer.inspecting) rows = (await snapshot(endpoint, abort.signal)).sessions;\n if (abort.signal.aborted) break;\n renderer.render(rows, Date.now());\n const inspectionId = renderer.inspectedTaskId;\n const inspectionAbort = detailAbort;\n if (endpoint && inspectionId && inspectionAbort) {\n try {\n const signal = AbortSignal.any([abort.signal, inspectionAbort.signal]);\n const history = await session(endpoint, inspectionId, signal);\n if (abort.signal.aborted || detailAbort !== inspectionAbort || renderer.inspectedTaskId !== inspectionId) continue;\n renderer.updateSession(history);\n const expandedId = renderer.expandedTaskId;\n if (expandedId) {\n const record = await detail(endpoint, expandedId, signal, !renderer.detailLoaded, renderer.knownResponseId);\n if (!abort.signal.aborted && detailAbort === inspectionAbort && renderer.expandedTaskId === expandedId) {\n renderer.updateDetail(record);\n }\n }\n } catch (error) {\n if (detailAbort !== inspectionAbort || renderer.inspectedTaskId !== inspectionId) continue;\n throw error;\n }\n }\n await waitForRefresh(Math.max(0, next - Date.now()));\n }\n } catch (error) {\n if (!abort.signal.aborted) throw error;\n } finally {\n abort.abort();\n detailAbort?.abort();\n decoder.close();\n try { renderer.close(); } catch (error) { outputError ??= error; }\n if (inputEnabled) {\n input.off('data', keys);\n input.setRawMode(wasRaw);\n if (!wasFlowing) input.pause();\n }\n signals.off('SIGINT', interrupt);\n signals.off('SIGTERM', terminate);\n output.off('resize', resize);\n output.off('error', failedOutput);\n }\n if (outputError) throw new AgentError('INTERNAL', 'The dashboard terminal output failed.');\n return exitCode;\n}\n"]}
package/dist/cli/help.js CHANGED
@@ -16,6 +16,8 @@ Usage:
16
16
  subharness queue <session-id>
17
17
  subharness cancel <task-id>
18
18
  subharness resume <session-id>
19
+ subharness respond <request-id> --content <json>
20
+ subharness respond <request-id> --content-file <path|->
19
21
 
20
22
  Direct harness targets: codex, claude, fx. These bare names are reserved; same-named specialists require repo: or global:.
21
23
  Specialist targets: repo:<name>, global:<name>, or an unambiguous bare name.
@@ -24,6 +26,11 @@ Run "subharness run <harness> --help" or "subharness check <harness> --help" for
24
26
  Execution commands accept --format text|jsonl; text is the default.
25
27
  Omit --after to wait for the first retained response; supply it to wait for the next response.
26
28
  Detach after admission with --detach, then use wait or status; steering cannot be detached.
29
+ Permission requests return approval_required with a request-specific schema. Inspect the action and scope,
30
+ respond with one JSON object matching that schema (at most 16 KiB), then wait on the same task.
31
+ Each request offers its own choices; never invent a universal allow/deny value or assume "always" is permanent.
32
+ Denial uses an offered rejection choice. Use cancel to stop the task; resume does not answer permissions.
33
+ Approval content files resolve from the caller's working directory; - reads standard input.
27
34
  Dashboard is a terminal-only read-only view and accepts no options.
28
35
  --help and --version do not start a coordinator or native harness.
29
36
  Use -- to pass a positional prompt beginning with a dash.
@@ -1 +1 @@
1
- {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BnB,CAAC;AAEF,MAAM,OAAO,GAA0E;IACrF,KAAK,EAAE;QACL,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,wEAAwE;QAChF,MAAM,EAAE,mGAAmG;KAC5G;IACD,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,8EAA8E;QACtF,MAAM,EAAE,yDAAyD;KAClE;IACD,EAAE,EAAE;QACF,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,oEAAoE;QAC5E,MAAM,EAAE,gGAAgG;KACzG;CACF,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,OAAuB,EAAE,OAAO,GAAoB,KAAK;IAClF,IAAI,CAAC,OAAO;QAAE,OAAO,WAAW,CAAC;IACjC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,OAAO,KAAK,OAAO;QAAE,OAAO,oBAAoB,MAAM,CAAC,IAAI,mBAAmB,MAAM,CAAC,IAAI;;;qBAG1E,MAAM,CAAC,IAAI;;;;;;;;;;;EAW9B,MAAM,CAAC,MAAM;EACb,MAAM,CAAC,MAAM;;CAEd,CAAC;IACA,OAAO,kBAAkB,MAAM,CAAC,IAAI,qBAAqB,MAAM,CAAC,IAAI;;;mBAGnD,MAAM,CAAC,IAAI;mBACX,MAAM,CAAC,IAAI;mBACX,MAAM,CAAC,IAAI;;;;;;;;;;;;EAY5B,MAAM,CAAC,MAAM;EACb,MAAM,CAAC,MAAM;;CAEd,CAAC;AACF,CAAC","sourcesContent":["type DirectHarness = 'codex' | 'claudeCode' | 'fx';\n\nconst GLOBAL_HELP = `subharness — coordinate external coding agents\n\nUsage:\n subharness list [--cwd <directory>]\n subharness dashboard\n subharness check <target> [--cwd <directory>] [--format text|jsonl]\n subharness check <harness> [--cwd <directory>] [--model <model>] [--effort <effort>] [--format text|jsonl]\n subharness run <target> [options] [--detach] <prompt>\n subharness run <target> [options] [--detach] --prompt <text>\n subharness run <target> [options] [--detach] --prompt-file <path|->\n subharness send <session-id> [--delivery queue|steer|interrupt] [--detach] <prompt>\n subharness send <session-id> [--delivery queue|steer|interrupt] [--detach] --prompt <text>\n subharness send <session-id> [--delivery queue|steer|interrupt] [--detach] --prompt-file <path|->\n subharness wait <task-id> [--after <response-id>]\n subharness status <task-id> [--full]\n subharness queue <session-id>\n subharness cancel <task-id>\n subharness resume <session-id>\n\nDirect harness targets: codex, claude, fx. These bare names are reserved; same-named specialists require repo: or global:.\nSpecialist targets: repo:<name>, global:<name>, or an unambiguous bare name.\nDeclared child targets: subagent:<name>, resolved only from the active managed parent's declarations.\nRun \"subharness run <harness> --help\" or \"subharness check <harness> --help\" for harness-specific options.\nExecution commands accept --format text|jsonl; text is the default.\nOmit --after to wait for the first retained response; supply it to wait for the next response.\nDetach after admission with --detach, then use wait or status; steering cannot be detached.\nDashboard is a terminal-only read-only view and accepts no options.\n--help and --version do not start a coordinator or native harness.\nUse -- to pass a positional prompt beginning with a dash.\nagent is an identical compatibility alias for subharness.\n`;\n\nconst details: Record<DirectHarness, {name: string; access: string; effort: string}> = {\n codex: {\n name: 'codex',\n access: 'Requires an installed Codex executable and eligible configured access.',\n effort: 'Codex accepts a nonempty native effort identifier; model compatibility is checked by the adapter.',\n },\n claudeCode: {\n name: 'claude',\n access: 'Requires an installed Claude Code executable and eligible configured access.',\n effort: 'Claude effort must be low, medium, high, xhigh, or max.',\n },\n fx: {\n name: 'fx',\n access: 'Requires an installed fx executable and configured Gateway access.',\n effort: 'fx accepts a nonempty native effort identifier; model compatibility is checked by the adapter.',\n },\n};\n\nexport function renderHelp(harness?: DirectHarness, command: 'run' | 'check' = 'run'): string {\n if (!harness) return GLOBAL_HELP;\n const target = details[harness];\n if (command === 'check') return `subharness check ${target.name} — check direct ${target.name} startup readiness\n\nUsage:\n subharness check ${target.name} [--cwd <directory>] [--model <model>] [--effort <effort>] [--format text|jsonl]\n\nOptions:\n --cwd <directory> Execution directory for the startup check\n --model <model> Native model identifier\n --effort <effort> Native effort identifier\n --format text|jsonl Output format (text by default)\n\nThe check opens and closes an isolated native session without submitting a turn.\nReadiness covers startup at that moment, not quota, task success, native permissions, or continued availability.\nOmitting --model or --effort uses the verifiable native default for the selected access route.\n${target.effort}\n${target.access}\nNative harness flags are not forwarded; unsupported options are errors.\n`;\n return `subharness run ${target.name} — start a direct ${target.name} session\n\nUsage:\n subharness run ${target.name} [--cwd <directory>] [--model <model>] [--effort <effort>] <prompt>\n subharness run ${target.name} [options] --prompt <text>\n subharness run ${target.name} [options] --prompt-file <path|->\n\nOptions:\n --cwd <directory> Execution directory for the new session\n --model <model> Native model identifier\n --effort <effort> Native effort identifier\n --prompt <text> Prompt text\n --prompt-file <path|-> Read the prompt from a UTF-8 file or stdin\n --detach Return after admission without observing a response\n --format text|jsonl Output format (text by default)\n\nOmitting --model or --effort uses the verifiable native default for the selected access route.\n${target.effort}\n${target.access}\nNative harness flags are not forwarded; unsupported options are errors.\n`;\n}\n"]}
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCnB,CAAC;AAEF,MAAM,OAAO,GAA0E;IACrF,KAAK,EAAE;QACL,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,wEAAwE;QAChF,MAAM,EAAE,mGAAmG;KAC5G;IACD,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,8EAA8E;QACtF,MAAM,EAAE,yDAAyD;KAClE;IACD,EAAE,EAAE;QACF,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,oEAAoE;QAC5E,MAAM,EAAE,gGAAgG;KACzG;CACF,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,OAAuB,EAAE,OAAO,GAAoB,KAAK;IAClF,IAAI,CAAC,OAAO;QAAE,OAAO,WAAW,CAAC;IACjC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,OAAO,KAAK,OAAO;QAAE,OAAO,oBAAoB,MAAM,CAAC,IAAI,mBAAmB,MAAM,CAAC,IAAI;;;qBAG1E,MAAM,CAAC,IAAI;;;;;;;;;;;EAW9B,MAAM,CAAC,MAAM;EACb,MAAM,CAAC,MAAM;;CAEd,CAAC;IACA,OAAO,kBAAkB,MAAM,CAAC,IAAI,qBAAqB,MAAM,CAAC,IAAI;;;mBAGnD,MAAM,CAAC,IAAI;mBACX,MAAM,CAAC,IAAI;mBACX,MAAM,CAAC,IAAI;;;;;;;;;;;;EAY5B,MAAM,CAAC,MAAM;EACb,MAAM,CAAC,MAAM;;CAEd,CAAC;AACF,CAAC","sourcesContent":["type DirectHarness = 'codex' | 'claudeCode' | 'fx';\n\nconst GLOBAL_HELP = `subharness — coordinate external coding agents\n\nUsage:\n subharness list [--cwd <directory>]\n subharness dashboard\n subharness check <target> [--cwd <directory>] [--format text|jsonl]\n subharness check <harness> [--cwd <directory>] [--model <model>] [--effort <effort>] [--format text|jsonl]\n subharness run <target> [options] [--detach] <prompt>\n subharness run <target> [options] [--detach] --prompt <text>\n subharness run <target> [options] [--detach] --prompt-file <path|->\n subharness send <session-id> [--delivery queue|steer|interrupt] [--detach] <prompt>\n subharness send <session-id> [--delivery queue|steer|interrupt] [--detach] --prompt <text>\n subharness send <session-id> [--delivery queue|steer|interrupt] [--detach] --prompt-file <path|->\n subharness wait <task-id> [--after <response-id>]\n subharness status <task-id> [--full]\n subharness queue <session-id>\n subharness cancel <task-id>\n subharness resume <session-id>\n subharness respond <request-id> --content <json>\n subharness respond <request-id> --content-file <path|->\n\nDirect harness targets: codex, claude, fx. These bare names are reserved; same-named specialists require repo: or global:.\nSpecialist targets: repo:<name>, global:<name>, or an unambiguous bare name.\nDeclared child targets: subagent:<name>, resolved only from the active managed parent's declarations.\nRun \"subharness run <harness> --help\" or \"subharness check <harness> --help\" for harness-specific options.\nExecution commands accept --format text|jsonl; text is the default.\nOmit --after to wait for the first retained response; supply it to wait for the next response.\nDetach after admission with --detach, then use wait or status; steering cannot be detached.\nPermission requests return approval_required with a request-specific schema. Inspect the action and scope,\nrespond with one JSON object matching that schema (at most 16 KiB), then wait on the same task.\nEach request offers its own choices; never invent a universal allow/deny value or assume \"always\" is permanent.\nDenial uses an offered rejection choice. Use cancel to stop the task; resume does not answer permissions.\nApproval content files resolve from the caller's working directory; - reads standard input.\nDashboard is a terminal-only read-only view and accepts no options.\n--help and --version do not start a coordinator or native harness.\nUse -- to pass a positional prompt beginning with a dash.\nagent is an identical compatibility alias for subharness.\n`;\n\nconst details: Record<DirectHarness, {name: string; access: string; effort: string}> = {\n codex: {\n name: 'codex',\n access: 'Requires an installed Codex executable and eligible configured access.',\n effort: 'Codex accepts a nonempty native effort identifier; model compatibility is checked by the adapter.',\n },\n claudeCode: {\n name: 'claude',\n access: 'Requires an installed Claude Code executable and eligible configured access.',\n effort: 'Claude effort must be low, medium, high, xhigh, or max.',\n },\n fx: {\n name: 'fx',\n access: 'Requires an installed fx executable and configured Gateway access.',\n effort: 'fx accepts a nonempty native effort identifier; model compatibility is checked by the adapter.',\n },\n};\n\nexport function renderHelp(harness?: DirectHarness, command: 'run' | 'check' = 'run'): string {\n if (!harness) return GLOBAL_HELP;\n const target = details[harness];\n if (command === 'check') return `subharness check ${target.name} — check direct ${target.name} startup readiness\n\nUsage:\n subharness check ${target.name} [--cwd <directory>] [--model <model>] [--effort <effort>] [--format text|jsonl]\n\nOptions:\n --cwd <directory> Execution directory for the startup check\n --model <model> Native model identifier\n --effort <effort> Native effort identifier\n --format text|jsonl Output format (text by default)\n\nThe check opens and closes an isolated native session without submitting a turn.\nReadiness covers startup at that moment, not quota, task success, native permissions, or continued availability.\nOmitting --model or --effort uses the verifiable native default for the selected access route.\n${target.effort}\n${target.access}\nNative harness flags are not forwarded; unsupported options are errors.\n`;\n return `subharness run ${target.name} — start a direct ${target.name} session\n\nUsage:\n subharness run ${target.name} [--cwd <directory>] [--model <model>] [--effort <effort>] <prompt>\n subharness run ${target.name} [options] --prompt <text>\n subharness run ${target.name} [options] --prompt-file <path|->\n\nOptions:\n --cwd <directory> Execution directory for the new session\n --model <model> Native model identifier\n --effort <effort> Native effort identifier\n --prompt <text> Prompt text\n --prompt-file <path|-> Read the prompt from a UTF-8 file or stdin\n --detach Return after admission without observing a response\n --format text|jsonl Output format (text by default)\n\nOmitting --model or --effort uses the verifiable native default for the selected access route.\n${target.effort}\n${target.access}\nNative harness flags are not forwarded; unsupported options are errors.\n`;\n}\n"]}
@@ -3,3 +3,4 @@ export type PromptStream = AsyncIterable<Uint8Array | string> & {
3
3
  isTTY?: boolean;
4
4
  };
5
5
  export declare function readPromptInput(source: string, cwd: string, stdin?: PromptStream): Promise<string>;
6
+ export declare function readApprovalInput(source: string, cwd: string, stdin?: PromptStream): Promise<string>;
package/dist/cli/input.js CHANGED
@@ -3,58 +3,59 @@ import { resolve } from 'node:path';
3
3
  import { AgentError } from '../errors.js';
4
4
  export const MAX_PROMPT_BYTES = 1024 * 1024;
5
5
  const invalid = (message) => { throw new AgentError('INVALID_ARGUMENT', message); };
6
- function decode(chunks, bytes, source) {
7
- if (bytes > MAX_PROMPT_BYTES)
8
- invalid('Prompt exceeds 1 MiB.');
6
+ const tooLarge = (limit) => invalid(`${limit.noun[0].toUpperCase()}${limit.noun.slice(1)} exceeds ${limit.size}.`);
7
+ function decode(chunks, bytes, source, limit) {
8
+ if (bytes > limit.bytes)
9
+ tooLarge(limit);
9
10
  try {
10
11
  return new TextDecoder('utf-8', { fatal: true }).decode(Buffer.concat(chunks, bytes));
11
12
  }
12
13
  catch {
13
- return invalid(`Cannot read UTF-8 prompt ${source}.`);
14
+ return invalid(`Cannot read UTF-8 ${limit.noun} ${source}.`);
14
15
  }
15
16
  }
16
- async function readStdin(stdin) {
17
+ async function readStdin(stdin, limit) {
17
18
  if (stdin.isTTY)
18
- invalid('Cannot read a prompt from interactive terminal stdin.');
19
+ invalid(`Cannot read ${limit.noun} from interactive terminal stdin.`);
19
20
  const chunks = [];
20
21
  let bytes = 0;
21
22
  try {
22
23
  for await (const value of stdin) {
23
24
  const chunk = Buffer.from(value);
24
25
  bytes += chunk.byteLength;
25
- if (bytes > MAX_PROMPT_BYTES)
26
- invalid('Prompt exceeds 1 MiB.');
26
+ if (bytes > limit.bytes)
27
+ tooLarge(limit);
27
28
  chunks.push(chunk);
28
29
  }
29
30
  }
30
31
  catch (error) {
31
32
  if (error instanceof AgentError)
32
33
  throw error;
33
- invalid('Cannot read prompt from stdin.');
34
+ invalid(`Cannot read ${limit.noun} from stdin.`);
34
35
  }
35
- return decode(chunks, bytes, 'from stdin');
36
+ return decode(chunks, bytes, 'from stdin', limit);
36
37
  }
37
- async function readFileBounded(path) {
38
+ async function readFileBounded(path, limit) {
38
39
  let file;
39
40
  try {
40
41
  file = await open(path, 'r');
41
42
  const chunks = [];
42
43
  let bytes = 0;
43
44
  while (true) {
44
- const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, MAX_PROMPT_BYTES + 1 - bytes));
45
+ const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, limit.bytes + 1 - bytes));
45
46
  const { bytesRead } = await file.read(buffer, 0, buffer.byteLength, null);
46
47
  if (!bytesRead)
47
- return decode(chunks, bytes, `file: ${path}`);
48
+ return decode(chunks, bytes, `file: ${path}`, limit);
48
49
  bytes += bytesRead;
49
- if (bytes > MAX_PROMPT_BYTES)
50
- invalid('Prompt exceeds 1 MiB.');
50
+ if (bytes > limit.bytes)
51
+ tooLarge(limit);
51
52
  chunks.push(buffer.subarray(0, bytesRead));
52
53
  }
53
54
  }
54
55
  catch (error) {
55
56
  if (error instanceof AgentError)
56
57
  throw error;
57
- return invalid(`Cannot read prompt file: ${path}`);
58
+ return invalid(`Cannot read ${limit.noun} file: ${path}`);
58
59
  }
59
60
  finally {
60
61
  try {
@@ -64,6 +65,11 @@ async function readFileBounded(path) {
64
65
  }
65
66
  }
66
67
  export function readPromptInput(source, cwd, stdin = process.stdin) {
67
- return source === '-' ? readStdin(stdin) : readFileBounded(resolve(cwd, source));
68
+ const limit = { bytes: MAX_PROMPT_BYTES, noun: 'prompt', size: '1 MiB' };
69
+ return source === '-' ? readStdin(stdin, limit) : readFileBounded(resolve(cwd, source), limit);
70
+ }
71
+ export function readApprovalInput(source, cwd, stdin = process.stdin) {
72
+ const limit = { bytes: 16 * 1024, noun: 'approval content', size: '16 KiB' };
73
+ return source === '-' ? readStdin(stdin, limit) : readFileBounded(resolve(cwd, source), limit);
68
74
  }
69
75
  //# sourceMappingURL=input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/cli/input.ts"],"names":[],"mappings":"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","sourcesContent":["import { open } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport { AgentError } from '../errors.js';\n\nexport const MAX_PROMPT_BYTES = 1024 * 1024;\n\nexport type PromptStream = AsyncIterable<Uint8Array | string> & {isTTY?: boolean};\n\nconst invalid = (message: string): never => { throw new AgentError('INVALID_ARGUMENT', message); };\n\nfunction decode(chunks: Uint8Array[], bytes: number, source: string): string {\n if (bytes > MAX_PROMPT_BYTES) invalid('Prompt exceeds 1 MiB.');\n try {\n return new TextDecoder('utf-8', {fatal: true}).decode(Buffer.concat(chunks, bytes));\n } catch {\n return invalid(`Cannot read UTF-8 prompt ${source}.`);\n }\n}\n\nasync function readStdin(stdin: PromptStream): Promise<string> {\n if (stdin.isTTY) invalid('Cannot read a prompt from interactive terminal stdin.');\n const chunks: Uint8Array[] = [];\n let bytes = 0;\n try {\n for await (const value of stdin) {\n const chunk = Buffer.from(value);\n bytes += chunk.byteLength;\n if (bytes > MAX_PROMPT_BYTES) invalid('Prompt exceeds 1 MiB.');\n chunks.push(chunk);\n }\n } catch (error) {\n if (error instanceof AgentError) throw error;\n invalid('Cannot read prompt from stdin.');\n }\n return decode(chunks, bytes, 'from stdin');\n}\n\nasync function readFileBounded(path: string): Promise<string> {\n let file;\n try {\n file = await open(path, 'r');\n const chunks: Uint8Array[] = [];\n let bytes = 0;\n while (true) {\n const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, MAX_PROMPT_BYTES + 1 - bytes));\n const {bytesRead} = await file.read(buffer, 0, buffer.byteLength, null);\n if (!bytesRead) return decode(chunks, bytes, `file: ${path}`);\n bytes += bytesRead;\n if (bytes > MAX_PROMPT_BYTES) invalid('Prompt exceeds 1 MiB.');\n chunks.push(buffer.subarray(0, bytesRead));\n }\n } catch (error) {\n if (error instanceof AgentError) throw error;\n return invalid(`Cannot read prompt file: ${path}`);\n } finally {\n try { await file?.close(); } catch {}\n }\n}\n\nexport function readPromptInput(source: string, cwd: string, stdin: PromptStream = process.stdin): Promise<string> {\n return source === '-' ? readStdin(stdin) : readFileBounded(resolve(cwd, source));\n}\n"]}
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/cli/input.ts"],"names":[],"mappings":"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","sourcesContent":["import { open } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport { AgentError } from '../errors.js';\n\nexport const MAX_PROMPT_BYTES = 1024 * 1024;\n\nexport type PromptStream = AsyncIterable<Uint8Array | string> & {isTTY?: boolean};\n\nconst invalid = (message: string): never => { throw new AgentError('INVALID_ARGUMENT', message); };\n\ninterface InputLimit { bytes: number; noun: string; size: string }\nconst tooLarge = (limit: InputLimit): never => invalid(`${limit.noun[0]!.toUpperCase()}${limit.noun.slice(1)} exceeds ${limit.size}.`);\n\nfunction decode(chunks: Uint8Array[], bytes: number, source: string, limit: InputLimit): string {\n if (bytes > limit.bytes) tooLarge(limit);\n try {\n return new TextDecoder('utf-8', {fatal: true}).decode(Buffer.concat(chunks, bytes));\n } catch {\n return invalid(`Cannot read UTF-8 ${limit.noun} ${source}.`);\n }\n}\n\nasync function readStdin(stdin: PromptStream, limit: InputLimit): Promise<string> {\n if (stdin.isTTY) invalid(`Cannot read ${limit.noun} from interactive terminal stdin.`);\n const chunks: Uint8Array[] = [];\n let bytes = 0;\n try {\n for await (const value of stdin) {\n const chunk = Buffer.from(value);\n bytes += chunk.byteLength;\n if (bytes > limit.bytes) tooLarge(limit);\n chunks.push(chunk);\n }\n } catch (error) {\n if (error instanceof AgentError) throw error;\n invalid(`Cannot read ${limit.noun} from stdin.`);\n }\n return decode(chunks, bytes, 'from stdin',limit);\n}\n\nasync function readFileBounded(path: string, limit: InputLimit): Promise<string> {\n let file;\n try {\n file = await open(path, 'r');\n const chunks: Uint8Array[] = [];\n let bytes = 0;\n while (true) {\n const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, limit.bytes + 1 - bytes));\n const {bytesRead} = await file.read(buffer, 0, buffer.byteLength, null);\n if (!bytesRead) return decode(chunks, bytes, `file: ${path}`,limit);\n bytes += bytesRead;\n if (bytes > limit.bytes) tooLarge(limit);\n chunks.push(buffer.subarray(0, bytesRead));\n }\n } catch (error) {\n if (error instanceof AgentError) throw error;\n return invalid(`Cannot read ${limit.noun} file: ${path}`);\n } finally {\n try { await file?.close(); } catch {}\n }\n}\n\nexport function readPromptInput(source: string, cwd: string, stdin: PromptStream = process.stdin): Promise<string> {\n const limit = {bytes:MAX_PROMPT_BYTES,noun:'prompt',size:'1 MiB'};\n return source === '-' ? readStdin(stdin,limit) : readFileBounded(resolve(cwd, source),limit);\n}\n\nexport function readApprovalInput(source: string, cwd: string, stdin: PromptStream = process.stdin): Promise<string> {\n const limit = {bytes:16 * 1024,noun:'approval content',size:'16 KiB'};\n return source === '-' ? readStdin(stdin,limit) : readFileBounded(resolve(cwd,source),limit);\n}\n"]}
package/dist/cli/main.js CHANGED
@@ -8,7 +8,7 @@ import { AgentError, errorInfo } from '../errors.js';
8
8
  import { connect, request } from '../runtime/client.js';
9
9
  import { harnessReference } from '../runtime/definition.js';
10
10
  import { checkReadiness } from '../runtime/readiness.js';
11
- const valueOptions = new Set(['cwd', 'prompt', 'prompt-file', 'model', 'effort', 'delivery', 'after']);
11
+ const valueOptions = new Set(['cwd', 'prompt', 'prompt-file', 'content', 'content-file', 'model', 'effort', 'delivery', 'after']);
12
12
  function parseErrorFormat(argv) {
13
13
  for (let index = 1; index < argv.length; index++) {
14
14
  const argument = argv[index];
@@ -1 +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';\nimport { checkReadiness } from '../runtime/readiness.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 = process.argv[2] === 'dashboard' ? 'text' : 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, args.helpCommand)); 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 if (args.command === 'dashboard') {\n const { runDashboard } = await import('./dashboard.js');\n process.exitCode = await runDashboard();\n return;\n }\n const parentToken = process.env.AGENT_PARENT_TOKEN;\n let reference: ExecutionReference | undefined;\n if (args.command === 'list' || args.command === 'run' || args.command === 'check') {\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.command === 'check') && 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.command === 'check') && 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 if (args.command === 'check') {\n await checkReadiness(reference!, args.cwd, process.env);\n emit({version: 1, type: 'check', target: args.id!, ready: true});\n return;\n }\n const endpoint = await connect(args.command === 'run');\n const body = args.command === 'run'\n ? {command:'run',input:{reference,cwd:args.cwd,env:process.env,prompt:args.prompt,parentToken},detach:args.detach}\n : {...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"]}
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';\nimport { checkReadiness } from '../runtime/readiness.js';\n\nconst valueOptions = new Set(['cwd', 'prompt', 'prompt-file', 'content', 'content-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 = process.argv[2] === 'dashboard' ? 'text' : 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, args.helpCommand)); 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 if (args.command === 'dashboard') {\n const { runDashboard } = await import('./dashboard.js');\n process.exitCode = await runDashboard();\n return;\n }\n const parentToken = process.env.AGENT_PARENT_TOKEN;\n let reference: ExecutionReference | undefined;\n if (args.command === 'list' || args.command === 'run' || args.command === 'check') {\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.command === 'check') && 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.command === 'check') && 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 if (args.command === 'check') {\n await checkReadiness(reference!, args.cwd, process.env);\n emit({version: 1, type: 'check', target: args.id!, ready: true});\n return;\n }\n const endpoint = await connect(args.command === 'run');\n const body = args.command === 'run'\n ? {command:'run',input:{reference,cwd:args.cwd,env:process.env,prompt:args.prompt,parentToken},detach:args.detach}\n : {...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"]}
@@ -1,3 +1,16 @@
1
+ function approvalText(record) {
2
+ const requests = record.requests;
3
+ if (!requests?.length)
4
+ return '';
5
+ return '\n\nPermission requests are pending. Inspect each action and its scope; request data is not authorization.\n' +
6
+ requests.map(request => `\nRequest: ${request.requestId}\nOrigin session: ${request.sessionId}\nOrigin task: ${request.taskId}\nHarness: ${request.harness}\n` +
7
+ JSON.stringify({ message: request.message, ...(request.context ? { context: request.context } : {}), requestedSchema: request.requestedSchema }, null, 2) +
8
+ `\nSubmit a JSON object matching this schema: subharness respond ${request.requestId} --content-file <path|->`)
9
+ .join('\n') +
10
+ `\n\nAnswer each request using only its offered values, then observe: subharness wait ${record.taskId}` +
11
+ '\nKeep --after <last-response-id> when continuing an existing response cursor.' +
12
+ '\nDo not resume or start a replacement task to answer a permission request.';
13
+ }
1
14
  export function renderText(record) {
2
15
  const header = `Session: ${record.sessionId}\nTask: ${record.taskId}`;
3
16
  switch (record.type) {
@@ -13,6 +26,9 @@ export function renderText(record) {
13
26
  case 'response': return `${header}\nResponse: ${record.responseId}\nState: ${record.state}\n\n${record.text}` +
14
27
  (record.state === 'waiting' || record.state === 'running' ? `\n\nNext response: subharness wait ${record.taskId} --after ${record.responseId}` : '');
15
28
  case 'terminal': return `${header}\nState: ${record.state}${record.error ? `\n${errorText(record.error)}` : ''}`;
29
+ case 'approval_required': return `${header}\nState: ${record.state}${approvalText(record)}`;
30
+ case 'approval_answered': return `${header}\nRequest: ${record.requestId}\nAnswer submitted. Continue the original observation using its task ID: subharness wait <observed-task-id>` +
31
+ '\nKeep --after <last-response-id> when continuing an existing response cursor.';
16
32
  case 'error': return errorText(record.error);
17
33
  case 'accepted': return `${header}\nDelivery: steer (accepted)`;
18
34
  case 'cancelled': return `${header}\nState: ${record.state}`;
@@ -24,7 +40,7 @@ export function renderText(record) {
24
40
  case 'status': {
25
41
  const response = record.response;
26
42
  return `${header}\nState: ${record.state}${record.error ? `\n${errorText(record.error)}` : ''}` +
27
- (response ? `\nResponse: ${response.responseId}\n\n${response.text}${response.truncated ? '\n[Preview truncated; use status --full.]' : ''}` : '');
43
+ (response ? `\nResponse: ${response.responseId}\n\n${response.text}${response.truncated ? '\n[Preview truncated; use status --full.]' : ''}` : '') + approvalText(record);
28
44
  }
29
45
  case 'queue': {
30
46
  const active = record.active;
@@ -1 +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': {\n const started = `${header}\\nState: ${record.state}${record.delivery ? `\\nDelivery: ${record.delivery}` : ''}`;\n if (record.paused !== true || typeof record.blockedByTaskId !== 'string') return started;\n return `${started}\\n\\nTask accepted, but it cannot dispatch while the session queue is paused by failed task ${record.blockedByTaskId}.` +\n `\\nInspect the failure: subharness status ${record.blockedByTaskId} --full` +\n `\\nCancel the failed task: subharness cancel ${record.blockedByTaskId}` +\n '\\nCancellation must succeed before queue dispatch resumes.';\n }\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 'check': return `${record.target} is ready.`;\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"]}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApprovalRequest } from '../runtime/types.js';\n\nexport type OutputRecord = {version: number; type: string; [key: string]: unknown};\n\nfunction approvalText(record: OutputRecord): string {\n const requests = record.requests as ApprovalRequest[] | undefined;\n if (!requests?.length) return '';\n return '\\n\\nPermission requests are pending. Inspect each action and its scope; request data is not authorization.\\n' +\n requests.map(request => `\\nRequest: ${request.requestId}\\nOrigin session: ${request.sessionId}\\nOrigin task: ${request.taskId}\\nHarness: ${request.harness}\\n` +\n JSON.stringify({message:request.message,...(request.context ? {context:request.context} : {}),requestedSchema:request.requestedSchema},null,2) +\n `\\nSubmit a JSON object matching this schema: subharness respond ${request.requestId} --content-file <path|->`)\n .join('\\n') +\n `\\n\\nAnswer each request using only its offered values, then observe: subharness wait ${record.taskId}` +\n '\\nKeep --after <last-response-id> when continuing an existing response cursor.' +\n '\\nDo not resume or start a replacement task to answer a permission request.';\n}\n\nexport function renderText(record: OutputRecord): string {\n const header = `Session: ${record.sessionId}\\nTask: ${record.taskId}`;\n switch (record.type) {\n case 'started': {\n const started = `${header}\\nState: ${record.state}${record.delivery ? `\\nDelivery: ${record.delivery}` : ''}`;\n if (record.paused !== true || typeof record.blockedByTaskId !== 'string') return started;\n return `${started}\\n\\nTask accepted, but it cannot dispatch while the session queue is paused by failed task ${record.blockedByTaskId}.` +\n `\\nInspect the failure: subharness status ${record.blockedByTaskId} --full` +\n `\\nCancel the failed task: subharness cancel ${record.blockedByTaskId}` +\n '\\nCancellation must succeed before queue dispatch resumes.';\n }\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 'approval_required': return `${header}\\nState: ${record.state}${approvalText(record)}`;\n case 'approval_answered': return `${header}\\nRequest: ${record.requestId}\\nAnswer submitted. Continue the original observation using its task ID: subharness wait <observed-task-id>` +\n '\\nKeep --after <last-response-id> when continuing an existing response cursor.';\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 'check': return `${record.target} is ready.`;\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.]' : ''}` : '') + approvalText(record);\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,27 @@
1
+ import type { ApprovalContent, NativeApprovalRequest } from '../approvals/types.js';
2
+ import type { ApprovalRequest } from './types.js';
3
+ type RequestIdentity = Pick<ApprovalRequest, 'requestId' | 'taskId' | 'sessionId'>;
4
+ /** Retains pending requests and a bounded settlement-ordered outcome history. */
5
+ export declare class ApprovalRegistry {
6
+ private readonly changed;
7
+ private pending;
8
+ private settled;
9
+ constructor(changed: (taskId: string) => void);
10
+ register(taskId: string, sessionId: string, request: NativeApprovalRequest, signal: AbortSignal): Promise<ApprovalContent>;
11
+ request(id: string): RequestIdentity;
12
+ respond(id: string, content: unknown): {
13
+ version: 1;
14
+ type: 'approval_answered';
15
+ requestId: string;
16
+ taskId: string;
17
+ sessionId: string;
18
+ };
19
+ pendingFor(taskId: string): ApprovalRequest[];
20
+ retireTask(taskId: string): void;
21
+ close(): void;
22
+ private retire;
23
+ private retain;
24
+ private validateBoundedContent;
25
+ private receipt;
26
+ }
27
+ export {};