acpx 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -7
- package/dist/cli.js +1168 -231
- package/package.json +2 -2
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);
|
|
@@ -1419,6 +1773,9 @@ async function defaultConfirmExecute(commandLine) {
|
|
|
1419
1773
|
[permission] Allow terminal command "${commandLine}"? (y/N) `
|
|
1420
1774
|
});
|
|
1421
1775
|
}
|
|
1776
|
+
function canPromptForPermission3() {
|
|
1777
|
+
return Boolean(process.stdin.isTTY && process.stderr.isTTY);
|
|
1778
|
+
}
|
|
1422
1779
|
function waitMs(ms) {
|
|
1423
1780
|
return new Promise((resolve) => {
|
|
1424
1781
|
setTimeout(resolve, Math.max(0, ms));
|
|
@@ -1427,14 +1784,18 @@ function waitMs(ms) {
|
|
|
1427
1784
|
var TerminalManager = class {
|
|
1428
1785
|
cwd;
|
|
1429
1786
|
permissionMode;
|
|
1787
|
+
nonInteractivePermissions;
|
|
1430
1788
|
onOperation;
|
|
1789
|
+
usesDefaultConfirmExecute;
|
|
1431
1790
|
confirmExecute;
|
|
1432
1791
|
killGraceMs;
|
|
1433
1792
|
terminals = /* @__PURE__ */ new Map();
|
|
1434
1793
|
constructor(options) {
|
|
1435
1794
|
this.cwd = options.cwd;
|
|
1436
1795
|
this.permissionMode = options.permissionMode;
|
|
1796
|
+
this.nonInteractivePermissions = options.nonInteractivePermissions ?? "deny";
|
|
1437
1797
|
this.onOperation = options.onOperation;
|
|
1798
|
+
this.usesDefaultConfirmExecute = options.confirmExecute == null;
|
|
1438
1799
|
this.confirmExecute = options.confirmExecute ?? defaultConfirmExecute;
|
|
1439
1800
|
this.killGraceMs = Math.max(
|
|
1440
1801
|
0,
|
|
@@ -1656,6 +2017,9 @@ var TerminalManager = class {
|
|
|
1656
2017
|
if (this.permissionMode === "deny-all") {
|
|
1657
2018
|
return false;
|
|
1658
2019
|
}
|
|
2020
|
+
if (this.usesDefaultConfirmExecute && this.nonInteractivePermissions === "fail" && !canPromptForPermission3()) {
|
|
2021
|
+
throw new PermissionPromptUnavailableError();
|
|
2022
|
+
}
|
|
1659
2023
|
return await this.confirmExecute(commandLine);
|
|
1660
2024
|
}
|
|
1661
2025
|
isRunning(terminal) {
|
|
@@ -1693,6 +2057,24 @@ var TerminalManager = class {
|
|
|
1693
2057
|
var REPLAY_IDLE_MS = 80;
|
|
1694
2058
|
var REPLAY_DRAIN_TIMEOUT_MS = 5e3;
|
|
1695
2059
|
var DRAIN_POLL_INTERVAL_MS = 20;
|
|
2060
|
+
function shouldSuppressSdkConsoleError(args) {
|
|
2061
|
+
if (args.length === 0) {
|
|
2062
|
+
return false;
|
|
2063
|
+
}
|
|
2064
|
+
return typeof args[0] === "string" && args[0] === "Error handling request";
|
|
2065
|
+
}
|
|
2066
|
+
function installSdkConsoleErrorSuppression() {
|
|
2067
|
+
const originalConsoleError = console.error;
|
|
2068
|
+
console.error = (...args) => {
|
|
2069
|
+
if (shouldSuppressSdkConsoleError(args)) {
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
originalConsoleError(...args);
|
|
2073
|
+
};
|
|
2074
|
+
return () => {
|
|
2075
|
+
console.error = originalConsoleError;
|
|
2076
|
+
};
|
|
2077
|
+
}
|
|
1696
2078
|
function isoNow() {
|
|
1697
2079
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1698
2080
|
}
|
|
@@ -1835,6 +2217,7 @@ var AcpClient = class {
|
|
|
1835
2217
|
agentStartedAt;
|
|
1836
2218
|
lastAgentExit;
|
|
1837
2219
|
lastKnownPid;
|
|
2220
|
+
promptPermissionFailures = /* @__PURE__ */ new Map();
|
|
1838
2221
|
constructor(options) {
|
|
1839
2222
|
this.options = {
|
|
1840
2223
|
...options,
|
|
@@ -1845,11 +2228,13 @@ var AcpClient = class {
|
|
|
1845
2228
|
this.filesystem = new FileSystemHandlers({
|
|
1846
2229
|
cwd: this.options.cwd,
|
|
1847
2230
|
permissionMode: this.options.permissionMode,
|
|
2231
|
+
nonInteractivePermissions: this.options.nonInteractivePermissions,
|
|
1848
2232
|
onOperation: emitOperation
|
|
1849
2233
|
});
|
|
1850
2234
|
this.terminalManager = new TerminalManager({
|
|
1851
2235
|
cwd: this.options.cwd,
|
|
1852
2236
|
permissionMode: this.options.permissionMode,
|
|
2237
|
+
nonInteractivePermissions: this.options.nonInteractivePermissions,
|
|
1853
2238
|
onOperation: emitOperation
|
|
1854
2239
|
});
|
|
1855
2240
|
}
|
|
@@ -2014,26 +2399,46 @@ var AcpClient = class {
|
|
|
2014
2399
|
}
|
|
2015
2400
|
async prompt(sessionId, text) {
|
|
2016
2401
|
const connection = this.getConnection();
|
|
2017
|
-
const
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2402
|
+
const restoreConsoleError = this.options.suppressSdkConsoleErrors ? installSdkConsoleErrorSuppression() : void 0;
|
|
2403
|
+
let promptPromise;
|
|
2404
|
+
try {
|
|
2405
|
+
promptPromise = connection.prompt({
|
|
2406
|
+
sessionId,
|
|
2407
|
+
prompt: [
|
|
2408
|
+
{
|
|
2409
|
+
type: "text",
|
|
2410
|
+
text
|
|
2411
|
+
}
|
|
2412
|
+
]
|
|
2413
|
+
});
|
|
2414
|
+
} catch (error) {
|
|
2415
|
+
restoreConsoleError?.();
|
|
2416
|
+
throw error;
|
|
2417
|
+
}
|
|
2026
2418
|
this.activePrompt = {
|
|
2027
2419
|
sessionId,
|
|
2028
2420
|
promise: promptPromise
|
|
2029
2421
|
};
|
|
2030
2422
|
try {
|
|
2031
|
-
|
|
2423
|
+
const response = await promptPromise;
|
|
2424
|
+
const permissionFailure = this.consumePromptPermissionFailure(sessionId);
|
|
2425
|
+
if (permissionFailure) {
|
|
2426
|
+
throw permissionFailure;
|
|
2427
|
+
}
|
|
2428
|
+
return response;
|
|
2429
|
+
} catch (error) {
|
|
2430
|
+
const permissionFailure = this.consumePromptPermissionFailure(sessionId);
|
|
2431
|
+
if (permissionFailure) {
|
|
2432
|
+
throw permissionFailure;
|
|
2433
|
+
}
|
|
2434
|
+
throw error;
|
|
2032
2435
|
} finally {
|
|
2436
|
+
restoreConsoleError?.();
|
|
2033
2437
|
if (this.activePrompt?.promise === promptPromise) {
|
|
2034
2438
|
this.activePrompt = void 0;
|
|
2035
2439
|
}
|
|
2036
2440
|
this.cancellingSessionIds.delete(sessionId);
|
|
2441
|
+
this.promptPermissionFailures.delete(sessionId);
|
|
2037
2442
|
}
|
|
2038
2443
|
}
|
|
2039
2444
|
async setSessionMode(sessionId, modeId) {
|
|
@@ -2110,6 +2515,7 @@ var AcpClient = class {
|
|
|
2110
2515
|
this.suppressSessionUpdates = false;
|
|
2111
2516
|
this.activePrompt = void 0;
|
|
2112
2517
|
this.cancellingSessionIds.clear();
|
|
2518
|
+
this.promptPermissionFailures.clear();
|
|
2113
2519
|
this.connection = void 0;
|
|
2114
2520
|
this.agent = void 0;
|
|
2115
2521
|
}
|
|
@@ -2177,10 +2583,26 @@ var AcpClient = class {
|
|
|
2177
2583
|
}
|
|
2178
2584
|
};
|
|
2179
2585
|
}
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2586
|
+
let response;
|
|
2587
|
+
try {
|
|
2588
|
+
response = await resolvePermissionRequest(
|
|
2589
|
+
params,
|
|
2590
|
+
this.options.permissionMode,
|
|
2591
|
+
this.options.nonInteractivePermissions ?? "deny"
|
|
2592
|
+
);
|
|
2593
|
+
} catch (error) {
|
|
2594
|
+
if (error instanceof PermissionPromptUnavailableError) {
|
|
2595
|
+
this.notePromptPermissionFailure(params.sessionId, error);
|
|
2596
|
+
this.permissionStats.requested += 1;
|
|
2597
|
+
this.permissionStats.cancelled += 1;
|
|
2598
|
+
return {
|
|
2599
|
+
outcome: {
|
|
2600
|
+
outcome: "cancelled"
|
|
2601
|
+
}
|
|
2602
|
+
};
|
|
2603
|
+
}
|
|
2604
|
+
throw error;
|
|
2605
|
+
}
|
|
2184
2606
|
const decision = classifyPermissionDecision(params, response);
|
|
2185
2607
|
this.permissionStats.requested += 1;
|
|
2186
2608
|
if (decision === "approved") {
|
|
@@ -2219,14 +2641,40 @@ var AcpClient = class {
|
|
|
2219
2641
|
unexpectedDuringPrompt: !this.closing && Boolean(this.activePrompt)
|
|
2220
2642
|
};
|
|
2221
2643
|
}
|
|
2644
|
+
notePromptPermissionFailure(sessionId, error) {
|
|
2645
|
+
if (!this.promptPermissionFailures.has(sessionId)) {
|
|
2646
|
+
this.promptPermissionFailures.set(sessionId, error);
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
consumePromptPermissionFailure(sessionId) {
|
|
2650
|
+
const error = this.promptPermissionFailures.get(sessionId);
|
|
2651
|
+
if (error) {
|
|
2652
|
+
this.promptPermissionFailures.delete(sessionId);
|
|
2653
|
+
}
|
|
2654
|
+
return error;
|
|
2655
|
+
}
|
|
2222
2656
|
async handleReadTextFile(params) {
|
|
2223
2657
|
return await this.filesystem.readTextFile(params);
|
|
2224
2658
|
}
|
|
2225
2659
|
async handleWriteTextFile(params) {
|
|
2226
|
-
|
|
2660
|
+
try {
|
|
2661
|
+
return await this.filesystem.writeTextFile(params);
|
|
2662
|
+
} catch (error) {
|
|
2663
|
+
if (error instanceof PermissionPromptUnavailableError) {
|
|
2664
|
+
this.notePromptPermissionFailure(params.sessionId, error);
|
|
2665
|
+
}
|
|
2666
|
+
throw error;
|
|
2667
|
+
}
|
|
2227
2668
|
}
|
|
2228
2669
|
async handleCreateTerminal(params) {
|
|
2229
|
-
|
|
2670
|
+
try {
|
|
2671
|
+
return await this.terminalManager.createTerminal(params);
|
|
2672
|
+
} catch (error) {
|
|
2673
|
+
if (error instanceof PermissionPromptUnavailableError) {
|
|
2674
|
+
this.notePromptPermissionFailure(params.sessionId, error);
|
|
2675
|
+
}
|
|
2676
|
+
throw error;
|
|
2677
|
+
}
|
|
2230
2678
|
}
|
|
2231
2679
|
async handleTerminalOutput(params) {
|
|
2232
2680
|
return await this.terminalManager.terminalOutput(params);
|
|
@@ -2325,7 +2773,11 @@ var QueueOwnerTurnController = class {
|
|
|
2325
2773
|
}
|
|
2326
2774
|
assertCanHandleControlRequest() {
|
|
2327
2775
|
if (this.state === "closing") {
|
|
2328
|
-
throw new QueueConnectionError("Queue owner is closing"
|
|
2776
|
+
throw new QueueConnectionError("Queue owner is closing", {
|
|
2777
|
+
detailCode: "QUEUE_OWNER_SHUTTING_DOWN",
|
|
2778
|
+
origin: "queue",
|
|
2779
|
+
retryable: true
|
|
2780
|
+
});
|
|
2329
2781
|
}
|
|
2330
2782
|
}
|
|
2331
2783
|
async requestCancel() {
|
|
@@ -2391,7 +2843,7 @@ import os2 from "os";
|
|
|
2391
2843
|
import path4 from "path";
|
|
2392
2844
|
|
|
2393
2845
|
// src/queue-messages.ts
|
|
2394
|
-
function
|
|
2846
|
+
function asRecord3(value) {
|
|
2395
2847
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2396
2848
|
return void 0;
|
|
2397
2849
|
}
|
|
@@ -2400,8 +2852,34 @@ function asRecord2(value) {
|
|
|
2400
2852
|
function isPermissionMode(value) {
|
|
2401
2853
|
return value === "approve-all" || value === "approve-reads" || value === "deny-all";
|
|
2402
2854
|
}
|
|
2855
|
+
function isNonInteractivePermissionPolicy(value) {
|
|
2856
|
+
return value === "deny" || value === "fail";
|
|
2857
|
+
}
|
|
2858
|
+
function isOutputErrorCode2(value) {
|
|
2859
|
+
return typeof value === "string" && OUTPUT_ERROR_CODES.includes(value);
|
|
2860
|
+
}
|
|
2861
|
+
function isOutputErrorOrigin2(value) {
|
|
2862
|
+
return typeof value === "string" && OUTPUT_ERROR_ORIGINS.includes(value);
|
|
2863
|
+
}
|
|
2864
|
+
function parseAcpError(value) {
|
|
2865
|
+
const record = asRecord3(value);
|
|
2866
|
+
if (!record) {
|
|
2867
|
+
return void 0;
|
|
2868
|
+
}
|
|
2869
|
+
if (typeof record.code !== "number" || !Number.isFinite(record.code)) {
|
|
2870
|
+
return void 0;
|
|
2871
|
+
}
|
|
2872
|
+
if (typeof record.message !== "string" || record.message.length === 0) {
|
|
2873
|
+
return void 0;
|
|
2874
|
+
}
|
|
2875
|
+
return {
|
|
2876
|
+
code: record.code,
|
|
2877
|
+
message: record.message,
|
|
2878
|
+
data: record.data
|
|
2879
|
+
};
|
|
2880
|
+
}
|
|
2403
2881
|
function parseQueueRequest(raw) {
|
|
2404
|
-
const request =
|
|
2882
|
+
const request = asRecord3(raw);
|
|
2405
2883
|
if (!request) {
|
|
2406
2884
|
return null;
|
|
2407
2885
|
}
|
|
@@ -2411,7 +2889,9 @@ function parseQueueRequest(raw) {
|
|
|
2411
2889
|
const timeoutRaw = request.timeoutMs;
|
|
2412
2890
|
const timeoutMs = typeof timeoutRaw === "number" && Number.isFinite(timeoutRaw) && timeoutRaw > 0 ? Math.round(timeoutRaw) : void 0;
|
|
2413
2891
|
if (request.type === "submit_prompt") {
|
|
2414
|
-
|
|
2892
|
+
const nonInteractivePermissions = request.nonInteractivePermissions == null ? void 0 : isNonInteractivePermissionPolicy(request.nonInteractivePermissions) ? request.nonInteractivePermissions : null;
|
|
2893
|
+
const suppressSdkConsoleErrors = request.suppressSdkConsoleErrors == null ? void 0 : typeof request.suppressSdkConsoleErrors === "boolean" ? request.suppressSdkConsoleErrors : null;
|
|
2894
|
+
if (typeof request.message !== "string" || !isPermissionMode(request.permissionMode) || nonInteractivePermissions === null || suppressSdkConsoleErrors === null || typeof request.waitForCompletion !== "boolean") {
|
|
2415
2895
|
return null;
|
|
2416
2896
|
}
|
|
2417
2897
|
return {
|
|
@@ -2419,7 +2899,9 @@ function parseQueueRequest(raw) {
|
|
|
2419
2899
|
requestId: request.requestId,
|
|
2420
2900
|
message: request.message,
|
|
2421
2901
|
permissionMode: request.permissionMode,
|
|
2902
|
+
nonInteractivePermissions,
|
|
2422
2903
|
timeoutMs,
|
|
2904
|
+
...suppressSdkConsoleErrors !== void 0 ? { suppressSdkConsoleErrors } : {},
|
|
2423
2905
|
waitForCompletion: request.waitForCompletion
|
|
2424
2906
|
};
|
|
2425
2907
|
}
|
|
@@ -2455,15 +2937,15 @@ function parseQueueRequest(raw) {
|
|
|
2455
2937
|
return null;
|
|
2456
2938
|
}
|
|
2457
2939
|
function parseSessionSendResult(raw) {
|
|
2458
|
-
const result =
|
|
2940
|
+
const result = asRecord3(raw);
|
|
2459
2941
|
if (!result) {
|
|
2460
2942
|
return null;
|
|
2461
2943
|
}
|
|
2462
2944
|
if (typeof result.stopReason !== "string" || typeof result.sessionId !== "string" || typeof result.resumed !== "boolean") {
|
|
2463
2945
|
return null;
|
|
2464
2946
|
}
|
|
2465
|
-
const permissionStats =
|
|
2466
|
-
const record =
|
|
2947
|
+
const permissionStats = asRecord3(result.permissionStats);
|
|
2948
|
+
const record = asRecord3(result.record);
|
|
2467
2949
|
if (!permissionStats || !record) {
|
|
2468
2950
|
return null;
|
|
2469
2951
|
}
|
|
@@ -2478,7 +2960,7 @@ function parseSessionSendResult(raw) {
|
|
|
2478
2960
|
return result;
|
|
2479
2961
|
}
|
|
2480
2962
|
function parseQueueOwnerMessage(raw) {
|
|
2481
|
-
const message =
|
|
2963
|
+
const message = asRecord3(raw);
|
|
2482
2964
|
if (!message || typeof message.type !== "string") {
|
|
2483
2965
|
return null;
|
|
2484
2966
|
}
|
|
@@ -2503,7 +2985,7 @@ function parseQueueOwnerMessage(raw) {
|
|
|
2503
2985
|
};
|
|
2504
2986
|
}
|
|
2505
2987
|
if (message.type === "client_operation") {
|
|
2506
|
-
const operation =
|
|
2988
|
+
const operation = asRecord3(message.operation);
|
|
2507
2989
|
if (!operation || typeof operation.method !== "string" || typeof operation.status !== "string" || typeof operation.summary !== "string" || typeof operation.timestamp !== "string") {
|
|
2508
2990
|
return null;
|
|
2509
2991
|
}
|
|
@@ -2558,7 +3040,7 @@ function parseQueueOwnerMessage(raw) {
|
|
|
2558
3040
|
};
|
|
2559
3041
|
}
|
|
2560
3042
|
if (message.type === "set_config_option_result") {
|
|
2561
|
-
const response =
|
|
3043
|
+
const response = asRecord3(message.response);
|
|
2562
3044
|
if (!response || !Array.isArray(response.configOptions)) {
|
|
2563
3045
|
return null;
|
|
2564
3046
|
}
|
|
@@ -2572,10 +3054,20 @@ function parseQueueOwnerMessage(raw) {
|
|
|
2572
3054
|
if (typeof message.message !== "string") {
|
|
2573
3055
|
return null;
|
|
2574
3056
|
}
|
|
3057
|
+
const code = isOutputErrorCode2(message.code) ? message.code : void 0;
|
|
3058
|
+
const detailCode = typeof message.detailCode === "string" && message.detailCode.trim().length > 0 ? message.detailCode : void 0;
|
|
3059
|
+
const origin = isOutputErrorOrigin2(message.origin) ? message.origin : void 0;
|
|
3060
|
+
const retryable = typeof message.retryable === "boolean" ? message.retryable : void 0;
|
|
3061
|
+
const acp = parseAcpError(message.acp);
|
|
2575
3062
|
return {
|
|
2576
3063
|
type: "error",
|
|
2577
3064
|
requestId: message.requestId,
|
|
2578
|
-
|
|
3065
|
+
code,
|
|
3066
|
+
detailCode,
|
|
3067
|
+
origin,
|
|
3068
|
+
message: message.message,
|
|
3069
|
+
retryable,
|
|
3070
|
+
acp
|
|
2579
3071
|
};
|
|
2580
3072
|
}
|
|
2581
3073
|
return null;
|
|
@@ -2589,21 +3081,34 @@ var QUEUE_CONNECT_RETRY_MS = 50;
|
|
|
2589
3081
|
function queueBaseDir() {
|
|
2590
3082
|
return path4.join(os2.homedir(), ".acpx", "queues");
|
|
2591
3083
|
}
|
|
2592
|
-
function
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
3084
|
+
function makeQueueOwnerError(requestId, message, detailCode, options = {}) {
|
|
3085
|
+
return {
|
|
3086
|
+
type: "error",
|
|
3087
|
+
requestId,
|
|
3088
|
+
code: "RUNTIME",
|
|
3089
|
+
detailCode,
|
|
3090
|
+
origin: "queue",
|
|
3091
|
+
retryable: options.retryable,
|
|
3092
|
+
message
|
|
3093
|
+
};
|
|
3094
|
+
}
|
|
3095
|
+
function makeQueueOwnerErrorFromUnknown(requestId, error, detailCode, options = {}) {
|
|
3096
|
+
const normalized = normalizeOutputError(error, {
|
|
3097
|
+
defaultCode: "RUNTIME",
|
|
3098
|
+
origin: "queue",
|
|
3099
|
+
detailCode,
|
|
3100
|
+
retryable: options.retryable
|
|
3101
|
+
});
|
|
3102
|
+
return {
|
|
3103
|
+
type: "error",
|
|
3104
|
+
requestId,
|
|
3105
|
+
code: normalized.code,
|
|
3106
|
+
detailCode: normalized.detailCode,
|
|
3107
|
+
origin: normalized.origin,
|
|
3108
|
+
message: normalized.message,
|
|
3109
|
+
retryable: normalized.retryable,
|
|
3110
|
+
acp: normalized.acp
|
|
3111
|
+
};
|
|
2607
3112
|
}
|
|
2608
3113
|
function isProcessAlive(pid) {
|
|
2609
3114
|
if (!pid || !Number.isInteger(pid) || pid <= 0 || pid === process.pid) {
|
|
@@ -2847,11 +3352,16 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2847
3352
|
}
|
|
2848
3353
|
for (const task of this.pending.splice(0)) {
|
|
2849
3354
|
if (task.waitForCompletion) {
|
|
2850
|
-
task.send(
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
3355
|
+
task.send(
|
|
3356
|
+
makeQueueOwnerError(
|
|
3357
|
+
task.requestId,
|
|
3358
|
+
"Queue owner shutting down before prompt execution",
|
|
3359
|
+
"QUEUE_OWNER_SHUTTING_DOWN",
|
|
3360
|
+
{
|
|
3361
|
+
retryable: true
|
|
3362
|
+
}
|
|
3363
|
+
)
|
|
3364
|
+
);
|
|
2855
3365
|
}
|
|
2856
3366
|
task.close();
|
|
2857
3367
|
}
|
|
@@ -2890,11 +3400,16 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2890
3400
|
enqueue(task) {
|
|
2891
3401
|
if (this.closed) {
|
|
2892
3402
|
if (task.waitForCompletion) {
|
|
2893
|
-
task.send(
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
3403
|
+
task.send(
|
|
3404
|
+
makeQueueOwnerError(
|
|
3405
|
+
task.requestId,
|
|
3406
|
+
"Queue owner is shutting down",
|
|
3407
|
+
"QUEUE_OWNER_SHUTTING_DOWN",
|
|
3408
|
+
{
|
|
3409
|
+
retryable: true
|
|
3410
|
+
}
|
|
3411
|
+
)
|
|
3412
|
+
);
|
|
2898
3413
|
}
|
|
2899
3414
|
task.close();
|
|
2900
3415
|
return;
|
|
@@ -2909,22 +3424,24 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2909
3424
|
handleConnection(socket) {
|
|
2910
3425
|
socket.setEncoding("utf8");
|
|
2911
3426
|
if (this.closed) {
|
|
2912
|
-
writeQueueMessage(
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
3427
|
+
writeQueueMessage(
|
|
3428
|
+
socket,
|
|
3429
|
+
makeQueueOwnerError("unknown", "Queue owner is closed", "QUEUE_OWNER_CLOSED", {
|
|
3430
|
+
retryable: true
|
|
3431
|
+
})
|
|
3432
|
+
);
|
|
2917
3433
|
socket.end();
|
|
2918
3434
|
return;
|
|
2919
3435
|
}
|
|
2920
3436
|
let buffer = "";
|
|
2921
3437
|
let handled = false;
|
|
2922
|
-
const fail = (requestId, message) => {
|
|
2923
|
-
writeQueueMessage(
|
|
2924
|
-
|
|
2925
|
-
requestId,
|
|
2926
|
-
|
|
2927
|
-
|
|
3438
|
+
const fail = (requestId, message, detailCode) => {
|
|
3439
|
+
writeQueueMessage(
|
|
3440
|
+
socket,
|
|
3441
|
+
makeQueueOwnerError(requestId, message, detailCode, {
|
|
3442
|
+
retryable: false
|
|
3443
|
+
})
|
|
3444
|
+
);
|
|
2928
3445
|
socket.end();
|
|
2929
3446
|
};
|
|
2930
3447
|
const processLine = (line) => {
|
|
@@ -2936,12 +3453,16 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2936
3453
|
try {
|
|
2937
3454
|
parsed = JSON.parse(line);
|
|
2938
3455
|
} catch {
|
|
2939
|
-
fail(
|
|
3456
|
+
fail(
|
|
3457
|
+
"unknown",
|
|
3458
|
+
"Invalid queue request payload",
|
|
3459
|
+
"QUEUE_REQUEST_PAYLOAD_INVALID_JSON"
|
|
3460
|
+
);
|
|
2940
3461
|
return;
|
|
2941
3462
|
}
|
|
2942
3463
|
const request = parseQueueRequest(parsed);
|
|
2943
3464
|
if (!request) {
|
|
2944
|
-
fail("unknown", "Invalid queue request");
|
|
3465
|
+
fail("unknown", "Invalid queue request", "QUEUE_REQUEST_INVALID");
|
|
2945
3466
|
return;
|
|
2946
3467
|
}
|
|
2947
3468
|
if (request.type === "cancel_prompt") {
|
|
@@ -2956,12 +3477,14 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2956
3477
|
cancelled: cancelled2
|
|
2957
3478
|
});
|
|
2958
3479
|
}).catch((error) => {
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
3480
|
+
writeQueueMessage(
|
|
3481
|
+
socket,
|
|
3482
|
+
makeQueueOwnerErrorFromUnknown(
|
|
3483
|
+
request.requestId,
|
|
3484
|
+
error,
|
|
3485
|
+
"QUEUE_CONTROL_REQUEST_FAILED"
|
|
3486
|
+
)
|
|
3487
|
+
);
|
|
2965
3488
|
}).finally(() => {
|
|
2966
3489
|
if (!socket.destroyed) {
|
|
2967
3490
|
socket.end();
|
|
@@ -2981,12 +3504,14 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
2981
3504
|
modeId: request.modeId
|
|
2982
3505
|
});
|
|
2983
3506
|
}).catch((error) => {
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
3507
|
+
writeQueueMessage(
|
|
3508
|
+
socket,
|
|
3509
|
+
makeQueueOwnerErrorFromUnknown(
|
|
3510
|
+
request.requestId,
|
|
3511
|
+
error,
|
|
3512
|
+
"QUEUE_CONTROL_REQUEST_FAILED"
|
|
3513
|
+
)
|
|
3514
|
+
);
|
|
2990
3515
|
}).finally(() => {
|
|
2991
3516
|
if (!socket.destroyed) {
|
|
2992
3517
|
socket.end();
|
|
@@ -3006,12 +3531,14 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
3006
3531
|
response
|
|
3007
3532
|
});
|
|
3008
3533
|
}).catch((error) => {
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3534
|
+
writeQueueMessage(
|
|
3535
|
+
socket,
|
|
3536
|
+
makeQueueOwnerErrorFromUnknown(
|
|
3537
|
+
request.requestId,
|
|
3538
|
+
error,
|
|
3539
|
+
"QUEUE_CONTROL_REQUEST_FAILED"
|
|
3540
|
+
)
|
|
3541
|
+
);
|
|
3015
3542
|
}).finally(() => {
|
|
3016
3543
|
if (!socket.destroyed) {
|
|
3017
3544
|
socket.end();
|
|
@@ -3023,7 +3550,9 @@ var SessionQueueOwner = class _SessionQueueOwner {
|
|
|
3023
3550
|
requestId: request.requestId,
|
|
3024
3551
|
message: request.message,
|
|
3025
3552
|
permissionMode: request.permissionMode,
|
|
3553
|
+
nonInteractivePermissions: request.nonInteractivePermissions,
|
|
3026
3554
|
timeoutMs: request.timeoutMs,
|
|
3555
|
+
suppressSdkConsoleErrors: request.suppressSdkConsoleErrors,
|
|
3027
3556
|
waitForCompletion: request.waitForCompletion,
|
|
3028
3557
|
send: (message) => {
|
|
3029
3558
|
writeQueueMessage(socket, message);
|
|
@@ -3071,9 +3600,16 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3071
3600
|
requestId,
|
|
3072
3601
|
message: options.message,
|
|
3073
3602
|
permissionMode: options.permissionMode,
|
|
3603
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
3074
3604
|
timeoutMs: options.timeoutMs,
|
|
3605
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
3075
3606
|
waitForCompletion: options.waitForCompletion
|
|
3076
3607
|
};
|
|
3608
|
+
options.outputFormatter.setContext({
|
|
3609
|
+
sessionId: options.sessionId,
|
|
3610
|
+
requestId,
|
|
3611
|
+
stream: "prompt"
|
|
3612
|
+
});
|
|
3077
3613
|
return await new Promise((resolve, reject) => {
|
|
3078
3614
|
let settled = false;
|
|
3079
3615
|
let acknowledged = false;
|
|
@@ -3106,16 +3642,33 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3106
3642
|
try {
|
|
3107
3643
|
parsed = JSON.parse(line);
|
|
3108
3644
|
} catch {
|
|
3109
|
-
finishReject(
|
|
3645
|
+
finishReject(
|
|
3646
|
+
new QueueProtocolError("Queue owner sent invalid JSON payload", {
|
|
3647
|
+
detailCode: "QUEUE_PROTOCOL_INVALID_JSON",
|
|
3648
|
+
origin: "queue",
|
|
3649
|
+
retryable: true
|
|
3650
|
+
})
|
|
3651
|
+
);
|
|
3110
3652
|
return;
|
|
3111
3653
|
}
|
|
3112
3654
|
const message = parseQueueOwnerMessage(parsed);
|
|
3113
3655
|
if (!message || message.requestId !== requestId) {
|
|
3114
|
-
finishReject(
|
|
3656
|
+
finishReject(
|
|
3657
|
+
new QueueProtocolError("Queue owner sent malformed message", {
|
|
3658
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
3659
|
+
origin: "queue",
|
|
3660
|
+
retryable: true
|
|
3661
|
+
})
|
|
3662
|
+
);
|
|
3115
3663
|
return;
|
|
3116
3664
|
}
|
|
3117
3665
|
if (message.type === "accepted") {
|
|
3118
3666
|
acknowledged = true;
|
|
3667
|
+
options.outputFormatter.setContext({
|
|
3668
|
+
sessionId: options.sessionId,
|
|
3669
|
+
requestId: message.requestId,
|
|
3670
|
+
stream: "prompt"
|
|
3671
|
+
});
|
|
3119
3672
|
if (!options.waitForCompletion) {
|
|
3120
3673
|
const queued = {
|
|
3121
3674
|
queued: true,
|
|
@@ -3126,9 +3679,41 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3126
3679
|
}
|
|
3127
3680
|
return;
|
|
3128
3681
|
}
|
|
3682
|
+
if (message.type === "error") {
|
|
3683
|
+
options.outputFormatter.setContext({
|
|
3684
|
+
sessionId: options.sessionId,
|
|
3685
|
+
requestId: message.requestId,
|
|
3686
|
+
stream: "prompt"
|
|
3687
|
+
});
|
|
3688
|
+
options.outputFormatter.onError({
|
|
3689
|
+
code: message.code ?? "RUNTIME",
|
|
3690
|
+
detailCode: message.detailCode,
|
|
3691
|
+
origin: message.origin ?? "queue",
|
|
3692
|
+
message: message.message,
|
|
3693
|
+
retryable: message.retryable,
|
|
3694
|
+
acp: message.acp
|
|
3695
|
+
});
|
|
3696
|
+
options.outputFormatter.flush();
|
|
3697
|
+
const queueErrorAlreadyEmitted = options.errorEmissionPolicy?.queueErrorAlreadyEmitted ?? true;
|
|
3698
|
+
finishReject(
|
|
3699
|
+
new QueueConnectionError(message.message, {
|
|
3700
|
+
outputCode: message.code,
|
|
3701
|
+
detailCode: message.detailCode,
|
|
3702
|
+
origin: message.origin ?? "queue",
|
|
3703
|
+
retryable: message.retryable,
|
|
3704
|
+
acp: message.acp,
|
|
3705
|
+
...queueErrorAlreadyEmitted ? { outputAlreadyEmitted: true } : {}
|
|
3706
|
+
})
|
|
3707
|
+
);
|
|
3708
|
+
return;
|
|
3709
|
+
}
|
|
3129
3710
|
if (!acknowledged) {
|
|
3130
3711
|
finishReject(
|
|
3131
|
-
new QueueConnectionError("Queue owner did not acknowledge request"
|
|
3712
|
+
new QueueConnectionError("Queue owner did not acknowledge request", {
|
|
3713
|
+
detailCode: "QUEUE_ACK_MISSING",
|
|
3714
|
+
origin: "queue",
|
|
3715
|
+
retryable: true
|
|
3716
|
+
})
|
|
3132
3717
|
);
|
|
3133
3718
|
return;
|
|
3134
3719
|
}
|
|
@@ -3153,11 +3738,13 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3153
3738
|
finishResolve(message.result);
|
|
3154
3739
|
return;
|
|
3155
3740
|
}
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3741
|
+
finishReject(
|
|
3742
|
+
new QueueProtocolError("Queue owner returned unexpected response", {
|
|
3743
|
+
detailCode: "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE",
|
|
3744
|
+
origin: "queue",
|
|
3745
|
+
retryable: true
|
|
3746
|
+
})
|
|
3747
|
+
);
|
|
3161
3748
|
};
|
|
3162
3749
|
socket.on("data", (chunk) => {
|
|
3163
3750
|
buffer += chunk;
|
|
@@ -3181,7 +3768,12 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3181
3768
|
if (!acknowledged) {
|
|
3182
3769
|
finishReject(
|
|
3183
3770
|
new QueueConnectionError(
|
|
3184
|
-
"Queue owner disconnected before acknowledging request"
|
|
3771
|
+
"Queue owner disconnected before acknowledging request",
|
|
3772
|
+
{
|
|
3773
|
+
detailCode: "QUEUE_DISCONNECTED_BEFORE_ACK",
|
|
3774
|
+
origin: "queue",
|
|
3775
|
+
retryable: true
|
|
3776
|
+
}
|
|
3185
3777
|
)
|
|
3186
3778
|
);
|
|
3187
3779
|
return;
|
|
@@ -3196,7 +3788,11 @@ async function submitToQueueOwner(owner, options) {
|
|
|
3196
3788
|
return;
|
|
3197
3789
|
}
|
|
3198
3790
|
finishReject(
|
|
3199
|
-
new QueueConnectionError("Queue owner disconnected before prompt completion"
|
|
3791
|
+
new QueueConnectionError("Queue owner disconnected before prompt completion", {
|
|
3792
|
+
detailCode: "QUEUE_DISCONNECTED_BEFORE_COMPLETION",
|
|
3793
|
+
origin: "queue",
|
|
3794
|
+
retryable: true
|
|
3795
|
+
})
|
|
3200
3796
|
);
|
|
3201
3797
|
});
|
|
3202
3798
|
socket.write(`${JSON.stringify(request)}
|
|
@@ -3240,31 +3836,59 @@ async function submitControlToQueueOwner(owner, request, isExpectedResponse) {
|
|
|
3240
3836
|
try {
|
|
3241
3837
|
parsed = JSON.parse(line);
|
|
3242
3838
|
} catch {
|
|
3243
|
-
finishReject(
|
|
3839
|
+
finishReject(
|
|
3840
|
+
new QueueProtocolError("Queue owner sent invalid JSON payload", {
|
|
3841
|
+
detailCode: "QUEUE_PROTOCOL_INVALID_JSON",
|
|
3842
|
+
origin: "queue",
|
|
3843
|
+
retryable: true
|
|
3844
|
+
})
|
|
3845
|
+
);
|
|
3244
3846
|
return;
|
|
3245
3847
|
}
|
|
3246
3848
|
const message = parseQueueOwnerMessage(parsed);
|
|
3247
3849
|
if (!message || message.requestId !== request.requestId) {
|
|
3248
|
-
finishReject(
|
|
3850
|
+
finishReject(
|
|
3851
|
+
new QueueProtocolError("Queue owner sent malformed message", {
|
|
3852
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
3853
|
+
origin: "queue",
|
|
3854
|
+
retryable: true
|
|
3855
|
+
})
|
|
3856
|
+
);
|
|
3249
3857
|
return;
|
|
3250
3858
|
}
|
|
3251
3859
|
if (message.type === "accepted") {
|
|
3252
3860
|
acknowledged = true;
|
|
3253
3861
|
return;
|
|
3254
3862
|
}
|
|
3255
|
-
if (
|
|
3863
|
+
if (message.type === "error") {
|
|
3256
3864
|
finishReject(
|
|
3257
|
-
new QueueConnectionError(
|
|
3865
|
+
new QueueConnectionError(message.message, {
|
|
3866
|
+
outputCode: message.code,
|
|
3867
|
+
detailCode: message.detailCode,
|
|
3868
|
+
origin: message.origin ?? "queue",
|
|
3869
|
+
retryable: message.retryable,
|
|
3870
|
+
acp: message.acp
|
|
3871
|
+
})
|
|
3258
3872
|
);
|
|
3259
3873
|
return;
|
|
3260
3874
|
}
|
|
3261
|
-
if (
|
|
3262
|
-
finishReject(
|
|
3875
|
+
if (!acknowledged) {
|
|
3876
|
+
finishReject(
|
|
3877
|
+
new QueueConnectionError("Queue owner did not acknowledge request", {
|
|
3878
|
+
detailCode: "QUEUE_ACK_MISSING",
|
|
3879
|
+
origin: "queue",
|
|
3880
|
+
retryable: true
|
|
3881
|
+
})
|
|
3882
|
+
);
|
|
3263
3883
|
return;
|
|
3264
3884
|
}
|
|
3265
3885
|
if (!isExpectedResponse(message)) {
|
|
3266
3886
|
finishReject(
|
|
3267
|
-
new QueueProtocolError("Queue owner returned unexpected response"
|
|
3887
|
+
new QueueProtocolError("Queue owner returned unexpected response", {
|
|
3888
|
+
detailCode: "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE",
|
|
3889
|
+
origin: "queue",
|
|
3890
|
+
retryable: true
|
|
3891
|
+
})
|
|
3268
3892
|
);
|
|
3269
3893
|
return;
|
|
3270
3894
|
}
|
|
@@ -3292,13 +3916,22 @@ async function submitControlToQueueOwner(owner, request, isExpectedResponse) {
|
|
|
3292
3916
|
if (!acknowledged) {
|
|
3293
3917
|
finishReject(
|
|
3294
3918
|
new QueueConnectionError(
|
|
3295
|
-
"Queue owner disconnected before acknowledging request"
|
|
3919
|
+
"Queue owner disconnected before acknowledging request",
|
|
3920
|
+
{
|
|
3921
|
+
detailCode: "QUEUE_DISCONNECTED_BEFORE_ACK",
|
|
3922
|
+
origin: "queue",
|
|
3923
|
+
retryable: true
|
|
3924
|
+
}
|
|
3296
3925
|
)
|
|
3297
3926
|
);
|
|
3298
3927
|
return;
|
|
3299
3928
|
}
|
|
3300
3929
|
finishReject(
|
|
3301
|
-
new QueueConnectionError("Queue owner disconnected before responding"
|
|
3930
|
+
new QueueConnectionError("Queue owner disconnected before responding", {
|
|
3931
|
+
detailCode: "QUEUE_DISCONNECTED_BEFORE_COMPLETION",
|
|
3932
|
+
origin: "queue",
|
|
3933
|
+
retryable: true
|
|
3934
|
+
})
|
|
3302
3935
|
);
|
|
3303
3936
|
});
|
|
3304
3937
|
socket.write(`${JSON.stringify(request)}
|
|
@@ -3319,7 +3952,11 @@ async function submitCancelToQueueOwner(owner) {
|
|
|
3319
3952
|
return void 0;
|
|
3320
3953
|
}
|
|
3321
3954
|
if (response.requestId !== request.requestId) {
|
|
3322
|
-
throw new QueueProtocolError("Queue owner returned mismatched cancel response"
|
|
3955
|
+
throw new QueueProtocolError("Queue owner returned mismatched cancel response", {
|
|
3956
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
3957
|
+
origin: "queue",
|
|
3958
|
+
retryable: true
|
|
3959
|
+
});
|
|
3323
3960
|
}
|
|
3324
3961
|
return response.cancelled;
|
|
3325
3962
|
}
|
|
@@ -3339,7 +3976,11 @@ async function submitSetModeToQueueOwner(owner, modeId, timeoutMs) {
|
|
|
3339
3976
|
return void 0;
|
|
3340
3977
|
}
|
|
3341
3978
|
if (response.requestId !== request.requestId) {
|
|
3342
|
-
throw new QueueProtocolError("Queue owner returned mismatched set_mode response"
|
|
3979
|
+
throw new QueueProtocolError("Queue owner returned mismatched set_mode response", {
|
|
3980
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
3981
|
+
origin: "queue",
|
|
3982
|
+
retryable: true
|
|
3983
|
+
});
|
|
3343
3984
|
}
|
|
3344
3985
|
return true;
|
|
3345
3986
|
}
|
|
@@ -3361,7 +4002,12 @@ async function submitSetConfigOptionToQueueOwner(owner, configId, value, timeout
|
|
|
3361
4002
|
}
|
|
3362
4003
|
if (response.requestId !== request.requestId) {
|
|
3363
4004
|
throw new QueueProtocolError(
|
|
3364
|
-
"Queue owner returned mismatched set_config_option response"
|
|
4005
|
+
"Queue owner returned mismatched set_config_option response",
|
|
4006
|
+
{
|
|
4007
|
+
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
4008
|
+
origin: "queue",
|
|
4009
|
+
retryable: true
|
|
4010
|
+
}
|
|
3365
4011
|
);
|
|
3366
4012
|
}
|
|
3367
4013
|
return response.response;
|
|
@@ -3390,7 +4036,12 @@ async function trySubmitToRunningOwner(options) {
|
|
|
3390
4036
|
return void 0;
|
|
3391
4037
|
}
|
|
3392
4038
|
throw new QueueConnectionError(
|
|
3393
|
-
"Session queue owner is running but not accepting queue requests"
|
|
4039
|
+
"Session queue owner is running but not accepting queue requests",
|
|
4040
|
+
{
|
|
4041
|
+
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
4042
|
+
origin: "queue",
|
|
4043
|
+
retryable: true
|
|
4044
|
+
}
|
|
3394
4045
|
);
|
|
3395
4046
|
}
|
|
3396
4047
|
async function tryCancelOnRunningOwner(options) {
|
|
@@ -3417,7 +4068,12 @@ async function tryCancelOnRunningOwner(options) {
|
|
|
3417
4068
|
return void 0;
|
|
3418
4069
|
}
|
|
3419
4070
|
throw new QueueConnectionError(
|
|
3420
|
-
"Session queue owner is running but not accepting cancel requests"
|
|
4071
|
+
"Session queue owner is running but not accepting cancel requests",
|
|
4072
|
+
{
|
|
4073
|
+
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
4074
|
+
origin: "queue",
|
|
4075
|
+
retryable: true
|
|
4076
|
+
}
|
|
3421
4077
|
);
|
|
3422
4078
|
}
|
|
3423
4079
|
async function trySetModeOnRunningOwner(sessionId, modeId, timeoutMs, verbose) {
|
|
@@ -3444,7 +4100,12 @@ async function trySetModeOnRunningOwner(sessionId, modeId, timeoutMs, verbose) {
|
|
|
3444
4100
|
return void 0;
|
|
3445
4101
|
}
|
|
3446
4102
|
throw new QueueConnectionError(
|
|
3447
|
-
"Session queue owner is running but not accepting set_mode requests"
|
|
4103
|
+
"Session queue owner is running but not accepting set_mode requests",
|
|
4104
|
+
{
|
|
4105
|
+
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
4106
|
+
origin: "queue",
|
|
4107
|
+
retryable: true
|
|
4108
|
+
}
|
|
3448
4109
|
);
|
|
3449
4110
|
}
|
|
3450
4111
|
async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, timeoutMs, verbose) {
|
|
@@ -3476,7 +4137,12 @@ async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, time
|
|
|
3476
4137
|
return void 0;
|
|
3477
4138
|
}
|
|
3478
4139
|
throw new QueueConnectionError(
|
|
3479
|
-
"Session queue owner is running but not accepting set_config_option requests"
|
|
4140
|
+
"Session queue owner is running but not accepting set_config_option requests",
|
|
4141
|
+
{
|
|
4142
|
+
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
4143
|
+
origin: "queue",
|
|
4144
|
+
retryable: true
|
|
4145
|
+
}
|
|
3480
4146
|
);
|
|
3481
4147
|
}
|
|
3482
4148
|
async function terminateQueueOwnerForSession(sessionId) {
|
|
@@ -3815,6 +4481,8 @@ var QueueTaskOutputFormatter = class {
|
|
|
3815
4481
|
this.requestId = task.requestId;
|
|
3816
4482
|
this.send = task.send;
|
|
3817
4483
|
}
|
|
4484
|
+
setContext() {
|
|
4485
|
+
}
|
|
3818
4486
|
onSessionUpdate(notification) {
|
|
3819
4487
|
this.send({
|
|
3820
4488
|
type: "session_update",
|
|
@@ -3836,16 +4504,32 @@ var QueueTaskOutputFormatter = class {
|
|
|
3836
4504
|
stopReason
|
|
3837
4505
|
});
|
|
3838
4506
|
}
|
|
4507
|
+
onError(params) {
|
|
4508
|
+
this.send({
|
|
4509
|
+
type: "error",
|
|
4510
|
+
requestId: this.requestId,
|
|
4511
|
+
code: params.code,
|
|
4512
|
+
detailCode: params.detailCode,
|
|
4513
|
+
origin: params.origin,
|
|
4514
|
+
message: params.message,
|
|
4515
|
+
retryable: params.retryable,
|
|
4516
|
+
acp: params.acp
|
|
4517
|
+
});
|
|
4518
|
+
}
|
|
3839
4519
|
flush() {
|
|
3840
4520
|
}
|
|
3841
4521
|
};
|
|
3842
4522
|
var DISCARD_OUTPUT_FORMATTER = {
|
|
4523
|
+
setContext() {
|
|
4524
|
+
},
|
|
3843
4525
|
onSessionUpdate() {
|
|
3844
4526
|
},
|
|
3845
4527
|
onClientOperation() {
|
|
3846
4528
|
},
|
|
3847
4529
|
onDone() {
|
|
3848
4530
|
},
|
|
4531
|
+
onError() {
|
|
4532
|
+
},
|
|
3849
4533
|
flush() {
|
|
3850
4534
|
}
|
|
3851
4535
|
};
|
|
@@ -3858,22 +4542,6 @@ function normalizeQueueOwnerTtlMs(ttlMs) {
|
|
|
3858
4542
|
}
|
|
3859
4543
|
return Math.round(ttlMs);
|
|
3860
4544
|
}
|
|
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
4545
|
function collapseWhitespace2(value) {
|
|
3878
4546
|
return value.replace(/\s+/g, " ").trim();
|
|
3879
4547
|
}
|
|
@@ -3953,12 +4621,7 @@ function shouldFallbackToNewSession(error) {
|
|
|
3953
4621
|
if (error instanceof TimeoutError || error instanceof InterruptedError) {
|
|
3954
4622
|
return false;
|
|
3955
4623
|
}
|
|
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;
|
|
4624
|
+
return isAcpResourceNotFoundError(error);
|
|
3962
4625
|
}
|
|
3963
4626
|
async function connectAndLoadSession(options) {
|
|
3964
4627
|
const record = options.record;
|
|
@@ -3998,7 +4661,7 @@ async function connectAndLoadSession(options) {
|
|
|
3998
4661
|
);
|
|
3999
4662
|
resumed = true;
|
|
4000
4663
|
} catch (error) {
|
|
4001
|
-
loadError =
|
|
4664
|
+
loadError = formatErrorMessage(error);
|
|
4002
4665
|
if (!shouldFallbackToNewSession(error)) {
|
|
4003
4666
|
throw error;
|
|
4004
4667
|
}
|
|
@@ -4026,10 +4689,12 @@ async function runQueuedTask(sessionRecordId, task, options) {
|
|
|
4026
4689
|
sessionRecordId,
|
|
4027
4690
|
message: task.message,
|
|
4028
4691
|
permissionMode: task.permissionMode,
|
|
4692
|
+
nonInteractivePermissions: task.nonInteractivePermissions ?? options.nonInteractivePermissions,
|
|
4029
4693
|
authCredentials: options.authCredentials,
|
|
4030
4694
|
authPolicy: options.authPolicy,
|
|
4031
4695
|
outputFormatter,
|
|
4032
4696
|
timeoutMs: task.timeoutMs,
|
|
4697
|
+
suppressSdkConsoleErrors: task.suppressSdkConsoleErrors ?? options.suppressSdkConsoleErrors,
|
|
4033
4698
|
verbose: options.verbose,
|
|
4034
4699
|
onClientAvailable: options.onClientAvailable,
|
|
4035
4700
|
onClientClosed: options.onClientClosed,
|
|
@@ -4043,12 +4708,20 @@ async function runQueuedTask(sessionRecordId, task, options) {
|
|
|
4043
4708
|
});
|
|
4044
4709
|
}
|
|
4045
4710
|
} catch (error) {
|
|
4046
|
-
const
|
|
4711
|
+
const normalizedError = normalizeOutputError(error, {
|
|
4712
|
+
origin: "runtime",
|
|
4713
|
+
detailCode: "QUEUE_RUNTIME_PROMPT_FAILED"
|
|
4714
|
+
});
|
|
4047
4715
|
if (task.waitForCompletion) {
|
|
4048
4716
|
task.send({
|
|
4049
4717
|
type: "error",
|
|
4050
4718
|
requestId: task.requestId,
|
|
4051
|
-
|
|
4719
|
+
code: normalizedError.code,
|
|
4720
|
+
detailCode: normalizedError.detailCode,
|
|
4721
|
+
origin: normalizedError.origin,
|
|
4722
|
+
message: normalizedError.message,
|
|
4723
|
+
retryable: normalizedError.retryable,
|
|
4724
|
+
acp: normalizedError.acp
|
|
4052
4725
|
});
|
|
4053
4726
|
}
|
|
4054
4727
|
if (error instanceof InterruptedError) {
|
|
@@ -4061,13 +4734,19 @@ async function runQueuedTask(sessionRecordId, task, options) {
|
|
|
4061
4734
|
async function runSessionPrompt(options) {
|
|
4062
4735
|
const output = options.outputFormatter;
|
|
4063
4736
|
const record = await resolveSessionRecord(options.sessionRecordId);
|
|
4737
|
+
output.setContext({
|
|
4738
|
+
sessionId: record.id,
|
|
4739
|
+
stream: "prompt"
|
|
4740
|
+
});
|
|
4064
4741
|
const assistantSnippets = [];
|
|
4065
4742
|
const client = new AcpClient({
|
|
4066
4743
|
agentCommand: record.agentCommand,
|
|
4067
4744
|
cwd: absolutePath(record.cwd),
|
|
4068
4745
|
permissionMode: options.permissionMode,
|
|
4746
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4069
4747
|
authCredentials: options.authCredentials,
|
|
4070
4748
|
authPolicy: options.authPolicy,
|
|
4749
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4071
4750
|
verbose: options.verbose,
|
|
4072
4751
|
onSessionUpdate: (notification) => {
|
|
4073
4752
|
output.onSessionUpdate(notification);
|
|
@@ -4129,7 +4808,7 @@ async function runSessionPrompt(options) {
|
|
|
4129
4808
|
} catch (error) {
|
|
4130
4809
|
if (options.verbose) {
|
|
4131
4810
|
process.stderr.write(
|
|
4132
|
-
`[acpx] onPromptActive hook failed: ${
|
|
4811
|
+
`[acpx] onPromptActive hook failed: ${formatErrorMessage(error)}
|
|
4133
4812
|
`
|
|
4134
4813
|
);
|
|
4135
4814
|
}
|
|
@@ -4209,6 +4888,7 @@ async function withConnectedSession(options) {
|
|
|
4209
4888
|
agentCommand: record.agentCommand,
|
|
4210
4889
|
cwd: absolutePath(record.cwd),
|
|
4211
4890
|
permissionMode: options.permissionMode ?? "approve-reads",
|
|
4891
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4212
4892
|
authCredentials: options.authCredentials,
|
|
4213
4893
|
authPolicy: options.authPolicy,
|
|
4214
4894
|
verbose: options.verbose
|
|
@@ -4288,6 +4968,7 @@ async function withConnectedSession(options) {
|
|
|
4288
4968
|
async function runSessionSetModeDirect(options) {
|
|
4289
4969
|
const result = await withConnectedSession({
|
|
4290
4970
|
sessionRecordId: options.sessionRecordId,
|
|
4971
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4291
4972
|
authCredentials: options.authCredentials,
|
|
4292
4973
|
authPolicy: options.authPolicy,
|
|
4293
4974
|
timeoutMs: options.timeoutMs,
|
|
@@ -4310,6 +4991,7 @@ async function runSessionSetModeDirect(options) {
|
|
|
4310
4991
|
async function runSessionSetConfigOptionDirect(options) {
|
|
4311
4992
|
const result = await withConnectedSession({
|
|
4312
4993
|
sessionRecordId: options.sessionRecordId,
|
|
4994
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4313
4995
|
authCredentials: options.authCredentials,
|
|
4314
4996
|
authPolicy: options.authPolicy,
|
|
4315
4997
|
timeoutMs: options.timeoutMs,
|
|
@@ -4336,8 +5018,10 @@ async function runOnce(options) {
|
|
|
4336
5018
|
agentCommand: options.agentCommand,
|
|
4337
5019
|
cwd: absolutePath(options.cwd),
|
|
4338
5020
|
permissionMode: options.permissionMode,
|
|
5021
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4339
5022
|
authCredentials: options.authCredentials,
|
|
4340
5023
|
authPolicy: options.authPolicy,
|
|
5024
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4341
5025
|
verbose: options.verbose,
|
|
4342
5026
|
onSessionUpdate: (notification) => output.onSessionUpdate(notification),
|
|
4343
5027
|
onClientOperation: (operation) => output.onClientOperation(operation)
|
|
@@ -4350,6 +5034,10 @@ async function runOnce(options) {
|
|
|
4350
5034
|
client.createSession(absolutePath(options.cwd)),
|
|
4351
5035
|
options.timeoutMs
|
|
4352
5036
|
);
|
|
5037
|
+
output.setContext({
|
|
5038
|
+
sessionId,
|
|
5039
|
+
stream: "prompt"
|
|
5040
|
+
});
|
|
4353
5041
|
const response = await withTimeout(
|
|
4354
5042
|
client.prompt(sessionId, options.message),
|
|
4355
5043
|
options.timeoutMs
|
|
@@ -4372,6 +5060,7 @@ async function createSession(options) {
|
|
|
4372
5060
|
agentCommand: options.agentCommand,
|
|
4373
5061
|
cwd: absolutePath(options.cwd),
|
|
4374
5062
|
permissionMode: options.permissionMode,
|
|
5063
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4375
5064
|
authCredentials: options.authCredentials,
|
|
4376
5065
|
authPolicy: options.authPolicy,
|
|
4377
5066
|
verbose: options.verbose
|
|
@@ -4413,6 +5102,38 @@ async function createSession(options) {
|
|
|
4413
5102
|
await client.close();
|
|
4414
5103
|
}
|
|
4415
5104
|
}
|
|
5105
|
+
async function ensureSession(options) {
|
|
5106
|
+
const cwd = absolutePath(options.cwd);
|
|
5107
|
+
const gitRoot = findGitRepositoryRoot(cwd);
|
|
5108
|
+
const walkBoundary = options.walkBoundary ?? gitRoot ?? cwd;
|
|
5109
|
+
const existing = await findSessionByDirectoryWalk({
|
|
5110
|
+
agentCommand: options.agentCommand,
|
|
5111
|
+
cwd,
|
|
5112
|
+
name: options.name,
|
|
5113
|
+
boundary: walkBoundary
|
|
5114
|
+
});
|
|
5115
|
+
if (existing) {
|
|
5116
|
+
return {
|
|
5117
|
+
record: existing,
|
|
5118
|
+
created: false
|
|
5119
|
+
};
|
|
5120
|
+
}
|
|
5121
|
+
const record = await createSession({
|
|
5122
|
+
agentCommand: options.agentCommand,
|
|
5123
|
+
cwd,
|
|
5124
|
+
name: options.name,
|
|
5125
|
+
permissionMode: options.permissionMode,
|
|
5126
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
5127
|
+
authCredentials: options.authCredentials,
|
|
5128
|
+
authPolicy: options.authPolicy,
|
|
5129
|
+
timeoutMs: options.timeoutMs,
|
|
5130
|
+
verbose: options.verbose
|
|
5131
|
+
});
|
|
5132
|
+
return {
|
|
5133
|
+
record,
|
|
5134
|
+
created: true
|
|
5135
|
+
};
|
|
5136
|
+
}
|
|
4416
5137
|
async function sendSession(options) {
|
|
4417
5138
|
const waitForCompletion = options.waitForCompletion !== false;
|
|
4418
5139
|
const queueOwnerTtlMs = normalizeQueueOwnerTtlMs(options.ttlMs);
|
|
@@ -4420,8 +5141,11 @@ async function sendSession(options) {
|
|
|
4420
5141
|
sessionId: options.sessionId,
|
|
4421
5142
|
message: options.message,
|
|
4422
5143
|
permissionMode: options.permissionMode,
|
|
5144
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4423
5145
|
outputFormatter: options.outputFormatter,
|
|
5146
|
+
errorEmissionPolicy: options.errorEmissionPolicy,
|
|
4424
5147
|
timeoutMs: options.timeoutMs,
|
|
5148
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4425
5149
|
waitForCompletion,
|
|
4426
5150
|
verbose: options.verbose
|
|
4427
5151
|
});
|
|
@@ -4435,8 +5159,11 @@ async function sendSession(options) {
|
|
|
4435
5159
|
sessionId: options.sessionId,
|
|
4436
5160
|
message: options.message,
|
|
4437
5161
|
permissionMode: options.permissionMode,
|
|
5162
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4438
5163
|
outputFormatter: options.outputFormatter,
|
|
5164
|
+
errorEmissionPolicy: options.errorEmissionPolicy,
|
|
4439
5165
|
timeoutMs: options.timeoutMs,
|
|
5166
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4440
5167
|
waitForCompletion,
|
|
4441
5168
|
verbose: options.verbose
|
|
4442
5169
|
});
|
|
@@ -4453,6 +5180,7 @@ async function sendSession(options) {
|
|
|
4453
5180
|
await runSessionSetModeDirect({
|
|
4454
5181
|
sessionRecordId: options.sessionId,
|
|
4455
5182
|
modeId,
|
|
5183
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4456
5184
|
authCredentials: options.authCredentials,
|
|
4457
5185
|
authPolicy: options.authPolicy,
|
|
4458
5186
|
timeoutMs,
|
|
@@ -4464,6 +5192,7 @@ async function sendSession(options) {
|
|
|
4464
5192
|
sessionRecordId: options.sessionId,
|
|
4465
5193
|
configId,
|
|
4466
5194
|
value,
|
|
5195
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4467
5196
|
authCredentials: options.authCredentials,
|
|
4468
5197
|
authPolicy: options.authPolicy,
|
|
4469
5198
|
timeoutMs,
|
|
@@ -4479,7 +5208,7 @@ async function sendSession(options) {
|
|
|
4479
5208
|
void applyPendingCancel().catch((error) => {
|
|
4480
5209
|
if (options.verbose) {
|
|
4481
5210
|
process.stderr.write(
|
|
4482
|
-
`[acpx] failed to apply deferred cancel: ${
|
|
5211
|
+
`[acpx] failed to apply deferred cancel: ${formatErrorMessage(error)}
|
|
4483
5212
|
`
|
|
4484
5213
|
);
|
|
4485
5214
|
}
|
|
@@ -4526,10 +5255,12 @@ async function sendSession(options) {
|
|
|
4526
5255
|
sessionRecordId: options.sessionId,
|
|
4527
5256
|
message: options.message,
|
|
4528
5257
|
permissionMode: options.permissionMode,
|
|
5258
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4529
5259
|
authCredentials: options.authCredentials,
|
|
4530
5260
|
authPolicy: options.authPolicy,
|
|
4531
5261
|
outputFormatter: options.outputFormatter,
|
|
4532
5262
|
timeoutMs: options.timeoutMs,
|
|
5263
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4533
5264
|
verbose: options.verbose,
|
|
4534
5265
|
onClientAvailable: setActiveController,
|
|
4535
5266
|
onClientClosed: clearActiveController,
|
|
@@ -4554,8 +5285,10 @@ async function sendSession(options) {
|
|
|
4554
5285
|
await runPromptTurn(async () => {
|
|
4555
5286
|
await runQueuedTask(options.sessionId, task, {
|
|
4556
5287
|
verbose: options.verbose,
|
|
5288
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4557
5289
|
authCredentials: options.authCredentials,
|
|
4558
5290
|
authPolicy: options.authPolicy,
|
|
5291
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
4559
5292
|
onClientAvailable: setActiveController,
|
|
4560
5293
|
onClientClosed: clearActiveController,
|
|
4561
5294
|
onPromptActive: async () => {
|
|
@@ -4598,6 +5331,7 @@ async function setSessionMode(options) {
|
|
|
4598
5331
|
return await runSessionSetModeDirect({
|
|
4599
5332
|
sessionRecordId: options.sessionId,
|
|
4600
5333
|
modeId: options.modeId,
|
|
5334
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4601
5335
|
authCredentials: options.authCredentials,
|
|
4602
5336
|
authPolicy: options.authPolicy,
|
|
4603
5337
|
timeoutMs: options.timeoutMs,
|
|
@@ -4623,6 +5357,7 @@ async function setSessionConfigOption(options) {
|
|
|
4623
5357
|
sessionRecordId: options.sessionId,
|
|
4624
5358
|
configId: options.configId,
|
|
4625
5359
|
value: options.value,
|
|
5360
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
4626
5361
|
authCredentials: options.authCredentials,
|
|
4627
5362
|
authPolicy: options.authPolicy,
|
|
4628
5363
|
timeoutMs: options.timeoutMs,
|
|
@@ -4669,19 +5404,6 @@ async function closeSession(sessionId) {
|
|
|
4669
5404
|
return record;
|
|
4670
5405
|
}
|
|
4671
5406
|
|
|
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
5407
|
// src/cli.ts
|
|
4686
5408
|
var NoSessionError = class extends Error {
|
|
4687
5409
|
constructor(message) {
|
|
@@ -4716,6 +5438,16 @@ function parseAuthPolicy2(value) {
|
|
|
4716
5438
|
}
|
|
4717
5439
|
return value;
|
|
4718
5440
|
}
|
|
5441
|
+
function parseNonInteractivePermissionPolicy2(value) {
|
|
5442
|
+
if (!NON_INTERACTIVE_PERMISSION_POLICIES.includes(
|
|
5443
|
+
value
|
|
5444
|
+
)) {
|
|
5445
|
+
throw new InvalidArgumentError(
|
|
5446
|
+
`Invalid non-interactive permission policy "${value}". Expected one of: ${NON_INTERACTIVE_PERMISSION_POLICIES.join(", ")}`
|
|
5447
|
+
);
|
|
5448
|
+
}
|
|
5449
|
+
return value;
|
|
5450
|
+
}
|
|
4719
5451
|
function parseTimeoutSeconds(value) {
|
|
4720
5452
|
const parsed = Number(value);
|
|
4721
5453
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
@@ -4817,7 +5549,14 @@ function addGlobalFlags(command) {
|
|
|
4817
5549
|
).option("--approve-all", "Auto-approve all permission requests").option(
|
|
4818
5550
|
"--approve-reads",
|
|
4819
5551
|
"Auto-approve read/search requests and prompt for writes"
|
|
4820
|
-
).option("--deny-all", "Deny all permission requests").option(
|
|
5552
|
+
).option("--deny-all", "Deny all permission requests").option(
|
|
5553
|
+
"--non-interactive-permissions <policy>",
|
|
5554
|
+
"When prompting is unavailable: deny or fail",
|
|
5555
|
+
parseNonInteractivePermissionPolicy2
|
|
5556
|
+
).option("--format <fmt>", "Output format: text, json, quiet", parseOutputFormat2).option(
|
|
5557
|
+
"--json-strict",
|
|
5558
|
+
"Strict JSON mode: requires --format json and suppresses non-JSON stderr output"
|
|
5559
|
+
).option(
|
|
4821
5560
|
"--timeout <seconds>",
|
|
4822
5561
|
"Maximum time to wait for agent response",
|
|
4823
5562
|
parseTimeoutSeconds
|
|
@@ -4866,19 +5605,39 @@ function addPromptInputOption(command) {
|
|
|
4866
5605
|
}
|
|
4867
5606
|
function resolveGlobalFlags(command, config) {
|
|
4868
5607
|
const opts = command.optsWithGlobals();
|
|
5608
|
+
const format = opts.format ?? config.format ?? "text";
|
|
5609
|
+
const jsonStrict = opts.jsonStrict === true;
|
|
5610
|
+
const verbose = opts.verbose === true;
|
|
5611
|
+
if (jsonStrict && format !== "json") {
|
|
5612
|
+
throw new InvalidArgumentError("--json-strict requires --format json");
|
|
5613
|
+
}
|
|
5614
|
+
if (jsonStrict && verbose) {
|
|
5615
|
+
throw new InvalidArgumentError("--json-strict cannot be combined with --verbose");
|
|
5616
|
+
}
|
|
4869
5617
|
return {
|
|
4870
5618
|
agent: opts.agent,
|
|
4871
5619
|
cwd: opts.cwd ?? process.cwd(),
|
|
4872
5620
|
authPolicy: opts.authPolicy ?? config.authPolicy,
|
|
5621
|
+
nonInteractivePermissions: opts.nonInteractivePermissions ?? config.nonInteractivePermissions,
|
|
5622
|
+
jsonStrict,
|
|
4873
5623
|
timeout: opts.timeout ?? config.timeoutMs,
|
|
4874
5624
|
ttl: opts.ttl ?? config.ttlMs ?? DEFAULT_QUEUE_OWNER_TTL_MS,
|
|
4875
|
-
verbose
|
|
4876
|
-
format
|
|
5625
|
+
verbose,
|
|
5626
|
+
format,
|
|
4877
5627
|
approveAll: opts.approveAll ? true : void 0,
|
|
4878
5628
|
approveReads: opts.approveReads ? true : void 0,
|
|
4879
5629
|
denyAll: opts.denyAll ? true : void 0
|
|
4880
5630
|
};
|
|
4881
5631
|
}
|
|
5632
|
+
function resolveOutputPolicy(format, jsonStrict) {
|
|
5633
|
+
return {
|
|
5634
|
+
format,
|
|
5635
|
+
jsonStrict,
|
|
5636
|
+
suppressNonJsonStderr: jsonStrict,
|
|
5637
|
+
queueErrorAlreadyEmitted: format !== "quiet",
|
|
5638
|
+
suppressSdkConsoleErrors: jsonStrict
|
|
5639
|
+
};
|
|
5640
|
+
}
|
|
4882
5641
|
function resolveAgentInvocation(explicitAgentName, globalFlags, config) {
|
|
4883
5642
|
const override = globalFlags.agent?.trim();
|
|
4884
5643
|
if (override && explicitAgentName) {
|
|
@@ -4966,6 +5725,29 @@ function printNewSessionByFormat(record, replaced, format) {
|
|
|
4966
5725
|
process.stdout.write(`${record.id}
|
|
4967
5726
|
`);
|
|
4968
5727
|
}
|
|
5728
|
+
function printEnsuredSessionByFormat(record, created, format) {
|
|
5729
|
+
if (format === "json") {
|
|
5730
|
+
process.stdout.write(
|
|
5731
|
+
`${JSON.stringify({
|
|
5732
|
+
type: "session_ensured",
|
|
5733
|
+
id: record.id,
|
|
5734
|
+
sessionId: record.sessionId,
|
|
5735
|
+
name: record.name,
|
|
5736
|
+
created
|
|
5737
|
+
})}
|
|
5738
|
+
`
|
|
5739
|
+
);
|
|
5740
|
+
return;
|
|
5741
|
+
}
|
|
5742
|
+
if (format === "quiet") {
|
|
5743
|
+
process.stdout.write(`${record.id}
|
|
5744
|
+
`);
|
|
5745
|
+
return;
|
|
5746
|
+
}
|
|
5747
|
+
const action = created ? "created" : "existing";
|
|
5748
|
+
process.stdout.write(`${record.id} (${action})
|
|
5749
|
+
`);
|
|
5750
|
+
}
|
|
4969
5751
|
function printQueuedPromptByFormat(result, format) {
|
|
4970
5752
|
if (format === "json") {
|
|
4971
5753
|
process.stdout.write(
|
|
@@ -5008,15 +5790,15 @@ function formatPromptSessionBannerLine(record, currentCwd) {
|
|
|
5008
5790
|
}
|
|
5009
5791
|
return `[acpx] session ${label} (${record.id}) \xB7 ${normalizedSessionCwd} \xB7 agent ${status}`;
|
|
5010
5792
|
}
|
|
5011
|
-
function printPromptSessionBanner(record, currentCwd, format) {
|
|
5012
|
-
if (format === "quiet") {
|
|
5793
|
+
function printPromptSessionBanner(record, currentCwd, format, jsonStrict = false) {
|
|
5794
|
+
if (format === "quiet" || jsonStrict && format === "json") {
|
|
5013
5795
|
return;
|
|
5014
5796
|
}
|
|
5015
5797
|
process.stderr.write(`${formatPromptSessionBannerLine(record, currentCwd)}
|
|
5016
5798
|
`);
|
|
5017
5799
|
}
|
|
5018
|
-
function printCreatedSessionBanner(record, agentName, format) {
|
|
5019
|
-
if (format === "quiet") {
|
|
5800
|
+
function printCreatedSessionBanner(record, agentName, format, jsonStrict = false) {
|
|
5801
|
+
if (format === "quiet" || jsonStrict && format === "json") {
|
|
5020
5802
|
return;
|
|
5021
5803
|
}
|
|
5022
5804
|
const label = formatSessionLabel(record);
|
|
@@ -5047,9 +5829,12 @@ Create one: ${createCmd}`
|
|
|
5047
5829
|
}
|
|
5048
5830
|
async function handlePrompt(explicitAgentName, promptParts, flags, command, config) {
|
|
5049
5831
|
const globalFlags = resolveGlobalFlags(command, config);
|
|
5832
|
+
const outputPolicy = resolveOutputPolicy(
|
|
5833
|
+
globalFlags.format,
|
|
5834
|
+
globalFlags.jsonStrict === true
|
|
5835
|
+
);
|
|
5050
5836
|
const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);
|
|
5051
5837
|
const prompt = await readPrompt(promptParts, flags.file, globalFlags.cwd);
|
|
5052
|
-
const outputFormatter = createOutputFormatter(globalFlags.format);
|
|
5053
5838
|
const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
|
|
5054
5839
|
const record = await findRoutedSessionOrThrow(
|
|
5055
5840
|
agent.agentCommand,
|
|
@@ -5057,21 +5842,37 @@ async function handlePrompt(explicitAgentName, promptParts, flags, command, conf
|
|
|
5057
5842
|
agent.cwd,
|
|
5058
5843
|
flags.session
|
|
5059
5844
|
);
|
|
5060
|
-
|
|
5845
|
+
const outputFormatter = createOutputFormatter(outputPolicy.format, {
|
|
5846
|
+
jsonContext: {
|
|
5847
|
+
sessionId: record.id,
|
|
5848
|
+
stream: "prompt"
|
|
5849
|
+
}
|
|
5850
|
+
});
|
|
5851
|
+
printPromptSessionBanner(
|
|
5852
|
+
record,
|
|
5853
|
+
agent.cwd,
|
|
5854
|
+
outputPolicy.format,
|
|
5855
|
+
outputPolicy.jsonStrict
|
|
5856
|
+
);
|
|
5061
5857
|
const result = await sendSession({
|
|
5062
5858
|
sessionId: record.id,
|
|
5063
5859
|
message: prompt,
|
|
5064
5860
|
permissionMode,
|
|
5861
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5065
5862
|
authCredentials: config.auth,
|
|
5066
5863
|
authPolicy: globalFlags.authPolicy,
|
|
5067
5864
|
outputFormatter,
|
|
5865
|
+
errorEmissionPolicy: {
|
|
5866
|
+
queueErrorAlreadyEmitted: outputPolicy.queueErrorAlreadyEmitted
|
|
5867
|
+
},
|
|
5868
|
+
suppressSdkConsoleErrors: outputPolicy.suppressSdkConsoleErrors,
|
|
5068
5869
|
timeoutMs: globalFlags.timeout,
|
|
5069
5870
|
ttlMs: globalFlags.ttl,
|
|
5070
5871
|
verbose: globalFlags.verbose,
|
|
5071
5872
|
waitForCompletion: flags.wait !== false
|
|
5072
5873
|
});
|
|
5073
5874
|
if ("queued" in result) {
|
|
5074
|
-
printQueuedPromptByFormat(result,
|
|
5875
|
+
printQueuedPromptByFormat(result, outputPolicy.format);
|
|
5075
5876
|
return;
|
|
5076
5877
|
}
|
|
5077
5878
|
applyPermissionExitCode(result);
|
|
@@ -5084,18 +5885,24 @@ async function handlePrompt(explicitAgentName, promptParts, flags, command, conf
|
|
|
5084
5885
|
}
|
|
5085
5886
|
async function handleExec(explicitAgentName, promptParts, flags, command, config) {
|
|
5086
5887
|
const globalFlags = resolveGlobalFlags(command, config);
|
|
5888
|
+
const outputPolicy = resolveOutputPolicy(
|
|
5889
|
+
globalFlags.format,
|
|
5890
|
+
globalFlags.jsonStrict === true
|
|
5891
|
+
);
|
|
5087
5892
|
const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);
|
|
5088
5893
|
const prompt = await readPrompt(promptParts, flags.file, globalFlags.cwd);
|
|
5089
|
-
const outputFormatter = createOutputFormatter(
|
|
5894
|
+
const outputFormatter = createOutputFormatter(outputPolicy.format);
|
|
5090
5895
|
const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
|
|
5091
5896
|
const result = await runOnce({
|
|
5092
5897
|
agentCommand: agent.agentCommand,
|
|
5093
5898
|
cwd: agent.cwd,
|
|
5094
5899
|
message: prompt,
|
|
5095
5900
|
permissionMode,
|
|
5901
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5096
5902
|
authCredentials: config.auth,
|
|
5097
5903
|
authPolicy: globalFlags.authPolicy,
|
|
5098
5904
|
outputFormatter,
|
|
5905
|
+
suppressSdkConsoleErrors: outputPolicy.suppressSdkConsoleErrors,
|
|
5099
5906
|
timeoutMs: globalFlags.timeout,
|
|
5100
5907
|
verbose: globalFlags.verbose
|
|
5101
5908
|
});
|
|
@@ -5196,6 +6003,7 @@ async function handleSetMode(explicitAgentName, modeId, flags, command, config)
|
|
|
5196
6003
|
const result = await setSessionMode({
|
|
5197
6004
|
sessionId: record.id,
|
|
5198
6005
|
modeId,
|
|
6006
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5199
6007
|
authCredentials: config.auth,
|
|
5200
6008
|
authPolicy: globalFlags.authPolicy,
|
|
5201
6009
|
timeoutMs: globalFlags.timeout,
|
|
@@ -5222,6 +6030,7 @@ async function handleSetConfigOption(explicitAgentName, configId, value, flags,
|
|
|
5222
6030
|
sessionId: record.id,
|
|
5223
6031
|
configId,
|
|
5224
6032
|
value,
|
|
6033
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5225
6034
|
authCredentials: config.auth,
|
|
5226
6035
|
authPolicy: globalFlags.authPolicy,
|
|
5227
6036
|
timeoutMs: globalFlags.timeout,
|
|
@@ -5281,12 +6090,18 @@ async function handleSessionsNew(explicitAgentName, flags, command, config) {
|
|
|
5281
6090
|
cwd: agent.cwd,
|
|
5282
6091
|
name: flags.name,
|
|
5283
6092
|
permissionMode,
|
|
6093
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
5284
6094
|
authCredentials: config.auth,
|
|
5285
6095
|
authPolicy: globalFlags.authPolicy,
|
|
5286
6096
|
timeoutMs: globalFlags.timeout,
|
|
5287
6097
|
verbose: globalFlags.verbose
|
|
5288
6098
|
});
|
|
5289
|
-
printCreatedSessionBanner(
|
|
6099
|
+
printCreatedSessionBanner(
|
|
6100
|
+
created,
|
|
6101
|
+
agent.agentName,
|
|
6102
|
+
globalFlags.format,
|
|
6103
|
+
globalFlags.jsonStrict
|
|
6104
|
+
);
|
|
5290
6105
|
if (globalFlags.verbose) {
|
|
5291
6106
|
const scope = flags.name ? `named session "${flags.name}"` : "cwd session";
|
|
5292
6107
|
process.stderr.write(`[acpx] created ${scope}: ${created.id}
|
|
@@ -5294,6 +6109,31 @@ async function handleSessionsNew(explicitAgentName, flags, command, config) {
|
|
|
5294
6109
|
}
|
|
5295
6110
|
printNewSessionByFormat(created, replaced, globalFlags.format);
|
|
5296
6111
|
}
|
|
6112
|
+
async function handleSessionsEnsure(explicitAgentName, flags, command, config) {
|
|
6113
|
+
const globalFlags = resolveGlobalFlags(command, config);
|
|
6114
|
+
const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);
|
|
6115
|
+
const agent = resolveAgentInvocation(explicitAgentName, globalFlags, config);
|
|
6116
|
+
const result = await ensureSession({
|
|
6117
|
+
agentCommand: agent.agentCommand,
|
|
6118
|
+
cwd: agent.cwd,
|
|
6119
|
+
name: flags.name,
|
|
6120
|
+
permissionMode,
|
|
6121
|
+
nonInteractivePermissions: globalFlags.nonInteractivePermissions,
|
|
6122
|
+
authCredentials: config.auth,
|
|
6123
|
+
authPolicy: globalFlags.authPolicy,
|
|
6124
|
+
timeoutMs: globalFlags.timeout,
|
|
6125
|
+
verbose: globalFlags.verbose
|
|
6126
|
+
});
|
|
6127
|
+
if (result.created) {
|
|
6128
|
+
printCreatedSessionBanner(
|
|
6129
|
+
result.record,
|
|
6130
|
+
agent.agentName,
|
|
6131
|
+
globalFlags.format,
|
|
6132
|
+
globalFlags.jsonStrict
|
|
6133
|
+
);
|
|
6134
|
+
}
|
|
6135
|
+
printEnsuredSessionByFormat(result.record, result.created, globalFlags.format);
|
|
6136
|
+
}
|
|
5297
6137
|
function printSessionDetailsByFormat(record, format) {
|
|
5298
6138
|
if (format === "json") {
|
|
5299
6139
|
process.stdout.write(`${JSON.stringify(record)}
|
|
@@ -5555,7 +6395,7 @@ async function handleConfigInit(command, config) {
|
|
|
5555
6395
|
`);
|
|
5556
6396
|
}
|
|
5557
6397
|
function registerSessionsCommand(parent, explicitAgentName, config) {
|
|
5558
|
-
const sessionsCommand = parent.command("sessions").description("List, create, or close sessions for this agent");
|
|
6398
|
+
const sessionsCommand = parent.command("sessions").description("List, ensure, create, or close sessions for this agent");
|
|
5559
6399
|
sessionsCommand.action(async function() {
|
|
5560
6400
|
await handleSessionsList(explicitAgentName, this, config);
|
|
5561
6401
|
});
|
|
@@ -5565,6 +6405,9 @@ function registerSessionsCommand(parent, explicitAgentName, config) {
|
|
|
5565
6405
|
sessionsCommand.command("new").description("Create a fresh session for current cwd").option("--name <name>", "Session name", parseSessionName).action(async function(flags) {
|
|
5566
6406
|
await handleSessionsNew(explicitAgentName, flags, this, config);
|
|
5567
6407
|
});
|
|
6408
|
+
sessionsCommand.command("ensure").description("Ensure a session exists for current cwd or ancestor").option("--name <name>", "Session name", parseSessionName).action(async function(flags) {
|
|
6409
|
+
await handleSessionsEnsure(explicitAgentName, flags, this, config);
|
|
6410
|
+
});
|
|
5568
6411
|
sessionsCommand.command("close").description("Close session for current cwd").argument("[name]", "Session name", parseSessionName).action(async function(name) {
|
|
5569
6412
|
await handleSessionsClose(explicitAgentName, name, this, config);
|
|
5570
6413
|
});
|
|
@@ -5685,14 +6528,14 @@ function detectAgentToken(argv) {
|
|
|
5685
6528
|
hasAgentOverride = true;
|
|
5686
6529
|
continue;
|
|
5687
6530
|
}
|
|
5688
|
-
if (token === "--cwd" || token === "--auth-policy" || token === "--format" || token === "--timeout" || token === "--ttl" || token === "--file") {
|
|
6531
|
+
if (token === "--cwd" || token === "--auth-policy" || token === "--non-interactive-permissions" || token === "--format" || token === "--timeout" || token === "--ttl" || token === "--file") {
|
|
5689
6532
|
index += 1;
|
|
5690
6533
|
continue;
|
|
5691
6534
|
}
|
|
5692
|
-
if (token.startsWith("--cwd=") || token.startsWith("--auth-policy=") || token.startsWith("--format=") || token.startsWith("--timeout=") || token.startsWith("--ttl=") || token.startsWith("--file=")) {
|
|
6535
|
+
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
6536
|
continue;
|
|
5694
6537
|
}
|
|
5695
|
-
if (token === "--approve-all" || token === "--approve-reads" || token === "--deny-all" || token === "--verbose") {
|
|
6538
|
+
if (token === "--approve-all" || token === "--approve-reads" || token === "--deny-all" || token === "--json-strict" || token === "--verbose") {
|
|
5696
6539
|
continue;
|
|
5697
6540
|
}
|
|
5698
6541
|
return { hasAgentOverride };
|
|
@@ -5722,15 +6565,103 @@ function detectInitialCwd(argv) {
|
|
|
5722
6565
|
}
|
|
5723
6566
|
return process.cwd();
|
|
5724
6567
|
}
|
|
6568
|
+
function detectRequestedOutputFormat(argv, fallback) {
|
|
6569
|
+
let detectedFormat = fallback;
|
|
6570
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
6571
|
+
const token = argv[index];
|
|
6572
|
+
if (token === "--") {
|
|
6573
|
+
break;
|
|
6574
|
+
}
|
|
6575
|
+
if (token === "--json-strict" || token.startsWith("--json-strict=")) {
|
|
6576
|
+
return "json";
|
|
6577
|
+
}
|
|
6578
|
+
if (token === "--format") {
|
|
6579
|
+
const raw = argv[index + 1];
|
|
6580
|
+
if (raw && OUTPUT_FORMATS.includes(raw)) {
|
|
6581
|
+
detectedFormat = raw;
|
|
6582
|
+
}
|
|
6583
|
+
continue;
|
|
6584
|
+
}
|
|
6585
|
+
if (token.startsWith("--format=")) {
|
|
6586
|
+
const raw = token.slice("--format=".length).trim();
|
|
6587
|
+
if (OUTPUT_FORMATS.includes(raw)) {
|
|
6588
|
+
detectedFormat = raw;
|
|
6589
|
+
}
|
|
6590
|
+
}
|
|
6591
|
+
}
|
|
6592
|
+
return detectedFormat;
|
|
6593
|
+
}
|
|
6594
|
+
function detectJsonStrict(argv) {
|
|
6595
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
6596
|
+
const token = argv[index];
|
|
6597
|
+
if (token === "--") {
|
|
6598
|
+
break;
|
|
6599
|
+
}
|
|
6600
|
+
if (token === "--json-strict") {
|
|
6601
|
+
return true;
|
|
6602
|
+
}
|
|
6603
|
+
if (token.startsWith("--json-strict=")) {
|
|
6604
|
+
return true;
|
|
6605
|
+
}
|
|
6606
|
+
}
|
|
6607
|
+
return false;
|
|
6608
|
+
}
|
|
6609
|
+
function emitJsonErrorEvent(error) {
|
|
6610
|
+
const formatter = createOutputFormatter("json", {
|
|
6611
|
+
jsonContext: {
|
|
6612
|
+
sessionId: "unknown",
|
|
6613
|
+
stream: "control"
|
|
6614
|
+
}
|
|
6615
|
+
});
|
|
6616
|
+
formatter.onError(error);
|
|
6617
|
+
formatter.flush();
|
|
6618
|
+
}
|
|
6619
|
+
function isOutputAlreadyEmitted(error) {
|
|
6620
|
+
if (!error || typeof error !== "object") {
|
|
6621
|
+
return false;
|
|
6622
|
+
}
|
|
6623
|
+
return error.outputAlreadyEmitted === true;
|
|
6624
|
+
}
|
|
6625
|
+
function emitRequestedError(error, normalized, outputPolicy) {
|
|
6626
|
+
if (isOutputAlreadyEmitted(error)) {
|
|
6627
|
+
return;
|
|
6628
|
+
}
|
|
6629
|
+
if (outputPolicy.format === "json") {
|
|
6630
|
+
emitJsonErrorEvent(normalized);
|
|
6631
|
+
} else if (!outputPolicy.suppressNonJsonStderr) {
|
|
6632
|
+
process.stderr.write(`${normalized.message}
|
|
6633
|
+
`);
|
|
6634
|
+
}
|
|
6635
|
+
}
|
|
6636
|
+
async function runWithOutputPolicy(_outputPolicy, run) {
|
|
6637
|
+
return await run();
|
|
6638
|
+
}
|
|
5725
6639
|
async function main(argv = process.argv) {
|
|
5726
6640
|
await maybeHandleSkillflag(argv, {
|
|
5727
6641
|
skillsRoot: findSkillsRoot(import.meta.url),
|
|
5728
6642
|
includeBundledSkill: false
|
|
5729
6643
|
});
|
|
5730
6644
|
const config = await loadResolvedConfig(detectInitialCwd(argv.slice(2)));
|
|
6645
|
+
const requestedJsonStrict = detectJsonStrict(argv.slice(2));
|
|
6646
|
+
const requestedOutputFormat = detectRequestedOutputFormat(
|
|
6647
|
+
argv.slice(2),
|
|
6648
|
+
config.format
|
|
6649
|
+
);
|
|
6650
|
+
const requestedOutputPolicy = resolveOutputPolicy(
|
|
6651
|
+
requestedOutputFormat,
|
|
6652
|
+
requestedJsonStrict
|
|
6653
|
+
);
|
|
5731
6654
|
const builtInAgents = listBuiltInAgents(config.agents);
|
|
5732
6655
|
const program = new Command();
|
|
5733
6656
|
program.name("acpx").description("Headless CLI client for the Agent Client Protocol").enablePositionalOptions().showHelpAfterError();
|
|
6657
|
+
if (requestedJsonStrict) {
|
|
6658
|
+
program.configureOutput({
|
|
6659
|
+
writeOut: () => {
|
|
6660
|
+
},
|
|
6661
|
+
writeErr: () => {
|
|
6662
|
+
}
|
|
6663
|
+
});
|
|
6664
|
+
}
|
|
5734
6665
|
addGlobalFlags(program);
|
|
5735
6666
|
for (const agentName of builtInAgents) {
|
|
5736
6667
|
registerAgentCommand(program, agentName, config);
|
|
@@ -5742,6 +6673,11 @@ async function main(argv = process.argv) {
|
|
|
5742
6673
|
}
|
|
5743
6674
|
program.argument("[prompt...]", "Prompt text").action(async function(promptParts) {
|
|
5744
6675
|
if (promptParts.length === 0 && process.stdin.isTTY) {
|
|
6676
|
+
if (requestedJsonStrict) {
|
|
6677
|
+
throw new InvalidArgumentError(
|
|
6678
|
+
"Prompt is required (pass as argument, --file, or pipe via stdin)"
|
|
6679
|
+
);
|
|
6680
|
+
}
|
|
5745
6681
|
this.outputHelp();
|
|
5746
6682
|
return;
|
|
5747
6683
|
}
|
|
@@ -5762,6 +6698,7 @@ Examples:
|
|
|
5762
6698
|
acpx codex -s backend "fix the API"
|
|
5763
6699
|
acpx codex sessions
|
|
5764
6700
|
acpx codex sessions new --name backend
|
|
6701
|
+
acpx codex sessions ensure --name backend
|
|
5765
6702
|
acpx codex sessions close backend
|
|
5766
6703
|
acpx codex status
|
|
5767
6704
|
acpx config show
|
|
@@ -5774,33 +6711,33 @@ Examples:
|
|
|
5774
6711
|
program.exitOverride((error) => {
|
|
5775
6712
|
throw error;
|
|
5776
6713
|
});
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
if (error
|
|
5782
|
-
|
|
6714
|
+
await runWithOutputPolicy(requestedOutputPolicy, async () => {
|
|
6715
|
+
try {
|
|
6716
|
+
await program.parseAsync(argv);
|
|
6717
|
+
} catch (error) {
|
|
6718
|
+
if (error instanceof CommanderError) {
|
|
6719
|
+
if (error.code === "commander.helpDisplayed" || error.code === "commander.version") {
|
|
6720
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
6721
|
+
}
|
|
6722
|
+
const normalized2 = normalizeOutputError(error, {
|
|
6723
|
+
defaultCode: "USAGE",
|
|
6724
|
+
origin: "cli"
|
|
6725
|
+
});
|
|
6726
|
+
if (requestedOutputPolicy.format === "json") {
|
|
6727
|
+
emitRequestedError(error, normalized2, requestedOutputPolicy);
|
|
6728
|
+
}
|
|
6729
|
+
process.exit(exitCodeForOutputErrorCode(normalized2.code));
|
|
5783
6730
|
}
|
|
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);
|
|
6731
|
+
if (error instanceof InterruptedError) {
|
|
6732
|
+
process.exit(EXIT_CODES.INTERRUPTED);
|
|
6733
|
+
}
|
|
6734
|
+
const normalized = normalizeOutputError(error, {
|
|
6735
|
+
origin: "cli"
|
|
6736
|
+
});
|
|
6737
|
+
emitRequestedError(error, normalized, requestedOutputPolicy);
|
|
6738
|
+
process.exit(exitCodeForOutputErrorCode(normalized.code));
|
|
5798
6739
|
}
|
|
5799
|
-
|
|
5800
|
-
process.stderr.write(`${message}
|
|
5801
|
-
`);
|
|
5802
|
-
process.exit(EXIT_CODES.ERROR);
|
|
5803
|
-
}
|
|
6740
|
+
});
|
|
5804
6741
|
}
|
|
5805
6742
|
function isCliEntrypoint(argv) {
|
|
5806
6743
|
const entry = argv[1];
|