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.
- package/README.md +8 -4
- package/dist/{cli-BGYGVo3b.js → cli-8dP_TqBp.js} +4 -4
- package/dist/{cli-BGYGVo3b.js.map → cli-8dP_TqBp.js.map} +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +930 -252
- package/dist/cli.js.map +1 -1
- package/dist/{client-FzXPdgP7.d.ts → client-C4iJBO0j.d.ts} +30 -3
- package/dist/client-C4iJBO0j.d.ts.map +1 -0
- package/dist/{flags-D706STfk.js → flags--2oX_ubW.js} +96 -39
- package/dist/flags--2oX_ubW.js.map +1 -0
- package/dist/{flows-hcjHmU7P.js → flows-e4umXVbY.js} +401 -336
- package/dist/flows-e4umXVbY.js.map +1 -0
- package/dist/flows.d.ts +21 -1
- package/dist/flows.d.ts.map +1 -1
- package/dist/flows.js +1 -1
- package/dist/{live-checkpoint-B9ctAuqV.js → live-checkpoint-CuFft_Nd.js} +1614 -931
- package/dist/live-checkpoint-CuFft_Nd.js.map +1 -0
- package/dist/{output-BL9XRWzS.js → output-Di77Yugq.js} +1153 -719
- package/dist/output-Di77Yugq.js.map +1 -0
- package/dist/runtime.d.ts +30 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +579 -425
- package/dist/runtime.js.map +1 -1
- package/dist/{session-options-BJyG6zEH.d.ts → session-options-Bh1bIqQ2.d.ts} +14 -1
- package/dist/{session-options-BJyG6zEH.d.ts.map → session-options-Bh1bIqQ2.d.ts.map} +1 -1
- package/package.json +21 -12
- package/skills/acpx/SKILL.md +22 -5
- package/dist/client-FzXPdgP7.d.ts.map +0 -1
- package/dist/flags-D706STfk.js.map +0 -1
- package/dist/flows-hcjHmU7P.js.map +0 -1
- package/dist/live-checkpoint-B9ctAuqV.js.map +0 -1
- 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,
|
|
3
|
-
import { At as EXIT_CODES,
|
|
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
|
|
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
|
|
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
|
|
53
|
-
|
|
54
|
-
|
|
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-
|
|
389
|
+
sessionModulePromise ??= import("./output-Di77Yugq.js").then((n) => n.i);
|
|
76
390
|
return sessionModulePromise;
|
|
77
391
|
}
|
|
78
392
|
function loadOutputModule() {
|
|
79
|
-
outputModulePromise ??= import("./output-
|
|
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 (
|
|
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]
|
|
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]
|
|
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]
|
|
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]
|
|
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
|
|
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
|
|
408
|
-
|
|
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(
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
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
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
846
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
process.stdout.write("
|
|
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
|
|
1184
|
-
const
|
|
1185
|
-
const
|
|
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
|
|
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
|
-
|
|
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
|
-
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
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
|
-
|
|
1230
|
-
|
|
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
|
|
1245
|
-
|
|
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-
|
|
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
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
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
|
-
|
|
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
|
|
1414
|
-
|
|
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
|
-
|
|
1452
|
-
if (
|
|
1453
|
-
|
|
1454
|
-
|
|
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
|
|
1498
|
-
|
|
1499
|
-
|
|
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
|
|
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
|
|
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
|
|
1550
|
-
|
|
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
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
2286
|
+
await program.parseAsync(normalizedArgv);
|
|
1603
2287
|
} catch (error) {
|
|
1604
|
-
|
|
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))
|
|
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
|
|