acpx 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +8 -4
  2. package/dist/{cli-BGYGVo3b.js → cli-8dP_TqBp.js} +4 -4
  3. package/dist/{cli-BGYGVo3b.js.map → cli-8dP_TqBp.js.map} +1 -1
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +930 -252
  7. package/dist/cli.js.map +1 -1
  8. package/dist/{client-FzXPdgP7.d.ts → client-C4iJBO0j.d.ts} +30 -3
  9. package/dist/client-C4iJBO0j.d.ts.map +1 -0
  10. package/dist/{flags-D706STfk.js → flags--2oX_ubW.js} +96 -39
  11. package/dist/flags--2oX_ubW.js.map +1 -0
  12. package/dist/{flows-hcjHmU7P.js → flows-e4umXVbY.js} +401 -336
  13. package/dist/flows-e4umXVbY.js.map +1 -0
  14. package/dist/flows.d.ts +21 -1
  15. package/dist/flows.d.ts.map +1 -1
  16. package/dist/flows.js +1 -1
  17. package/dist/{live-checkpoint-B9ctAuqV.js → live-checkpoint-CuFft_Nd.js} +1614 -931
  18. package/dist/live-checkpoint-CuFft_Nd.js.map +1 -0
  19. package/dist/{output-BL9XRWzS.js → output-Di77Yugq.js} +1153 -719
  20. package/dist/output-Di77Yugq.js.map +1 -0
  21. package/dist/runtime.d.ts +30 -2
  22. package/dist/runtime.d.ts.map +1 -1
  23. package/dist/runtime.js +579 -425
  24. package/dist/runtime.js.map +1 -1
  25. package/dist/{session-options-BJyG6zEH.d.ts → session-options-Bh1bIqQ2.d.ts} +14 -1
  26. package/dist/{session-options-BJyG6zEH.d.ts.map → session-options-Bh1bIqQ2.d.ts.map} +1 -1
  27. package/package.json +21 -12
  28. package/skills/acpx/SKILL.md +22 -5
  29. package/dist/client-FzXPdgP7.d.ts.map +0 -1
  30. package/dist/flags-D706STfk.js.map +0 -1
  31. package/dist/flows-hcjHmU7P.js.map +0 -1
  32. package/dist/live-checkpoint-B9ctAuqV.js.map +0 -1
  33. package/dist/output-BL9XRWzS.js.map +0 -1
package/dist/cli.js CHANGED
@@ -1,13 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import { a as runSessionQueueOwner, c as buildQueueOwnerArgOverride, h as __exportAll, l as flushPerfMetricsCapture, n as getTextErrorRemediationHints, p as probeQueueOwnerHealth, t as createOutputFormatter, u as installPerfMetricsCapture } from "./output-BL9XRWzS.js";
3
- import { At as EXIT_CODES, F as findSession, I as findSessionByDirectoryWalk, P as findGitRepositoryRoot, Pt as OUTPUT_FORMATS, St as exitCodeForOutputErrorCode, Tt as normalizeOutputError, bt as normalizeAgentName, ct as PromptInputValidationError, dt as parsePromptSource, mt as InterruptedError, pt as textPrompt, st as normalizeRuntimeSessionId, ut as mergePromptSourceWithText, vt as DEFAULT_AGENT_NAME, yt as listBuiltInAgents } from "./live-checkpoint-B9ctAuqV.js";
4
- import { _ as resolveOutputPolicy, b as loadPermissionPolicySpec, c as parseHistoryLimit, d as parseOutputFormat$1, f as parsePruneBeforeDate, g as resolveGlobalFlags, h as resolveAgentInvocation, i as addSessionOption, l as parseMaxTurns, m as parseTtlSeconds, n as addPromptInputOption, o as parseAllowedTools, p as parseSessionName, r as addSessionNameOption, s as parseDaysOlderThan, t as addGlobalFlags, u as parseNonEmptyValue, v as resolvePermissionMode, y as resolveSessionNameFromFlags } from "./flags-D706STfk.js";
2
+ import { a as runSessionQueueOwner, c as buildQueueOwnerArgOverride, g as __exportAll, h as isProcessAlive, l as flushPerfMetricsCapture, n as getTextErrorRemediationHints, p as probeQueueOwnerHealth, t as createOutputFormatter, u as installPerfMetricsCapture } from "./output-Di77Yugq.js";
3
+ import { $ as defaultSessionEventLog, A as findGitRepositoryRoot, At as EXIT_CODES, I as normalizeName, M as findSessionByDirectoryWalk, P as listSessions, Pt as OUTPUT_FORMATS, Rt as AcpxOperationalError, St as exitCodeForOutputErrorCode, Tt as normalizeOutputError, X as serializeSessionRecordForDisk, Y as parseSessionRecord, Z as normalizeRuntimeSessionId, at as isAcpJsonRpcMessage, bt as normalizeAgentName$1, ct as PromptInputValidationError, dt as parsePromptSource, j as findSession, mt as InterruptedError, nt as sessionEventLockPath, pt as textPrompt, rt as sessionEventSegmentPath, tt as sessionEventActivePath, ut as mergePromptSourceWithText, vt as DEFAULT_AGENT_NAME, yt as listBuiltInAgents, z as writeSessionRecord, zt as AgentSpawnError } from "./live-checkpoint-CuFft_Nd.js";
4
+ import { _ as resolveOutputPolicy, b as loadPermissionPolicySpec, c as parseHistoryLimit, d as parseOutputFormat$1, f as parsePruneBeforeDate, g as resolveGlobalFlags, h as resolveAgentInvocation, i as addSessionOption, l as parseMaxTurns, m as parseTtlSeconds, n as addPromptInputOption, o as parseAllowedTools, p as parseSessionName, r as addSessionNameOption, s as parseDaysOlderThan, t as addGlobalFlags, u as parseNonEmptyValue, v as resolvePermissionMode, y as resolveSessionNameFromFlags } from "./flags--2oX_ubW.js";
5
5
  import { readFileSync, realpathSync } from "node:fs";
6
6
  import { fileURLToPath, pathToFileURL } from "node:url";
7
7
  import path from "node:path";
8
- import { Command, CommanderError, InvalidArgumentError } from "commander";
8
+ import { Command, CommanderError, InvalidArgumentError, Option } from "commander";
9
9
  import fs$1 from "node:fs/promises";
10
10
  import os from "node:os";
11
+ import { randomUUID } from "node:crypto";
12
+ import { ZodError, z } from "zod";
11
13
  //#region src/cli-public.ts
12
14
  function configurePublicCli(options) {
13
15
  const builtInAgents = options.listBuiltInAgents(options.config.agents);
@@ -34,7 +36,7 @@ Examples:
34
36
  acpx codex exec "what does this repo do"
35
37
  acpx codex cancel
36
38
  acpx codex set-mode plan
37
- acpx codex set thought_level high
39
+ acpx codex set model 'gpt-5.2[high]'
38
40
  acpx codex -s backend "fix the API"
39
41
  acpx codex sessions
40
42
  acpx codex sessions new --name backend
@@ -49,9 +51,321 @@ Examples:
49
51
  }
50
52
  //#endregion
51
53
  //#region src/acp/codex-compat.ts
52
- function isCodexInvocation(agentName, agentCommand) {
53
- if (agentName === "codex") return true;
54
- return /\bcodex-acp\b/u.test(agentCommand);
54
+ function isLegacyZedCodexAcpInvocation(agentCommand) {
55
+ return /@zed-industries\/codex-acp\b/u.test(agentCommand);
56
+ }
57
+ //#endregion
58
+ //#region src/session/export.ts
59
+ var SessionExportError = class extends AcpxOperationalError {
60
+ code;
61
+ exitCode = 2;
62
+ constructor(message, code) {
63
+ super(message, {
64
+ outputCode: "USAGE",
65
+ detailCode: code,
66
+ origin: "cli"
67
+ });
68
+ this.code = code;
69
+ }
70
+ };
71
+ function sessionLookupError(message, code) {
72
+ return new SessionExportError(message, code);
73
+ }
74
+ async function loadSessionRecord(sessionLookup) {
75
+ const cwd = path.resolve(sessionLookup.cwd ?? process.cwd());
76
+ const name = normalizeName(sessionLookup.name);
77
+ if (sessionLookup.agentCommand) {
78
+ const active = await findSession({
79
+ agentCommand: sessionLookup.agentCommand,
80
+ cwd,
81
+ name
82
+ });
83
+ if (active) return active;
84
+ return (await listSessions()).find((session) => {
85
+ if (session.agentCommand !== sessionLookup.agentCommand || session.cwd !== cwd) return false;
86
+ if (name == null) return session.name == null;
87
+ return session.name === name;
88
+ });
89
+ }
90
+ const matches = (await listSessions()).filter((session) => {
91
+ if (session.cwd !== cwd) return false;
92
+ if (name == null) return session.name == null;
93
+ return session.name === name;
94
+ });
95
+ if (matches.length > 1) throw sessionLookupError("multiple sessions match export lookup", "ambiguous-session");
96
+ return matches[0];
97
+ }
98
+ function parseEventLockPayload(raw) {
99
+ try {
100
+ const parsed = JSON.parse(raw);
101
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
102
+ const record = parsed;
103
+ return { pid: typeof record.pid === "number" ? record.pid : void 0 };
104
+ } catch {
105
+ return {};
106
+ }
107
+ }
108
+ async function hasLiveEventLock(recordId) {
109
+ try {
110
+ return isProcessAlive(parseEventLockPayload(await fs$1.readFile(sessionEventLockPath(recordId), "utf8")).pid);
111
+ } catch (error) {
112
+ if (error.code === "ENOENT") return false;
113
+ throw error;
114
+ }
115
+ }
116
+ async function isSessionActive(record) {
117
+ if (record.closed) return false;
118
+ return isProcessAlive(record.pid) || await hasLiveEventLock(record.acpxRecordId);
119
+ }
120
+ async function readHistoryFile(filePath) {
121
+ const payload = await fs$1.readFile(filePath, "utf8").catch((error) => {
122
+ if (error.code === "ENOENT") return "";
123
+ throw error;
124
+ });
125
+ const history = [];
126
+ for (const line of payload.split("\n").filter((entry) => entry.trim().length > 0)) try {
127
+ const parsed = JSON.parse(line);
128
+ if (isAcpJsonRpcMessage(parsed)) history.push(parsed);
129
+ } catch {}
130
+ return history;
131
+ }
132
+ async function readSessionHistory(record) {
133
+ const history = [];
134
+ const maxSegments = Number.isInteger(record.eventLog.max_segments) ? record.eventLog.max_segments : 0;
135
+ for (let segment = maxSegments; segment >= 1; segment -= 1) history.push(...await readHistoryFile(sessionEventSegmentPath(record.acpxRecordId, segment)));
136
+ history.push(...await readHistoryFile(sessionEventActivePath(record.acpxRecordId)));
137
+ return history;
138
+ }
139
+ function cwdRelativeToHome(cwd, home) {
140
+ const relative = path.relative(home, cwd);
141
+ if (relative.length === 0) return ".";
142
+ if (relative.length > 0 && !relative.startsWith("..") && !path.isAbsolute(relative)) return relative;
143
+ return cwd;
144
+ }
145
+ function serializeSessionRecordForArchive(record, cwdRelative) {
146
+ const state = serializeSessionRecordForDisk(record);
147
+ state.cwd = cwdRelative;
148
+ if (state.event_log && typeof state.event_log === "object" && !Array.isArray(state.event_log)) state.event_log = {
149
+ ...state.event_log,
150
+ active_path: ".stream.ndjson"
151
+ };
152
+ return state;
153
+ }
154
+ async function exportSession(sessionLookup, outputPath) {
155
+ const record = await loadSessionRecord(sessionLookup);
156
+ if (!record) throw sessionLookupError("session not found", "not-found");
157
+ if (await isSessionActive(record)) throw sessionLookupError("session is currently locked by a running queue owner; close it first with `acpx sessions close`", "session-locked");
158
+ const home = os.homedir();
159
+ const cwdRelative = cwdRelativeToHome(record.cwd, home);
160
+ const exported = {
161
+ format_version: 1,
162
+ exported_at: (/* @__PURE__ */ new Date()).toISOString(),
163
+ exported_by: "acpx",
164
+ session: {
165
+ record_id: record.acpxRecordId,
166
+ name: record.name ?? null,
167
+ agent: record.agentCommand,
168
+ agent_name: normalizeAgentName(sessionLookup.agentName),
169
+ cwd_relative: cwdRelative,
170
+ cwd_original: cwdRelative,
171
+ created_at: record.createdAt,
172
+ updated_at: record.lastUsedAt,
173
+ state: serializeSessionRecordForArchive(record, cwdRelative)
174
+ },
175
+ history: await readSessionHistory(record)
176
+ };
177
+ await fs$1.mkdir(path.dirname(path.resolve(outputPath)), { recursive: true });
178
+ await fs$1.writeFile(outputPath, `${JSON.stringify(exported, null, 2)}\n`, "utf8");
179
+ }
180
+ function normalizeAgentName(agentName) {
181
+ const normalized = agentName?.trim().toLowerCase();
182
+ if (!normalized || normalized.length === 0) return;
183
+ return normalized === "factory-droid" || normalized === "factorydroid" ? "droid" : normalized;
184
+ }
185
+ //#endregion
186
+ //#region src/session/import.ts
187
+ const SUPPORTED_FORMAT_VERSION = 1;
188
+ const exportedSessionSchema = z.object({
189
+ format_version: z.literal(SUPPORTED_FORMAT_VERSION),
190
+ exported_at: z.string(),
191
+ exported_by: z.string(),
192
+ session: z.object({
193
+ record_id: z.string(),
194
+ name: z.string().nullable(),
195
+ agent: z.string(),
196
+ agent_name: z.string().optional(),
197
+ cwd_relative: z.string(),
198
+ cwd_original: z.string().optional(),
199
+ cwd_absolute_original: z.string().optional(),
200
+ created_at: z.string(),
201
+ updated_at: z.string(),
202
+ state: z.unknown()
203
+ }),
204
+ history: z.array(z.unknown())
205
+ });
206
+ var SessionImportError = class extends AcpxOperationalError {
207
+ code;
208
+ exitCode = 2;
209
+ constructor(message, code) {
210
+ super(message, {
211
+ outputCode: "USAGE",
212
+ detailCode: code,
213
+ origin: "cli"
214
+ });
215
+ this.code = code;
216
+ }
217
+ };
218
+ function importError(message, code) {
219
+ return new SessionImportError(message, code);
220
+ }
221
+ function parseArchiveJson(raw) {
222
+ try {
223
+ return JSON.parse(raw);
224
+ } catch (error) {
225
+ throw importError(`Invalid session export archive JSON: ${error instanceof Error ? error.message : String(error)}`, "invalid-archive");
226
+ }
227
+ }
228
+ function assertSupportedFormatVersion(parsed) {
229
+ const record = parsed && typeof parsed === "object" ? parsed : {};
230
+ if (record.format_version !== SUPPORTED_FORMAT_VERSION) throw importError(`Unsupported session export format_version ${String(record.format_version)}; supported version is ${SUPPORTED_FORMAT_VERSION}`, "unsupported-format-version");
231
+ }
232
+ function parseArchive(raw) {
233
+ const parsed = parseArchiveJson(raw);
234
+ assertSupportedFormatVersion(parsed);
235
+ try {
236
+ return exportedSessionSchema.parse(parsed);
237
+ } catch (error) {
238
+ if (error instanceof ZodError) throw importError(`Invalid session export archive: ${error.issues[0]?.message}`, "invalid-archive");
239
+ throw error;
240
+ }
241
+ }
242
+ async function generateRecordId(sessionsDir) {
243
+ for (;;) {
244
+ const recordId = randomUUID();
245
+ const filePath = path.join(sessionsDir, `${encodeURIComponent(recordId)}.json`);
246
+ try {
247
+ await fs$1.access(filePath);
248
+ } catch (error) {
249
+ if (error.code === "ENOENT") return recordId;
250
+ throw error;
251
+ }
252
+ }
253
+ }
254
+ function resolveImportedCwd(cwdRelative, newCwd) {
255
+ if (newCwd) return path.resolve(newCwd);
256
+ if (path.isAbsolute(cwdRelative)) return cwdRelative;
257
+ return path.join(os.homedir(), cwdRelative);
258
+ }
259
+ function resolveImportedName(parsed, requestedName) {
260
+ return requestedName ?? parsed.session.name ?? void 0;
261
+ }
262
+ function assertExpectedAgentCommand(parsed, sourceRecord, options) {
263
+ const expectedAgentCommand = options.expectedAgentCommand;
264
+ if (!expectedAgentCommand) return;
265
+ const expectedAgentName = normalizeAgentIdentity(options.expectedAgentName);
266
+ const archiveAgentName = normalizeAgentIdentity(parsed.session.agent_name);
267
+ const archiveCommandMatches = agentCommandMatchesExpected(parsed.session.agent, expectedAgentCommand, expectedAgentName);
268
+ const stateCommandMatches = agentCommandMatchesExpected(sourceRecord.agentCommand, expectedAgentCommand, expectedAgentName);
269
+ if (archiveCommandMatches && stateCommandMatches && archiveAgentNameMatches({
270
+ archiveAgentName,
271
+ expectedAgentName,
272
+ archiveCommand: parsed.session.agent,
273
+ stateCommand: sourceRecord.agentCommand,
274
+ expectedAgentCommand
275
+ })) {
276
+ sourceRecord.agentCommand = expectedAgentCommand;
277
+ return;
278
+ }
279
+ throw importError("Session export archive agent does not match the requested agent", "agent-mismatch");
280
+ }
281
+ function archiveAgentNameMatches(params) {
282
+ if (params.archiveCommand === params.expectedAgentCommand && params.stateCommand === params.expectedAgentCommand) return true;
283
+ return params.archiveAgentName == null || params.expectedAgentName == null || params.archiveAgentName === params.expectedAgentName;
284
+ }
285
+ function normalizeAgentIdentity(agentName) {
286
+ const normalized = agentName?.trim().toLowerCase();
287
+ if (!normalized || normalized.length === 0) return;
288
+ return normalized === "factory-droid" || normalized === "factorydroid" ? "droid" : normalized;
289
+ }
290
+ function agentCommandMatchesExpected(archivedCommand, expectedAgentCommand, expectedAgentName) {
291
+ if (archivedCommand === expectedAgentCommand) return true;
292
+ return expectedAgentName ? commandLooksLikeBuiltInAgent(archivedCommand, expectedAgentName) : false;
293
+ }
294
+ function commandLooksLikeBuiltInAgent(command, agentName) {
295
+ const normalized = command.trim();
296
+ switch (agentName) {
297
+ case "pi": return /(?:^|\s)pi-acp(?:@|\s|$)/.test(normalized);
298
+ case "codex": return /(?:^|\s)@agentclientprotocol\/codex-acp(?:@|\s|$)/.test(normalized);
299
+ case "claude": return /(?:^|\s)@agentclientprotocol\/claude-agent-acp(?:@|\s|$)/.test(normalized);
300
+ default: return false;
301
+ }
302
+ }
303
+ async function assertDestinationScopeAvailable(record) {
304
+ if (!await findSession({
305
+ agentCommand: record.agentCommand,
306
+ cwd: record.cwd,
307
+ name: record.name
308
+ })) return;
309
+ throw importError("A session already exists for the import destination scope; pass --name or --cwd to import a separate copy", "session-scope-exists");
310
+ }
311
+ async function assertProviderSessionAvailable(record) {
312
+ if (!(await listSessions()).find((session) => session.acpSessionId === record.acpSessionId)) return;
313
+ throw importError("A local session already uses this provider session id; prune or remove the existing record before importing this archive", "session-provider-exists");
314
+ }
315
+ function buildImportedRecord(parsed, sourceRecord, options) {
316
+ const eventLog = {
317
+ ...defaultSessionEventLog(options.newRecordId),
318
+ max_segment_bytes: sourceRecord.eventLog.max_segment_bytes,
319
+ max_segments: sourceRecord.eventLog.max_segments,
320
+ segment_count: parsed.history.length > 0 ? 1 : sourceRecord.eventLog.segment_count
321
+ };
322
+ return {
323
+ ...sourceRecord,
324
+ acpxRecordId: options.newRecordId,
325
+ cwd: options.cwd,
326
+ name: resolveImportedName(parsed, options.name),
327
+ closed: false,
328
+ closedAt: void 0,
329
+ pid: void 0,
330
+ agentStartedAt: void 0,
331
+ lastAgentExitCode: void 0,
332
+ lastAgentExitSignal: void 0,
333
+ lastAgentExitAt: void 0,
334
+ lastAgentDisconnectReason: void 0,
335
+ eventLog,
336
+ importedFrom: {
337
+ recordId: parsed.session.record_id,
338
+ cwdOriginal: parsed.session.cwd_original ?? parsed.session.cwd_relative,
339
+ exportedBy: parsed.exported_by,
340
+ exportedAt: parsed.exported_at
341
+ }
342
+ };
343
+ }
344
+ async function importSession(archivePath, options = {}) {
345
+ const parsed = parseArchive(await fs$1.readFile(archivePath, "utf8"));
346
+ const sourceRecord = parseSessionRecord(parsed.session.state);
347
+ if (!sourceRecord) throw importError("Invalid session export archive: session.state is not a session record", "invalid-archive");
348
+ assertExpectedAgentCommand(parsed, sourceRecord, options);
349
+ const sessionsDir = path.join(os.homedir(), ".acpx", "sessions");
350
+ await fs$1.mkdir(sessionsDir, { recursive: true });
351
+ const cwd = resolveImportedCwd(parsed.session.cwd_relative, options.newCwd);
352
+ const newRecordId = await generateRecordId(sessionsDir);
353
+ const newRecord = buildImportedRecord(parsed, sourceRecord, {
354
+ newRecordId,
355
+ cwd,
356
+ name: options.name
357
+ });
358
+ await assertDestinationScopeAvailable(newRecord);
359
+ await assertProviderSessionAvailable(newRecord);
360
+ await writeSessionRecord(newRecord);
361
+ if (parsed.history.length > 0) {
362
+ const history = parsed.history;
363
+ await fs$1.writeFile(sessionEventActivePath(newRecordId), `${history.map((entry) => JSON.stringify(entry)).join("\n")}\n`, "utf8");
364
+ }
365
+ return {
366
+ record_id: newRecordId,
367
+ cwd
368
+ };
55
369
  }
56
370
  //#endregion
57
371
  //#region src/cli/output/json-output.ts
@@ -72,11 +386,11 @@ let sessionModulePromise;
72
386
  let outputModulePromise;
73
387
  let outputRenderModulePromise;
74
388
  function loadSessionModule() {
75
- sessionModulePromise ??= import("./output-BL9XRWzS.js").then((n) => n.i);
389
+ sessionModulePromise ??= import("./output-Di77Yugq.js").then((n) => n.i);
76
390
  return sessionModulePromise;
77
391
  }
78
392
  function loadOutputModule() {
79
- outputModulePromise ??= import("./output-BL9XRWzS.js").then((n) => n.r);
393
+ outputModulePromise ??= import("./output-Di77Yugq.js").then((n) => n.r);
80
394
  return outputModulePromise;
81
395
  }
82
396
  function loadOutputRenderModule() {
@@ -90,11 +404,7 @@ async function readPromptInputFromStdin() {
90
404
  }
91
405
  async function readPrompt(promptParts, filePath, cwd) {
92
406
  try {
93
- if (filePath) {
94
- const prompt = mergePromptSourceWithText(filePath === "-" ? await readPromptInputFromStdin() : await fs$1.readFile(path.resolve(cwd, filePath), "utf8"), promptParts.join(" "));
95
- if (prompt.length === 0) throw new InvalidArgumentError("Prompt from --file is empty");
96
- return prompt;
97
- }
407
+ if (filePath) return await readPromptFromFile(filePath, cwd, promptParts);
98
408
  const joined = promptParts.join(" ").trim();
99
409
  if (joined.length > 0) return textPrompt(joined);
100
410
  if (process.stdin.isTTY) throw new InvalidArgumentError("Prompt is required (pass as argument, --file, or pipe via stdin)");
@@ -106,13 +416,18 @@ async function readPrompt(promptParts, filePath, cwd) {
106
416
  throw error;
107
417
  }
108
418
  }
419
+ async function readPromptFromFile(filePath, cwd, promptParts) {
420
+ const prompt = mergePromptSourceWithText(filePath === "-" ? await readPromptInputFromStdin() : await fs$1.readFile(path.resolve(cwd, filePath), "utf8"), promptParts.join(" "));
421
+ if (prompt.length === 0) throw new InvalidArgumentError("Prompt from --file is empty");
422
+ return prompt;
423
+ }
109
424
  function applyPermissionExitCode(result) {
110
425
  const stats = result.permissionStats;
111
426
  const deniedOrCancelled = stats.denied + stats.cancelled;
112
427
  if (stats.requested > 0 && stats.approved === 0 && deniedOrCancelled > 0) process.exitCode = EXIT_CODES.PERMISSION_DENIED;
113
428
  }
114
429
  function resolveCompatibleConfigId(agent, configId) {
115
- if (isCodexInvocation(agent.agentName, agent.agentCommand) && configId === "thought_level") return "reasoning_effort";
430
+ if (isLegacyZedCodexAcpInvocation(agent.agentCommand) && configId === "thought_level") return "reasoning_effort";
116
431
  return configId;
117
432
  }
118
433
  function resolveRequestedOutputPolicy(globalFlags) {
@@ -154,6 +469,14 @@ function buildSessionStartOptions(params) {
154
469
  sessionOptions: sessionOptionsFromGlobalFlags(params.globalFlags)
155
470
  };
156
471
  }
472
+ function resolveSessionListFilterCwd(flags, agentCwd) {
473
+ return flags.filterCwd ? path.resolve(agentCwd, flags.filterCwd) : void 0;
474
+ }
475
+ async function printLocalSessionsList(agentCommand, filterCwd, format) {
476
+ const [{ listSessionsForAgent }, { printSessionsByFormat }] = await Promise.all([loadSessionModule(), loadOutputRenderModule()]);
477
+ const sessions = await listSessionsForAgent(agentCommand);
478
+ printSessionsByFormat(filterCwd ? sessions.filter((session) => session.cwd === filterCwd) : sessions, format);
479
+ }
157
480
  function missingScopedSessionMessage(agent, sessionName) {
158
481
  return sessionName ? `No named session "${sessionName}" for cwd ${agent.cwd} and agent ${agent.agentName}` : `No cwd session for ${agent.cwd} and agent ${agent.agentName}`;
159
482
  }
@@ -227,7 +550,7 @@ async function handlePrompt(explicitAgentName, promptParts, flags, command, conf
227
550
  return;
228
551
  }
229
552
  applyPermissionExitCode(result);
230
- if (globalFlags.verbose && result.loadError) process.stderr.write(`[acpx] loadSession failed, started fresh session: ${result.loadError}\n`);
553
+ if (globalFlags.verbose && result.loadError) process.stderr.write(`[acpx] session reconnect failed, started fresh session: ${result.loadError}\n`);
231
554
  }
232
555
  async function handleExec(explicitAgentName, promptParts, flags, command, config) {
233
556
  if (config.disableExec) {
@@ -356,7 +679,7 @@ async function handleSetMode(explicitAgentName, modeId, flags, command, config)
356
679
  timeoutMs: globalFlags.timeout,
357
680
  verbose: globalFlags.verbose
358
681
  });
359
- if (globalFlags.verbose && result.loadError) process.stderr.write(`[acpx] loadSession failed, started fresh session: ${result.loadError}\n`);
682
+ if (globalFlags.verbose && result.loadError) process.stderr.write(`[acpx] session reconnect failed, started fresh session: ${result.loadError}\n`);
360
683
  printSetModeResultByFormat(modeId, result, globalFlags.format);
361
684
  }
362
685
  async function handleSetModel(explicitAgentName, modelId, flags, command, config) {
@@ -374,7 +697,7 @@ async function handleSetModel(explicitAgentName, modelId, flags, command, config
374
697
  timeoutMs: globalFlags.timeout,
375
698
  verbose: globalFlags.verbose
376
699
  });
377
- if (globalFlags.verbose && result.loadError) process.stderr.write(`[acpx] loadSession failed, started fresh session: ${result.loadError}\n`);
700
+ if (globalFlags.verbose && result.loadError) process.stderr.write(`[acpx] session reconnect failed, started fresh session: ${result.loadError}\n`);
378
701
  printSetModelResultByFormat(modelId, result, globalFlags.format);
379
702
  }
380
703
  async function handleSetConfigOption(explicitAgentName, configId, value, flags, command, config) {
@@ -398,14 +721,50 @@ async function handleSetConfigOption(explicitAgentName, configId, value, flags,
398
721
  timeoutMs: globalFlags.timeout,
399
722
  verbose: globalFlags.verbose
400
723
  });
401
- if (globalFlags.verbose && result.loadError) process.stderr.write(`[acpx] loadSession failed, started fresh session: ${result.loadError}\n`);
724
+ if (globalFlags.verbose && result.loadError) process.stderr.write(`[acpx] session reconnect failed, started fresh session: ${result.loadError}\n`);
402
725
  printSetConfigOptionResultByFormat(configId, value, result, globalFlags.format);
403
726
  }
404
- async function handleSessionsList(explicitAgentName, command, config) {
727
+ async function tryListAgentSessions(agent, flags, globalFlags, config) {
728
+ const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);
729
+ const permissionPolicy = await resolvePermissionPolicyFromFlags(globalFlags);
730
+ const { listAgentSessions } = await loadSessionModule();
731
+ try {
732
+ return await listAgentSessions({
733
+ agentCommand: agent.agentCommand,
734
+ cwd: agent.cwd,
735
+ cursor: flags.cursor,
736
+ filterCwd: resolveSessionListFilterCwd(flags, agent.cwd),
737
+ mcpServers: config.mcpServers,
738
+ permissionMode,
739
+ nonInteractivePermissions: globalFlags.nonInteractivePermissions,
740
+ permissionPolicy,
741
+ authCredentials: config.auth,
742
+ authPolicy: globalFlags.authPolicy,
743
+ terminal: globalFlags.terminal,
744
+ timeoutMs: globalFlags.timeout,
745
+ verbose: globalFlags.verbose
746
+ });
747
+ } catch (error) {
748
+ if (error instanceof AgentSpawnError) return "spawn-failed";
749
+ throw error;
750
+ }
751
+ }
752
+ async function handleSessionsList(explicitAgentName, flags, command, config) {
405
753
  const globalFlags = resolveGlobalFlags(command, config);
406
754
  const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
407
- const [{ listSessionsForAgent }, { printSessionsByFormat }] = await Promise.all([loadSessionModule(), loadOutputRenderModule()]);
408
- printSessionsByFormat(await listSessionsForAgent(agent.agentCommand), globalFlags.format);
755
+ const filterCwd = resolveSessionListFilterCwd(flags, agent.cwd);
756
+ if (flags.local) {
757
+ if (flags.cursor) throw new InvalidArgumentError("--cursor cannot be combined with --local");
758
+ await printLocalSessionsList(agent.agentCommand, filterCwd, globalFlags.format);
759
+ return;
760
+ }
761
+ const [result, { printAgentSessionsByFormat }] = await Promise.all([tryListAgentSessions(agent, flags, globalFlags, config), loadOutputRenderModule()]);
762
+ if (!result || result === "spawn-failed") {
763
+ if (result !== "spawn-failed" && (flags.cursor || flags.filterCwd)) throw new Error(`Agent command "${agent.agentCommand}" does not advertise sessionCapabilities.list; cannot use agent-side session/list filters`);
764
+ await printLocalSessionsList(agent.agentCommand, void 0, globalFlags.format);
765
+ return;
766
+ }
767
+ printAgentSessionsByFormat(result, globalFlags.format);
409
768
  }
410
769
  async function handleSessionsClose(explicitAgentName, sessionName, command, config) {
411
770
  const globalFlags = resolveGlobalFlags(command, config);
@@ -470,6 +829,7 @@ function userContentToText(content) {
470
829
  if ("Text" in content) return content.Text;
471
830
  if ("Mention" in content) return content.Mention.content;
472
831
  if ("Image" in content) return content.Image.source || "[image]";
832
+ if ("Audio" in content) return `[audio] ${content.Audio.mime_type || "audio"}`;
473
833
  return "";
474
834
  }
475
835
  function agentContentToText(content) {
@@ -514,24 +874,32 @@ function printSessionDetailsByFormat(record, format) {
514
874
  process.stdout.write(`${record.acpxRecordId}\n`);
515
875
  return;
516
876
  }
517
- process.stdout.write(`id: ${record.acpxRecordId}\n`);
518
- process.stdout.write(`sessionId: ${record.acpSessionId}\n`);
519
- process.stdout.write(`agentSessionId: ${record.agentSessionId ?? "-"}\n`);
520
- process.stdout.write(`agent: ${record.agentCommand}\n`);
521
- process.stdout.write(`cwd: ${record.cwd}\n`);
522
- process.stdout.write(`name: ${record.name ?? "-"}\n`);
523
- process.stdout.write(`created: ${record.createdAt}\n`);
524
- process.stdout.write(`lastActivity: ${record.lastUsedAt}\n`);
525
- process.stdout.write(`lastPrompt: ${record.lastPromptAt ?? "-"}\n`);
526
- process.stdout.write(`closed: ${record.closed ? "yes" : "no"}\n`);
527
- process.stdout.write(`closedAt: ${record.closedAt ?? "-"}\n`);
528
- process.stdout.write(`pid: ${record.pid ?? "-"}\n`);
529
- process.stdout.write(`agentStartedAt: ${record.agentStartedAt ?? "-"}\n`);
530
- process.stdout.write(`lastExitCode: ${record.lastAgentExitCode ?? "-"}\n`);
531
- process.stdout.write(`lastExitSignal: ${record.lastAgentExitSignal ?? "-"}\n`);
532
- process.stdout.write(`lastExitAt: ${record.lastAgentExitAt ?? "-"}\n`);
533
- process.stdout.write(`disconnectReason: ${record.lastAgentDisconnectReason ?? "-"}\n`);
534
- process.stdout.write(`historyEntries: ${conversationHistoryEntries(record).length}\n`);
877
+ for (const line of sessionDetailsLines(record)) process.stdout.write(`${line}\n`);
878
+ }
879
+ function sessionDetailsLines(record) {
880
+ return [
881
+ `id: ${record.acpxRecordId}`,
882
+ `sessionId: ${record.acpSessionId}`,
883
+ `agentSessionId: ${displayValue(record.agentSessionId)}`,
884
+ `agent: ${record.agentCommand}`,
885
+ `cwd: ${record.cwd}`,
886
+ `name: ${displayValue(record.name)}`,
887
+ `created: ${record.createdAt}`,
888
+ `lastActivity: ${record.lastUsedAt}`,
889
+ `lastPrompt: ${displayValue(record.lastPromptAt)}`,
890
+ `closed: ${record.closed ? "yes" : "no"}`,
891
+ `closedAt: ${displayValue(record.closedAt)}`,
892
+ `pid: ${displayValue(record.pid)}`,
893
+ `agentStartedAt: ${displayValue(record.agentStartedAt)}`,
894
+ `lastExitCode: ${displayValue(record.lastAgentExitCode)}`,
895
+ `lastExitSignal: ${displayValue(record.lastAgentExitSignal)}`,
896
+ `lastExitAt: ${displayValue(record.lastAgentExitAt)}`,
897
+ `disconnectReason: ${displayValue(record.lastAgentDisconnectReason)}`,
898
+ `historyEntries: ${conversationHistoryEntries(record).length}`
899
+ ];
900
+ }
901
+ function displayValue(value) {
902
+ return value == null ? "-" : String(value);
535
903
  }
536
904
  function printSessionHistoryByFormat(record, limit, format) {
537
905
  const history = conversationHistoryEntries(record);
@@ -565,6 +933,46 @@ async function handleSessionsHistory(explicitAgentName, sessionName, flags, comm
565
933
  const globalFlags = resolveGlobalFlags(command, config);
566
934
  printSessionHistoryByFormat(await findScopedSessionOrThrow(resolveAgentInvocation(explicitAgentName, globalFlags, config), sessionName), flags.limit, globalFlags.format);
567
935
  }
936
+ async function handleSessionsExport(explicitAgentName, sessionName, flags, command, config) {
937
+ const globalFlags = resolveGlobalFlags(command, config);
938
+ const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
939
+ const cwd = flags.sourceCwd ? path.resolve(agent.cwd, flags.sourceCwd) : agent.cwd;
940
+ await exportSession({
941
+ agentName: globalFlags.agent ? void 0 : agent.agentName,
942
+ agentCommand: agent.agentCommand,
943
+ cwd,
944
+ name: sessionName
945
+ }, flags.output);
946
+ if (emitJsonResult(globalFlags.format, {
947
+ action: "session_exported",
948
+ output: flags.output
949
+ })) return;
950
+ if (globalFlags.format === "quiet") {
951
+ process.stdout.write(`${flags.output}\n`);
952
+ return;
953
+ }
954
+ process.stdout.write(`exported session to ${flags.output}\n`);
955
+ }
956
+ async function handleSessionsImport(explicitAgentName, archivePath, flags, command, config) {
957
+ const globalFlags = resolveGlobalFlags(command, config);
958
+ const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
959
+ const result = await importSession(archivePath, {
960
+ name: flags.name,
961
+ newCwd: flags.destinationCwd ? path.resolve(globalFlags.cwd, flags.destinationCwd) : void 0,
962
+ expectedAgentName: globalFlags.agent ? void 0 : agent.agentName,
963
+ expectedAgentCommand: agent.agentCommand
964
+ });
965
+ if (emitJsonResult(globalFlags.format, {
966
+ action: "session_imported",
967
+ record_id: result.record_id,
968
+ cwd: result.cwd
969
+ })) return;
970
+ if (globalFlags.format === "quiet") {
971
+ process.stdout.write(`${result.record_id}\n`);
972
+ return;
973
+ }
974
+ process.stdout.write(`imported session ${result.record_id} at ${result.cwd}\n`);
975
+ }
568
976
  async function handleSessionsPrune(explicitAgentName, flags, command, config) {
569
977
  const globalFlags = resolveGlobalFlags(command, config);
570
978
  const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
@@ -636,38 +1044,38 @@ function parseMeta(value, path) {
636
1044
  if (!asRecord$1(value)) throw new Error(`Invalid ${path}: expected object or null`);
637
1045
  return value;
638
1046
  }
639
- function parseServer(rawServer, path) {
640
- const serverRecord = asRecord$1(rawServer);
641
- if (!serverRecord) throw new Error(`Invalid ${path}: expected object`);
642
- const name = parseNonEmptyString(serverRecord.name, `${path}.name`);
643
- const _meta = parseMeta(serverRecord._meta, `${path}._meta`);
644
- const rawType = serverRecord.type;
645
- let typeValue;
646
- if (rawType === void 0) typeValue = "stdio";
647
- else {
648
- const parsedType = parseNonEmptyString(rawType, `${path}.type`);
649
- if (parsedType !== "http" && parsedType !== "sse" && parsedType !== "stdio") throw new Error(`Invalid ${path}.type: expected http, sse, or stdio`);
650
- typeValue = parsedType;
651
- }
652
- if (typeValue === "http" || typeValue === "sse") {
653
- const url = parseNonEmptyString(serverRecord.url, `${path}.url`);
654
- const headers = parseHeaders(serverRecord.headers, `${path}.headers`);
655
- return {
656
- type: typeValue,
657
- name,
658
- url,
659
- headers,
660
- _meta
661
- };
662
- }
663
- if (typeValue === "stdio") return {
1047
+ function parseServerType(rawType, path) {
1048
+ if (rawType === void 0) return "stdio";
1049
+ const parsedType = parseNonEmptyString(rawType, `${path}.type`);
1050
+ if (parsedType !== "http" && parsedType !== "sse" && parsedType !== "stdio") throw new Error(`Invalid ${path}.type: expected http, sse, or stdio`);
1051
+ return parsedType;
1052
+ }
1053
+ function parseHttpServer(serverRecord, path, type, name, _meta) {
1054
+ return {
1055
+ type,
1056
+ name,
1057
+ url: parseNonEmptyString(serverRecord.url, `${path}.url`),
1058
+ headers: parseHeaders(serverRecord.headers, `${path}.headers`),
1059
+ _meta
1060
+ };
1061
+ }
1062
+ function parseStdioServer(serverRecord, path, name, _meta) {
1063
+ return {
664
1064
  name,
665
1065
  command: parseNonEmptyString(serverRecord.command, `${path}.command`),
666
1066
  args: parseArgs(serverRecord.args, `${path}.args`),
667
1067
  env: parseEnv(serverRecord.env, `${path}.env`),
668
1068
  _meta
669
1069
  };
670
- throw new Error(`Invalid ${path}.type: expected http, sse, or stdio`);
1070
+ }
1071
+ function parseServer(rawServer, path) {
1072
+ const serverRecord = asRecord$1(rawServer);
1073
+ if (!serverRecord) throw new Error(`Invalid ${path}: expected object`);
1074
+ const name = parseNonEmptyString(serverRecord.name, `${path}.name`);
1075
+ const _meta = parseMeta(serverRecord._meta, `${path}._meta`);
1076
+ const typeValue = parseServerType(serverRecord.type, path);
1077
+ if (typeValue === "http" || typeValue === "sse") return parseHttpServer(serverRecord, path, typeValue, name, _meta);
1078
+ return parseStdioServer(serverRecord, path, name, _meta);
671
1079
  }
672
1080
  function parseMcpServers(value, sourcePath, fieldName = "mcpServers") {
673
1081
  const fieldPath = `${fieldName} in ${sourcePath}`;
@@ -749,7 +1157,7 @@ function parseOutputFormat(value, sourcePath) {
749
1157
  function parseDefaultAgent(value, sourcePath) {
750
1158
  if (value == null) return;
751
1159
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`Invalid config defaultAgent in ${sourcePath}: expected non-empty string`);
752
- return normalizeAgentName(value);
1160
+ return normalizeAgentName$1(value);
753
1161
  }
754
1162
  function parseAgents(value, sourcePath) {
755
1163
  if (value == null) return;
@@ -760,7 +1168,7 @@ function parseAgents(value, sourcePath) {
760
1168
  const command = raw.command;
761
1169
  if (typeof command !== "string" || command.trim().length === 0) throw new Error(`Invalid config agents.${name}.command in ${sourcePath}: expected non-empty string`);
762
1170
  const args = parseAgentArgs(raw.args, name, sourcePath);
763
- parsed[normalizeAgentName(name)] = args.length > 0 ? `${command.trim()} ${args.map(quoteCommandArg).join(" ")}` : command.trim();
1171
+ parsed[normalizeAgentName$1(name)] = args.length > 0 ? `${command.trim()} ${args.map(quoteCommandArg).join(" ")}` : command.trim();
764
1172
  }
765
1173
  return parsed;
766
1174
  }
@@ -828,35 +1236,13 @@ async function loadResolvedConfig(cwd) {
828
1236
  const [globalResult, projectResult] = await Promise.all([readConfigFile(globalPath), readConfigFile(projectPath)]);
829
1237
  const globalConfig = globalResult.config;
830
1238
  const projectConfig = projectResult.config;
831
- const defaultAgent = parseDefaultAgent(projectConfig?.defaultAgent, projectPath) ?? parseDefaultAgent(globalConfig?.defaultAgent, globalPath) ?? "codex";
832
- const defaultPermissions = parsePermissionMode(projectConfig?.defaultPermissions, projectPath) ?? parsePermissionMode(globalConfig?.defaultPermissions, globalPath) ?? DEFAULT_PERMISSION_MODE;
833
- const nonInteractivePermissions = parseNonInteractivePermissionPolicy(projectConfig?.nonInteractivePermissions, projectPath) ?? parseNonInteractivePermissionPolicy(globalConfig?.nonInteractivePermissions, globalPath) ?? DEFAULT_NON_INTERACTIVE_PERMISSION_POLICY;
834
- const authPolicy = parseAuthPolicy(projectConfig?.authPolicy, projectPath) ?? parseAuthPolicy(globalConfig?.authPolicy, globalPath) ?? DEFAULT_AUTH_POLICY;
835
- const ttlMs = parseTtlMs(projectConfig?.ttl, projectPath) ?? parseTtlMs(globalConfig?.ttl, globalPath) ?? DEFAULT_TTL_MS;
836
- const timeoutConfiguredInProject = projectConfig != null && Object.prototype.hasOwnProperty.call(projectConfig, "timeout");
837
- const timeoutConfiguredInGlobal = globalConfig != null && Object.prototype.hasOwnProperty.call(globalConfig, "timeout");
838
- let timeoutMs = DEFAULT_TIMEOUT_MS;
839
- if (timeoutConfiguredInProject) timeoutMs = parseTimeoutMs(projectConfig?.timeout, projectPath);
840
- else if (timeoutConfiguredInGlobal) timeoutMs = parseTimeoutMs(globalConfig?.timeout, globalPath);
841
- const format = parseOutputFormat(projectConfig?.format, projectPath) ?? parseOutputFormat(globalConfig?.format, globalPath) ?? DEFAULT_OUTPUT_FORMAT;
842
- const queueMaxDepth = parseQueueMaxDepth(projectConfig?.queueMaxDepth, projectPath) ?? parseQueueMaxDepth(globalConfig?.queueMaxDepth, globalPath) ?? DEFAULT_QUEUE_MAX_DEPTH;
1239
+ const scalar = resolveScalarConfigValues(projectConfig, projectPath, globalConfig, globalPath);
843
1240
  const agents = mergeAgents(parseAgents(globalConfig?.agents, globalPath), parseAgents(projectConfig?.agents, projectPath));
844
1241
  const auth = mergeAuth(parseAuth(globalConfig?.auth, globalPath), parseAuth(projectConfig?.auth, projectPath));
845
- const mcpServersConfiguredInProject = projectConfig != null && Object.prototype.hasOwnProperty.call(projectConfig, "mcpServers");
846
- const mcpServersConfiguredInGlobal = globalConfig != null && Object.prototype.hasOwnProperty.call(globalConfig, "mcpServers");
847
- let mcpServers = [];
848
- if (mcpServersConfiguredInProject) mcpServers = parseMcpServers(projectConfig?.mcpServers, projectPath);
849
- else if (mcpServersConfiguredInGlobal) mcpServers = parseMcpServers(globalConfig?.mcpServers, globalPath);
850
- const disableExec = parseDisableExec(projectConfig?.disableExec, projectPath) ?? parseDisableExec(globalConfig?.disableExec, globalPath) ?? DEFAULT_DISABLE_EXEC;
1242
+ const mcpServers = resolveMcpServers(projectConfig, projectPath, globalConfig, globalPath);
1243
+ const disableExec = resolveDisableExec(projectConfig, projectPath, globalConfig, globalPath);
851
1244
  return {
852
- defaultAgent,
853
- defaultPermissions,
854
- nonInteractivePermissions,
855
- authPolicy,
856
- ttlMs,
857
- timeoutMs,
858
- queueMaxDepth,
859
- format,
1245
+ ...scalar,
860
1246
  agents,
861
1247
  auth,
862
1248
  disableExec,
@@ -867,6 +1253,55 @@ async function loadResolvedConfig(cwd) {
867
1253
  hasProjectConfig: projectResult.exists
868
1254
  };
869
1255
  }
1256
+ function resolveScalarConfigValues(projectConfig, projectPath, globalConfig, globalPath) {
1257
+ return {
1258
+ defaultAgent: resolveDefaultAgent(projectConfig, projectPath, globalConfig, globalPath),
1259
+ defaultPermissions: resolveDefaultPermissions(projectConfig, projectPath, globalConfig, globalPath),
1260
+ nonInteractivePermissions: resolveNonInteractivePermissions(projectConfig, projectPath, globalConfig, globalPath),
1261
+ authPolicy: resolveAuthPolicy(projectConfig, projectPath, globalConfig, globalPath),
1262
+ ttlMs: resolveTtlMs(projectConfig, projectPath, globalConfig, globalPath),
1263
+ timeoutMs: resolveTimeoutMs(projectConfig, projectPath, globalConfig, globalPath),
1264
+ queueMaxDepth: resolveQueueMaxDepth(projectConfig, projectPath, globalConfig, globalPath),
1265
+ format: resolveFormat(projectConfig, projectPath, globalConfig, globalPath)
1266
+ };
1267
+ }
1268
+ function resolveDefaultAgent(projectConfig, projectPath, globalConfig, globalPath) {
1269
+ return parseDefaultAgent(projectConfig?.defaultAgent, projectPath) ?? parseDefaultAgent(globalConfig?.defaultAgent, globalPath) ?? "codex";
1270
+ }
1271
+ function resolveDefaultPermissions(projectConfig, projectPath, globalConfig, globalPath) {
1272
+ return parsePermissionMode(projectConfig?.defaultPermissions, projectPath) ?? parsePermissionMode(globalConfig?.defaultPermissions, globalPath) ?? DEFAULT_PERMISSION_MODE;
1273
+ }
1274
+ function resolveNonInteractivePermissions(projectConfig, projectPath, globalConfig, globalPath) {
1275
+ return parseNonInteractivePermissionPolicy(projectConfig?.nonInteractivePermissions, projectPath) ?? parseNonInteractivePermissionPolicy(globalConfig?.nonInteractivePermissions, globalPath) ?? DEFAULT_NON_INTERACTIVE_PERMISSION_POLICY;
1276
+ }
1277
+ function resolveAuthPolicy(projectConfig, projectPath, globalConfig, globalPath) {
1278
+ return parseAuthPolicy(projectConfig?.authPolicy, projectPath) ?? parseAuthPolicy(globalConfig?.authPolicy, globalPath) ?? DEFAULT_AUTH_POLICY;
1279
+ }
1280
+ function resolveTtlMs(projectConfig, projectPath, globalConfig, globalPath) {
1281
+ return parseTtlMs(projectConfig?.ttl, projectPath) ?? parseTtlMs(globalConfig?.ttl, globalPath) ?? DEFAULT_TTL_MS;
1282
+ }
1283
+ function resolveQueueMaxDepth(projectConfig, projectPath, globalConfig, globalPath) {
1284
+ return parseQueueMaxDepth(projectConfig?.queueMaxDepth, projectPath) ?? parseQueueMaxDepth(globalConfig?.queueMaxDepth, globalPath) ?? DEFAULT_QUEUE_MAX_DEPTH;
1285
+ }
1286
+ function resolveFormat(projectConfig, projectPath, globalConfig, globalPath) {
1287
+ return parseOutputFormat(projectConfig?.format, projectPath) ?? parseOutputFormat(globalConfig?.format, globalPath) ?? DEFAULT_OUTPUT_FORMAT;
1288
+ }
1289
+ function hasConfigKey(config, key) {
1290
+ return config != null && Object.prototype.hasOwnProperty.call(config, key);
1291
+ }
1292
+ function resolveTimeoutMs(projectConfig, projectPath, globalConfig, globalPath) {
1293
+ if (hasConfigKey(projectConfig, "timeout")) return parseTimeoutMs(projectConfig?.timeout, projectPath);
1294
+ if (hasConfigKey(globalConfig, "timeout")) return parseTimeoutMs(globalConfig?.timeout, globalPath);
1295
+ return DEFAULT_TIMEOUT_MS;
1296
+ }
1297
+ function resolveMcpServers(projectConfig, projectPath, globalConfig, globalPath) {
1298
+ if (hasConfigKey(projectConfig, "mcpServers")) return parseMcpServers(projectConfig?.mcpServers, projectPath);
1299
+ if (hasConfigKey(globalConfig, "mcpServers")) return parseMcpServers(globalConfig?.mcpServers, globalPath);
1300
+ return [];
1301
+ }
1302
+ function resolveDisableExec(projectConfig, projectPath, globalConfig, globalPath) {
1303
+ return parseDisableExec(projectConfig?.disableExec, projectPath) ?? parseDisableExec(globalConfig?.disableExec, globalPath) ?? DEFAULT_DISABLE_EXEC;
1304
+ }
870
1305
  function toConfigDisplay(config) {
871
1306
  const agents = {};
872
1307
  for (const [name, command] of Object.entries(config.agents)) agents[name] = { command };
@@ -970,6 +1405,7 @@ function registerConfigCommand(program, config) {
970
1405
  var render_exports = /* @__PURE__ */ __exportAll({
971
1406
  agentSessionIdPayload: () => agentSessionIdPayload,
972
1407
  formatPromptSessionBannerLine: () => formatPromptSessionBannerLine,
1408
+ printAgentSessionsByFormat: () => printAgentSessionsByFormat,
973
1409
  printClosedSessionByFormat: () => printClosedSessionByFormat,
974
1410
  printCreatedSessionBanner: () => printCreatedSessionBanner,
975
1411
  printEnsuredSessionByFormat: () => printEnsuredSessionByFormat,
@@ -996,10 +1432,7 @@ function printSessionsByFormat(sessions, format) {
996
1432
  return;
997
1433
  }
998
1434
  if (format === "quiet") {
999
- for (const session of sessions) {
1000
- const closedMarker = session.closed ? " [closed]" : "";
1001
- process.stdout.write(`${session.acpxRecordId}${closedMarker}\n`);
1002
- }
1435
+ printQuietSessions(sessions);
1003
1436
  return;
1004
1437
  }
1005
1438
  if (sessions.length === 0) {
@@ -1011,6 +1444,36 @@ function printSessionsByFormat(sessions, format) {
1011
1444
  process.stdout.write(`${session.acpxRecordId}${closedMarker}\t${session.name ?? "-"}\t${session.cwd}\t${session.lastUsedAt}\n`);
1012
1445
  }
1013
1446
  }
1447
+ function printQuietSessions(sessions) {
1448
+ for (const session of sessions) {
1449
+ const closedMarker = session.closed ? " [closed]" : "";
1450
+ process.stdout.write(`${session.acpxRecordId}${closedMarker}\n`);
1451
+ }
1452
+ }
1453
+ function printAgentSessionsByFormat(result, format) {
1454
+ if (format === "json") {
1455
+ process.stdout.write(`${JSON.stringify(result)}\n`);
1456
+ return;
1457
+ }
1458
+ if (format === "quiet") {
1459
+ printQuietAgentSessions(result);
1460
+ return;
1461
+ }
1462
+ printTextAgentSessions(result);
1463
+ }
1464
+ function printQuietAgentSessions(result) {
1465
+ for (const session of result.sessions) process.stdout.write(`${session.sessionId}\n`);
1466
+ }
1467
+ function printTextAgentSessions(result) {
1468
+ if (result.sessions.length === 0) process.stdout.write("No sessions\n");
1469
+ else for (const session of result.sessions) {
1470
+ const title = session.title ?? "-";
1471
+ const updatedAt = session.updatedAt ?? "-";
1472
+ const meta = session._meta ? JSON.stringify(session._meta) : "-";
1473
+ process.stdout.write(`${session.sessionId}\t${title}\t${session.cwd}\t${updatedAt}\t${meta}\n`);
1474
+ }
1475
+ if (result.nextCursor) process.stdout.write(`Next cursor: ${result.nextCursor}\n`);
1476
+ }
1014
1477
  function printClosedSessionByFormat(record, format) {
1015
1478
  if (emitJsonResult(format, {
1016
1479
  action: "session_closed",
@@ -1095,29 +1558,38 @@ function formatBytes(bytes) {
1095
1558
  }
1096
1559
  function printPruneResultByFormat(result, format) {
1097
1560
  const count = result.pruned.length;
1098
- if (emitJsonResult(format, {
1099
- action: result.dryRun ? "sessions_prune_dry_run" : "sessions_pruned",
1100
- dryRun: result.dryRun,
1101
- count,
1102
- bytesFreed: result.bytesFreed,
1103
- pruned: result.pruned.map((r) => r.acpxRecordId)
1104
- })) return;
1561
+ if (emitPruneJsonResult(result, format, count)) return;
1105
1562
  if (format === "quiet") {
1106
- for (const record of result.pruned) process.stdout.write(`${record.acpxRecordId}\n`);
1563
+ printQuietPruneResult(result.pruned);
1107
1564
  return;
1108
1565
  }
1109
1566
  if (count === 0) {
1110
1567
  process.stdout.write(result.dryRun ? "[DRY RUN] No sessions to prune\n" : "No sessions pruned\n");
1111
1568
  return;
1112
1569
  }
1113
- const prefix = result.dryRun ? "[DRY RUN] Would prune" : "Pruned";
1114
- const bytesSuffix = !result.dryRun && result.bytesFreed > 0 ? `, freed ${formatBytes(result.bytesFreed)}` : "";
1115
- process.stdout.write(`${prefix} ${count} session${count === 1 ? "" : "s"}${bytesSuffix}\n`);
1570
+ process.stdout.write(`${formatPruneSummaryLine(result, count)}\n`);
1116
1571
  for (const record of result.pruned) {
1117
1572
  const label = record.name ? ` (${record.name})` : "";
1118
1573
  process.stdout.write(` ${record.acpxRecordId}${label}\t${record.closedAt ?? record.lastUsedAt}\n`);
1119
1574
  }
1120
1575
  }
1576
+ function emitPruneJsonResult(result, format, count) {
1577
+ return emitJsonResult(format, {
1578
+ action: result.dryRun ? "sessions_prune_dry_run" : "sessions_pruned",
1579
+ dryRun: result.dryRun,
1580
+ count,
1581
+ bytesFreed: result.bytesFreed,
1582
+ pruned: result.pruned.map((r) => r.acpxRecordId)
1583
+ });
1584
+ }
1585
+ function printQuietPruneResult(pruned) {
1586
+ for (const record of pruned) process.stdout.write(`${record.acpxRecordId}\n`);
1587
+ }
1588
+ function formatPruneSummaryLine(result, count) {
1589
+ const prefix = result.dryRun ? "[DRY RUN] Would prune" : "Pruned";
1590
+ const bytesSuffix = !result.dryRun && result.bytesFreed > 0 ? `, freed ${formatBytes(result.bytesFreed)}` : "";
1591
+ return `${prefix} ${count} session${count === 1 ? "" : "s"}${bytesSuffix}`;
1592
+ }
1121
1593
  function agentSessionIdPayload(agentSessionId) {
1122
1594
  const normalized = normalizeRuntimeSessionId(agentSessionId);
1123
1595
  if (!normalized) return {};
@@ -1159,63 +1631,115 @@ async function handleStatus(explicitAgentName, flags, command, config) {
1159
1631
  name: resolveSessionNameFromFlags(flags, command)
1160
1632
  });
1161
1633
  if (!record) {
1162
- if (emitJsonResult(globalFlags.format, {
1163
- action: "status_snapshot",
1164
- status: "no-session",
1165
- summary: "no active session"
1166
- })) return;
1167
- if (globalFlags.format === "quiet") {
1168
- process.stdout.write("no-session\n");
1169
- return;
1170
- }
1171
- process.stdout.write("session: -\n");
1172
- process.stdout.write(`agent: ${agent.agentCommand}\n`);
1173
- process.stdout.write("pid: -\n");
1174
- process.stdout.write("status: no-session\n");
1175
- process.stdout.write("model: -\n");
1176
- process.stdout.write("mode: -\n");
1177
- process.stdout.write("uptime: -\n");
1178
- process.stdout.write("lastPromptTime: -\n");
1634
+ printMissingStatus(globalFlags.format, agent.agentCommand);
1635
+ return;
1636
+ }
1637
+ await printSessionStatus(record, globalFlags.format);
1638
+ }
1639
+ function printMissingStatus(format, agentCommand) {
1640
+ if (emitJsonResult(format, {
1641
+ action: "status_snapshot",
1642
+ status: "no-session",
1643
+ summary: "no active session"
1644
+ })) return;
1645
+ if (format === "quiet") {
1646
+ process.stdout.write("no-session\n");
1179
1647
  return;
1180
1648
  }
1649
+ process.stdout.write("session: -\n");
1650
+ process.stdout.write(`agent: ${agentCommand}\n`);
1651
+ process.stdout.write("pid: -\n");
1652
+ process.stdout.write("status: no-session\n");
1653
+ process.stdout.write("model: -\n");
1654
+ process.stdout.write("mode: -\n");
1655
+ process.stdout.write("uptime: -\n");
1656
+ process.stdout.write("lastPromptTime: -\n");
1657
+ }
1658
+ async function printSessionStatus(record, format) {
1181
1659
  const health = await probeQueueOwnerHealth(record.acpxRecordId);
1182
1660
  const statusState = resolveStatusState(record, health);
1183
- const running = statusState === "running";
1184
- const dead = statusState === "dead";
1185
- const payload = {
1661
+ const payload = createStatusPayload(record, health, statusState);
1662
+ const running = isRunningStatus(statusState);
1663
+ const dead = isDeadStatus(statusState);
1664
+ if (emitStatusJson(format, record, payload, statusState, running, dead)) return;
1665
+ if (format === "quiet") {
1666
+ process.stdout.write(`${payload.status}\n`);
1667
+ return;
1668
+ }
1669
+ printTextStatus(payload, dead);
1670
+ }
1671
+ function createStatusPayload(record, health, statusState) {
1672
+ const running = isRunningStatus(statusState);
1673
+ const acpx = statusAcpxFields(record);
1674
+ return {
1186
1675
  sessionId: record.acpxRecordId,
1187
1676
  agentCommand: record.agentCommand,
1188
- pid: health.pid ?? record.pid ?? null,
1677
+ pid: statusPid(health),
1189
1678
  status: statusState,
1679
+ model: acpx.model,
1680
+ mode: acpx.mode,
1681
+ availableModels: acpx.availableModels,
1682
+ uptime: running ? optionalStatusString(formatUptime(record.agentStartedAt)) : null,
1683
+ lastPromptTime: optionalStatusString(record.lastPromptAt),
1684
+ exitCode: running ? null : optionalStatusNumber(record.lastAgentExitCode),
1685
+ signal: running ? null : optionalStatusSignal(record.lastAgentExitSignal),
1686
+ ...agentSessionIdPayload(record.agentSessionId)
1687
+ };
1688
+ }
1689
+ function statusAcpxFields(record) {
1690
+ return {
1190
1691
  model: record.acpx?.current_model_id ?? null,
1191
1692
  mode: record.acpx?.current_mode_id ?? null,
1192
- availableModels: record.acpx?.available_models ?? null,
1193
- uptime: running ? formatUptime(record.agentStartedAt) ?? null : null,
1194
- lastPromptTime: record.lastPromptAt ?? null,
1195
- exitCode: running ? null : record.lastAgentExitCode ?? null,
1196
- signal: running ? null : record.lastAgentExitSignal ?? null,
1197
- ...agentSessionIdPayload(record.agentSessionId)
1693
+ availableModels: record.acpx?.available_models ?? null
1198
1694
  };
1199
- if (emitJsonResult(globalFlags.format, {
1695
+ }
1696
+ function statusPid(health) {
1697
+ if (health.pidAlive) return health.pid ?? null;
1698
+ return null;
1699
+ }
1700
+ function optionalStatusString(value) {
1701
+ return value ?? null;
1702
+ }
1703
+ function optionalStatusNumber(value) {
1704
+ return value ?? null;
1705
+ }
1706
+ function optionalStatusSignal(value) {
1707
+ return value ?? null;
1708
+ }
1709
+ function isRunningStatus(status) {
1710
+ return status === "running";
1711
+ }
1712
+ function isDeadStatus(status) {
1713
+ return status === "dead";
1714
+ }
1715
+ function emitStatusJson(format, record, payload, statusState, running, dead) {
1716
+ return emitJsonResult(format, statusJsonPayload(record, payload, statusState, running, dead));
1717
+ }
1718
+ function statusJsonPayload(record, payload, statusState, running, dead) {
1719
+ const result = {
1200
1720
  action: "status_snapshot",
1201
1721
  status: running ? "alive" : statusState,
1202
- pid: payload.pid ?? void 0,
1203
1722
  summary: statusSummary(statusState),
1204
- model: payload.model ?? void 0,
1205
- mode: payload.mode ?? void 0,
1206
- availableModels: payload.availableModels ?? void 0,
1207
- uptime: payload.uptime ?? void 0,
1208
- lastPromptTime: payload.lastPromptTime ?? void 0,
1209
- exitCode: dead ? payload.exitCode ?? void 0 : void 0,
1210
- signal: dead ? payload.signal ?? void 0 : void 0,
1211
1723
  acpxRecordId: record.acpxRecordId,
1212
1724
  acpxSessionId: record.acpSessionId,
1213
1725
  agentSessionId: record.agentSessionId
1214
- })) return;
1215
- if (globalFlags.format === "quiet") {
1216
- process.stdout.write(`${payload.status}\n`);
1217
- return;
1726
+ };
1727
+ assignDefinedJsonField(result, "pid", payload.pid);
1728
+ assignDefinedJsonField(result, "model", payload.model);
1729
+ assignDefinedJsonField(result, "mode", payload.mode);
1730
+ assignDefinedJsonField(result, "availableModels", payload.availableModels);
1731
+ assignDefinedJsonField(result, "uptime", payload.uptime);
1732
+ assignDefinedJsonField(result, "lastPromptTime", payload.lastPromptTime);
1733
+ if (dead) {
1734
+ assignDefinedJsonField(result, "exitCode", payload.exitCode);
1735
+ assignDefinedJsonField(result, "signal", payload.signal);
1218
1736
  }
1737
+ return result;
1738
+ }
1739
+ function assignDefinedJsonField(target, key, value) {
1740
+ if (value !== null && value !== void 0) target[key] = value;
1741
+ }
1742
+ function printTextStatus(payload, dead) {
1219
1743
  process.stdout.write(`session: ${payload.sessionId}\n`);
1220
1744
  if ("agentSessionId" in payload) process.stdout.write(`agentSessionId: ${payload.agentSessionId}\n`);
1221
1745
  process.stdout.write(`agent: ${payload.agentCommand}\n`);
@@ -1225,10 +1749,11 @@ async function handleStatus(explicitAgentName, flags, command, config) {
1225
1749
  process.stdout.write(`mode: ${payload.mode ?? "-"}\n`);
1226
1750
  process.stdout.write(`uptime: ${payload.uptime ?? "-"}\n`);
1227
1751
  process.stdout.write(`lastPromptTime: ${payload.lastPromptTime ?? "-"}\n`);
1228
- if (dead) {
1229
- process.stdout.write(`exitCode: ${payload.exitCode ?? "-"}\n`);
1230
- process.stdout.write(`signal: ${payload.signal ?? "-"}\n`);
1231
- }
1752
+ if (dead) printDeadStatusDetails(payload);
1753
+ }
1754
+ function printDeadStatusDetails(payload) {
1755
+ process.stdout.write(`exitCode: ${payload.exitCode ?? "-"}\n`);
1756
+ process.stdout.write(`signal: ${payload.signal ?? "-"}\n`);
1232
1757
  }
1233
1758
  function registerStatusCommand(parent, explicitAgentName, config, description) {
1234
1759
  const statusCommand = parent.command("status").description(description);
@@ -1239,13 +1764,27 @@ function registerStatusCommand(parent, explicitAgentName, config, description) {
1239
1764
  }
1240
1765
  //#endregion
1241
1766
  //#region src/cli/command-registration.ts
1767
+ var LocalAttributeOption = class extends Option {
1768
+ localAttributeName;
1769
+ constructor(flags, description, localAttributeName) {
1770
+ super(flags, description);
1771
+ this.localAttributeName = localAttributeName;
1772
+ }
1773
+ attributeName() {
1774
+ return this.localAttributeName;
1775
+ }
1776
+ };
1777
+ function addSessionsListOptions(command) {
1778
+ return command.option("--local", "List local acpx session records instead of agent protocol sessions").option("--cursor <cursor>", "Opaque ACP session/list cursor", (value) => parseNonEmptyValue("Cursor", value)).option("--filter-cwd <dir>", "Filter agent sessions by working directory", (value) => parseNonEmptyValue("Filter cwd", value));
1779
+ }
1242
1780
  function registerSessionsCommand(parent, explicitAgentName, config) {
1243
1781
  const sessionsCommand = parent.command("sessions").description("List, ensure, create, or close sessions for this agent");
1244
- sessionsCommand.action(async function() {
1245
- await handleSessionsList(explicitAgentName, this, config);
1782
+ addSessionsListOptions(sessionsCommand);
1783
+ sessionsCommand.action(async function(flags) {
1784
+ await handleSessionsList(explicitAgentName, flags, this, config);
1246
1785
  });
1247
- sessionsCommand.command("list").description("List sessions").action(async function() {
1248
- await handleSessionsList(explicitAgentName, this, config);
1786
+ addSessionsListOptions(sessionsCommand.command("list")).description("List sessions").action(async function(flags) {
1787
+ await handleSessionsList(explicitAgentName, flags, this, config);
1249
1788
  });
1250
1789
  sessionsCommand.command("new").description("Create a fresh session for current cwd").option("-s, --name <name>", "Session name", parseSessionName).option("--resume-session <id>", "Resume existing ACP session id", (value) => parseNonEmptyValue("Resume session id", value)).action(async function(flags) {
1251
1790
  await handleSessionsNew(explicitAgentName, flags, this, config);
@@ -1265,6 +1804,12 @@ function registerSessionsCommand(parent, explicitAgentName, config) {
1265
1804
  sessionsCommand.command("read").description("Read full session history").argument("[name]", "Session name", parseSessionName).option("--tail <count>", "Show only the last N entries instead of all history", parseHistoryLimit).action(async function(name, flags) {
1266
1805
  await handleSessionsHistory(explicitAgentName, name, { limit: flags.tail ?? 0 }, this, config);
1267
1806
  });
1807
+ sessionsCommand.command("export").description("Export a portable session archive").argument("[name]", "Session name", parseSessionName).requiredOption("--output <path>", "Output archive path", (value) => parseNonEmptyValue("Output path", value)).addOption(new LocalAttributeOption("--cwd <cwd>", "Session cwd to export", "sourceCwd").argParser((value) => parseNonEmptyValue("Session cwd", value))).action(async function(name, flags) {
1808
+ await handleSessionsExport(explicitAgentName, name, flags, this, config);
1809
+ });
1810
+ sessionsCommand.command("import").description("Import a portable session archive").argument("<archive-path>", "Archive path", (value) => parseNonEmptyValue("Archive path", value)).option("--name <name>", "Imported session name", parseSessionName).addOption(new LocalAttributeOption("--cwd <cwd>", "Imported session cwd", "destinationCwd").argParser((value) => parseNonEmptyValue("Imported session cwd", value))).action(async function(archivePath, flags) {
1811
+ await handleSessionsImport(explicitAgentName, archivePath, flags, this, config);
1812
+ });
1268
1813
  sessionsCommand.command("prune").description("Delete closed sessions and free disk space").option("--dry-run", "Preview what would be pruned without deleting anything").option("--before <date>", "Prune sessions closed before this date", parsePruneBeforeDate).option("--older-than <days>", "Prune sessions closed more than N days ago", parseDaysOlderThan).option("--include-history", "Also delete event stream files (.stream.ndjson)").action(async function(flags) {
1269
1814
  await handleSessionsPrune(explicitAgentName, flags, this, config);
1270
1815
  });
@@ -1317,7 +1862,7 @@ function registerAgentCommand(program, agentName, config) {
1317
1862
  }
1318
1863
  function registerFlowCommand(program, config) {
1319
1864
  program.command("flow").description("Run multi-step ACP workflows from flow files").command("run").description("Run a flow file").argument("<file>", "Flow module path").option("--input-json <json>", "Flow input as JSON").option("--input-file <path>", "Read flow input JSON from file").option("--default-agent <name>", "Default agent profile for ACP nodes without profile", (value) => parseNonEmptyValue("Default agent", value)).action(async function(file, flags) {
1320
- const { handleFlowRun } = await import("./cli-BGYGVo3b.js");
1865
+ const { handleFlowRun } = await import("./cli-8dP_TqBp.js");
1321
1866
  await handleFlowRun(file, flags, this, config);
1322
1867
  });
1323
1868
  }
@@ -1349,33 +1894,63 @@ function parseQueueOwnerPayload(raw) {
1349
1894
  sessionId: record.sessionId,
1350
1895
  permissionMode: record.permissionMode
1351
1896
  };
1897
+ assignQueueOwnerTransportOptions(options, record);
1898
+ assignQueueOwnerScalarOptions(options, record);
1899
+ assignQueueOwnerSessionOptions(options, record.sessionOptions);
1900
+ return options;
1901
+ }
1902
+ function assignQueueOwnerTransportOptions(options, record) {
1352
1903
  const parsedMcpServers = parseOptionalMcpServers(record.mcpServers, "queue owner payload");
1353
1904
  if (parsedMcpServers) options.mcpServers = parsedMcpServers;
1354
- if (typeof record.nonInteractivePermissions === "string") options.nonInteractivePermissions = record.nonInteractivePermissions === "deny" || record.nonInteractivePermissions === "fail" ? record.nonInteractivePermissions : void 0;
1355
1905
  if (record.authCredentials && typeof record.authCredentials === "object") {
1356
1906
  const entries = Object.entries(record.authCredentials).filter(([, value]) => typeof value === "string");
1357
1907
  options.authCredentials = Object.fromEntries(entries);
1358
1908
  }
1909
+ }
1910
+ function assignQueueOwnerScalarOptions(options, record) {
1911
+ if (record.nonInteractivePermissions === "deny" || record.nonInteractivePermissions === "fail") options.nonInteractivePermissions = record.nonInteractivePermissions;
1359
1912
  if (record.authPolicy === "skip" || record.authPolicy === "fail") options.authPolicy = record.authPolicy;
1360
- if (typeof record.terminal === "boolean") options.terminal = record.terminal;
1361
- if (typeof record.suppressSdkConsoleErrors === "boolean") options.suppressSdkConsoleErrors = record.suppressSdkConsoleErrors;
1362
- if (typeof record.verbose === "boolean") options.verbose = record.verbose;
1363
- if (typeof record.ttlMs === "number" && Number.isFinite(record.ttlMs)) options.ttlMs = record.ttlMs;
1364
- if (typeof record.maxQueueDepth === "number" && Number.isFinite(record.maxQueueDepth)) options.maxQueueDepth = Math.max(1, Math.round(record.maxQueueDepth));
1365
- if (typeof record.promptRetries === "number" && Number.isFinite(record.promptRetries)) options.promptRetries = Math.max(0, Math.round(record.promptRetries));
1366
- const sessionOpts = asRecord(record.sessionOptions);
1367
- if (sessionOpts) {
1368
- options.sessionOptions = {};
1369
- if (typeof sessionOpts.model === "string" && sessionOpts.model.trim().length > 0) options.sessionOptions.model = sessionOpts.model;
1370
- if (Array.isArray(sessionOpts.allowedTools)) options.sessionOptions.allowedTools = sessionOpts.allowedTools.filter((tool) => typeof tool === "string");
1371
- if (typeof sessionOpts.maxTurns === "number" && Number.isFinite(sessionOpts.maxTurns)) options.sessionOptions.maxTurns = Math.max(1, Math.round(sessionOpts.maxTurns));
1372
- if (typeof sessionOpts.systemPrompt === "string") options.sessionOptions.systemPrompt = sessionOpts.systemPrompt;
1373
- else {
1374
- const systemPrompt = asRecord(sessionOpts.systemPrompt);
1375
- if (typeof systemPrompt?.append === "string") options.sessionOptions.systemPrompt = { append: systemPrompt.append };
1376
- }
1913
+ assignBooleanOption(options, "terminal", record.terminal);
1914
+ assignBooleanOption(options, "suppressSdkConsoleErrors", record.suppressSdkConsoleErrors);
1915
+ assignBooleanOption(options, "verbose", record.verbose);
1916
+ assignFiniteNumberOption(options, "ttlMs", record.ttlMs);
1917
+ assignRoundedNumberOption(options, "maxQueueDepth", record.maxQueueDepth, 1);
1918
+ assignRoundedNumberOption(options, "promptRetries", record.promptRetries, 0);
1919
+ }
1920
+ function assignBooleanOption(options, key, value) {
1921
+ if (typeof value === "boolean") options[key] = value;
1922
+ }
1923
+ function assignFiniteNumberOption(options, key, value) {
1924
+ if (typeof value === "number" && Number.isFinite(value)) options[key] = value;
1925
+ }
1926
+ function assignRoundedNumberOption(options, key, value, min) {
1927
+ if (typeof value === "number" && Number.isFinite(value)) options[key] = Math.max(min, Math.round(value));
1928
+ }
1929
+ function assignQueueOwnerSessionOptions(options, rawSessionOptions) {
1930
+ const sessionOpts = asRecord(rawSessionOptions);
1931
+ if (!sessionOpts) return;
1932
+ options.sessionOptions = {};
1933
+ assignSessionModel(options.sessionOptions, sessionOpts.model);
1934
+ assignSessionAllowedTools(options.sessionOptions, sessionOpts.allowedTools);
1935
+ assignSessionMaxTurns(options.sessionOptions, sessionOpts.maxTurns);
1936
+ assignSessionSystemPrompt(options.sessionOptions, sessionOpts.systemPrompt);
1937
+ }
1938
+ function assignSessionModel(options, value) {
1939
+ if (typeof value === "string" && value.trim().length > 0) options.model = value;
1940
+ }
1941
+ function assignSessionAllowedTools(options, value) {
1942
+ if (Array.isArray(value)) options.allowedTools = value.filter((tool) => typeof tool === "string");
1943
+ }
1944
+ function assignSessionMaxTurns(options, value) {
1945
+ if (typeof value === "number" && Number.isFinite(value)) options.maxTurns = Math.max(1, Math.round(value));
1946
+ }
1947
+ function assignSessionSystemPrompt(options, value) {
1948
+ if (typeof value === "string") {
1949
+ options.systemPrompt = value;
1950
+ return;
1377
1951
  }
1378
- return options;
1952
+ const systemPrompt = asRecord(value);
1953
+ if (typeof systemPrompt?.append === "string") options.systemPrompt = { append: systemPrompt.append };
1379
1954
  }
1380
1955
  async function runQueueOwnerFromEnv(env) {
1381
1956
  const payload = env.ACPX_QUEUE_OWNER_PAYLOAD;
@@ -1410,13 +1985,16 @@ function resolveVersionFromAncestors(startDir) {
1410
1985
  }
1411
1986
  }
1412
1987
  function resolveAcpxVersion(params) {
1413
- const env = params?.env ?? process.env;
1414
- const envPackageName = parseVersion(env.npm_package_name);
1415
- const envVersion = parseVersion(env.npm_package_version);
1416
- if (envPackageName === "acpx" && envVersion) return envVersion;
1988
+ const envVersion = resolvePackageEnvVersion(params?.env ?? process.env);
1989
+ if (envVersion) return envVersion;
1417
1990
  if (params?.packageJsonPath) return readPackageVersion(params.packageJsonPath) ?? UNKNOWN_VERSION;
1418
1991
  return resolveVersionFromAncestors(MODULE_DIR) ?? UNKNOWN_VERSION;
1419
1992
  }
1993
+ function resolvePackageEnvVersion(env) {
1994
+ const envPackageName = parseVersion(env.npm_package_name);
1995
+ const envVersion = parseVersion(env.npm_package_version);
1996
+ return envPackageName === "acpx" ? envVersion : null;
1997
+ }
1420
1998
  function getAcpxVersion() {
1421
1999
  if (cachedVersion) return cachedVersion;
1422
2000
  cachedVersion = resolveAcpxVersion();
@@ -1436,6 +2014,36 @@ const TOP_LEVEL_VERBS = new Set([
1436
2014
  "config",
1437
2015
  "help"
1438
2016
  ]);
2017
+ const TOP_LEVEL_VERSION_VALUE_FLAG_VALUES = [
2018
+ "--agent",
2019
+ "--cwd",
2020
+ "--auth-policy",
2021
+ "--non-interactive-permissions",
2022
+ "--permission-policy",
2023
+ "--policy",
2024
+ "--format",
2025
+ "--model",
2026
+ "--allowed-tools",
2027
+ "--max-turns",
2028
+ "--system-prompt",
2029
+ "--append-system-prompt",
2030
+ "--prompt-retries",
2031
+ "--timeout",
2032
+ "--ttl"
2033
+ ];
2034
+ const TOP_LEVEL_VERSION_VALUE_FLAGS = new Set(TOP_LEVEL_VERSION_VALUE_FLAG_VALUES);
2035
+ const TOP_LEVEL_VERSION_BOOLEAN_FLAGS = new Set([
2036
+ "--approve-all",
2037
+ "--approve-reads",
2038
+ "--deny-all",
2039
+ "--suppress-reads",
2040
+ "--json-strict",
2041
+ "--no-terminal",
2042
+ "--verbose"
2043
+ ]);
2044
+ const AGENT_SCAN_VALUE_FLAG_VALUES = [...TOP_LEVEL_VERSION_VALUE_FLAG_VALUES, "--file"];
2045
+ const AGENT_SCAN_VALUE_FLAGS = new Set(AGENT_SCAN_VALUE_FLAG_VALUES);
2046
+ const AGENT_SCAN_BOOLEAN_FLAGS = new Set(TOP_LEVEL_VERSION_BOOLEAN_FLAGS);
1439
2047
  let skillflagModulePromise;
1440
2048
  function loadSkillflagModule() {
1441
2049
  skillflagModulePromise ??= import("skillflag");
@@ -1444,31 +2052,48 @@ function loadSkillflagModule() {
1444
2052
  function shouldMaybeHandleSkillflag(argv) {
1445
2053
  return argv.some((token) => token === "--skill" || token.startsWith("--skill="));
1446
2054
  }
2055
+ function matchesLongFlagValue(token, flags) {
2056
+ for (const flag of flags) if (token.startsWith(`${flag}=`)) return true;
2057
+ return false;
2058
+ }
2059
+ function classifyAgentTokenFlag(token) {
2060
+ if (token === "--agent" || token.startsWith("--agent=")) return "agent-value";
2061
+ if (AGENT_SCAN_VALUE_FLAGS.has(token)) return "skip-next";
2062
+ if (AGENT_SCAN_BOOLEAN_FLAGS.has(token) || matchesLongFlagValue(token, AGENT_SCAN_VALUE_FLAGS) || token.startsWith("--json-strict=")) return "skip";
2063
+ return "unknown";
2064
+ }
2065
+ function scanAgentTokenStep(token, hasAgentOverride) {
2066
+ if (token === "--") return {
2067
+ result: { hasAgentOverride },
2068
+ indexDelta: 0
2069
+ };
2070
+ if (!token.startsWith("-") || token === "-") return {
2071
+ result: {
2072
+ token,
2073
+ hasAgentOverride
2074
+ },
2075
+ indexDelta: 0
2076
+ };
2077
+ const flagScan = classifyAgentTokenFlag(token);
2078
+ if (flagScan === "agent-value") return {
2079
+ indexDelta: token === "--agent" ? 1 : 0,
2080
+ hasAgentOverride: true
2081
+ };
2082
+ if (flagScan === "skip-next") return { indexDelta: 1 };
2083
+ if (flagScan === "skip") return { indexDelta: 0 };
2084
+ return {
2085
+ result: { hasAgentOverride },
2086
+ indexDelta: 0
2087
+ };
2088
+ }
1447
2089
  function detectAgentToken(argv) {
1448
2090
  let hasAgentOverride = false;
1449
2091
  for (let index = 0; index < argv.length; index += 1) {
1450
2092
  const token = argv[index];
1451
- if (token === "--") break;
1452
- if (!token.startsWith("-") || token === "-") return {
1453
- token,
1454
- hasAgentOverride
1455
- };
1456
- if (token === "--agent") {
1457
- hasAgentOverride = true;
1458
- index += 1;
1459
- continue;
1460
- }
1461
- if (token.startsWith("--agent=")) {
1462
- hasAgentOverride = true;
1463
- continue;
1464
- }
1465
- if (token === "--cwd" || token === "--auth-policy" || token === "--non-interactive-permissions" || token === "--permission-policy" || token === "--policy" || token === "--format" || token === "--model" || token === "--allowed-tools" || token === "--max-turns" || token === "--timeout" || token === "--ttl" || token === "--file") {
1466
- index += 1;
1467
- continue;
1468
- }
1469
- if (token.startsWith("--cwd=") || token.startsWith("--auth-policy=") || token.startsWith("--non-interactive-permissions=") || token.startsWith("--permission-policy=") || token.startsWith("--policy=") || token.startsWith("--format=") || token.startsWith("--model=") || token.startsWith("--allowed-tools=") || token.startsWith("--max-turns=") || token.startsWith("--json-strict=") || token.startsWith("--timeout=") || token.startsWith("--ttl=") || token.startsWith("--file=")) continue;
1470
- if (token === "--approve-all" || token === "--approve-reads" || token === "--deny-all" || token === "--json-strict" || token === "--verbose" || token === "--suppress-reads") continue;
1471
- return { hasAgentOverride };
2093
+ const step = scanAgentTokenStep(token, hasAgentOverride);
2094
+ if (step.result) return step.result;
2095
+ if (step.hasAgentOverride) hasAgentOverride = true;
2096
+ index += step.indexDelta;
1472
2097
  }
1473
2098
  return { hasAgentOverride };
1474
2099
  }
@@ -1494,24 +2119,52 @@ function detectRequestedOutputFormat(argv, fallback) {
1494
2119
  for (let index = 0; index < argv.length; index += 1) {
1495
2120
  const token = argv[index];
1496
2121
  if (token === "--") break;
1497
- if (token === "--json-strict" || token.startsWith("--json-strict=")) return "json";
1498
- if (token === "--format") {
1499
- const raw = argv[index + 1];
1500
- if (raw && OUTPUT_FORMATS.includes(raw)) detectedFormat = raw;
1501
- continue;
1502
- }
1503
- if (token.startsWith("--format=")) {
1504
- const raw = token.slice(9).trim();
1505
- if (OUTPUT_FORMATS.includes(raw)) detectedFormat = raw;
1506
- }
2122
+ if (isJsonStrictToken(token)) return "json";
2123
+ const format = readFormatFlagValue(token, argv[index + 1]);
2124
+ if (format) detectedFormat = format;
1507
2125
  }
1508
2126
  return detectedFormat;
1509
2127
  }
2128
+ function readFormatFlagValue(token, nextToken) {
2129
+ const raw = token === "--format" ? nextToken : readInlineFlagValue(token, "--format");
2130
+ return isOutputFormat(raw) ? raw : void 0;
2131
+ }
2132
+ function readInlineFlagValue(token, flag) {
2133
+ if (!token.startsWith(`${flag}=`)) return;
2134
+ return token.slice(flag.length + 1).trim();
2135
+ }
2136
+ function isOutputFormat(value) {
2137
+ return typeof value === "string" && OUTPUT_FORMATS.includes(value);
2138
+ }
2139
+ function isJsonStrictToken(token) {
2140
+ return token === "--json-strict" || token.startsWith("--json-strict=");
2141
+ }
1510
2142
  function detectJsonStrict(argv) {
1511
2143
  for (let index = 0; index < argv.length; index += 1) {
1512
2144
  const token = argv[index];
1513
2145
  if (token === "--") break;
1514
- if (token === "--json-strict" || token.startsWith("--json-strict=")) return true;
2146
+ if (isJsonStrictToken(token)) return true;
2147
+ }
2148
+ return false;
2149
+ }
2150
+ function shouldSkipTopLevelVersionToken(token) {
2151
+ return matchesLongFlagValue(token, TOP_LEVEL_VERSION_VALUE_FLAG_VALUES) || TOP_LEVEL_VERSION_BOOLEAN_FLAGS.has(token);
2152
+ }
2153
+ function topLevelVersionTokenDecision(token) {
2154
+ if (token === "--version" || token === "-V") return "version";
2155
+ if (!token.startsWith("-") || token === "-") return "stop";
2156
+ if (TOP_LEVEL_VERSION_VALUE_FLAGS.has(token)) return "skip-next";
2157
+ if (shouldSkipTopLevelVersionToken(token)) return "skip";
2158
+ return "stop";
2159
+ }
2160
+ function isTopLevelVersionRequest(argv) {
2161
+ for (let index = 0; index < argv.length; index += 1) {
2162
+ const token = argv[index];
2163
+ if (token === "--") return false;
2164
+ const decision = topLevelVersionTokenDecision(token);
2165
+ if (decision === "version") return true;
2166
+ if (decision === "stop") return false;
2167
+ if (decision === "skip-next") index += 1;
1515
2168
  }
1516
2169
  return false;
1517
2170
  }
@@ -1541,43 +2194,74 @@ async function emitRequestedError(error, normalized, outputPolicy) {
1541
2194
  async function runWithOutputPolicy(_outputPolicy, run) {
1542
2195
  return await run();
1543
2196
  }
1544
- async function main(argv = process.argv) {
2197
+ async function handleQueueOwnerCommand(argv) {
1545
2198
  installPerfMetricsCapture({
1546
2199
  argv: argv.slice(2),
1547
2200
  role: argv[2] === "__queue-owner" ? "queue_owner" : "cli"
1548
2201
  });
1549
- if (argv.includes("--version") || argv.includes("-V")) {
1550
- process.stdout.write(`${getAcpxVersion()}\n`);
1551
- return;
1552
- }
1553
- if (argv[2] === "__queue-owner") try {
2202
+ if (argv[2] !== "__queue-owner") return false;
2203
+ try {
1554
2204
  await runQueueOwnerFromEnv(process.env);
1555
- return;
2205
+ return true;
1556
2206
  } catch (error) {
1557
2207
  const message = error instanceof Error ? error.message : String(error);
1558
2208
  process.stderr.write(`[acpx] queue owner failed: ${message}\n`);
1559
2209
  process.exit(EXIT_CODES.ERROR);
2210
+ return true;
1560
2211
  }
1561
- if (shouldMaybeHandleSkillflag(argv)) {
1562
- const { findSkillsRoot, maybeHandleSkillflag } = await loadSkillflagModule();
1563
- await maybeHandleSkillflag(argv, {
1564
- skillsRoot: findSkillsRoot(import.meta.url),
1565
- includeBundledSkill: false
2212
+ }
2213
+ async function maybeHandleSkillflag(argv) {
2214
+ if (!shouldMaybeHandleSkillflag(argv)) return;
2215
+ const { findSkillsRoot, maybeHandleSkillflag } = await loadSkillflagModule();
2216
+ await maybeHandleSkillflag(argv, {
2217
+ skillsRoot: findSkillsRoot(import.meta.url),
2218
+ includeBundledSkill: false
2219
+ });
2220
+ }
2221
+ function createProgram(requestedJsonStrict) {
2222
+ const program = new Command();
2223
+ program.name("acpx").description("Headless CLI client for the Agent Client Protocol").version(getAcpxVersion()).enablePositionalOptions().showHelpAfterError();
2224
+ if (requestedJsonStrict) program.configureOutput({
2225
+ writeOut: () => {},
2226
+ writeErr: () => {}
2227
+ });
2228
+ return program;
2229
+ }
2230
+ async function handleProgramParseError(error, requestedOutputPolicy) {
2231
+ if (error instanceof CommanderError) {
2232
+ if (error.code === "commander.helpDisplayed" || error.code === "commander.version") process.exit(EXIT_CODES.SUCCESS);
2233
+ const normalized = normalizeOutputError(error, {
2234
+ defaultCode: "USAGE",
2235
+ origin: "cli"
1566
2236
  });
2237
+ await emitRequestedError(error, normalized, requestedOutputPolicy);
2238
+ process.exit(exitCodeForOutputErrorCode(normalized.code));
2239
+ }
2240
+ if (error instanceof InterruptedError) process.exit(EXIT_CODES.INTERRUPTED);
2241
+ const normalized = normalizeOutputError(error, { origin: "cli" });
2242
+ await emitRequestedError(error, normalized, requestedOutputPolicy);
2243
+ process.exit(exitCodeForOutputErrorCode(normalized.code));
2244
+ }
2245
+ async function main(argv = process.argv) {
2246
+ const rawArgs = normalizeLifecycleScriptArgs(argv.slice(2));
2247
+ const normalizedArgv = [
2248
+ argv[0] ?? "node",
2249
+ argv[1] ?? "acpx",
2250
+ ...rawArgs
2251
+ ];
2252
+ if (await handleQueueOwnerCommand(argv)) return;
2253
+ if (isTopLevelVersionRequest(rawArgs)) {
2254
+ process.stdout.write(`${getAcpxVersion()}\n`);
2255
+ return;
1567
2256
  }
1568
- const rawArgs = argv.slice(2);
2257
+ await maybeHandleSkillflag(normalizedArgv);
1569
2258
  const config = await loadResolvedConfig(detectInitialCwd(rawArgs));
1570
2259
  const requestedJsonStrict = detectJsonStrict(rawArgs);
1571
2260
  const requestedOutputPolicy = {
1572
2261
  ...resolveOutputPolicy(detectRequestedOutputFormat(rawArgs, config.format), requestedJsonStrict),
1573
2262
  suppressReads: rawArgs.some((token) => token === "--suppress-reads")
1574
2263
  };
1575
- const program = new Command();
1576
- program.name("acpx").description("Headless CLI client for the Agent Client Protocol").version(getAcpxVersion()).enablePositionalOptions().showHelpAfterError();
1577
- if (requestedJsonStrict) program.configureOutput({
1578
- writeOut: () => {},
1579
- writeErr: () => {}
1580
- });
2264
+ const program = createProgram(requestedJsonStrict);
1581
2265
  addGlobalFlags(program);
1582
2266
  configurePublicCli({
1583
2267
  program,
@@ -1599,27 +2283,19 @@ async function main(argv = process.argv) {
1599
2283
  try {
1600
2284
  await runWithOutputPolicy(requestedOutputPolicy, async () => {
1601
2285
  try {
1602
- await program.parseAsync(argv);
2286
+ await program.parseAsync(normalizedArgv);
1603
2287
  } catch (error) {
1604
- if (error instanceof CommanderError) {
1605
- if (error.code === "commander.helpDisplayed" || error.code === "commander.version") process.exit(EXIT_CODES.SUCCESS);
1606
- const normalized = normalizeOutputError(error, {
1607
- defaultCode: "USAGE",
1608
- origin: "cli"
1609
- });
1610
- await emitRequestedError(error, normalized, requestedOutputPolicy);
1611
- process.exit(exitCodeForOutputErrorCode(normalized.code));
1612
- }
1613
- if (error instanceof InterruptedError) process.exit(EXIT_CODES.INTERRUPTED);
1614
- const normalized = normalizeOutputError(error, { origin: "cli" });
1615
- await emitRequestedError(error, normalized, requestedOutputPolicy);
1616
- process.exit(exitCodeForOutputErrorCode(normalized.code));
2288
+ await handleProgramParseError(error, requestedOutputPolicy);
1617
2289
  }
1618
2290
  });
1619
2291
  } finally {
1620
2292
  flushPerfMetricsCapture();
1621
2293
  }
1622
2294
  }
2295
+ function normalizeLifecycleScriptArgs(rawArgs) {
2296
+ if (rawArgs[0] === "--" && (process.env.npm_lifecycle_event || process.env.npm_lifecycle_script)) return rawArgs.slice(1);
2297
+ return rawArgs;
2298
+ }
1623
2299
  //#endregion
1624
2300
  //#region src/cli.ts
1625
2301
  function installBrokenPipeHandler(stream) {
@@ -1628,10 +2304,6 @@ function installBrokenPipeHandler(stream) {
1628
2304
  throw error;
1629
2305
  });
1630
2306
  }
1631
- installBrokenPipeHandler(process.stdout);
1632
- installBrokenPipeHandler(process.stderr);
1633
- const queueOwnerArgOverride = buildQueueOwnerArgOverride(fileURLToPath(import.meta.url));
1634
- if (queueOwnerArgOverride) process.env.ACPX_QUEUE_OWNER_ARGS ??= queueOwnerArgOverride;
1635
2307
  function isCliEntrypoint(argv) {
1636
2308
  const entry = argv[1];
1637
2309
  if (!entry) return false;
@@ -1642,7 +2314,13 @@ function isCliEntrypoint(argv) {
1642
2314
  return false;
1643
2315
  }
1644
2316
  }
1645
- if (isCliEntrypoint(process.argv)) main(process.argv);
2317
+ if (isCliEntrypoint(process.argv)) {
2318
+ installBrokenPipeHandler(process.stdout);
2319
+ installBrokenPipeHandler(process.stderr);
2320
+ const queueOwnerArgOverride = buildQueueOwnerArgOverride(fileURLToPath(import.meta.url));
2321
+ if (queueOwnerArgOverride) process.env.ACPX_QUEUE_OWNER_ARGS ??= queueOwnerArgOverride;
2322
+ main(process.argv);
2323
+ }
1646
2324
  //#endregion
1647
2325
  export { formatPromptSessionBannerLine, parseAllowedTools, parseMaxTurns, parseTtlSeconds };
1648
2326