acpx 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/{cli-BkYIxj_N.js → cli-CiyfEC7L.js} +5 -4
- package/dist/{cli-BkYIxj_N.js.map → cli-CiyfEC7L.js.map} +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +33 -26
- package/dist/cli.js.map +1 -1
- package/dist/{client-5levcBIs.d.ts → client-C6NUFqr-.d.ts} +12 -6
- package/dist/client-C6NUFqr-.d.ts.map +1 -0
- package/dist/{flows-Bxs4udrs.js → flows-CTOdIk-m.js} +6 -5
- package/dist/{flows-Bxs4udrs.js.map → flows-CTOdIk-m.js.map} +1 -1
- package/dist/flows.d.ts +2 -2
- package/dist/flows.js +1 -1
- package/dist/{invocation-options-BY4lxkn3.js → invocation-options-DbCcOAzM.js} +4 -3
- package/dist/{invocation-options-BY4lxkn3.js.map → invocation-options-DbCcOAzM.js.map} +1 -1
- package/dist/ipc-D3akHMEq.js +3350 -0
- package/dist/ipc-D3akHMEq.js.map +1 -0
- package/dist/output-BPPjvJTI.js +980 -0
- package/dist/output-BPPjvJTI.js.map +1 -0
- package/dist/{live-checkpoint-BEfxBKCh.js → queue-owner-runtime--IbbndGz.js} +3052 -1852
- package/dist/queue-owner-runtime--IbbndGz.js.map +1 -0
- package/dist/runtime.d.ts +99 -12
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +308 -69
- package/dist/runtime.js.map +1 -1
- package/dist/{session-options-t3d-F4dn.d.ts → session-options-Dp6mzNSy.d.ts} +2 -2
- package/dist/{session-options-t3d-F4dn.d.ts.map → session-options-Dp6mzNSy.d.ts.map} +1 -1
- package/dist/session-watch--UX5dh00.js +76 -0
- package/dist/session-watch--UX5dh00.js.map +1 -0
- package/dist/watch-BbBxO-kb.js +32 -0
- package/dist/watch-BbBxO-kb.js.map +1 -0
- package/package.json +1 -1
- package/skills/acpx/SKILL.md +5 -2
- package/dist/client-5levcBIs.d.ts.map +0 -1
- package/dist/live-checkpoint-BEfxBKCh.js.map +0 -1
- package/dist/output-uo5a27KB.js +0 -4711
- package/dist/output-uo5a27KB.js.map +0 -1
|
@@ -0,0 +1,980 @@
|
|
|
1
|
+
import { A as listSessions, D as findSession, E as findGitRepositoryRoot, N as pruneSessions, O as findSessionByDirectoryWalk, at as parsePermissionNotice, et as extractSessionUpdateNotification, ht as isProcessAlive, it as parseJsonRpcErrorMessage, j as listSessionsForAgent, ot as parsePromptStopReason } from "./ipc-D3akHMEq.js";
|
|
2
|
+
import { $ as normalizeQueueOwnerTtlMs, Q as DEFAULT_QUEUE_OWNER_TTL_MS, S as setSessionModel, _ as cancelSessionPrompt, a as runQueuedTask, b as setSessionConfigOption, g as listAgentSessions, h as ensureSession, i as runOnce, m as createSessionWithClient, n as runSessionQueueOwner, nt as InterruptedError, o as sendSessionDirect, p as createSession, r as sendSession, rt as TimeoutError, t as queueOwnerRuntimeTestInternals, v as closeSession, x as setSessionMode, y as sessionControlTestInternals } from "./queue-owner-runtime--IbbndGz.js";
|
|
3
|
+
//#region \0rolldown/runtime.js
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __exportAll = (all, no_symbols) => {
|
|
6
|
+
let target = {};
|
|
7
|
+
for (var name in all) __defProp(target, name, {
|
|
8
|
+
get: all[name],
|
|
9
|
+
enumerable: true
|
|
10
|
+
});
|
|
11
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
12
|
+
return target;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/session/session.ts
|
|
16
|
+
var session_exports = /* @__PURE__ */ __exportAll({
|
|
17
|
+
DEFAULT_HISTORY_LIMIT: () => 20,
|
|
18
|
+
DEFAULT_QUEUE_OWNER_TTL_MS: () => DEFAULT_QUEUE_OWNER_TTL_MS,
|
|
19
|
+
InterruptedError: () => InterruptedError,
|
|
20
|
+
TimeoutError: () => TimeoutError,
|
|
21
|
+
cancelSessionPrompt: () => cancelSessionPrompt,
|
|
22
|
+
closeSession: () => closeSession,
|
|
23
|
+
createSession: () => createSession,
|
|
24
|
+
createSessionWithClient: () => createSessionWithClient,
|
|
25
|
+
ensureSession: () => ensureSession,
|
|
26
|
+
findGitRepositoryRoot: () => findGitRepositoryRoot,
|
|
27
|
+
findSession: () => findSession,
|
|
28
|
+
findSessionByDirectoryWalk: () => findSessionByDirectoryWalk,
|
|
29
|
+
isProcessAlive: () => isProcessAlive,
|
|
30
|
+
listAgentSessions: () => listAgentSessions,
|
|
31
|
+
listSessions: () => listSessions,
|
|
32
|
+
listSessionsForAgent: () => listSessionsForAgent,
|
|
33
|
+
normalizeQueueOwnerTtlMs: () => normalizeQueueOwnerTtlMs,
|
|
34
|
+
pruneSessions: () => pruneSessions,
|
|
35
|
+
queueOwnerRuntimeTestInternals: () => queueOwnerRuntimeTestInternals,
|
|
36
|
+
runOnce: () => runOnce,
|
|
37
|
+
runQueuedTask: () => runQueuedTask,
|
|
38
|
+
runSessionQueueOwner: () => runSessionQueueOwner,
|
|
39
|
+
sendSession: () => sendSession,
|
|
40
|
+
sendSessionDirect: () => sendSessionDirect,
|
|
41
|
+
sessionControlTestInternals: () => sessionControlTestInternals,
|
|
42
|
+
setSessionConfigOption: () => setSessionConfigOption,
|
|
43
|
+
setSessionMode: () => setSessionMode,
|
|
44
|
+
setSessionModel: () => setSessionModel
|
|
45
|
+
});
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/acp/jsonrpc-error.ts
|
|
48
|
+
const OUTPUT_ERROR_JSONRPC_CODES = {
|
|
49
|
+
NO_SESSION: -32002,
|
|
50
|
+
TIMEOUT: -32070,
|
|
51
|
+
PERMISSION_DENIED: -32071,
|
|
52
|
+
PERMISSION_PROMPT_UNAVAILABLE: -32072,
|
|
53
|
+
RUNTIME: -32603,
|
|
54
|
+
USAGE: -32602
|
|
55
|
+
};
|
|
56
|
+
function hasValidAcpError(acp) {
|
|
57
|
+
return Boolean(acp && Number.isFinite(acp.code) && typeof acp.message === "string" && acp.message.trim().length > 0);
|
|
58
|
+
}
|
|
59
|
+
function buildFallbackData(params) {
|
|
60
|
+
const data = {
|
|
61
|
+
acpxCode: params.outputCode,
|
|
62
|
+
detailCode: params.detailCode,
|
|
63
|
+
origin: params.origin,
|
|
64
|
+
retryable: params.retryable,
|
|
65
|
+
timestamp: params.timestamp,
|
|
66
|
+
sessionId: params.sessionId
|
|
67
|
+
};
|
|
68
|
+
for (const [key, value] of Object.entries(data)) if (value === void 0) delete data[key];
|
|
69
|
+
return data;
|
|
70
|
+
}
|
|
71
|
+
function mergeAcpErrorData(acpData, fallbackData) {
|
|
72
|
+
if (Object.keys(fallbackData).length === 0) return acpData;
|
|
73
|
+
if (acpData === void 0) return fallbackData;
|
|
74
|
+
if (acpData && typeof acpData === "object" && !Array.isArray(acpData)) return {
|
|
75
|
+
...fallbackData,
|
|
76
|
+
...acpData
|
|
77
|
+
};
|
|
78
|
+
return acpData;
|
|
79
|
+
}
|
|
80
|
+
function buildErrorObject(params) {
|
|
81
|
+
const fallbackData = buildFallbackData(params);
|
|
82
|
+
if (hasValidAcpError(params.acp)) {
|
|
83
|
+
const data = mergeAcpErrorData(params.acp.data, fallbackData);
|
|
84
|
+
return {
|
|
85
|
+
code: params.acp.code,
|
|
86
|
+
message: params.acp.message,
|
|
87
|
+
...data !== void 0 ? { data } : {}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const data = fallbackData;
|
|
91
|
+
return {
|
|
92
|
+
code: OUTPUT_ERROR_JSONRPC_CODES[params.outputCode] ?? -32603,
|
|
93
|
+
message: params.message,
|
|
94
|
+
...Object.keys(data).length > 0 ? { data } : {}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function buildJsonRpcErrorResponse(params) {
|
|
98
|
+
return {
|
|
99
|
+
jsonrpc: "2.0",
|
|
100
|
+
id: params.id ?? null,
|
|
101
|
+
error: buildErrorObject(params)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/cli/output/read-suppression.ts
|
|
106
|
+
const SUPPRESSED_READ_OUTPUT = "[read output suppressed]";
|
|
107
|
+
function inferToolKindFromTitle(title) {
|
|
108
|
+
const normalized = title?.trim().toLowerCase();
|
|
109
|
+
if (!normalized) return;
|
|
110
|
+
const head = normalized.split(":", 1)[0]?.trim();
|
|
111
|
+
if (!head) return;
|
|
112
|
+
if ([
|
|
113
|
+
"read",
|
|
114
|
+
"cat",
|
|
115
|
+
"open",
|
|
116
|
+
"view"
|
|
117
|
+
].some((needle) => head.includes(needle))) return "read";
|
|
118
|
+
}
|
|
119
|
+
function isReadLikeTool(tool) {
|
|
120
|
+
return tool.kind?.trim().toLowerCase() === "read" || inferToolKindFromTitle(tool.title) === "read";
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/cli/output/json-formatter.ts
|
|
124
|
+
const DEFAULT_JSON_SESSION_ID = "unknown";
|
|
125
|
+
function asRecord$1(value) {
|
|
126
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
127
|
+
return value;
|
|
128
|
+
}
|
|
129
|
+
function jsonRpcIdKey(value) {
|
|
130
|
+
if (typeof value === "string") return `s:${value}`;
|
|
131
|
+
if (typeof value === "number" && Number.isFinite(value)) return `n:${value}`;
|
|
132
|
+
}
|
|
133
|
+
function sanitizeReadResult(result) {
|
|
134
|
+
const record = asRecord$1(result);
|
|
135
|
+
if (!record || typeof record.content !== "string") return result;
|
|
136
|
+
return {
|
|
137
|
+
...record,
|
|
138
|
+
content: SUPPRESSED_READ_OUTPUT
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function sanitizeToolContent(content) {
|
|
142
|
+
if (!Array.isArray(content)) return content;
|
|
143
|
+
return [{
|
|
144
|
+
type: "content",
|
|
145
|
+
content: {
|
|
146
|
+
type: "text",
|
|
147
|
+
text: SUPPRESSED_READ_OUTPUT
|
|
148
|
+
}
|
|
149
|
+
}];
|
|
150
|
+
}
|
|
151
|
+
function sanitizeToolMessage(message) {
|
|
152
|
+
const root = asRecord$1(message);
|
|
153
|
+
const params = asRecord$1(root?.params);
|
|
154
|
+
const update = asRecord$1(params?.update);
|
|
155
|
+
if (!root || !params || !update) return message;
|
|
156
|
+
return {
|
|
157
|
+
...root,
|
|
158
|
+
params: {
|
|
159
|
+
...params,
|
|
160
|
+
update: sanitizeToolUpdate(update)
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function sanitizeToolUpdate(update) {
|
|
165
|
+
return {
|
|
166
|
+
...update,
|
|
167
|
+
rawOutput: sanitizedRawOutput(update),
|
|
168
|
+
content: sanitizedContent(update)
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function sanitizedRawOutput(update) {
|
|
172
|
+
if (Object.prototype.hasOwnProperty.call(update, "rawOutput") && update.rawOutput !== void 0) return { content: SUPPRESSED_READ_OUTPUT };
|
|
173
|
+
return update.rawOutput;
|
|
174
|
+
}
|
|
175
|
+
function sanitizedContent(update) {
|
|
176
|
+
if (Object.prototype.hasOwnProperty.call(update, "content") && update.content !== void 0) return sanitizeToolContent(update.content);
|
|
177
|
+
return update.content;
|
|
178
|
+
}
|
|
179
|
+
var JsonMessageSanitizer = class {
|
|
180
|
+
suppressReads;
|
|
181
|
+
partialHistory;
|
|
182
|
+
requestMethodById = /* @__PURE__ */ new Map();
|
|
183
|
+
toolStateById = /* @__PURE__ */ new Map();
|
|
184
|
+
constructor(suppressReads, partialHistory = false) {
|
|
185
|
+
this.suppressReads = suppressReads;
|
|
186
|
+
this.partialHistory = partialHistory;
|
|
187
|
+
}
|
|
188
|
+
sanitize(message) {
|
|
189
|
+
if (!this.suppressReads) return message;
|
|
190
|
+
const sanitizedResponse = this.sanitizeReadResponse(message);
|
|
191
|
+
if (sanitizedResponse !== message) return sanitizedResponse;
|
|
192
|
+
const sanitizedToolMessage = this.sanitizeReadToolMessage(message);
|
|
193
|
+
if (sanitizedToolMessage !== message) return sanitizedToolMessage;
|
|
194
|
+
this.trackRequestMethod(message);
|
|
195
|
+
return message;
|
|
196
|
+
}
|
|
197
|
+
trackRequestMethod(message) {
|
|
198
|
+
const candidate = message;
|
|
199
|
+
if (typeof candidate.method !== "string") return;
|
|
200
|
+
const idKey = jsonRpcIdKey(candidate.id);
|
|
201
|
+
if (!idKey) return;
|
|
202
|
+
this.requestMethodById.set(idKey, candidate.method);
|
|
203
|
+
}
|
|
204
|
+
sanitizeReadResponse(message) {
|
|
205
|
+
const candidate = message;
|
|
206
|
+
const idKey = jsonRpcIdKey(candidate.id);
|
|
207
|
+
if (!idKey) return message;
|
|
208
|
+
const hasResult = Object.hasOwn(candidate, "result");
|
|
209
|
+
const hasError = Object.hasOwn(candidate, "error");
|
|
210
|
+
if (!hasResult && !hasError) return message;
|
|
211
|
+
const method = this.requestMethodById.get(idKey);
|
|
212
|
+
this.requestMethodById.delete(idKey);
|
|
213
|
+
if (!hasResult || !this.suppressReadResponse(method)) return message;
|
|
214
|
+
const root = asRecord$1(message);
|
|
215
|
+
if (!root) return message;
|
|
216
|
+
return {
|
|
217
|
+
...root,
|
|
218
|
+
result: sanitizeReadResult(candidate.result)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
suppressReadResponse(method) {
|
|
222
|
+
return method === "fs/read_text_file" || this.partialHistory && method === void 0;
|
|
223
|
+
}
|
|
224
|
+
sanitizeReadToolMessage(message) {
|
|
225
|
+
const update = this.readToolUpdate(message);
|
|
226
|
+
if (!update) return message;
|
|
227
|
+
const toolCallId = typeof update.toolCallId === "string" ? update.toolCallId : void 0;
|
|
228
|
+
if (!toolCallId) return message;
|
|
229
|
+
const current = this.mergeToolState(toolCallId, update);
|
|
230
|
+
this.toolStateById.set(toolCallId, current);
|
|
231
|
+
const unclassified = this.partialHistory && !current.kind && !current.title;
|
|
232
|
+
return isReadLikeTool(current) || unclassified ? sanitizeToolMessage(message) : message;
|
|
233
|
+
}
|
|
234
|
+
readToolUpdate(message) {
|
|
235
|
+
const root = asRecord$1(message);
|
|
236
|
+
if (root?.method !== "session/update") return;
|
|
237
|
+
const params = asRecord$1(root.params);
|
|
238
|
+
const update = asRecord$1(params?.update);
|
|
239
|
+
if (!params || !update) return;
|
|
240
|
+
const sessionUpdate = update.sessionUpdate;
|
|
241
|
+
if (sessionUpdate !== "tool_call" && sessionUpdate !== "tool_call_update") return;
|
|
242
|
+
return update;
|
|
243
|
+
}
|
|
244
|
+
mergeToolState(toolCallId, update) {
|
|
245
|
+
const previous = this.toolStateById.get(toolCallId) ?? {};
|
|
246
|
+
return {
|
|
247
|
+
title: typeof update.title === "string" ? update.title : previous.title,
|
|
248
|
+
kind: typeof update.kind === "string" || update.kind === null ? update.kind : previous.kind
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
var JsonOutputFormatter = class {
|
|
253
|
+
stdout;
|
|
254
|
+
sanitizer;
|
|
255
|
+
sessionId;
|
|
256
|
+
constructor(stdout, suppressReads, context) {
|
|
257
|
+
this.stdout = stdout;
|
|
258
|
+
this.sanitizer = new JsonMessageSanitizer(suppressReads);
|
|
259
|
+
this.sessionId = context?.sessionId?.trim() || DEFAULT_JSON_SESSION_ID;
|
|
260
|
+
}
|
|
261
|
+
setContext(context) {
|
|
262
|
+
this.sessionId = context.sessionId?.trim() || this.sessionId || DEFAULT_JSON_SESSION_ID;
|
|
263
|
+
}
|
|
264
|
+
onAcpMessage(message) {
|
|
265
|
+
this.stdout.write(`${JSON.stringify(this.sanitizer.sanitize(message))}\n`);
|
|
266
|
+
}
|
|
267
|
+
onError(params) {
|
|
268
|
+
this.stdout.write(`${JSON.stringify(buildJsonRpcErrorResponse({
|
|
269
|
+
outputCode: params.code,
|
|
270
|
+
detailCode: params.detailCode,
|
|
271
|
+
origin: params.origin,
|
|
272
|
+
message: params.message,
|
|
273
|
+
retryable: params.retryable,
|
|
274
|
+
timestamp: params.timestamp,
|
|
275
|
+
sessionId: this.sessionId,
|
|
276
|
+
acp: params.acp
|
|
277
|
+
}))}\n`);
|
|
278
|
+
}
|
|
279
|
+
onPermissionEscalation() {}
|
|
280
|
+
flush() {}
|
|
281
|
+
};
|
|
282
|
+
function createJsonOutputFormatter(stdout, suppressReads = false, context) {
|
|
283
|
+
return new JsonOutputFormatter(stdout, suppressReads, context);
|
|
284
|
+
}
|
|
285
|
+
//#endregion
|
|
286
|
+
//#region src/cli/output/output.ts
|
|
287
|
+
var output_exports = /* @__PURE__ */ __exportAll({
|
|
288
|
+
createOutputFormatter: () => createOutputFormatter,
|
|
289
|
+
getTextErrorRemediationHints: () => getTextErrorRemediationHints
|
|
290
|
+
});
|
|
291
|
+
const MAX_THOUGHT_CHARS = 900;
|
|
292
|
+
const MAX_INLINE_CHARS = 220;
|
|
293
|
+
const MAX_OUTPUT_CHARS = 2e3;
|
|
294
|
+
const MAX_OUTPUT_LINES = 28;
|
|
295
|
+
const MAX_LOCATION_ITEMS = 5;
|
|
296
|
+
const OUTPUT_PRIORITY_KEYS = [
|
|
297
|
+
"stdout",
|
|
298
|
+
"stderr",
|
|
299
|
+
"output",
|
|
300
|
+
"content",
|
|
301
|
+
"text",
|
|
302
|
+
"message",
|
|
303
|
+
"result",
|
|
304
|
+
"response",
|
|
305
|
+
"value"
|
|
306
|
+
];
|
|
307
|
+
function asStatus(status) {
|
|
308
|
+
return status ?? "unknown";
|
|
309
|
+
}
|
|
310
|
+
function isFinalStatus(status) {
|
|
311
|
+
return status === "completed" || status === "failed";
|
|
312
|
+
}
|
|
313
|
+
function toStatusLabel(status) {
|
|
314
|
+
return isFinalStatus(status) || status === "pending" ? status : "running";
|
|
315
|
+
}
|
|
316
|
+
function asRecord(value) {
|
|
317
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
318
|
+
return value;
|
|
319
|
+
}
|
|
320
|
+
function parseJsonRpcErrorSummary(message) {
|
|
321
|
+
const fallback = parseJsonRpcErrorMessage(message);
|
|
322
|
+
if (!fallback) return;
|
|
323
|
+
const details = asRecord(asRecord(message.error)?.data)?.details;
|
|
324
|
+
return typeof details === "string" && details.trim().length > 0 ? details.trim() : fallback;
|
|
325
|
+
}
|
|
326
|
+
function extractJsonRpcMethod(message) {
|
|
327
|
+
return Object.hasOwn(message, "method") ? message.method?.toString() : void 0;
|
|
328
|
+
}
|
|
329
|
+
function collapseWhitespace(value) {
|
|
330
|
+
return value.replace(/\s+/g, " ").trim();
|
|
331
|
+
}
|
|
332
|
+
function normalizeLineEndings(value) {
|
|
333
|
+
return value.replace(/\r\n?/g, "\n");
|
|
334
|
+
}
|
|
335
|
+
function truncate(value, maxChars) {
|
|
336
|
+
if (value.length <= maxChars) return value;
|
|
337
|
+
if (maxChars <= 3) return value.slice(0, maxChars);
|
|
338
|
+
return `${value.slice(0, maxChars - 3)}...`;
|
|
339
|
+
}
|
|
340
|
+
function toInline(value, maxChars = MAX_INLINE_CHARS) {
|
|
341
|
+
return truncate(collapseWhitespace(value), maxChars);
|
|
342
|
+
}
|
|
343
|
+
function indentBlock(value, prefix) {
|
|
344
|
+
return value.split("\n").map((line) => `${prefix}${line}`).join("\n");
|
|
345
|
+
}
|
|
346
|
+
function dedupeStrings(values) {
|
|
347
|
+
return [...new Set(values)];
|
|
348
|
+
}
|
|
349
|
+
function safeJson(value, spacing) {
|
|
350
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
351
|
+
try {
|
|
352
|
+
return JSON.stringify(value, (_key, entry) => {
|
|
353
|
+
if (typeof entry === "bigint") return `${entry}n`;
|
|
354
|
+
if (typeof entry === "function") return `[Function ${entry.name || "anonymous"}]`;
|
|
355
|
+
if (typeof entry === "symbol") return entry.toString();
|
|
356
|
+
if (entry && typeof entry === "object") {
|
|
357
|
+
if (seen.has(entry)) return "[Circular]";
|
|
358
|
+
seen.add(entry);
|
|
359
|
+
}
|
|
360
|
+
return entry;
|
|
361
|
+
}, spacing);
|
|
362
|
+
} catch {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function readFirstString(source, keys) {
|
|
367
|
+
for (const key of keys) {
|
|
368
|
+
const value = source[key];
|
|
369
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function readFirstFiniteNumber(source, keys) {
|
|
373
|
+
for (const key of keys) {
|
|
374
|
+
const value = source[key];
|
|
375
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function formatMetadataNumber(value) {
|
|
379
|
+
return Number.isInteger(value) ? String(value) : String(Number(value.toFixed(8)));
|
|
380
|
+
}
|
|
381
|
+
function readFirstStringArray(source, keys) {
|
|
382
|
+
for (const key of keys) {
|
|
383
|
+
const value = source[key];
|
|
384
|
+
if (!Array.isArray(value)) continue;
|
|
385
|
+
const entries = value.map((entry) => typeof entry === "string" ? entry.trim() : "").filter((entry) => entry.length > 0);
|
|
386
|
+
if (entries.length > 0) return entries;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function formatDisjunction(values) {
|
|
390
|
+
if (values.length <= 1) return values[0] ?? "";
|
|
391
|
+
if (values.length === 2) return `${values[0]} or ${values[1]}`;
|
|
392
|
+
return `${values.slice(0, -1).join(", ")}, or ${values.at(-1)}`;
|
|
393
|
+
}
|
|
394
|
+
function parseAuthMethodIdsFromMessage(message) {
|
|
395
|
+
const methods = [];
|
|
396
|
+
const methodListMatch = message.match(/auth methods \[([^\]]+)\]/iu);
|
|
397
|
+
if (methodListMatch) methods.push(...methodListMatch[1].split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0));
|
|
398
|
+
const singleMethodMatch = message.match(/auth method ([\w.-]+)/iu);
|
|
399
|
+
if (singleMethodMatch) methods.push(singleMethodMatch[1]);
|
|
400
|
+
return dedupeStrings(methods);
|
|
401
|
+
}
|
|
402
|
+
function parseAuthMethodIdsFromAcpData(data) {
|
|
403
|
+
const record = asRecord(data);
|
|
404
|
+
if (!record) return [];
|
|
405
|
+
const methodIds = [];
|
|
406
|
+
if (typeof record.methodId === "string" && record.methodId.trim().length > 0) methodIds.push(record.methodId.trim());
|
|
407
|
+
if (Array.isArray(record.methods)) for (const entry of record.methods) {
|
|
408
|
+
const id = parseAuthMethodIdEntry(entry);
|
|
409
|
+
if (id) methodIds.push(id);
|
|
410
|
+
}
|
|
411
|
+
return dedupeStrings(methodIds);
|
|
412
|
+
}
|
|
413
|
+
function parseAuthMethodIdEntry(entry) {
|
|
414
|
+
if (typeof entry === "string" && entry.trim().length > 0) return entry.trim();
|
|
415
|
+
const id = asRecord(entry)?.id;
|
|
416
|
+
return typeof id === "string" && id.trim().length > 0 ? id.trim() : void 0;
|
|
417
|
+
}
|
|
418
|
+
function renderAuthRequiredHint(params) {
|
|
419
|
+
const methodIds = dedupeStrings([...parseAuthMethodIdsFromAcpData(params.acp?.data), ...parseAuthMethodIdsFromMessage(params.message)]);
|
|
420
|
+
if (methodIds.length === 0) return "hint: run `acpx config show` to locate the active config, then add the required credential under `auth` and retry.";
|
|
421
|
+
return `hint: run \`acpx config show\` to locate the active config, then add ${formatDisjunction(methodIds.map((methodId) => `\`auth.${methodId}\``))} and retry.`;
|
|
422
|
+
}
|
|
423
|
+
function getTextErrorRemediationHints(params) {
|
|
424
|
+
const lowerMessage = params.message.toLowerCase();
|
|
425
|
+
if (params.detailCode === "AUTH_REQUIRED") return [renderAuthRequiredHint(params)];
|
|
426
|
+
if (params.code === "TIMEOUT") return ["hint: increase `--timeout <seconds>` for long-running prompts, or check whether the agent/provider is stalled."];
|
|
427
|
+
if (params.code === "NO_SESSION") return noSessionHints(lowerMessage);
|
|
428
|
+
return matchingTextErrorRule(params, lowerMessage)?.hints ?? [];
|
|
429
|
+
}
|
|
430
|
+
const TEXT_ERROR_HINT_RULES = [
|
|
431
|
+
{
|
|
432
|
+
matches: (_params, lowerMessage) => isUnsupportedSessionLoadError(lowerMessage),
|
|
433
|
+
hints: ["hint: this adapter cannot resume saved ACP sessions; create a fresh one with `acpx <agent> sessions new` instead of reusing `--resume-session`."]
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
matches: (_params, lowerMessage) => isSessionLoadError(lowerMessage),
|
|
437
|
+
hints: ["hint: rerun with `--verbose` to capture the ACP load failure details.", "hint: if you do not need the old backend session, start a fresh one with `acpx <agent> sessions new` and retry."]
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
matches: (params, lowerMessage) => isRateLimitError(params.message, lowerMessage),
|
|
441
|
+
hints: ["hint: the provider appears rate-limited; retry later, switch model, or check provider quota/billing."]
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
matches: (_params, lowerMessage) => isModelLookupError(lowerMessage),
|
|
445
|
+
hints: ["hint: check the configured model name for this agent, then retry with `--model <model>` or `sessions set-model <model>`."]
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
matches: (_params, lowerMessage) => isSessionConfigMethodError(lowerMessage),
|
|
449
|
+
hints: ["hint: rerun with `--verbose` to capture the ACP method/error details before retrying."]
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
matches: isRuntimeAcpProtocolError,
|
|
453
|
+
hints: ["hint: rerun with `--verbose` to capture the underlying ACP error details."]
|
|
454
|
+
}
|
|
455
|
+
];
|
|
456
|
+
function matchingTextErrorRule(params, lowerMessage) {
|
|
457
|
+
return TEXT_ERROR_HINT_RULES.find((rule) => rule.matches(params, lowerMessage));
|
|
458
|
+
}
|
|
459
|
+
function noSessionHints(lowerMessage) {
|
|
460
|
+
if (lowerMessage.includes("create one:")) return [];
|
|
461
|
+
return ["hint: the saved ACP session is missing or stale; start a fresh session with `acpx <agent> sessions new`, then retry."];
|
|
462
|
+
}
|
|
463
|
+
function isUnsupportedSessionLoadError(lowerMessage) {
|
|
464
|
+
return lowerMessage.includes("does not support session/resume") || lowerMessage.includes("does not support session/load");
|
|
465
|
+
}
|
|
466
|
+
function isSessionLoadError(lowerMessage) {
|
|
467
|
+
return lowerMessage.includes("failed to resume acp session") || lowerMessage.includes("session/resume") || lowerMessage.includes("session/load");
|
|
468
|
+
}
|
|
469
|
+
function isRateLimitError(message, lowerMessage) {
|
|
470
|
+
return /\b429\b/u.test(message) || ["rate limit", "quota exceeded"].some((text) => lowerMessage.includes(text));
|
|
471
|
+
}
|
|
472
|
+
function isModelLookupError(lowerMessage) {
|
|
473
|
+
return [
|
|
474
|
+
"model not found",
|
|
475
|
+
"unknown model",
|
|
476
|
+
"invalid model"
|
|
477
|
+
].some((text) => lowerMessage.includes(text));
|
|
478
|
+
}
|
|
479
|
+
function isSessionConfigMethodError(lowerMessage) {
|
|
480
|
+
return [
|
|
481
|
+
"session/set_mode",
|
|
482
|
+
"session/set_model",
|
|
483
|
+
"session/set_config_option"
|
|
484
|
+
].some((text) => lowerMessage.includes(text));
|
|
485
|
+
}
|
|
486
|
+
function isRuntimeAcpProtocolError(params, lowerMessage) {
|
|
487
|
+
return params.origin === "acp" && params.code === "RUNTIME" && (params.acp?.code === -32602 || params.acp?.code === -32603 || lowerMessage.includes("internal error"));
|
|
488
|
+
}
|
|
489
|
+
function summarizeToolInput(rawInput) {
|
|
490
|
+
if (rawInput == null) return;
|
|
491
|
+
if (isScalarToolInput(rawInput)) return toInline(String(rawInput));
|
|
492
|
+
const record = asRecord(rawInput);
|
|
493
|
+
if (record) return summarizeToolInputRecord(record) ?? summarizeToolInputJson(rawInput);
|
|
494
|
+
return summarizeToolInputJson(rawInput);
|
|
495
|
+
}
|
|
496
|
+
function isScalarToolInput(value) {
|
|
497
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
498
|
+
}
|
|
499
|
+
function summarizeToolInputRecord(record) {
|
|
500
|
+
const command = readFirstString(record, [
|
|
501
|
+
"command",
|
|
502
|
+
"cmd",
|
|
503
|
+
"program"
|
|
504
|
+
]);
|
|
505
|
+
const args = readFirstStringArray(record, ["args", "arguments"]);
|
|
506
|
+
if (command) return toInline([command, ...args ?? []].join(" "));
|
|
507
|
+
const location = readFirstString(record, [
|
|
508
|
+
"path",
|
|
509
|
+
"file",
|
|
510
|
+
"filePath",
|
|
511
|
+
"filepath",
|
|
512
|
+
"target",
|
|
513
|
+
"uri",
|
|
514
|
+
"url"
|
|
515
|
+
]);
|
|
516
|
+
const query = readFirstString(record, [
|
|
517
|
+
"query",
|
|
518
|
+
"pattern",
|
|
519
|
+
"text",
|
|
520
|
+
"search"
|
|
521
|
+
]);
|
|
522
|
+
return location || query ? toInline(location ?? query ?? "") : void 0;
|
|
523
|
+
}
|
|
524
|
+
function summarizeToolInputJson(rawInput) {
|
|
525
|
+
const json = safeJson(rawInput, 0);
|
|
526
|
+
return json ? toInline(json) : void 0;
|
|
527
|
+
}
|
|
528
|
+
function formatLocations(locations) {
|
|
529
|
+
if (!locations || locations.length === 0) return;
|
|
530
|
+
const unique = /* @__PURE__ */ new Set();
|
|
531
|
+
for (const location of locations) {
|
|
532
|
+
const formatted = formatLocation(location);
|
|
533
|
+
if (formatted) unique.add(formatted);
|
|
534
|
+
}
|
|
535
|
+
const items = [...unique];
|
|
536
|
+
if (items.length === 0) return;
|
|
537
|
+
const visible = items.slice(0, MAX_LOCATION_ITEMS);
|
|
538
|
+
const hidden = items.length - visible.length;
|
|
539
|
+
if (hidden <= 0) return visible.join(", ");
|
|
540
|
+
return `${visible.join(", ")}, +${hidden} more`;
|
|
541
|
+
}
|
|
542
|
+
function formatLocation(location) {
|
|
543
|
+
const path = location.path?.trim();
|
|
544
|
+
if (!path) return;
|
|
545
|
+
return `${path}${typeof location.line === "number" && Number.isFinite(location.line) ? `:${Math.max(1, Math.trunc(location.line))}` : ""}`;
|
|
546
|
+
}
|
|
547
|
+
function summarizeDiff(path, oldText, newText) {
|
|
548
|
+
const oldLines = oldText ? oldText.split("\n").length : 0;
|
|
549
|
+
const delta = newText.split("\n").length - oldLines;
|
|
550
|
+
if (delta === 0) return `diff ${path} (line count unchanged)`;
|
|
551
|
+
return `diff ${path} (${`${delta > 0 ? "+" : ""}${delta}`} lines)`;
|
|
552
|
+
}
|
|
553
|
+
function textFromContentBlock(content) {
|
|
554
|
+
switch (content.type) {
|
|
555
|
+
case "text": return content.text;
|
|
556
|
+
case "resource_link": return content.title ?? content.name ?? content.uri;
|
|
557
|
+
case "resource": return textFromResourceBlock(content);
|
|
558
|
+
case "image": return `[image] ${content.mimeType}`;
|
|
559
|
+
case "audio": return `[audio] ${content.mimeType}`;
|
|
560
|
+
default: return;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
function textFromResourceBlock(content) {
|
|
564
|
+
if ("text" in content.resource && typeof content.resource.text === "string") return content.resource.text;
|
|
565
|
+
const uri = content.resource.uri;
|
|
566
|
+
const mimeType = content.resource.mimeType;
|
|
567
|
+
return `[resource] ${uri}${mimeType ? ` (${mimeType})` : ""}`;
|
|
568
|
+
}
|
|
569
|
+
function summarizeToolContent(content) {
|
|
570
|
+
if (!content || content.length === 0) return;
|
|
571
|
+
const fragments = [];
|
|
572
|
+
for (const entry of content) {
|
|
573
|
+
const fragment = summarizeToolContentEntry(entry);
|
|
574
|
+
if (fragment) fragments.push(fragment);
|
|
575
|
+
}
|
|
576
|
+
const unique = dedupeStrings(fragments.map((fragment) => fragment.trim()).filter((fragment) => fragment.length > 0));
|
|
577
|
+
if (unique.length === 0) return;
|
|
578
|
+
return unique.join("\n\n");
|
|
579
|
+
}
|
|
580
|
+
function summarizeToolContentEntry(entry) {
|
|
581
|
+
if (entry.type === "content") {
|
|
582
|
+
const text = textFromContentBlock(entry.content);
|
|
583
|
+
return text && text.trim() ? text.trimEnd() : void 0;
|
|
584
|
+
}
|
|
585
|
+
if (entry.type === "diff") return summarizeDiff(entry.path, entry.oldText, entry.newText);
|
|
586
|
+
if (entry.type === "terminal") return `[terminal] ${entry.terminalId}`;
|
|
587
|
+
}
|
|
588
|
+
function extractOutputText(value, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
589
|
+
if (value == null) return;
|
|
590
|
+
const scalar = extractScalarOutputText(value);
|
|
591
|
+
if (scalar !== null) return scalar;
|
|
592
|
+
if (depth >= 4) return;
|
|
593
|
+
if (Array.isArray(value)) return extractOutputTextArray(value, depth, seen);
|
|
594
|
+
return extractOutputTextRecord(value, depth, seen);
|
|
595
|
+
}
|
|
596
|
+
function extractOutputTextRecord(value, depth, seen) {
|
|
597
|
+
const record = asRecord(value);
|
|
598
|
+
if (!record || seen.has(record)) return;
|
|
599
|
+
seen.add(record);
|
|
600
|
+
return extractPreferredOutputText(record, depth, seen) ?? extractJsonOutputText(record);
|
|
601
|
+
}
|
|
602
|
+
function extractScalarOutputText(value) {
|
|
603
|
+
if (typeof value === "string") {
|
|
604
|
+
const trimmed = value.trimEnd();
|
|
605
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
606
|
+
}
|
|
607
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
610
|
+
function extractOutputTextArray(value, depth, seen) {
|
|
611
|
+
const parts = value.map((entry) => extractOutputText(entry, depth + 1, seen)).filter((entry) => Boolean(entry));
|
|
612
|
+
return parts.length > 0 ? dedupeStrings(parts).join("\n") : void 0;
|
|
613
|
+
}
|
|
614
|
+
function extractPreferredOutputText(record, depth, seen) {
|
|
615
|
+
const uniquePreferred = dedupeStrings(OUTPUT_PRIORITY_KEYS.flatMap((key) => {
|
|
616
|
+
if (!(key in record)) return [];
|
|
617
|
+
const extracted = extractOutputText(record[key], depth + 1, seen);
|
|
618
|
+
return extracted ? [extracted] : [];
|
|
619
|
+
}));
|
|
620
|
+
return uniquePreferred.length > 0 ? uniquePreferred.join("\n") : void 0;
|
|
621
|
+
}
|
|
622
|
+
function extractJsonOutputText(record) {
|
|
623
|
+
const json = safeJson(record, 2);
|
|
624
|
+
return !json || json === "{}" ? void 0 : json;
|
|
625
|
+
}
|
|
626
|
+
function summarizeToolOutput(rawOutput, content) {
|
|
627
|
+
const fragments = dedupeStrings([extractOutputText(rawOutput), summarizeToolContent(content)].map((fragment) => fragment?.trim()).filter((fragment) => Boolean(fragment)));
|
|
628
|
+
if (fragments.length === 0) return;
|
|
629
|
+
return fragments.join("\n\n");
|
|
630
|
+
}
|
|
631
|
+
function renderToolOutput(state, suppressReads) {
|
|
632
|
+
if (suppressReads && isReadLikeTool(state)) return SUPPRESSED_READ_OUTPUT;
|
|
633
|
+
return summarizeToolOutput(state.rawOutput, state.content);
|
|
634
|
+
}
|
|
635
|
+
function limitOutputBlock(value) {
|
|
636
|
+
const normalized = value.replace(/\r\n/g, "\n").trim();
|
|
637
|
+
if (!normalized) return "";
|
|
638
|
+
const lines = normalized.split("\n");
|
|
639
|
+
const visible = lines.slice(0, MAX_OUTPUT_LINES);
|
|
640
|
+
let result = visible.join("\n");
|
|
641
|
+
if (lines.length > visible.length) {
|
|
642
|
+
const hidden = lines.length - visible.length;
|
|
643
|
+
result += `\n... (${hidden} more lines)`;
|
|
644
|
+
}
|
|
645
|
+
if (result.length > MAX_OUTPUT_CHARS) result = `${result.slice(0, 1997)}...`;
|
|
646
|
+
return result;
|
|
647
|
+
}
|
|
648
|
+
var TextOutputFormatter = class {
|
|
649
|
+
stdout;
|
|
650
|
+
useColor;
|
|
651
|
+
suppressReads;
|
|
652
|
+
toolStates = /* @__PURE__ */ new Map();
|
|
653
|
+
thoughtBuffer = "";
|
|
654
|
+
wroteAny = false;
|
|
655
|
+
atLineStart = true;
|
|
656
|
+
constructor(stdout, suppressReads) {
|
|
657
|
+
this.stdout = stdout;
|
|
658
|
+
this.useColor = Boolean(stdout.isTTY);
|
|
659
|
+
this.suppressReads = suppressReads;
|
|
660
|
+
}
|
|
661
|
+
setContext(_context) {}
|
|
662
|
+
onAcpMessage(message) {
|
|
663
|
+
const notice = parsePermissionNotice(message);
|
|
664
|
+
if (notice) {
|
|
665
|
+
this.beginSection();
|
|
666
|
+
this.writeLine(`${this.bold("[permission]")} ${notice}`);
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
const notification = extractSessionUpdateNotification(message);
|
|
670
|
+
if (notification) {
|
|
671
|
+
this.renderSessionUpdate(notification);
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
const method = extractJsonRpcMethod(message);
|
|
675
|
+
if (method && method !== "session/prompt" && method !== "session/cancel") {
|
|
676
|
+
this.onClientOperation({
|
|
677
|
+
method,
|
|
678
|
+
status: "running",
|
|
679
|
+
summary: method,
|
|
680
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
681
|
+
});
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
const stopReason = parsePromptStopReason(message);
|
|
685
|
+
if (stopReason) {
|
|
686
|
+
this.renderDone(stopReason);
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
const errorMessage = parseJsonRpcErrorSummary(message);
|
|
690
|
+
if (errorMessage) this.onError({
|
|
691
|
+
code: "RUNTIME",
|
|
692
|
+
origin: "acp",
|
|
693
|
+
message: errorMessage
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
renderSessionUpdate(notification) {
|
|
697
|
+
const update = notification.update;
|
|
698
|
+
if (update.sessionUpdate !== "agent_thought_chunk") this.flushThoughtBuffer();
|
|
699
|
+
this.renderSessionUpdateBody(update);
|
|
700
|
+
}
|
|
701
|
+
renderSessionUpdateBody(update) {
|
|
702
|
+
switch (update.sessionUpdate) {
|
|
703
|
+
case "agent_message_chunk":
|
|
704
|
+
if (update.content.type === "text") this.write(update.content.text);
|
|
705
|
+
return;
|
|
706
|
+
case "agent_thought_chunk":
|
|
707
|
+
if (update.content.type === "text") this.thoughtBuffer += update.content.text;
|
|
708
|
+
return;
|
|
709
|
+
case "tool_call":
|
|
710
|
+
this.renderToolUpdate(update);
|
|
711
|
+
return;
|
|
712
|
+
case "tool_call_update":
|
|
713
|
+
this.renderToolUpdate(update);
|
|
714
|
+
return;
|
|
715
|
+
case "plan":
|
|
716
|
+
this.renderPlanUpdate(update.entries);
|
|
717
|
+
return;
|
|
718
|
+
default: return;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
renderPlanUpdate(entries) {
|
|
722
|
+
this.beginSection();
|
|
723
|
+
this.writeLine(this.bold("[plan]"));
|
|
724
|
+
for (const entry of entries) this.writeLine(` - [${entry.status}] ${entry.content}`);
|
|
725
|
+
}
|
|
726
|
+
renderDone(stopReason) {
|
|
727
|
+
this.flushThoughtBuffer();
|
|
728
|
+
this.beginSection();
|
|
729
|
+
this.writeLine(this.dim(`[done] ${stopReason}`));
|
|
730
|
+
}
|
|
731
|
+
onError(params) {
|
|
732
|
+
this.flushThoughtBuffer();
|
|
733
|
+
this.beginSection();
|
|
734
|
+
this.writeLine(this.formatAnsi(`[error] ${params.code}: ${params.message}`, "31"));
|
|
735
|
+
for (const hint of getTextErrorRemediationHints(params)) this.writeLine(this.dim(hint));
|
|
736
|
+
}
|
|
737
|
+
onClientOperation(operation) {
|
|
738
|
+
this.flushThoughtBuffer();
|
|
739
|
+
this.beginSection();
|
|
740
|
+
const normalizedStatus = operation.status === "completed" ? "completed" : operation.status === "failed" ? "failed" : "in_progress";
|
|
741
|
+
const statusText = this.colorStatus(operation.status, normalizedStatus);
|
|
742
|
+
this.writeLine(`${this.bold("[client]")} ${operation.summary} (${statusText})`);
|
|
743
|
+
if (operation.details && operation.details.trim().length > 0) {
|
|
744
|
+
this.writeLine(" details:");
|
|
745
|
+
this.writeLine(indentBlock(operation.details, " "));
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
onPermissionEscalation(event) {
|
|
749
|
+
this.flushThoughtBuffer();
|
|
750
|
+
this.beginSection();
|
|
751
|
+
this.writeLine(`${this.bold("[permission]")} ${event.message}`);
|
|
752
|
+
const details = [
|
|
753
|
+
`sessionId: ${event.sessionId}`,
|
|
754
|
+
`toolCallId: ${event.toolCallId}`,
|
|
755
|
+
event.toolName ? `toolName: ${event.toolName}` : void 0,
|
|
756
|
+
`toolTitle: ${event.toolTitle}`,
|
|
757
|
+
event.toolInput !== void 0 ? `toolInput: ${summarizeToolInput(event.toolInput) ?? "(structured input)"}` : void 0,
|
|
758
|
+
event.toolKind ? `toolKind: ${event.toolKind}` : void 0,
|
|
759
|
+
event.matchedRule ? `matchedRule: ${event.matchedRule}` : void 0
|
|
760
|
+
].filter((line) => Boolean(line));
|
|
761
|
+
this.writeLine(indentBlock(details.join("\n"), " "));
|
|
762
|
+
}
|
|
763
|
+
flush() {
|
|
764
|
+
this.flushThoughtBuffer();
|
|
765
|
+
if (!this.atLineStart) this.write("\n");
|
|
766
|
+
}
|
|
767
|
+
write(chunk) {
|
|
768
|
+
if (!chunk) return;
|
|
769
|
+
this.stdout.write(chunk);
|
|
770
|
+
this.wroteAny = true;
|
|
771
|
+
this.atLineStart = chunk.endsWith("\n");
|
|
772
|
+
}
|
|
773
|
+
writeLine(line) {
|
|
774
|
+
this.write(`${line}\n`);
|
|
775
|
+
}
|
|
776
|
+
beginSection() {
|
|
777
|
+
if (!this.atLineStart) this.write("\n");
|
|
778
|
+
if (this.wroteAny) this.write("\n");
|
|
779
|
+
}
|
|
780
|
+
flushThoughtBuffer() {
|
|
781
|
+
const thought = truncate(normalizeLineEndings(this.thoughtBuffer).trim(), MAX_THOUGHT_CHARS);
|
|
782
|
+
this.thoughtBuffer = "";
|
|
783
|
+
if (!thought) return;
|
|
784
|
+
this.beginSection();
|
|
785
|
+
const [firstLine, ...restLines] = thought.split("\n");
|
|
786
|
+
this.writeLine(this.dim(`[thinking] ${firstLine}`));
|
|
787
|
+
for (const line of restLines) this.writeLine(this.dim(` ${line}`));
|
|
788
|
+
}
|
|
789
|
+
renderToolUpdate(update) {
|
|
790
|
+
const state = this.getOrCreateToolState(update.toolCallId);
|
|
791
|
+
this.mergeToolState(state, update);
|
|
792
|
+
const status = asStatus(state.status);
|
|
793
|
+
const final = isFinalStatus(status);
|
|
794
|
+
if (!final && state.startedPrinted) return;
|
|
795
|
+
const display = {
|
|
796
|
+
input: summarizeToolInput(state.rawInput),
|
|
797
|
+
files: formatLocations(state.locations),
|
|
798
|
+
output: final ? renderToolOutput(state, this.suppressReads) : void 0
|
|
799
|
+
};
|
|
800
|
+
if (final) {
|
|
801
|
+
const payload = {
|
|
802
|
+
title: state.title,
|
|
803
|
+
status: state.status,
|
|
804
|
+
kind: state.kind,
|
|
805
|
+
...display
|
|
806
|
+
};
|
|
807
|
+
const signature = safeJson(payload, 0) ?? JSON.stringify(payload);
|
|
808
|
+
if (signature === state.finalSignature) return;
|
|
809
|
+
state.finalSignature = signature;
|
|
810
|
+
} else state.startedPrinted = true;
|
|
811
|
+
this.renderToolState(state, status, display);
|
|
812
|
+
}
|
|
813
|
+
getOrCreateToolState(toolCallId) {
|
|
814
|
+
const existing = this.toolStates.get(toolCallId);
|
|
815
|
+
if (existing) return existing;
|
|
816
|
+
const created = {
|
|
817
|
+
id: toolCallId,
|
|
818
|
+
startedPrinted: false
|
|
819
|
+
};
|
|
820
|
+
this.toolStates.set(toolCallId, created);
|
|
821
|
+
return created;
|
|
822
|
+
}
|
|
823
|
+
mergeToolState(state, update) {
|
|
824
|
+
this.mergeToolTitle(state, update.title);
|
|
825
|
+
this.mergeToolPayloadState(state, update);
|
|
826
|
+
}
|
|
827
|
+
mergeToolTitle(state, title) {
|
|
828
|
+
if (typeof title === "string" && title.trim().length > 0) state.title = title;
|
|
829
|
+
}
|
|
830
|
+
mergeToolPayloadState(state, update) {
|
|
831
|
+
if (update.status !== void 0) state.status = update.status;
|
|
832
|
+
if (update.kind !== void 0) state.kind = update.kind;
|
|
833
|
+
if (update.locations !== void 0) state.locations = update.locations;
|
|
834
|
+
if (update.rawInput !== void 0) state.rawInput = update.rawInput;
|
|
835
|
+
if (update.rawOutput !== void 0) state.rawOutput = update.rawOutput;
|
|
836
|
+
if (update.content !== void 0) state.content = update.content;
|
|
837
|
+
}
|
|
838
|
+
renderToolState(state, status, display) {
|
|
839
|
+
this.beginSection();
|
|
840
|
+
const title = state.title ?? state.id;
|
|
841
|
+
const statusText = this.colorStatus(toStatusLabel(status), status);
|
|
842
|
+
this.writeLine(`${this.bold("[tool]")} ${title} (${statusText})`);
|
|
843
|
+
if (isFinalStatus(status) && state.kind) this.writeLine(` kind: ${state.kind}`);
|
|
844
|
+
if (display.input) this.writeLine(` input: ${display.input}`);
|
|
845
|
+
if (display.files) this.writeLine(` files: ${display.files}`);
|
|
846
|
+
if (display.output) {
|
|
847
|
+
this.writeLine(" output:");
|
|
848
|
+
this.writeLine(indentBlock(limitOutputBlock(display.output), " "));
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
formatAnsi(text, code) {
|
|
852
|
+
if (!this.useColor) return text;
|
|
853
|
+
return `\u001b[${code}m${text}\u001b[0m`;
|
|
854
|
+
}
|
|
855
|
+
bold(text) {
|
|
856
|
+
return this.formatAnsi(text, "1");
|
|
857
|
+
}
|
|
858
|
+
dim(text) {
|
|
859
|
+
return this.formatAnsi(text, "2");
|
|
860
|
+
}
|
|
861
|
+
colorStatus(text, status) {
|
|
862
|
+
if (!this.useColor) return text;
|
|
863
|
+
switch (status) {
|
|
864
|
+
case "completed": return this.formatAnsi(text, "32");
|
|
865
|
+
case "failed": return this.formatAnsi(text, "31");
|
|
866
|
+
default: return this.formatAnsi(text, "33");
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
var QuietOutputFormatter = class {
|
|
871
|
+
stdout;
|
|
872
|
+
stderr;
|
|
873
|
+
chunks = [];
|
|
874
|
+
flushed = false;
|
|
875
|
+
metadataFlushed = false;
|
|
876
|
+
constructor(stdout, stderr) {
|
|
877
|
+
this.stdout = stdout;
|
|
878
|
+
this.stderr = stderr;
|
|
879
|
+
}
|
|
880
|
+
setContext(_context) {}
|
|
881
|
+
onAcpMessage(message) {
|
|
882
|
+
const notice = parsePermissionNotice(message);
|
|
883
|
+
if (notice) {
|
|
884
|
+
this.stderr.write(`[acpx] permission: ${notice.replace(/\r\n?|\n/g, " ")}\n`);
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const update = extractSessionUpdateNotification(message);
|
|
888
|
+
if (update?.update.sessionUpdate === "agent_message_chunk" && update.update.content.type === "text") {
|
|
889
|
+
this.chunks.push(update.update.content.text);
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
if (parsePromptStopReason(message)) {
|
|
893
|
+
this.flushBufferedOutput();
|
|
894
|
+
this.flushMetadata(message);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
onError(params) {
|
|
898
|
+
const qualifier = params.detailCode ? `${params.code} ${params.detailCode}` : params.code;
|
|
899
|
+
const message = preferredAcpErrorDetails(params.acp) ?? params.message;
|
|
900
|
+
this.stderr.write(`[acpx] error: ${qualifier} ${message.replace(/\r\n?|\n/g, " ")}\n`);
|
|
901
|
+
}
|
|
902
|
+
onPermissionEscalation(_event) {}
|
|
903
|
+
flush() {}
|
|
904
|
+
flushBufferedOutput() {
|
|
905
|
+
if (this.flushed) return;
|
|
906
|
+
this.flushed = true;
|
|
907
|
+
const text = this.chunks.join("");
|
|
908
|
+
this.stdout.write(text.endsWith("\n") ? text : `${text}\n`);
|
|
909
|
+
}
|
|
910
|
+
flushMetadata(message) {
|
|
911
|
+
if (this.metadataFlushed) return;
|
|
912
|
+
this.metadataFlushed = true;
|
|
913
|
+
const result = asRecord(message.result);
|
|
914
|
+
if (!result) return;
|
|
915
|
+
const usageLine = this.formatUsageLine(asRecord(result.usage));
|
|
916
|
+
if (usageLine) this.stderr.write(`${usageLine}\n`);
|
|
917
|
+
const costLine = this.formatCostLine(result.cost);
|
|
918
|
+
if (costLine) this.stderr.write(`${costLine}\n`);
|
|
919
|
+
}
|
|
920
|
+
formatUsageLine(usage) {
|
|
921
|
+
if (!usage) return;
|
|
922
|
+
const parts = [];
|
|
923
|
+
for (const [label, keys] of [
|
|
924
|
+
["input", ["inputTokens", "input_tokens"]],
|
|
925
|
+
["output", ["outputTokens", "output_tokens"]],
|
|
926
|
+
["cache_read", [
|
|
927
|
+
"cachedReadTokens",
|
|
928
|
+
"cacheReadInputTokens",
|
|
929
|
+
"cache_read_input_tokens"
|
|
930
|
+
]],
|
|
931
|
+
["cache_write", [
|
|
932
|
+
"cachedWriteTokens",
|
|
933
|
+
"cacheCreationInputTokens",
|
|
934
|
+
"cache_creation_input_tokens"
|
|
935
|
+
]],
|
|
936
|
+
["total", ["totalTokens", "total_tokens"]]
|
|
937
|
+
]) {
|
|
938
|
+
const value = readFirstFiniteNumber(usage, keys);
|
|
939
|
+
if (value !== void 0) parts.push(`${label}=${formatMetadataNumber(value)}`);
|
|
940
|
+
}
|
|
941
|
+
return parts.length > 0 ? `[acpx] tokens: ${parts.join(" ")}` : void 0;
|
|
942
|
+
}
|
|
943
|
+
formatCostLine(cost) {
|
|
944
|
+
const scalar = this.formatScalarCostLine(cost);
|
|
945
|
+
if (scalar) return scalar;
|
|
946
|
+
const record = asRecord(cost);
|
|
947
|
+
if (!record) return;
|
|
948
|
+
const amount = readFirstFiniteNumber(record, [
|
|
949
|
+
"amount",
|
|
950
|
+
"value",
|
|
951
|
+
"total"
|
|
952
|
+
]);
|
|
953
|
+
if (amount === void 0) return;
|
|
954
|
+
const currency = typeof record.currency === "string" && record.currency.trim() ? ` ${record.currency.trim()}` : "";
|
|
955
|
+
return `[acpx] cost: ${formatMetadataNumber(amount)}${currency}`;
|
|
956
|
+
}
|
|
957
|
+
formatScalarCostLine(cost) {
|
|
958
|
+
if (typeof cost === "number" && Number.isFinite(cost)) return `[acpx] cost: ${formatMetadataNumber(cost)}`;
|
|
959
|
+
if (typeof cost === "string" && cost.trim()) return `[acpx] cost: ${cost.trim()}`;
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
function preferredAcpErrorDetails(acp) {
|
|
963
|
+
const details = asRecord(acp?.data)?.details;
|
|
964
|
+
return typeof details === "string" && details.trim().length > 0 ? details.trim() : void 0;
|
|
965
|
+
}
|
|
966
|
+
function createOutputFormatter(format, options = {}) {
|
|
967
|
+
const stdout = options.stdout ?? process.stdout;
|
|
968
|
+
const stderr = options.stderr ?? process.stderr;
|
|
969
|
+
const suppressReads = options.suppressReads === true;
|
|
970
|
+
switch (format) {
|
|
971
|
+
case "text": return new TextOutputFormatter(stdout, suppressReads);
|
|
972
|
+
case "json": return createJsonOutputFormatter(stdout, suppressReads, options.jsonContext);
|
|
973
|
+
case "quiet": return new QuietOutputFormatter(stdout, stderr);
|
|
974
|
+
default: throw new Error("Unsupported output format");
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
//#endregion
|
|
978
|
+
export { session_exports as a, JsonMessageSanitizer as i, getTextErrorRemediationHints as n, __exportAll as o, output_exports as r, createOutputFormatter as t };
|
|
979
|
+
|
|
980
|
+
//# sourceMappingURL=output-BPPjvJTI.js.map
|