acpx 0.1.6 → 0.1.8
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/LICENSE +1 -1
- package/README.md +42 -7
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1256 -241
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -50,6 +50,7 @@ import path from "path";
|
|
|
50
50
|
var DEFAULT_TIMEOUT_MS = void 0;
|
|
51
51
|
var DEFAULT_TTL_MS = 3e5;
|
|
52
52
|
var DEFAULT_PERMISSION_MODE = "approve-reads";
|
|
53
|
+
var DEFAULT_NON_INTERACTIVE_PERMISSION_POLICY = "deny";
|
|
53
54
|
var DEFAULT_AUTH_POLICY = "skip";
|
|
54
55
|
var DEFAULT_OUTPUT_FORMAT = "text";
|
|
55
56
|
var VALID_PERMISSION_MODES = /* @__PURE__ */ new Set([
|
|
@@ -57,6 +58,7 @@ var VALID_PERMISSION_MODES = /* @__PURE__ */ new Set([
|
|
|
57
58
|
"approve-reads",
|
|
58
59
|
"deny-all"
|
|
59
60
|
]);
|
|
61
|
+
var VALID_NON_INTERACTIVE_PERMISSION_POLICIES = /* @__PURE__ */ new Set(["deny", "fail"]);
|
|
60
62
|
var VALID_AUTH_POLICIES = /* @__PURE__ */ new Set(["skip", "fail"]);
|
|
61
63
|
var VALID_OUTPUT_FORMATS = /* @__PURE__ */ new Set(["text", "json", "quiet"]);
|
|
62
64
|
function defaultGlobalConfigPath() {
|
|
@@ -101,6 +103,19 @@ function parsePermissionMode(value, sourcePath) {
|
|
|
101
103
|
}
|
|
102
104
|
return value;
|
|
103
105
|
}
|
|
106
|
+
function parseNonInteractivePermissionPolicy(value, sourcePath) {
|
|
107
|
+
if (value == null) {
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
if (typeof value !== "string" || !VALID_NON_INTERACTIVE_PERMISSION_POLICIES.has(
|
|
111
|
+
value
|
|
112
|
+
)) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`Invalid config nonInteractivePermissions in ${sourcePath}: expected deny or fail`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
104
119
|
function parseAuthPolicy(value, sourcePath) {
|
|
105
120
|
if (value == null) {
|
|
106
121
|
return void 0;
|
|
@@ -225,6 +240,13 @@ async function loadResolvedConfig(cwd) {
|
|
|
225
240
|
const projectConfig = projectResult.config;
|
|
226
241
|
const defaultAgent = parseDefaultAgent(projectConfig?.defaultAgent, projectPath) ?? parseDefaultAgent(globalConfig?.defaultAgent, globalPath) ?? DEFAULT_AGENT_NAME;
|
|
227
242
|
const defaultPermissions = parsePermissionMode(projectConfig?.defaultPermissions, projectPath) ?? parsePermissionMode(globalConfig?.defaultPermissions, globalPath) ?? DEFAULT_PERMISSION_MODE;
|
|
243
|
+
const nonInteractivePermissions = parseNonInteractivePermissionPolicy(
|
|
244
|
+
projectConfig?.nonInteractivePermissions,
|
|
245
|
+
projectPath
|
|
246
|
+
) ?? parseNonInteractivePermissionPolicy(
|
|
247
|
+
globalConfig?.nonInteractivePermissions,
|
|
248
|
+
globalPath
|
|
249
|
+
) ?? DEFAULT_NON_INTERACTIVE_PERMISSION_POLICY;
|
|
228
250
|
const authPolicy = parseAuthPolicy(projectConfig?.authPolicy, projectPath) ?? parseAuthPolicy(globalConfig?.authPolicy, globalPath) ?? DEFAULT_AUTH_POLICY;
|
|
229
251
|
const ttlMs = parseTtlMs(projectConfig?.ttl, projectPath) ?? parseTtlMs(globalConfig?.ttl, globalPath) ?? DEFAULT_TTL_MS;
|
|
230
252
|
const timeoutConfiguredInProject = projectConfig != null && Object.prototype.hasOwnProperty.call(projectConfig, "timeout");
|
|
@@ -247,6 +269,7 @@ async function loadResolvedConfig(cwd) {
|
|
|
247
269
|
return {
|
|
248
270
|
defaultAgent,
|
|
249
271
|
defaultPermissions,
|
|
272
|
+
nonInteractivePermissions,
|
|
250
273
|
authPolicy,
|
|
251
274
|
ttlMs,
|
|
252
275
|
timeoutMs,
|
|
@@ -267,6 +290,7 @@ function toConfigDisplay(config) {
|
|
|
267
290
|
return {
|
|
268
291
|
defaultAgent: config.defaultAgent,
|
|
269
292
|
defaultPermissions: config.defaultPermissions,
|
|
293
|
+
nonInteractivePermissions: config.nonInteractivePermissions,
|
|
270
294
|
authPolicy: config.authPolicy,
|
|
271
295
|
ttl: Math.round(config.ttlMs / 1e3),
|
|
272
296
|
timeout: config.timeoutMs == null ? null : config.timeoutMs / 1e3,
|
|
@@ -289,6 +313,7 @@ async function initGlobalConfigFile() {
|
|
|
289
313
|
const payload = {
|
|
290
314
|
defaultAgent: DEFAULT_AGENT_NAME,
|
|
291
315
|
defaultPermissions: "approve-all",
|
|
316
|
+
nonInteractivePermissions: "deny",
|
|
292
317
|
authPolicy: "skip",
|
|
293
318
|
ttl: 300,
|
|
294
319
|
timeout: null,
|
|
@@ -304,6 +329,293 @@ async function initGlobalConfigFile() {
|
|
|
304
329
|
};
|
|
305
330
|
}
|
|
306
331
|
|
|
332
|
+
// src/errors.ts
|
|
333
|
+
var AcpxOperationalError = class extends Error {
|
|
334
|
+
outputCode;
|
|
335
|
+
detailCode;
|
|
336
|
+
origin;
|
|
337
|
+
retryable;
|
|
338
|
+
acp;
|
|
339
|
+
outputAlreadyEmitted;
|
|
340
|
+
constructor(message, options) {
|
|
341
|
+
super(message, options);
|
|
342
|
+
this.name = new.target.name;
|
|
343
|
+
this.outputCode = options?.outputCode;
|
|
344
|
+
this.detailCode = options?.detailCode;
|
|
345
|
+
this.origin = options?.origin;
|
|
346
|
+
this.retryable = options?.retryable;
|
|
347
|
+
this.acp = options?.acp;
|
|
348
|
+
this.outputAlreadyEmitted = options?.outputAlreadyEmitted;
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
var SessionNotFoundError = class extends AcpxOperationalError {
|
|
352
|
+
sessionId;
|
|
353
|
+
constructor(sessionId) {
|
|
354
|
+
super(`Session not found: ${sessionId}`);
|
|
355
|
+
this.sessionId = sessionId;
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
var SessionResolutionError = class extends AcpxOperationalError {
|
|
359
|
+
};
|
|
360
|
+
var AgentSpawnError = class extends AcpxOperationalError {
|
|
361
|
+
agentCommand;
|
|
362
|
+
constructor(agentCommand, cause) {
|
|
363
|
+
super(`Failed to spawn agent command: ${agentCommand}`, {
|
|
364
|
+
cause: cause instanceof Error ? cause : void 0
|
|
365
|
+
});
|
|
366
|
+
this.agentCommand = agentCommand;
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
var AuthPolicyError = class extends AcpxOperationalError {
|
|
370
|
+
constructor(message, options) {
|
|
371
|
+
super(message, {
|
|
372
|
+
outputCode: "RUNTIME",
|
|
373
|
+
detailCode: "AUTH_REQUIRED",
|
|
374
|
+
origin: "acp",
|
|
375
|
+
...options
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
var QueueConnectionError = class extends AcpxOperationalError {
|
|
380
|
+
};
|
|
381
|
+
var QueueProtocolError = class extends AcpxOperationalError {
|
|
382
|
+
};
|
|
383
|
+
var PermissionDeniedError = class extends AcpxOperationalError {
|
|
384
|
+
};
|
|
385
|
+
var PermissionPromptUnavailableError = class extends AcpxOperationalError {
|
|
386
|
+
constructor() {
|
|
387
|
+
super("Permission prompt unavailable in non-interactive mode");
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
// src/types.ts
|
|
392
|
+
var EXIT_CODES = {
|
|
393
|
+
SUCCESS: 0,
|
|
394
|
+
ERROR: 1,
|
|
395
|
+
USAGE: 2,
|
|
396
|
+
TIMEOUT: 3,
|
|
397
|
+
NO_SESSION: 4,
|
|
398
|
+
PERMISSION_DENIED: 5,
|
|
399
|
+
INTERRUPTED: 130
|
|
400
|
+
};
|
|
401
|
+
var OUTPUT_FORMATS = ["text", "json", "quiet"];
|
|
402
|
+
var AUTH_POLICIES = ["skip", "fail"];
|
|
403
|
+
var NON_INTERACTIVE_PERMISSION_POLICIES = ["deny", "fail"];
|
|
404
|
+
var OUTPUT_ERROR_CODES = [
|
|
405
|
+
"NO_SESSION",
|
|
406
|
+
"TIMEOUT",
|
|
407
|
+
"PERMISSION_DENIED",
|
|
408
|
+
"PERMISSION_PROMPT_UNAVAILABLE",
|
|
409
|
+
"RUNTIME",
|
|
410
|
+
"USAGE"
|
|
411
|
+
];
|
|
412
|
+
var OUTPUT_ERROR_ORIGINS = ["cli", "runtime", "queue", "acp"];
|
|
413
|
+
|
|
414
|
+
// src/error-normalization.ts
|
|
415
|
+
var RESOURCE_NOT_FOUND_ACP_CODES = /* @__PURE__ */ new Set([-32001, -32002]);
|
|
416
|
+
var AUTH_REQUIRED_ACP_CODES = /* @__PURE__ */ new Set([-32e3]);
|
|
417
|
+
function asRecord(value) {
|
|
418
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
419
|
+
return void 0;
|
|
420
|
+
}
|
|
421
|
+
return value;
|
|
422
|
+
}
|
|
423
|
+
function isAuthRequiredMessage(value) {
|
|
424
|
+
if (!value) {
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
const normalized = value.toLowerCase();
|
|
428
|
+
return normalized.includes("auth required") || normalized.includes("authentication required") || normalized.includes("authorization required") || normalized.includes("credential required") || normalized.includes("credentials required") || normalized.includes("token required") || normalized.includes("login required");
|
|
429
|
+
}
|
|
430
|
+
function isAcpAuthRequiredPayload(acp) {
|
|
431
|
+
if (!acp) {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
if (!AUTH_REQUIRED_ACP_CODES.has(acp.code)) {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
if (isAuthRequiredMessage(acp.message)) {
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
const data = asRecord(acp.data);
|
|
441
|
+
if (!data) {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
if (data.authRequired === true) {
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
const methodId = data.methodId;
|
|
448
|
+
if (typeof methodId === "string" && methodId.trim().length > 0) {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
const methods = data.methods;
|
|
452
|
+
if (Array.isArray(methods) && methods.length > 0) {
|
|
453
|
+
return true;
|
|
454
|
+
}
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
function isOutputErrorCode(value) {
|
|
458
|
+
return typeof value === "string" && OUTPUT_ERROR_CODES.includes(value);
|
|
459
|
+
}
|
|
460
|
+
function isOutputErrorOrigin(value) {
|
|
461
|
+
return typeof value === "string" && OUTPUT_ERROR_ORIGINS.includes(value);
|
|
462
|
+
}
|
|
463
|
+
function readOutputErrorMeta(error) {
|
|
464
|
+
const record = asRecord(error);
|
|
465
|
+
if (!record) {
|
|
466
|
+
return {};
|
|
467
|
+
}
|
|
468
|
+
const outputCode = isOutputErrorCode(record.outputCode) ? record.outputCode : void 0;
|
|
469
|
+
const detailCode = typeof record.detailCode === "string" && record.detailCode.trim().length > 0 ? record.detailCode : void 0;
|
|
470
|
+
const origin = isOutputErrorOrigin(record.origin) ? record.origin : void 0;
|
|
471
|
+
const retryable = typeof record.retryable === "boolean" ? record.retryable : void 0;
|
|
472
|
+
const acp = toAcpErrorPayload(record.acp);
|
|
473
|
+
return {
|
|
474
|
+
outputCode,
|
|
475
|
+
detailCode,
|
|
476
|
+
origin,
|
|
477
|
+
retryable,
|
|
478
|
+
acp
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
function toAcpErrorPayload(value) {
|
|
482
|
+
const record = asRecord(value);
|
|
483
|
+
if (!record) {
|
|
484
|
+
return void 0;
|
|
485
|
+
}
|
|
486
|
+
if (typeof record.code !== "number" || !Number.isFinite(record.code)) {
|
|
487
|
+
return void 0;
|
|
488
|
+
}
|
|
489
|
+
if (typeof record.message !== "string" || record.message.length === 0) {
|
|
490
|
+
return void 0;
|
|
491
|
+
}
|
|
492
|
+
return {
|
|
493
|
+
code: record.code,
|
|
494
|
+
message: record.message,
|
|
495
|
+
data: record.data
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
function extractAcpErrorInternal(value, depth) {
|
|
499
|
+
if (depth > 5) {
|
|
500
|
+
return void 0;
|
|
501
|
+
}
|
|
502
|
+
const direct = toAcpErrorPayload(value);
|
|
503
|
+
if (direct) {
|
|
504
|
+
return direct;
|
|
505
|
+
}
|
|
506
|
+
const record = asRecord(value);
|
|
507
|
+
if (!record) {
|
|
508
|
+
return void 0;
|
|
509
|
+
}
|
|
510
|
+
if ("error" in record) {
|
|
511
|
+
const nested = extractAcpErrorInternal(record.error, depth + 1);
|
|
512
|
+
if (nested) {
|
|
513
|
+
return nested;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if ("cause" in record) {
|
|
517
|
+
const nested = extractAcpErrorInternal(record.cause, depth + 1);
|
|
518
|
+
if (nested) {
|
|
519
|
+
return nested;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return void 0;
|
|
523
|
+
}
|
|
524
|
+
function isTimeoutLike(error) {
|
|
525
|
+
return error instanceof Error && error.name === "TimeoutError";
|
|
526
|
+
}
|
|
527
|
+
function isNoSessionLike(error) {
|
|
528
|
+
return error instanceof Error && error.name === "NoSessionError";
|
|
529
|
+
}
|
|
530
|
+
function isUsageLike(error) {
|
|
531
|
+
if (!(error instanceof Error)) {
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
return error.name === "CommanderError" || error.name === "InvalidArgumentError" || asRecord(error)?.code === "commander.invalidArgument";
|
|
535
|
+
}
|
|
536
|
+
function formatErrorMessage(error) {
|
|
537
|
+
if (error instanceof Error) {
|
|
538
|
+
return error.message;
|
|
539
|
+
}
|
|
540
|
+
if (error && typeof error === "object") {
|
|
541
|
+
const maybeMessage = error.message;
|
|
542
|
+
if (typeof maybeMessage === "string" && maybeMessage.length > 0) {
|
|
543
|
+
return maybeMessage;
|
|
544
|
+
}
|
|
545
|
+
try {
|
|
546
|
+
return JSON.stringify(error);
|
|
547
|
+
} catch {
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return String(error);
|
|
551
|
+
}
|
|
552
|
+
function extractAcpError(error) {
|
|
553
|
+
return extractAcpErrorInternal(error, 0);
|
|
554
|
+
}
|
|
555
|
+
function isAcpResourceNotFoundError(error) {
|
|
556
|
+
const acp = extractAcpError(error);
|
|
557
|
+
if (acp && RESOURCE_NOT_FOUND_ACP_CODES.has(acp.code)) {
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
560
|
+
const message = formatErrorMessage(error).toLowerCase();
|
|
561
|
+
return message.includes("resource_not_found") || message.includes("resource not found") || message.includes("session not found") || message.includes("unknown session");
|
|
562
|
+
}
|
|
563
|
+
function mapErrorCode(error) {
|
|
564
|
+
if (error instanceof PermissionPromptUnavailableError) {
|
|
565
|
+
return "PERMISSION_PROMPT_UNAVAILABLE";
|
|
566
|
+
}
|
|
567
|
+
if (error instanceof PermissionDeniedError) {
|
|
568
|
+
return "PERMISSION_DENIED";
|
|
569
|
+
}
|
|
570
|
+
if (isTimeoutLike(error)) {
|
|
571
|
+
return "TIMEOUT";
|
|
572
|
+
}
|
|
573
|
+
if (isNoSessionLike(error) || isAcpResourceNotFoundError(error)) {
|
|
574
|
+
return "NO_SESSION";
|
|
575
|
+
}
|
|
576
|
+
if (isUsageLike(error)) {
|
|
577
|
+
return "USAGE";
|
|
578
|
+
}
|
|
579
|
+
return void 0;
|
|
580
|
+
}
|
|
581
|
+
function normalizeOutputError(error, options = {}) {
|
|
582
|
+
const meta = readOutputErrorMeta(error);
|
|
583
|
+
const mapped = mapErrorCode(error);
|
|
584
|
+
let code = mapped ?? options.defaultCode ?? "RUNTIME";
|
|
585
|
+
if (meta.outputCode) {
|
|
586
|
+
code = meta.outputCode;
|
|
587
|
+
}
|
|
588
|
+
if (code === "RUNTIME" && isAcpResourceNotFoundError(error)) {
|
|
589
|
+
code = "NO_SESSION";
|
|
590
|
+
}
|
|
591
|
+
const acp = options.acp ?? meta.acp ?? extractAcpError(error);
|
|
592
|
+
const detailCode = meta.detailCode ?? options.detailCode ?? (error instanceof AuthPolicyError || isAcpAuthRequiredPayload(acp) ? "AUTH_REQUIRED" : void 0);
|
|
593
|
+
return {
|
|
594
|
+
code,
|
|
595
|
+
message: formatErrorMessage(error),
|
|
596
|
+
detailCode,
|
|
597
|
+
origin: meta.origin ?? options.origin,
|
|
598
|
+
retryable: meta.retryable ?? options.retryable,
|
|
599
|
+
acp
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
function exitCodeForOutputErrorCode(code) {
|
|
603
|
+
switch (code) {
|
|
604
|
+
case "USAGE":
|
|
605
|
+
return EXIT_CODES.USAGE;
|
|
606
|
+
case "TIMEOUT":
|
|
607
|
+
return EXIT_CODES.TIMEOUT;
|
|
608
|
+
case "NO_SESSION":
|
|
609
|
+
return EXIT_CODES.NO_SESSION;
|
|
610
|
+
case "PERMISSION_DENIED":
|
|
611
|
+
case "PERMISSION_PROMPT_UNAVAILABLE":
|
|
612
|
+
return EXIT_CODES.PERMISSION_DENIED;
|
|
613
|
+
case "RUNTIME":
|
|
614
|
+
default:
|
|
615
|
+
return EXIT_CODES.ERROR;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
307
619
|
// src/output.ts
|
|
308
620
|
var MAX_THOUGHT_CHARS = 900;
|
|
309
621
|
var MAX_INLINE_CHARS = 220;
|
|
@@ -324,6 +636,8 @@ var OUTPUT_PRIORITY_KEYS = [
|
|
|
324
636
|
function nowIso() {
|
|
325
637
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
326
638
|
}
|
|
639
|
+
var DEFAULT_JSON_SESSION_ID = "unknown";
|
|
640
|
+
var DEFAULT_JSON_STREAM = "prompt";
|
|
327
641
|
function asStatus(status) {
|
|
328
642
|
return status ?? "unknown";
|
|
329
643
|
}
|
|
@@ -344,7 +658,7 @@ function toStatusLabel(status) {
|
|
|
344
658
|
return "running";
|
|
345
659
|
}
|
|
346
660
|
}
|
|
347
|
-
function
|
|
661
|
+
function asRecord2(value) {
|
|
348
662
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
349
663
|
return void 0;
|
|
350
664
|
}
|
|
@@ -438,7 +752,7 @@ function summarizeToolInput(rawInput) {
|
|
|
438
752
|
if (typeof rawInput === "string" || typeof rawInput === "number" || typeof rawInput === "boolean") {
|
|
439
753
|
return toInline(String(rawInput));
|
|
440
754
|
}
|
|
441
|
-
const record =
|
|
755
|
+
const record = asRecord2(rawInput);
|
|
442
756
|
if (record) {
|
|
443
757
|
const command = readFirstString(record, ["command", "cmd", "program"]);
|
|
444
758
|
const args = readFirstStringArray(record, ["args", "arguments"]);
|
|
@@ -572,7 +886,7 @@ function extractOutputText(value, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
|
572
886
|
}
|
|
573
887
|
return dedupeStrings(parts).join("\n");
|
|
574
888
|
}
|
|
575
|
-
const record =
|
|
889
|
+
const record = asRecord2(value);
|
|
576
890
|
if (!record) {
|
|
577
891
|
return void 0;
|
|
578
892
|
}
|
|
@@ -641,6 +955,8 @@ var TextOutputFormatter = class {
|
|
|
641
955
|
this.stdout = stdout;
|
|
642
956
|
this.useColor = Boolean(stdout.isTTY);
|
|
643
957
|
}
|
|
958
|
+
setContext(_context) {
|
|
959
|
+
}
|
|
644
960
|
onSessionUpdate(notification) {
|
|
645
961
|
const update = notification.update;
|
|
646
962
|
if (update.sessionUpdate !== "agent_thought_chunk") {
|
|
@@ -684,6 +1000,11 @@ var TextOutputFormatter = class {
|
|
|
684
1000
|
this.beginSection("done");
|
|
685
1001
|
this.writeLine(this.dim(`[done] ${stopReason}`));
|
|
686
1002
|
}
|
|
1003
|
+
onError(params) {
|
|
1004
|
+
this.flushThoughtBuffer();
|
|
1005
|
+
this.beginSection("done");
|
|
1006
|
+
this.writeLine(this.formatAnsi(`[error] ${params.code}: ${params.message}`, "31"));
|
|
1007
|
+
}
|
|
687
1008
|
onClientOperation(operation) {
|
|
688
1009
|
this.flushThoughtBuffer();
|
|
689
1010
|
this.beginSection("client");
|
|
@@ -870,8 +1191,29 @@ var TextOutputFormatter = class {
|
|
|
870
1191
|
};
|
|
871
1192
|
var JsonOutputFormatter = class {
|
|
872
1193
|
stdout;
|
|
873
|
-
|
|
1194
|
+
sessionId;
|
|
1195
|
+
requestId;
|
|
1196
|
+
stream;
|
|
1197
|
+
sequence = 0;
|
|
1198
|
+
constructor(stdout, context) {
|
|
874
1199
|
this.stdout = stdout;
|
|
1200
|
+
this.sessionId = context?.sessionId?.trim() || DEFAULT_JSON_SESSION_ID;
|
|
1201
|
+
this.requestId = context?.requestId?.trim() || void 0;
|
|
1202
|
+
this.stream = context?.stream ?? DEFAULT_JSON_STREAM;
|
|
1203
|
+
}
|
|
1204
|
+
setContext(context) {
|
|
1205
|
+
const nextSessionId = context.sessionId?.trim() || this.sessionId || DEFAULT_JSON_SESSION_ID;
|
|
1206
|
+
const nextRequestId = context.requestId?.trim() || void 0;
|
|
1207
|
+
const nextStream = context.stream ?? this.stream ?? DEFAULT_JSON_STREAM;
|
|
1208
|
+
const sessionChanged = nextSessionId !== this.sessionId;
|
|
1209
|
+
const requestChanged = nextRequestId !== this.requestId;
|
|
1210
|
+
const streamChanged = nextStream !== this.stream;
|
|
1211
|
+
this.sessionId = nextSessionId;
|
|
1212
|
+
this.requestId = nextRequestId;
|
|
1213
|
+
this.stream = nextStream;
|
|
1214
|
+
if (sessionChanged || requestChanged || streamChanged) {
|
|
1215
|
+
this.sequence = 0;
|
|
1216
|
+
}
|
|
875
1217
|
}
|
|
876
1218
|
onSessionUpdate(notification) {
|
|
877
1219
|
const update = notification.update;
|
|
@@ -945,6 +1287,18 @@ var JsonOutputFormatter = class {
|
|
|
945
1287
|
timestamp: nowIso()
|
|
946
1288
|
});
|
|
947
1289
|
}
|
|
1290
|
+
onError(params) {
|
|
1291
|
+
this.emit({
|
|
1292
|
+
type: "error",
|
|
1293
|
+
code: params.code,
|
|
1294
|
+
detailCode: params.detailCode,
|
|
1295
|
+
origin: params.origin,
|
|
1296
|
+
message: params.message,
|
|
1297
|
+
retryable: params.retryable,
|
|
1298
|
+
acp: params.acp,
|
|
1299
|
+
timestamp: params.timestamp ?? nowIso()
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
948
1302
|
onClientOperation(operation) {
|
|
949
1303
|
this.emit({
|
|
950
1304
|
type: "client_operation",
|
|
@@ -958,7 +1312,15 @@ var JsonOutputFormatter = class {
|
|
|
958
1312
|
flush() {
|
|
959
1313
|
}
|
|
960
1314
|
emit(event) {
|
|
961
|
-
|
|
1315
|
+
const payload = {
|
|
1316
|
+
eventVersion: 1,
|
|
1317
|
+
sessionId: this.sessionId || DEFAULT_JSON_SESSION_ID,
|
|
1318
|
+
requestId: this.requestId,
|
|
1319
|
+
seq: this.sequence++,
|
|
1320
|
+
stream: this.stream ?? DEFAULT_JSON_STREAM,
|
|
1321
|
+
...event
|
|
1322
|
+
};
|
|
1323
|
+
this.stdout.write(`${JSON.stringify(payload)}
|
|
962
1324
|
`);
|
|
963
1325
|
}
|
|
964
1326
|
};
|
|
@@ -968,6 +1330,8 @@ var QuietOutputFormatter = class {
|
|
|
968
1330
|
constructor(stdout) {
|
|
969
1331
|
this.stdout = stdout;
|
|
970
1332
|
}
|
|
1333
|
+
setContext(_context) {
|
|
1334
|
+
}
|
|
971
1335
|
onSessionUpdate(notification) {
|
|
972
1336
|
const update = notification.update;
|
|
973
1337
|
if (update.sessionUpdate !== "agent_message_chunk") {
|
|
@@ -982,6 +1346,8 @@ var QuietOutputFormatter = class {
|
|
|
982
1346
|
const text = this.chunks.join("");
|
|
983
1347
|
this.stdout.write(text.endsWith("\n") ? text : `${text}
|
|
984
1348
|
`);
|
|
1349
|
+
}
|
|
1350
|
+
onError(_params) {
|
|
985
1351
|
}
|
|
986
1352
|
onClientOperation(_operation) {
|
|
987
1353
|
}
|
|
@@ -994,7 +1360,7 @@ function createOutputFormatter(format, options = {}) {
|
|
|
994
1360
|
case "text":
|
|
995
1361
|
return new TextOutputFormatter(stdout);
|
|
996
1362
|
case "json":
|
|
997
|
-
return new JsonOutputFormatter(stdout);
|
|
1363
|
+
return new JsonOutputFormatter(stdout, options.jsonContext);
|
|
998
1364
|
case "quiet":
|
|
999
1365
|
return new QuietOutputFormatter(stdout);
|
|
1000
1366
|
default: {
|
|
@@ -1018,40 +1384,6 @@ import { spawn as spawn2 } from "child_process";
|
|
|
1018
1384
|
import path3 from "path";
|
|
1019
1385
|
import { Readable, Writable } from "stream";
|
|
1020
1386
|
|
|
1021
|
-
// src/errors.ts
|
|
1022
|
-
var AcpxOperationalError = class extends Error {
|
|
1023
|
-
constructor(message, options) {
|
|
1024
|
-
super(message, options);
|
|
1025
|
-
this.name = new.target.name;
|
|
1026
|
-
}
|
|
1027
|
-
};
|
|
1028
|
-
var SessionNotFoundError = class extends AcpxOperationalError {
|
|
1029
|
-
sessionId;
|
|
1030
|
-
constructor(sessionId) {
|
|
1031
|
-
super(`Session not found: ${sessionId}`);
|
|
1032
|
-
this.sessionId = sessionId;
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
var SessionResolutionError = class extends AcpxOperationalError {
|
|
1036
|
-
};
|
|
1037
|
-
var AgentSpawnError = class extends AcpxOperationalError {
|
|
1038
|
-
agentCommand;
|
|
1039
|
-
constructor(agentCommand, cause) {
|
|
1040
|
-
super(`Failed to spawn agent command: ${agentCommand}`, {
|
|
1041
|
-
cause: cause instanceof Error ? cause : void 0
|
|
1042
|
-
});
|
|
1043
|
-
this.agentCommand = agentCommand;
|
|
1044
|
-
}
|
|
1045
|
-
};
|
|
1046
|
-
var AuthPolicyError = class extends AcpxOperationalError {
|
|
1047
|
-
};
|
|
1048
|
-
var QueueConnectionError = class extends AcpxOperationalError {
|
|
1049
|
-
};
|
|
1050
|
-
var QueueProtocolError = class extends AcpxOperationalError {
|
|
1051
|
-
};
|
|
1052
|
-
var PermissionDeniedError = class extends AcpxOperationalError {
|
|
1053
|
-
};
|
|
1054
|
-
|
|
1055
1387
|
// src/filesystem.ts
|
|
1056
1388
|
import fs2 from "fs/promises";
|
|
1057
1389
|
import path2 from "path";
|
|
@@ -1115,15 +1447,22 @@ async function defaultConfirmWrite(filePath, preview) {
|
|
|
1115
1447
|
prompt: "Allow write? (y/N) "
|
|
1116
1448
|
});
|
|
1117
1449
|
}
|
|
1450
|
+
function canPromptForPermission() {
|
|
1451
|
+
return Boolean(process.stdin.isTTY && process.stderr.isTTY);
|
|
1452
|
+
}
|
|
1118
1453
|
var FileSystemHandlers = class {
|
|
1119
1454
|
rootDir;
|
|
1120
1455
|
permissionMode;
|
|
1456
|
+
nonInteractivePermissions;
|
|
1121
1457
|
onOperation;
|
|
1458
|
+
usesDefaultConfirmWrite;
|
|
1122
1459
|
confirmWrite;
|
|
1123
1460
|
constructor(options) {
|
|
1124
1461
|
this.rootDir = path2.resolve(options.cwd);
|
|
1125
1462
|
this.permissionMode = options.permissionMode;
|
|
1463
|
+
this.nonInteractivePermissions = options.nonInteractivePermissions ?? "deny";
|
|
1126
1464
|
this.onOperation = options.onOperation;
|
|
1465
|
+
this.usesDefaultConfirmWrite = options.confirmWrite == null;
|
|
1127
1466
|
this.confirmWrite = options.confirmWrite ?? defaultConfirmWrite;
|
|
1128
1467
|
}
|
|
1129
1468
|
async readTextFile(params) {
|
|
@@ -1208,6 +1547,9 @@ var FileSystemHandlers = class {
|
|
|
1208
1547
|
if (this.permissionMode === "deny-all") {
|
|
1209
1548
|
return false;
|
|
1210
1549
|
}
|
|
1550
|
+
if (this.usesDefaultConfirmWrite && this.nonInteractivePermissions === "fail" && !canPromptForPermission()) {
|
|
1551
|
+
throw new PermissionPromptUnavailableError();
|
|
1552
|
+
}
|
|
1211
1553
|
return await this.confirmWrite(filePath, preview);
|
|
1212
1554
|
}
|
|
1213
1555
|
resolvePathWithinRoot(rawPath) {
|
|
@@ -1312,7 +1654,10 @@ async function promptForToolPermission(params) {
|
|
|
1312
1654
|
[permission] Allow ${toolName} [${toolKind}]? (y/N) `
|
|
1313
1655
|
});
|
|
1314
1656
|
}
|
|
1315
|
-
|
|
1657
|
+
function canPromptForPermission2() {
|
|
1658
|
+
return Boolean(process.stdin.isTTY && process.stderr.isTTY);
|
|
1659
|
+
}
|
|
1660
|
+
async function resolvePermissionRequest(params, mode, nonInteractivePolicy = "deny") {
|
|
1316
1661
|
const options = params.options ?? [];
|
|
1317
1662
|
if (options.length === 0) {
|
|
1318
1663
|
return cancelled();
|
|
@@ -1335,6 +1680,15 @@ async function resolvePermissionRequest(params, mode) {
|
|
|
1335
1680
|
if (isAutoApprovedReadKind(kind) && allowOption) {
|
|
1336
1681
|
return selected(allowOption.optionId);
|
|
1337
1682
|
}
|
|
1683
|
+
if (!canPromptForPermission2()) {
|
|
1684
|
+
if (nonInteractivePolicy === "fail") {
|
|
1685
|
+
throw new PermissionPromptUnavailableError();
|
|
1686
|
+
}
|
|
1687
|
+
if (rejectOption) {
|
|
1688
|
+
return selected(rejectOption.optionId);
|
|
1689
|
+
}
|
|
1690
|
+
return cancelled();
|
|
1691
|
+
}
|
|
1338
1692
|
const approved = await promptForToolPermission(params);
|
|
1339
1693
|
if (approved && allowOption) {
|
|
1340
1694
|
return selected(allowOption.optionId);
|
|
@@ -1361,6 +1715,40 @@ function classifyPermissionDecision(params, response) {
|
|
|
1361
1715
|
return "denied";
|
|
1362
1716
|
}
|
|
1363
1717
|
|
|
1718
|
+
// src/runtime-session-id.ts
|
|
1719
|
+
var RUNTIME_SESSION_ID_META_KEYS = [
|
|
1720
|
+
"runtimeSessionId",
|
|
1721
|
+
"providerSessionId",
|
|
1722
|
+
"codexSessionId",
|
|
1723
|
+
"claudeSessionId"
|
|
1724
|
+
];
|
|
1725
|
+
function normalizeRuntimeSessionId(value) {
|
|
1726
|
+
if (typeof value !== "string") {
|
|
1727
|
+
return void 0;
|
|
1728
|
+
}
|
|
1729
|
+
const trimmed = value.trim();
|
|
1730
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
1731
|
+
}
|
|
1732
|
+
function asMetaRecord(meta) {
|
|
1733
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta)) {
|
|
1734
|
+
return void 0;
|
|
1735
|
+
}
|
|
1736
|
+
return meta;
|
|
1737
|
+
}
|
|
1738
|
+
function extractRuntimeSessionId(meta) {
|
|
1739
|
+
const record = asMetaRecord(meta);
|
|
1740
|
+
if (!record) {
|
|
1741
|
+
return void 0;
|
|
1742
|
+
}
|
|
1743
|
+
for (const key of RUNTIME_SESSION_ID_META_KEYS) {
|
|
1744
|
+
const normalized = normalizeRuntimeSessionId(record[key]);
|
|
1745
|
+
if (normalized) {
|
|
1746
|
+
return normalized;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
return void 0;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1364
1752
|
// src/terminal.ts
|
|
1365
1753
|
import { spawn } from "child_process";
|
|
1366
1754
|
import { randomUUID } from "crypto";
|
|
@@ -1419,6 +1807,9 @@ async function defaultConfirmExecute(commandLine) {
|
|
|
1419
1807
|
[permission] Allow terminal command "${commandLine}"? (y/N) `
|
|
1420
1808
|
});
|
|
1421
1809
|
}
|
|
1810
|
+
function canPromptForPermission3() {
|
|
1811
|
+
return Boolean(process.stdin.isTTY && process.stderr.isTTY);
|
|
1812
|
+
}
|
|
1422
1813
|
function waitMs(ms) {
|
|
1423
1814
|
return new Promise((resolve) => {
|
|
1424
1815
|
setTimeout(resolve, Math.max(0, ms));
|
|
@@ -1427,14 +1818,18 @@ function waitMs(ms) {
|
|
|
1427
1818
|
var TerminalManager = class {
|
|
1428
1819
|
cwd;
|
|
1429
1820
|
permissionMode;
|
|
1821
|
+
nonInteractivePermissions;
|
|
1430
1822
|
onOperation;
|
|
1823
|
+
usesDefaultConfirmExecute;
|
|
1431
1824
|
confirmExecute;
|
|
1432
1825
|
killGraceMs;
|
|
1433
1826
|
terminals = /* @__PURE__ */ new Map();
|
|
1434
1827
|
constructor(options) {
|
|
1435
1828
|
this.cwd = options.cwd;
|
|
1436
1829
|
this.permissionMode = options.permissionMode;
|
|
1830
|
+
this.nonInteractivePermissions = options.nonInteractivePermissions ?? "deny";
|
|
1437
1831
|
this.onOperation = options.onOperation;
|
|
1832
|
+
this.usesDefaultConfirmExecute = options.confirmExecute == null;
|
|
1438
1833
|
this.confirmExecute = options.confirmExecute ?? defaultConfirmExecute;
|
|
1439
1834
|
this.killGraceMs = Math.max(
|
|
1440
1835
|
0,
|
|
@@ -1656,6 +2051,9 @@ var TerminalManager = class {
|
|
|
1656
2051
|
if (this.permissionMode === "deny-all") {
|
|
1657
2052
|
return false;
|
|
1658
2053
|
}
|
|
2054
|
+
if (this.usesDefaultConfirmExecute && this.nonInteractivePermissions === "fail" && !canPromptForPermission3()) {
|
|
2055
|
+
throw new PermissionPromptUnavailableError();
|
|
2056
|
+
}
|
|
1659
2057
|
return await this.confirmExecute(commandLine);
|
|
1660
2058
|
}
|
|
1661
2059
|
isRunning(terminal) {
|
|
@@ -1693,6 +2091,24 @@ var TerminalManager = class {
|
|
|
1693
2091
|
var REPLAY_IDLE_MS = 80;
|
|
1694
2092
|
var REPLAY_DRAIN_TIMEOUT_MS = 5e3;
|
|
1695
2093
|
var DRAIN_POLL_INTERVAL_MS = 20;
|
|
2094
|
+
function shouldSuppressSdkConsoleError(args) {
|
|
2095
|
+
if (args.length === 0) {
|
|
2096
|
+
return false;
|
|
2097
|
+
}
|
|
2098
|
+
return typeof args[0] === "string" && args[0] === "Error handling request";
|
|
2099
|
+
}
|
|
2100
|
+
function installSdkConsoleErrorSuppression() {
|
|
2101
|
+
const originalConsoleError = console.error;
|
|
2102
|
+
console.error = (...args) => {
|
|
2103
|
+
if (shouldSuppressSdkConsoleError(args)) {
|
|
2104
|
+
return;
|
|
2105
|
+
}
|
|
2106
|
+
originalConsoleError(...args);
|
|
2107
|
+
};
|
|
2108
|
+
return () => {
|
|
2109
|
+
console.error = originalConsoleError;
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
1696
2112
|
function isoNow() {
|
|
1697
2113
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1698
2114
|
}
|
|
@@ -1835,6 +2251,7 @@ var AcpClient = class {
|
|
|
1835
2251
|
agentStartedAt;
|
|
1836
2252
|
lastAgentExit;
|
|
1837
2253
|
lastKnownPid;
|
|
2254
|
+
promptPermissionFailures = /* @__PURE__ */ new Map();
|
|
1838
2255
|
constructor(options) {
|
|
1839
2256
|
this.options = {
|
|
1840
2257
|
...options,
|
|
@@ -1845,11 +2262,13 @@ var AcpClient = class {
|
|
|
1845
2262
|
this.filesystem = new FileSystemHandlers({
|
|
1846
2263
|
cwd: this.options.cwd,
|
|
1847
2264
|
permissionMode: this.options.permissionMode,
|
|
2265
|
+
nonInteractivePermissions: this.options.nonInteractivePermissions,
|
|
1848
2266
|
onOperation: emitOperation
|
|
1849
2267
|
});
|
|
1850
2268
|
this.terminalManager = new TerminalManager({
|
|
1851
2269
|
cwd: this.options.cwd,
|
|
1852
2270
|
permissionMode: this.options.permissionMode,
|
|
2271
|
+
nonInteractivePermissions: this.options.nonInteractivePermissions,
|
|
1853
2272
|
onOperation: emitOperation
|
|
1854
2273
|
});
|
|
1855
2274
|
}
|
|
@@ -1988,18 +2407,22 @@ var AcpClient = class {
|
|
|
1988
2407
|
cwd: asAbsoluteCwd(cwd),
|
|
1989
2408
|
mcpServers: []
|
|
1990
2409
|
});
|
|
1991
|
-
return
|
|
2410
|
+
return {
|
|
2411
|
+
sessionId: result.sessionId,
|
|
2412
|
+
runtimeSessionId: extractRuntimeSessionId(result._meta)
|
|
2413
|
+
};
|
|
1992
2414
|
}
|
|
1993
2415
|
async loadSession(sessionId, cwd = this.options.cwd) {
|
|
1994
2416
|
this.getConnection();
|
|
1995
|
-
await this.loadSessionWithOptions(sessionId, cwd, {});
|
|
2417
|
+
return await this.loadSessionWithOptions(sessionId, cwd, {});
|
|
1996
2418
|
}
|
|
1997
2419
|
async loadSessionWithOptions(sessionId, cwd = this.options.cwd, options = {}) {
|
|
1998
2420
|
const connection = this.getConnection();
|
|
1999
2421
|
const previousSuppression = this.suppressSessionUpdates;
|
|
2000
2422
|
this.suppressSessionUpdates = previousSuppression || Boolean(options.suppressReplayUpdates);
|
|
2423
|
+
let response;
|
|
2001
2424
|
try {
|
|
2002
|
-
await connection.loadSession({
|
|
2425
|
+
response = await connection.loadSession({
|
|
2003
2426
|
sessionId,
|
|
2004
2427
|
cwd: asAbsoluteCwd(cwd),
|
|
2005
2428
|
mcpServers: []
|
|
@@ -2011,29 +2434,52 @@ var AcpClient = class {
|
|
|
2011
2434
|
} finally {
|
|
2012
2435
|
this.suppressSessionUpdates = previousSuppression;
|
|
2013
2436
|
}
|
|
2437
|
+
return {
|
|
2438
|
+
runtimeSessionId: extractRuntimeSessionId(response?._meta)
|
|
2439
|
+
};
|
|
2014
2440
|
}
|
|
2015
2441
|
async prompt(sessionId, text) {
|
|
2016
2442
|
const connection = this.getConnection();
|
|
2017
|
-
const
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2443
|
+
const restoreConsoleError = this.options.suppressSdkConsoleErrors ? installSdkConsoleErrorSuppression() : void 0;
|
|
2444
|
+
let promptPromise;
|
|
2445
|
+
try {
|
|
2446
|
+
promptPromise = connection.prompt({
|
|
2447
|
+
sessionId,
|
|
2448
|
+
prompt: [
|
|
2449
|
+
{
|
|
2450
|
+
type: "text",
|
|
2451
|
+
text
|
|
2452
|
+
}
|
|
2453
|
+
]
|
|
2454
|
+
});
|
|
2455
|
+
} catch (error) {
|
|
2456
|
+
restoreConsoleError?.();
|
|
2457
|
+
throw error;
|
|
2458
|
+
}
|
|
2026
2459
|
this.activePrompt = {
|
|
2027
2460
|
sessionId,
|
|
2028
2461
|
promise: promptPromise
|
|
2029
2462
|
};
|
|
2030
2463
|
try {
|
|
2031
|
-
|
|
2464
|
+
const response = await promptPromise;
|
|
2465
|
+
const permissionFailure = this.consumePromptPermissionFailure(sessionId);
|
|
2466
|
+
if (permissionFailure) {
|
|
2467
|
+
throw permissionFailure;
|
|
2468
|
+
}
|
|
2469
|
+
return response;
|
|
2470
|
+
} catch (error) {
|
|
2471
|
+
const permissionFailure = this.consumePromptPermissionFailure(sessionId);
|
|
2472
|
+
if (permissionFailure) {
|
|
2473
|
+
throw permissionFailure;
|
|
2474
|
+
}
|
|
2475
|
+
throw error;
|
|
2032
2476
|
} finally {
|
|
2477
|
+
restoreConsoleError?.();
|
|
2033
2478
|
if (this.activePrompt?.promise === promptPromise) {
|
|
2034
2479
|
this.activePrompt = void 0;
|
|
2035
2480
|
}
|
|
2036
2481
|
this.cancellingSessionIds.delete(sessionId);
|
|
2482
|
+
this.promptPermissionFailures.delete(sessionId);
|
|
2037
2483
|
}
|
|
2038
2484
|
}
|
|
2039
2485
|
async setSessionMode(sessionId, modeId) {
|
|
@@ -2110,6 +2556,7 @@ var AcpClient = class {
|
|
|
2110
2556
|
this.suppressSessionUpdates = false;
|
|
2111
2557
|
this.activePrompt = void 0;
|
|
2112
2558
|
this.cancellingSessionIds.clear();
|
|
2559
|
+
this.promptPermissionFailures.clear();
|
|
2113
2560
|
this.connection = void 0;
|
|
2114
2561
|
this.agent = void 0;
|
|
2115
2562
|
}
|
|
@@ -2177,10 +2624,26 @@ var AcpClient = class {
|
|
|
2177
2624
|
}
|
|
2178
2625
|
};
|
|
2179
2626
|
}
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2627
|
+
let response;
|
|
2628
|
+
try {
|
|
2629
|
+
response = await resolvePermissionRequest(
|
|
2630
|
+
params,
|
|
2631
|
+
this.options.permissionMode,
|
|
2632
|
+
this.options.nonInteractivePermissions ?? "deny"
|
|
2633
|
+
);
|
|
2634
|
+
} catch (error) {
|
|
2635
|
+
if (error instanceof PermissionPromptUnavailableError) {
|
|
2636
|
+
this.notePromptPermissionFailure(params.sessionId, error);
|
|
2637
|
+
this.permissionStats.requested += 1;
|
|
2638
|
+
this.permissionStats.cancelled += 1;
|
|
2639
|
+
return {
|
|
2640
|
+
outcome: {
|
|
2641
|
+
outcome: "cancelled"
|
|
2642
|
+
}
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
throw error;
|
|
2646
|
+
}
|
|
2184
2647
|
const decision = classifyPermissionDecision(params, response);
|
|
2185
2648
|
this.permissionStats.requested += 1;
|
|
2186
2649
|
if (decision === "approved") {
|
|
@@ -2219,14 +2682,40 @@ var AcpClient = class {
|
|
|
2219
2682
|
unexpectedDuringPrompt: !this.closing && Boolean(this.activePrompt)
|
|
2220
2683
|
};
|
|
2221
2684
|
}
|
|
2685
|
+
notePromptPermissionFailure(sessionId, error) {
|
|
2686
|
+
if (!this.promptPermissionFailures.has(sessionId)) {
|
|
2687
|
+
this.promptPermissionFailures.set(sessionId, error);
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
consumePromptPermissionFailure(sessionId) {
|
|
2691
|
+
const error = this.promptPermissionFailures.get(sessionId);
|
|
2692
|
+
if (error) {
|
|
2693
|
+
this.promptPermissionFailures.delete(sessionId);
|
|
2694
|
+
}
|
|
2695
|
+
return error;
|
|
2696
|
+
}
|
|
2222
2697
|
async handleReadTextFile(params) {
|
|
2223
2698
|
return await this.filesystem.readTextFile(params);
|
|
2224
2699
|
}
|
|
2225
2700
|
async handleWriteTextFile(params) {
|
|
2226
|
-
|
|
2701
|
+
try {
|
|
2702
|
+
return await this.filesystem.writeTextFile(params);
|
|
2703
|
+
} catch (error) {
|
|
2704
|
+
if (error instanceof PermissionPromptUnavailableError) {
|
|
2705
|
+
this.notePromptPermissionFailure(params.sessionId, error);
|
|
2706
|
+
}
|
|
2707
|
+
throw error;
|
|
2708
|
+
}
|
|
2227
2709
|
}
|
|
2228
2710
|
async handleCreateTerminal(params) {
|
|
2229
|
-
|
|
2711
|
+
try {
|
|
2712
|
+
return await this.terminalManager.createTerminal(params);
|
|
2713
|
+
} catch (error) {
|
|
2714
|
+
if (error instanceof PermissionPromptUnavailableError) {
|
|
2715
|
+
this.notePromptPermissionFailure(params.sessionId, error);
|
|
2716
|
+
}
|
|
2717
|
+
throw error;
|
|
2718
|
+
}
|
|
2230
2719
|
}
|
|
2231
2720
|
async handleTerminalOutput(params) {
|
|
2232
2721
|
return await this.terminalManager.terminalOutput(params);
|
|
@@ -2325,7 +2814,11 @@ var QueueOwnerTurnController = class {
|
|
|
2325
2814
|
}
|
|
2326
2815
|
assertCanHandleControlRequest() {
|
|
2327
2816
|
if (this.state === "closing") {
|
|
2328
|
-
throw new QueueConnectionError("Queue owner is closing"
|
|
2817
|
+
throw new QueueConnectionError("Queue owner is closing", {
|
|
2818
|
+
detailCode: "QUEUE_OWNER_SHUTTING_DOWN",
|
|
2819
|
+
origin: "queue",
|
|
2820
|
+
retryable: true
|
|
2821
|
+
});
|
|
2329
2822
|
}
|
|
2330
2823
|
}
|
|
2331
2824
|
async requestCancel() {
|
|
@@ -2391,7 +2884,7 @@ import os2 from "os";
|
|
|
2391
2884
|
import path4 from "path";
|
|
2392
2885
|
|
|
2393
2886
|
// src/queue-messages.ts
|
|
2394
|
-
function
|
|
2887
|
+
function asRecord3(value) {
|
|
2395
2888
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2396
2889
|
return void 0;
|
|
2397
2890
|
}
|
|
@@ -2400,8 +2893,34 @@ function asRecord2(value) {
|
|
|
2400
2893
|
function isPermissionMode(value) {
|
|
2401
2894
|
return value === "approve-all" || value === "approve-reads" || value === "deny-all";
|
|
2402
2895
|
}
|
|
2896
|
+
function isNonInteractivePermissionPolicy(value) {
|
|
2897
|
+
return value === "deny" || value === "fail";
|
|
2898
|
+
}
|
|
2899
|
+
function isOutputErrorCode2(value) {
|
|
2900
|
+
return typeof value === "string" && OUTPUT_ERROR_CODES.includes(value);
|
|
2901
|
+
}
|
|
2902
|
+
function isOutputErrorOrigin2(value) {
|
|
2903
|
+
return typeof value === "string" && OUTPUT_ERROR_ORIGINS.includes(value);
|
|
2904
|
+
}
|
|
2905
|
+
function parseAcpError(value) {
|
|
2906
|
+
const record = asRecord3(value);
|
|
2907
|
+
if (!record) {
|
|
2908
|
+
return void 0;
|
|
2909
|
+
}
|
|
2910
|
+
if (typeof record.code !== "number" || !Number.isFinite(record.code)) {
|
|
2911
|
+
return void 0;
|
|
2912
|
+
}
|
|
2913
|
+
if (typeof record.message !== "string" || record.message.length === 0) {
|
|
2914
|
+
return void 0;
|
|
2915
|
+
}
|
|
2916
|
+
return {
|
|
2917
|
+
code: record.code,
|
|
2918
|
+
message: record.message,
|
|
2919
|
+
data: record.data
|
|
2920
|
+
};
|
|
2921
|
+
}
|
|
2403
2922
|
function parseQueueRequest(raw) {
|
|
2404
|
-
const request =
|
|
2923
|
+
const request = asRecord3(raw);
|
|
2405
2924
|
if (!request) {
|
|
2406
2925
|
return null;
|
|
2407
2926
|
}
|
|
@@ -2411,7 +2930,9 @@ function parseQueueRequest(raw) {
|
|
|
2411
2930
|
const timeoutRaw = request.timeoutMs;
|
|
2412
2931
|
const timeoutMs = typeof timeoutRaw === "number" && Number.isFinite(timeoutRaw) && timeoutRaw > 0 ? Math.round(timeoutRaw) : void 0;
|
|
2413
2932
|
if (request.type === "submit_prompt") {
|
|
2414
|
-
|
|
2933
|
+
const nonInteractivePermissions = request.nonInteractivePermissions == null ? void 0 : isNonInteractivePermissionPolicy(request.nonInteractivePermissions) ? request.nonInteractivePermissions : null;
|
|
2934
|
+
const suppressSdkConsoleErrors = request.suppressSdkConsoleErrors == null ? void 0 : typeof request.suppressSdkConsoleErrors === "boolean" ? request.suppressSdkConsoleErrors : null;
|
|
2935
|
+
if (typeof request.message !== "string" || !isPermissionMode(request.permissionMode) || nonInteractivePermissions === null || suppressSdkConsoleErrors === null || typeof request.waitForCompletion !== "boolean") {
|
|
2415
2936
|
return null;
|
|
2416
2937
|
}
|
|
2417
2938
|
return {
|
|
@@ -2419,7 +2940,9 @@ function parseQueueRequest(raw) {
|
|
|
2419
2940
|
requestId: request.requestId,
|
|
2420
2941
|
message: request.message,
|
|
2421
2942
|
permissionMode: request.permissionMode,
|
|
2943
|
+
nonInteractivePermissions,
|
|
2422
2944
|
timeoutMs,
|
|
2945
|
+
...suppressSdkConsoleErrors !== void 0 ? { suppressSdkConsoleErrors } : {},
|
|
2423
2946
|
waitForCompletion: request.waitForCompletion
|
|
2424
2947
|
};
|
|
2425
2948
|
}
|
|
@@ -2455,15 +2978,15 @@ function parseQueueRequest(raw) {
|
|
|
2455
2978
|
return null;
|
|
2456
2979
|
}
|
|
2457
2980
|
function parseSessionSendResult(raw) {
|
|
2458
|
-
const result =
|
|
2981
|
+
const result = asRecord3(raw);
|
|
2459
2982
|
if (!result) {
|
|
2460
2983
|
return null;
|
|
2461
2984
|
}
|
|
2462
2985
|
if (typeof result.stopReason !== "string" || typeof result.sessionId !== "string" || typeof result.resumed !== "boolean") {
|
|
2463
2986
|
return null;
|
|
2464
2987
|
}
|
|
2465
|
-
const permissionStats =
|
|
2466
|
-
const record =
|
|
2988
|
+
const permissionStats = asRecord3(result.permissionStats);
|
|
2989
|
+
const record = asRecord3(result.record);
|
|
2467
2990
|
if (!permissionStats || !record) {
|
|
2468
2991
|
return null;
|
|
2469
2992
|
}
|
|
@@ -2478,7 +3001,7 @@ function parseSessionSendResult(raw) {
|
|
|
2478
3001
|
return result;
|
|
2479
3002
|
}
|
|
2480
3003
|
function parseQueueOwnerMessage(raw) {
|
|
2481
|
-
const message =
|
|
3004
|
+
const message = asRecord3(raw);
|
|
2482
3005
|
if (!message || typeof message.type !== "string") {
|
|
2483
3006
|
return null;
|
|
2484
3007
|
}
|
|
@@ -2503,7 +3026,7 @@ function parseQueueOwnerMessage(raw) {
|
|
|
2503
3026
|
};
|
|
2504
3027
|
}
|
|
2505
3028
|
if (message.type === "client_operation") {
|
|
2506
|
-
const operation =
|
|
3029
|
+
const operation = asRecord3(message.operation);
|
|
2507
3030
|
if (!operation || typeof operation.method !== "string" || typeof operation.status !== "string" || typeof operation.summary !== "string" || typeof operation.timestamp !== "string") {
|
|
2508
3031
|
return null;
|
|
2509
3032
|
}
|
|
@@ -2558,7 +3081,7 @@ function parseQueueOwnerMessage(raw) {
|
|
|
2558
3081
|
};
|
|
2559
3082
|
}
|
|
2560
3083
|
if (message.type === "set_config_option_result") {
|
|
2561
|
-
const response =
|
|
3084
|
+
const response = asRecord3(message.response);
|
|
2562
3085
|
if (!response || !Array.isArray(response.configOptions)) {
|
|
2563
3086
|
return null;
|
|
2564
3087
|
}
|
|
@@ -2572,10 +3095,20 @@ function parseQueueOwnerMessage(raw) {
|
|
|
2572
3095
|
if (typeof message.message !== "string") {
|
|
2573
3096
|
return null;
|
|
2574
3097
|
}
|
|
3098
|
+
const code = isOutputErrorCode2(message.code) ? message.code : void 0;
|
|
3099
|
+
const detailCode = typeof message.detailCode === "string" && message.detailCode.trim().length > 0 ? message.detailCode : void 0;
|
|
3100
|
+
const origin = isOutputErrorOrigin2(message.origin) ? message.origin : void 0;
|
|
3101
|
+
const retryable = typeof message.retryable === "boolean" ? message.retryable : void 0;
|
|
3102
|
+
const acp = parseAcpError(message.acp);
|
|
2575
3103
|
return {
|
|
2576
3104
|
type: "error",
|
|
2577
3105
|
requestId: message.requestId,
|
|
2578
|
-
|
|
3106
|
+
code,
|
|
3107
|
+
detailCode,
|
|
3108
|
+
origin,
|
|
3109
|
+
message: message.message,
|
|
3110
|
+
retryable,
|
|
3111
|
+
acp
|
|
2579
3112
|
};
|
|
2580
3113
|
}
|
|
2581
3114
|
return null;
|
|
@@ -2589,21 +3122,34 @@ var QUEUE_CONNECT_RETRY_MS = 50;
|
|
|
2589
3122
|
function queueBaseDir() {
|
|
2590
3123
|
return path4.join(os2.homedir(), ".acpx", "queues");
|
|
2591
3124
|
}
|
|
2592
|
-
function
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
3125
|
+
function makeQueueOwnerError(requestId, message, detailCode, options = {}) {
|
|
3126
|
+
return {
|
|
3127
|
+
type: "error",
|
|
3128
|
+
requestId,
|
|
3129
|
+
code: "RUNTIME",
|
|
3130
|
+
detailCode,
|
|
3131
|
+
origin: "queue",
|
|
3132
|
+
retryable: options.retryable,
|
|
3133
|
+
message
|
|
3134
|
+
};
|
|
3135
|
+
}
|
|
3136
|
+
function makeQueueOwnerErrorFromUnknown(requestId, error, detailCode, options = {}) {
|
|
3137
|
+
const normalized = normalizeOutputError(error, {
|
|
3138
|
+
defaultCode: "RUNTIME",
|
|
3139
|
+
origin: "queue",
|
|
3140
|
+
detailCode,
|
|
3141
|
+
retryable: options.retryable
|
|
3142
|
+
});
|
|
3143
|
+
return {
|
|
3144
|
+
type: "error",
|
|
3145
|
+
requestId,
|
|
3146
|
+
code: normalized.code,
|
|
3147
|
+
detailCode: normalized.detailCode,
|
|
3148
|
+
origin: normalized.origin,
|
|
3149
|
+
message: normalized.message,
|
|
3150
|
+
retryable: normalized.retryable,
|
|
3151
|
+
acp: normalized.acp
|
|
3152
|
+
};
|
|
2607
3153
|
}
|
|
2608
3154
|
function isProcessAlive(pid) {
|
|
2609
3155
|
if (!pid || !Number.isInteger(pid) || pid <= 0 || pid === process.pid) {
|
|
@@ -2847,11 +3393,16 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2847
3393
|
}
|
|
2848
3394
|
for (const task of this.pending.splice(0)) {
|
|
2849
3395
|
if (task.waitForCompletion) {
|
|
2850
|
-
task.send(
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
3396
|
+
task.send(
|
|
3397
|
+
makeQueueOwnerError(
|
|
3398
|
+
task.requestId,
|
|
3399
|
+
"Queue owner shutting down before prompt execution",
|
|
3400
|
+
"QUEUE_OWNER_SHUTTING_DOWN",
|
|
3401
|
+
{
|
|
3402
|
+
retryable: true
|
|
3403
|
+
}
|
|
3404
|
+
)
|
|
3405
|
+
);
|
|
2855
3406
|
}
|
|
2856
3407
|
task.close();
|
|
2857
3408
|
}
|
|
@@ -2890,11 +3441,16 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2890
3441
|
enqueue(task) {
|
|
2891
3442
|
if (this.closed) {
|
|
2892
3443
|
if (task.waitForCompletion) {
|
|
2893
|
-
task.send(
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
3444
|
+
task.send(
|
|
3445
|
+
makeQueueOwnerError(
|
|
3446
|
+
task.requestId,
|
|
3447
|
+
"Queue owner is shutting down",
|
|
3448
|
+
"QUEUE_OWNER_SHUTTING_DOWN",
|
|
3449
|
+
{
|
|
3450
|
+
retryable: true
|
|
3451
|
+
}
|
|
3452
|
+
)
|
|
3453
|
+
);
|
|
2898
3454
|
}
|
|
2899
3455
|
task.close();
|
|
2900
3456
|
return;
|
|
@@ -2909,22 +3465,24 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2909
3465
|
handleConnection(socket) {
|
|
2910
3466
|
socket.setEncoding("utf8");
|
|
2911
3467
|
if (this.closed) {
|
|
2912
|
-
writeQueueMessage(
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
3468
|
+
writeQueueMessage(
|
|
3469
|
+
socket,
|
|
3470
|
+
makeQueueOwnerError("unknown", "Queue owner is closed", "QUEUE_OWNER_CLOSED", {
|
|
3471
|
+
retryable: true
|
|
3472
|
+
})
|
|
3473
|
+
);
|
|
2917
3474
|
socket.end();
|
|
2918
3475
|
return;
|
|
2919
3476
|
}
|
|
2920
3477
|
let buffer = "";
|
|
2921
3478
|
let handled = false;
|
|
2922
|
-
const fail = (requestId, message) => {
|
|
2923
|
-
writeQueueMessage(
|
|
2924
|
-
|
|
2925
|
-
requestId,
|
|
2926
|
-
|
|
2927
|
-
|
|
3479
|
+
const fail = (requestId, message, detailCode) => {
|
|
3480
|
+
writeQueueMessage(
|
|
3481
|
+
socket,
|
|
3482
|
+
makeQueueOwnerError(requestId, message, detailCode, {
|
|
3483
|
+
retryable: false
|
|
3484
|
+
})
|
|
3485
|
+
);
|
|
2928
3486
|
socket.end();
|
|
2929
3487
|
};
|
|
2930
3488
|
const processLine = (line) => {
|
|
@@ -2936,12 +3494,16 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2936
3494
|
try {
|
|
2937
3495
|
parsed = JSON.parse(line);
|
|
2938
3496
|
} catch {
|
|
2939
|
-
fail(
|
|
3497
|
+
fail(
|
|
3498
|
+
"unknown",
|
|
3499
|
+
"Invalid queue request payload",
|
|
3500
|
+
"QUEUE_REQUEST_PAYLOAD_INVALID_JSON"
|
|
3501
|
+
);
|
|
2940
3502
|
return;
|
|
2941
3503
|
}
|
|
2942
3504
|
const request = parseQueueRequest(parsed);
|
|
2943
3505
|
if (!request) {
|
|
2944
|
-
fail("unknown", "Invalid queue request");
|
|
3506
|
+
fail("unknown", "Invalid queue request", "QUEUE_REQUEST_INVALID");
|
|
2945
3507
|
return;
|
|
2946
3508
|
}
|
|
2947
3509
|
if (request.type === "cancel_prompt") {
|
|
@@ -2956,12 +3518,14 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2956
3518
|
cancelled: cancelled2
|
|
2957
3519
|
});
|
|
2958
3520
|
}).catch((error) => {
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
3521
|
+
writeQueueMessage(
|
|
3522
|
+
socket,
|
|
3523
|
+
makeQueueOwnerErrorFromUnknown(
|
|
3524
|
+
request.requestId,
|
|
3525
|
+
error,
|
|
3526
|
+
"QUEUE_CONTROL_REQUEST_FAILED"
|
|
3527
|
+
)
|
|
3528
|
+
);
|
|
2965
3529
|
}).finally(() => {
|
|
2966
3530
|
if (!socket.destroyed) {
|
|
2967
3531
|
socket.end();
|
|
@@ -2981,12 +3545,14 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2981
3545
|
modeId: request.modeId
|
|
2982
3546
|
});
|
|
2983
3547
|
}).catch((error) => {
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
3548
|
+
writeQueueMessage(
|
|
3549
|
+
socket,
|
|
3550
|
+
makeQueueOwnerErrorFromUnknown(
|
|
3551
|
+
request.requestId,
|
|
3552
|
+
error,
|
|
3553
|
+
"QUEUE_CONTROL_REQUEST_FAILED"
|
|
3554
|
+
)
|
|
3555
|
+
);
|
|
2990
3556
|
}).finally(() => {
|
|
2991
3557
|
if (!socket.destroyed) {
|
|
2992
3558
|
socket.end();
|
|
@@ -3006,12 +3572,14 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
3006
3572
|
response
|
|
3007
3573
|
});
|
|
3008
3574
|
}).catch((error) => {
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3575
|
+
writeQueueMessage(
|
|
3576
|
+
socket,
|
|
3577
|
+
makeQueueOwnerErrorFromUnknown(
|
|
3578
|
+
request.requestId,
|
|
3579
|
+
error,
|
|
3580
|
+
"QUEUE_CONTROL_REQUEST_FAILED"
|
|
3581
|
+
)
|
|
3582
|
+
);
|
|
3015
3583
|
}).finally(() => {
|
|
3016
3584
|
if (!socket.destroyed) {
|
|
3017
3585
|
socket.end();
|
|
@@ -3023,7 +3591,9 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
3023
3591
|
requestId: request.requestId,
|
|
3024
3592
|
message: request.message,
|
|
3025
3593
|
permissionMode: request.permissionMode,
|
|
3594
|
+
nonInteractivePermissions: request.nonInteractivePermissions,
|
|
3026
3595
|
timeoutMs: request.timeoutMs,
|
|
3596
|
+
suppressSdkConsoleErrors: request.suppressSdkConsoleErrors,
|
|
3027
3597
|
waitForCompletion: request.waitForCompletion,
|
|
3028
3598
|
send: (message) => {
|
|
3029
3599
|
writeQueueMessage(socket, message);
|
|
@@ -3071,9 +3641,16 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3071
3641
|
requestId,
|
|
3072
3642
|
message: options.message,
|
|
3073
3643
|
permissionMode: options.permissionMode,
|
|
3644
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
3074
3645
|
timeoutMs: options.timeoutMs,
|
|
3646
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
3075
3647
|
waitForCompletion: options.waitForCompletion
|
|
3076
3648
|
};
|
|
3649
|
+
options.outputFormatter.setContext({
|
|
3650
|
+
sessionId: options.sessionId,
|
|
3651
|
+
requestId,
|
|
3652
|
+
stream: "prompt"
|
|
3653
|
+
});
|
|
3077
3654
|
return await new Promise((resolve, reject) => {
|
|
3078
3655
|
let settled = false;
|
|
3079
3656
|
let acknowledged = false;
|
|
@@ -3106,16 +3683,33 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3106
3683
|
try {
|
|
3107
3684
|
parsed = JSON.parse(line);
|
|
3108
3685
|
} catch {
|
|
3109
|
-
finishReject(
|
|
3686
|
+
finishReject(
|
|
3687
|
+
new QueueProtocolError("Queue owner sent invalid JSON payload", {
|
|
3688
|
+
detailCode: "QUEUE_PROTOCOL_INVALID_JSON",
|
|
3689
|
+
origin: "queue",
|
|
3690
|
+
retryable: true
|
|
3691
|
+
})
|
|
3692
|
+
);
|
|
3110
3693
|
return;
|
|
3111
3694
|
}
|
|
3112
3695
|
const message = parseQueueOwnerMessage(parsed);
|
|
3113
3696
|
if (!message || message.requestId !== requestId) {
|
|
3114
|
-
finishReject(
|
|
3697
|
+
finishReject(
|
|
3698
|
+
new QueueProtocolError("Queue owner sent malformed message", {
|
|
3699
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
3700
|
+
origin: "queue",
|
|
3701
|
+
retryable: true
|
|
3702
|
+
})
|
|
3703
|
+
);
|
|
3115
3704
|
return;
|
|
3116
3705
|
}
|
|
3117
3706
|
if (message.type === "accepted") {
|
|
3118
3707
|
acknowledged = true;
|
|
3708
|
+
options.outputFormatter.setContext({
|
|
3709
|
+
sessionId: options.sessionId,
|
|
3710
|
+
requestId: message.requestId,
|
|
3711
|
+
stream: "prompt"
|
|
3712
|
+
});
|
|
3119
3713
|
if (!options.waitForCompletion) {
|
|
3120
3714
|
const queued = {
|
|
3121
3715
|
queued: true,
|
|
@@ -3126,9 +3720,41 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3126
3720
|
}
|
|
3127
3721
|
return;
|
|
3128
3722
|
}
|
|
3723
|
+
if (message.type === "error") {
|
|
3724
|
+
options.outputFormatter.setContext({
|
|
3725
|
+
sessionId: options.sessionId,
|
|
3726
|
+
requestId: message.requestId,
|
|
3727
|
+
stream: "prompt"
|
|
3728
|
+
});
|
|
3729
|
+
options.outputFormatter.onError({
|
|
3730
|
+
code: message.code ?? "RUNTIME",
|
|
3731
|
+
detailCode: message.detailCode,
|
|
3732
|
+
origin: message.origin ?? "queue",
|
|
3733
|
+
message: message.message,
|
|
3734
|
+
retryable: message.retryable,
|
|
3735
|
+
acp: message.acp
|
|
3736
|
+
});
|
|
3737
|
+
options.outputFormatter.flush();
|
|
3738
|
+
const queueErrorAlreadyEmitted = options.errorEmissionPolicy?.queueErrorAlreadyEmitted ?? true;
|
|
3739
|
+
finishReject(
|
|
3740
|
+
new QueueConnectionError(message.message, {
|
|
3741
|
+
outputCode: message.code,
|
|
3742
|
+
detailCode: message.detailCode,
|
|
3743
|
+
origin: message.origin ?? "queue",
|
|
3744
|
+
retryable: message.retryable,
|
|
3745
|
+
acp: message.acp,
|
|
3746
|
+
...queueErrorAlreadyEmitted ? { outputAlreadyEmitted: true } : {}
|
|
3747
|
+
})
|
|
3748
|
+
);
|
|
3749
|
+
return;
|
|
3750
|
+
}
|
|
3129
3751
|
if (!acknowledged) {
|
|
3130
3752
|
finishReject(
|
|
3131
|
-
new QueueConnectionError("Queue owner did not acknowledge request"
|
|
3753
|
+
new QueueConnectionError("Queue owner did not acknowledge request", {
|
|
3754
|
+
detailCode: "QUEUE_ACK_MISSING",
|
|
3755
|
+
origin: "queue",
|
|
3756
|
+
retryable: true
|
|
3757
|
+
})
|
|
3132
3758
|
);
|
|
3133
3759
|
return;
|
|
3134
3760
|
}
|
|
@@ -3153,11 +3779,13 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3153
3779
|
finishResolve(message.result);
|
|
3154
3780
|
return;
|
|
3155
3781
|
}
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3782
|
+
finishReject(
|
|
3783
|
+
new QueueProtocolError("Queue owner returned unexpected response", {
|
|
3784
|
+
detailCode: "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE",
|
|
3785
|
+
origin: "queue",
|
|
3786
|
+
retryable: true
|
|
3787
|
+
})
|
|
3788
|
+
);
|
|
3161
3789
|
};
|
|
3162
3790
|
socket.on("data", (chunk) => {
|
|
3163
3791
|
buffer += chunk;
|
|
@@ -3181,7 +3809,12 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3181
3809
|
if (!acknowledged) {
|
|
3182
3810
|
finishReject(
|
|
3183
3811
|
new QueueConnectionError(
|
|
3184
|
-
"Queue owner disconnected before acknowledging request"
|
|
3812
|
+
"Queue owner disconnected before acknowledging request",
|
|
3813
|
+
{
|
|
3814
|
+
detailCode: "QUEUE_DISCONNECTED_BEFORE_ACK",
|
|
3815
|
+
origin: "queue",
|
|
3816
|
+
retryable: true
|
|
3817
|
+
}
|
|
3185
3818
|
)
|
|
3186
3819
|
);
|
|
3187
3820
|
return;
|
|
@@ -3196,7 +3829,11 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3196
3829
|
return;
|
|
3197
3830
|
}
|
|
3198
3831
|
finishReject(
|
|
3199
|
-
new QueueConnectionError("Queue owner disconnected before prompt completion"
|
|
3832
|
+
new QueueConnectionError("Queue owner disconnected before prompt completion", {
|
|
3833
|
+
detailCode: "QUEUE_DISCONNECTED_BEFORE_COMPLETION",
|
|
3834
|
+
origin: "queue",
|
|
3835
|
+
retryable: true
|
|
3836
|
+
})
|
|
3200
3837
|
);
|
|
3201
3838
|
});
|
|
3202
3839
|
socket.write(`${JSON.stringify(request)}
|
|
@@ -3240,31 +3877,59 @@ async function submitControlToQueueOwner(owner, request, isExpectedResponse) {
|
|
|
3240
3877
|
try {
|
|
3241
3878
|
parsed = JSON.parse(line);
|
|
3242
3879
|
} catch {
|
|
3243
|
-
finishReject(
|
|
3880
|
+
finishReject(
|
|
3881
|
+
new QueueProtocolError("Queue owner sent invalid JSON payload", {
|
|
3882
|
+
detailCode: "QUEUE_PROTOCOL_INVALID_JSON",
|
|
3883
|
+
origin: "queue",
|
|
3884
|
+
retryable: true
|
|
3885
|
+
})
|
|
3886
|
+
);
|
|
3244
3887
|
return;
|
|
3245
3888
|
}
|
|
3246
3889
|
const message = parseQueueOwnerMessage(parsed);
|
|
3247
3890
|
if (!message || message.requestId !== request.requestId) {
|
|
3248
|
-
finishReject(
|
|
3891
|
+
finishReject(
|
|
3892
|
+
new QueueProtocolError("Queue owner sent malformed message", {
|
|
3893
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
3894
|
+
origin: "queue",
|
|
3895
|
+
retryable: true
|
|
3896
|
+
})
|
|
3897
|
+
);
|
|
3249
3898
|
return;
|
|
3250
3899
|
}
|
|
3251
3900
|
if (message.type === "accepted") {
|
|
3252
3901
|
acknowledged = true;
|
|
3253
3902
|
return;
|
|
3254
3903
|
}
|
|
3255
|
-
if (
|
|
3904
|
+
if (message.type === "error") {
|
|
3256
3905
|
finishReject(
|
|
3257
|
-
new QueueConnectionError(
|
|
3906
|
+
new QueueConnectionError(message.message, {
|
|
3907
|
+
outputCode: message.code,
|
|
3908
|
+
detailCode: message.detailCode,
|
|
3909
|
+
origin: message.origin ?? "queue",
|
|
3910
|
+
retryable: message.retryable,
|
|
3911
|
+
acp: message.acp
|
|
3912
|
+
})
|
|
3258
3913
|
);
|
|
3259
3914
|
return;
|
|
3260
3915
|
}
|
|
3261
|
-
if (
|
|
3262
|
-
finishReject(
|
|
3916
|
+
if (!acknowledged) {
|
|
3917
|
+
finishReject(
|
|
3918
|
+
new QueueConnectionError("Queue owner did not acknowledge request", {
|
|
3919
|
+
detailCode: "QUEUE_ACK_MISSING",
|
|
3920
|
+
origin: "queue",
|
|
3921
|
+
retryable: true
|
|
3922
|
+
})
|
|
3923
|
+
);
|
|
3263
3924
|
return;
|
|
3264
3925
|
}
|
|
3265
3926
|
if (!isExpectedResponse(message)) {
|
|
3266
3927
|
finishReject(
|
|
3267
|
-
new QueueProtocolError("Queue owner returned unexpected response"
|
|
3928
|
+
new QueueProtocolError("Queue owner returned unexpected response", {
|
|
3929
|
+
detailCode: "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE",
|
|
3930
|
+
origin: "queue",
|
|
3931
|
+
retryable: true
|
|
3932
|
+
})
|
|
3268
3933
|
);
|
|
3269
3934
|
return;
|
|
3270
3935
|
}
|
|
@@ -3292,13 +3957,22 @@ async function submitControlToQueueOwner(owner, request, isExpectedResponse) {
|
|
|
3292
3957
|
if (!acknowledged) {
|
|
3293
3958
|
finishReject(
|
|
3294
3959
|
new QueueConnectionError(
|
|
3295
|
-
"Queue owner disconnected before acknowledging request"
|
|
3960
|
+
"Queue owner disconnected before acknowledging request",
|
|
3961
|
+
{
|
|
3962
|
+
detailCode: "QUEUE_DISCONNECTED_BEFORE_ACK",
|
|
3963
|
+
origin: "queue",
|
|
3964
|
+
retryable: true
|
|
3965
|
+
}
|
|
3296
3966
|
)
|
|
3297
3967
|
);
|
|
3298
3968
|
return;
|
|
3299
3969
|
}
|
|
3300
3970
|
finishReject(
|
|
3301
|
-
new QueueConnectionError("Queue owner disconnected before responding"
|
|
3971
|
+
new QueueConnectionError("Queue owner disconnected before responding", {
|
|
3972
|
+
detailCode: "QUEUE_DISCONNECTED_BEFORE_COMPLETION",
|
|
3973
|
+
origin: "queue",
|
|
3974
|
+
retryable: true
|
|
3975
|
+
})
|
|
3302
3976
|
);
|
|
3303
3977
|
});
|
|
3304
3978
|
socket.write(`${JSON.stringify(request)}
|
|
@@ -3319,7 +3993,11 @@ async function submitCancelToQueueOwner(owner) {
|
|
|
3319
3993
|
return void 0;
|
|
3320
3994
|
}
|
|
3321
3995
|
if (response.requestId !== request.requestId) {
|
|
3322
|
-
throw new QueueProtocolError("Queue owner returned mismatched cancel response"
|
|
3996
|
+
throw new QueueProtocolError("Queue owner returned mismatched cancel response", {
|
|
3997
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
3998
|
+
origin: "queue",
|
|
3999
|
+
retryable: true
|
|
4000
|
+
});
|
|
3323
4001
|
}
|
|
3324
4002
|
return response.cancelled;
|
|
3325
4003
|
}
|
|
@@ -3339,7 +4017,11 @@ async function submitSetModeToQueueOwner(owner, modeId, timeoutMs) {
|
|
|
3339
4017
|
return void 0;
|
|
3340
4018
|
}
|
|
3341
4019
|
if (response.requestId !== request.requestId) {
|
|
3342
|
-
throw new QueueProtocolError("Queue owner returned mismatched set_mode response"
|
|
4020
|
+
throw new QueueProtocolError("Queue owner returned mismatched set_mode response", {
|
|
4021
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
4022
|
+
origin: "queue",
|
|
4023
|
+
retryable: true
|
|
4024
|
+
});
|
|
3343
4025
|
}
|
|
3344
4026
|
return true;
|
|
3345
4027
|
}
|
|
@@ -3361,7 +4043,12 @@ async function submitSetConfigOptionToQueueOwner(owner, configId, value, timeout
|
|
|
3361
4043
|
}
|
|
3362
4044
|
if (response.requestId !== request.requestId) {
|
|
3363
4045
|
throw new QueueProtocolError(
|
|
3364
|
-
"Queue owner returned mismatched set_config_option response"
|
|
4046
|
+
"Queue owner returned mismatched set_config_option response",
|
|
4047
|
+
{
|
|
4048
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
4049
|
+
origin: "queue",
|
|
4050
|
+
retryable: true
|
|
4051
|
+
}
|
|
3365
4052
|
);
|
|
3366
4053
|
}
|
|
3367
4054
|
return response.response;
|
|
@@ -3390,7 +4077,12 @@ async function trySubmitToRunningOwner(options) {
|
|
|
3390
4077
|
return void 0;
|
|
3391
4078
|
}
|
|
3392
4079
|
throw new QueueConnectionError(
|
|
3393
|
-
"Session queue owner is running but not accepting queue requests"
|
|
4080
|
+
"Session queue owner is running but not accepting queue requests",
|
|
4081
|
+
{
|
|
4082
|
+
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
4083
|
+
origin: "queue",
|
|
4084
|
+
retryable: true
|
|
4085
|
+
}
|
|
3394
4086
|
);
|
|
3395
4087
|
}
|
|
3396
4088
|
async function tryCancelOnRunningOwner(options) {
|
|
@@ -3417,7 +4109,12 @@ async function tryCancelOnRunningOwner(options) {
|
|
|
3417
4109
|
return void 0;
|
|
3418
4110
|
}
|
|
3419
4111
|
throw new QueueConnectionError(
|
|
3420
|
-
"Session queue owner is running but not accepting cancel requests"
|
|
4112
|
+
"Session queue owner is running but not accepting cancel requests",
|
|
4113
|
+
{
|
|
4114
|
+
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
4115
|
+
origin: "queue",
|
|
4116
|
+
retryable: true
|
|
4117
|
+
}
|
|
3421
4118
|
);
|
|
3422
4119
|
}
|
|
3423
4120
|
async function trySetModeOnRunningOwner(sessionId, modeId, timeoutMs, verbose) {
|
|
@@ -3444,7 +4141,12 @@ async function trySetModeOnRunningOwner(sessionId, modeId, timeoutMs, verbose) {
|
|
|
3444
4141
|
return void 0;
|
|
3445
4142
|
}
|
|
3446
4143
|
throw new QueueConnectionError(
|
|
3447
|
-
"Session queue owner is running but not accepting set_mode requests"
|
|
4144
|
+
"Session queue owner is running but not accepting set_mode requests",
|
|
4145
|
+
{
|
|
4146
|
+
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
4147
|
+
origin: "queue",
|
|
4148
|
+
retryable: true
|
|
4149
|
+
}
|
|
3448
4150
|
);
|
|
3449
4151
|
}
|
|
3450
4152
|
async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, timeoutMs, verbose) {
|
|
@@ -3476,7 +4178,12 @@ async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, time
|
|
|
3476
4178
|
return void 0;
|
|
3477
4179
|
}
|
|
3478
4180
|
throw new QueueConnectionError(
|
|
3479
|
-
"Session queue owner is running but not accepting set_config_option requests"
|
|
4181
|
+
"Session queue owner is running but not accepting set_config_option requests",
|
|
4182
|
+
{
|
|
4183
|
+
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
4184
|
+
origin: "queue",
|
|
4185
|
+
retryable: true
|
|
4186
|
+
}
|
|
3480
4187
|
);
|
|
3481
4188
|
}
|
|
3482
4189
|
async function terminateQueueOwnerForSession(sessionId) {
|
|
@@ -3537,6 +4244,7 @@ function parseSessionRecord(raw) {
|
|
|
3537
4244
|
return null;
|
|
3538
4245
|
}
|
|
3539
4246
|
const record = raw;
|
|
4247
|
+
const runtimeSessionId = normalizeRuntimeSessionId(record.runtimeSessionId);
|
|
3540
4248
|
const name = record.name == null ? void 0 : typeof record.name === "string" && record.name.trim().length > 0 ? record.name.trim() : null;
|
|
3541
4249
|
const pid = record.pid == null ? void 0 : Number.isInteger(record.pid) && record.pid > 0 ? record.pid : null;
|
|
3542
4250
|
const closed = record.closed == null ? false : typeof record.closed === "boolean" ? record.closed : null;
|
|
@@ -3559,6 +4267,7 @@ function parseSessionRecord(raw) {
|
|
|
3559
4267
|
...record,
|
|
3560
4268
|
id: record.id,
|
|
3561
4269
|
sessionId: record.sessionId,
|
|
4270
|
+
runtimeSessionId,
|
|
3562
4271
|
agentCommand: record.agentCommand,
|
|
3563
4272
|
cwd: record.cwd,
|
|
3564
4273
|
name,
|
|
@@ -3815,6 +4524,8 @@ var QueueTaskOutputFormatter = class {
|
|
|
3815
4524
|
this.requestId = task.requestId;
|
|
3816
4525
|
this.send = task.send;
|
|
3817
4526
|
}
|
|
4527
|
+
setContext() {
|
|
4528
|
+
}
|
|
3818
4529
|
onSessionUpdate(notification) {
|
|
3819
4530
|
this.send({
|
|
3820
4531
|
type: "session_update",
|
|
@@ -3836,16 +4547,32 @@ var QueueTaskOutputFormatter = class {
|
|
|
3836
4547
|
stopReason
|
|
3837
4548
|
});
|
|
3838
4549
|
}
|
|
4550
|
+
onError(params) {
|
|
4551
|
+
this.send({
|
|
4552
|
+
type: "error",
|
|
4553
|
+
requestId: this.requestId,
|
|
4554
|
+
code: params.code,
|
|
4555
|
+
detailCode: params.detailCode,
|
|
4556
|
+
origin: params.origin,
|
|
4557
|
+
message: params.message,
|
|
4558
|
+
retryable: params.retryable,
|
|
4559
|
+
acp: params.acp
|
|
4560
|
+
});
|
|
4561
|
+
}
|
|
3839
4562
|
flush() {
|
|
3840
4563
|
}
|
|
3841
4564
|
};
|
|
3842
4565
|
var DISCARD_OUTPUT_FORMATTER = {
|
|
4566
|
+
setContext() {
|
|
4567
|
+
},
|
|
3843
4568
|
onSessionUpdate() {
|
|
3844
4569
|
},
|
|
3845
4570
|
onClientOperation() {
|
|
3846
4571
|
},
|
|
3847
4572
|
onDone() {
|
|
3848
4573
|
},
|
|
4574
|
+
onError() {
|
|
4575
|
+
},
|
|
3849
4576
|
flush() {
|
|
3850
4577
|
}
|
|
3851
4578
|
};
|
|
@@ -3858,22 +4585,6 @@ function normalizeQueueOwnerTtlMs(ttlMs) {
|
|
|
3858
4585
|
}
|
|
3859
4586
|
return Math.round(ttlMs);
|
|
3860
4587
|
}
|
|
3861
|
-
function formatError2(error) {
|
|
3862
|
-
if (error instanceof Error) {
|
|
3863
|
-
return error.message;
|
|
3864
|
-
}
|
|
3865
|
-
if (error && typeof error === "object") {
|
|
3866
|
-
const maybeMessage = error.message;
|
|
3867
|
-
if (typeof maybeMessage === "string" && maybeMessage.length > 0) {
|
|
3868
|
-
return maybeMessage;
|
|
3869
|
-
}
|
|
3870
|
-
try {
|
|
3871
|
-
return JSON.stringify(error);
|
|
3872
|
-
} catch {
|
|
3873
|
-
}
|
|
3874
|
-
}
|
|
3875
|
-
return String(error);
|
|
3876
|
-
}
|
|
3877
4588
|
function collapseWhitespace2(value) {
|
|
3878
4589
|
return value.replace(/\s+/g, " ").trim();
|
|
3879
4590
|
}
|
|
@@ -3949,16 +4660,18 @@ function applyLifecycleSnapshotToRecord(record, snapshot) {
|
|
|
3949
4660
|
record.lastAgentExitAt = void 0;
|
|
3950
4661
|
record.lastAgentDisconnectReason = void 0;
|
|
3951
4662
|
}
|
|
4663
|
+
function reconcileRuntimeSessionId(record, runtimeSessionId) {
|
|
4664
|
+
const normalized = normalizeRuntimeSessionId(runtimeSessionId);
|
|
4665
|
+
if (!normalized) {
|
|
4666
|
+
return;
|
|
4667
|
+
}
|
|
4668
|
+
record.runtimeSessionId = normalized;
|
|
4669
|
+
}
|
|
3952
4670
|
function shouldFallbackToNewSession(error) {
|
|
3953
4671
|
if (error instanceof TimeoutError || error instanceof InterruptedError) {
|
|
3954
4672
|
return false;
|
|
3955
4673
|
}
|
|
3956
|
-
|
|
3957
|
-
if (message.includes("resource_not_found") || message.includes("resource not found") || message.includes("session not found") || message.includes("unknown session") || message.includes("invalid session")) {
|
|
3958
|
-
return true;
|
|
3959
|
-
}
|
|
3960
|
-
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
3961
|
-
return code === -32001 || code === -32002;
|
|
4674
|
+
return isAcpResourceNotFoundError(error);
|
|
3962
4675
|
}
|
|
3963
4676
|
async function connectAndLoadSession(options) {
|
|
3964
4677
|
const record = options.record;
|
|
@@ -3990,31 +4703,40 @@ async function connectAndLoadSession(options) {
|
|
|
3990
4703
|
let sessionId = record.sessionId;
|
|
3991
4704
|
if (client.supportsLoadSession()) {
|
|
3992
4705
|
try {
|
|
3993
|
-
await withTimeout(
|
|
4706
|
+
const loadResult = await withTimeout(
|
|
3994
4707
|
client.loadSessionWithOptions(record.sessionId, record.cwd, {
|
|
3995
4708
|
suppressReplayUpdates: true
|
|
3996
4709
|
}),
|
|
3997
4710
|
options.timeoutMs
|
|
3998
4711
|
);
|
|
4712
|
+
reconcileRuntimeSessionId(record, loadResult.runtimeSessionId);
|
|
3999
4713
|
resumed = true;
|
|
4000
4714
|
} catch (error) {
|
|
4001
|
-
loadError =
|
|
4715
|
+
loadError = formatErrorMessage(error);
|
|
4002
4716
|
if (!shouldFallbackToNewSession(error)) {
|
|
4003
4717
|
throw error;
|
|
4004
4718
|
}
|
|
4005
|
-
|
|
4719
|
+
const createdSession = await withTimeout(
|
|
4006
4720
|
client.createSession(record.cwd),
|
|
4007
4721
|
options.timeoutMs
|
|
4008
4722
|
);
|
|
4723
|
+
sessionId = createdSession.sessionId;
|
|
4009
4724
|
record.sessionId = sessionId;
|
|
4725
|
+
reconcileRuntimeSessionId(record, createdSession.runtimeSessionId);
|
|
4010
4726
|
}
|
|
4011
4727
|
} else {
|
|
4012
|
-
|
|
4728
|
+
const createdSession = await withTimeout(
|
|
4729
|
+
client.createSession(record.cwd),
|
|
4730
|
+
options.timeoutMs
|
|
4731
|
+
);
|
|
4732
|
+
sessionId = createdSession.sessionId;
|
|
4013
4733
|
record.sessionId = sessionId;
|
|
4734
|
+
reconcileRuntimeSessionId(record, createdSession.runtimeSessionId);
|
|
4014
4735
|
}
|
|
4015
4736
|
options.onSessionIdResolved?.(sessionId);
|
|
4016
4737
|
return {
|
|
4017
4738
|
sessionId,
|
|
4739
|
+
runtimeSessionId: record.runtimeSessionId,
|
|
4018
4740
|
resumed,
|
|
4019
4741
|
loadError
|
|
4020
4742
|
};
|
|
@@ -4026,10 +4748,12 @@ async function runQueuedTask(sessionRecordId, task, options) {
|
|
|
4026
4748
|
sessionRecordId,
|
|
4027
4749
|
message: task.message,
|
|
4028
4750
|
permissionMode: task.permissionMode,
|
|
4751
|
+
nonInteractivePermissions: task.nonInteractivePermissions ?? options.nonInteractivePermissions,
|
|
4029
4752
|
authCredentials: options.authCredentials,
|
|
4030
4753
|
authPolicy: options.authPolicy,
|
|
4031
4754
|
outputFormatter,
|
|
4032
4755
|
timeoutMs: task.timeoutMs,
|
|
4756
|
+
suppressSdkConsoleErrors: task.suppressSdkConsoleErrors ?? options.suppressSdkConsoleErrors,
|
|
4033
4757
|
verbose: options.verbose,
|
|
4034
4758
|
onClientAvailable: options.onClientAvailable,
|
|
4035
4759
|
onClientClosed: options.onClientClosed,
|
|
@@ -4043,12 +4767,20 @@ async function runQueuedTask(sessionRecordId, task, options) {
|
|
|
4043
4767
|
});
|
|
4044
4768
|
}
|
|
4045
4769
|
} catch (error) {
|
|
4046
|
-
const
|
|
4770
|
+
const normalizedError = normalizeOutputError(error, {
|
|
4771
|
+
origin: "runtime",
|
|
4772
|
+
detailCode: "QUEUE_RUNTIME_PROMPT_FAILED"
|
|
4773
|
+
});
|
|
4047
4774
|
if (task.waitForCompletion) {
|
|
4048
4775
|
task.send({
|
|
4049
4776
|
type: "error",
|
|
4050
4777
|
requestId: task.requestId,
|
|
4051
|
-
|
|
4778
|
+
code: normalizedError.code,
|
|
4779
|
+
detailCode: normalizedError.detailCode,
|
|
4780
|
+
origin: normalizedError.origin,
|
|
4781
|
+
message: normalizedError.message,
|
|
4782
|
+
retryable: normalizedError.retryable,
|
|
4783
|
+
acp: normalizedError.acp
|
|
4052
4784
|
});
|
|
4053
4785
|
}
|
|
4054
4786
|
if (error instanceof InterruptedError) {
|
|
@@ -4061,13 +4793,19 @@ async function runQueuedTask(sessionRecordId, task, options) {
|
|
|
4061
4793
|
async function runSessionPrompt(options) {
|
|
4062
4794
|
const output = options.outputFormatter;
|
|
4063
4795
|
const record = await resolveSessionRecord(options.sessionRecordId);
|
|
4796
|
+
output.setContext({
|
|
4797
|
+
sessionId: record.id,
|
|
4798
|
+
stream: "prompt"
|
|
4799
|
+
});
|
|
4064
4800
|
const assistantSnippets = [];
|
|
4065
4801
|
const client = new AcpClient({
|
|
4066
4802
|
agentCommand: record.agentCommand,
|
|
4067
4803
|
cwd: absolutePath(record.cwd),
|
|
4068
4804
|
permissionMode: options.permissionMode,
|
|
4805
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4069
4806
|
authCredentials: options.authCredentials,
|
|
4070
4807
|
authPolicy: options.authPolicy,
|
|
4808
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4071
4809
|
verbose: options.verbose,
|
|
4072
4810
|
onSessionUpdate: (notification) => {
|
|
4073
4811
|
output.onSessionUpdate(notification);
|
|
@@ -4129,7 +4867,7 @@ async function runSessionPrompt(options) {
|
|
|
4129
4867
|
} catch (error) {
|
|
4130
4868
|
if (options.verbose) {
|
|
4131
4869
|
process.stderr.write(
|
|
4132
|
-
`[acpx] onPromptActive hook failed: ${
|
|
4870
|
+
`[acpx] onPromptActive hook failed: ${formatErrorMessage(error)}
|
|
4133
4871
|
`
|
|
4134
4872
|
);
|
|
4135
4873
|
}
|
|
@@ -4209,6 +4947,7 @@ async function withConnectedSession(options) {
|
|
|
4209
4947
|
agentCommand: record.agentCommand,
|
|
4210
4948
|
cwd: absolutePath(record.cwd),
|
|
4211
4949
|
permissionMode: options.permissionMode ?? "approve-reads",
|
|
4950
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4212
4951
|
authCredentials: options.authCredentials,
|
|
4213
4952
|
authPolicy: options.authPolicy,
|
|
4214
4953
|
verbose: options.verbose
|
|
@@ -4288,6 +5027,7 @@ async function withConnectedSession(options) {
|
|
|
4288
5027
|
async function runSessionSetModeDirect(options) {
|
|
4289
5028
|
const result = await withConnectedSession({
|
|
4290
5029
|
sessionRecordId: options.sessionRecordId,
|
|
5030
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4291
5031
|
authCredentials: options.authCredentials,
|
|
4292
5032
|
authPolicy: options.authPolicy,
|
|
4293
5033
|
timeoutMs: options.timeoutMs,
|
|
@@ -4310,6 +5050,7 @@ async function runSessionSetModeDirect(options) {
|
|
|
4310
5050
|
async function runSessionSetConfigOptionDirect(options) {
|
|
4311
5051
|
const result = await withConnectedSession({
|
|
4312
5052
|
sessionRecordId: options.sessionRecordId,
|
|
5053
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4313
5054
|
authCredentials: options.authCredentials,
|
|
4314
5055
|
authPolicy: options.authPolicy,
|
|
4315
5056
|
timeoutMs: options.timeoutMs,
|
|
@@ -4336,8 +5077,10 @@ async function runOnce(options) {
|
|
|
4336
5077
|
agentCommand: options.agentCommand,
|
|
4337
5078
|
cwd: absolutePath(options.cwd),
|
|
4338
5079
|
permissionMode: options.permissionMode,
|
|
5080
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4339
5081
|
authCredentials: options.authCredentials,
|
|
4340
5082
|
authPolicy: options.authPolicy,
|
|
5083
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4341
5084
|
verbose: options.verbose,
|
|
4342
5085
|
onSessionUpdate: (notification) => output.onSessionUpdate(notification),
|
|
4343
5086
|
onClientOperation: (operation) => output.onClientOperation(operation)
|
|
@@ -4346,10 +5089,15 @@ async function runOnce(options) {
|
|
|
4346
5089
|
return await withInterrupt(
|
|
4347
5090
|
async () => {
|
|
4348
5091
|
await withTimeout(client.start(), options.timeoutMs);
|
|
4349
|
-
const
|
|
5092
|
+
const createdSession = await withTimeout(
|
|
4350
5093
|
client.createSession(absolutePath(options.cwd)),
|
|
4351
5094
|
options.timeoutMs
|
|
4352
5095
|
);
|
|
5096
|
+
const sessionId = createdSession.sessionId;
|
|
5097
|
+
output.setContext({
|
|
5098
|
+
sessionId,
|
|
5099
|
+
stream: "prompt"
|
|
5100
|
+
});
|
|
4353
5101
|
const response = await withTimeout(
|
|
4354
5102
|
client.prompt(sessionId, options.message),
|
|
4355
5103
|
options.timeoutMs
|
|
@@ -4372,6 +5120,7 @@ async function createSession(options) {
|
|
|
4372
5120
|
agentCommand: options.agentCommand,
|
|
4373
5121
|
cwd: absolutePath(options.cwd),
|
|
4374
5122
|
permissionMode: options.permissionMode,
|
|
5123
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4375
5124
|
authCredentials: options.authCredentials,
|
|
4376
5125
|
authPolicy: options.authPolicy,
|
|
4377
5126
|
verbose: options.verbose
|
|
@@ -4380,15 +5129,17 @@ async function createSession(options) {
|
|
|
4380
5129
|
return await withInterrupt(
|
|
4381
5130
|
async () => {
|
|
4382
5131
|
await withTimeout(client.start(), options.timeoutMs);
|
|
4383
|
-
const
|
|
5132
|
+
const createdSession = await withTimeout(
|
|
4384
5133
|
client.createSession(absolutePath(options.cwd)),
|
|
4385
5134
|
options.timeoutMs
|
|
4386
5135
|
);
|
|
5136
|
+
const sessionId = createdSession.sessionId;
|
|
4387
5137
|
const lifecycle = client.getAgentLifecycleSnapshot();
|
|
4388
5138
|
const now = isoNow2();
|
|
4389
5139
|
const record = {
|
|
4390
5140
|
id: sessionId,
|
|
4391
5141
|
sessionId,
|
|
5142
|
+
runtimeSessionId: createdSession.runtimeSessionId,
|
|
4392
5143
|
agentCommand: options.agentCommand,
|
|
4393
5144
|
cwd: absolutePath(options.cwd),
|
|
4394
5145
|
name: normalizeName(options.name),
|
|
@@ -4413,6 +5164,38 @@ async function createSession(options) {
|
|
|
4413
5164
|
await client.close();
|
|
4414
5165
|
}
|
|
4415
5166
|
}
|
|
5167
|
+
async function ensureSession(options) {
|
|
5168
|
+
const cwd = absolutePath(options.cwd);
|
|
5169
|
+
const gitRoot = findGitRepositoryRoot(cwd);
|
|
5170
|
+
const walkBoundary = options.walkBoundary ?? gitRoot ?? cwd;
|
|
5171
|
+
const existing = await findSessionByDirectoryWalk({
|
|
5172
|
+
agentCommand: options.agentCommand,
|
|
5173
|
+
cwd,
|
|
5174
|
+
name: options.name,
|
|
5175
|
+
boundary: walkBoundary
|
|
5176
|
+
});
|
|
5177
|
+
if (existing) {
|
|
5178
|
+
return {
|
|
5179
|
+
record: existing,
|
|
5180
|
+
created: false
|
|
5181
|
+
};
|
|
5182
|
+
}
|
|
5183
|
+
const record = await createSession({
|
|
5184
|
+
agentCommand: options.agentCommand,
|
|
5185
|
+
cwd,
|
|
5186
|
+
name: options.name,
|
|
5187
|
+
permissionMode: options.permissionMode,
|
|
5188
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
5189
|
+
authCredentials: options.authCredentials,
|
|
5190
|
+
authPolicy: options.authPolicy,
|
|
5191
|
+
timeoutMs: options.timeoutMs,
|
|
5192
|
+
verbose: options.verbose
|
|
5193
|
+
});
|
|
5194
|
+
return {
|
|
5195
|
+
record,
|
|
5196
|
+
created: true
|
|
5197
|
+
};
|
|
5198
|
+
}
|
|
4416
5199
|
async function sendSession(options) {
|
|
4417
5200
|
const waitForCompletion = options.waitForCompletion !== false;
|
|
4418
5201
|
const queueOwnerTtlMs = normalizeQueueOwnerTtlMs(options.ttlMs);
|
|
@@ -4420,8 +5203,11 @@ async function sendSession(options) {
|
|
|
4420
5203
|
sessionId: options.sessionId,
|
|
4421
5204
|
message: options.message,
|
|
4422
5205
|
permissionMode: options.permissionMode,
|
|
5206
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4423
5207
|
outputFormatter: options.outputFormatter,
|
|
5208
|
+
errorEmissionPolicy: options.errorEmissionPolicy,
|
|
4424
5209
|
timeoutMs: options.timeoutMs,
|
|
5210
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4425
5211
|
waitForCompletion,
|
|
4426
5212
|
verbose: options.verbose
|
|
4427
5213
|
});
|
|
@@ -4435,8 +5221,11 @@ async function sendSession(options) {
|
|
|
4435
5221
|
sessionId: options.sessionId,
|
|
4436
5222
|
message: options.message,
|
|
4437
5223
|
permissionMode: options.permissionMode,
|
|
5224
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4438
5225
|
outputFormatter: options.outputFormatter,
|
|
5226
|
+
errorEmissionPolicy: options.errorEmissionPolicy,
|
|
4439
5227
|
timeoutMs: options.timeoutMs,
|
|
5228
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4440
5229
|
waitForCompletion,
|
|
4441
5230
|
verbose: options.verbose
|
|
4442
5231
|
});
|
|
@@ -4453,6 +5242,7 @@ async function sendSession(options) {
|
|
|
4453
5242
|
await runSessionSetModeDirect({
|
|
4454
5243
|
sessionRecordId: options.sessionId,
|
|
4455
5244
|
modeId,
|
|
5245
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4456
5246
|
authCredentials: options.authCredentials,
|
|
4457
5247
|
authPolicy: options.authPolicy,
|
|
4458
5248
|
timeoutMs,
|
|
@@ -4464,6 +5254,7 @@ async function sendSession(options) {
|
|
|
4464
5254
|
sessionRecordId: options.sessionId,
|
|
4465
5255
|
configId,
|
|
4466
5256
|
value,
|
|
5257
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4467
5258
|
authCredentials: options.authCredentials,
|
|
4468
5259
|
authPolicy: options.authPolicy,
|
|
4469
5260
|
timeoutMs,
|
|
@@ -4479,7 +5270,7 @@ async function sendSession(options) {
|
|
|
4479
5270
|
void applyPendingCancel().catch((error) => {
|
|
4480
5271
|
if (options.verbose) {
|
|
4481
5272
|
process.stderr.write(
|
|
4482
|
-
`[acpx] failed to apply deferred cancel: ${
|
|
5273
|
+
`[acpx] failed to apply deferred cancel: ${formatErrorMessage(error)}
|
|
4483
5274
|
`
|
|
4484
5275
|
);
|
|
4485
5276
|
}
|
|
@@ -4526,10 +5317,12 @@ async function sendSession(options) {
|
|
|
4526
5317
|
sessionRecordId: options.sessionId,
|
|
4527
5318
|
message: options.message,
|
|
4528
5319
|
permissionMode: options.permissionMode,
|
|
5320
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4529
5321
|
authCredentials: options.authCredentials,
|
|
4530
5322
|
authPolicy: options.authPolicy,
|
|
4531
5323
|
outputFormatter: options.outputFormatter,
|
|
4532
5324
|
timeoutMs: options.timeoutMs,
|
|
5325
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4533
5326
|
verbose: options.verbose,
|
|
4534
5327
|
onClientAvailable: setActiveController,
|
|
4535
5328
|
onClientClosed: clearActiveController,
|
|
@@ -4554,8 +5347,10 @@ async function sendSession(options) {
|
|
|
4554
5347
|
await runPromptTurn(async () => {
|
|
4555
5348
|
await runQueuedTask(options.sessionId, task, {
|
|
4556
5349
|
verbose: options.verbose,
|
|
5350
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4557
5351
|
authCredentials: options.authCredentials,
|
|
4558
5352
|
authPolicy: options.authPolicy,
|
|
5353
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4559
5354
|
onClientAvailable: setActiveController,
|
|
4560
5355
|
onClientClosed: clearActiveController,
|
|
4561
5356
|
onPromptActive: async () => {
|
|
@@ -4598,6 +5393,7 @@ async function setSessionMode(options) {
|
|
|
4598
5393
|
return await runSessionSetModeDirect({
|
|
4599
5394
|
sessionRecordId: options.sessionId,
|
|
4600
5395
|
modeId: options.modeId,
|
|
5396
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4601
5397
|
authCredentials: options.authCredentials,
|
|
4602
5398
|
authPolicy: options.authPolicy,
|
|
4603
5399
|
timeoutMs: options.timeoutMs,
|
|
@@ -4623,6 +5419,7 @@ async function setSessionConfigOption(options) {
|
|
|
4623
5419
|
sessionRecordId: options.sessionId,
|
|
4624
5420
|
configId: options.configId,
|
|
4625
5421
|
value: options.value,
|
|
5422
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4626
5423
|
authCredentials: options.authCredentials,
|
|
4627
5424
|
authPolicy: options.authPolicy,
|
|
4628
5425
|
timeoutMs: options.timeoutMs,
|
|
@@ -4669,19 +5466,6 @@ async function closeSession(sessionId) {
|
|
|
4669
5466
|
return record;
|
|
4670
5467
|
}
|
|
4671
5468
|
|
|
4672
|
-
// src/types.ts
|
|
4673
|
-
var EXIT_CODES = {
|
|
4674
|
-
SUCCESS: 0,
|
|
4675
|
-
ERROR: 1,
|
|
4676
|
-
USAGE: 2,
|
|
4677
|
-
TIMEOUT: 3,
|
|
4678
|
-
NO_SESSION: 4,
|
|
4679
|
-
PERMISSION_DENIED: 5,
|
|
4680
|
-
INTERRUPTED: 130
|
|
4681
|
-
};
|
|
4682
|
-
var OUTPUT_FORMATS = ["text", "json", "quiet"];
|
|
4683
|
-
var AUTH_POLICIES = ["skip", "fail"];
|
|
4684
|
-
|
|
4685
5469
|
// src/cli.ts
|
|
4686
5470
|
var NoSessionError = class extends Error {
|
|
4687
5471
|
constructor(message) {
|
|
@@ -4716,6 +5500,16 @@ function parseAuthPolicy2(value) {
|
|
|
4716
5500
|
}
|
|
4717
5501
|
return value;
|
|
4718
5502
|
}
|
|
5503
|
+
function parseNonInteractivePermissionPolicy2(value) {
|
|
5504
|
+
if (!NON_INTERACTIVE_PERMISSION_POLICIES.includes(
|
|
5505
|
+
value
|
|
5506
|
+
)) {
|
|
5507
|
+
throw new InvalidArgumentError(
|
|
5508
|
+
`Invalid non-interactive permission policy "${value}". Expected one of: ${NON_INTERACTIVE_PERMISSION_POLICIES.join(", ")}`
|
|
5509
|
+
);
|
|
5510
|
+
}
|
|
5511
|
+
return value;
|
|
5512
|
+
}
|
|
4719
5513
|
function parseTimeoutSeconds(value) {
|
|
4720
5514
|
const parsed = Number(value);
|
|
4721
5515
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
@@ -4817,7 +5611,14 @@ function addGlobalFlags(command) {
|
|
|
4817
5611
|
).option("--approve-all", "Auto-approve all permission requests").option(
|
|
4818
5612
|
"--approve-reads",
|
|
4819
5613
|
"Auto-approve read/search requests and prompt for writes"
|
|
4820
|
-
).option("--deny-all", "Deny all permission requests").option(
|
|
5614
|
+
).option("--deny-all", "Deny all permission requests").option(
|
|
5615
|
+
"--non-interactive-permissions <policy>",
|
|
5616
|
+
"When prompting is unavailable: deny or fail",
|
|
5617
|
+
parseNonInteractivePermissionPolicy2
|
|
5618
|
+
).option("--format <fmt>", "Output format: text, json, quiet", parseOutputFormat2).option(
|
|
5619
|
+
"--json-strict",
|
|
5620
|
+
"Strict JSON mode: requires --format json and suppresses non-JSON stderr output"
|
|
5621
|
+
).option(
|
|
4821
5622
|
"--timeout <seconds>",
|
|
4822
5623
|
"Maximum time to wait for agent response",
|
|
4823
5624
|
parseTimeoutSeconds
|
|
@@ -4866,19 +5667,39 @@ function addPromptInputOption(command) {
|
|
|
4866
5667
|
}
|
|
4867
5668
|
function resolveGlobalFlags(command, config) {
|
|
4868
5669
|
const opts = command.optsWithGlobals();
|
|
5670
|
+
const format = opts.format ?? config.format ?? "text";
|
|
5671
|
+
const jsonStrict = opts.jsonStrict === true;
|
|
5672
|
+
const verbose = opts.verbose === true;
|
|
5673
|
+
if (jsonStrict && format !== "json") {
|
|
5674
|
+
throw new InvalidArgumentError("--json-strict requires --format json");
|
|
5675
|
+
}
|
|
5676
|
+
if (jsonStrict && verbose) {
|
|
5677
|
+
throw new InvalidArgumentError("--json-strict cannot be combined with --verbose");
|
|
5678
|
+
}
|
|
4869
5679
|
return {
|
|
4870
5680
|
agent: opts.agent,
|
|
4871
5681
|
cwd: opts.cwd ?? process.cwd(),
|
|
4872
5682
|
authPolicy: opts.authPolicy ?? config.authPolicy,
|
|
5683
|
+
nonInteractivePermissions: opts.nonInteractivePermissions ?? config.nonInteractivePermissions,
|
|
5684
|
+
jsonStrict,
|
|
4873
5685
|
timeout: opts.timeout ?? config.timeoutMs,
|
|
4874
5686
|
ttl: opts.ttl ?? config.ttlMs ?? DEFAULT_QUEUE_OWNER_TTL_MS,
|
|
4875
|
-
verbose
|
|
4876
|
-
format
|
|
5687
|
+
verbose,
|
|
5688
|
+
format,
|
|
4877
5689
|
approveAll: opts.approveAll ? true : void 0,
|
|
4878
5690
|
approveReads: opts.approveReads ? true : void 0,
|
|
4879
5691
|
denyAll: opts.denyAll ? true : void 0
|
|
4880
5692
|
};
|
|
4881
5693
|
}
|
|
5694
|
+
function resolveOutputPolicy(format, jsonStrict) {
|
|
5695
|
+
return {
|
|
5696
|
+
format,
|
|
5697
|
+
jsonStrict,
|
|
5698
|
+
suppressNonJsonStderr: jsonStrict,
|
|
5699
|
+
queueErrorAlreadyEmitted: format !== "quiet",
|
|
5700
|
+
suppressSdkConsoleErrors: jsonStrict
|
|
5701
|
+
};
|
|
5702
|
+
}
|
|
4882
5703
|
function resolveAgentInvocation(explicitAgentName, globalFlags, config) {
|
|
4883
5704
|
const override = globalFlags.agent?.trim();
|
|
4884
5705
|
if (override && explicitAgentName) {
|
|
@@ -4939,6 +5760,13 @@ function printClosedSessionByFormat(record, format) {
|
|
|
4939
5760
|
process.stdout.write(`${record.id}
|
|
4940
5761
|
`);
|
|
4941
5762
|
}
|
|
5763
|
+
function runtimeSessionIdPayload(runtimeSessionId) {
|
|
5764
|
+
const normalized = normalizeRuntimeSessionId(runtimeSessionId);
|
|
5765
|
+
if (!normalized) {
|
|
5766
|
+
return {};
|
|
5767
|
+
}
|
|
5768
|
+
return { runtimeSessionId: normalized };
|
|
5769
|
+
}
|
|
4942
5770
|
function printNewSessionByFormat(record, replaced, format) {
|
|
4943
5771
|
if (format === "json") {
|
|
4944
5772
|
process.stdout.write(
|
|
@@ -4947,7 +5775,8 @@ function printNewSessionByFormat(record, replaced, format) {
|
|
|
4947
5775
|
id: record.id,
|
|
4948
5776
|
sessionId: record.sessionId,
|
|
4949
5777
|
name: record.name,
|
|
4950
|
-
replacedSessionId: replaced?.id
|
|
5778
|
+
replacedSessionId: replaced?.id,
|
|
5779
|
+
...runtimeSessionIdPayload(record.runtimeSessionId)
|
|
4951
5780
|
})}
|
|
4952
5781
|
`
|
|
4953
5782
|
);
|
|
@@ -4966,6 +5795,30 @@ function printNewSessionByFormat(record, replaced, format) {
|
|
|
4966
5795
|
process.stdout.write(`${record.id}
|
|
4967
5796
|
`);
|
|
4968
5797
|
}
|
|
5798
|
+
function printEnsuredSessionByFormat(record, created, format) {
|
|
5799
|
+
if (format === "json") {
|
|
5800
|
+
process.stdout.write(
|
|
5801
|
+
`${JSON.stringify({
|
|
5802
|
+
type: "session_ensured",
|
|
5803
|
+
id: record.id,
|
|
5804
|
+
sessionId: record.sessionId,
|
|
5805
|
+
name: record.name,
|
|
5806
|
+
created,
|
|
5807
|
+
...runtimeSessionIdPayload(record.runtimeSessionId)
|
|
5808
|
+
})}
|
|
5809
|
+
`
|
|
5810
|
+
);
|
|
5811
|
+
return;
|
|
5812
|
+
}
|
|
5813
|
+
if (format === "quiet") {
|
|
5814
|
+
process.stdout.write(`${record.id}
|
|
5815
|
+
`);
|
|
5816
|
+
return;
|
|
5817
|
+
}
|
|
5818
|
+
const action = created ? "created" : "existing";
|
|
5819
|
+
process.stdout.write(`${record.id} (${action})
|
|
5820
|
+
`);
|
|
5821
|
+
}
|
|
4969
5822
|
function printQueuedPromptByFormat(result, format) {
|
|
4970
5823
|
if (format === "json") {
|
|
4971
5824
|
process.stdout.write(
|
|
@@ -5008,15 +5861,15 @@ function formatPromptSessionBannerLine(record, currentCwd) {
|
|
|
5008
5861
|
}
|
|
5009
5862
|
return `[acpx] session ${label} (${record.id}) \xB7 ${normalizedSessionCwd} \xB7 agent ${status}`;
|
|
5010
5863
|
}
|
|
5011
|
-
function printPromptSessionBanner(record, currentCwd, format) {
|
|
5012
|
-
if (format === "quiet") {
|
|
5864
|
+
function printPromptSessionBanner(record, currentCwd, format, jsonStrict = false) {
|
|
5865
|
+
if (format === "quiet" || jsonStrict && format === "json") {
|
|
5013
5866
|
return;
|
|
5014
5867
|
}
|
|
5015
5868
|
process.stderr.write(`${formatPromptSessionBannerLine(record, currentCwd)}
|
|
5016
5869
|
`);
|
|
5017
5870
|
}
|
|
5018
|
-
function printCreatedSessionBanner(record, agentName, format) {
|
|
5019
|
-
if (format === "quiet") {
|
|
5871
|
+
function printCreatedSessionBanner(record, agentName, format, jsonStrict = false) {
|
|
5872
|
+
if (format === "quiet" || jsonStrict && format === "json") {
|
|
5020
5873
|
return;
|
|
5021
5874
|
}
|
|
5022
5875
|
const label = formatSessionLabel(record);
|
|
@@ -5047,9 +5900,12 @@ Create one: ${createCmd}`
|
|
|
5047
5900
|
}
|
|
5048
5901
|
async function handlePrompt(explicitAgentName, promptParts, flags, command, config) {
|
|
5049
5902
|
const globalFlags = resolveGlobalFlags(command, config);
|
|
5903
|
+
const outputPolicy = resolveOutputPolicy(
|
|
5904
|
+
globalFlags.format,
|
|
5905
|
+
globalFlags.jsonStrict === true
|
|
5906
|
+
);
|
|
5050
5907
|
const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);
|
|
5051
5908
|
const prompt = await readPrompt(promptParts, flags.file, globalFlags.cwd);
|
|
5052
|
-
const outputFormatter = createOutputFormatter(globalFlags.format);
|
|
5053
5909
|
const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
|
|
5054
5910
|
const record = await findRoutedSessionOrThrow(
|
|
5055
5911
|
agent.agentCommand,
|
|
@@ -5057,21 +5913,37 @@ async function handlePrompt(explicitAgentName, promptParts, flags, command, conf
|
|
|
5057
5913
|
agent.cwd,
|
|
5058
5914
|
flags.session
|
|
5059
5915
|
);
|
|
5060
|
-
|
|
5916
|
+
const outputFormatter = createOutputFormatter(outputPolicy.format, {
|
|
5917
|
+
jsonContext: {
|
|
5918
|
+
sessionId: record.id,
|
|
5919
|
+
stream: "prompt"
|
|
5920
|
+
}
|
|
5921
|
+
});
|
|
5922
|
+
printPromptSessionBanner(
|
|
5923
|
+
record,
|
|
5924
|
+
agent.cwd,
|
|
5925
|
+
outputPolicy.format,
|
|
5926
|
+
outputPolicy.jsonStrict
|
|
5927
|
+
);
|
|
5061
5928
|
const result = await sendSession({
|
|
5062
5929
|
sessionId: record.id,
|
|
5063
5930
|
message: prompt,
|
|
5064
5931
|
permissionMode,
|
|
5932
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5065
5933
|
authCredentials: config.auth,
|
|
5066
5934
|
authPolicy: globalFlags.authPolicy,
|
|
5067
5935
|
outputFormatter,
|
|
5936
|
+
errorEmissionPolicy: {
|
|
5937
|
+
queueErrorAlreadyEmitted: outputPolicy.queueErrorAlreadyEmitted
|
|
5938
|
+
},
|
|
5939
|
+
suppressSdkConsoleErrors: outputPolicy.suppressSdkConsoleErrors,
|
|
5068
5940
|
timeoutMs: globalFlags.timeout,
|
|
5069
5941
|
ttlMs: globalFlags.ttl,
|
|
5070
5942
|
verbose: globalFlags.verbose,
|
|
5071
5943
|
waitForCompletion: flags.wait !== false
|
|
5072
5944
|
});
|
|
5073
5945
|
if ("queued" in result) {
|
|
5074
|
-
printQueuedPromptByFormat(result,
|
|
5946
|
+
printQueuedPromptByFormat(result, outputPolicy.format);
|
|
5075
5947
|
return;
|
|
5076
5948
|
}
|
|
5077
5949
|
applyPermissionExitCode(result);
|
|
@@ -5084,18 +5956,24 @@ async function handlePrompt(explicitAgentName, promptParts, flags, command, conf
|
|
|
5084
5956
|
}
|
|
5085
5957
|
async function handleExec(explicitAgentName, promptParts, flags, command, config) {
|
|
5086
5958
|
const globalFlags = resolveGlobalFlags(command, config);
|
|
5959
|
+
const outputPolicy = resolveOutputPolicy(
|
|
5960
|
+
globalFlags.format,
|
|
5961
|
+
globalFlags.jsonStrict === true
|
|
5962
|
+
);
|
|
5087
5963
|
const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);
|
|
5088
5964
|
const prompt = await readPrompt(promptParts, flags.file, globalFlags.cwd);
|
|
5089
|
-
const outputFormatter = createOutputFormatter(
|
|
5965
|
+
const outputFormatter = createOutputFormatter(outputPolicy.format);
|
|
5090
5966
|
const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
|
|
5091
5967
|
const result = await runOnce({
|
|
5092
5968
|
agentCommand: agent.agentCommand,
|
|
5093
5969
|
cwd: agent.cwd,
|
|
5094
5970
|
message: prompt,
|
|
5095
5971
|
permissionMode,
|
|
5972
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5096
5973
|
authCredentials: config.auth,
|
|
5097
5974
|
authPolicy: globalFlags.authPolicy,
|
|
5098
5975
|
outputFormatter,
|
|
5976
|
+
suppressSdkConsoleErrors: outputPolicy.suppressSdkConsoleErrors,
|
|
5099
5977
|
timeoutMs: globalFlags.timeout,
|
|
5100
5978
|
verbose: globalFlags.verbose
|
|
5101
5979
|
});
|
|
@@ -5196,6 +6074,7 @@ async function handleSetMode(explicitAgentName, modeId, flags, command, config)
|
|
|
5196
6074
|
const result = await setSessionMode({
|
|
5197
6075
|
sessionId: record.id,
|
|
5198
6076
|
modeId,
|
|
6077
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5199
6078
|
authCredentials: config.auth,
|
|
5200
6079
|
authPolicy: globalFlags.authPolicy,
|
|
5201
6080
|
timeoutMs: globalFlags.timeout,
|
|
@@ -5222,6 +6101,7 @@ async function handleSetConfigOption(explicitAgentName, configId, value, flags,
|
|
|
5222
6101
|
sessionId: record.id,
|
|
5223
6102
|
configId,
|
|
5224
6103
|
value,
|
|
6104
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5225
6105
|
authCredentials: config.auth,
|
|
5226
6106
|
authPolicy: globalFlags.authPolicy,
|
|
5227
6107
|
timeoutMs: globalFlags.timeout,
|
|
@@ -5281,12 +6161,18 @@ async function handleSessionsNew(explicitAgentName, flags, command, config) {
|
|
|
5281
6161
|
cwd: agent.cwd,
|
|
5282
6162
|
name: flags.name,
|
|
5283
6163
|
permissionMode,
|
|
6164
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5284
6165
|
authCredentials: config.auth,
|
|
5285
6166
|
authPolicy: globalFlags.authPolicy,
|
|
5286
6167
|
timeoutMs: globalFlags.timeout,
|
|
5287
6168
|
verbose: globalFlags.verbose
|
|
5288
6169
|
});
|
|
5289
|
-
printCreatedSessionBanner(
|
|
6170
|
+
printCreatedSessionBanner(
|
|
6171
|
+
created,
|
|
6172
|
+
agent.agentName,
|
|
6173
|
+
globalFlags.format,
|
|
6174
|
+
globalFlags.jsonStrict
|
|
6175
|
+
);
|
|
5290
6176
|
if (globalFlags.verbose) {
|
|
5291
6177
|
const scope = flags.name ? `named session "${flags.name}"` : "cwd session";
|
|
5292
6178
|
process.stderr.write(`[acpx] created ${scope}: ${created.id}
|
|
@@ -5294,6 +6180,31 @@ async function handleSessionsNew(explicitAgentName, flags, command, config) {
|
|
|
5294
6180
|
}
|
|
5295
6181
|
printNewSessionByFormat(created, replaced, globalFlags.format);
|
|
5296
6182
|
}
|
|
6183
|
+
async function handleSessionsEnsure(explicitAgentName, flags, command, config) {
|
|
6184
|
+
const globalFlags = resolveGlobalFlags(command, config);
|
|
6185
|
+
const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);
|
|
6186
|
+
const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
|
|
6187
|
+
const result = await ensureSession({
|
|
6188
|
+
agentCommand: agent.agentCommand,
|
|
6189
|
+
cwd: agent.cwd,
|
|
6190
|
+
name: flags.name,
|
|
6191
|
+
permissionMode,
|
|
6192
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
6193
|
+
authCredentials: config.auth,
|
|
6194
|
+
authPolicy: globalFlags.authPolicy,
|
|
6195
|
+
timeoutMs: globalFlags.timeout,
|
|
6196
|
+
verbose: globalFlags.verbose
|
|
6197
|
+
});
|
|
6198
|
+
if (result.created) {
|
|
6199
|
+
printCreatedSessionBanner(
|
|
6200
|
+
result.record,
|
|
6201
|
+
agent.agentName,
|
|
6202
|
+
globalFlags.format,
|
|
6203
|
+
globalFlags.jsonStrict
|
|
6204
|
+
);
|
|
6205
|
+
}
|
|
6206
|
+
printEnsuredSessionByFormat(result.record, result.created, globalFlags.format);
|
|
6207
|
+
}
|
|
5297
6208
|
function printSessionDetailsByFormat(record, format) {
|
|
5298
6209
|
if (format === "json") {
|
|
5299
6210
|
process.stdout.write(`${JSON.stringify(record)}
|
|
@@ -5308,6 +6219,8 @@ function printSessionDetailsByFormat(record, format) {
|
|
|
5308
6219
|
process.stdout.write(`id: ${record.id}
|
|
5309
6220
|
`);
|
|
5310
6221
|
process.stdout.write(`sessionId: ${record.sessionId}
|
|
6222
|
+
`);
|
|
6223
|
+
process.stdout.write(`runtimeSessionId: ${record.runtimeSessionId ?? "-"}
|
|
5311
6224
|
`);
|
|
5312
6225
|
process.stdout.write(`agent: ${record.agentCommand}
|
|
5313
6226
|
`);
|
|
@@ -5476,7 +6389,8 @@ async function handleStatus(explicitAgentName, flags, command, config) {
|
|
|
5476
6389
|
uptime: running ? formatUptime(record.agentStartedAt) ?? null : null,
|
|
5477
6390
|
lastPromptTime: record.lastPromptAt ?? null,
|
|
5478
6391
|
exitCode: running ? null : record.lastAgentExitCode ?? null,
|
|
5479
|
-
signal: running ? null : record.lastAgentExitSignal ?? null
|
|
6392
|
+
signal: running ? null : record.lastAgentExitSignal ?? null,
|
|
6393
|
+
...runtimeSessionIdPayload(record.runtimeSessionId)
|
|
5480
6394
|
};
|
|
5481
6395
|
if (globalFlags.format === "json") {
|
|
5482
6396
|
process.stdout.write(`${JSON.stringify(payload)}
|
|
@@ -5490,6 +6404,10 @@ async function handleStatus(explicitAgentName, flags, command, config) {
|
|
|
5490
6404
|
}
|
|
5491
6405
|
process.stdout.write(`session: ${payload.sessionId}
|
|
5492
6406
|
`);
|
|
6407
|
+
if ("runtimeSessionId" in payload) {
|
|
6408
|
+
process.stdout.write(`runtimeSessionId: ${payload.runtimeSessionId}
|
|
6409
|
+
`);
|
|
6410
|
+
}
|
|
5493
6411
|
process.stdout.write(`agent: ${payload.agentCommand}
|
|
5494
6412
|
`);
|
|
5495
6413
|
process.stdout.write(`pid: ${payload.pid ?? "-"}
|
|
@@ -5555,7 +6473,7 @@ async function handleConfigInit(command, config) {
|
|
|
5555
6473
|
`);
|
|
5556
6474
|
}
|
|
5557
6475
|
function registerSessionsCommand(parent, explicitAgentName, config) {
|
|
5558
|
-
const sessionsCommand = parent.command("sessions").description("List, create, or close sessions for this agent");
|
|
6476
|
+
const sessionsCommand = parent.command("sessions").description("List, ensure, create, or close sessions for this agent");
|
|
5559
6477
|
sessionsCommand.action(async function() {
|
|
5560
6478
|
await handleSessionsList(explicitAgentName, this, config);
|
|
5561
6479
|
});
|
|
@@ -5565,6 +6483,9 @@ function registerSessionsCommand(parent, explicitAgentName, config) {
|
|
|
5565
6483
|
sessionsCommand.command("new").description("Create a fresh session for current cwd").option("--name <name>", "Session name", parseSessionName).action(async function(flags) {
|
|
5566
6484
|
await handleSessionsNew(explicitAgentName, flags, this, config);
|
|
5567
6485
|
});
|
|
6486
|
+
sessionsCommand.command("ensure").description("Ensure a session exists for current cwd or ancestor").option("--name <name>", "Session name", parseSessionName).action(async function(flags) {
|
|
6487
|
+
await handleSessionsEnsure(explicitAgentName, flags, this, config);
|
|
6488
|
+
});
|
|
5568
6489
|
sessionsCommand.command("close").description("Close session for current cwd").argument("[name]", "Session name", parseSessionName).action(async function(name) {
|
|
5569
6490
|
await handleSessionsClose(explicitAgentName, name, this, config);
|
|
5570
6491
|
});
|
|
@@ -5685,14 +6606,14 @@ function detectAgentToken(argv) {
|
|
|
5685
6606
|
hasAgentOverride = true;
|
|
5686
6607
|
continue;
|
|
5687
6608
|
}
|
|
5688
|
-
if (token === "--cwd" || token === "--auth-policy" || token === "--format" || token === "--timeout" || token === "--ttl" || token === "--file") {
|
|
6609
|
+
if (token === "--cwd" || token === "--auth-policy" || token === "--non-interactive-permissions" || token === "--format" || token === "--timeout" || token === "--ttl" || token === "--file") {
|
|
5689
6610
|
index += 1;
|
|
5690
6611
|
continue;
|
|
5691
6612
|
}
|
|
5692
|
-
if (token.startsWith("--cwd=") || token.startsWith("--auth-policy=") || token.startsWith("--format=") || token.startsWith("--timeout=") || token.startsWith("--ttl=") || token.startsWith("--file=")) {
|
|
6613
|
+
if (token.startsWith("--cwd=") || token.startsWith("--auth-policy=") || token.startsWith("--non-interactive-permissions=") || token.startsWith("--format=") || token.startsWith("--json-strict=") || token.startsWith("--timeout=") || token.startsWith("--ttl=") || token.startsWith("--file=")) {
|
|
5693
6614
|
continue;
|
|
5694
6615
|
}
|
|
5695
|
-
if (token === "--approve-all" || token === "--approve-reads" || token === "--deny-all" || token === "--verbose") {
|
|
6616
|
+
if (token === "--approve-all" || token === "--approve-reads" || token === "--deny-all" || token === "--json-strict" || token === "--verbose") {
|
|
5696
6617
|
continue;
|
|
5697
6618
|
}
|
|
5698
6619
|
return { hasAgentOverride };
|
|
@@ -5722,15 +6643,103 @@ function detectInitialCwd(argv) {
|
|
|
5722
6643
|
}
|
|
5723
6644
|
return process.cwd();
|
|
5724
6645
|
}
|
|
6646
|
+
function detectRequestedOutputFormat(argv, fallback) {
|
|
6647
|
+
let detectedFormat = fallback;
|
|
6648
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
6649
|
+
const token = argv[index];
|
|
6650
|
+
if (token === "--") {
|
|
6651
|
+
break;
|
|
6652
|
+
}
|
|
6653
|
+
if (token === "--json-strict" || token.startsWith("--json-strict=")) {
|
|
6654
|
+
return "json";
|
|
6655
|
+
}
|
|
6656
|
+
if (token === "--format") {
|
|
6657
|
+
const raw = argv[index + 1];
|
|
6658
|
+
if (raw && OUTPUT_FORMATS.includes(raw)) {
|
|
6659
|
+
detectedFormat = raw;
|
|
6660
|
+
}
|
|
6661
|
+
continue;
|
|
6662
|
+
}
|
|
6663
|
+
if (token.startsWith("--format=")) {
|
|
6664
|
+
const raw = token.slice("--format=".length).trim();
|
|
6665
|
+
if (OUTPUT_FORMATS.includes(raw)) {
|
|
6666
|
+
detectedFormat = raw;
|
|
6667
|
+
}
|
|
6668
|
+
}
|
|
6669
|
+
}
|
|
6670
|
+
return detectedFormat;
|
|
6671
|
+
}
|
|
6672
|
+
function detectJsonStrict(argv) {
|
|
6673
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
6674
|
+
const token = argv[index];
|
|
6675
|
+
if (token === "--") {
|
|
6676
|
+
break;
|
|
6677
|
+
}
|
|
6678
|
+
if (token === "--json-strict") {
|
|
6679
|
+
return true;
|
|
6680
|
+
}
|
|
6681
|
+
if (token.startsWith("--json-strict=")) {
|
|
6682
|
+
return true;
|
|
6683
|
+
}
|
|
6684
|
+
}
|
|
6685
|
+
return false;
|
|
6686
|
+
}
|
|
6687
|
+
function emitJsonErrorEvent(error) {
|
|
6688
|
+
const formatter = createOutputFormatter("json", {
|
|
6689
|
+
jsonContext: {
|
|
6690
|
+
sessionId: "unknown",
|
|
6691
|
+
stream: "control"
|
|
6692
|
+
}
|
|
6693
|
+
});
|
|
6694
|
+
formatter.onError(error);
|
|
6695
|
+
formatter.flush();
|
|
6696
|
+
}
|
|
6697
|
+
function isOutputAlreadyEmitted(error) {
|
|
6698
|
+
if (!error || typeof error !== "object") {
|
|
6699
|
+
return false;
|
|
6700
|
+
}
|
|
6701
|
+
return error.outputAlreadyEmitted === true;
|
|
6702
|
+
}
|
|
6703
|
+
function emitRequestedError(error, normalized, outputPolicy) {
|
|
6704
|
+
if (isOutputAlreadyEmitted(error)) {
|
|
6705
|
+
return;
|
|
6706
|
+
}
|
|
6707
|
+
if (outputPolicy.format === "json") {
|
|
6708
|
+
emitJsonErrorEvent(normalized);
|
|
6709
|
+
} else if (!outputPolicy.suppressNonJsonStderr) {
|
|
6710
|
+
process.stderr.write(`${normalized.message}
|
|
6711
|
+
`);
|
|
6712
|
+
}
|
|
6713
|
+
}
|
|
6714
|
+
async function runWithOutputPolicy(_outputPolicy, run) {
|
|
6715
|
+
return await run();
|
|
6716
|
+
}
|
|
5725
6717
|
async function main(argv = process.argv) {
|
|
5726
6718
|
await maybeHandleSkillflag(argv, {
|
|
5727
6719
|
skillsRoot: findSkillsRoot(import.meta.url),
|
|
5728
6720
|
includeBundledSkill: false
|
|
5729
6721
|
});
|
|
5730
6722
|
const config = await loadResolvedConfig(detectInitialCwd(argv.slice(2)));
|
|
6723
|
+
const requestedJsonStrict = detectJsonStrict(argv.slice(2));
|
|
6724
|
+
const requestedOutputFormat = detectRequestedOutputFormat(
|
|
6725
|
+
argv.slice(2),
|
|
6726
|
+
config.format
|
|
6727
|
+
);
|
|
6728
|
+
const requestedOutputPolicy = resolveOutputPolicy(
|
|
6729
|
+
requestedOutputFormat,
|
|
6730
|
+
requestedJsonStrict
|
|
6731
|
+
);
|
|
5731
6732
|
const builtInAgents = listBuiltInAgents(config.agents);
|
|
5732
6733
|
const program = new Command();
|
|
5733
6734
|
program.name("acpx").description("Headless CLI client for the Agent Client Protocol").enablePositionalOptions().showHelpAfterError();
|
|
6735
|
+
if (requestedJsonStrict) {
|
|
6736
|
+
program.configureOutput({
|
|
6737
|
+
writeOut: () => {
|
|
6738
|
+
},
|
|
6739
|
+
writeErr: () => {
|
|
6740
|
+
}
|
|
6741
|
+
});
|
|
6742
|
+
}
|
|
5734
6743
|
addGlobalFlags(program);
|
|
5735
6744
|
for (const agentName of builtInAgents) {
|
|
5736
6745
|
registerAgentCommand(program, agentName, config);
|
|
@@ -5742,6 +6751,11 @@ async function main(argv = process.argv) {
|
|
|
5742
6751
|
}
|
|
5743
6752
|
program.argument("[prompt...]", "Prompt text").action(async function(promptParts) {
|
|
5744
6753
|
if (promptParts.length === 0 && process.stdin.isTTY) {
|
|
6754
|
+
if (requestedJsonStrict) {
|
|
6755
|
+
throw new InvalidArgumentError(
|
|
6756
|
+
"Prompt is required (pass as argument, --file, or pipe via stdin)"
|
|
6757
|
+
);
|
|
6758
|
+
}
|
|
5745
6759
|
this.outputHelp();
|
|
5746
6760
|
return;
|
|
5747
6761
|
}
|
|
@@ -5762,6 +6776,7 @@ Examples:
|
|
|
5762
6776
|
acpx codex -s backend "fix the API"
|
|
5763
6777
|
acpx codex sessions
|
|
5764
6778
|
acpx codex sessions new --name backend
|
|
6779
|
+
acpx codex sessions ensure --name backend
|
|
5765
6780
|
acpx codex sessions close backend
|
|
5766
6781
|
acpx codex status
|
|
5767
6782
|
acpx config show
|
|
@@ -5774,33 +6789,33 @@ Examples:
|
|
|
5774
6789
|
program.exitOverride((error) => {
|
|
5775
6790
|
throw error;
|
|
5776
6791
|
});
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
if (error
|
|
5782
|
-
|
|
6792
|
+
await runWithOutputPolicy(requestedOutputPolicy, async () => {
|
|
6793
|
+
try {
|
|
6794
|
+
await program.parseAsync(argv);
|
|
6795
|
+
} catch (error) {
|
|
6796
|
+
if (error instanceof CommanderError) {
|
|
6797
|
+
if (error.code === "commander.helpDisplayed" || error.code === "commander.version") {
|
|
6798
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
6799
|
+
}
|
|
6800
|
+
const normalized2 = normalizeOutputError(error, {
|
|
6801
|
+
defaultCode: "USAGE",
|
|
6802
|
+
origin: "cli"
|
|
6803
|
+
});
|
|
6804
|
+
if (requestedOutputPolicy.format === "json") {
|
|
6805
|
+
emitRequestedError(error, normalized2, requestedOutputPolicy);
|
|
6806
|
+
}
|
|
6807
|
+
process.exit(exitCodeForOutputErrorCode(normalized2.code));
|
|
5783
6808
|
}
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
process.exit(EXIT_CODES.TIMEOUT);
|
|
5793
|
-
}
|
|
5794
|
-
if (error instanceof NoSessionError) {
|
|
5795
|
-
process.stderr.write(`${error.message}
|
|
5796
|
-
`);
|
|
5797
|
-
process.exit(EXIT_CODES.NO_SESSION);
|
|
6809
|
+
if (error instanceof InterruptedError) {
|
|
6810
|
+
process.exit(EXIT_CODES.INTERRUPTED);
|
|
6811
|
+
}
|
|
6812
|
+
const normalized = normalizeOutputError(error, {
|
|
6813
|
+
origin: "cli"
|
|
6814
|
+
});
|
|
6815
|
+
emitRequestedError(error, normalized, requestedOutputPolicy);
|
|
6816
|
+
process.exit(exitCodeForOutputErrorCode(normalized.code));
|
|
5798
6817
|
}
|
|
5799
|
-
|
|
5800
|
-
process.stderr.write(`${message}
|
|
5801
|
-
`);
|
|
5802
|
-
process.exit(EXIT_CODES.ERROR);
|
|
5803
|
-
}
|
|
6818
|
+
});
|
|
5804
6819
|
}
|
|
5805
6820
|
function isCliEntrypoint(argv) {
|
|
5806
6821
|
const entry = argv[1];
|