@nathapp/nax 0.83.5 → 0.83.6
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 +11 -12
- package/dist/nax.js +887 -2693
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -29718,7 +29718,7 @@ function isBuiltInModelMap(agent, entry) {
|
|
|
29718
29718
|
const tiers = Object.entries(entry);
|
|
29719
29719
|
return tiers.length === Object.keys(builtIn).length && tiers.every(([tier, value]) => Object.hasOwn(builtIn, tier) && builtIn[tier] === value);
|
|
29720
29720
|
}
|
|
29721
|
-
var DEFAULT_AGENT_PROTOCOL = "hybrid", DEFAULT_AGENT_NAME = "native",
|
|
29721
|
+
var DEFAULT_AGENT_PROTOCOL = "hybrid", DEFAULT_AGENT_NAME = "native", DEFAULT_MODEL_MAPS;
|
|
29722
29722
|
var init_agent_defaults = __esm(() => {
|
|
29723
29723
|
init_internal();
|
|
29724
29724
|
DEFAULT_MODEL_MAPS = {
|
|
@@ -31247,6 +31247,15 @@ function _applyRemovedWorktreeInheritShim(conf, warn = defaultConfigWarn) {
|
|
|
31247
31247
|
execution: { ...execution, worktreeDependencies: { ...worktreeDependencies, mode: "off" } }
|
|
31248
31248
|
};
|
|
31249
31249
|
}
|
|
31250
|
+
function _applyRemovedAcpTransportShim(conf, warn = defaultConfigWarn) {
|
|
31251
|
+
const agent = conf.agent;
|
|
31252
|
+
const acp = agent?.acp;
|
|
31253
|
+
if (acp === undefined || !Object.hasOwn(acp, "transport"))
|
|
31254
|
+
return conf;
|
|
31255
|
+
const { transport, ...rest } = acp;
|
|
31256
|
+
warn(transport === "acpx" ? 'agent.acp.transport "acpx" was removed: the acpx CLI transport no longer exists, and ACP agents run through ' + "@nathapp/nax-agent-acp (each agent's ACP launcher must be installed). Remove the key from your config." : "agent.acp.transport was removed and has no effect: ACP agents always run through @nathapp/nax-agent-acp. " + "Remove the key from your config.");
|
|
31257
|
+
return { ...conf, agent: { ...agent, acp: rest } };
|
|
31258
|
+
}
|
|
31250
31259
|
function applyBatchModeCompat(conf, warn = defaultConfigWarn) {
|
|
31251
31260
|
const routing = conf.routing;
|
|
31252
31261
|
const llm = routing?.llm;
|
|
@@ -31373,6 +31382,7 @@ function applyConfigCompatShims(conf, logger, dedupe) {
|
|
|
31373
31382
|
out = _applyRemovedRoutingKeysShim(out, warn);
|
|
31374
31383
|
out = _applyLegacyReviewExecutionShim(out, warn);
|
|
31375
31384
|
out = _applyRemovedWorktreeInheritShim(out, warn);
|
|
31385
|
+
out = _applyRemovedAcpTransportShim(out, warn);
|
|
31376
31386
|
out = _applyFinishAutoFlowShim(out, warn);
|
|
31377
31387
|
out = _applyRemovedOptimizerKeysShim(out, warn);
|
|
31378
31388
|
out = _applyRemovedCrossPackageDepthShim(out, warn);
|
|
@@ -33130,7 +33140,6 @@ var init_schemas_infra = __esm(() => {
|
|
|
33130
33140
|
path: ["stopAfterRepeats"]
|
|
33131
33141
|
});
|
|
33132
33142
|
AgentAcpConfigSchema = exports_external.object({
|
|
33133
|
-
transport: exports_external.enum(["acpx", "sdk"]).default(DEFAULT_ACP_TRANSPORT),
|
|
33134
33143
|
promptRetries: exports_external.number().int().min(0).max(5).default(0),
|
|
33135
33144
|
trackedSpawnDeadlineMs: exports_external.number().int().positive().default(1e4),
|
|
33136
33145
|
trackedSpawnStartupDeadlineMs: exports_external.number().int().positive().default(30000)
|
|
@@ -33166,7 +33175,6 @@ var init_schemas_infra = __esm(() => {
|
|
|
33166
33175
|
rebuildContext: true
|
|
33167
33176
|
}),
|
|
33168
33177
|
acp: AgentAcpConfigSchema.default({
|
|
33169
|
-
transport: DEFAULT_ACP_TRANSPORT,
|
|
33170
33178
|
promptRetries: 0,
|
|
33171
33179
|
trackedSpawnDeadlineMs: 1e4,
|
|
33172
33180
|
trackedSpawnStartupDeadlineMs: 30000
|
|
@@ -33254,7 +33262,7 @@ function validateProtocolGate(data, ctx) {
|
|
|
33254
33262
|
ctx.addIssue({
|
|
33255
33263
|
code: "custom",
|
|
33256
33264
|
path: ["agent", "default"],
|
|
33257
|
-
message: 'agent.protocol "acp" cannot reach agent.default "native", which is also the built-in default when agent.default is unset. Set agent.default to an
|
|
33265
|
+
message: 'agent.protocol "acp" cannot reach agent.default "native", which is also the built-in default when agent.default is unset. Set agent.default to an ACP agent such as "claude", or use agent.protocol "hybrid".'
|
|
33258
33266
|
});
|
|
33259
33267
|
}
|
|
33260
33268
|
if (protocol === "acp" && modelAgents.includes(NATIVE_AGENT_NAME)) {
|
|
@@ -33271,7 +33279,7 @@ function validateProtocolGate(data, ctx) {
|
|
|
33271
33279
|
ctx.addIssue({
|
|
33272
33280
|
code: "custom",
|
|
33273
33281
|
path: ["models", agent],
|
|
33274
|
-
message: `agent.protocol "native" permits only models.native; "${agent}" is an
|
|
33282
|
+
message: `agent.protocol "native" permits only models.native; "${agent}" is an ACP agent. Use "hybrid" to run both.`
|
|
33275
33283
|
});
|
|
33276
33284
|
}
|
|
33277
33285
|
if ((data.agent?.default ?? DEFAULT_AGENT_NAME) !== NATIVE_AGENT_NAME) {
|
|
@@ -33759,7 +33767,6 @@ var init_schemas3 = __esm(() => {
|
|
|
33759
33767
|
usageAudit: { enabled: false },
|
|
33760
33768
|
fallback: { enabled: false, map: {}, maxHopsPerStory: 2, onQualityFailure: false, rebuildContext: true },
|
|
33761
33769
|
acp: {
|
|
33762
|
-
transport: DEFAULT_ACP_TRANSPORT,
|
|
33763
33770
|
promptRetries: 0,
|
|
33764
33771
|
trackedSpawnDeadlineMs: 1e4,
|
|
33765
33772
|
trackedSpawnStartupDeadlineMs: 30000
|
|
@@ -34500,7 +34507,7 @@ function describeUnreferencedAgentModels(agents, config2) {
|
|
|
34500
34507
|
const maps = agents.map((agent) => `models.${agent}`).join(", ");
|
|
34501
34508
|
const head = `${maps} is declared but nothing dispatches to it: no agent.default, enabled fallback rung, pin, escalation rung, ` + `complexity route, routing profile or PRD story names ${agents.join(", ")}.`;
|
|
34502
34509
|
if (config2.agent?.protocol === "native") {
|
|
34503
|
-
return `${head} Under agent.protocol "native"
|
|
34510
|
+
return `${head} Under agent.protocol "native" ACP agents cannot run; remove the map or use protocol "hybrid".`;
|
|
34504
34511
|
}
|
|
34505
34512
|
const defaultAgent = config2.agent?.default ?? DEFAULT_AGENT_NAME;
|
|
34506
34513
|
return `${head} Unassigned work runs on agent.default "${defaultAgent}". ` + `Set agent.default "${agents[0]}" to run it, or reference it from a pin or fallback rung.`;
|
|
@@ -34712,7 +34719,6 @@ __export(exports_config, {
|
|
|
34712
34719
|
ContextConfigSchema: () => ContextConfigSchema,
|
|
34713
34720
|
ContextV2ConfigSchema: () => ContextV2ConfigSchema,
|
|
34714
34721
|
CuratorRetentionConfigSchema: () => CuratorRetentionConfigSchema,
|
|
34715
|
-
DEFAULT_ACP_TRANSPORT: () => DEFAULT_ACP_TRANSPORT,
|
|
34716
34722
|
DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG: () => DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG,
|
|
34717
34723
|
DEFAULT_AGENT_NAME: () => DEFAULT_AGENT_NAME,
|
|
34718
34724
|
DEFAULT_AGENT_PROTOCOL: () => DEFAULT_AGENT_PROTOCOL,
|
|
@@ -38137,41 +38143,341 @@ var init_accept = __esm(() => {
|
|
|
38137
38143
|
init_prd();
|
|
38138
38144
|
});
|
|
38139
38145
|
|
|
38140
|
-
// src/agents/
|
|
38141
|
-
function
|
|
38142
|
-
|
|
38143
|
-
|
|
38144
|
-
return reason;
|
|
38146
|
+
// src/agents/errors/parse-agent-error.ts
|
|
38147
|
+
function parseAgentError(stderr) {
|
|
38148
|
+
if (!stderr) {
|
|
38149
|
+
return { type: "unknown" };
|
|
38145
38150
|
}
|
|
38146
|
-
|
|
38147
|
-
|
|
38151
|
+
const parsedJson = parseJsonObject(stderr);
|
|
38152
|
+
if (parsedJson) {
|
|
38153
|
+
const classified = classifyJsonPayload(parsedJson);
|
|
38154
|
+
if (classified)
|
|
38155
|
+
return classified;
|
|
38148
38156
|
}
|
|
38149
|
-
|
|
38157
|
+
if (!parsedJson) {
|
|
38158
|
+
for (const embedded of extractEmbeddedJsonObjects(stderr)) {
|
|
38159
|
+
const classified = classifyJsonPayload(embedded);
|
|
38160
|
+
if (classified)
|
|
38161
|
+
return classified;
|
|
38162
|
+
}
|
|
38163
|
+
}
|
|
38164
|
+
const fromKeyValue = classifyFromCodeTokens(extractKeyValueCodes(stderr));
|
|
38165
|
+
if (fromKeyValue)
|
|
38166
|
+
return fromKeyValue;
|
|
38167
|
+
const flatModel = classifyModelErrorMessage(stderr);
|
|
38168
|
+
if (flatModel)
|
|
38169
|
+
return flatModel;
|
|
38170
|
+
return { type: "unknown" };
|
|
38150
38171
|
}
|
|
38151
|
-
function
|
|
38152
|
-
|
|
38153
|
-
|
|
38172
|
+
function classifyJsonPayload(payload) {
|
|
38173
|
+
const direct = classifyDirectType(payload);
|
|
38174
|
+
if (direct)
|
|
38175
|
+
return direct;
|
|
38176
|
+
const nested = classifyNestedAnthropicError(payload);
|
|
38177
|
+
if (nested)
|
|
38178
|
+
return nested;
|
|
38179
|
+
const jsonRpcModel = classifyJsonRpcModelError(payload);
|
|
38180
|
+
if (jsonRpcModel)
|
|
38181
|
+
return jsonRpcModel;
|
|
38182
|
+
const structured = classifyFromCodeTokens(extractJsonCodeTokens(payload), payload);
|
|
38183
|
+
if (structured)
|
|
38184
|
+
return structured;
|
|
38185
|
+
return null;
|
|
38186
|
+
}
|
|
38187
|
+
function classifyNestedAnthropicError(payload) {
|
|
38188
|
+
if (payload.type !== "error")
|
|
38189
|
+
return null;
|
|
38190
|
+
const inner = payload.error;
|
|
38191
|
+
if (!inner || typeof inner !== "object")
|
|
38192
|
+
return null;
|
|
38193
|
+
const innerType = inner.type;
|
|
38194
|
+
if (typeof innerType !== "string")
|
|
38195
|
+
return null;
|
|
38196
|
+
switch (innerType) {
|
|
38197
|
+
case "authentication_error":
|
|
38198
|
+
case "permission_error":
|
|
38199
|
+
case "invalid_api_key_error":
|
|
38200
|
+
return { type: "auth" };
|
|
38201
|
+
case "rate_limit_error":
|
|
38202
|
+
case "overloaded_error": {
|
|
38203
|
+
const retryAfterSeconds = toNumber(inner.retryAfterSeconds ?? inner.retry_after_seconds ?? payload.retryAfterSeconds ?? payload.retry_after_seconds);
|
|
38204
|
+
return retryAfterSeconds !== undefined ? { type: "rate-limit", retryAfterSeconds } : { type: "rate-limit" };
|
|
38205
|
+
}
|
|
38206
|
+
default:
|
|
38207
|
+
return null;
|
|
38154
38208
|
}
|
|
38155
38209
|
}
|
|
38156
|
-
|
|
38157
|
-
|
|
38158
|
-
|
|
38210
|
+
function extractEmbeddedJsonObjects(text) {
|
|
38211
|
+
const objects = [];
|
|
38212
|
+
let i = 0;
|
|
38213
|
+
while (i < text.length && objects.length < MAX_EMBEDDED_CANDIDATES) {
|
|
38214
|
+
const open3 = text.indexOf("{", i);
|
|
38215
|
+
if (open3 === -1)
|
|
38216
|
+
break;
|
|
38217
|
+
const close = findMatchingBrace(text, open3);
|
|
38218
|
+
if (close === -1)
|
|
38219
|
+
break;
|
|
38220
|
+
const candidate = text.slice(open3, close + 1);
|
|
38221
|
+
try {
|
|
38222
|
+
const parsed = JSON.parse(candidate);
|
|
38223
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
38224
|
+
objects.push(parsed);
|
|
38225
|
+
}
|
|
38226
|
+
} catch {}
|
|
38227
|
+
i = close + 1;
|
|
38159
38228
|
}
|
|
38160
|
-
|
|
38161
|
-
|
|
38229
|
+
return objects;
|
|
38230
|
+
}
|
|
38231
|
+
function findMatchingBrace(text, openIdx) {
|
|
38232
|
+
let depth = 0;
|
|
38233
|
+
let inString = false;
|
|
38234
|
+
let escaped = false;
|
|
38235
|
+
for (let i = openIdx;i < text.length; i++) {
|
|
38236
|
+
const ch = text[i];
|
|
38237
|
+
if (escaped) {
|
|
38238
|
+
escaped = false;
|
|
38239
|
+
continue;
|
|
38240
|
+
}
|
|
38241
|
+
if (ch === "\\" && inString) {
|
|
38242
|
+
escaped = true;
|
|
38243
|
+
continue;
|
|
38244
|
+
}
|
|
38245
|
+
if (ch === '"') {
|
|
38246
|
+
inString = !inString;
|
|
38247
|
+
continue;
|
|
38248
|
+
}
|
|
38249
|
+
if (inString)
|
|
38250
|
+
continue;
|
|
38251
|
+
if (ch === "{")
|
|
38252
|
+
depth++;
|
|
38253
|
+
else if (ch === "}") {
|
|
38254
|
+
depth--;
|
|
38255
|
+
if (depth === 0)
|
|
38256
|
+
return i;
|
|
38257
|
+
}
|
|
38162
38258
|
}
|
|
38163
|
-
return
|
|
38164
|
-
const onAbort = () => reject(createAbortError(signal, fallback));
|
|
38165
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
38166
|
-
promise2.then((value) => {
|
|
38167
|
-
signal.removeEventListener("abort", onAbort);
|
|
38168
|
-
resolve21(value);
|
|
38169
|
-
}, (error48) => {
|
|
38170
|
-
signal.removeEventListener("abort", onAbort);
|
|
38171
|
-
reject(error48);
|
|
38172
|
-
});
|
|
38173
|
-
});
|
|
38259
|
+
return -1;
|
|
38174
38260
|
}
|
|
38261
|
+
function parseJsonObject(stderr) {
|
|
38262
|
+
try {
|
|
38263
|
+
const value = JSON.parse(stderr);
|
|
38264
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
38265
|
+
return value;
|
|
38266
|
+
}
|
|
38267
|
+
return null;
|
|
38268
|
+
} catch {
|
|
38269
|
+
return null;
|
|
38270
|
+
}
|
|
38271
|
+
}
|
|
38272
|
+
function classifyJsonRpcModelError(payload) {
|
|
38273
|
+
const errObj = payload.error;
|
|
38274
|
+
if (!errObj || typeof errObj !== "object")
|
|
38275
|
+
return null;
|
|
38276
|
+
const message = errObj.message;
|
|
38277
|
+
if (typeof message !== "string")
|
|
38278
|
+
return null;
|
|
38279
|
+
return classifyModelErrorMessage(message);
|
|
38280
|
+
}
|
|
38281
|
+
function classifyModelErrorMessage(message) {
|
|
38282
|
+
if (message.includes("There's an issue with the selected model") && message.includes("Run --model")) {
|
|
38283
|
+
return { type: "model-not-available" };
|
|
38284
|
+
}
|
|
38285
|
+
return null;
|
|
38286
|
+
}
|
|
38287
|
+
function classifyDirectType(payload) {
|
|
38288
|
+
const type = payload.type;
|
|
38289
|
+
if (type !== "rate-limit" && type !== "auth" && type !== "timeout" && type !== "crash" && type !== "unknown") {
|
|
38290
|
+
return null;
|
|
38291
|
+
}
|
|
38292
|
+
const result = { type };
|
|
38293
|
+
if (type === "rate-limit") {
|
|
38294
|
+
const retryAfterSeconds = toNumber(payload.retryAfterSeconds ?? payload.retry_after_seconds ?? payload.retryAfter);
|
|
38295
|
+
if (retryAfterSeconds !== undefined) {
|
|
38296
|
+
result.retryAfterSeconds = retryAfterSeconds;
|
|
38297
|
+
}
|
|
38298
|
+
}
|
|
38299
|
+
return result;
|
|
38300
|
+
}
|
|
38301
|
+
function extractJsonCodeTokens(payload) {
|
|
38302
|
+
const tokens = [];
|
|
38303
|
+
const pushToken = (candidate) => {
|
|
38304
|
+
if (typeof candidate === "number" && Number.isFinite(candidate)) {
|
|
38305
|
+
tokens.push(String(candidate));
|
|
38306
|
+
} else if (typeof candidate === "string" && candidate.trim()) {
|
|
38307
|
+
tokens.push(candidate.trim());
|
|
38308
|
+
}
|
|
38309
|
+
};
|
|
38310
|
+
const MAX_WALK_DEPTH = 8;
|
|
38311
|
+
const walk = (obj, depth) => {
|
|
38312
|
+
if (depth > MAX_WALK_DEPTH)
|
|
38313
|
+
return;
|
|
38314
|
+
const candidates = [obj.code, obj.status, obj.statusCode, obj.httpStatus, obj.errorCode, obj.detailCode];
|
|
38315
|
+
for (const candidate of candidates)
|
|
38316
|
+
pushToken(candidate);
|
|
38317
|
+
for (const key of ["error", "data"]) {
|
|
38318
|
+
const nested = obj[key];
|
|
38319
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
38320
|
+
walk(nested, depth + 1);
|
|
38321
|
+
}
|
|
38322
|
+
}
|
|
38323
|
+
};
|
|
38324
|
+
walk(payload, 0);
|
|
38325
|
+
return tokens;
|
|
38326
|
+
}
|
|
38327
|
+
function extractKeyValueCodes(stderr) {
|
|
38328
|
+
const tokens = [];
|
|
38329
|
+
const patterns = [
|
|
38330
|
+
/(?:status|statusCode|httpStatus|code)\s*[:=]\s*(\d{3})/g,
|
|
38331
|
+
/(?:detailCode|errorCode)\s*[:=]\s*([A-Z0-9_]+)/g
|
|
38332
|
+
];
|
|
38333
|
+
for (const pattern of patterns) {
|
|
38334
|
+
while (true) {
|
|
38335
|
+
const match = pattern.exec(stderr);
|
|
38336
|
+
if (!match)
|
|
38337
|
+
break;
|
|
38338
|
+
const code = match[1];
|
|
38339
|
+
if (code)
|
|
38340
|
+
tokens.push(code);
|
|
38341
|
+
}
|
|
38342
|
+
}
|
|
38343
|
+
return tokens;
|
|
38344
|
+
}
|
|
38345
|
+
function classifyFromCodeTokens(tokens, payload) {
|
|
38346
|
+
for (const token of tokens.map((value) => value.toUpperCase())) {
|
|
38347
|
+
if (token === "429" || token === "TOO_MANY_REQUESTS" || token === "RATE_LIMIT" || token === "RATE_LIMITED" || token === "QUOTA_EXCEEDED" || token === "RESOURCE_EXHAUSTED") {
|
|
38348
|
+
const retryAfterSeconds = payload ? findRetryAfterSeconds(payload) : undefined;
|
|
38349
|
+
return retryAfterSeconds !== undefined ? { type: "rate-limit", retryAfterSeconds } : { type: "rate-limit" };
|
|
38350
|
+
}
|
|
38351
|
+
if (token === "401" || token === "403" || token === "UNAUTHORIZED" || token === "FORBIDDEN" || token === "AUTH_FAILED" || token === "AUTHENTICATION_FAILED" || token === "PERMISSION_DENIED") {
|
|
38352
|
+
return { type: "auth" };
|
|
38353
|
+
}
|
|
38354
|
+
}
|
|
38355
|
+
return null;
|
|
38356
|
+
}
|
|
38357
|
+
function toNumber(value) {
|
|
38358
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
38359
|
+
return Math.trunc(value);
|
|
38360
|
+
if (typeof value === "string" && value.trim()) {
|
|
38361
|
+
const parsed = Number.parseInt(value, 10);
|
|
38362
|
+
if (Number.isFinite(parsed))
|
|
38363
|
+
return parsed;
|
|
38364
|
+
}
|
|
38365
|
+
return;
|
|
38366
|
+
}
|
|
38367
|
+
function findRetryAfterSeconds(payload) {
|
|
38368
|
+
const topLevel = toNumber(payload.retryAfterSeconds ?? payload.retry_after_seconds ?? payload.retryAfter);
|
|
38369
|
+
if (topLevel !== undefined)
|
|
38370
|
+
return topLevel;
|
|
38371
|
+
const error48 = payload.error;
|
|
38372
|
+
if (error48 && typeof error48 === "object" && !Array.isArray(error48)) {
|
|
38373
|
+
const errObj = error48;
|
|
38374
|
+
const inError = toNumber(errObj.retryAfterSeconds ?? errObj.retry_after_seconds ?? errObj.retryAfter);
|
|
38375
|
+
if (inError !== undefined)
|
|
38376
|
+
return inError;
|
|
38377
|
+
const data = errObj.data;
|
|
38378
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
38379
|
+
const dataObj = data;
|
|
38380
|
+
return toNumber(dataObj.retryAfterSeconds ?? dataObj.retry_after_seconds ?? dataObj.retryAfter);
|
|
38381
|
+
}
|
|
38382
|
+
}
|
|
38383
|
+
return;
|
|
38384
|
+
}
|
|
38385
|
+
var MAX_EMBEDDED_CANDIDATES = 8;
|
|
38386
|
+
|
|
38387
|
+
// src/agents/errors/index.ts
|
|
38388
|
+
var init_errors5 = () => {};
|
|
38389
|
+
|
|
38390
|
+
// src/agents/transport-failure-message.ts
|
|
38391
|
+
function isTransportFailureMessage(message) {
|
|
38392
|
+
if (!message)
|
|
38393
|
+
return false;
|
|
38394
|
+
const haystack = message.toLowerCase();
|
|
38395
|
+
return TRANSPORT_FAULT_MARKERS.some((marker) => haystack.includes(marker));
|
|
38396
|
+
}
|
|
38397
|
+
var TRANSPORT_FAULT_MARKERS;
|
|
38398
|
+
var init_transport_failure_message = __esm(() => {
|
|
38399
|
+
TRANSPORT_FAULT_MARKERS = [
|
|
38400
|
+
"idle timeout exceeded",
|
|
38401
|
+
"stream idle timeout",
|
|
38402
|
+
"upstream timeout",
|
|
38403
|
+
"bad gateway",
|
|
38404
|
+
"service unavailable",
|
|
38405
|
+
"gateway timeout",
|
|
38406
|
+
"econnreset",
|
|
38407
|
+
"econnrefused",
|
|
38408
|
+
"econnaborted",
|
|
38409
|
+
"etimedout",
|
|
38410
|
+
"socket hang up",
|
|
38411
|
+
"premature close",
|
|
38412
|
+
"terminated: other side closed",
|
|
38413
|
+
"network error"
|
|
38414
|
+
];
|
|
38415
|
+
});
|
|
38416
|
+
|
|
38417
|
+
// src/agents/types.ts
|
|
38418
|
+
var CompleteError, SessionFailureError;
|
|
38419
|
+
var init_types4 = __esm(() => {
|
|
38420
|
+
init_src();
|
|
38421
|
+
CompleteError = class CompleteError extends Error {
|
|
38422
|
+
exitCode;
|
|
38423
|
+
retryable;
|
|
38424
|
+
constructor(message, exitCode, retryable) {
|
|
38425
|
+
super(message);
|
|
38426
|
+
this.exitCode = exitCode;
|
|
38427
|
+
this.retryable = retryable;
|
|
38428
|
+
this.name = "CompleteError";
|
|
38429
|
+
}
|
|
38430
|
+
};
|
|
38431
|
+
SessionFailureError = class SessionFailureError extends Error {
|
|
38432
|
+
adapterFailure;
|
|
38433
|
+
constructor(message, adapterFailure) {
|
|
38434
|
+
super(message);
|
|
38435
|
+
this.adapterFailure = adapterFailure;
|
|
38436
|
+
this.name = "SessionFailureError";
|
|
38437
|
+
}
|
|
38438
|
+
};
|
|
38439
|
+
});
|
|
38440
|
+
|
|
38441
|
+
// src/agents/complete-exception-classifier.ts
|
|
38442
|
+
function classifyCompleteException(err) {
|
|
38443
|
+
if ((err instanceof SessionTurnError || err instanceof SessionFailureError) && err.adapterFailure !== undefined) {
|
|
38444
|
+
return err.adapterFailure;
|
|
38445
|
+
}
|
|
38446
|
+
const fullMessage = errorMessage(err);
|
|
38447
|
+
const message = fullMessage.slice(0, MAX_FAILURE_MESSAGE_CHARS);
|
|
38448
|
+
if (err instanceof NaxError && err.code === "AGENT_TIMEOUT") {
|
|
38449
|
+
return { category: "quality", outcome: "fail-timeout", retriable: true, message };
|
|
38450
|
+
}
|
|
38451
|
+
const parsed = parseAgentError(fullMessage);
|
|
38452
|
+
switch (parsed.type) {
|
|
38453
|
+
case "auth":
|
|
38454
|
+
return { category: "availability", outcome: "fail-auth", retriable: false, message };
|
|
38455
|
+
case "rate-limit":
|
|
38456
|
+
return {
|
|
38457
|
+
category: "availability",
|
|
38458
|
+
outcome: "fail-rate-limit",
|
|
38459
|
+
retriable: true,
|
|
38460
|
+
message,
|
|
38461
|
+
...parsed.retryAfterSeconds !== undefined ? { retryAfterSeconds: parsed.retryAfterSeconds } : {}
|
|
38462
|
+
};
|
|
38463
|
+
case "model-not-available":
|
|
38464
|
+
return { category: "quality", outcome: "fail-adapter-error", retriable: false, message };
|
|
38465
|
+
case "timeout":
|
|
38466
|
+
return { category: "quality", outcome: "fail-timeout", retriable: true, message };
|
|
38467
|
+
case "crash":
|
|
38468
|
+
return { category: "quality", outcome: "fail-adapter-error", retriable: false, message };
|
|
38469
|
+
default:
|
|
38470
|
+
return isTransportFailureMessage(fullMessage) ? { category: "availability", outcome: "fail-service-down", retriable: true, message } : { category: "quality", outcome: "fail-unknown", retriable: false, message };
|
|
38471
|
+
}
|
|
38472
|
+
}
|
|
38473
|
+
var MAX_FAILURE_MESSAGE_CHARS = 500;
|
|
38474
|
+
var init_complete_exception_classifier = __esm(() => {
|
|
38475
|
+
init_internal();
|
|
38476
|
+
init_errors4();
|
|
38477
|
+
init_errors5();
|
|
38478
|
+
init_transport_failure_message();
|
|
38479
|
+
init_types4();
|
|
38480
|
+
});
|
|
38175
38481
|
|
|
38176
38482
|
// src/agents/cost/calculate.ts
|
|
38177
38483
|
function resolvePricingSource(model) {
|
|
@@ -38188,7 +38494,7 @@ var package_default;
|
|
|
38188
38494
|
var init_package = __esm(() => {
|
|
38189
38495
|
package_default = {
|
|
38190
38496
|
name: "@nathapp/nax",
|
|
38191
|
-
version: "0.83.
|
|
38497
|
+
version: "0.83.6",
|
|
38192
38498
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
38193
38499
|
type: "module",
|
|
38194
38500
|
bin: {
|
|
@@ -38482,2404 +38788,33 @@ var init_cost = __esm(() => {
|
|
|
38482
38788
|
init_rate_card();
|
|
38483
38789
|
});
|
|
38484
38790
|
|
|
38485
|
-
// src/
|
|
38486
|
-
function
|
|
38487
|
-
|
|
38488
|
-
const output = timedOut ? "" : input.output;
|
|
38489
|
-
const hasUsage = totalTokenUsage.inputTokens > 0 || totalTokenUsage.outputTokens > 0;
|
|
38490
|
-
const priced = hasUsage ? priceCall(totalTokenUsage, rateCard.rates) : undefined;
|
|
38491
|
-
return {
|
|
38492
|
-
output,
|
|
38493
|
-
tokenUsage: totalTokenUsage,
|
|
38494
|
-
estimatedCostUsd: priced?.costUsd ?? 0,
|
|
38495
|
-
exactCostUsd: totalExactCostUsd,
|
|
38496
|
-
internalRoundTrips: turnCount,
|
|
38497
|
-
...interactions.length > 0 ? { interactions } : {},
|
|
38498
|
-
timedOut,
|
|
38499
|
-
pricingSource: rateCard.source,
|
|
38500
|
-
...priced?.resolvedRates !== undefined ? { rates: priced.resolvedRates } : {}
|
|
38501
|
-
};
|
|
38502
|
-
}
|
|
38503
|
-
function warnWallClockTimeout(sessionName, timeoutSeconds, stage) {
|
|
38504
|
-
getSafeLogger2()?.warn(stage, "wall-clock timeout exceeded \u2014 session terminated", {
|
|
38505
|
-
sessionName,
|
|
38506
|
-
timeoutSeconds
|
|
38507
|
-
});
|
|
38508
|
-
}
|
|
38509
|
-
var init_turn_deadline2 = __esm(() => {
|
|
38510
|
-
init_logger2();
|
|
38511
|
-
init_cost();
|
|
38512
|
-
});
|
|
38513
|
-
|
|
38514
|
-
// src/agents/turn/index.ts
|
|
38515
|
-
var init_turn = __esm(() => {
|
|
38516
|
-
init_turn_deadline2();
|
|
38517
|
-
});
|
|
38518
|
-
|
|
38519
|
-
// src/utils/bun-deps.ts
|
|
38520
|
-
function typedSpawn(cmd, opts) {
|
|
38521
|
-
return Bun.spawn(cmd, opts);
|
|
38522
|
-
}
|
|
38523
|
-
function which2(name) {
|
|
38524
|
-
return Bun.which(name);
|
|
38525
|
-
}
|
|
38526
|
-
function sleep(ms) {
|
|
38527
|
-
return Bun.sleep(ms);
|
|
38528
|
-
}
|
|
38529
|
-
function cancellableDelay(ms, signal) {
|
|
38530
|
-
return new Promise((resolve21, reject) => {
|
|
38531
|
-
if (signal?.aborted) {
|
|
38532
|
-
reject(signal.reason ?? new Error("delay aborted"));
|
|
38533
|
-
return;
|
|
38534
|
-
}
|
|
38535
|
-
const timer = setTimeout(() => {
|
|
38536
|
-
signal?.removeEventListener("abort", onAbort);
|
|
38537
|
-
resolve21();
|
|
38538
|
-
}, ms);
|
|
38539
|
-
const onAbort = () => {
|
|
38540
|
-
clearTimeout(timer);
|
|
38541
|
-
reject(signal?.reason ?? new Error("delay aborted"));
|
|
38542
|
-
};
|
|
38543
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
38544
|
-
});
|
|
38545
|
-
}
|
|
38546
|
-
var spawn;
|
|
38547
|
-
var init_bun_deps = __esm(() => {
|
|
38548
|
-
spawn = Bun.spawn;
|
|
38549
|
-
});
|
|
38550
|
-
|
|
38551
|
-
// src/agents/errors/parse-agent-error.ts
|
|
38552
|
-
function classifyCompleteError(error48, pricingSource) {
|
|
38553
|
-
if (error48.retryable === undefined)
|
|
38554
|
-
return null;
|
|
38555
|
-
return {
|
|
38556
|
-
output: error48.message,
|
|
38557
|
-
tokenUsage: { inputTokens: 0, outputTokens: 0 },
|
|
38558
|
-
estimatedCostUsd: 0,
|
|
38559
|
-
adapterFailure: {
|
|
38560
|
-
category: "quality",
|
|
38561
|
-
outcome: "fail-adapter-error",
|
|
38562
|
-
retriable: error48.retryable,
|
|
38563
|
-
message: error48.message.slice(0, 500)
|
|
38564
|
-
},
|
|
38565
|
-
...pricingSource !== undefined ? { pricingSource } : {}
|
|
38566
|
-
};
|
|
38567
|
-
}
|
|
38568
|
-
function classifyParsedAgentError(parsed, message, pricingSource) {
|
|
38569
|
-
const base = {
|
|
38570
|
-
output: message,
|
|
38571
|
-
tokenUsage: { inputTokens: 0, outputTokens: 0 },
|
|
38572
|
-
estimatedCostUsd: 0,
|
|
38573
|
-
...pricingSource !== undefined ? { pricingSource } : {}
|
|
38574
|
-
};
|
|
38575
|
-
const truncated = message.slice(0, 500);
|
|
38576
|
-
switch (parsed.type) {
|
|
38577
|
-
case "auth":
|
|
38578
|
-
return {
|
|
38579
|
-
...base,
|
|
38580
|
-
adapterFailure: { category: "availability", outcome: "fail-auth", retriable: false, message: truncated }
|
|
38581
|
-
};
|
|
38582
|
-
case "rate-limit":
|
|
38583
|
-
return {
|
|
38584
|
-
...base,
|
|
38585
|
-
adapterFailure: {
|
|
38586
|
-
category: "availability",
|
|
38587
|
-
outcome: "fail-rate-limit",
|
|
38588
|
-
retriable: true,
|
|
38589
|
-
message: truncated,
|
|
38590
|
-
...parsed.retryAfterSeconds !== undefined && { retryAfterSeconds: parsed.retryAfterSeconds }
|
|
38591
|
-
}
|
|
38592
|
-
};
|
|
38593
|
-
case "model-not-available":
|
|
38594
|
-
return {
|
|
38595
|
-
...base,
|
|
38596
|
-
adapterFailure: { category: "quality", outcome: "fail-adapter-error", retriable: false, message: truncated }
|
|
38597
|
-
};
|
|
38598
|
-
default:
|
|
38599
|
-
return null;
|
|
38600
|
-
}
|
|
38601
|
-
}
|
|
38602
|
-
function parseAgentError(stderr) {
|
|
38603
|
-
if (!stderr) {
|
|
38604
|
-
return { type: "unknown" };
|
|
38605
|
-
}
|
|
38606
|
-
const parsedJson = parseJsonObject(stderr);
|
|
38607
|
-
if (parsedJson) {
|
|
38608
|
-
const classified = classifyJsonPayload(parsedJson);
|
|
38609
|
-
if (classified)
|
|
38610
|
-
return classified;
|
|
38611
|
-
}
|
|
38612
|
-
if (!parsedJson) {
|
|
38613
|
-
for (const embedded of extractEmbeddedJsonObjects(stderr)) {
|
|
38614
|
-
const classified = classifyJsonPayload(embedded);
|
|
38615
|
-
if (classified)
|
|
38616
|
-
return classified;
|
|
38617
|
-
}
|
|
38618
|
-
}
|
|
38619
|
-
const bracketed = extractBracketedCodes(stderr);
|
|
38620
|
-
const fromBracketed = classifyFromCodeTokens(bracketed);
|
|
38621
|
-
if (fromBracketed)
|
|
38622
|
-
return fromBracketed;
|
|
38623
|
-
const fromKeyValue = classifyFromCodeTokens(extractKeyValueCodes(stderr));
|
|
38624
|
-
if (fromKeyValue)
|
|
38625
|
-
return fromKeyValue;
|
|
38626
|
-
const flatModel = classifyModelErrorMessage(stderr);
|
|
38627
|
-
if (flatModel)
|
|
38628
|
-
return flatModel;
|
|
38629
|
-
return { type: "unknown" };
|
|
38630
|
-
}
|
|
38631
|
-
function classifyJsonPayload(payload) {
|
|
38632
|
-
const direct = classifyDirectType(payload);
|
|
38633
|
-
if (direct)
|
|
38634
|
-
return direct;
|
|
38635
|
-
const nested = classifyNestedAnthropicError(payload);
|
|
38636
|
-
if (nested)
|
|
38637
|
-
return nested;
|
|
38638
|
-
const jsonRpcModel = classifyJsonRpcModelError(payload);
|
|
38639
|
-
if (jsonRpcModel)
|
|
38640
|
-
return jsonRpcModel;
|
|
38641
|
-
const structured = classifyFromCodeTokens(extractJsonCodeTokens(payload), payload);
|
|
38642
|
-
if (structured)
|
|
38643
|
-
return structured;
|
|
38644
|
-
return null;
|
|
38645
|
-
}
|
|
38646
|
-
function classifyNestedAnthropicError(payload) {
|
|
38647
|
-
if (payload.type !== "error")
|
|
38648
|
-
return null;
|
|
38649
|
-
const inner = payload.error;
|
|
38650
|
-
if (!inner || typeof inner !== "object")
|
|
38651
|
-
return null;
|
|
38652
|
-
const innerType = inner.type;
|
|
38653
|
-
if (typeof innerType !== "string")
|
|
38654
|
-
return null;
|
|
38655
|
-
switch (innerType) {
|
|
38656
|
-
case "authentication_error":
|
|
38657
|
-
case "permission_error":
|
|
38658
|
-
case "invalid_api_key_error":
|
|
38659
|
-
return { type: "auth" };
|
|
38660
|
-
case "rate_limit_error":
|
|
38661
|
-
case "overloaded_error": {
|
|
38662
|
-
const retryAfterSeconds = toNumber(inner.retryAfterSeconds ?? inner.retry_after_seconds ?? payload.retryAfterSeconds ?? payload.retry_after_seconds);
|
|
38663
|
-
return retryAfterSeconds !== undefined ? { type: "rate-limit", retryAfterSeconds } : { type: "rate-limit" };
|
|
38664
|
-
}
|
|
38665
|
-
default:
|
|
38666
|
-
return null;
|
|
38667
|
-
}
|
|
38668
|
-
}
|
|
38669
|
-
function extractEmbeddedJsonObjects(text) {
|
|
38670
|
-
const objects = [];
|
|
38671
|
-
let i = 0;
|
|
38672
|
-
while (i < text.length && objects.length < MAX_EMBEDDED_CANDIDATES) {
|
|
38673
|
-
const open3 = text.indexOf("{", i);
|
|
38674
|
-
if (open3 === -1)
|
|
38675
|
-
break;
|
|
38676
|
-
const close = findMatchingBrace(text, open3);
|
|
38677
|
-
if (close === -1)
|
|
38678
|
-
break;
|
|
38679
|
-
const candidate = text.slice(open3, close + 1);
|
|
38680
|
-
try {
|
|
38681
|
-
const parsed = JSON.parse(candidate);
|
|
38682
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
38683
|
-
objects.push(parsed);
|
|
38684
|
-
}
|
|
38685
|
-
} catch {}
|
|
38686
|
-
i = close + 1;
|
|
38687
|
-
}
|
|
38688
|
-
return objects;
|
|
38689
|
-
}
|
|
38690
|
-
function findMatchingBrace(text, openIdx) {
|
|
38691
|
-
let depth = 0;
|
|
38692
|
-
let inString = false;
|
|
38693
|
-
let escaped = false;
|
|
38694
|
-
for (let i = openIdx;i < text.length; i++) {
|
|
38695
|
-
const ch = text[i];
|
|
38696
|
-
if (escaped) {
|
|
38697
|
-
escaped = false;
|
|
38698
|
-
continue;
|
|
38699
|
-
}
|
|
38700
|
-
if (ch === "\\" && inString) {
|
|
38701
|
-
escaped = true;
|
|
38702
|
-
continue;
|
|
38703
|
-
}
|
|
38704
|
-
if (ch === '"') {
|
|
38705
|
-
inString = !inString;
|
|
38706
|
-
continue;
|
|
38707
|
-
}
|
|
38708
|
-
if (inString)
|
|
38709
|
-
continue;
|
|
38710
|
-
if (ch === "{")
|
|
38711
|
-
depth++;
|
|
38712
|
-
else if (ch === "}") {
|
|
38713
|
-
depth--;
|
|
38714
|
-
if (depth === 0)
|
|
38715
|
-
return i;
|
|
38716
|
-
}
|
|
38717
|
-
}
|
|
38718
|
-
return -1;
|
|
38719
|
-
}
|
|
38720
|
-
function parseJsonObject(stderr) {
|
|
38721
|
-
try {
|
|
38722
|
-
const value = JSON.parse(stderr);
|
|
38723
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
38724
|
-
return value;
|
|
38725
|
-
}
|
|
38726
|
-
return null;
|
|
38727
|
-
} catch {
|
|
38728
|
-
return null;
|
|
38729
|
-
}
|
|
38730
|
-
}
|
|
38731
|
-
function classifyJsonRpcModelError(payload) {
|
|
38732
|
-
const errObj = payload.error;
|
|
38733
|
-
if (!errObj || typeof errObj !== "object")
|
|
38734
|
-
return null;
|
|
38735
|
-
const message = errObj.message;
|
|
38736
|
-
if (typeof message !== "string")
|
|
38737
|
-
return null;
|
|
38738
|
-
return classifyModelErrorMessage(message);
|
|
38739
|
-
}
|
|
38740
|
-
function classifyModelErrorMessage(message) {
|
|
38741
|
-
if (message.startsWith("Cannot apply --model") || message.startsWith("Cannot replay saved model")) {
|
|
38742
|
-
return { type: "model-not-available" };
|
|
38743
|
-
}
|
|
38744
|
-
if (message.includes("There's an issue with the selected model") && message.includes("Run --model")) {
|
|
38745
|
-
return { type: "model-not-available" };
|
|
38746
|
-
}
|
|
38747
|
-
return null;
|
|
38748
|
-
}
|
|
38749
|
-
function classifyDirectType(payload) {
|
|
38750
|
-
const type = payload.type;
|
|
38751
|
-
if (type !== "rate-limit" && type !== "auth" && type !== "timeout" && type !== "crash" && type !== "unknown") {
|
|
38752
|
-
return null;
|
|
38753
|
-
}
|
|
38754
|
-
const result = { type };
|
|
38755
|
-
if (type === "rate-limit") {
|
|
38756
|
-
const retryAfterSeconds = toNumber(payload.retryAfterSeconds ?? payload.retry_after_seconds ?? payload.retryAfter);
|
|
38757
|
-
if (retryAfterSeconds !== undefined) {
|
|
38758
|
-
result.retryAfterSeconds = retryAfterSeconds;
|
|
38759
|
-
}
|
|
38760
|
-
}
|
|
38761
|
-
return result;
|
|
38762
|
-
}
|
|
38763
|
-
function extractJsonCodeTokens(payload) {
|
|
38764
|
-
const tokens = [];
|
|
38765
|
-
const pushToken = (candidate) => {
|
|
38766
|
-
if (typeof candidate === "number" && Number.isFinite(candidate)) {
|
|
38767
|
-
tokens.push(String(candidate));
|
|
38768
|
-
} else if (typeof candidate === "string" && candidate.trim()) {
|
|
38769
|
-
tokens.push(candidate.trim());
|
|
38770
|
-
}
|
|
38771
|
-
};
|
|
38772
|
-
const MAX_WALK_DEPTH = 8;
|
|
38773
|
-
const walk = (obj, depth) => {
|
|
38774
|
-
if (depth > MAX_WALK_DEPTH)
|
|
38775
|
-
return;
|
|
38776
|
-
const candidates = [
|
|
38777
|
-
obj.code,
|
|
38778
|
-
obj.status,
|
|
38779
|
-
obj.statusCode,
|
|
38780
|
-
obj.httpStatus,
|
|
38781
|
-
obj.errorCode,
|
|
38782
|
-
obj.acpxCode,
|
|
38783
|
-
obj.detailCode
|
|
38784
|
-
];
|
|
38785
|
-
for (const candidate of candidates)
|
|
38786
|
-
pushToken(candidate);
|
|
38787
|
-
for (const key of ["error", "data"]) {
|
|
38788
|
-
const nested = obj[key];
|
|
38789
|
-
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
38790
|
-
walk(nested, depth + 1);
|
|
38791
|
-
}
|
|
38792
|
-
}
|
|
38793
|
-
};
|
|
38794
|
-
walk(payload, 0);
|
|
38795
|
-
return tokens;
|
|
38796
|
-
}
|
|
38797
|
-
function extractBracketedCodes(stderr) {
|
|
38798
|
-
const tokens = [];
|
|
38799
|
-
const matches = stderr.match(/\[([A-Z0-9_/-]+)\]/g) ?? [];
|
|
38800
|
-
for (const entry of matches) {
|
|
38801
|
-
const inner = entry.slice(1, -1);
|
|
38802
|
-
for (const token of inner.split("/")) {
|
|
38803
|
-
const trimmed = token.trim();
|
|
38804
|
-
if (trimmed)
|
|
38805
|
-
tokens.push(trimmed);
|
|
38806
|
-
}
|
|
38807
|
-
}
|
|
38808
|
-
return tokens;
|
|
38809
|
-
}
|
|
38810
|
-
function extractKeyValueCodes(stderr) {
|
|
38811
|
-
const tokens = [];
|
|
38812
|
-
const patterns = [
|
|
38813
|
-
/(?:status|statusCode|httpStatus|code)\s*[:=]\s*(\d{3})/g,
|
|
38814
|
-
/(?:acpxCode|detailCode|errorCode)\s*[:=]\s*([A-Z0-9_]+)/g
|
|
38815
|
-
];
|
|
38816
|
-
for (const pattern of patterns) {
|
|
38817
|
-
while (true) {
|
|
38818
|
-
const match = pattern.exec(stderr);
|
|
38819
|
-
if (!match)
|
|
38820
|
-
break;
|
|
38821
|
-
const code = match[1];
|
|
38822
|
-
if (code)
|
|
38823
|
-
tokens.push(code);
|
|
38824
|
-
}
|
|
38825
|
-
}
|
|
38826
|
-
return tokens;
|
|
38827
|
-
}
|
|
38828
|
-
function classifyFromCodeTokens(tokens, payload) {
|
|
38829
|
-
for (const token of tokens.map((value) => value.toUpperCase())) {
|
|
38830
|
-
if (token === "429" || token === "TOO_MANY_REQUESTS" || token === "RATE_LIMIT" || token === "RATE_LIMITED" || token === "QUOTA_EXCEEDED" || token === "RESOURCE_EXHAUSTED") {
|
|
38831
|
-
const retryAfterSeconds = payload ? findRetryAfterSeconds(payload) : undefined;
|
|
38832
|
-
return retryAfterSeconds !== undefined ? { type: "rate-limit", retryAfterSeconds } : { type: "rate-limit" };
|
|
38833
|
-
}
|
|
38834
|
-
if (token === "401" || token === "403" || token === "UNAUTHORIZED" || token === "FORBIDDEN" || token === "AUTH_FAILED" || token === "AUTHENTICATION_FAILED" || token === "PERMISSION_DENIED") {
|
|
38835
|
-
return { type: "auth" };
|
|
38836
|
-
}
|
|
38837
|
-
}
|
|
38838
|
-
return null;
|
|
38839
|
-
}
|
|
38840
|
-
function toNumber(value) {
|
|
38841
|
-
if (typeof value === "number" && Number.isFinite(value))
|
|
38842
|
-
return Math.trunc(value);
|
|
38843
|
-
if (typeof value === "string" && value.trim()) {
|
|
38844
|
-
const parsed = Number.parseInt(value, 10);
|
|
38845
|
-
if (Number.isFinite(parsed))
|
|
38846
|
-
return parsed;
|
|
38847
|
-
}
|
|
38848
|
-
return;
|
|
38849
|
-
}
|
|
38850
|
-
function findRetryAfterSeconds(payload) {
|
|
38851
|
-
const topLevel = toNumber(payload.retryAfterSeconds ?? payload.retry_after_seconds ?? payload.retryAfter);
|
|
38852
|
-
if (topLevel !== undefined)
|
|
38853
|
-
return topLevel;
|
|
38854
|
-
const error48 = payload.error;
|
|
38855
|
-
if (error48 && typeof error48 === "object" && !Array.isArray(error48)) {
|
|
38856
|
-
const errObj = error48;
|
|
38857
|
-
const inError = toNumber(errObj.retryAfterSeconds ?? errObj.retry_after_seconds ?? errObj.retryAfter);
|
|
38858
|
-
if (inError !== undefined)
|
|
38859
|
-
return inError;
|
|
38860
|
-
const data = errObj.data;
|
|
38861
|
-
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
38862
|
-
const dataObj = data;
|
|
38863
|
-
return toNumber(dataObj.retryAfterSeconds ?? dataObj.retry_after_seconds ?? dataObj.retryAfter);
|
|
38864
|
-
}
|
|
38865
|
-
}
|
|
38866
|
-
return;
|
|
38867
|
-
}
|
|
38868
|
-
var MAX_EMBEDDED_CANDIDATES = 8;
|
|
38869
|
-
|
|
38870
|
-
// src/agents/errors/index.ts
|
|
38871
|
-
var init_errors5 = () => {};
|
|
38872
|
-
|
|
38873
|
-
// src/agents/shared/env.ts
|
|
38874
|
-
import { homedir as homedir5 } from "os";
|
|
38875
|
-
import { isAbsolute as isAbsolute10 } from "path";
|
|
38876
|
-
function buildAllowedEnv(options) {
|
|
38877
|
-
const allowed = {};
|
|
38878
|
-
for (const varName of ESSENTIAL_VARS) {
|
|
38879
|
-
if (process.env[varName])
|
|
38880
|
-
allowed[varName] = process.env[varName];
|
|
38881
|
-
}
|
|
38882
|
-
const rawHome = process.env.HOME ?? "";
|
|
38883
|
-
const safeHome = rawHome && isAbsolute10(rawHome) ? rawHome : homedir5();
|
|
38884
|
-
if (rawHome !== safeHome) {
|
|
38885
|
-
getSafeLogger2()?.warn("env", `HOME env is not absolute ("${rawHome}"), falling back to os.homedir(): ${safeHome}`);
|
|
38886
|
-
}
|
|
38887
|
-
allowed.HOME = safeHome;
|
|
38888
|
-
for (const varName of API_KEY_VARS) {
|
|
38889
|
-
if (process.env[varName])
|
|
38890
|
-
allowed[varName] = process.env[varName];
|
|
38891
|
-
}
|
|
38892
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
38893
|
-
if (ALLOWED_PREFIXES.some((prefix) => key.startsWith(prefix))) {
|
|
38894
|
-
allowed[key] = value;
|
|
38895
|
-
}
|
|
38896
|
-
}
|
|
38897
|
-
if (options?.modelEnv)
|
|
38898
|
-
Object.assign(allowed, options.modelEnv);
|
|
38899
|
-
if (options?.env)
|
|
38900
|
-
Object.assign(allowed, options.env);
|
|
38901
|
-
return allowed;
|
|
38902
|
-
}
|
|
38903
|
-
var ESSENTIAL_VARS, API_KEY_VARS, ALLOWED_PREFIXES;
|
|
38904
|
-
var init_env = __esm(() => {
|
|
38905
|
-
init_logger2();
|
|
38906
|
-
ESSENTIAL_VARS = ["PATH", "TMPDIR", "NODE_ENV", "USER", "LOGNAME"];
|
|
38907
|
-
API_KEY_VARS = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY", "CLAUDE_API_KEY"];
|
|
38908
|
-
ALLOWED_PREFIXES = [
|
|
38909
|
-
"CLAUDE_",
|
|
38910
|
-
"NAX_",
|
|
38911
|
-
"CLAW_",
|
|
38912
|
-
"TURBO_",
|
|
38913
|
-
"ACPX_",
|
|
38914
|
-
"CODEX_",
|
|
38915
|
-
"GEMINI_",
|
|
38916
|
-
"ANTHROPIC_",
|
|
38917
|
-
"OPENCODE_",
|
|
38918
|
-
"MINIMAX_"
|
|
38919
|
-
];
|
|
38920
|
-
});
|
|
38921
|
-
|
|
38922
|
-
// src/agents/acp/reasoning-effort.ts
|
|
38923
|
-
async function discoverEffortOptionId(params) {
|
|
38924
|
-
const { agentName, sessionName, cwd, storyId, spawn: spawn2 } = params;
|
|
38925
|
-
const cmd = ["acpx", "--cwd", cwd, "--format", "json", agentName, "sessions", "show", sessionName];
|
|
38926
|
-
try {
|
|
38927
|
-
const { exitCode, stdout, stderr } = await spawn2(cmd);
|
|
38928
|
-
if (exitCode !== 0) {
|
|
38929
|
-
getSafeLogger2()?.debug("acp-adapter", "Could not list session config options; falling back to static map", {
|
|
38930
|
-
storyId,
|
|
38931
|
-
agentName,
|
|
38932
|
-
cause: stdout || stderr
|
|
38933
|
-
});
|
|
38934
|
-
return;
|
|
38935
|
-
}
|
|
38936
|
-
const parsed = JSON.parse(stdout);
|
|
38937
|
-
const options = parsed.acpx?.config_options;
|
|
38938
|
-
const match = Array.isArray(options) ? options.find((o) => o?.category === THOUGHT_LEVEL_CATEGORY) : undefined;
|
|
38939
|
-
return typeof match?.id === "string" ? match.id : undefined;
|
|
38940
|
-
} catch (err) {
|
|
38941
|
-
getSafeLogger2()?.debug("acp-adapter", "Effort option discovery failed; falling back to static map", {
|
|
38942
|
-
storyId,
|
|
38943
|
-
agentName,
|
|
38944
|
-
cause: err instanceof Error ? err.message : String(err)
|
|
38945
|
-
});
|
|
38946
|
-
return;
|
|
38947
|
-
}
|
|
38948
|
-
}
|
|
38949
|
-
async function applyReasoningEffort(params) {
|
|
38950
|
-
const { effort, agentName, sessionName, cwd, storyId, spawn: spawn2 } = params;
|
|
38951
|
-
if (!effort)
|
|
38952
|
-
return;
|
|
38953
|
-
const optionName = await discoverEffortOptionId({ agentName, sessionName, cwd, storyId, spawn: spawn2 }) ?? EFFORT_OPTION_BY_AGENT[agentName];
|
|
38954
|
-
if (!optionName) {
|
|
38955
|
-
getSafeLogger2()?.debug("acp-adapter", "Agent has no known effort option; skipping", {
|
|
38956
|
-
storyId,
|
|
38957
|
-
agentName,
|
|
38958
|
-
effort
|
|
38959
|
-
});
|
|
38960
|
-
return;
|
|
38961
|
-
}
|
|
38962
|
-
const cmd = ["acpx", "--cwd", cwd, agentName, "set", optionName, effort, "-s", sessionName];
|
|
38963
|
-
const { exitCode, stdout, stderr } = await spawn2(cmd);
|
|
38964
|
-
if (exitCode !== 0) {
|
|
38965
|
-
getSafeLogger2()?.warn("acp-adapter", `Failed to set ${optionName}; continuing at adapter default`, {
|
|
38966
|
-
storyId,
|
|
38967
|
-
effort,
|
|
38968
|
-
session: sessionName,
|
|
38969
|
-
cause: stdout || stderr
|
|
38970
|
-
});
|
|
38971
|
-
}
|
|
38972
|
-
}
|
|
38973
|
-
var THOUGHT_LEVEL_CATEGORY = "thought_level", EFFORT_OPTION_BY_AGENT;
|
|
38974
|
-
var init_reasoning_effort = __esm(() => {
|
|
38975
|
-
init_logger2();
|
|
38976
|
-
EFFORT_OPTION_BY_AGENT = {
|
|
38977
|
-
codex: "reasoning_effort",
|
|
38978
|
-
claude: "effort",
|
|
38979
|
-
opencode: "effort",
|
|
38980
|
-
pi: "thought_level"
|
|
38981
|
-
};
|
|
38982
|
-
});
|
|
38983
|
-
|
|
38984
|
-
// src/agents/acp/session-ids.ts
|
|
38985
|
-
function parseSessionIds(stdout) {
|
|
38986
|
-
for (const line of stdout.split(`
|
|
38987
|
-
`).reverse()) {
|
|
38988
|
-
const trimmed = line.trim();
|
|
38989
|
-
if (!trimmed.startsWith("{"))
|
|
38990
|
-
continue;
|
|
38991
|
-
try {
|
|
38992
|
-
const parsed = JSON.parse(trimmed);
|
|
38993
|
-
const sessionId = parsed.acpxSessionId;
|
|
38994
|
-
const recordId = parsed.acpxRecordId;
|
|
38995
|
-
if (typeof sessionId === "string" && sessionId.length > 0) {
|
|
38996
|
-
return {
|
|
38997
|
-
sessionId,
|
|
38998
|
-
recordId: typeof recordId === "string" && recordId.length > 0 ? recordId : undefined
|
|
38999
|
-
};
|
|
39000
|
-
}
|
|
39001
|
-
} catch {}
|
|
39002
|
-
}
|
|
39003
|
-
return { sessionId: undefined, recordId: undefined };
|
|
39004
|
-
}
|
|
39005
|
-
|
|
39006
|
-
// src/agents/acp/spawn-client-deps.ts
|
|
39007
|
-
var ACPX_STREAM_DRAIN_TIMEOUT_MS = 5000, KILL_TREE_GRACE_MS = 250, TRACKED_SPAWN_DEADLINE_MS = 1e4, TRACKED_SPAWN_STARTUP_DEADLINE_MS = 30000, _spawnClientDeps;
|
|
39008
|
-
var init_spawn_client_deps = __esm(() => {
|
|
39009
|
-
init_bun_deps();
|
|
39010
|
-
_spawnClientDeps = {
|
|
39011
|
-
spawn: typedSpawn,
|
|
39012
|
-
streamDrainTimeoutMs: ACPX_STREAM_DRAIN_TIMEOUT_MS,
|
|
39013
|
-
killTreeGraceMs: KILL_TREE_GRACE_MS,
|
|
39014
|
-
trackedSpawnDeadlineMs: TRACKED_SPAWN_DEADLINE_MS,
|
|
39015
|
-
trackedSpawnStartupDeadlineMs: TRACKED_SPAWN_STARTUP_DEADLINE_MS
|
|
39016
|
-
};
|
|
39017
|
-
});
|
|
39018
|
-
|
|
39019
|
-
// src/agents/acp/spawn-client-process.ts
|
|
39020
|
-
function makeStreamDrain(ms) {
|
|
39021
|
-
let id;
|
|
39022
|
-
const promise2 = new Promise((resolve21) => {
|
|
39023
|
-
id = setTimeout(() => resolve21(""), ms);
|
|
39024
|
-
});
|
|
39025
|
-
return { promise: promise2, cancel: () => clearTimeout(id) };
|
|
39026
|
-
}
|
|
39027
|
-
function killProcessTree(pid, graceMs, exited) {
|
|
39028
|
-
activeKillTimers.get(pid)?.cancel();
|
|
39029
|
-
activeKillTimers.delete(pid);
|
|
39030
|
-
try {
|
|
39031
|
-
killProcessGroup(pid, "SIGTERM");
|
|
39032
|
-
getSafeLogger2()?.debug("acp-adapter", `Sent SIGTERM to process group ${pid}`);
|
|
39033
|
-
} catch {}
|
|
39034
|
-
let settled2 = false;
|
|
39035
|
-
const timer = { id: undefined };
|
|
39036
|
-
const gracePromise = new Promise((resolve21) => {
|
|
39037
|
-
timer.id = setTimeout(() => resolve21("grace"), graceMs);
|
|
39038
|
-
if (timer.id.unref)
|
|
39039
|
-
timer.id.unref();
|
|
39040
|
-
});
|
|
39041
|
-
const exitedPromise = exited?.then(() => "exited", () => "exited");
|
|
39042
|
-
const raced = exitedPromise !== undefined ? Promise.race([gracePromise, exitedPromise]) : gracePromise;
|
|
39043
|
-
raced.then((outcome) => {
|
|
39044
|
-
clearTimeout(timer.id);
|
|
39045
|
-
if (settled2)
|
|
39046
|
-
return;
|
|
39047
|
-
settled2 = true;
|
|
39048
|
-
activeKillTimers.delete(pid);
|
|
39049
|
-
if (outcome === "exited")
|
|
39050
|
-
return;
|
|
39051
|
-
if (!isProcessAlive(pid))
|
|
39052
|
-
return;
|
|
39053
|
-
try {
|
|
39054
|
-
killProcessGroup(pid, "SIGKILL");
|
|
39055
|
-
} catch {}
|
|
39056
|
-
});
|
|
39057
|
-
const handle = {
|
|
39058
|
-
cancel: () => {
|
|
39059
|
-
settled2 = true;
|
|
39060
|
-
clearTimeout(timer.id);
|
|
39061
|
-
activeKillTimers.delete(pid);
|
|
39062
|
-
}
|
|
39063
|
-
};
|
|
39064
|
-
activeKillTimers.set(pid, handle);
|
|
39065
|
-
return handle;
|
|
39066
|
-
}
|
|
39067
|
-
async function runTrackedSpawn(deps, cmd, opts, onPidSpawned, onPidExited, signal) {
|
|
39068
|
-
const proc = deps.spawn(cmd, { stdout: "pipe", stderr: "pipe", ...opts });
|
|
39069
|
-
const pid = proc.pid;
|
|
39070
|
-
onPidSpawned?.(pid);
|
|
39071
|
-
const exitedNotified = proc.exited.catch(() => -1).finally(() => {
|
|
39072
|
-
try {
|
|
39073
|
-
onPidExited?.(pid);
|
|
39074
|
-
} catch {}
|
|
39075
|
-
});
|
|
39076
|
-
const deadlineController = new AbortController;
|
|
39077
|
-
const forwardAbort = () => deadlineController.abort(signal?.reason);
|
|
39078
|
-
if (signal?.aborted) {
|
|
39079
|
-
deadlineController.abort(signal.reason);
|
|
39080
|
-
} else {
|
|
39081
|
-
signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
39082
|
-
}
|
|
39083
|
-
const deadline = cancellableDelay(deps.trackedSpawnDeadlineMs, deadlineController.signal).catch(() => {});
|
|
39084
|
-
try {
|
|
39085
|
-
const raced = await Promise.race([
|
|
39086
|
-
exitedNotified.then((code) => ({ timedOut: false, code })),
|
|
39087
|
-
deadline.then(() => ({ timedOut: true, code: -1 }))
|
|
39088
|
-
]);
|
|
39089
|
-
if (raced.timedOut) {
|
|
39090
|
-
const reason = signal?.aborted ? "aborted" : "deadline exceeded";
|
|
39091
|
-
getSafeLogger2()?.warn("acp-adapter", `trackedSpawn ${reason} \u2014 killing process tree for PID ${pid}`, {
|
|
39092
|
-
pid,
|
|
39093
|
-
deadlineMs: deps.trackedSpawnDeadlineMs,
|
|
39094
|
-
reason
|
|
39095
|
-
});
|
|
39096
|
-
killProcessTree(pid, deps.killTreeGraceMs, proc.exited);
|
|
39097
|
-
try {
|
|
39098
|
-
proc.stdout?.cancel?.();
|
|
39099
|
-
} catch {}
|
|
39100
|
-
try {
|
|
39101
|
-
proc.stderr?.cancel?.();
|
|
39102
|
-
} catch {}
|
|
39103
|
-
return { exitCode: -1, stdout: "", stderr: "" };
|
|
39104
|
-
}
|
|
39105
|
-
const [stdout, stderr] = await Promise.all([
|
|
39106
|
-
drainStream(proc.stdout, deps.streamDrainTimeoutMs),
|
|
39107
|
-
drainStream(proc.stderr, deps.streamDrainTimeoutMs)
|
|
39108
|
-
]);
|
|
39109
|
-
return { exitCode: raced.code, stdout, stderr };
|
|
39110
|
-
} finally {
|
|
39111
|
-
deadlineController.abort();
|
|
39112
|
-
signal?.removeEventListener("abort", forwardAbort);
|
|
39113
|
-
}
|
|
39114
|
-
}
|
|
39115
|
-
async function drainStream(stream, timeoutMs) {
|
|
39116
|
-
if (!stream)
|
|
39117
|
-
return "";
|
|
39118
|
-
const reader = stream.getReader();
|
|
39119
|
-
const decoder = new TextDecoder;
|
|
39120
|
-
const readAll = async () => {
|
|
39121
|
-
let text = "";
|
|
39122
|
-
for (;; ) {
|
|
39123
|
-
const { done, value } = await reader.read();
|
|
39124
|
-
if (done)
|
|
39125
|
-
break;
|
|
39126
|
-
text += decoder.decode(value, { stream: true });
|
|
39127
|
-
}
|
|
39128
|
-
text += decoder.decode();
|
|
39129
|
-
return text;
|
|
39130
|
-
};
|
|
39131
|
-
const drain = makeStreamDrain(timeoutMs);
|
|
39132
|
-
const winner = await Promise.race([
|
|
39133
|
-
readAll().catch(() => "").then((text) => ({ fromStream: true, text })),
|
|
39134
|
-
drain.promise.then(() => ({ fromStream: false, text: "" }))
|
|
39135
|
-
]).finally(() => drain.cancel());
|
|
39136
|
-
if (!winner.fromStream) {
|
|
39137
|
-
reader.cancel().catch(() => {});
|
|
39138
|
-
}
|
|
39139
|
-
return winner.text;
|
|
39140
|
-
}
|
|
39141
|
-
var activeKillTimers;
|
|
39142
|
-
var init_spawn_client_process = __esm(() => {
|
|
39143
|
-
init_internal();
|
|
39144
|
-
init_logger2();
|
|
39145
|
-
init_bun_deps();
|
|
39146
|
-
activeKillTimers = new Map;
|
|
39147
|
-
});
|
|
39148
|
-
|
|
39149
|
-
// src/agents/acp/parser-line-handlers.ts
|
|
39150
|
-
function asFiniteNumber(...values) {
|
|
39151
|
-
for (const v of values) {
|
|
39152
|
-
if (typeof v === "number" && Number.isFinite(v))
|
|
39153
|
-
return v;
|
|
39154
|
-
}
|
|
39155
|
-
return;
|
|
39156
|
-
}
|
|
39157
|
-
function isProtocolDrift(event) {
|
|
39158
|
-
const looksLikeJsonRpcShape = typeof event.method === "string" && event.params !== undefined || event.id !== undefined && event.result && typeof event.result === "object";
|
|
39159
|
-
return event.jsonrpc !== "2.0" && looksLikeJsonRpcShape;
|
|
39160
|
-
}
|
|
39161
|
-
function reportProtocolDrift(event, state) {
|
|
39162
|
-
getSafeLogger2()?.error("acp-adapter", "Unsupported or missing JSON-RPC protocol version in acpx output", {
|
|
39163
|
-
jsonrpc: event.jsonrpc,
|
|
39164
|
-
method: typeof event.method === "string" ? event.method : undefined
|
|
39165
|
-
});
|
|
39166
|
-
state.error ??= "Unsupported acpx JSON-RPC protocol version";
|
|
39167
|
-
}
|
|
39168
|
-
function decorateAcpxError(err, errorMsg, state) {
|
|
39169
|
-
let msg = errorMsg;
|
|
39170
|
-
const data = err.data;
|
|
39171
|
-
if (data && typeof data === "object") {
|
|
39172
|
-
const suffix = [data.acpxCode, data.detailCode].filter(Boolean).join("/");
|
|
39173
|
-
if (suffix)
|
|
39174
|
-
msg = `${msg} [${suffix}]`;
|
|
39175
|
-
if (!state.error && data.retryable === true)
|
|
39176
|
-
state.retryable = true;
|
|
39177
|
-
}
|
|
39178
|
-
return msg;
|
|
39179
|
-
}
|
|
39180
|
-
function handleAgentMessageChunk(update, state) {
|
|
39181
|
-
if (update.content?.type === "text" && typeof update.content.text === "string") {
|
|
39182
|
-
const text = update.content.text;
|
|
39183
|
-
state.text += text;
|
|
39184
|
-
return {
|
|
39185
|
-
kind: "message_update",
|
|
39186
|
-
deltaBytes: text.length
|
|
39187
|
-
};
|
|
39188
|
-
}
|
|
39189
|
-
return;
|
|
39190
|
-
}
|
|
39191
|
-
function handleAgentThoughtChunk(update) {
|
|
39192
|
-
if (update.content?.type === "text" && typeof update.content.text === "string") {
|
|
39193
|
-
return {
|
|
39194
|
-
kind: "thinking_update",
|
|
39195
|
-
deltaBytes: update.content.text.length
|
|
39196
|
-
};
|
|
39197
|
-
}
|
|
39198
|
-
return;
|
|
39199
|
-
}
|
|
39200
|
-
function handleUsageUpdate(update, state) {
|
|
39201
|
-
const activity = { kind: "usage_update" };
|
|
39202
|
-
const metaUsage = update._meta != null && typeof update._meta === "object" ? update._meta.usage : undefined;
|
|
39203
|
-
if (metaUsage != null && typeof metaUsage === "object") {
|
|
39204
|
-
const inp = asFiniteNumber(metaUsage.inputTokens, metaUsage.input_tokens);
|
|
39205
|
-
if (inp !== undefined)
|
|
39206
|
-
activity.inputTokens = inp;
|
|
39207
|
-
const out = asFiniteNumber(metaUsage.outputTokens, metaUsage.output_tokens);
|
|
39208
|
-
if (out !== undefined)
|
|
39209
|
-
activity.outputTokens = out;
|
|
39210
|
-
const cacheRead = asFiniteNumber(metaUsage.cachedReadTokens, metaUsage.cache_read_input_tokens);
|
|
39211
|
-
if (cacheRead !== undefined)
|
|
39212
|
-
activity.cacheRead = cacheRead;
|
|
39213
|
-
const cacheWrite = asFiniteNumber(metaUsage.cachedWriteTokens, metaUsage.cache_creation_input_tokens);
|
|
39214
|
-
if (cacheWrite !== undefined)
|
|
39215
|
-
activity.cacheWrite = cacheWrite;
|
|
39216
|
-
}
|
|
39217
|
-
if (activity.outputTokens == null) {
|
|
39218
|
-
const used = asFiniteNumber(update.used);
|
|
39219
|
-
if (used !== undefined)
|
|
39220
|
-
activity.outputTokens = used;
|
|
39221
|
-
}
|
|
39222
|
-
const costAmount = asFiniteNumber(update.cost?.amount);
|
|
39223
|
-
if (costAmount !== undefined) {
|
|
39224
|
-
activity.costUsd = costAmount;
|
|
39225
|
-
state.exactCostUsd = costAmount;
|
|
39226
|
-
}
|
|
39227
|
-
return activity;
|
|
39228
|
-
}
|
|
39229
|
-
function handleToolCallActivity(update) {
|
|
39230
|
-
return {
|
|
39231
|
-
kind: "tool_call_update",
|
|
39232
|
-
toolName: extractToolName(update)
|
|
39233
|
-
};
|
|
39234
|
-
}
|
|
39235
|
-
function extractToolName(update) {
|
|
39236
|
-
const directName = update.toolName;
|
|
39237
|
-
if (typeof directName === "string" && directName.trim())
|
|
39238
|
-
return directName;
|
|
39239
|
-
const nestedTool = update.tool;
|
|
39240
|
-
if (nestedTool && typeof nestedTool === "object") {
|
|
39241
|
-
const name = nestedTool.name;
|
|
39242
|
-
if (typeof name === "string" && name.trim())
|
|
39243
|
-
return name;
|
|
39244
|
-
}
|
|
39245
|
-
return;
|
|
39246
|
-
}
|
|
39247
|
-
function handleSessionUpdate(update, state) {
|
|
39248
|
-
const key = update.sessionUpdate;
|
|
39249
|
-
if (typeof key !== "string")
|
|
39250
|
-
return;
|
|
39251
|
-
if (!Object.hasOwn(SESSION_UPDATE_HANDLERS, key))
|
|
39252
|
-
return;
|
|
39253
|
-
return SESSION_UPDATE_HANDLERS[key](update, state);
|
|
39254
|
-
}
|
|
39255
|
-
function applyJsonRpcResult(event, state) {
|
|
39256
|
-
if (event.id !== undefined && event.result && typeof event.result === "object") {
|
|
39257
|
-
const result = event.result;
|
|
39258
|
-
if (result.stopReason)
|
|
39259
|
-
state.stopReason = result.stopReason;
|
|
39260
|
-
if (result.stop_reason)
|
|
39261
|
-
state.stopReason = result.stop_reason;
|
|
39262
|
-
if (result.usage && typeof result.usage === "object") {
|
|
39263
|
-
const u = result.usage;
|
|
39264
|
-
const inputTokens = asFiniteNumber(u.inputTokens, u.input_tokens);
|
|
39265
|
-
const outputTokens = asFiniteNumber(u.outputTokens, u.output_tokens);
|
|
39266
|
-
if (inputTokens !== undefined && outputTokens !== undefined) {
|
|
39267
|
-
state.tokenUsage = {
|
|
39268
|
-
input_tokens: inputTokens,
|
|
39269
|
-
output_tokens: outputTokens,
|
|
39270
|
-
cache_read_input_tokens: asFiniteNumber(u.cachedReadTokens, u.cache_read_input_tokens) ?? 0,
|
|
39271
|
-
cache_creation_input_tokens: asFiniteNumber(u.cachedWriteTokens, u.cache_creation_input_tokens) ?? 0
|
|
39272
|
-
};
|
|
39273
|
-
}
|
|
39274
|
-
}
|
|
39275
|
-
}
|
|
39276
|
-
}
|
|
39277
|
-
function applyJsonRpcError(event, state) {
|
|
39278
|
-
if (event.error && typeof event.error === "object") {
|
|
39279
|
-
const err = event.error;
|
|
39280
|
-
let errorMsg = typeof err.message === "string" ? err.message : JSON.stringify(event.error);
|
|
39281
|
-
errorMsg = decorateAcpxError(err, errorMsg, state);
|
|
39282
|
-
if (!state.error)
|
|
39283
|
-
state.error = errorMsg;
|
|
39284
|
-
}
|
|
39285
|
-
}
|
|
39286
|
-
function handleJsonRpcEvent(event, state) {
|
|
39287
|
-
if (event.method === "session/update" && event.params?.update) {
|
|
39288
|
-
const activity = handleSessionUpdate(event.params.update, state);
|
|
39289
|
-
if (activity !== undefined)
|
|
39290
|
-
return activity;
|
|
39291
|
-
}
|
|
39292
|
-
applyJsonRpcResult(event, state);
|
|
39293
|
-
applyJsonRpcError(event, state);
|
|
39294
|
-
return;
|
|
39295
|
-
}
|
|
39296
|
-
function applyLegacyCumulativeUsage(event, state) {
|
|
39297
|
-
if (event.cumulative_token_usage && typeof event.cumulative_token_usage === "object") {
|
|
39298
|
-
const c = event.cumulative_token_usage;
|
|
39299
|
-
const inputTokens = asFiniteNumber(c.input_tokens);
|
|
39300
|
-
const outputTokens = asFiniteNumber(c.output_tokens);
|
|
39301
|
-
if (inputTokens !== undefined && outputTokens !== undefined) {
|
|
39302
|
-
state.tokenUsage = {
|
|
39303
|
-
input_tokens: inputTokens,
|
|
39304
|
-
output_tokens: outputTokens,
|
|
39305
|
-
cache_read_input_tokens: asFiniteNumber(c.cache_read_input_tokens) ?? 0,
|
|
39306
|
-
cache_creation_input_tokens: asFiniteNumber(c.cache_creation_input_tokens) ?? 0
|
|
39307
|
-
};
|
|
39308
|
-
}
|
|
39309
|
-
}
|
|
39310
|
-
}
|
|
39311
|
-
function applyLegacyUsage(event, state) {
|
|
39312
|
-
if (!event.usage)
|
|
39313
|
-
return;
|
|
39314
|
-
const legacyInputTokens = asFiniteNumber(event.usage.input_tokens, event.usage.prompt_tokens);
|
|
39315
|
-
const legacyOutputTokens = asFiniteNumber(event.usage.output_tokens, event.usage.completion_tokens);
|
|
39316
|
-
if (legacyInputTokens !== undefined && legacyOutputTokens !== undefined) {
|
|
39317
|
-
state.tokenUsage = {
|
|
39318
|
-
input_tokens: legacyInputTokens,
|
|
39319
|
-
output_tokens: legacyOutputTokens
|
|
39320
|
-
};
|
|
39321
|
-
}
|
|
39322
|
-
}
|
|
39323
|
-
function applyLegacyStopReason(event, state) {
|
|
39324
|
-
if (event.stopReason)
|
|
39325
|
-
state.stopReason = event.stopReason;
|
|
39326
|
-
if (event.stop_reason)
|
|
39327
|
-
state.stopReason = event.stop_reason;
|
|
39328
|
-
}
|
|
39329
|
-
function applyLegacyError(event, state) {
|
|
39330
|
-
if (!event.error)
|
|
39331
|
-
return;
|
|
39332
|
-
if (typeof event.error === "string") {
|
|
39333
|
-
state.error ??= event.error;
|
|
39334
|
-
return;
|
|
39335
|
-
}
|
|
39336
|
-
let errorMsg = typeof event.error.message === "string" ? event.error.message : JSON.stringify(event.error);
|
|
39337
|
-
errorMsg = decorateAcpxError(event.error, errorMsg, state);
|
|
39338
|
-
state.error ??= errorMsg;
|
|
39339
|
-
}
|
|
39340
|
-
function handleLegacyLine(event, state) {
|
|
39341
|
-
if (event.result && typeof event.result === "string") {
|
|
39342
|
-
state.text = event.result;
|
|
39343
|
-
} else if (event.content && typeof event.content === "string") {
|
|
39344
|
-
state.text += event.content;
|
|
39345
|
-
} else if (event.text && typeof event.text === "string") {
|
|
39346
|
-
state.text += event.text;
|
|
39347
|
-
}
|
|
39348
|
-
applyLegacyCumulativeUsage(event, state);
|
|
39349
|
-
applyLegacyUsage(event, state);
|
|
39350
|
-
applyLegacyStopReason(event, state);
|
|
39351
|
-
applyLegacyError(event, state);
|
|
39352
|
-
}
|
|
39353
|
-
var SESSION_UPDATE_HANDLERS;
|
|
39354
|
-
var init_parser_line_handlers = __esm(() => {
|
|
39355
|
-
init_logger2();
|
|
39356
|
-
SESSION_UPDATE_HANDLERS = {
|
|
39357
|
-
agent_message_chunk: handleAgentMessageChunk,
|
|
39358
|
-
agent_thought_chunk: handleAgentThoughtChunk,
|
|
39359
|
-
usage_update: handleUsageUpdate,
|
|
39360
|
-
tool_call: handleToolCallActivity,
|
|
39361
|
-
tool_call_update: handleToolCallActivity
|
|
39362
|
-
};
|
|
39363
|
-
});
|
|
39364
|
-
|
|
39365
|
-
// src/agents/acp/parser.ts
|
|
39366
|
-
function createParseState() {
|
|
39367
|
-
return {
|
|
39368
|
-
text: "",
|
|
39369
|
-
tokenUsage: undefined,
|
|
39370
|
-
exactCostUsd: undefined,
|
|
39371
|
-
stopReason: undefined,
|
|
39372
|
-
error: undefined,
|
|
39373
|
-
retryable: false,
|
|
39374
|
-
sawJsonLine: false
|
|
39375
|
-
};
|
|
39376
|
-
}
|
|
39377
|
-
function parseAcpxJsonLine(line, state) {
|
|
39378
|
-
try {
|
|
39379
|
-
const event = JSON.parse(line);
|
|
39380
|
-
if (!state.sawJsonLine) {
|
|
39381
|
-
state.text = "";
|
|
39382
|
-
state.sawJsonLine = true;
|
|
39383
|
-
}
|
|
39384
|
-
if (isProtocolDrift(event)) {
|
|
39385
|
-
reportProtocolDrift(event, state);
|
|
39386
|
-
return;
|
|
39387
|
-
}
|
|
39388
|
-
if (event.jsonrpc === "2.0") {
|
|
39389
|
-
return handleJsonRpcEvent(event, state);
|
|
39390
|
-
}
|
|
39391
|
-
handleLegacyLine(event, state);
|
|
39392
|
-
} catch {
|
|
39393
|
-
if (!state.text && !state.sawJsonLine)
|
|
39394
|
-
state.text = line;
|
|
39395
|
-
}
|
|
39396
|
-
return;
|
|
39397
|
-
}
|
|
39398
|
-
function finalizeParseState(state) {
|
|
39399
|
-
return {
|
|
39400
|
-
text: state.text.trim(),
|
|
39401
|
-
tokenUsage: state.tokenUsage,
|
|
39402
|
-
exactCostUsd: state.exactCostUsd,
|
|
39403
|
-
stopReason: state.stopReason,
|
|
39404
|
-
error: state.error,
|
|
39405
|
-
retryable: state.retryable
|
|
39406
|
-
};
|
|
39407
|
-
}
|
|
39408
|
-
var init_parser = __esm(() => {
|
|
39409
|
-
init_parser_line_handlers();
|
|
39410
|
-
});
|
|
39411
|
-
|
|
39412
|
-
// src/agents/acp/stdout-line-reader.ts
|
|
39413
|
-
function readStreamTail(stream, maxBytes = MAX_BUFFERED_STDERR_BYTES) {
|
|
39414
|
-
const decoder = new TextDecoder;
|
|
39415
|
-
const reader = stream.getReader();
|
|
39416
|
-
let tail = "";
|
|
39417
|
-
const append = (chunk) => {
|
|
39418
|
-
tail += chunk;
|
|
39419
|
-
const bytes = Buffer.byteLength(tail, "utf8");
|
|
39420
|
-
if (bytes <= maxBytes)
|
|
39421
|
-
return;
|
|
39422
|
-
let cutoff = bytes - maxBytes;
|
|
39423
|
-
let index = 0;
|
|
39424
|
-
while (index < tail.length && cutoff > 0) {
|
|
39425
|
-
const cp = tail.codePointAt(index) ?? 0;
|
|
39426
|
-
const units = cp > 65535 ? 2 : 1;
|
|
39427
|
-
index += units;
|
|
39428
|
-
cutoff -= Buffer.byteLength(String.fromCodePoint(cp), "utf8");
|
|
39429
|
-
}
|
|
39430
|
-
tail = tail.slice(index);
|
|
39431
|
-
};
|
|
39432
|
-
const promise2 = (async () => {
|
|
39433
|
-
try {
|
|
39434
|
-
while (true) {
|
|
39435
|
-
const { done, value } = await reader.read();
|
|
39436
|
-
if (done)
|
|
39437
|
-
break;
|
|
39438
|
-
append(decoder.decode(value, { stream: true }));
|
|
39439
|
-
}
|
|
39440
|
-
append(decoder.decode());
|
|
39441
|
-
return tail;
|
|
39442
|
-
} finally {
|
|
39443
|
-
reader.releaseLock();
|
|
39444
|
-
}
|
|
39445
|
-
})();
|
|
39446
|
-
return {
|
|
39447
|
-
promise: promise2,
|
|
39448
|
-
cancel: () => {
|
|
39449
|
-
reader.cancel().catch(() => {});
|
|
39450
|
-
}
|
|
39451
|
-
};
|
|
39452
|
-
}
|
|
39453
|
-
function readAndParseLines(stream, state, onActivity) {
|
|
39454
|
-
const decoder = new TextDecoder;
|
|
39455
|
-
let remainder = "";
|
|
39456
|
-
const reader = stream.getReader();
|
|
39457
|
-
const promise2 = (async () => {
|
|
39458
|
-
try {
|
|
39459
|
-
while (true) {
|
|
39460
|
-
const { done, value } = await reader.read();
|
|
39461
|
-
if (done)
|
|
39462
|
-
break;
|
|
39463
|
-
remainder += decoder.decode(value, { stream: true });
|
|
39464
|
-
for (;; ) {
|
|
39465
|
-
const nl = remainder.indexOf(`
|
|
39466
|
-
`);
|
|
39467
|
-
if (nl < 0)
|
|
39468
|
-
break;
|
|
39469
|
-
const line = remainder.slice(0, nl);
|
|
39470
|
-
remainder = remainder.slice(nl + 1);
|
|
39471
|
-
if (line.trim()) {
|
|
39472
|
-
const activity = parseAcpxJsonLine(line, state);
|
|
39473
|
-
if (activity && onActivity)
|
|
39474
|
-
onActivity(activity);
|
|
39475
|
-
}
|
|
39476
|
-
}
|
|
39477
|
-
if (Buffer.byteLength(remainder, "utf8") > MAX_BUFFERED_LINE_BYTES) {
|
|
39478
|
-
getSafeLogger2()?.error("acp-adapter", "Dropping oversized buffered stdout line (exceeds cap)", {
|
|
39479
|
-
bufferedBytes: Buffer.byteLength(remainder, "utf8"),
|
|
39480
|
-
maxBufferedLineBytes: MAX_BUFFERED_LINE_BYTES
|
|
39481
|
-
});
|
|
39482
|
-
remainder = "";
|
|
39483
|
-
}
|
|
39484
|
-
}
|
|
39485
|
-
remainder += decoder.decode();
|
|
39486
|
-
if (remainder.trim()) {
|
|
39487
|
-
const activity = parseAcpxJsonLine(remainder.trim(), state);
|
|
39488
|
-
if (activity && onActivity)
|
|
39489
|
-
onActivity(activity);
|
|
39490
|
-
}
|
|
39491
|
-
} finally {
|
|
39492
|
-
reader.releaseLock();
|
|
39493
|
-
}
|
|
39494
|
-
})();
|
|
39495
|
-
return {
|
|
39496
|
-
promise: promise2,
|
|
39497
|
-
cancel: () => {
|
|
39498
|
-
reader.cancel().catch(() => {});
|
|
39499
|
-
}
|
|
39500
|
-
};
|
|
39501
|
-
}
|
|
39502
|
-
var MAX_BUFFERED_LINE_BYTES, MAX_BUFFERED_STDERR_BYTES;
|
|
39503
|
-
var init_stdout_line_reader = __esm(() => {
|
|
39504
|
-
init_logger2();
|
|
39505
|
-
init_parser();
|
|
39506
|
-
MAX_BUFFERED_LINE_BYTES = 10 * 1024 * 1024;
|
|
39507
|
-
MAX_BUFFERED_STDERR_BYTES = 64 * 1024;
|
|
39508
|
-
});
|
|
39509
|
-
|
|
39510
|
-
// src/agents/acp/spawn-client-session.ts
|
|
39511
|
-
var exports_spawn_client_session = {};
|
|
39512
|
-
__export(exports_spawn_client_session, {
|
|
39513
|
-
SpawnAcpSession: () => SpawnAcpSession
|
|
39514
|
-
});
|
|
39515
|
-
import { randomUUID as randomUUID8 } from "crypto";
|
|
39516
|
-
|
|
39517
|
-
class SpawnAcpSession {
|
|
39518
|
-
agentName;
|
|
39519
|
-
sessionName;
|
|
39520
|
-
cwd;
|
|
39521
|
-
model;
|
|
39522
|
-
modelLabel;
|
|
39523
|
-
timeoutSeconds;
|
|
39524
|
-
promptRetries;
|
|
39525
|
-
permissionMode;
|
|
39526
|
-
env;
|
|
39527
|
-
onPidSpawned;
|
|
39528
|
-
onPidExited;
|
|
39529
|
-
onStreamActivity;
|
|
39530
|
-
onActiveCall;
|
|
39531
|
-
runId;
|
|
39532
|
-
storyId;
|
|
39533
|
-
stage;
|
|
39534
|
-
trackedSpawnDeadlineMs;
|
|
39535
|
-
activeProc = null;
|
|
39536
|
-
_externallyCancelled = false;
|
|
39537
|
-
id;
|
|
39538
|
-
recordId;
|
|
39539
|
-
constructor(opts) {
|
|
39540
|
-
this.agentName = opts.agentName;
|
|
39541
|
-
this.sessionName = opts.sessionName;
|
|
39542
|
-
this.cwd = opts.cwd;
|
|
39543
|
-
this.model = opts.model;
|
|
39544
|
-
this.modelLabel = opts.modelLabel ?? opts.model;
|
|
39545
|
-
this.timeoutSeconds = opts.timeoutSeconds;
|
|
39546
|
-
this.promptRetries = opts.promptRetries;
|
|
39547
|
-
this.permissionMode = opts.permissionMode;
|
|
39548
|
-
this.env = opts.env;
|
|
39549
|
-
this.onPidSpawned = opts.onPidSpawned;
|
|
39550
|
-
this.onPidExited = opts.onPidExited;
|
|
39551
|
-
this.onStreamActivity = opts.onStreamActivity;
|
|
39552
|
-
this.onActiveCall = opts.onActiveCall;
|
|
39553
|
-
this.runId = opts.runId ?? "";
|
|
39554
|
-
this.storyId = opts.storyId;
|
|
39555
|
-
this.stage = opts.stage;
|
|
39556
|
-
this.id = opts.id;
|
|
39557
|
-
this.recordId = opts.recordId;
|
|
39558
|
-
this.trackedSpawnDeadlineMs = opts.trackedSpawnDeadlineMs ?? _spawnClientDeps.trackedSpawnDeadlineMs;
|
|
39559
|
-
}
|
|
39560
|
-
async prompt(text) {
|
|
39561
|
-
const callId = randomUUID8();
|
|
39562
|
-
const emit = this.onStreamActivity;
|
|
39563
|
-
const now = () => Date.now();
|
|
39564
|
-
this._externallyCancelled = false;
|
|
39565
|
-
const baseEvent = {
|
|
39566
|
-
callId,
|
|
39567
|
-
runId: this.runId,
|
|
39568
|
-
agentName: this.agentName,
|
|
39569
|
-
sessionName: this.sessionName,
|
|
39570
|
-
storyId: this.storyId,
|
|
39571
|
-
stage: this.stage
|
|
39572
|
-
};
|
|
39573
|
-
const cmd = [
|
|
39574
|
-
"acpx",
|
|
39575
|
-
"--cwd",
|
|
39576
|
-
this.cwd,
|
|
39577
|
-
"--format",
|
|
39578
|
-
"json",
|
|
39579
|
-
...this.permissionMode === "approve-all" ? ["--approve-all"] : [],
|
|
39580
|
-
"--model",
|
|
39581
|
-
this.model,
|
|
39582
|
-
"--timeout",
|
|
39583
|
-
String(this.timeoutSeconds),
|
|
39584
|
-
...this.promptRetries > 0 ? ["--prompt-retries", String(this.promptRetries)] : [],
|
|
39585
|
-
this.agentName,
|
|
39586
|
-
"prompt",
|
|
39587
|
-
"-s",
|
|
39588
|
-
this.sessionName,
|
|
39589
|
-
"--file",
|
|
39590
|
-
"-"
|
|
39591
|
-
];
|
|
39592
|
-
getSafeLogger2()?.info("acp-adapter", "Sending prompt", {
|
|
39593
|
-
session: this.sessionName,
|
|
39594
|
-
permission: this.permissionMode,
|
|
39595
|
-
cmd: cmd.join(" ")
|
|
39596
|
-
});
|
|
39597
|
-
getSafeLogger2()?.debug("acp-adapter", `Sending prompt to session: ${this.sessionName}`);
|
|
39598
|
-
let proc;
|
|
39599
|
-
try {
|
|
39600
|
-
proc = _spawnClientDeps.spawn(cmd, {
|
|
39601
|
-
cwd: this.cwd,
|
|
39602
|
-
stdin: "pipe",
|
|
39603
|
-
stdout: "pipe",
|
|
39604
|
-
stderr: "pipe",
|
|
39605
|
-
env: this.env,
|
|
39606
|
-
detached: true
|
|
39607
|
-
});
|
|
39608
|
-
} catch (spawnErr) {
|
|
39609
|
-
emit?.({ ...baseEvent, kind: "agent.call_ended", status: "error", timestamp: now() });
|
|
39610
|
-
throw spawnErr;
|
|
39611
|
-
}
|
|
39612
|
-
this.activeProc = proc;
|
|
39613
|
-
const processPid = proc.pid;
|
|
39614
|
-
this.onPidSpawned?.(processPid);
|
|
39615
|
-
this.onActiveCall?.(callId, () => this.cancelActivePrompt());
|
|
39616
|
-
emit?.({
|
|
39617
|
-
...baseEvent,
|
|
39618
|
-
kind: "agent.call_started",
|
|
39619
|
-
model: this.modelLabel,
|
|
39620
|
-
timeoutSeconds: this.timeoutSeconds,
|
|
39621
|
-
timestamp: now()
|
|
39622
|
-
});
|
|
39623
|
-
emit?.({
|
|
39624
|
-
...baseEvent,
|
|
39625
|
-
kind: "agent.process_update",
|
|
39626
|
-
status: "spawned",
|
|
39627
|
-
pid: processPid,
|
|
39628
|
-
timestamp: now()
|
|
39629
|
-
});
|
|
39630
|
-
let exitNotified = false;
|
|
39631
|
-
const notifyExit = () => {
|
|
39632
|
-
if (exitNotified)
|
|
39633
|
-
return;
|
|
39634
|
-
exitNotified = true;
|
|
39635
|
-
try {
|
|
39636
|
-
this.onPidExited?.(processPid);
|
|
39637
|
-
} catch {}
|
|
39638
|
-
};
|
|
39639
|
-
let callEndedEmitted = false;
|
|
39640
|
-
try {
|
|
39641
|
-
try {
|
|
39642
|
-
proc.stdin?.write(text);
|
|
39643
|
-
proc.stdin?.end();
|
|
39644
|
-
} catch {
|
|
39645
|
-
getSafeLogger2()?.warn("acp-adapter", "Failed to write prompt to acpx stdin (subprocess exited early)", {
|
|
39646
|
-
session: this.sessionName
|
|
39647
|
-
});
|
|
39648
|
-
}
|
|
39649
|
-
const parseState = createParseState();
|
|
39650
|
-
const onActivity = emit ? (activity) => {
|
|
39651
|
-
if (activity.kind === "message_update") {
|
|
39652
|
-
emit({ ...baseEvent, kind: "agent.message_update", deltaBytes: activity.deltaBytes, timestamp: now() });
|
|
39653
|
-
} else if (activity.kind === "thinking_update") {
|
|
39654
|
-
emit({ ...baseEvent, kind: "agent.thinking_update", deltaBytes: activity.deltaBytes, timestamp: now() });
|
|
39655
|
-
} else if (activity.kind === "usage_update") {
|
|
39656
|
-
emit({
|
|
39657
|
-
...baseEvent,
|
|
39658
|
-
kind: "agent.usage_update",
|
|
39659
|
-
inputTokens: activity.inputTokens,
|
|
39660
|
-
outputTokens: activity.outputTokens,
|
|
39661
|
-
costUsd: activity.costUsd,
|
|
39662
|
-
...activity.cacheRead !== undefined ? { cacheRead: activity.cacheRead } : {},
|
|
39663
|
-
...activity.cacheWrite !== undefined ? { cacheWrite: activity.cacheWrite } : {},
|
|
39664
|
-
cadence: "agent",
|
|
39665
|
-
timestamp: now()
|
|
39666
|
-
});
|
|
39667
|
-
} else if (activity.kind === "tool_call_update") {
|
|
39668
|
-
emit({
|
|
39669
|
-
...baseEvent,
|
|
39670
|
-
kind: "agent.tool_call_update",
|
|
39671
|
-
toolName: activity.toolName,
|
|
39672
|
-
timestamp: now()
|
|
39673
|
-
});
|
|
39674
|
-
}
|
|
39675
|
-
} : undefined;
|
|
39676
|
-
const parseHandle = readAndParseLines(proc.stdout, parseState, onActivity);
|
|
39677
|
-
const parsePromise = parseHandle.promise.catch(() => {});
|
|
39678
|
-
const stderrHandle = readStreamTail(proc.stderr);
|
|
39679
|
-
const stderrPromise = stderrHandle.promise.catch(() => "");
|
|
39680
|
-
const exitCode = await proc.exited;
|
|
39681
|
-
const drainA = makeStreamDrain(_spawnClientDeps.streamDrainTimeoutMs);
|
|
39682
|
-
const drainB = makeStreamDrain(_spawnClientDeps.streamDrainTimeoutMs);
|
|
39683
|
-
const stdoutRaceResult = Promise.race([
|
|
39684
|
-
parsePromise.then(() => "parsed"),
|
|
39685
|
-
drainA.promise.then(() => "drain")
|
|
39686
|
-
]).finally(() => drainA.cancel());
|
|
39687
|
-
const [stdoutWinner, stderr] = await Promise.all([
|
|
39688
|
-
stdoutRaceResult,
|
|
39689
|
-
Promise.race([stderrPromise, drainB.promise]).finally(() => drainB.cancel())
|
|
39690
|
-
]);
|
|
39691
|
-
if (stdoutWinner === "drain")
|
|
39692
|
-
parseHandle.cancel();
|
|
39693
|
-
if (stderr === "")
|
|
39694
|
-
stderrHandle.cancel();
|
|
39695
|
-
emit?.({ ...baseEvent, kind: "agent.process_update", status: "exited", exitCode, timestamp: now() });
|
|
39696
|
-
if (exitCode !== 0) {
|
|
39697
|
-
const parsedOnError = finalizeParseState(parseState);
|
|
39698
|
-
const errorContent = parsedOnError.error || stderr || `Exit code ${exitCode}`;
|
|
39699
|
-
getSafeLogger2()?.warn("acp-adapter", `Session prompt exited with code ${exitCode}`, {
|
|
39700
|
-
exitCode,
|
|
39701
|
-
error: errorContent.slice(0, 500),
|
|
39702
|
-
...stderr && stderr !== errorContent ? { banner: stderr.trim().slice(0, 200) } : {}
|
|
39703
|
-
});
|
|
39704
|
-
callEndedEmitted = true;
|
|
39705
|
-
emit?.({ ...baseEvent, kind: "agent.call_ended", status: "error", exitCode, timestamp: now() });
|
|
39706
|
-
const errResponse = {
|
|
39707
|
-
messages: [{ role: "assistant", content: errorContent }],
|
|
39708
|
-
stopReason: "error",
|
|
39709
|
-
retryable: parsedOnError.retryable,
|
|
39710
|
-
exitCode
|
|
39711
|
-
};
|
|
39712
|
-
if (this._externallyCancelled)
|
|
39713
|
-
errResponse.cancelled = true;
|
|
39714
|
-
return errResponse;
|
|
39715
|
-
}
|
|
39716
|
-
try {
|
|
39717
|
-
const parsed = finalizeParseState(parseState);
|
|
39718
|
-
callEndedEmitted = true;
|
|
39719
|
-
const cancelled = this._externallyCancelled;
|
|
39720
|
-
emit?.({ ...baseEvent, kind: "agent.call_ended", status: cancelled ? "error" : "success", timestamp: now() });
|
|
39721
|
-
const successResponse = {
|
|
39722
|
-
messages: [{ role: "assistant", content: parsed.text || "" }],
|
|
39723
|
-
stopReason: cancelled ? "error" : parsed.stopReason ?? "end_turn",
|
|
39724
|
-
cumulative_token_usage: parsed.tokenUsage,
|
|
39725
|
-
exactCostUsd: parsed.exactCostUsd,
|
|
39726
|
-
error: parsed.error,
|
|
39727
|
-
retryable: parsed.retryable
|
|
39728
|
-
};
|
|
39729
|
-
if (cancelled)
|
|
39730
|
-
successResponse.cancelled = true;
|
|
39731
|
-
return successResponse;
|
|
39732
|
-
} catch (err) {
|
|
39733
|
-
getSafeLogger2()?.warn("acp-adapter", "Failed to parse session prompt response", {
|
|
39734
|
-
stderr: stderr.slice(0, 200)
|
|
39735
|
-
});
|
|
39736
|
-
throw err;
|
|
39737
|
-
}
|
|
39738
|
-
} catch (err) {
|
|
39739
|
-
if (!callEndedEmitted) {
|
|
39740
|
-
callEndedEmitted = true;
|
|
39741
|
-
emit?.({ ...baseEvent, kind: "agent.call_ended", status: "error", timestamp: now() });
|
|
39742
|
-
}
|
|
39743
|
-
throw err;
|
|
39744
|
-
} finally {
|
|
39745
|
-
this.activeProc = null;
|
|
39746
|
-
notifyExit();
|
|
39747
|
-
}
|
|
39748
|
-
}
|
|
39749
|
-
async trackedSpawn(cmd, opts, signal) {
|
|
39750
|
-
return runTrackedSpawn({ ..._spawnClientDeps, trackedSpawnDeadlineMs: this.trackedSpawnDeadlineMs }, cmd, opts, this.onPidSpawned, this.onPidExited, signal);
|
|
39751
|
-
}
|
|
39752
|
-
killActiveProcTree() {
|
|
39753
|
-
if (!this.activeProc)
|
|
39754
|
-
return;
|
|
39755
|
-
killProcessTree(this.activeProc.pid, _spawnClientDeps.killTreeGraceMs, this.activeProc.exited);
|
|
39756
|
-
}
|
|
39757
|
-
async close(options) {
|
|
39758
|
-
if (this.activeProc) {
|
|
39759
|
-
this.killActiveProcTree();
|
|
39760
|
-
this.activeProc = null;
|
|
39761
|
-
}
|
|
39762
|
-
const cmd = ["acpx", "--cwd", this.cwd, this.agentName, "sessions", "close", this.sessionName];
|
|
39763
|
-
getSafeLogger2()?.debug("acp-adapter", `Closing session: ${this.sessionName}`);
|
|
39764
|
-
const { exitCode, stderr } = await this.trackedSpawn(cmd, undefined, options?.signal);
|
|
39765
|
-
if (exitCode !== 0) {
|
|
39766
|
-
getSafeLogger2()?.warn("acp-adapter", "Failed to close session", {
|
|
39767
|
-
sessionName: this.sessionName,
|
|
39768
|
-
stderr: stderr.slice(0, 200)
|
|
39769
|
-
});
|
|
39770
|
-
}
|
|
39771
|
-
if (options?.forceTerminate) {
|
|
39772
|
-
try {
|
|
39773
|
-
await this.trackedSpawn(["acpx", "--cwd", this.cwd, this.agentName, "stop"], undefined, options?.signal);
|
|
39774
|
-
} catch (err) {
|
|
39775
|
-
getSafeLogger2()?.debug("acp-adapter", "acpx stop failed (swallowed)", { cause: String(err) });
|
|
39776
|
-
}
|
|
39777
|
-
}
|
|
39778
|
-
}
|
|
39779
|
-
async cancelActivePrompt() {
|
|
39780
|
-
this._externallyCancelled = true;
|
|
39781
|
-
if (this.activeProc) {
|
|
39782
|
-
this.killActiveProcTree();
|
|
39783
|
-
this.activeProc = null;
|
|
39784
|
-
}
|
|
39785
|
-
const cmd = ["acpx", "--cwd", this.cwd, this.agentName, "cancel"];
|
|
39786
|
-
getSafeLogger2()?.debug("acp-adapter", `Cancelling active prompt: ${this.sessionName}`);
|
|
39787
|
-
await this.trackedSpawn(cmd);
|
|
39788
|
-
}
|
|
39789
|
-
}
|
|
39790
|
-
var init_spawn_client_session = __esm(() => {
|
|
39791
|
-
init_agents();
|
|
39792
|
-
init_logger2();
|
|
39793
|
-
init_spawn_client_deps();
|
|
39794
|
-
init_spawn_client_process();
|
|
39795
|
-
init_stdout_line_reader();
|
|
39796
|
-
});
|
|
39797
|
-
|
|
39798
|
-
// src/agents/acp/spawn-client.ts
|
|
39799
|
-
class SpawnAcpClient {
|
|
39800
|
-
model;
|
|
39801
|
-
rawModel;
|
|
39802
|
-
reasoningEffort;
|
|
39803
|
-
cwd;
|
|
39804
|
-
timeoutSeconds;
|
|
39805
|
-
promptRetries;
|
|
39806
|
-
env;
|
|
39807
|
-
onPidSpawned;
|
|
39808
|
-
onPidExited;
|
|
39809
|
-
onStreamActivity;
|
|
39810
|
-
onActiveCall;
|
|
39811
|
-
runId;
|
|
39812
|
-
storyId;
|
|
39813
|
-
stage;
|
|
39814
|
-
trackedSpawnDeadlineMs;
|
|
39815
|
-
trackedSpawnStartupDeadlineMs;
|
|
39816
|
-
constructor(cmdStr, cwd, timeoutSeconds, onPidSpawned, promptRetries, onPidExited, opts) {
|
|
39817
|
-
const parts = cmdStr.split(/\s+/);
|
|
39818
|
-
const modelIdx = parts.indexOf("--model");
|
|
39819
|
-
const rawModel = modelIdx >= 0 && parts[modelIdx + 1] ? parts[modelIdx + 1] : "default";
|
|
39820
|
-
const spec = parseModelSpec(rawModel);
|
|
39821
|
-
this.rawModel = rawModel;
|
|
39822
|
-
this.model = spec.model;
|
|
39823
|
-
this.reasoningEffort = spec.effort;
|
|
39824
|
-
const lastToken = parts[parts.length - 1];
|
|
39825
|
-
if (!lastToken || lastToken.startsWith("-")) {
|
|
39826
|
-
throw new NaxError(`[acp-adapter] Could not parse agentName from cmdStr: "${cmdStr}"`, "ACP_AGENT_NAME_PARSE_FAILED", {
|
|
39827
|
-
stage: "session",
|
|
39828
|
-
cmdStr
|
|
39829
|
-
});
|
|
39830
|
-
}
|
|
39831
|
-
if (!cwd) {
|
|
39832
|
-
throw new NaxError("[acp-adapter] SpawnAcpClient requires cwd", "ACP_CWD_REQUIRED", { stage: "session" });
|
|
39833
|
-
}
|
|
39834
|
-
this.cwd = cwd;
|
|
39835
|
-
this.timeoutSeconds = timeoutSeconds ?? DEFAULT_ACP_TIMEOUT_SECONDS;
|
|
39836
|
-
this.promptRetries = promptRetries ?? 0;
|
|
39837
|
-
this.env = buildAllowedEnv({ modelEnv: opts?.env });
|
|
39838
|
-
this.onPidSpawned = onPidSpawned;
|
|
39839
|
-
this.onPidExited = onPidExited;
|
|
39840
|
-
this.onStreamActivity = opts?.onStreamActivity;
|
|
39841
|
-
this.onActiveCall = opts?.onActiveCall;
|
|
39842
|
-
this.runId = opts?.runId;
|
|
39843
|
-
this.storyId = opts?.storyId;
|
|
39844
|
-
this.stage = opts?.stage;
|
|
39845
|
-
this.trackedSpawnDeadlineMs = opts?.trackedSpawnDeadlineMs ?? _spawnClientDeps.trackedSpawnDeadlineMs;
|
|
39846
|
-
this.trackedSpawnStartupDeadlineMs = opts?.trackedSpawnStartupDeadlineMs ?? _spawnClientDeps.trackedSpawnStartupDeadlineMs;
|
|
39847
|
-
}
|
|
39848
|
-
async start() {}
|
|
39849
|
-
async trackedSpawn(cmd, signal, deadlineMsOverride) {
|
|
39850
|
-
return runTrackedSpawn({ ..._spawnClientDeps, trackedSpawnDeadlineMs: deadlineMsOverride ?? this.trackedSpawnStartupDeadlineMs }, cmd, undefined, this.onPidSpawned, this.onPidExited, signal);
|
|
39851
|
-
}
|
|
39852
|
-
async createSession(opts) {
|
|
39853
|
-
const sessionName = opts.sessionName || `nax-${Date.now()}`;
|
|
39854
|
-
const cmd = [
|
|
39855
|
-
"acpx",
|
|
39856
|
-
"--cwd",
|
|
39857
|
-
this.cwd,
|
|
39858
|
-
"--format",
|
|
39859
|
-
"json",
|
|
39860
|
-
opts.agentName,
|
|
39861
|
-
"sessions",
|
|
39862
|
-
"ensure",
|
|
39863
|
-
"--name",
|
|
39864
|
-
sessionName
|
|
39865
|
-
];
|
|
39866
|
-
getSafeLogger2()?.debug("acp-adapter", `Ensuring session: ${sessionName}`);
|
|
39867
|
-
const { exitCode, stdout, stderr } = await this.trackedSpawn(cmd);
|
|
39868
|
-
if (exitCode !== 0) {
|
|
39869
|
-
throw new NaxError(`[acp-adapter] Failed to create session: ${stdout || stderr || `exit code ${exitCode}`}`, "ACP_SESSION_CREATE_FAILED", { stage: "session", agentName: opts.agentName, exitCode });
|
|
39870
|
-
}
|
|
39871
|
-
const { sessionId, recordId } = parseSessionIds(stdout);
|
|
39872
|
-
await applyReasoningEffort({
|
|
39873
|
-
effort: this.reasoningEffort,
|
|
39874
|
-
agentName: opts.agentName,
|
|
39875
|
-
sessionName,
|
|
39876
|
-
cwd: this.cwd,
|
|
39877
|
-
storyId: this.storyId,
|
|
39878
|
-
spawn: (c) => this.trackedSpawn(c)
|
|
39879
|
-
});
|
|
39880
|
-
const { SpawnAcpSession: SpawnAcpSession2 } = await Promise.resolve().then(() => (init_spawn_client_session(), exports_spawn_client_session));
|
|
39881
|
-
return new SpawnAcpSession2({
|
|
39882
|
-
agentName: opts.agentName,
|
|
39883
|
-
sessionName,
|
|
39884
|
-
cwd: this.cwd,
|
|
39885
|
-
model: this.model,
|
|
39886
|
-
modelLabel: this.rawModel,
|
|
39887
|
-
timeoutSeconds: this.timeoutSeconds,
|
|
39888
|
-
promptRetries: this.promptRetries,
|
|
39889
|
-
permissionMode: opts.permissionMode,
|
|
39890
|
-
env: this.env,
|
|
39891
|
-
onPidSpawned: this.onPidSpawned,
|
|
39892
|
-
onPidExited: this.onPidExited,
|
|
39893
|
-
onStreamActivity: this.onStreamActivity,
|
|
39894
|
-
onActiveCall: this.onActiveCall,
|
|
39895
|
-
runId: this.runId,
|
|
39896
|
-
storyId: this.storyId,
|
|
39897
|
-
stage: this.stage,
|
|
39898
|
-
id: sessionId,
|
|
39899
|
-
recordId,
|
|
39900
|
-
trackedSpawnDeadlineMs: this.trackedSpawnDeadlineMs
|
|
39901
|
-
});
|
|
39902
|
-
}
|
|
39903
|
-
async loadSession(sessionName, agentName, permissionMode) {
|
|
39904
|
-
const cmd = ["acpx", "--cwd", this.cwd, "--format", "json", agentName, "sessions", "ensure", "--name", sessionName];
|
|
39905
|
-
const { exitCode, stdout } = await this.trackedSpawn(cmd);
|
|
39906
|
-
if (exitCode !== 0) {
|
|
39907
|
-
if (exitCode === -1) {
|
|
39908
|
-
getSafeLogger2()?.warn("acp-adapter", "sessions ensure hit its trackedSpawn deadline \u2014 falling back to a context-less session", { sessionName, agentName });
|
|
39909
|
-
}
|
|
39910
|
-
return null;
|
|
39911
|
-
}
|
|
39912
|
-
const { sessionId, recordId } = parseSessionIds(stdout);
|
|
39913
|
-
await applyReasoningEffort({
|
|
39914
|
-
effort: this.reasoningEffort,
|
|
39915
|
-
agentName,
|
|
39916
|
-
sessionName,
|
|
39917
|
-
cwd: this.cwd,
|
|
39918
|
-
storyId: this.storyId,
|
|
39919
|
-
spawn: (c) => this.trackedSpawn(c)
|
|
39920
|
-
});
|
|
39921
|
-
const { SpawnAcpSession: SpawnAcpSession2 } = await Promise.resolve().then(() => (init_spawn_client_session(), exports_spawn_client_session));
|
|
39922
|
-
return new SpawnAcpSession2({
|
|
39923
|
-
agentName,
|
|
39924
|
-
sessionName,
|
|
39925
|
-
cwd: this.cwd,
|
|
39926
|
-
model: this.model,
|
|
39927
|
-
modelLabel: this.rawModel,
|
|
39928
|
-
timeoutSeconds: this.timeoutSeconds,
|
|
39929
|
-
promptRetries: this.promptRetries,
|
|
39930
|
-
permissionMode,
|
|
39931
|
-
env: this.env,
|
|
39932
|
-
onPidSpawned: this.onPidSpawned,
|
|
39933
|
-
onPidExited: this.onPidExited,
|
|
39934
|
-
onStreamActivity: this.onStreamActivity,
|
|
39935
|
-
onActiveCall: this.onActiveCall,
|
|
39936
|
-
runId: this.runId,
|
|
39937
|
-
storyId: this.storyId,
|
|
39938
|
-
stage: this.stage,
|
|
39939
|
-
id: sessionId,
|
|
39940
|
-
recordId,
|
|
39941
|
-
trackedSpawnDeadlineMs: this.trackedSpawnDeadlineMs
|
|
39942
|
-
});
|
|
39943
|
-
}
|
|
39944
|
-
async closeSession(sessionName, agentName, signal) {
|
|
39945
|
-
const cmd = ["acpx", "--cwd", this.cwd, agentName, "sessions", "close", sessionName];
|
|
39946
|
-
const { exitCode, stderr } = await this.trackedSpawn(cmd, signal, this.trackedSpawnDeadlineMs);
|
|
39947
|
-
if (exitCode !== 0) {
|
|
39948
|
-
getSafeLogger2()?.debug("acp-adapter", "Session close failed (ignored)", {
|
|
39949
|
-
sessionName,
|
|
39950
|
-
agentName,
|
|
39951
|
-
exitCode,
|
|
39952
|
-
stderr: stderr.slice(0, 200)
|
|
39953
|
-
});
|
|
39954
|
-
}
|
|
39955
|
-
}
|
|
39956
|
-
async forceStop(agentName, signal) {
|
|
39957
|
-
const cmd = ["acpx", "--cwd", this.cwd, agentName, "stop"];
|
|
39958
|
-
const { exitCode, stderr } = await this.trackedSpawn(cmd, signal, this.trackedSpawnDeadlineMs);
|
|
39959
|
-
if (exitCode !== 0) {
|
|
39960
|
-
getSafeLogger2()?.debug("acp-adapter", "forceStop failed (ignored)", {
|
|
39961
|
-
agentName,
|
|
39962
|
-
exitCode,
|
|
39963
|
-
stderr: stderr.slice(0, 200)
|
|
39964
|
-
});
|
|
39965
|
-
}
|
|
39966
|
-
}
|
|
39967
|
-
async close() {}
|
|
39968
|
-
}
|
|
39969
|
-
function createSpawnAcpClient(cmdStr, cwd, timeoutSeconds, onPidSpawned, promptRetries, onPidExited, opts) {
|
|
39970
|
-
return new SpawnAcpClient(cmdStr, cwd, timeoutSeconds, onPidSpawned, promptRetries, onPidExited, opts);
|
|
39971
|
-
}
|
|
39972
|
-
var DEFAULT_ACP_TIMEOUT_SECONDS = 1800;
|
|
39973
|
-
var init_spawn_client = __esm(() => {
|
|
39974
|
-
init_src();
|
|
39975
|
-
init_errors4();
|
|
39976
|
-
init_logger2();
|
|
39977
|
-
init_env();
|
|
39978
|
-
init_reasoning_effort();
|
|
39979
|
-
init_spawn_client_deps();
|
|
39980
|
-
init_spawn_client_process();
|
|
39981
|
-
init_spawn_client_deps();
|
|
39982
|
-
});
|
|
39983
|
-
|
|
39984
|
-
// src/agents/acp/adapter-lifecycle.ts
|
|
39985
|
-
async function ensureAcpSession(client2, sessionName, agentName, permissionMode) {
|
|
39986
|
-
if (!agentName) {
|
|
39987
|
-
throw new NaxError("[acp-adapter] agentName is required for ensureAcpSession", "ACP_AGENT_NAME_REQUIRED", {
|
|
39988
|
-
stage: "open-session",
|
|
39989
|
-
sessionName
|
|
39990
|
-
});
|
|
39991
|
-
}
|
|
39992
|
-
if (client2.cwd && !await _acpAdapterDeps.cwdExists(client2.cwd)) {
|
|
39993
|
-
throw new NaxError(`[acp-adapter] Session cwd does not exist: ${client2.cwd} \u2014 cannot start agent "${agentName}". If this is a new package for the feature, ensure its directory is created before the run.`, "SESSION_CWD_MISSING", { stage: "open-session", agentName, cwd: client2.cwd, sessionName });
|
|
39994
|
-
}
|
|
39995
|
-
if (client2.loadSession) {
|
|
39996
|
-
try {
|
|
39997
|
-
const existing2 = await client2.loadSession(sessionName, agentName, permissionMode);
|
|
39998
|
-
if (existing2) {
|
|
39999
|
-
getSafeLogger2()?.debug("acp-adapter", `Resumed existing session: ${sessionName}`);
|
|
40000
|
-
return { session: existing2, resumed: true };
|
|
40001
|
-
}
|
|
40002
|
-
} catch {}
|
|
40003
|
-
}
|
|
40004
|
-
getSafeLogger2()?.debug("acp-adapter", `Creating new session: ${sessionName}`);
|
|
40005
|
-
return { session: await client2.createSession({ agentName, permissionMode, sessionName }), resumed: false };
|
|
40006
|
-
}
|
|
40007
|
-
async function runSessionPrompt(session2, prompt, timeoutMs, signal) {
|
|
40008
|
-
throwIfAborted(signal, "Run aborted \u2014 shutdown in progress");
|
|
40009
|
-
const promptPromise = session2.prompt(prompt);
|
|
40010
|
-
let timeoutId;
|
|
40011
|
-
const timeoutPromise = new Promise((resolve21) => {
|
|
40012
|
-
timeoutId = setTimeout(() => resolve21("timeout"), timeoutMs);
|
|
40013
|
-
});
|
|
40014
|
-
let abortHandler;
|
|
40015
|
-
const abortPromise = signal ? new Promise((resolve21) => {
|
|
40016
|
-
abortHandler = () => resolve21("aborted");
|
|
40017
|
-
signal.addEventListener("abort", abortHandler, { once: true });
|
|
40018
|
-
}) : null;
|
|
40019
|
-
let winner;
|
|
40020
|
-
try {
|
|
40021
|
-
winner = await Promise.race([promptPromise, timeoutPromise, ...abortPromise !== null ? [abortPromise] : []]);
|
|
40022
|
-
} finally {
|
|
40023
|
-
clearTimeout(timeoutId);
|
|
40024
|
-
if (signal && abortHandler) {
|
|
40025
|
-
signal.removeEventListener("abort", abortHandler);
|
|
40026
|
-
}
|
|
40027
|
-
}
|
|
40028
|
-
if (winner === "timeout" || winner === "aborted") {
|
|
40029
|
-
promptPromise.catch(() => {});
|
|
40030
|
-
try {
|
|
40031
|
-
await session2.cancelActivePrompt();
|
|
40032
|
-
} catch {
|
|
40033
|
-
await session2.close().catch(() => {});
|
|
40034
|
-
}
|
|
40035
|
-
return { response: null, timedOut: winner === "timeout", aborted: winner === "aborted" };
|
|
40036
|
-
}
|
|
40037
|
-
return { response: winner, timedOut: false, aborted: false };
|
|
40038
|
-
}
|
|
40039
|
-
async function closeAcpSession(session2) {
|
|
40040
|
-
try {
|
|
40041
|
-
await session2.close();
|
|
40042
|
-
} catch (err) {
|
|
40043
|
-
getSafeLogger2()?.warn("acp-adapter", "Failed to close session", { error: String(err) });
|
|
40044
|
-
}
|
|
40045
|
-
}
|
|
40046
|
-
|
|
40047
|
-
class AcpSessionHandleImpl {
|
|
40048
|
-
id;
|
|
40049
|
-
agentName;
|
|
40050
|
-
protocolIds;
|
|
40051
|
-
modelDef;
|
|
40052
|
-
modelTier;
|
|
40053
|
-
_client;
|
|
40054
|
-
_session;
|
|
40055
|
-
_sessionName;
|
|
40056
|
-
_resumed;
|
|
40057
|
-
_timeoutSeconds;
|
|
40058
|
-
_modelDef;
|
|
40059
|
-
_rateCard;
|
|
40060
|
-
_permissionMode;
|
|
40061
|
-
constructor(opts) {
|
|
40062
|
-
this.id = opts.id;
|
|
40063
|
-
this.agentName = opts.agentName;
|
|
40064
|
-
this.protocolIds = opts.protocolIds;
|
|
40065
|
-
this._client = opts.client;
|
|
40066
|
-
this._session = opts.session;
|
|
40067
|
-
this._sessionName = opts.sessionName;
|
|
40068
|
-
this._resumed = opts.resumed;
|
|
40069
|
-
this._timeoutSeconds = opts.timeoutSeconds;
|
|
40070
|
-
this._modelDef = opts.modelDef;
|
|
40071
|
-
this.modelDef = opts.modelDef;
|
|
40072
|
-
this.modelTier = opts.modelTier;
|
|
40073
|
-
this._rateCard = opts.rateCard;
|
|
40074
|
-
this._permissionMode = opts.permissionMode;
|
|
40075
|
-
}
|
|
40076
|
-
}
|
|
40077
|
-
var _acpAdapterDeps, _fallbackDeps;
|
|
40078
|
-
var init_adapter_lifecycle = __esm(() => {
|
|
40079
|
-
init_cost();
|
|
40080
|
-
init_errors4();
|
|
40081
|
-
init_logger2();
|
|
40082
|
-
init_bun_deps();
|
|
40083
|
-
init_errors5();
|
|
40084
|
-
init_turn();
|
|
40085
|
-
init_spawn_client();
|
|
40086
|
-
_acpAdapterDeps = {
|
|
40087
|
-
which: which2,
|
|
40088
|
-
sleep,
|
|
40089
|
-
async cwdExists(dir) {
|
|
40090
|
-
const { stat: stat7 } = await import("fs/promises");
|
|
40091
|
-
try {
|
|
40092
|
-
return (await stat7(dir)).isDirectory();
|
|
40093
|
-
} catch {
|
|
40094
|
-
return false;
|
|
40095
|
-
}
|
|
40096
|
-
},
|
|
40097
|
-
createClient(cmdStr, cwd, timeoutSeconds, onPidSpawned, promptRetries, onPidExited, opts) {
|
|
40098
|
-
return createSpawnAcpClient(cmdStr, cwd, timeoutSeconds, onPidSpawned, promptRetries, onPidExited, opts);
|
|
40099
|
-
},
|
|
40100
|
-
resolveRateCard(modelId) {
|
|
40101
|
-
return resolveRateCard(modelId);
|
|
40102
|
-
}
|
|
40103
|
-
};
|
|
40104
|
-
_fallbackDeps = {
|
|
40105
|
-
parseAgentError,
|
|
40106
|
-
sleep
|
|
40107
|
-
};
|
|
40108
|
-
});
|
|
40109
|
-
|
|
40110
|
-
// src/agents/acp/adapter-close-physical.ts
|
|
40111
|
-
async function closePhysicalSession(agentName, handle, workdir, options) {
|
|
40112
|
-
const cmdStr = `acpx ${agentName}`;
|
|
40113
|
-
const client2 = _acpAdapterDeps.createClient(cmdStr, workdir, undefined, undefined);
|
|
40114
|
-
try {
|
|
40115
|
-
await client2.start();
|
|
40116
|
-
try {
|
|
40117
|
-
if (client2.closeSession) {
|
|
40118
|
-
await client2.closeSession(handle, agentName, options?.signal);
|
|
40119
|
-
if (options?.force) {
|
|
40120
|
-
await client2.forceStop?.(agentName, options?.signal).catch(() => {});
|
|
40121
|
-
}
|
|
40122
|
-
} else if (client2.loadSession) {
|
|
40123
|
-
const session2 = await client2.loadSession(handle, agentName, SESSION_CLOSE_PERMISSION_MODE);
|
|
40124
|
-
if (session2)
|
|
40125
|
-
await session2.close({ forceTerminate: options?.force, signal: options?.signal }).catch(() => {});
|
|
40126
|
-
}
|
|
40127
|
-
} catch (err) {
|
|
40128
|
-
getSafeLogger2()?.warn("acp-adapter", `[close] Failed to close session ${handle}`, { error: String(err) });
|
|
40129
|
-
}
|
|
40130
|
-
} finally {
|
|
40131
|
-
await client2.close().catch(() => {});
|
|
40132
|
-
}
|
|
40133
|
-
}
|
|
40134
|
-
var init_adapter_close_physical = __esm(() => {
|
|
40135
|
-
init_config();
|
|
40136
|
-
init_logger2();
|
|
40137
|
-
init_adapter_lifecycle();
|
|
40138
|
-
});
|
|
40139
|
-
|
|
40140
|
-
// src/agents/session-naming.ts
|
|
40141
|
-
import { createHash as createHash6 } from "crypto";
|
|
40142
|
-
function computeAcpHandle(workdir, featureName, storyId, sessionRole) {
|
|
40143
|
-
const hash2 = createHash6("sha256").update(workdir).digest("hex").slice(0, 8);
|
|
40144
|
-
const sanitize = (s) => s.replace(/[^a-z0-9]+/gi, "-").toLowerCase().replace(/^-+|-+$/g, "");
|
|
40145
|
-
const parts = ["nax", hash2];
|
|
40146
|
-
if (featureName)
|
|
40147
|
-
parts.push(sanitize(featureName));
|
|
40148
|
-
if (storyId)
|
|
40149
|
-
parts.push(sanitize(storyId));
|
|
40150
|
-
if (sessionRole)
|
|
40151
|
-
parts.push(sanitize(sessionRole));
|
|
40152
|
-
return parts.join("-");
|
|
40153
|
-
}
|
|
40154
|
-
var init_session_naming = () => {};
|
|
40155
|
-
|
|
40156
|
-
// src/agents/types.ts
|
|
40157
|
-
var CompleteError, SessionFailureError;
|
|
40158
|
-
var init_types4 = __esm(() => {
|
|
40159
|
-
init_src();
|
|
40160
|
-
CompleteError = class CompleteError extends Error {
|
|
40161
|
-
exitCode;
|
|
40162
|
-
retryable;
|
|
40163
|
-
constructor(message, exitCode, retryable) {
|
|
40164
|
-
super(message);
|
|
40165
|
-
this.exitCode = exitCode;
|
|
40166
|
-
this.retryable = retryable;
|
|
40167
|
-
this.name = "CompleteError";
|
|
40168
|
-
}
|
|
40169
|
-
};
|
|
40170
|
-
SessionFailureError = class SessionFailureError extends Error {
|
|
40171
|
-
adapterFailure;
|
|
40172
|
-
constructor(message, adapterFailure) {
|
|
40173
|
-
super(message);
|
|
40174
|
-
this.adapterFailure = adapterFailure;
|
|
40175
|
-
this.name = "SessionFailureError";
|
|
40176
|
-
}
|
|
40177
|
-
};
|
|
40178
|
-
});
|
|
40179
|
-
|
|
40180
|
-
// src/agents/acp/adapter-output.ts
|
|
40181
|
-
function extractOutput(response) {
|
|
40182
|
-
if (!response)
|
|
40183
|
-
return "";
|
|
40184
|
-
return response.messages.filter((m) => m.role === "assistant").map((m) => m.content).join(`
|
|
40185
|
-
`).trim();
|
|
40186
|
-
}
|
|
40187
|
-
function deriveTokenUsage(wire, rateCard, mapper) {
|
|
40188
|
-
const tokenUsage = wire ? mapper.toInternal(wire) : { inputTokens: 0, outputTokens: 0 };
|
|
40189
|
-
const nonzeroUsage = tokenUsage.inputTokens > 0 || tokenUsage.outputTokens > 0;
|
|
40190
|
-
const priced = nonzeroUsage ? priceCall(tokenUsage, rateCard.rates) : undefined;
|
|
40191
|
-
return {
|
|
40192
|
-
tokenUsage,
|
|
40193
|
-
estimatedCostUsd: priced?.costUsd ?? 0,
|
|
40194
|
-
rates: priced?.resolvedRates
|
|
40195
|
-
};
|
|
38791
|
+
// src/utils/bun-deps.ts
|
|
38792
|
+
function typedSpawn(cmd, opts) {
|
|
38793
|
+
return Bun.spawn(cmd, opts);
|
|
40196
38794
|
}
|
|
40197
|
-
function
|
|
40198
|
-
|
|
40199
|
-
return assembleTurnResult({ ...rest, output: extractOutput(lastResponse) });
|
|
38795
|
+
function sleep(ms) {
|
|
38796
|
+
return Bun.sleep(ms);
|
|
40200
38797
|
}
|
|
40201
|
-
|
|
40202
|
-
|
|
40203
|
-
|
|
40204
|
-
|
|
40205
|
-
|
|
40206
|
-
// src/agents/acp/adapter-complete-flow.ts
|
|
40207
|
-
async function runCompleteFlow(input) {
|
|
40208
|
-
const { adapter, prompt, options, mapper, rateCard, createClient: createClient2 } = input;
|
|
40209
|
-
const tryOneAgent = async (agentName) => {
|
|
40210
|
-
const cmdStr = `acpx --model ${options.modelDef.model} ${agentName}`;
|
|
40211
|
-
const timeoutMs = options.timeoutMs ?? 120000;
|
|
40212
|
-
const timeoutSeconds = Math.ceil(timeoutMs / 1000);
|
|
40213
|
-
const client2 = createClient2(cmdStr, options.workdir, timeoutSeconds, options.onPidSpawned, options.promptRetries, options.onPidExited, {
|
|
40214
|
-
onStreamActivity: options.onStreamActivity,
|
|
40215
|
-
onActiveCall: options.onActiveCall,
|
|
40216
|
-
trackedSpawnDeadlineMs: options.trackedSpawnDeadlineMs,
|
|
40217
|
-
trackedSpawnStartupDeadlineMs: options.trackedSpawnStartupDeadlineMs,
|
|
40218
|
-
env: options.modelDef.env
|
|
40219
|
-
});
|
|
40220
|
-
await client2.start();
|
|
40221
|
-
let session2 = null;
|
|
40222
|
-
try {
|
|
40223
|
-
const completeSessionName = options.sessionName ?? computeAcpHandle(options.workdir, options.featureName, options.storyId, options.sessionRole);
|
|
40224
|
-
session2 = await client2.createSession({
|
|
40225
|
-
agentName,
|
|
40226
|
-
permissionMode: options.resolvedPermissions.mode,
|
|
40227
|
-
sessionName: completeSessionName
|
|
40228
|
-
});
|
|
40229
|
-
let timeoutId;
|
|
40230
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
40231
|
-
timeoutId = setTimeout(() => reject(new NaxError("complete() timed out", "AGENT_TIMEOUT", { stage: "acp", timeoutMs })), timeoutMs);
|
|
40232
|
-
});
|
|
40233
|
-
timeoutPromise.catch(() => {});
|
|
40234
|
-
let response;
|
|
40235
|
-
try {
|
|
40236
|
-
const promptPromise = session2.prompt(prompt);
|
|
40237
|
-
promptPromise.catch(() => {});
|
|
40238
|
-
response = await Promise.race([promptPromise, timeoutPromise]);
|
|
40239
|
-
} finally {
|
|
40240
|
-
clearTimeout(timeoutId);
|
|
40241
|
-
}
|
|
40242
|
-
if (response.stopReason === "error") {
|
|
40243
|
-
if (response.cancelled) {
|
|
40244
|
-
const { tokenUsage: tokenUsage2, estimatedCostUsd: estimatedCostUsd2, rates: rates2 } = deriveTokenUsage(response.cumulative_token_usage, rateCard, mapper);
|
|
40245
|
-
return {
|
|
40246
|
-
output: "",
|
|
40247
|
-
tokenUsage: tokenUsage2,
|
|
40248
|
-
estimatedCostUsd: estimatedCostUsd2,
|
|
40249
|
-
exactCostUsd: response.exactCostUsd,
|
|
40250
|
-
cancelled: true,
|
|
40251
|
-
pricingSource: rateCard.source,
|
|
40252
|
-
...rates2 !== undefined ? { rates: rates2 } : {}
|
|
40253
|
-
};
|
|
40254
|
-
}
|
|
40255
|
-
const errSuffix = response.error ? `: ${response.error.slice(0, 500)}` : "";
|
|
40256
|
-
throw new CompleteError(`complete() failed: stop reason is error${errSuffix}`, undefined, response.retryable);
|
|
40257
|
-
}
|
|
40258
|
-
const text = response.messages.filter((m) => m.role === "assistant").map((m) => m.content).join(`
|
|
40259
|
-
`).trim();
|
|
40260
|
-
let unwrapped = text;
|
|
40261
|
-
try {
|
|
40262
|
-
const envelope = JSON.parse(text);
|
|
40263
|
-
if (envelope?.type === "result" && typeof envelope?.result === "string") {
|
|
40264
|
-
unwrapped = envelope.result;
|
|
40265
|
-
}
|
|
40266
|
-
} catch {}
|
|
40267
|
-
if (!unwrapped) {
|
|
40268
|
-
throw new CompleteError("complete() returned empty output");
|
|
40269
|
-
}
|
|
40270
|
-
const { tokenUsage, estimatedCostUsd, rates } = deriveTokenUsage(response.cumulative_token_usage, rateCard, mapper);
|
|
40271
|
-
const exactCostUsd = response.exactCostUsd;
|
|
40272
|
-
if (exactCostUsd !== undefined) {
|
|
40273
|
-
getSafeLogger2()?.info("acp-adapter", "complete() cost", {
|
|
40274
|
-
costUsd: exactCostUsd,
|
|
40275
|
-
model: options.modelDef.model
|
|
40276
|
-
});
|
|
40277
|
-
}
|
|
40278
|
-
return {
|
|
40279
|
-
output: unwrapped,
|
|
40280
|
-
tokenUsage,
|
|
40281
|
-
estimatedCostUsd,
|
|
40282
|
-
exactCostUsd,
|
|
40283
|
-
pricingSource: rateCard.source,
|
|
40284
|
-
...rates !== undefined ? { rates } : {}
|
|
40285
|
-
};
|
|
40286
|
-
} finally {
|
|
40287
|
-
if (session2) {
|
|
40288
|
-
await session2.close({ forceTerminate: true }).catch(() => {});
|
|
40289
|
-
}
|
|
40290
|
-
await client2.close().catch(() => {});
|
|
40291
|
-
}
|
|
40292
|
-
};
|
|
40293
|
-
try {
|
|
40294
|
-
return await tryOneAgent(adapter.name);
|
|
40295
|
-
} catch (err) {
|
|
40296
|
-
const error48 = err instanceof Error ? err : new Error(String(err));
|
|
40297
|
-
if (error48 instanceof CompleteError) {
|
|
40298
|
-
const classified = classifyCompleteError(error48, rateCard.source);
|
|
40299
|
-
if (classified)
|
|
40300
|
-
return classified;
|
|
38798
|
+
function cancellableDelay(ms, signal) {
|
|
38799
|
+
return new Promise((resolve21, reject) => {
|
|
38800
|
+
if (signal?.aborted) {
|
|
38801
|
+
reject(signal.reason ?? new Error("delay aborted"));
|
|
38802
|
+
return;
|
|
40301
38803
|
}
|
|
40302
|
-
const
|
|
40303
|
-
|
|
40304
|
-
|
|
40305
|
-
|
|
40306
|
-
|
|
40307
|
-
|
|
40308
|
-
|
|
40309
|
-
init_errors4();
|
|
40310
|
-
init_logger2();
|
|
40311
|
-
init_errors5();
|
|
40312
|
-
init_session_naming();
|
|
40313
|
-
init_types4();
|
|
40314
|
-
init_adapter_lifecycle();
|
|
40315
|
-
init_adapter_output();
|
|
40316
|
-
});
|
|
40317
|
-
|
|
40318
|
-
// src/agents/interaction/output-parsing.ts
|
|
40319
|
-
function extractQuestion(output) {
|
|
40320
|
-
const text = output.trim();
|
|
40321
|
-
if (!text)
|
|
40322
|
-
return null;
|
|
40323
|
-
const lines = text.split(`
|
|
40324
|
-
`).filter((l) => l.trim().length > 0);
|
|
40325
|
-
const lastLine = lines.at(-1)?.trim() ?? "";
|
|
40326
|
-
const lower = lastLine.toLowerCase();
|
|
40327
|
-
const markers = [
|
|
40328
|
-
"please confirm",
|
|
40329
|
-
"please specify",
|
|
40330
|
-
"please provide",
|
|
40331
|
-
"which would you",
|
|
40332
|
-
"should i ",
|
|
40333
|
-
"do you want",
|
|
40334
|
-
"can you clarify"
|
|
40335
|
-
];
|
|
40336
|
-
const isQuestion = lastLine.endsWith("?") && lastLine.length > 10 || markers.some((m) => lower.includes(m));
|
|
40337
|
-
if (!isQuestion)
|
|
40338
|
-
return null;
|
|
40339
|
-
const paragraphs = text.split(/\n\n+/);
|
|
40340
|
-
const questionPara = paragraphs.at(-1)?.trim() ?? lastLine;
|
|
40341
|
-
const contextPara = paragraphs.at(-2)?.trim();
|
|
40342
|
-
return contextPara ? `${contextPara}
|
|
40343
|
-
|
|
40344
|
-
${questionPara}` : questionPara;
|
|
40345
|
-
}
|
|
40346
|
-
function extractContextToolCall(output) {
|
|
40347
|
-
const match = output.match(CONTEXT_TOOL_CALL_PATTERN);
|
|
40348
|
-
if (!match)
|
|
40349
|
-
return null;
|
|
40350
|
-
const [, name, rawInput] = match;
|
|
40351
|
-
const trimmedInput = rawInput.trim();
|
|
40352
|
-
if (!trimmedInput) {
|
|
40353
|
-
return { name, input: {} };
|
|
40354
|
-
}
|
|
40355
|
-
try {
|
|
40356
|
-
return { name, input: JSON.parse(trimmedInput) };
|
|
40357
|
-
} catch (error48) {
|
|
40358
|
-
return {
|
|
40359
|
-
name,
|
|
40360
|
-
error: `Invalid JSON tool input: ${error48 instanceof Error ? error48.message : String(error48)}`
|
|
38804
|
+
const timer = setTimeout(() => {
|
|
38805
|
+
signal?.removeEventListener("abort", onAbort);
|
|
38806
|
+
resolve21();
|
|
38807
|
+
}, ms);
|
|
38808
|
+
const onAbort = () => {
|
|
38809
|
+
clearTimeout(timer);
|
|
38810
|
+
reject(signal?.reason ?? new Error("delay aborted"));
|
|
40361
38811
|
};
|
|
40362
|
-
|
|
40363
|
-
}
|
|
40364
|
-
var CONTEXT_TOOL_CALL_PATTERN;
|
|
40365
|
-
var init_output_parsing = __esm(() => {
|
|
40366
|
-
CONTEXT_TOOL_CALL_PATTERN = /<nax_tool_call\s+name="([^"]+)">\s*([\s\S]*?)\s*<\/nax_tool_call>/i;
|
|
40367
|
-
});
|
|
40368
|
-
|
|
40369
|
-
// src/agents/interaction/turn-interactions.ts
|
|
40370
|
-
async function awaitInteractionReply(ctx, interaction, warnSuffix) {
|
|
40371
|
-
let timeoutId;
|
|
40372
|
-
try {
|
|
40373
|
-
const response = await Promise.race([
|
|
40374
|
-
raceWithAbort(ctx.interactionHandler.onInteraction(interaction), ctx.signal, INTERACTION_ABORT_MESSAGE),
|
|
40375
|
-
new Promise((resolve21) => {
|
|
40376
|
-
timeoutId = setTimeout(() => resolve21(null), ctx.timeoutMs ?? INTERACTION_TIMEOUT_MS);
|
|
40377
|
-
})
|
|
40378
|
-
]);
|
|
40379
|
-
if (response) {
|
|
40380
|
-
return { kind: "answered", answer: response.answer };
|
|
40381
|
-
}
|
|
40382
|
-
} catch (err) {
|
|
40383
|
-
if (ctx.signal?.aborted) {
|
|
40384
|
-
return { kind: "aborted" };
|
|
40385
|
-
}
|
|
40386
|
-
getSafeLogger2()?.warn(ctx.stage, `InteractionHandler.onInteraction failed${warnSuffix}${err instanceof Error ? err.message : String(err)}`);
|
|
40387
|
-
} finally {
|
|
40388
|
-
clearTimeout(timeoutId);
|
|
40389
|
-
}
|
|
40390
|
-
return { kind: "no-reply" };
|
|
40391
|
-
}
|
|
40392
|
-
function toContextToolInteraction(toolCall) {
|
|
40393
|
-
return toolCall.error ? { kind: "context-tool", name: toolCall.name, error: toolCall.error } : { kind: "context-tool", name: toolCall.name, input: toolCall.input };
|
|
40394
|
-
}
|
|
40395
|
-
var INTERACTION_TIMEOUT_MS, INTERACTION_ABORT_MESSAGE = "Run aborted \u2014 shutdown in progress";
|
|
40396
|
-
var init_turn_interactions = __esm(() => {
|
|
40397
|
-
init_logger2();
|
|
40398
|
-
init_turn();
|
|
40399
|
-
INTERACTION_TIMEOUT_MS = 5 * 60 * 1000;
|
|
40400
|
-
});
|
|
40401
|
-
|
|
40402
|
-
// src/agents/interaction/index.ts
|
|
40403
|
-
var init_interaction = __esm(() => {
|
|
40404
|
-
init_output_parsing();
|
|
40405
|
-
init_turn_interactions();
|
|
40406
|
-
});
|
|
40407
|
-
|
|
40408
|
-
// src/agents/acp/adapter-send-turn.ts
|
|
40409
|
-
function buildSendTurnFrame(input) {
|
|
40410
|
-
const { impl, mapper, opts } = input;
|
|
40411
|
-
const { _sessionName: sessionName, _timeoutSeconds: timeoutSeconds, _rateCard: rateCard } = impl;
|
|
40412
|
-
return {
|
|
40413
|
-
impl,
|
|
40414
|
-
mapper,
|
|
40415
|
-
opts,
|
|
40416
|
-
sessionName,
|
|
40417
|
-
timeoutSeconds,
|
|
40418
|
-
rateCard,
|
|
40419
|
-
maxInteractions: opts.maxInteractions ?? DEFAULT_MAX_INTERACTIONS,
|
|
40420
|
-
turnDeadline: createTurnDeadline(timeoutSeconds)
|
|
40421
|
-
};
|
|
40422
|
-
}
|
|
40423
|
-
function initialSendTurnState(prompt) {
|
|
40424
|
-
return {
|
|
40425
|
-
sessionRecreated: false,
|
|
40426
|
-
totalTokenUsage: { inputTokens: 0, outputTokens: 0 },
|
|
40427
|
-
totalExactCostUsd: undefined,
|
|
40428
|
-
interactions: [],
|
|
40429
|
-
turnCount: 0,
|
|
40430
|
-
lastResponse: null,
|
|
40431
|
-
timedOut: false,
|
|
40432
|
-
aborted: false,
|
|
40433
|
-
currentPrompt: prompt
|
|
40434
|
-
};
|
|
40435
|
-
}
|
|
40436
|
-
function zeroCostAbortedResult(frame) {
|
|
40437
|
-
return {
|
|
40438
|
-
output: "",
|
|
40439
|
-
tokenUsage: { inputTokens: 0, outputTokens: 0 },
|
|
40440
|
-
estimatedCostUsd: 0,
|
|
40441
|
-
internalRoundTrips: 0,
|
|
40442
|
-
pricingSource: frame.rateCard.source
|
|
40443
|
-
};
|
|
40444
|
-
}
|
|
40445
|
-
async function beginTurnIteration(frame, state) {
|
|
40446
|
-
if (frame.turnDeadline.expired()) {
|
|
40447
|
-
state.timedOut = true;
|
|
40448
|
-
warnWallClockTimeout(frame.sessionName, frame.timeoutSeconds, "acp-adapter");
|
|
40449
|
-
return { kind: "break" };
|
|
40450
|
-
}
|
|
40451
|
-
state.turnCount++;
|
|
40452
|
-
getSafeLogger2()?.debug("acp-adapter", `Session turn ${state.turnCount}/${frame.maxInteractions}`, {
|
|
40453
|
-
sessionName: frame.sessionName
|
|
40454
|
-
});
|
|
40455
|
-
const turnResult = await runSessionPrompt(frame.impl._session, state.currentPrompt, frame.turnDeadline.remainingMs() ?? 0, frame.opts.signal);
|
|
40456
|
-
if (turnResult.timedOut) {
|
|
40457
|
-
state.timedOut = true;
|
|
40458
|
-
warnWallClockTimeout(frame.sessionName, frame.timeoutSeconds, "acp-adapter");
|
|
40459
|
-
return { kind: "break" };
|
|
40460
|
-
}
|
|
40461
|
-
if (turnResult.aborted) {
|
|
40462
|
-
state.aborted = true;
|
|
40463
|
-
return { kind: "break" };
|
|
40464
|
-
}
|
|
40465
|
-
state.lastResponse = turnResult.response;
|
|
40466
|
-
if (!state.lastResponse)
|
|
40467
|
-
return { kind: "break" };
|
|
40468
|
-
return { kind: "response", response: state.lastResponse };
|
|
40469
|
-
}
|
|
40470
|
-
async function recoverNoSession(frame, state) {
|
|
40471
|
-
if (state.lastResponse?.exitCode !== 4 || state.sessionRecreated) {
|
|
40472
|
-
return false;
|
|
40473
|
-
}
|
|
40474
|
-
state.sessionRecreated = true;
|
|
40475
|
-
getSafeLogger2()?.info("acp-adapter", "NO_SESSION detected \u2014 re-establishing session", {
|
|
40476
|
-
sessionName: frame.sessionName
|
|
40477
|
-
});
|
|
40478
|
-
try {
|
|
40479
|
-
const ensured = await ensureAcpSession(frame.impl._client, frame.impl._sessionName, frame.impl.agentName, frame.impl._permissionMode);
|
|
40480
|
-
frame.impl._session = ensured.session;
|
|
40481
|
-
state.turnCount--;
|
|
40482
|
-
return true;
|
|
40483
|
-
} catch (err) {
|
|
40484
|
-
getSafeLogger2()?.warn("acp-adapter", "Session re-establishment failed after NO_SESSION", {
|
|
40485
|
-
sessionName: frame.sessionName,
|
|
40486
|
-
error: err instanceof Error ? err.message : String(err)
|
|
40487
|
-
});
|
|
40488
|
-
return false;
|
|
40489
|
-
}
|
|
40490
|
-
}
|
|
40491
|
-
function accumulateUsage(frame, state, response) {
|
|
40492
|
-
if (response.cumulative_token_usage) {
|
|
40493
|
-
state.totalTokenUsage = addTokenUsage(state.totalTokenUsage, frame.mapper.toInternal(response.cumulative_token_usage));
|
|
40494
|
-
}
|
|
40495
|
-
if (response.exactCostUsd !== undefined) {
|
|
40496
|
-
state.totalExactCostUsd = (state.totalExactCostUsd ?? 0) + response.exactCostUsd;
|
|
40497
|
-
}
|
|
40498
|
-
}
|
|
40499
|
-
function replyContext(frame) {
|
|
40500
|
-
return { interactionHandler: frame.opts.interactionHandler, signal: frame.opts.signal, stage: "acp-adapter" };
|
|
40501
|
-
}
|
|
40502
|
-
async function handleContextToolCall(frame, state, toolCall) {
|
|
40503
|
-
const interaction = toContextToolInteraction(toolCall);
|
|
40504
|
-
const reply = await awaitInteractionReply(replyContext(frame), interaction, " for context-tool: ");
|
|
40505
|
-
if (reply.kind === "answered") {
|
|
40506
|
-
state.currentPrompt = reply.answer;
|
|
40507
|
-
return true;
|
|
40508
|
-
}
|
|
40509
|
-
if (reply.kind === "aborted") {
|
|
40510
|
-
state.aborted = true;
|
|
40511
|
-
}
|
|
40512
|
-
return false;
|
|
40513
|
-
}
|
|
40514
|
-
async function handleQuestion(frame, state, question) {
|
|
40515
|
-
const reply = await awaitInteractionReply(replyContext(frame), { kind: "question", text: question }, ": ");
|
|
40516
|
-
if (reply.kind === "answered") {
|
|
40517
|
-
state.interactions.push({ turnIndex: state.turnCount, question, reply: reply.answer });
|
|
40518
|
-
state.currentPrompt = reply.answer;
|
|
40519
|
-
return true;
|
|
40520
|
-
}
|
|
40521
|
-
if (reply.kind === "aborted") {
|
|
40522
|
-
state.aborted = true;
|
|
40523
|
-
}
|
|
40524
|
-
return false;
|
|
40525
|
-
}
|
|
40526
|
-
async function processResponseInteractions(frame, state, response) {
|
|
40527
|
-
const outputText = extractOutput(response);
|
|
40528
|
-
const isEndTurn = response.stopReason === "end_turn";
|
|
40529
|
-
if (isEndTurn) {
|
|
40530
|
-
const toolCall = extractContextToolCall(outputText);
|
|
40531
|
-
if (toolCall) {
|
|
40532
|
-
return await handleContextToolCall(frame, state, toolCall) ? "continue" : "break";
|
|
40533
|
-
}
|
|
40534
|
-
const question = extractQuestion(outputText);
|
|
40535
|
-
if (question) {
|
|
40536
|
-
return await handleQuestion(frame, state, question) ? "continue" : "break";
|
|
40537
|
-
}
|
|
40538
|
-
}
|
|
40539
|
-
return "break";
|
|
40540
|
-
}
|
|
40541
|
-
function maybeWarnBudgetSpent(frame, state) {
|
|
40542
|
-
if (state.turnCount >= frame.maxInteractions && !state.timedOut && !state.aborted && frame.maxInteractions > 1) {
|
|
40543
|
-
getSafeLogger2()?.warn("acp-adapter", "Interaction budget spent", {
|
|
40544
|
-
sessionName: frame.sessionName,
|
|
40545
|
-
maxInteractions: frame.maxInteractions
|
|
40546
|
-
});
|
|
40547
|
-
}
|
|
40548
|
-
}
|
|
40549
|
-
function throwIfTurnFailed(frame, state) {
|
|
40550
|
-
const lastResponse = state.lastResponse;
|
|
40551
|
-
if (lastResponse?.stopReason !== "error") {
|
|
40552
|
-
return;
|
|
40553
|
-
}
|
|
40554
|
-
const hasUsage = state.totalTokenUsage.inputTokens > 0 || state.totalTokenUsage.outputTokens > 0;
|
|
40555
|
-
throw new SessionTurnError(lastResponse.cancelled ? "Agent session ended with stop reason: error (externally cancelled)" : "Agent session ended with stop reason: error", lastResponse.cancelled === true, lastResponse.retryable === true, state.totalTokenUsage, hasUsage ? estimateCostUsd(state.totalTokenUsage, frame.rateCard.rates) : 0, state.totalExactCostUsd, frame.rateCard.source);
|
|
40556
|
-
}
|
|
40557
|
-
async function runTurnLoop(frame, state) {
|
|
40558
|
-
while (state.turnCount < frame.maxInteractions) {
|
|
40559
|
-
const began = await beginTurnIteration(frame, state);
|
|
40560
|
-
if (began.kind === "break")
|
|
40561
|
-
break;
|
|
40562
|
-
if (await recoverNoSession(frame, state))
|
|
40563
|
-
continue;
|
|
40564
|
-
accumulateUsage(frame, state, began.response);
|
|
40565
|
-
if (await processResponseInteractions(frame, state, began.response) === "break")
|
|
40566
|
-
break;
|
|
40567
|
-
}
|
|
40568
|
-
maybeWarnBudgetSpent(frame, state);
|
|
40569
|
-
throwIfTurnFailed(frame, state);
|
|
40570
|
-
return buildTurnResult2({
|
|
40571
|
-
lastResponse: state.lastResponse,
|
|
40572
|
-
totalTokenUsage: state.totalTokenUsage,
|
|
40573
|
-
totalExactCostUsd: state.totalExactCostUsd,
|
|
40574
|
-
turnCount: state.turnCount,
|
|
40575
|
-
interactions: state.interactions,
|
|
40576
|
-
timedOut: state.timedOut,
|
|
40577
|
-
rateCard: frame.rateCard
|
|
38812
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
40578
38813
|
});
|
|
40579
38814
|
}
|
|
40580
|
-
var
|
|
40581
|
-
var
|
|
40582
|
-
|
|
40583
|
-
init_logger2();
|
|
40584
|
-
init_cost();
|
|
40585
|
-
init_interaction();
|
|
40586
|
-
init_turn();
|
|
40587
|
-
init_types4();
|
|
40588
|
-
init_adapter_lifecycle();
|
|
40589
|
-
init_adapter_output();
|
|
40590
|
-
});
|
|
40591
|
-
|
|
40592
|
-
// src/agents/acp/agent-entries.ts
|
|
40593
|
-
function resolveRegistryEntry(agentName) {
|
|
40594
|
-
return AGENT_REGISTRY[agentName] ?? DEFAULT_ENTRY;
|
|
40595
|
-
}
|
|
40596
|
-
var AGENT_REGISTRY, DEFAULT_ENTRY, ACP_ADAPTER_NAMES;
|
|
40597
|
-
var init_agent_entries = __esm(() => {
|
|
40598
|
-
AGENT_REGISTRY = {
|
|
40599
|
-
claude: {
|
|
40600
|
-
binary: "claude",
|
|
40601
|
-
displayName: "Claude Code (ACP)",
|
|
40602
|
-
supportedTiers: ["fast", "balanced", "powerful"],
|
|
40603
|
-
maxContextTokens: 200000
|
|
40604
|
-
},
|
|
40605
|
-
codex: {
|
|
40606
|
-
binary: "codex",
|
|
40607
|
-
displayName: "OpenAI Codex (ACP)",
|
|
40608
|
-
supportedTiers: ["fast", "balanced"],
|
|
40609
|
-
maxContextTokens: 128000
|
|
40610
|
-
},
|
|
40611
|
-
gemini: {
|
|
40612
|
-
binary: "gemini",
|
|
40613
|
-
displayName: "Gemini CLI (ACP)",
|
|
40614
|
-
supportedTiers: ["fast", "balanced", "powerful"],
|
|
40615
|
-
maxContextTokens: 1e6
|
|
40616
|
-
},
|
|
40617
|
-
opencode: {
|
|
40618
|
-
binary: "opencode",
|
|
40619
|
-
displayName: "opencode (ACP)",
|
|
40620
|
-
supportedTiers: ["fast", "balanced", "powerful"],
|
|
40621
|
-
maxContextTokens: 128000
|
|
40622
|
-
},
|
|
40623
|
-
pi: {
|
|
40624
|
-
binary: "pi",
|
|
40625
|
-
displayName: "Pi Coding Agent (ACP)",
|
|
40626
|
-
supportedTiers: ["fast", "balanced", "powerful"],
|
|
40627
|
-
maxContextTokens: 128000
|
|
40628
|
-
}
|
|
40629
|
-
};
|
|
40630
|
-
DEFAULT_ENTRY = {
|
|
40631
|
-
binary: "claude",
|
|
40632
|
-
displayName: "ACP Agent",
|
|
40633
|
-
supportedTiers: ["balanced"],
|
|
40634
|
-
maxContextTokens: 128000
|
|
40635
|
-
};
|
|
40636
|
-
ACP_ADAPTER_NAMES = new Set(Object.keys(AGENT_REGISTRY));
|
|
40637
|
-
});
|
|
40638
|
-
|
|
40639
|
-
// src/agents/acp/token-mapper.ts
|
|
40640
|
-
function toFiniteTokenCount2(value) {
|
|
40641
|
-
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
40642
|
-
}
|
|
40643
|
-
function toFiniteOrUndefined(value) {
|
|
40644
|
-
if (value === undefined)
|
|
40645
|
-
return;
|
|
40646
|
-
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
40647
|
-
}
|
|
40648
|
-
|
|
40649
|
-
class AcpTokenUsageMapper {
|
|
40650
|
-
toInternal(wire) {
|
|
40651
|
-
return {
|
|
40652
|
-
inputTokens: toFiniteTokenCount2(wire.input_tokens),
|
|
40653
|
-
outputTokens: toFiniteTokenCount2(wire.output_tokens),
|
|
40654
|
-
cacheReadTokens: toFiniteOrUndefined(wire.cache_read_input_tokens),
|
|
40655
|
-
cacheWriteTokens: toFiniteOrUndefined(wire.cache_creation_input_tokens)
|
|
40656
|
-
};
|
|
40657
|
-
}
|
|
40658
|
-
}
|
|
40659
|
-
var defaultAcpTokenUsageMapper;
|
|
40660
|
-
var init_token_mapper = __esm(() => {
|
|
40661
|
-
defaultAcpTokenUsageMapper = new AcpTokenUsageMapper;
|
|
40662
|
-
});
|
|
40663
|
-
|
|
40664
|
-
// src/agents/acp/adapter.ts
|
|
40665
|
-
class AcpAgentAdapter {
|
|
40666
|
-
name;
|
|
40667
|
-
displayName;
|
|
40668
|
-
binary;
|
|
40669
|
-
capabilities;
|
|
40670
|
-
_mapper;
|
|
40671
|
-
constructor(agentName, mapper = defaultAcpTokenUsageMapper) {
|
|
40672
|
-
const entry = resolveRegistryEntry(agentName);
|
|
40673
|
-
this.name = agentName;
|
|
40674
|
-
this.displayName = entry.displayName;
|
|
40675
|
-
this.binary = entry.binary;
|
|
40676
|
-
this._mapper = mapper;
|
|
40677
|
-
this.capabilities = {
|
|
40678
|
-
supportedTiers: entry.supportedTiers,
|
|
40679
|
-
maxContextTokens: entry.maxContextTokens,
|
|
40680
|
-
features: new Set(["tdd", "review", "refactor"])
|
|
40681
|
-
};
|
|
40682
|
-
}
|
|
40683
|
-
async isInstalled() {
|
|
40684
|
-
const path3 = _acpAdapterDeps.which(this.binary);
|
|
40685
|
-
return path3 !== null;
|
|
40686
|
-
}
|
|
40687
|
-
buildCommand(_options) {
|
|
40688
|
-
return ["acpx", this.name, "session"];
|
|
40689
|
-
}
|
|
40690
|
-
buildAllowedEnv(_options) {
|
|
40691
|
-
return {};
|
|
40692
|
-
}
|
|
40693
|
-
async complete(prompt, options) {
|
|
40694
|
-
const rateCard = await _acpAdapterDeps.resolveRateCard(options.modelDef.model);
|
|
40695
|
-
return runCompleteFlow({
|
|
40696
|
-
adapter: this,
|
|
40697
|
-
prompt,
|
|
40698
|
-
options,
|
|
40699
|
-
mapper: this._mapper,
|
|
40700
|
-
rateCard,
|
|
40701
|
-
createClient: _acpAdapterDeps.createClient
|
|
40702
|
-
});
|
|
40703
|
-
}
|
|
40704
|
-
async closePhysicalSession(handle, workdir, options) {
|
|
40705
|
-
return closePhysicalSession(this.name, handle, workdir, options);
|
|
40706
|
-
}
|
|
40707
|
-
async openSession(name, opts) {
|
|
40708
|
-
const {
|
|
40709
|
-
agentName,
|
|
40710
|
-
workdir,
|
|
40711
|
-
resolvedPermissions,
|
|
40712
|
-
modelDef,
|
|
40713
|
-
timeoutSeconds,
|
|
40714
|
-
promptRetries,
|
|
40715
|
-
onSessionEstablished,
|
|
40716
|
-
onPidSpawned,
|
|
40717
|
-
onPidExited
|
|
40718
|
-
} = opts;
|
|
40719
|
-
const { signal } = opts;
|
|
40720
|
-
throwIfAborted(signal, "Run aborted \u2014 shutdown in progress");
|
|
40721
|
-
const rateCard = await _acpAdapterDeps.resolveRateCard(modelDef.model);
|
|
40722
|
-
const cmdStr = `acpx --model ${modelDef.model} ${agentName}`;
|
|
40723
|
-
const client2 = _acpAdapterDeps.createClient(cmdStr, workdir, timeoutSeconds, onPidSpawned, promptRetries, onPidExited, {
|
|
40724
|
-
onStreamActivity: opts.onStreamActivity,
|
|
40725
|
-
onActiveCall: opts.onActiveCall,
|
|
40726
|
-
trackedSpawnDeadlineMs: opts.trackedSpawnDeadlineMs,
|
|
40727
|
-
trackedSpawnStartupDeadlineMs: opts.trackedSpawnStartupDeadlineMs,
|
|
40728
|
-
env: modelDef.env
|
|
40729
|
-
});
|
|
40730
|
-
let session2;
|
|
40731
|
-
try {
|
|
40732
|
-
await raceWithAbort(client2.start(), signal, "Run aborted \u2014 shutdown in progress");
|
|
40733
|
-
const permissionMode = resolvedPermissions.mode;
|
|
40734
|
-
getSafeLogger2()?.info("acp-adapter", "Permission mode resolved", {
|
|
40735
|
-
permission: permissionMode,
|
|
40736
|
-
stage: "open-session"
|
|
40737
|
-
});
|
|
40738
|
-
const ensured = await raceWithAbort(ensureAcpSession(client2, name, agentName, permissionMode), signal, "Run aborted \u2014 shutdown in progress");
|
|
40739
|
-
session2 = ensured.session;
|
|
40740
|
-
const protocolIds = {
|
|
40741
|
-
recordId: session2.recordId ?? null,
|
|
40742
|
-
sessionId: session2.id ?? null
|
|
40743
|
-
};
|
|
40744
|
-
if (onSessionEstablished) {
|
|
40745
|
-
try {
|
|
40746
|
-
onSessionEstablished(protocolIds, name);
|
|
40747
|
-
} catch (err) {
|
|
40748
|
-
getSafeLogger2()?.warn("acp-adapter", "onSessionEstablished callback threw \u2014 continuing", {
|
|
40749
|
-
sessionName: name,
|
|
40750
|
-
error: err instanceof Error ? err.message : String(err)
|
|
40751
|
-
});
|
|
40752
|
-
}
|
|
40753
|
-
}
|
|
40754
|
-
throwIfAborted(signal, "Run aborted \u2014 shutdown in progress");
|
|
40755
|
-
return new AcpSessionHandleImpl({
|
|
40756
|
-
id: name,
|
|
40757
|
-
agentName,
|
|
40758
|
-
protocolIds,
|
|
40759
|
-
client: client2,
|
|
40760
|
-
session: session2,
|
|
40761
|
-
sessionName: name,
|
|
40762
|
-
resumed: ensured.resumed,
|
|
40763
|
-
timeoutSeconds,
|
|
40764
|
-
modelDef,
|
|
40765
|
-
modelTier: opts.modelTier,
|
|
40766
|
-
rateCard,
|
|
40767
|
-
permissionMode: resolvedPermissions.mode
|
|
40768
|
-
});
|
|
40769
|
-
} catch (error48) {
|
|
40770
|
-
if (session2) {
|
|
40771
|
-
await closeAcpSession(session2).catch(() => {});
|
|
40772
|
-
}
|
|
40773
|
-
await client2.close().catch(() => {});
|
|
40774
|
-
throw error48;
|
|
40775
|
-
}
|
|
40776
|
-
}
|
|
40777
|
-
async sendTurn(handle, prompt, opts) {
|
|
40778
|
-
const impl = handle;
|
|
40779
|
-
const frame = buildSendTurnFrame({ impl, mapper: this._mapper, opts });
|
|
40780
|
-
if (frame.opts.signal?.aborted) {
|
|
40781
|
-
return zeroCostAbortedResult(frame);
|
|
40782
|
-
}
|
|
40783
|
-
return runTurnLoop(frame, initialSendTurnState(prompt));
|
|
40784
|
-
}
|
|
40785
|
-
async closeSession(handle) {
|
|
40786
|
-
const impl = handle;
|
|
40787
|
-
try {
|
|
40788
|
-
await closeAcpSession(impl._session);
|
|
40789
|
-
} finally {
|
|
40790
|
-
await impl._client.close().catch(() => {});
|
|
40791
|
-
}
|
|
40792
|
-
}
|
|
40793
|
-
}
|
|
40794
|
-
var init_adapter = __esm(() => {
|
|
40795
|
-
init_logger2();
|
|
40796
|
-
init_turn();
|
|
40797
|
-
init_adapter_close_physical();
|
|
40798
|
-
init_adapter_complete_flow();
|
|
40799
|
-
init_adapter_lifecycle();
|
|
40800
|
-
init_adapter_send_turn();
|
|
40801
|
-
init_agent_entries();
|
|
40802
|
-
init_token_mapper();
|
|
40803
|
-
init_adapter_lifecycle();
|
|
40804
|
-
init_adapter_output();
|
|
40805
|
-
init_agent_entries();
|
|
40806
|
-
});
|
|
40807
|
-
|
|
40808
|
-
// src/agents/acp/index.ts
|
|
40809
|
-
var init_acp = __esm(() => {
|
|
40810
|
-
init_adapter();
|
|
40811
|
-
init_parser();
|
|
40812
|
-
init_spawn_client();
|
|
40813
|
-
init_stdout_line_reader();
|
|
40814
|
-
init_token_mapper();
|
|
40815
|
-
});
|
|
40816
|
-
|
|
40817
|
-
// src/agents/transport-failure-message.ts
|
|
40818
|
-
function isTransportFailureMessage(message) {
|
|
40819
|
-
if (!message)
|
|
40820
|
-
return false;
|
|
40821
|
-
const haystack = message.toLowerCase();
|
|
40822
|
-
return TRANSPORT_FAULT_MARKERS.some((marker) => haystack.includes(marker));
|
|
40823
|
-
}
|
|
40824
|
-
var TRANSPORT_FAULT_MARKERS;
|
|
40825
|
-
var init_transport_failure_message = __esm(() => {
|
|
40826
|
-
TRANSPORT_FAULT_MARKERS = [
|
|
40827
|
-
"idle timeout exceeded",
|
|
40828
|
-
"stream idle timeout",
|
|
40829
|
-
"upstream timeout",
|
|
40830
|
-
"bad gateway",
|
|
40831
|
-
"service unavailable",
|
|
40832
|
-
"gateway timeout",
|
|
40833
|
-
"econnreset",
|
|
40834
|
-
"econnrefused",
|
|
40835
|
-
"econnaborted",
|
|
40836
|
-
"etimedout",
|
|
40837
|
-
"socket hang up",
|
|
40838
|
-
"premature close",
|
|
40839
|
-
"terminated: other side closed",
|
|
40840
|
-
"network error"
|
|
40841
|
-
];
|
|
40842
|
-
});
|
|
40843
|
-
|
|
40844
|
-
// src/agents/complete-exception-classifier.ts
|
|
40845
|
-
function classifyCompleteException(err) {
|
|
40846
|
-
if ((err instanceof SessionTurnError || err instanceof SessionFailureError) && err.adapterFailure !== undefined) {
|
|
40847
|
-
return err.adapterFailure;
|
|
40848
|
-
}
|
|
40849
|
-
const fullMessage = errorMessage(err);
|
|
40850
|
-
const message = fullMessage.slice(0, MAX_FAILURE_MESSAGE_CHARS);
|
|
40851
|
-
if (err instanceof NaxError && err.code === "AGENT_TIMEOUT") {
|
|
40852
|
-
return { category: "quality", outcome: "fail-timeout", retriable: true, message };
|
|
40853
|
-
}
|
|
40854
|
-
const parsed = parseAgentError(fullMessage);
|
|
40855
|
-
switch (parsed.type) {
|
|
40856
|
-
case "auth":
|
|
40857
|
-
return { category: "availability", outcome: "fail-auth", retriable: false, message };
|
|
40858
|
-
case "rate-limit":
|
|
40859
|
-
return {
|
|
40860
|
-
category: "availability",
|
|
40861
|
-
outcome: "fail-rate-limit",
|
|
40862
|
-
retriable: true,
|
|
40863
|
-
message,
|
|
40864
|
-
...parsed.retryAfterSeconds !== undefined ? { retryAfterSeconds: parsed.retryAfterSeconds } : {}
|
|
40865
|
-
};
|
|
40866
|
-
case "model-not-available":
|
|
40867
|
-
return { category: "quality", outcome: "fail-adapter-error", retriable: false, message };
|
|
40868
|
-
case "timeout":
|
|
40869
|
-
return { category: "quality", outcome: "fail-timeout", retriable: true, message };
|
|
40870
|
-
case "crash":
|
|
40871
|
-
return { category: "quality", outcome: "fail-adapter-error", retriable: false, message };
|
|
40872
|
-
default:
|
|
40873
|
-
return isTransportFailureMessage(fullMessage) ? { category: "availability", outcome: "fail-service-down", retriable: true, message } : { category: "quality", outcome: "fail-unknown", retriable: false, message };
|
|
40874
|
-
}
|
|
40875
|
-
}
|
|
40876
|
-
var MAX_FAILURE_MESSAGE_CHARS = 500;
|
|
40877
|
-
var init_complete_exception_classifier = __esm(() => {
|
|
40878
|
-
init_internal();
|
|
40879
|
-
init_errors4();
|
|
40880
|
-
init_errors5();
|
|
40881
|
-
init_transport_failure_message();
|
|
40882
|
-
init_types4();
|
|
38815
|
+
var spawn;
|
|
38816
|
+
var init_bun_deps = __esm(() => {
|
|
38817
|
+
spawn = Bun.spawn;
|
|
40883
38818
|
});
|
|
40884
38819
|
|
|
40885
38820
|
// src/agents/retry/failure-policy.ts
|
|
@@ -43734,14 +41669,14 @@ function analyzeTestExitCode(output, exitCode) {
|
|
|
43734
41669
|
}
|
|
43735
41670
|
return result;
|
|
43736
41671
|
}
|
|
43737
|
-
var
|
|
41672
|
+
var init_parser = __esm(() => {
|
|
43738
41673
|
init_detector2();
|
|
43739
41674
|
init_parse_bun();
|
|
43740
41675
|
init_parse_rust();
|
|
43741
41676
|
});
|
|
43742
41677
|
|
|
43743
41678
|
// src/test-runners/resolver.ts
|
|
43744
|
-
import { dirname as dirname12, isAbsolute as
|
|
41679
|
+
import { dirname as dirname12, isAbsolute as isAbsolute10, join as join31, relative as relative12, resolve as resolve21 } from "path";
|
|
43745
41680
|
function buildResolved(globs, resolution) {
|
|
43746
41681
|
return {
|
|
43747
41682
|
globs,
|
|
@@ -43762,7 +41697,7 @@ function validateGlobs(patterns, stage) {
|
|
|
43762
41697
|
}
|
|
43763
41698
|
}
|
|
43764
41699
|
async function resolveTestFilePatterns(config2, workdir, packageDir, options) {
|
|
43765
|
-
if (packageDir !== undefined &&
|
|
41700
|
+
if (packageDir !== undefined && isAbsolute10(packageDir)) {
|
|
43766
41701
|
throw new NaxError(`resolveTestFilePatterns: packageDir must be relative to workdir, got absolute path "${packageDir}"`, "INVALID_PACKAGE_DIR", { stage: "resolver", workdir, packageDir });
|
|
43767
41702
|
}
|
|
43768
41703
|
if (packageDir) {
|
|
@@ -44464,7 +42399,7 @@ var init_test_runners = __esm(() => {
|
|
|
44464
42399
|
init_detector2();
|
|
44465
42400
|
init_parse_bun();
|
|
44466
42401
|
init_parse_rust();
|
|
44467
|
-
|
|
42402
|
+
init_parser();
|
|
44468
42403
|
init_resolver();
|
|
44469
42404
|
init_scoped_selection();
|
|
44470
42405
|
});
|
|
@@ -44650,7 +42585,7 @@ var init_diff_utils = __esm(() => {
|
|
|
44650
42585
|
|
|
44651
42586
|
// src/utils/path-security.ts
|
|
44652
42587
|
import { realpathSync as realpathSync4 } from "fs";
|
|
44653
|
-
import { dirname as dirname13, isAbsolute as
|
|
42588
|
+
import { dirname as dirname13, isAbsolute as isAbsolute11, join as join34, normalize as normalize3, resolve as resolve22 } from "path";
|
|
44654
42589
|
function safeRealpathForComparison(p) {
|
|
44655
42590
|
try {
|
|
44656
42591
|
return realpathSync4(p);
|
|
@@ -44668,7 +42603,7 @@ function isRelativeAndSafe(filePath2) {
|
|
|
44668
42603
|
if (!isSafeRelativePath(filePath2))
|
|
44669
42604
|
return false;
|
|
44670
42605
|
const normalized = normalize3(filePath2);
|
|
44671
|
-
if (
|
|
42606
|
+
if (isAbsolute11(normalized))
|
|
44672
42607
|
return false;
|
|
44673
42608
|
return true;
|
|
44674
42609
|
}
|
|
@@ -44677,7 +42612,7 @@ function validateModulePath(modulePath, allowedRoots) {
|
|
|
44677
42612
|
return { valid: false, error: "Module path is empty" };
|
|
44678
42613
|
}
|
|
44679
42614
|
const resolvedRoots = allowedRoots.map((r) => safeRealpathForComparison(resolve22(r)));
|
|
44680
|
-
if (
|
|
42615
|
+
if (isAbsolute11(modulePath)) {
|
|
44681
42616
|
const normalized = normalize3(modulePath);
|
|
44682
42617
|
const resolved = safeRealpathForComparison(normalized);
|
|
44683
42618
|
const isWithin3 = resolvedRoots.some((root) => resolved.startsWith(`${root}/`) || resolved === root);
|
|
@@ -46713,7 +44648,7 @@ var init_hermetic = __esm(() => {
|
|
|
46713
44648
|
});
|
|
46714
44649
|
|
|
46715
44650
|
// src/prompts/sections/protocol-region.ts
|
|
46716
|
-
import { randomUUID as
|
|
44651
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
46717
44652
|
function call(tool, input) {
|
|
46718
44653
|
return `${tool} ${JSON.stringify(input)}`;
|
|
46719
44654
|
}
|
|
@@ -46830,7 +44765,7 @@ var KIND_PATTERN, NONCE, PROTOCOL_REGION_MARKER_PREFIX = "<!--nax:", REGION, OWN
|
|
|
46830
44765
|
var init_protocol_region = __esm(() => {
|
|
46831
44766
|
init_errors4();
|
|
46832
44767
|
KIND_PATTERN = /^[a-z][a-z-]*$/;
|
|
46833
|
-
NONCE =
|
|
44768
|
+
NONCE = randomUUID8().slice(0, 8);
|
|
46834
44769
|
REGION = new RegExp(`<!--nax:([a-z][a-z-]*):([a-f0-9]+) (\\{.*?\\})-->\\n` + `((?:(?!<!--nax:[a-z][a-z-]*:[a-f0-9]+ )[\\s\\S])*?)` + `<!--\\/nax:\\1-->\\n?`, "g");
|
|
46835
44770
|
OWN_OPEN = new RegExp(`<!--nax:[a-z][a-z-]*:${NONCE} `, "g");
|
|
46836
44771
|
REGISTRY = {
|
|
@@ -51790,6 +49725,14 @@ function lintForNeutrality(content, fileName) {
|
|
|
51790
49725
|
function estimateTokens3(text) {
|
|
51791
49726
|
return Math.ceil(text.length / 4);
|
|
51792
49727
|
}
|
|
49728
|
+
function handleFrontmatterFailure(err, filePath2, onInvalidFrontmatter, issues, logger) {
|
|
49729
|
+
if (!(err instanceof RulesFrontmatterError))
|
|
49730
|
+
throw err;
|
|
49731
|
+
logger.warn("canonical-loader", onInvalidFrontmatter === "throw" ? "Invalid rule frontmatter \u2014 load will fail" : "Invalid rule frontmatter \u2014 skipping file", { file: filePath2, error: err.message });
|
|
49732
|
+
if (onInvalidFrontmatter === "throw") {
|
|
49733
|
+
issues.push({ file: filePath2, message: err.message });
|
|
49734
|
+
}
|
|
49735
|
+
}
|
|
51793
49736
|
function applyCanonicalRulesBudget(rules, budgetTokens, options = {}) {
|
|
51794
49737
|
const enforce = options.enforce === true;
|
|
51795
49738
|
const totalTokens = rules.reduce((sum, r) => sum + (r.tokens ?? estimateTokens3(r.content)), 0);
|
|
@@ -51848,6 +49791,7 @@ async function loadCanonicalRules(workdir, options = {}) {
|
|
|
51848
49791
|
}
|
|
51849
49792
|
const rules = [];
|
|
51850
49793
|
const allViolations = [];
|
|
49794
|
+
const frontmatterIssues = [];
|
|
51851
49795
|
for (const filePath2 of filePaths) {
|
|
51852
49796
|
const normalizedPath = filePath2.replaceAll("\\", "/");
|
|
51853
49797
|
const normalizedRulesDir = rulesDir.replaceAll("\\", "/");
|
|
@@ -51868,14 +49812,8 @@ async function loadCanonicalRules(workdir, options = {}) {
|
|
|
51868
49812
|
try {
|
|
51869
49813
|
parsed = parseFrontmatter(content, filePath2);
|
|
51870
49814
|
} catch (err) {
|
|
51871
|
-
|
|
51872
|
-
|
|
51873
|
-
file: filePath2,
|
|
51874
|
-
error: err.message
|
|
51875
|
-
});
|
|
51876
|
-
continue;
|
|
51877
|
-
}
|
|
51878
|
-
throw err;
|
|
49815
|
+
handleFrontmatterFailure(err, filePath2, options.onInvalidFrontmatter, frontmatterIssues, logger);
|
|
49816
|
+
continue;
|
|
51879
49817
|
}
|
|
51880
49818
|
if (!parsed.content)
|
|
51881
49819
|
continue;
|
|
@@ -51901,6 +49839,9 @@ async function loadCanonicalRules(workdir, options = {}) {
|
|
|
51901
49839
|
...parsed.warnings.length > 0 && { warnings: parsed.warnings }
|
|
51902
49840
|
});
|
|
51903
49841
|
}
|
|
49842
|
+
if (frontmatterIssues.length > 0) {
|
|
49843
|
+
throw new RulesFrontmatterLintError(frontmatterIssues);
|
|
49844
|
+
}
|
|
51904
49845
|
if (allViolations.length > 0) {
|
|
51905
49846
|
throw new NeutralityLintError(allViolations);
|
|
51906
49847
|
}
|
|
@@ -51936,7 +49877,7 @@ async function loadCanonicalRules(workdir, options = {}) {
|
|
|
51936
49877
|
}
|
|
51937
49878
|
return budgetResult.rules;
|
|
51938
49879
|
}
|
|
51939
|
-
var CANONICAL_RULES_DIR = ".nax/rules", _canonicalLoaderDeps, NEUTRALITY_RULES, DEFAULT_CANONICAL_RULES_BUDGET_TOKENS = 8192, RULES_BUDGET_WARNING_RATIO = 0.75, RULE_ALLOW_MARKER, NeutralityLintError;
|
|
49880
|
+
var CANONICAL_RULES_DIR = ".nax/rules", _canonicalLoaderDeps, NEUTRALITY_RULES, DEFAULT_CANONICAL_RULES_BUDGET_TOKENS = 8192, RULES_BUDGET_WARNING_RATIO = 0.75, RULE_ALLOW_MARKER, NeutralityLintError, RulesFrontmatterLintError;
|
|
51940
49881
|
var init_canonical_loader = __esm(() => {
|
|
51941
49882
|
init_errors4();
|
|
51942
49883
|
init_logger2();
|
|
@@ -52040,6 +49981,19 @@ ${summary}`, "NEUTRALITY_LINT_FAILED", {
|
|
|
52040
49981
|
this.violations = violations;
|
|
52041
49982
|
}
|
|
52042
49983
|
};
|
|
49984
|
+
RulesFrontmatterLintError = class RulesFrontmatterLintError extends NaxError {
|
|
49985
|
+
issues;
|
|
49986
|
+
constructor(issues) {
|
|
49987
|
+
const summary = issues.map((i) => ` ${i.file}: ${i.message}`).join(`
|
|
49988
|
+
`);
|
|
49989
|
+
super(`Canonical rules frontmatter lint failed:
|
|
49990
|
+
${summary}`, "RULES_FRONTMATTER_LINT_FAILED", {
|
|
49991
|
+
stage: "canonical-loader",
|
|
49992
|
+
issueCount: issues.length
|
|
49993
|
+
});
|
|
49994
|
+
this.issues = issues;
|
|
49995
|
+
}
|
|
49996
|
+
};
|
|
52043
49997
|
});
|
|
52044
49998
|
|
|
52045
49999
|
// src/context/engine/agent-profiles.ts
|
|
@@ -52433,7 +50387,7 @@ var init_digest = __esm(() => {
|
|
|
52433
50387
|
|
|
52434
50388
|
// src/context/engine/manifest-store.ts
|
|
52435
50389
|
import { mkdir as mkdir13 } from "fs/promises";
|
|
52436
|
-
import { dirname as dirname14, isAbsolute as
|
|
50390
|
+
import { dirname as dirname14, isAbsolute as isAbsolute12, join as join37, relative as relative17, resolve as resolve24 } from "path";
|
|
52437
50391
|
function contextStoryDir(projectDir, featureId, storyId) {
|
|
52438
50392
|
return join37(featureDir(projectDir, featureId), "stories", storyId);
|
|
52439
50393
|
}
|
|
@@ -52444,11 +50398,11 @@ function rebuildManifestPath(projectDir, featureId, storyId) {
|
|
|
52444
50398
|
return join37(contextStoryDir(projectDir, featureId, storyId), "rebuild-manifest.json");
|
|
52445
50399
|
}
|
|
52446
50400
|
function toStoredPath(projectDir, pathValue) {
|
|
52447
|
-
const relativePath =
|
|
50401
|
+
const relativePath = isAbsolute12(pathValue) ? relative17(projectDir, pathValue) : pathValue;
|
|
52448
50402
|
return relativePath === "" ? "." : relativePath;
|
|
52449
50403
|
}
|
|
52450
50404
|
function toAbsolutePath(projectDir, pathValue) {
|
|
52451
|
-
return
|
|
50405
|
+
return isAbsolute12(pathValue) ? pathValue : resolve24(projectDir, pathValue);
|
|
52452
50406
|
}
|
|
52453
50407
|
function toStoredManifest(projectDir, manifest) {
|
|
52454
50408
|
return {
|
|
@@ -52993,10 +50947,10 @@ var init_static_rules_scoping = __esm(() => {
|
|
|
52993
50947
|
});
|
|
52994
50948
|
|
|
52995
50949
|
// src/context/engine/providers/static-rules.ts
|
|
52996
|
-
import { createHash as
|
|
50950
|
+
import { createHash as createHash6 } from "crypto";
|
|
52997
50951
|
import { join as join38 } from "path";
|
|
52998
50952
|
function contentHash8(content) {
|
|
52999
|
-
return
|
|
50953
|
+
return createHash6("sha256").update(content).digest("hex").slice(0, 8);
|
|
53000
50954
|
}
|
|
53001
50955
|
function canonicalRuleId(rule) {
|
|
53002
50956
|
return rule.id ?? rule.fileName.replace(/\.md$/i, "");
|
|
@@ -53733,9 +51687,9 @@ var init_loop_handler_forwarding = __esm(() => {
|
|
|
53733
51687
|
});
|
|
53734
51688
|
|
|
53735
51689
|
// src/session/manager-deps.ts
|
|
53736
|
-
import { randomUUID as
|
|
51690
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
53737
51691
|
import { mkdir as mkdir14 } from "fs/promises";
|
|
53738
|
-
import { isAbsolute as
|
|
51692
|
+
import { isAbsolute as isAbsolute13, join as join39, relative as relative18, sep as sep13 } from "path";
|
|
53739
51693
|
function resolveProjectDirFromScratchDir(scratchDir) {
|
|
53740
51694
|
const marker = `${sep13}.nax${sep13}features${sep13}`;
|
|
53741
51695
|
const markerIdx = scratchDir.lastIndexOf(marker);
|
|
@@ -53747,7 +51701,7 @@ function resolveProjectDirFromScratchDir(scratchDir) {
|
|
|
53747
51701
|
return;
|
|
53748
51702
|
}
|
|
53749
51703
|
function toProjectRelativePath(projectDir, pathValue) {
|
|
53750
|
-
const relativePath =
|
|
51704
|
+
const relativePath = isAbsolute13(pathValue) ? relative18(projectDir, pathValue) : pathValue;
|
|
53751
51705
|
return relativePath === "" ? "." : relativePath;
|
|
53752
51706
|
}
|
|
53753
51707
|
function deriveNativeTranscriptDir(opts) {
|
|
@@ -53775,7 +51729,7 @@ var init_manager_deps = __esm(() => {
|
|
|
53775
51729
|
_sessionManagerDeps = {
|
|
53776
51730
|
now: () => new Date().toISOString(),
|
|
53777
51731
|
nowMs: () => Date.now(),
|
|
53778
|
-
uuid: () =>
|
|
51732
|
+
uuid: () => randomUUID9(),
|
|
53779
51733
|
sessionScratchDir: (projectDir, featureName, sessionId) => join39(featureDir(projectDir, featureName), "sessions", sessionId),
|
|
53780
51734
|
writeDescriptor: async (scratchDir, descriptor, projectDir) => {
|
|
53781
51735
|
await mkdir14(scratchDir, { recursive: true });
|
|
@@ -53838,9 +51792,9 @@ var init_model_selection = __esm(() => {
|
|
|
53838
51792
|
});
|
|
53839
51793
|
|
|
53840
51794
|
// src/runtime/session-name.ts
|
|
53841
|
-
import { createHash as
|
|
51795
|
+
import { createHash as createHash7 } from "crypto";
|
|
53842
51796
|
function formatSessionName(req) {
|
|
53843
|
-
const hash2 =
|
|
51797
|
+
const hash2 = createHash7("sha256").update(req.workdir).digest("hex").slice(0, 8);
|
|
53844
51798
|
const sanitize = (s) => s.replace(/[^a-z0-9]+/gi, "-").toLowerCase().replace(/^-+|-+$/g, "");
|
|
53845
51799
|
const parts = ["nax", hash2];
|
|
53846
51800
|
if (req.featureName)
|
|
@@ -55042,9 +52996,9 @@ var init_staleness = __esm(() => {
|
|
|
55042
52996
|
});
|
|
55043
52997
|
|
|
55044
52998
|
// src/context/engine/providers/feature-context.ts
|
|
55045
|
-
import { createHash as
|
|
52999
|
+
import { createHash as createHash8 } from "crypto";
|
|
55046
53000
|
function contentHash82(content) {
|
|
55047
|
-
return
|
|
53001
|
+
return createHash8("sha256").update(content).digest("hex").slice(0, 8);
|
|
55048
53002
|
}
|
|
55049
53003
|
function estimateTokens4(text) {
|
|
55050
53004
|
return Math.ceil(text.length / 4);
|
|
@@ -55449,9 +53403,9 @@ var init_code_neighbor_cache = __esm(() => {
|
|
|
55449
53403
|
});
|
|
55450
53404
|
|
|
55451
53405
|
// src/context/engine/providers/code-neighbor-chunk.ts
|
|
55452
|
-
import { createHash as
|
|
53406
|
+
import { createHash as createHash9 } from "crypto";
|
|
55453
53407
|
function contentHash83(content) {
|
|
55454
|
-
return
|
|
53408
|
+
return createHash9("sha256").update(content).digest("hex").slice(0, 8);
|
|
55455
53409
|
}
|
|
55456
53410
|
function assembleCodeNeighborChunk(input) {
|
|
55457
53411
|
const { sections: sections2, truncated, maxGlobFiles } = input;
|
|
@@ -55529,7 +53483,7 @@ var MAX_CHUNK_TOKENS = 500;
|
|
|
55529
53483
|
var init_code_neighbor_chunk = () => {};
|
|
55530
53484
|
|
|
55531
53485
|
// src/context/engine/providers/code-neighbor-phases.ts
|
|
55532
|
-
import { isAbsolute as
|
|
53486
|
+
import { isAbsolute as isAbsolute14, join as join44, relative as relative19, resolve as resolve25 } from "path";
|
|
55533
53487
|
function parseImportSpecifiers(content) {
|
|
55534
53488
|
const specifiers = new Set;
|
|
55535
53489
|
for (const match of content.matchAll(FROM_PATTERN)) {
|
|
@@ -55559,7 +53513,7 @@ function resolveImport(specifier, fromFile, workdir) {
|
|
|
55559
53513
|
function packageScopeRelative(execRoot, packageDir) {
|
|
55560
53514
|
if (!packageDir)
|
|
55561
53515
|
return "";
|
|
55562
|
-
const rel =
|
|
53516
|
+
const rel = isAbsolute14(packageDir) ? relative19(execRoot, packageDir) : packageDir;
|
|
55563
53517
|
const normalized = rel.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
55564
53518
|
if (normalized === "" || normalized === "." || normalized.startsWith(".."))
|
|
55565
53519
|
return "";
|
|
@@ -56584,7 +54538,7 @@ var init_render = __esm(() => {
|
|
|
56584
54538
|
});
|
|
56585
54539
|
|
|
56586
54540
|
// src/context/engine/rebuild.ts
|
|
56587
|
-
import { randomUUID as
|
|
54541
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
56588
54542
|
function toPackedChunks(prior, newAgentId, targetAgentId) {
|
|
56589
54543
|
const priorAgentForNeutralize = prior.agentId ?? "";
|
|
56590
54544
|
return prior.chunks.map((c) => {
|
|
@@ -56711,7 +54665,7 @@ var init_rebuild = __esm(() => {
|
|
|
56711
54665
|
init_render();
|
|
56712
54666
|
init_scratch_neutralizer();
|
|
56713
54667
|
DEFAULT_REBUILD_DEPS = {
|
|
56714
|
-
uuid: () =>
|
|
54668
|
+
uuid: () => randomUUID10(),
|
|
56715
54669
|
getLogger: () => getLogger2()
|
|
56716
54670
|
};
|
|
56717
54671
|
});
|
|
@@ -56757,7 +54711,7 @@ var init_scoring = __esm(() => {
|
|
|
56757
54711
|
});
|
|
56758
54712
|
|
|
56759
54713
|
// src/context/engine/orchestrator.ts
|
|
56760
|
-
import { createHash as
|
|
54714
|
+
import { createHash as createHash10, randomUUID as randomUUID11 } from "crypto";
|
|
56761
54715
|
function buildPullToolDescriptors(stageToolNames, pullConfig) {
|
|
56762
54716
|
if (!pullConfig?.enabled || stageToolNames.length === 0)
|
|
56763
54717
|
return [];
|
|
@@ -56924,7 +54878,7 @@ class ContextOrchestrator {
|
|
|
56924
54878
|
const providerResults = fetchResults.map(({ providerStatus }) => providerStatus);
|
|
56925
54879
|
if (request.priorStageDigest && (request.planDigestBoost ?? 1) > 1) {
|
|
56926
54880
|
const boost = request.planDigestBoost ?? 1;
|
|
56927
|
-
const hash2 =
|
|
54881
|
+
const hash2 = createHash10("sha256").update(request.priorStageDigest).digest("hex").slice(0, 8);
|
|
56928
54882
|
const tokens = Math.ceil(request.priorStageDigest.length / 4);
|
|
56929
54883
|
allRaw.push({
|
|
56930
54884
|
id: `plan-digest:${hash2}`,
|
|
@@ -57060,7 +55014,7 @@ var init_orchestrator = __esm(() => {
|
|
|
57060
55014
|
init_stage_config();
|
|
57061
55015
|
_orchestratorDeps = {
|
|
57062
55016
|
now: () => Date.now(),
|
|
57063
|
-
uuid: () =>
|
|
55017
|
+
uuid: () => randomUUID11(),
|
|
57064
55018
|
getLogger: getLogger2,
|
|
57065
55019
|
rebuild
|
|
57066
55020
|
};
|
|
@@ -57068,10 +55022,10 @@ var init_orchestrator = __esm(() => {
|
|
|
57068
55022
|
});
|
|
57069
55023
|
|
|
57070
55024
|
// src/context/engine/providers/git-history.ts
|
|
57071
|
-
import { createHash as
|
|
55025
|
+
import { createHash as createHash11 } from "crypto";
|
|
57072
55026
|
import { join as join46 } from "path";
|
|
57073
55027
|
function contentHash84(content) {
|
|
57074
|
-
return
|
|
55028
|
+
return createHash11("sha256").update(content).digest("hex").slice(0, 8);
|
|
57075
55029
|
}
|
|
57076
55030
|
async function hasHistoryAt(path5, repoRoot) {
|
|
57077
55031
|
const { stdout, exitCode } = await _gitHistoryDeps.gitWithTimeout(["log", "--oneline", "-1", "--", path5], repoRoot);
|
|
@@ -57215,10 +55169,10 @@ var init_git_history = __esm(() => {
|
|
|
57215
55169
|
});
|
|
57216
55170
|
|
|
57217
55171
|
// src/context/engine/providers/lint-config.ts
|
|
57218
|
-
import { createHash as
|
|
55172
|
+
import { createHash as createHash12 } from "crypto";
|
|
57219
55173
|
import { join as join47 } from "path";
|
|
57220
55174
|
function contentHash85(content) {
|
|
57221
|
-
return
|
|
55175
|
+
return createHash12("sha256").update(content).digest("hex").slice(0, 8);
|
|
57222
55176
|
}
|
|
57223
55177
|
function distillLintConfig(tool, raw) {
|
|
57224
55178
|
if (tool !== "biome")
|
|
@@ -57956,9 +55910,9 @@ var init_metrics = __esm(() => {
|
|
|
57956
55910
|
});
|
|
57957
55911
|
|
|
57958
55912
|
// src/context/engine/providers/prior-run-failure.ts
|
|
57959
|
-
import { createHash as
|
|
55913
|
+
import { createHash as createHash13 } from "crypto";
|
|
57960
55914
|
function contentHash86(content) {
|
|
57961
|
-
return
|
|
55915
|
+
return createHash13("sha256").update(content).digest("hex").slice(0, 8);
|
|
57962
55916
|
}
|
|
57963
55917
|
function aggregatePriorFailures(runs, storyId) {
|
|
57964
55918
|
let totalAttempts = 0;
|
|
@@ -58068,9 +56022,9 @@ async function readJsonlTail(path6, maxBytes = DEFAULT_JSONL_TAIL_BYTES) {
|
|
|
58068
56022
|
var DEFAULT_JSONL_TAIL_BYTES = 65536;
|
|
58069
56023
|
|
|
58070
56024
|
// src/context/engine/providers/session-scratch.ts
|
|
58071
|
-
import { createHash as
|
|
56025
|
+
import { createHash as createHash14 } from "crypto";
|
|
58072
56026
|
function contentHash87(content) {
|
|
58073
|
-
return
|
|
56027
|
+
return createHash14("sha256").update(content).digest("hex").slice(0, 8);
|
|
58074
56028
|
}
|
|
58075
56029
|
function parseJsonl(raw) {
|
|
58076
56030
|
const entries = [];
|
|
@@ -58177,9 +56131,9 @@ var init_session_scratch = __esm(() => {
|
|
|
58177
56131
|
});
|
|
58178
56132
|
|
|
58179
56133
|
// src/context/engine/providers/test-coverage.ts
|
|
58180
|
-
import { createHash as
|
|
56134
|
+
import { createHash as createHash15 } from "crypto";
|
|
58181
56135
|
function contentHash88(content) {
|
|
58182
|
-
return
|
|
56136
|
+
return createHash15("sha256").update(content).digest("hex").slice(0, 8);
|
|
58183
56137
|
}
|
|
58184
56138
|
|
|
58185
56139
|
class TestCoverageProvider {
|
|
@@ -58259,9 +56213,9 @@ var init_test_coverage = __esm(() => {
|
|
|
58259
56213
|
});
|
|
58260
56214
|
|
|
58261
56215
|
// src/context/engine/providers/tool-diagnostics.ts
|
|
58262
|
-
import { createHash as
|
|
56216
|
+
import { createHash as createHash16 } from "crypto";
|
|
58263
56217
|
function contentHash89(content) {
|
|
58264
|
-
return
|
|
56218
|
+
return createHash16("sha256").update(content).digest("hex").slice(0, 8);
|
|
58265
56219
|
}
|
|
58266
56220
|
function parseToolDiagnosticsJsonl(raw) {
|
|
58267
56221
|
const entries = [];
|
|
@@ -58643,9 +56597,9 @@ var init_registry4 = __esm(() => {
|
|
|
58643
56597
|
});
|
|
58644
56598
|
|
|
58645
56599
|
// src/trust/store.ts
|
|
58646
|
-
import { randomUUID as
|
|
56600
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
58647
56601
|
import { mkdir as mkdir18, rename as rename5, stat as stat8, unlink as unlink4, writeFile as writeFile10 } from "fs/promises";
|
|
58648
|
-
import { dirname as dirname20, isAbsolute as
|
|
56602
|
+
import { dirname as dirname20, isAbsolute as isAbsolute15, join as join48 } from "path";
|
|
58649
56603
|
function trustStorePath() {
|
|
58650
56604
|
return join48(globalConfigDir(), "trust.json");
|
|
58651
56605
|
}
|
|
@@ -58716,7 +56670,7 @@ async function readFoldersForWrite(storePath) {
|
|
|
58716
56670
|
return read.state === "ok" ? read.file.folders : [];
|
|
58717
56671
|
}
|
|
58718
56672
|
async function writeTrustStore(storePath, file2) {
|
|
58719
|
-
const tempPath = `${storePath}.${process.pid}.${
|
|
56673
|
+
const tempPath = `${storePath}.${process.pid}.${randomUUID12()}.tmp`;
|
|
58720
56674
|
try {
|
|
58721
56675
|
await writeFile10(tempPath, `${JSON.stringify(file2, null, 2)}
|
|
58722
56676
|
`, { mode: 384 });
|
|
@@ -58745,7 +56699,7 @@ var init_store2 = __esm(() => {
|
|
|
58745
56699
|
TrustStoreFileSchema = exports_external.object({
|
|
58746
56700
|
version: exports_external.literal(1),
|
|
58747
56701
|
folders: exports_external.array(exports_external.object({
|
|
58748
|
-
path: exports_external.string().refine((path6) =>
|
|
56702
|
+
path: exports_external.string().refine((path6) => isAbsolute15(path6), { message: "path must be absolute" }),
|
|
58749
56703
|
addedAt: exports_external.string(),
|
|
58750
56704
|
via: exports_external.enum(["prompt", "cli"])
|
|
58751
56705
|
}))
|
|
@@ -58811,7 +56765,7 @@ var init_trust = __esm(() => {
|
|
|
58811
56765
|
});
|
|
58812
56766
|
|
|
58813
56767
|
// src/context/engine/providers/plugin-loader.ts
|
|
58814
|
-
import { isAbsolute as
|
|
56768
|
+
import { isAbsolute as isAbsolute16, join as join49, resolve as resolve28 } from "path";
|
|
58815
56769
|
function isInitialisable(p) {
|
|
58816
56770
|
return typeof p.init === "function";
|
|
58817
56771
|
}
|
|
@@ -58834,7 +56788,7 @@ function extractProvider(mod) {
|
|
|
58834
56788
|
return null;
|
|
58835
56789
|
}
|
|
58836
56790
|
function resolveModuleSpecifier(specifier, workdir) {
|
|
58837
|
-
if (
|
|
56791
|
+
if (isAbsolute16(specifier)) {
|
|
58838
56792
|
throw new NaxError(`Plugin module path must be a bare package name or a project-relative path (./... or ../...): got absolute "${specifier}"`, "PLUGIN_MODULE_ABSOLUTE_PATH", { stage: "context", workdir, specifier });
|
|
58839
56793
|
}
|
|
58840
56794
|
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
@@ -59016,8 +56970,8 @@ var init_version = __esm(() => {
|
|
|
59016
56970
|
NAX_AI_VERSION = CATALOG_VERSION;
|
|
59017
56971
|
NAX_COMMIT = (() => {
|
|
59018
56972
|
try {
|
|
59019
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
59020
|
-
return "
|
|
56973
|
+
if (/^[0-9a-f]{6,10}$/.test("eab634ebe"))
|
|
56974
|
+
return "eab634ebe";
|
|
59021
56975
|
} catch {}
|
|
59022
56976
|
try {
|
|
59023
56977
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -60028,18 +57982,18 @@ var init_in_flight_usage = __esm(() => {
|
|
|
60028
57982
|
});
|
|
60029
57983
|
|
|
60030
57984
|
// src/runtime/packages.ts
|
|
60031
|
-
import { isAbsolute as
|
|
57985
|
+
import { isAbsolute as isAbsolute17, join as join53, relative as relative21 } from "path";
|
|
60032
57986
|
function packageWorkdir(view) {
|
|
60033
57987
|
const { packageDir, repoRoot } = view;
|
|
60034
57988
|
if (!packageDir)
|
|
60035
57989
|
return repoRoot;
|
|
60036
|
-
if (!repoRoot ||
|
|
57990
|
+
if (!repoRoot || isAbsolute17(packageDir))
|
|
60037
57991
|
return packageDir;
|
|
60038
57992
|
return join53(repoRoot, packageDir);
|
|
60039
57993
|
}
|
|
60040
57994
|
function createPackageView(config2, packageDir, repoRoot, hasOverride, overlay) {
|
|
60041
57995
|
const memo2 = new Map;
|
|
60042
|
-
const relativeFromRoot = packageDir ?
|
|
57996
|
+
const relativeFromRoot = packageDir ? isAbsolute17(packageDir) && isAbsolute17(repoRoot) ? stripLeadingSlash(relative21(repoRoot, packageDir)) : packageDir : "";
|
|
60043
57997
|
return {
|
|
60044
57998
|
packageDir,
|
|
60045
57999
|
relativeFromRoot,
|
|
@@ -60075,7 +58029,7 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
60075
58029
|
function toRelativeKey(packageDir) {
|
|
60076
58030
|
if (!packageDir)
|
|
60077
58031
|
return "";
|
|
60078
|
-
if (
|
|
58032
|
+
if (isAbsolute17(packageDir) && isAbsolute17(repoRoot)) {
|
|
60079
58033
|
if (packageDir === repoRoot)
|
|
60080
58034
|
return "";
|
|
60081
58035
|
return stripLeadingSlash(relative21(repoRoot, packageDir));
|
|
@@ -60143,7 +58097,7 @@ function storyExecRoot(view) {
|
|
|
60143
58097
|
const { repoRoot, packageDir } = view;
|
|
60144
58098
|
if (!packageDir)
|
|
60145
58099
|
return repoRoot;
|
|
60146
|
-
if (!repoRoot ||
|
|
58100
|
+
if (!repoRoot || isAbsolute17(packageDir))
|
|
60147
58101
|
return packageDir;
|
|
60148
58102
|
const segments = packageDir.split("/");
|
|
60149
58103
|
if (segments[0] !== ".nax-wt" || segments.length < 2)
|
|
@@ -70504,7 +68458,7 @@ var require_which = __commonJS(function(exports, module) {
|
|
|
70504
68458
|
pathExtExe
|
|
70505
68459
|
};
|
|
70506
68460
|
};
|
|
70507
|
-
var
|
|
68461
|
+
var which2 = (cmd, opt, cb) => {
|
|
70508
68462
|
if (typeof opt === "function") {
|
|
70509
68463
|
cb = opt;
|
|
70510
68464
|
opt = {};
|
|
@@ -70566,8 +68520,8 @@ var require_which = __commonJS(function(exports, module) {
|
|
|
70566
68520
|
return null;
|
|
70567
68521
|
throw getNotFoundError(cmd);
|
|
70568
68522
|
};
|
|
70569
|
-
module.exports =
|
|
70570
|
-
|
|
68523
|
+
module.exports = which2;
|
|
68524
|
+
which2.sync = whichSync;
|
|
70571
68525
|
});
|
|
70572
68526
|
|
|
70573
68527
|
// ../../node_modules/.bun/path-key@3.1.1/node_modules/path-key/index.js
|
|
@@ -70587,7 +68541,7 @@ var require_path_key = __commonJS(function(exports, module) {
|
|
|
70587
68541
|
// ../../node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
|
|
70588
68542
|
var require_resolveCommand = __commonJS(function(exports, module) {
|
|
70589
68543
|
var path7 = __require("path");
|
|
70590
|
-
var
|
|
68544
|
+
var which2 = require_which();
|
|
70591
68545
|
var getPathKey = require_path_key();
|
|
70592
68546
|
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
70593
68547
|
const env2 = parsed.options.env || process.env;
|
|
@@ -70601,7 +68555,7 @@ var require_resolveCommand = __commonJS(function(exports, module) {
|
|
|
70601
68555
|
}
|
|
70602
68556
|
let resolved;
|
|
70603
68557
|
try {
|
|
70604
|
-
resolved =
|
|
68558
|
+
resolved = which2.sync(parsed.command, {
|
|
70605
68559
|
path: env2[getPathKey({ env: env2 })],
|
|
70606
68560
|
pathExt: withoutPathExt ? path7.delimiter : undefined
|
|
70607
68561
|
});
|
|
@@ -71106,7 +69060,7 @@ var init_client4 = __esm(() => {
|
|
|
71106
69060
|
});
|
|
71107
69061
|
|
|
71108
69062
|
// src/mcp/lock.ts
|
|
71109
|
-
import { createHash as
|
|
69063
|
+
import { createHash as createHash17 } from "crypto";
|
|
71110
69064
|
import { mkdir as mkdir22, readFile as readFile9, writeFile as writeFile11 } from "fs/promises";
|
|
71111
69065
|
import { join as join55 } from "path";
|
|
71112
69066
|
function mcpLockPath(projectRoot) {
|
|
@@ -71121,7 +69075,7 @@ function canonical3(value) {
|
|
|
71121
69075
|
return Object.fromEntries(entries.map(([k, v]) => [k, canonical3(v)]));
|
|
71122
69076
|
}
|
|
71123
69077
|
function schemaHash(schema) {
|
|
71124
|
-
return
|
|
69078
|
+
return createHash17("sha256").update(JSON.stringify(canonical3(schema) ?? null)).digest("hex").slice(0, 16);
|
|
71125
69079
|
}
|
|
71126
69080
|
async function readMcpLock(projectRoot) {
|
|
71127
69081
|
try {
|
|
@@ -71642,7 +69596,7 @@ var init_flake_probe = __esm(() => {
|
|
|
71642
69596
|
init_internal();
|
|
71643
69597
|
init_errors4();
|
|
71644
69598
|
init_logger2();
|
|
71645
|
-
|
|
69599
|
+
init_parser();
|
|
71646
69600
|
init_executor();
|
|
71647
69601
|
NO_TESTS_EXECUTED_MARKERS = [/no tests? to run/i, /^ran 0 tests?/im];
|
|
71648
69602
|
_flakeProbeDeps = {
|
|
@@ -72981,10 +70935,10 @@ async function resolvePackageName(root) {
|
|
|
72981
70935
|
var init_exec_package_name = () => {};
|
|
72982
70936
|
|
|
72983
70937
|
// src/agents/nax-owned-writes.ts
|
|
72984
|
-
import { isAbsolute as
|
|
70938
|
+
import { isAbsolute as isAbsolute18, relative as relative22, resolve as resolve31, sep as sep15 } from "path";
|
|
72985
70939
|
function naxWriteOptIns(root, allowWrite) {
|
|
72986
70940
|
const naxDir = resolve31(root, ".nax");
|
|
72987
|
-
const names = allowWrite.map((p) => relative22(naxDir,
|
|
70941
|
+
const names = allowWrite.map((p) => relative22(naxDir, isAbsolute18(p) ? resolve31(p) : resolve31(root, p))).filter((rel) => rel !== "" && !rel.startsWith("..") && !rel.includes(sep15) && !isAbsolute18(rel)).filter((name) => name !== NAX_SCRATCHPAD_ENTRY && !NAX_NEVER_OPT_IN.has(name));
|
|
72988
70942
|
return new Set(names);
|
|
72989
70943
|
}
|
|
72990
70944
|
function isNaxConfigSegments(segments) {
|
|
@@ -73562,12 +71516,12 @@ var init_tool_preamble = __esm(() => {
|
|
|
73562
71516
|
});
|
|
73563
71517
|
|
|
73564
71518
|
// src/session/instruction-options.ts
|
|
73565
|
-
import { isAbsolute as
|
|
71519
|
+
import { isAbsolute as isAbsolute19, relative as relative23 } from "path";
|
|
73566
71520
|
function instructionOptionsForSession(agentName, options) {
|
|
73567
71521
|
if (agentName !== "native")
|
|
73568
71522
|
return {};
|
|
73569
71523
|
const packageDir = options.codingToolPackageDir;
|
|
73570
|
-
const packageScope = packageDir ?
|
|
71524
|
+
const packageScope = packageDir ? isAbsolute19(packageDir) ? relative23(options.workdir, packageDir) : packageOverrideKey(packageDir) : ".";
|
|
73571
71525
|
return {
|
|
73572
71526
|
instructionFileName: options.config.agent?.native?.instructionFileName ?? DEFAULT_INSTRUCTION_FILE_NAME,
|
|
73573
71527
|
instructionDirectories: options.instructionDirectories ?? [options.codingToolWorkdirLabel ?? (packageScope || ".")],
|
|
@@ -73774,7 +71728,7 @@ __export(exports_runtime, {
|
|
|
73774
71728
|
totalSpendUsd: () => totalSpendUsd,
|
|
73775
71729
|
writeProjectIdentity: () => writeProjectIdentity
|
|
73776
71730
|
});
|
|
73777
|
-
import { basename as basename9, isAbsolute as
|
|
71731
|
+
import { basename as basename9, isAbsolute as isAbsolute20, join as join60, resolve as resolve32 } from "path";
|
|
73778
71732
|
function createRuntime(config2, workdir, opts) {
|
|
73779
71733
|
const runId = crypto.randomUUID();
|
|
73780
71734
|
const controller = new AbortController;
|
|
@@ -73805,7 +71759,7 @@ function createRuntime(config2, workdir, opts) {
|
|
|
73805
71759
|
const reviewAuditor = opts?.reviewAuditor ?? (config2.review?.audit?.enabled ? new ReviewAuditor(runId, outputDir) : createNoOpReviewAuditor());
|
|
73806
71760
|
const usageEnabled = config2.agent?.usageAudit?.enabled ?? false;
|
|
73807
71761
|
const configuredUsageDir = config2.agent?.usageAudit?.dir;
|
|
73808
|
-
const usageDir = configuredUsageDir === undefined ? join60(outputDir, "usage") :
|
|
71762
|
+
const usageDir = configuredUsageDir === undefined ? join60(outputDir, "usage") : isAbsolute20(configuredUsageDir) ? configuredUsageDir : resolve32(workdir, configuredUsageDir);
|
|
73809
71763
|
let usageAuditor;
|
|
73810
71764
|
if (opts?.usageAuditor) {
|
|
73811
71765
|
usageAuditor = opts.usageAuditor;
|
|
@@ -74001,12 +71955,12 @@ var init_runtime3 = __esm(() => {
|
|
|
74001
71955
|
|
|
74002
71956
|
// src/context/engine/stage-assembler.ts
|
|
74003
71957
|
import { readdir as readdir4 } from "fs/promises";
|
|
74004
|
-
import { isAbsolute as
|
|
71958
|
+
import { isAbsolute as isAbsolute21, join as join61, resolve as resolve33 } from "path";
|
|
74005
71959
|
function dedupeScratchDirs(dirs) {
|
|
74006
71960
|
return [...new Set(dirs.filter((dir) => Boolean(dir)))];
|
|
74007
71961
|
}
|
|
74008
71962
|
function toAbsolutePath2(projectDir, pathValue) {
|
|
74009
|
-
return
|
|
71963
|
+
return isAbsolute21(pathValue) ? pathValue : resolve33(projectDir, pathValue);
|
|
74010
71964
|
}
|
|
74011
71965
|
async function discoverSessionScratchDirsOnDisk(projectDir, featureName, storyId, ttlMs) {
|
|
74012
71966
|
const logger = getLogger2();
|
|
@@ -80131,6 +78085,54 @@ var init_fix_review2 = __esm(() => {
|
|
|
80131
78085
|
};
|
|
80132
78086
|
});
|
|
80133
78087
|
|
|
78088
|
+
// src/agents/shared/env.ts
|
|
78089
|
+
import { homedir as homedir5 } from "os";
|
|
78090
|
+
import { isAbsolute as isAbsolute22 } from "path";
|
|
78091
|
+
function buildAllowedEnv(options) {
|
|
78092
|
+
const allowed = {};
|
|
78093
|
+
for (const varName of ESSENTIAL_VARS) {
|
|
78094
|
+
if (process.env[varName])
|
|
78095
|
+
allowed[varName] = process.env[varName];
|
|
78096
|
+
}
|
|
78097
|
+
const rawHome = process.env.HOME ?? "";
|
|
78098
|
+
const safeHome = rawHome && isAbsolute22(rawHome) ? rawHome : homedir5();
|
|
78099
|
+
if (rawHome !== safeHome) {
|
|
78100
|
+
getSafeLogger2()?.warn("env", `HOME env is not absolute ("${rawHome}"), falling back to os.homedir(): ${safeHome}`);
|
|
78101
|
+
}
|
|
78102
|
+
allowed.HOME = safeHome;
|
|
78103
|
+
for (const varName of API_KEY_VARS) {
|
|
78104
|
+
if (process.env[varName])
|
|
78105
|
+
allowed[varName] = process.env[varName];
|
|
78106
|
+
}
|
|
78107
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
78108
|
+
if (ALLOWED_PREFIXES.some((prefix) => key.startsWith(prefix))) {
|
|
78109
|
+
allowed[key] = value;
|
|
78110
|
+
}
|
|
78111
|
+
}
|
|
78112
|
+
if (options?.modelEnv)
|
|
78113
|
+
Object.assign(allowed, options.modelEnv);
|
|
78114
|
+
if (options?.env)
|
|
78115
|
+
Object.assign(allowed, options.env);
|
|
78116
|
+
return allowed;
|
|
78117
|
+
}
|
|
78118
|
+
var ESSENTIAL_VARS, API_KEY_VARS, ALLOWED_PREFIXES;
|
|
78119
|
+
var init_env = __esm(() => {
|
|
78120
|
+
init_logger2();
|
|
78121
|
+
ESSENTIAL_VARS = ["PATH", "TMPDIR", "NODE_ENV", "USER", "LOGNAME"];
|
|
78122
|
+
API_KEY_VARS = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY", "CLAUDE_API_KEY"];
|
|
78123
|
+
ALLOWED_PREFIXES = [
|
|
78124
|
+
"CLAUDE_",
|
|
78125
|
+
"NAX_",
|
|
78126
|
+
"CLAW_",
|
|
78127
|
+
"TURBO_",
|
|
78128
|
+
"CODEX_",
|
|
78129
|
+
"GEMINI_",
|
|
78130
|
+
"ANTHROPIC_",
|
|
78131
|
+
"OPENCODE_",
|
|
78132
|
+
"MINIMAX_"
|
|
78133
|
+
];
|
|
78134
|
+
});
|
|
78135
|
+
|
|
80134
78136
|
// src/utils/command-argv.ts
|
|
80135
78137
|
function parseCommandToArgv(command) {
|
|
80136
78138
|
const safeEnv = buildAllowedEnv();
|
|
@@ -84759,7 +82761,93 @@ var init_manager_run_fallback = __esm(() => {
|
|
|
84759
82761
|
init_swap_decision();
|
|
84760
82762
|
});
|
|
84761
82763
|
|
|
84762
|
-
// src/agents/
|
|
82764
|
+
// src/agents/turn/abort.ts
|
|
82765
|
+
function createAbortError(signal, fallback = "Run aborted") {
|
|
82766
|
+
const reason = signal?.reason;
|
|
82767
|
+
if (reason instanceof Error) {
|
|
82768
|
+
return reason;
|
|
82769
|
+
}
|
|
82770
|
+
if (typeof reason === "string" && reason.length > 0) {
|
|
82771
|
+
return new Error(reason);
|
|
82772
|
+
}
|
|
82773
|
+
return new Error(fallback);
|
|
82774
|
+
}
|
|
82775
|
+
function throwIfAborted(signal, fallback) {
|
|
82776
|
+
if (signal?.aborted) {
|
|
82777
|
+
throw createAbortError(signal, fallback);
|
|
82778
|
+
}
|
|
82779
|
+
}
|
|
82780
|
+
async function raceWithAbort(promise3, signal, fallback) {
|
|
82781
|
+
if (!signal) {
|
|
82782
|
+
return promise3;
|
|
82783
|
+
}
|
|
82784
|
+
if (signal.aborted) {
|
|
82785
|
+
throw createAbortError(signal, fallback);
|
|
82786
|
+
}
|
|
82787
|
+
return await new Promise((resolve35, reject) => {
|
|
82788
|
+
const onAbort = () => reject(createAbortError(signal, fallback));
|
|
82789
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
82790
|
+
promise3.then((value) => {
|
|
82791
|
+
signal.removeEventListener("abort", onAbort);
|
|
82792
|
+
resolve35(value);
|
|
82793
|
+
}, (error48) => {
|
|
82794
|
+
signal.removeEventListener("abort", onAbort);
|
|
82795
|
+
reject(error48);
|
|
82796
|
+
});
|
|
82797
|
+
});
|
|
82798
|
+
}
|
|
82799
|
+
|
|
82800
|
+
// src/agents/turn/turn-deadline.ts
|
|
82801
|
+
function assembleTurnResult(input) {
|
|
82802
|
+
const { totalTokenUsage, totalExactCostUsd, turnCount, interactions, timedOut, rateCard } = input;
|
|
82803
|
+
const output = timedOut ? "" : input.output;
|
|
82804
|
+
const hasUsage = totalTokenUsage.inputTokens > 0 || totalTokenUsage.outputTokens > 0;
|
|
82805
|
+
const priced = hasUsage ? priceCall(totalTokenUsage, rateCard.rates) : undefined;
|
|
82806
|
+
return {
|
|
82807
|
+
output,
|
|
82808
|
+
tokenUsage: totalTokenUsage,
|
|
82809
|
+
estimatedCostUsd: priced?.costUsd ?? 0,
|
|
82810
|
+
exactCostUsd: totalExactCostUsd,
|
|
82811
|
+
internalRoundTrips: turnCount,
|
|
82812
|
+
...interactions.length > 0 ? { interactions } : {},
|
|
82813
|
+
timedOut,
|
|
82814
|
+
pricingSource: rateCard.source,
|
|
82815
|
+
...priced?.resolvedRates !== undefined ? { rates: priced.resolvedRates } : {}
|
|
82816
|
+
};
|
|
82817
|
+
}
|
|
82818
|
+
function warnWallClockTimeout(sessionName, timeoutSeconds, stage) {
|
|
82819
|
+
getSafeLogger2()?.warn(stage, "wall-clock timeout exceeded \u2014 session terminated", {
|
|
82820
|
+
sessionName,
|
|
82821
|
+
timeoutSeconds
|
|
82822
|
+
});
|
|
82823
|
+
}
|
|
82824
|
+
var init_turn_deadline2 = __esm(() => {
|
|
82825
|
+
init_logger2();
|
|
82826
|
+
init_cost();
|
|
82827
|
+
});
|
|
82828
|
+
|
|
82829
|
+
// src/agents/turn/index.ts
|
|
82830
|
+
var init_turn = __esm(() => {
|
|
82831
|
+
init_turn_deadline2();
|
|
82832
|
+
});
|
|
82833
|
+
|
|
82834
|
+
// src/agents/session-naming.ts
|
|
82835
|
+
import { createHash as createHash18 } from "crypto";
|
|
82836
|
+
function computeAcpHandle(workdir, featureName, storyId, sessionRole) {
|
|
82837
|
+
const hash2 = createHash18("sha256").update(workdir).digest("hex").slice(0, 8);
|
|
82838
|
+
const sanitize = (s) => s.replace(/[^a-z0-9]+/gi, "-").toLowerCase().replace(/^-+|-+$/g, "");
|
|
82839
|
+
const parts = ["nax", hash2];
|
|
82840
|
+
if (featureName)
|
|
82841
|
+
parts.push(sanitize(featureName));
|
|
82842
|
+
if (storyId)
|
|
82843
|
+
parts.push(sanitize(storyId));
|
|
82844
|
+
if (sessionRole)
|
|
82845
|
+
parts.push(sanitize(sessionRole));
|
|
82846
|
+
return parts.join("-");
|
|
82847
|
+
}
|
|
82848
|
+
var init_session_naming = () => {};
|
|
82849
|
+
|
|
82850
|
+
// src/agents/acp/pricing.ts
|
|
84763
82851
|
function spendOfResult(result) {
|
|
84764
82852
|
return {
|
|
84765
82853
|
tokenUsage: result.tokenUsage,
|
|
@@ -84795,7 +82883,7 @@ var init_pricing = __esm(() => {
|
|
|
84795
82883
|
});
|
|
84796
82884
|
});
|
|
84797
82885
|
|
|
84798
|
-
// src/agents/acp
|
|
82886
|
+
// src/agents/acp/failure-map.ts
|
|
84799
82887
|
function capped(text) {
|
|
84800
82888
|
return text.slice(0, MAX_MESSAGE_CHARS);
|
|
84801
82889
|
}
|
|
@@ -88959,7 +87047,7 @@ function client3(options) {
|
|
|
88959
87047
|
return new ClientApp(options);
|
|
88960
87048
|
}
|
|
88961
87049
|
var methods, startActiveSession, AgentContext, ClientContext, AgentConnectionHandle, ClientConnectionHandle, ActiveSession, agentRequestSpecs, agentNotificationSpecs, clientRequestSpecs, clientNotificationSpecs, agentRequestSpecsByMethod, agentNotificationSpecsByMethod, clientRequestSpecsByMethod, clientNotificationSpecsByMethod, sessionUpdateRouters, appBuilder, runAgentConnectHandlers, runClientConnectHandlers, stableConnectionOptions, AgentApp, ClientApp, legacyAgentRequestMethods, legacyAgentNotificationMethods, legacyClientRequestMethods, legacyClientNotificationMethods, TerminalHandle;
|
|
88962
|
-
var
|
|
87050
|
+
var init_acp = __esm(() => {
|
|
88963
87051
|
init_schema3();
|
|
88964
87052
|
init_zod_gen();
|
|
88965
87053
|
init_stream();
|
|
@@ -89593,7 +87681,7 @@ function stopReasonError(stopReason) {
|
|
|
89593
87681
|
}
|
|
89594
87682
|
var EXCERPT_BYTES = 4096, AUTH_REQUIRED_CODE = -32000, RESOURCE_NOT_FOUND_CODE = -32002, RESTORE_STEPS, SESSION_NOT_FOUND_TEXT2, ACP_STOP_CODES;
|
|
89595
87683
|
var init_errors6 = __esm(() => {
|
|
89596
|
-
|
|
87684
|
+
init_acp();
|
|
89597
87685
|
init_src();
|
|
89598
87686
|
init_text();
|
|
89599
87687
|
RESTORE_STEPS = new Set(["session/resume", "session/load"]);
|
|
@@ -90420,7 +88508,7 @@ async function agentGoneError(during, launched, secrets) {
|
|
|
90420
88508
|
}
|
|
90421
88509
|
var GONE_WAIT_MS = 1000, STDERR_DRAIN_MS = 200;
|
|
90422
88510
|
var init_launch = __esm(() => {
|
|
90423
|
-
|
|
88511
|
+
init_acp();
|
|
90424
88512
|
init_src();
|
|
90425
88513
|
init_errors6();
|
|
90426
88514
|
});
|
|
@@ -90522,7 +88610,7 @@ function openConnection(target, handlers) {
|
|
|
90522
88610
|
};
|
|
90523
88611
|
}
|
|
90524
88612
|
var init_connection = __esm(() => {
|
|
90525
|
-
|
|
88613
|
+
init_acp();
|
|
90526
88614
|
});
|
|
90527
88615
|
|
|
90528
88616
|
// ../nax-agent-acp/src/client/pre-approval.ts
|
|
@@ -90794,7 +88882,7 @@ function initialDoc(o, record4, agentSessionId) {
|
|
|
90794
88882
|
}
|
|
90795
88883
|
var MAX_OFFERED_MODELS = 50, MAX_MODEL_ID_CHARS = 100;
|
|
90796
88884
|
var init_open = __esm(() => {
|
|
90797
|
-
|
|
88885
|
+
init_acp();
|
|
90798
88886
|
init_src();
|
|
90799
88887
|
init_capabilities();
|
|
90800
88888
|
init_connection();
|
|
@@ -94120,7 +92208,97 @@ var init_client5 = __esm(() => {
|
|
|
94120
92208
|
init_launchable();
|
|
94121
92209
|
});
|
|
94122
92210
|
|
|
94123
|
-
// src/agents/
|
|
92211
|
+
// src/agents/interaction/output-parsing.ts
|
|
92212
|
+
function extractQuestion(output) {
|
|
92213
|
+
const text = output.trim();
|
|
92214
|
+
if (!text)
|
|
92215
|
+
return null;
|
|
92216
|
+
const lines2 = text.split(`
|
|
92217
|
+
`).filter((l) => l.trim().length > 0);
|
|
92218
|
+
const lastLine = lines2.at(-1)?.trim() ?? "";
|
|
92219
|
+
const lower = lastLine.toLowerCase();
|
|
92220
|
+
const markers = [
|
|
92221
|
+
"please confirm",
|
|
92222
|
+
"please specify",
|
|
92223
|
+
"please provide",
|
|
92224
|
+
"which would you",
|
|
92225
|
+
"should i ",
|
|
92226
|
+
"do you want",
|
|
92227
|
+
"can you clarify"
|
|
92228
|
+
];
|
|
92229
|
+
const isQuestion = lastLine.endsWith("?") && lastLine.length > 10 || markers.some((m) => lower.includes(m));
|
|
92230
|
+
if (!isQuestion)
|
|
92231
|
+
return null;
|
|
92232
|
+
const paragraphs = text.split(/\n\n+/);
|
|
92233
|
+
const questionPara = paragraphs.at(-1)?.trim() ?? lastLine;
|
|
92234
|
+
const contextPara = paragraphs.at(-2)?.trim();
|
|
92235
|
+
return contextPara ? `${contextPara}
|
|
92236
|
+
|
|
92237
|
+
${questionPara}` : questionPara;
|
|
92238
|
+
}
|
|
92239
|
+
function extractContextToolCall(output) {
|
|
92240
|
+
const match = output.match(CONTEXT_TOOL_CALL_PATTERN);
|
|
92241
|
+
if (!match)
|
|
92242
|
+
return null;
|
|
92243
|
+
const [, name, rawInput] = match;
|
|
92244
|
+
const trimmedInput = rawInput.trim();
|
|
92245
|
+
if (!trimmedInput) {
|
|
92246
|
+
return { name, input: {} };
|
|
92247
|
+
}
|
|
92248
|
+
try {
|
|
92249
|
+
return { name, input: JSON.parse(trimmedInput) };
|
|
92250
|
+
} catch (error48) {
|
|
92251
|
+
return {
|
|
92252
|
+
name,
|
|
92253
|
+
error: `Invalid JSON tool input: ${error48 instanceof Error ? error48.message : String(error48)}`
|
|
92254
|
+
};
|
|
92255
|
+
}
|
|
92256
|
+
}
|
|
92257
|
+
var CONTEXT_TOOL_CALL_PATTERN;
|
|
92258
|
+
var init_output_parsing = __esm(() => {
|
|
92259
|
+
CONTEXT_TOOL_CALL_PATTERN = /<nax_tool_call\s+name="([^"]+)">\s*([\s\S]*?)\s*<\/nax_tool_call>/i;
|
|
92260
|
+
});
|
|
92261
|
+
|
|
92262
|
+
// src/agents/interaction/turn-interactions.ts
|
|
92263
|
+
async function awaitInteractionReply(ctx, interaction, warnSuffix) {
|
|
92264
|
+
let timeoutId;
|
|
92265
|
+
try {
|
|
92266
|
+
const response = await Promise.race([
|
|
92267
|
+
raceWithAbort(ctx.interactionHandler.onInteraction(interaction), ctx.signal, INTERACTION_ABORT_MESSAGE),
|
|
92268
|
+
new Promise((resolve36) => {
|
|
92269
|
+
timeoutId = setTimeout(() => resolve36(null), ctx.timeoutMs ?? INTERACTION_TIMEOUT_MS);
|
|
92270
|
+
})
|
|
92271
|
+
]);
|
|
92272
|
+
if (response) {
|
|
92273
|
+
return { kind: "answered", answer: response.answer };
|
|
92274
|
+
}
|
|
92275
|
+
} catch (err) {
|
|
92276
|
+
if (ctx.signal?.aborted) {
|
|
92277
|
+
return { kind: "aborted" };
|
|
92278
|
+
}
|
|
92279
|
+
getSafeLogger2()?.warn(ctx.stage, `InteractionHandler.onInteraction failed${warnSuffix}${err instanceof Error ? err.message : String(err)}`);
|
|
92280
|
+
} finally {
|
|
92281
|
+
clearTimeout(timeoutId);
|
|
92282
|
+
}
|
|
92283
|
+
return { kind: "no-reply" };
|
|
92284
|
+
}
|
|
92285
|
+
function toContextToolInteraction(toolCall) {
|
|
92286
|
+
return toolCall.error ? { kind: "context-tool", name: toolCall.name, error: toolCall.error } : { kind: "context-tool", name: toolCall.name, input: toolCall.input };
|
|
92287
|
+
}
|
|
92288
|
+
var INTERACTION_TIMEOUT_MS, INTERACTION_ABORT_MESSAGE = "Run aborted \u2014 shutdown in progress";
|
|
92289
|
+
var init_turn_interactions = __esm(() => {
|
|
92290
|
+
init_logger2();
|
|
92291
|
+
init_turn();
|
|
92292
|
+
INTERACTION_TIMEOUT_MS = 5 * 60 * 1000;
|
|
92293
|
+
});
|
|
92294
|
+
|
|
92295
|
+
// src/agents/interaction/index.ts
|
|
92296
|
+
var init_interaction = __esm(() => {
|
|
92297
|
+
init_output_parsing();
|
|
92298
|
+
init_turn_interactions();
|
|
92299
|
+
});
|
|
92300
|
+
|
|
92301
|
+
// src/agents/acp/ask-port.ts
|
|
94124
92302
|
function beatWhileWaiting(turn, beatMs) {
|
|
94125
92303
|
let timer;
|
|
94126
92304
|
const beat = () => {
|
|
@@ -94169,13 +92347,13 @@ function createAskPort(slot, beatMs = AWAITING_HUMAN_BEAT_MS, audit) {
|
|
|
94169
92347
|
}
|
|
94170
92348
|
};
|
|
94171
92349
|
}
|
|
94172
|
-
var STAGE = "acp
|
|
92350
|
+
var STAGE = "acp", AWAITING_HUMAN_BEAT_MS = 30000;
|
|
94173
92351
|
var init_ask_port = __esm(() => {
|
|
94174
92352
|
init_logger2();
|
|
94175
92353
|
init_interaction();
|
|
94176
92354
|
});
|
|
94177
92355
|
|
|
94178
|
-
// src/agents/acp
|
|
92356
|
+
// src/agents/acp/profile-map.ts
|
|
94179
92357
|
function acpProfileFor(mode) {
|
|
94180
92358
|
return PROFILE_BY_MODE[mode];
|
|
94181
92359
|
}
|
|
@@ -94188,7 +92366,7 @@ var init_profile_map = __esm(() => {
|
|
|
94188
92366
|
});
|
|
94189
92367
|
});
|
|
94190
92368
|
|
|
94191
|
-
// src/agents/acp
|
|
92369
|
+
// src/agents/acp/open-context.ts
|
|
94192
92370
|
function backendEnv(modelEnv) {
|
|
94193
92371
|
const allowed2 = buildAllowedEnv(modelEnv === undefined ? undefined : { modelEnv: { ...modelEnv } });
|
|
94194
92372
|
return Object.fromEntries(Object.entries(allowed2).filter((entry2) => typeof entry2[1] === "string" && ENV_NAME.test(entry2[0]) && !entry2[1].includes("\x00")));
|
|
@@ -94244,7 +92422,7 @@ var init_open_context = __esm(() => {
|
|
|
94244
92422
|
ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
94245
92423
|
});
|
|
94246
92424
|
|
|
94247
|
-
// src/agents/acp
|
|
92425
|
+
// src/agents/acp/tool-audit.ts
|
|
94248
92426
|
function inputOf2(input) {
|
|
94249
92427
|
return typeof input === "object" && input !== null && !Array.isArray(input) ? input : { value: input };
|
|
94250
92428
|
}
|
|
@@ -94300,7 +92478,7 @@ var init_tool_audit2 = __esm(() => {
|
|
|
94300
92478
|
init_src();
|
|
94301
92479
|
});
|
|
94302
92480
|
|
|
94303
|
-
// src/agents/acp
|
|
92481
|
+
// src/agents/acp/turn-slot.ts
|
|
94304
92482
|
function createTurnSlot() {
|
|
94305
92483
|
let running;
|
|
94306
92484
|
return {
|
|
@@ -94320,7 +92498,7 @@ var init_turn_slot = __esm(() => {
|
|
|
94320
92498
|
IDLE_SIGNAL2 = new AbortController().signal;
|
|
94321
92499
|
});
|
|
94322
92500
|
|
|
94323
|
-
// src/agents/acp
|
|
92501
|
+
// src/agents/acp/session.ts
|
|
94324
92502
|
import { stat as stat10 } from "fs/promises";
|
|
94325
92503
|
function errorText(err) {
|
|
94326
92504
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -94336,6 +92514,18 @@ async function discard(store, name) {
|
|
|
94336
92514
|
});
|
|
94337
92515
|
});
|
|
94338
92516
|
}
|
|
92517
|
+
async function discardAcpSessionLeftover(transcriptDir, name) {
|
|
92518
|
+
if (transcriptDir === undefined)
|
|
92519
|
+
return;
|
|
92520
|
+
try {
|
|
92521
|
+
await discard(transcriptStoreFor(transcriptDir), name);
|
|
92522
|
+
} catch (err) {
|
|
92523
|
+
getSafeLogger2()?.warn(STAGE2, "Could not discard a stale ACP session transcript", {
|
|
92524
|
+
sessionName: name,
|
|
92525
|
+
error: errorText(err)
|
|
92526
|
+
});
|
|
92527
|
+
}
|
|
92528
|
+
}
|
|
94339
92529
|
function processHooks(base) {
|
|
94340
92530
|
return {
|
|
94341
92531
|
spawned: (pid) => {
|
|
@@ -94354,7 +92544,7 @@ function killAgent(process5) {
|
|
|
94354
92544
|
killProcessGroup(process5.pid, "SIGKILL");
|
|
94355
92545
|
}
|
|
94356
92546
|
async function openBackend2(base, resume) {
|
|
94357
|
-
const backend2 =
|
|
92547
|
+
const backend2 = _acpDeps.acpBackend(backendOptions(base.agent, base.opts, processHooks(base)));
|
|
94358
92548
|
return backend2.open(openContext({
|
|
94359
92549
|
name: base.name,
|
|
94360
92550
|
opts: base.opts,
|
|
@@ -94441,7 +92631,7 @@ async function createSession(name, agent, opts) {
|
|
|
94441
92631
|
process: { pid: undefined }
|
|
94442
92632
|
};
|
|
94443
92633
|
try {
|
|
94444
|
-
const rateCard = await
|
|
92634
|
+
const rateCard = await _acpDeps.resolveRateCard(opts.modelDef.model);
|
|
94445
92635
|
const opened = await openWithLeftover(base);
|
|
94446
92636
|
const protocolIds = await protocolIdsOf(base.store, name);
|
|
94447
92637
|
const handle2 = Object.freeze({
|
|
@@ -94517,7 +92707,7 @@ async function reopenFresh(session2) {
|
|
|
94517
92707
|
await discard(session2.store, session2.name);
|
|
94518
92708
|
session2.opened = await openBackend2(session2, undefined);
|
|
94519
92709
|
}
|
|
94520
|
-
var STAGE2 = "acp
|
|
92710
|
+
var STAGE2 = "acp", DISCARD_CODES, _acpDeps;
|
|
94521
92711
|
var init_session3 = __esm(() => {
|
|
94522
92712
|
init_src();
|
|
94523
92713
|
init_client5();
|
|
@@ -94535,7 +92725,7 @@ var init_session3 = __esm(() => {
|
|
|
94535
92725
|
"AGENT_SESSION_NOT_FOUND",
|
|
94536
92726
|
"TRANSCRIPT_CORRUPT"
|
|
94537
92727
|
]);
|
|
94538
|
-
|
|
92728
|
+
_acpDeps = {
|
|
94539
92729
|
acpBackend: (options) => acpBackend(options),
|
|
94540
92730
|
launchCandidateKind: (agent) => launchCandidateKind(agent),
|
|
94541
92731
|
resolveRateCard: (modelId) => resolveRateCard(modelId),
|
|
@@ -94550,7 +92740,7 @@ var init_session3 = __esm(() => {
|
|
|
94550
92740
|
};
|
|
94551
92741
|
});
|
|
94552
92742
|
|
|
94553
|
-
// src/agents/acp
|
|
92743
|
+
// src/agents/acp/prompt-retry.ts
|
|
94554
92744
|
function isRetryablePromptError(err) {
|
|
94555
92745
|
if (isSessionGone(err))
|
|
94556
92746
|
return false;
|
|
@@ -94571,8 +92761,8 @@ var init_prompt_retry = __esm(() => {
|
|
|
94571
92761
|
RETRYABLE_RPC_CODES = new Set([-32603, -32700]);
|
|
94572
92762
|
});
|
|
94573
92763
|
|
|
94574
|
-
// src/agents/acp
|
|
94575
|
-
import { randomUUID as
|
|
92764
|
+
// src/agents/acp/stream-bridge.ts
|
|
92765
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
94576
92766
|
function toolUpdate(toolName) {
|
|
94577
92767
|
return toolName === undefined ? { kind: "agent.tool_call_update" } : { kind: "agent.tool_call_update", toolName };
|
|
94578
92768
|
}
|
|
@@ -94617,7 +92807,7 @@ function sender(ctx) {
|
|
|
94617
92807
|
try {
|
|
94618
92808
|
ctx.emit(event);
|
|
94619
92809
|
} catch (err) {
|
|
94620
|
-
getSafeLogger2()?.debug("acp
|
|
92810
|
+
getSafeLogger2()?.debug("acp", "A stream listener threw; the turn continues", {
|
|
94621
92811
|
sessionName: ctx.sessionName,
|
|
94622
92812
|
error: err instanceof Error ? err.message : String(err)
|
|
94623
92813
|
});
|
|
@@ -94625,7 +92815,7 @@ function sender(ctx) {
|
|
|
94625
92815
|
};
|
|
94626
92816
|
}
|
|
94627
92817
|
function startCall(ctx, now = Date.now) {
|
|
94628
|
-
const callId =
|
|
92818
|
+
const callId = randomUUID13();
|
|
94629
92819
|
const send = sender(ctx);
|
|
94630
92820
|
const base = {
|
|
94631
92821
|
callId,
|
|
@@ -94673,8 +92863,8 @@ var init_stream_bridge = __esm(() => {
|
|
|
94673
92863
|
init_logger2();
|
|
94674
92864
|
});
|
|
94675
92865
|
|
|
94676
|
-
// src/agents/acp
|
|
94677
|
-
import { randomUUID as
|
|
92866
|
+
// src/agents/acp/turn-loop.ts
|
|
92867
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
94678
92868
|
function used(state) {
|
|
94679
92869
|
return state.turnCount + state.asked;
|
|
94680
92870
|
}
|
|
@@ -94750,7 +92940,7 @@ async function sendWithRetries(loop, attempt) {
|
|
|
94750
92940
|
retry: retryIndex + 1,
|
|
94751
92941
|
of: retries
|
|
94752
92942
|
});
|
|
94753
|
-
await
|
|
92943
|
+
await _acpDeps.delay(promptRetryDelayMs(retryIndex), attempt.controller.signal);
|
|
94754
92944
|
}
|
|
94755
92945
|
}
|
|
94756
92946
|
return sendOnce(loop.session, loop.state.currentPrompt, attempt);
|
|
@@ -94765,7 +92955,7 @@ async function runIteration(loop) {
|
|
|
94765
92955
|
}
|
|
94766
92956
|
const timer = armDeadline(controller, loop.deadline.remainingMs());
|
|
94767
92957
|
const call2 = startCall(session2.stream);
|
|
94768
|
-
const turnId = opts.turnId ??
|
|
92958
|
+
const turnId = opts.turnId ?? randomUUID14();
|
|
94769
92959
|
try {
|
|
94770
92960
|
session2.opts.onActiveCall?.(call2.callId, async () => controller.abort(new WatchdogCancel));
|
|
94771
92961
|
session2.slot.set({
|
|
@@ -94792,7 +92982,7 @@ async function runIteration(loop) {
|
|
|
94792
92982
|
session2.slot.clear();
|
|
94793
92983
|
}
|
|
94794
92984
|
}
|
|
94795
|
-
function
|
|
92985
|
+
function replyContext(loop) {
|
|
94796
92986
|
return { interactionHandler: loop.opts.interactionHandler, signal: loop.opts.signal, stage: STAGE3 };
|
|
94797
92987
|
}
|
|
94798
92988
|
function answerOf(loop, reply2) {
|
|
@@ -94805,13 +92995,13 @@ function answerOf(loop, reply2) {
|
|
|
94805
92995
|
async function nextPrompt(loop, output) {
|
|
94806
92996
|
const toolCall = extractContextToolCall(output);
|
|
94807
92997
|
if (toolCall !== null) {
|
|
94808
|
-
const reply2 = await awaitInteractionReply(
|
|
92998
|
+
const reply2 = await awaitInteractionReply(replyContext(loop), toContextToolInteraction(toolCall), " for context-tool: ");
|
|
94809
92999
|
return answerOf(loop, reply2);
|
|
94810
93000
|
}
|
|
94811
93001
|
const question = extractQuestion(output);
|
|
94812
93002
|
if (question === null)
|
|
94813
93003
|
return;
|
|
94814
|
-
const answer = answerOf(loop, await awaitInteractionReply(
|
|
93004
|
+
const answer = answerOf(loop, await awaitInteractionReply(replyContext(loop), { kind: "question", text: question }, ": "));
|
|
94815
93005
|
if (answer !== undefined)
|
|
94816
93006
|
loop.state.interactions.push({ turnIndex: loop.state.turnCount, question, reply: answer });
|
|
94817
93007
|
return answer;
|
|
@@ -94859,7 +93049,7 @@ async function runLoop(loop) {
|
|
|
94859
93049
|
rateCard: loop.session.rateCard
|
|
94860
93050
|
});
|
|
94861
93051
|
}
|
|
94862
|
-
async function
|
|
93052
|
+
async function runTurnLoop(session2, prompt, opts) {
|
|
94863
93053
|
if (session2.running !== undefined) {
|
|
94864
93054
|
throw new NaxError(`ACP session "${session2.name}" already has a turn in flight`, "ACP_SDK_TURN_IN_FLIGHT", {
|
|
94865
93055
|
stage: STAGE3,
|
|
@@ -94869,7 +93059,7 @@ async function runTurnLoop2(session2, prompt, opts) {
|
|
|
94869
93059
|
const run = runLoop({
|
|
94870
93060
|
session: session2,
|
|
94871
93061
|
opts,
|
|
94872
|
-
max: opts.maxInteractions ??
|
|
93062
|
+
max: opts.maxInteractions ?? DEFAULT_MAX_INTERACTIONS,
|
|
94873
93063
|
deadline: createTurnDeadline(session2.opts.timeoutSeconds),
|
|
94874
93064
|
state: {
|
|
94875
93065
|
turnCount: 0,
|
|
@@ -94893,7 +93083,7 @@ async function runTurnLoop2(session2, prompt, opts) {
|
|
|
94893
93083
|
session2.running = undefined;
|
|
94894
93084
|
}
|
|
94895
93085
|
}
|
|
94896
|
-
var STAGE3 = "acp
|
|
93086
|
+
var STAGE3 = "acp", DEFAULT_MAX_INTERACTIONS = 10;
|
|
94897
93087
|
var init_turn_loop2 = __esm(() => {
|
|
94898
93088
|
init_src();
|
|
94899
93089
|
init_errors4();
|
|
@@ -94907,7 +93097,7 @@ var init_turn_loop2 = __esm(() => {
|
|
|
94907
93097
|
init_stream_bridge();
|
|
94908
93098
|
});
|
|
94909
93099
|
|
|
94910
|
-
// src/agents/acp
|
|
93100
|
+
// src/agents/acp/complete.ts
|
|
94911
93101
|
function sessionOptsFor(adapterName, options, timeoutMs) {
|
|
94912
93102
|
return {
|
|
94913
93103
|
agentName: adapterName,
|
|
@@ -94962,7 +93152,7 @@ async function runComplete(adapterName, agent, prompt, options) {
|
|
|
94962
93152
|
}
|
|
94963
93153
|
const session2 = await openClassified(name, agent, sessionOptsFor(adapterName, options, timeoutMs));
|
|
94964
93154
|
try {
|
|
94965
|
-
const result = await
|
|
93155
|
+
const result = await runTurnLoop(session2, prompt, {
|
|
94966
93156
|
interactionHandler: NO_OP_INTERACTION_HANDLER2,
|
|
94967
93157
|
maxInteractions: 1,
|
|
94968
93158
|
...options.signal === undefined ? {} : { signal: options.signal }
|
|
@@ -94989,7 +93179,7 @@ async function openClassified(name, agent, opts) {
|
|
|
94989
93179
|
throw new SessionFailureError(failure3.message, failure3.adapterFailure);
|
|
94990
93180
|
}
|
|
94991
93181
|
}
|
|
94992
|
-
var STAGE4 = "acp
|
|
93182
|
+
var STAGE4 = "acp", DEFAULT_COMPLETE_TIMEOUT_MS = 120000, MS_PER_SECOND = 1000;
|
|
94993
93183
|
var init_complete2 = __esm(() => {
|
|
94994
93184
|
init_src();
|
|
94995
93185
|
init_errors4();
|
|
@@ -95003,11 +93193,11 @@ var init_complete2 = __esm(() => {
|
|
|
95003
93193
|
init_turn_loop2();
|
|
95004
93194
|
});
|
|
95005
93195
|
|
|
95006
|
-
// src/agents/acp
|
|
95007
|
-
function
|
|
93196
|
+
// src/agents/acp/entries.ts
|
|
93197
|
+
function acpEntry(agentName) {
|
|
95008
93198
|
return Object.hasOwn(ENTRIES, agentName) ? ENTRIES[agentName] : undefined;
|
|
95009
93199
|
}
|
|
95010
|
-
var ENTRIES,
|
|
93200
|
+
var ENTRIES, ACP_AGENT_NAMES2, UNSUPPORTED_ENTRY;
|
|
95011
93201
|
var init_entries = __esm(() => {
|
|
95012
93202
|
ENTRIES = Object.freeze({
|
|
95013
93203
|
claude: {
|
|
@@ -95046,7 +93236,7 @@ var init_entries = __esm(() => {
|
|
|
95046
93236
|
maxContextTokens: 128000
|
|
95047
93237
|
}
|
|
95048
93238
|
});
|
|
95049
|
-
|
|
93239
|
+
ACP_AGENT_NAMES2 = new Set(Object.keys(ENTRIES));
|
|
95050
93240
|
UNSUPPORTED_ENTRY = Object.freeze({
|
|
95051
93241
|
binary: "",
|
|
95052
93242
|
displayName: "ACP Agent",
|
|
@@ -95055,7 +93245,7 @@ var init_entries = __esm(() => {
|
|
|
95055
93245
|
});
|
|
95056
93246
|
});
|
|
95057
93247
|
|
|
95058
|
-
// src/agents/acp
|
|
93248
|
+
// src/agents/acp/adapter.ts
|
|
95059
93249
|
function notifyEstablished(opts, protocolIds, name) {
|
|
95060
93250
|
if (opts.onSessionEstablished === undefined || protocolIds === undefined)
|
|
95061
93251
|
return;
|
|
@@ -95069,7 +93259,7 @@ function notifyEstablished(opts, protocolIds, name) {
|
|
|
95069
93259
|
}
|
|
95070
93260
|
}
|
|
95071
93261
|
|
|
95072
|
-
class
|
|
93262
|
+
class AcpAgentAdapter {
|
|
95073
93263
|
name;
|
|
95074
93264
|
displayName;
|
|
95075
93265
|
binary;
|
|
@@ -95077,7 +93267,7 @@ class AcpSdkAgentAdapter {
|
|
|
95077
93267
|
entry;
|
|
95078
93268
|
live = new Map;
|
|
95079
93269
|
constructor(agentName) {
|
|
95080
|
-
this.entry =
|
|
93270
|
+
this.entry = acpEntry(agentName);
|
|
95081
93271
|
const shown2 = this.entry ?? UNSUPPORTED_ENTRY;
|
|
95082
93272
|
this.name = agentName;
|
|
95083
93273
|
this.displayName = shown2.displayName;
|
|
@@ -95089,10 +93279,10 @@ class AcpSdkAgentAdapter {
|
|
|
95089
93279
|
};
|
|
95090
93280
|
}
|
|
95091
93281
|
async isInstalled() {
|
|
95092
|
-
return this.entry !== undefined &&
|
|
93282
|
+
return this.entry !== undefined && _acpDeps.launchCandidateKind(this.entry.agent) !== undefined;
|
|
95093
93283
|
}
|
|
95094
93284
|
launchNote() {
|
|
95095
|
-
if (this.entry === undefined ||
|
|
93285
|
+
if (this.entry === undefined || _acpDeps.launchCandidateKind(this.entry.agent) !== "npx")
|
|
95096
93286
|
return;
|
|
95097
93287
|
return `Only the npx fallback can launch ACP agent "${this.name}"; the first run downloads it inside the startup deadline`;
|
|
95098
93288
|
}
|
|
@@ -95130,7 +93320,7 @@ class AcpSdkAgentAdapter {
|
|
|
95130
93320
|
return session2.handle;
|
|
95131
93321
|
}
|
|
95132
93322
|
async sendTurn(handle2, prompt, opts) {
|
|
95133
|
-
return
|
|
93323
|
+
return runTurnLoop(this.sessionFor(handle2.id), prompt, opts);
|
|
95134
93324
|
}
|
|
95135
93325
|
async closeSession(handle2) {
|
|
95136
93326
|
const session2 = this.live.get(handle2.id);
|
|
@@ -95155,12 +93345,12 @@ class AcpSdkAgentAdapter {
|
|
|
95155
93345
|
requireEntry(sessionName) {
|
|
95156
93346
|
if (this.entry !== undefined)
|
|
95157
93347
|
return this.entry;
|
|
95158
|
-
throw new NaxError(`Agent "${this.name}" has no ACP launcher
|
|
93348
|
+
throw new NaxError(`Agent "${this.name}" has no ACP launcher, so it cannot run as an ACP agent`, "ACP_AGENT_UNSUPPORTED", { stage: STAGE5, agentName: this.name, sessionName });
|
|
95159
93349
|
}
|
|
95160
93350
|
async requireWorkdir(sessionName, workdir) {
|
|
95161
|
-
if (await
|
|
93351
|
+
if (await _acpDeps.cwdExists(workdir))
|
|
95162
93352
|
return;
|
|
95163
|
-
throw new NaxError(`[acp
|
|
93353
|
+
throw new NaxError(`[acp] Session cwd does not exist: ${workdir} \u2014 cannot start agent "${this.name}". If this is a new package for the feature, ensure its directory is created before the run.`, "SESSION_CWD_MISSING", { stage: "open-session", agentName: this.name, cwd: workdir, sessionName });
|
|
95164
93354
|
}
|
|
95165
93355
|
sessionFor(id) {
|
|
95166
93356
|
const session2 = this.live.get(id);
|
|
@@ -95172,8 +93362,8 @@ class AcpSdkAgentAdapter {
|
|
|
95172
93362
|
});
|
|
95173
93363
|
}
|
|
95174
93364
|
}
|
|
95175
|
-
var STAGE5 = "acp
|
|
95176
|
-
var
|
|
93365
|
+
var STAGE5 = "acp";
|
|
93366
|
+
var init_adapter = __esm(() => {
|
|
95177
93367
|
init_errors4();
|
|
95178
93368
|
init_logger2();
|
|
95179
93369
|
init_env();
|
|
@@ -95184,9 +93374,17 @@ var init_adapter2 = __esm(() => {
|
|
|
95184
93374
|
init_turn_loop2();
|
|
95185
93375
|
});
|
|
95186
93376
|
|
|
95187
|
-
// src/agents/acp
|
|
95188
|
-
var
|
|
95189
|
-
|
|
93377
|
+
// src/agents/acp/index.ts
|
|
93378
|
+
var exports_acp = {};
|
|
93379
|
+
__export(exports_acp, {
|
|
93380
|
+
ACP_AGENT_NAMES: () => ACP_AGENT_NAMES2,
|
|
93381
|
+
AcpAgentAdapter: () => AcpAgentAdapter,
|
|
93382
|
+
_acpDeps: () => _acpDeps,
|
|
93383
|
+
acpEntry: () => acpEntry,
|
|
93384
|
+
discardAcpSessionLeftover: () => discardAcpSessionLeftover
|
|
93385
|
+
});
|
|
93386
|
+
var init_acp2 = __esm(() => {
|
|
93387
|
+
init_adapter();
|
|
95190
93388
|
init_entries();
|
|
95191
93389
|
init_session3();
|
|
95192
93390
|
});
|
|
@@ -95246,11 +93444,11 @@ var init_native_agent = __esm(() => {
|
|
|
95246
93444
|
});
|
|
95247
93445
|
|
|
95248
93446
|
// src/agents/registry.ts
|
|
95249
|
-
function acpAdapterFor(name
|
|
95250
|
-
return
|
|
93447
|
+
function acpAdapterFor(name) {
|
|
93448
|
+
return new AcpAgentAdapter(name);
|
|
95251
93449
|
}
|
|
95252
93450
|
function adapterFor(name) {
|
|
95253
|
-
return name === NATIVE_AGENT_NAME ? new NativeAgentAdapter : acpAdapterFor(name
|
|
93451
|
+
return name === NATIVE_AGENT_NAME ? new NativeAgentAdapter : acpAdapterFor(name);
|
|
95254
93452
|
}
|
|
95255
93453
|
function buildAdapterList() {
|
|
95256
93454
|
return [...Array.from(_registryTestAdapters.values()), ...KNOWN_AGENT_NAMES.map(adapterFor)];
|
|
@@ -95268,14 +93466,10 @@ function createAgentRegistry(config2) {
|
|
|
95268
93466
|
const adapterCache = new Map;
|
|
95269
93467
|
const protocol = config2.agent?.protocol ?? DEFAULT_AGENT_PROTOCOL;
|
|
95270
93468
|
logger?.info("agents", `Agent protocol: ${protocol}`, { protocol, hasConfig: !!config2.agent });
|
|
95271
|
-
const transport = config2.agent?.acp?.transport ?? DEFAULT_ACP_TRANSPORT;
|
|
95272
|
-
if (transport !== DEFAULT_ACP_TRANSPORT) {
|
|
95273
|
-
logger?.info("agents", `ACP transport: ${transport} (S4b development key)`, { transport });
|
|
95274
|
-
}
|
|
95275
93469
|
function cachedAdapter(name) {
|
|
95276
93470
|
let adapter = adapterCache.get(name);
|
|
95277
93471
|
if (adapter === undefined) {
|
|
95278
|
-
adapter = name === NATIVE_AGENT_NAME ? new NativeAgentAdapter(undefined, config2.agent?.native?.catalogOverrides ?? []) : acpAdapterFor(name
|
|
93472
|
+
adapter = name === NATIVE_AGENT_NAME ? new NativeAgentAdapter(undefined, config2.agent?.native?.catalogOverrides ?? []) : acpAdapterFor(name);
|
|
95279
93473
|
adapterCache.set(name, adapter);
|
|
95280
93474
|
logger?.debug("agents", `Created ${adapter.constructor.name} for ${name}`, { name });
|
|
95281
93475
|
}
|
|
@@ -95312,8 +93506,7 @@ var init_registry6 = __esm(() => {
|
|
|
95312
93506
|
init_src();
|
|
95313
93507
|
init_config();
|
|
95314
93508
|
init_logger2();
|
|
95315
|
-
|
|
95316
|
-
init_acp_sdk();
|
|
93509
|
+
init_acp2();
|
|
95317
93510
|
init_native_agent();
|
|
95318
93511
|
KNOWN_AGENT_NAMES = ["claude", "codex", "opencode", "gemini", "aider", "pi", NATIVE_AGENT_NAME];
|
|
95319
93512
|
_registryTestAdapters = new Map;
|
|
@@ -95938,7 +94131,6 @@ var init_utils = __esm(() => {
|
|
|
95938
94131
|
// src/agents/index.ts
|
|
95939
94132
|
var init_agents = __esm(() => {
|
|
95940
94133
|
init_src();
|
|
95941
|
-
init_acp();
|
|
95942
94134
|
init_complete_exception_classifier();
|
|
95943
94135
|
init_cost();
|
|
95944
94136
|
init_manager2();
|
|
@@ -95954,8 +94146,7 @@ var init_agents = __esm(() => {
|
|
|
95954
94146
|
// src/cli/agents.ts
|
|
95955
94147
|
async function agentsListCommand(config2, _workdir) {
|
|
95956
94148
|
const acpReachable = (config2.agent?.protocol ?? DEFAULT_AGENT_PROTOCOL) !== "native";
|
|
95957
|
-
const
|
|
95958
|
-
const adapters = acpReachable ? Array.from(ACP_SDK_AGENT_NAMES).map((name) => acpAdapterFor(name, transport)) : [];
|
|
94149
|
+
const adapters = acpReachable ? Array.from(ACP_AGENT_NAMES2).map((name) => acpAdapterFor(name)) : [];
|
|
95959
94150
|
const defaultAgent = resolveDefaultAgent(config2);
|
|
95960
94151
|
const acpVersions = await Promise.all(adapters.map(async (agent) => ({
|
|
95961
94152
|
name: agent.name,
|
|
@@ -96023,7 +94214,7 @@ var _cliAgentsDeps;
|
|
|
96023
94214
|
var init_agents2 = __esm(() => {
|
|
96024
94215
|
init_src();
|
|
96025
94216
|
init_agents();
|
|
96026
|
-
|
|
94217
|
+
init_acp2();
|
|
96027
94218
|
init_native_agent();
|
|
96028
94219
|
init_version_detection();
|
|
96029
94220
|
init_config();
|
|
@@ -97065,7 +95256,6 @@ var init_config_descriptions = __esm(() => {
|
|
|
97065
95256
|
agent: "Agent protocol configuration (ACP-003)",
|
|
97066
95257
|
"agent.protocol": "Protocol for agent communication: 'acp' (default) | 'native' | 'hybrid'",
|
|
97067
95258
|
"agent.acp": "ACP agent transport settings (claude, codex, opencode, gemini, pi)",
|
|
97068
|
-
"agent.acp.transport": "How ACP agents are driven: 'sdk' (default) uses @nathapp/nax-agent-acp in-process; 'acpx' shells out to the acpx CLI (S4b development key; S4b-5 removes acpx and this key)",
|
|
97069
95259
|
"agent.native.instructionFileName": "Repository instruction filename (default: AGENTS.md). Custom Markdown basenames load without AGENTS/CLAUDE fallbacks.",
|
|
97070
95260
|
"agent.native.catalogOverrides": "Native only. Explicit catalog entries for model ids newer than the bundled pi-ai snapshot, plus optional provider-wide baseUrl/headers.",
|
|
97071
95261
|
"agent.native.catalogOverrides.baseUrl": "Provider-wide endpoint redirect. WARNING: applies to EVERY model of that provider, bundled ones included, and the provider's stored credential is sent to this host. https only (http allowed for localhost/127.0.0.1); credentials in the URL are rejected.",
|
|
@@ -97087,7 +95277,7 @@ var init_config_descriptions = __esm(() => {
|
|
|
97087
95277
|
"agent.spinBreaker.stopAfterNoProgressSeconds": "Seconds with no new call key after which a repeat run ends the turn so a slow spin stops as fail-spin before the tool-call-only idle watchdog cancels it as fail-stale (default: half agent.idleWatchdog.toolCallOnlyIdleTimeoutSeconds, 900 when that watchdog is off; 0 disables) (nax#2017)",
|
|
97088
95278
|
"quality.testing": "Hermetic test enforcement \u2014 per-package overridable (ENH-010)",
|
|
97089
95279
|
"quality.testing.hermetic": "Inject hermetic test requirement into prompts \u2014 never call real external services in tests (default: true)",
|
|
97090
|
-
"quality.testing.externalBoundaries": "Project-specific CLI tools/clients to mock (e.g. ['claude', '
|
|
95280
|
+
"quality.testing.externalBoundaries": "Project-specific CLI tools/clients to mock (e.g. ['claude', 'gh', 'redis'])",
|
|
97091
95281
|
"quality.testing.mockGuidance": "Project-specific mocking guidance injected verbatim into the prompt",
|
|
97092
95282
|
mcp: "External MCP servers the native agent may call tools on (client only; nax is not an MCP server)",
|
|
97093
95283
|
"mcp.servers": "Map of server id to server block. The id is the tool-name namespace: a tool named search_graph on server codebase-memory is advertised as codebase-memory__search_graph",
|
|
@@ -107976,7 +106166,7 @@ var init_escalation = __esm(() => {
|
|
|
107976
106166
|
});
|
|
107977
106167
|
|
|
107978
106168
|
// src/execution/lock.ts
|
|
107979
|
-
import { randomUUID as
|
|
106169
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
107980
106170
|
import { rename as rename6, unlink as unlink6 } from "fs/promises";
|
|
107981
106171
|
import { hostname as hostname3 } from "os";
|
|
107982
106172
|
import path14 from "path";
|
|
@@ -108020,7 +106210,7 @@ function parseHolder(raw) {
|
|
|
108020
106210
|
}
|
|
108021
106211
|
}
|
|
108022
106212
|
async function publishFileAtomically(targetPath, content) {
|
|
108023
|
-
const tempPath = `${targetPath}.${
|
|
106213
|
+
const tempPath = `${targetPath}.${randomUUID15()}.tmp`;
|
|
108024
106214
|
try {
|
|
108025
106215
|
await Bun.write(tempPath, content);
|
|
108026
106216
|
const fs = await import("fs");
|
|
@@ -110783,7 +108973,7 @@ var init_scope_files = __esm(() => {
|
|
|
110783
108973
|
});
|
|
110784
108974
|
|
|
110785
108975
|
// src/pipeline/stages/context.ts
|
|
110786
|
-
import { randomUUID as
|
|
108976
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
110787
108977
|
import { join as join99 } from "path";
|
|
110788
108978
|
async function runV2Path(ctx) {
|
|
110789
108979
|
const logger = getLogger2();
|
|
@@ -111024,7 +109214,7 @@ var init_context3 = __esm(() => {
|
|
|
111024
109214
|
createOrchestrator: createDefaultOrchestrator,
|
|
111025
109215
|
loadPlugins: loadPluginProviders,
|
|
111026
109216
|
v1FeatureProvider: () => new FeatureContextProvider,
|
|
111027
|
-
uuid: () =>
|
|
109217
|
+
uuid: () => randomUUID16(),
|
|
111028
109218
|
readDigest: readDigestFile,
|
|
111029
109219
|
writeDigest: writeDigestFile,
|
|
111030
109220
|
loadFeatureManifests,
|
|
@@ -111847,52 +110037,9 @@ var exports_merge_conflict_rectify = {};
|
|
|
111847
110037
|
__export(exports_merge_conflict_rectify, {
|
|
111848
110038
|
_mergeRectifyDeps: () => _mergeRectifyDeps,
|
|
111849
110039
|
buildRectificationPipelineContext: () => buildRectificationPipelineContext,
|
|
111850
|
-
closeStaleAcpSession: () => closeStaleAcpSession,
|
|
111851
|
-
evictStaleSessions: () => evictStaleSessions,
|
|
111852
110040
|
rectifyConflictedStory: () => rectifyConflictedStory,
|
|
111853
110041
|
rectifyMergeFailure: () => rectifyMergeFailure
|
|
111854
110042
|
});
|
|
111855
|
-
async function closeStaleAcpSession(worktreePath, sessionName) {
|
|
111856
|
-
const logger = getSafeLogger2();
|
|
111857
|
-
try {
|
|
111858
|
-
const cmd = ["acpx", "--cwd", worktreePath, "claude", "sessions", "close", sessionName];
|
|
111859
|
-
logger?.debug("parallel", "Closing stale ACP session before rectification", { sessionName });
|
|
111860
|
-
const proc = _mergeRectifyDeps.typedSpawn(cmd, {
|
|
111861
|
-
stdout: "pipe",
|
|
111862
|
-
stderr: "pipe",
|
|
111863
|
-
detached: true
|
|
111864
|
-
});
|
|
111865
|
-
let timedOut = false;
|
|
111866
|
-
await new Promise((resolve39) => {
|
|
111867
|
-
let settled2 = false;
|
|
111868
|
-
const finish = () => {
|
|
111869
|
-
if (settled2)
|
|
111870
|
-
return;
|
|
111871
|
-
settled2 = true;
|
|
111872
|
-
clearTimeout(timer);
|
|
111873
|
-
resolve39();
|
|
111874
|
-
};
|
|
111875
|
-
const timer = setTimeout(() => {
|
|
111876
|
-
timedOut = true;
|
|
111877
|
-
try {
|
|
111878
|
-
_mergeRectifyDeps.killProcessGroup(proc.pid, "SIGKILL");
|
|
111879
|
-
} catch {}
|
|
111880
|
-
finish();
|
|
111881
|
-
}, _mergeRectifyDeps.timeoutMs);
|
|
111882
|
-
proc.exited.then(finish, finish);
|
|
111883
|
-
});
|
|
111884
|
-
if (timedOut) {
|
|
111885
|
-
logger?.debug("parallel", "Stale ACP session eviction timed out \u2014 swallowed (best-effort)", {
|
|
111886
|
-
sessionName,
|
|
111887
|
-
timeoutMs: _mergeRectifyDeps.timeoutMs
|
|
111888
|
-
});
|
|
111889
|
-
}
|
|
111890
|
-
} catch {}
|
|
111891
|
-
}
|
|
111892
|
-
async function evictStaleSessions(worktreePath) {
|
|
111893
|
-
const cwd = worktreePath ?? ".";
|
|
111894
|
-
await closeStaleAcpSession(cwd, "nax-evict-stale-sentinel");
|
|
111895
|
-
}
|
|
111896
110043
|
function rectifyMergeFailure(storyId, cost, mergeResult) {
|
|
111897
110044
|
return {
|
|
111898
110045
|
success: false,
|
|
@@ -111945,7 +110092,11 @@ async function rectifyConflictedStory(options) {
|
|
|
111945
110092
|
storyId,
|
|
111946
110093
|
role: "main"
|
|
111947
110094
|
});
|
|
111948
|
-
|
|
110095
|
+
const transcriptDir = deriveNativeTranscriptDir({
|
|
110096
|
+
featureName: prd.feature,
|
|
110097
|
+
transcriptRoot: pipelineContextBase.runtime.outputDir
|
|
110098
|
+
});
|
|
110099
|
+
await _mergeRectifyDeps.discardStaleSession(transcriptDir, staleSessionName).catch(() => {});
|
|
111949
110100
|
const story = prd.userStories.find((s) => s.id === storyId);
|
|
111950
110101
|
if (!story) {
|
|
111951
110102
|
return { success: false, storyId, cost: 0, finalConflict: false, pipelineFailure: true };
|
|
@@ -111992,18 +110143,18 @@ async function rectifyConflictedStory(options) {
|
|
|
111992
110143
|
return { success: false, storyId, cost: 0, finalConflict: false, pipelineFailure: true };
|
|
111993
110144
|
}
|
|
111994
110145
|
}
|
|
111995
|
-
var
|
|
110146
|
+
var _mergeRectifyDeps;
|
|
111996
110147
|
var init_merge_conflict_rectify = __esm(() => {
|
|
111997
110148
|
init_internal();
|
|
111998
|
-
init_bun_deps();
|
|
111999
110149
|
init_logger2();
|
|
110150
|
+
init_manager_deps();
|
|
112000
110151
|
init_worktree();
|
|
112001
110152
|
init_parallel_worker();
|
|
112002
110153
|
_mergeRectifyDeps = {
|
|
112003
|
-
|
|
112004
|
-
|
|
112005
|
-
|
|
112006
|
-
|
|
110154
|
+
discardStaleSession: async (transcriptDir, name) => {
|
|
110155
|
+
const { discardAcpSessionLeftover: discardAcpSessionLeftover2 } = await Promise.resolve().then(() => (init_acp2(), exports_acp));
|
|
110156
|
+
await discardAcpSessionLeftover2(transcriptDir, name);
|
|
110157
|
+
}
|
|
112007
110158
|
};
|
|
112008
110159
|
});
|
|
112009
110160
|
|
|
@@ -113937,7 +112088,7 @@ var init_run_cleanup = __esm(() => {
|
|
|
113937
112088
|
});
|
|
113938
112089
|
|
|
113939
112090
|
// src/execution/session-manager-runtime.ts
|
|
113940
|
-
async function
|
|
112091
|
+
async function closePhysicalSession(descriptor, agentGetFn, force, signal) {
|
|
113941
112092
|
if (!descriptor.handle)
|
|
113942
112093
|
return;
|
|
113943
112094
|
const adapter = agentGetFn?.(descriptor.agent);
|
|
@@ -113956,7 +112107,7 @@ async function closeStorylessSession(sessionManager, descriptor, agentGetFn, opt
|
|
|
113956
112107
|
} catch {}
|
|
113957
112108
|
}
|
|
113958
112109
|
const force = opts?.force === true || descriptor.state === "FAILED";
|
|
113959
|
-
await
|
|
112110
|
+
await closePhysicalSession(descriptor, agentGetFn, force, opts?.signal);
|
|
113960
112111
|
return 1;
|
|
113961
112112
|
}
|
|
113962
112113
|
function getStorylessCloseChain(state) {
|
|
@@ -113979,7 +112130,7 @@ async function closeStorySessions(sessionManager, storyId, agentGetFn, opts) {
|
|
|
113979
112130
|
const closedSessions = sessionManager.closeStory(storyId);
|
|
113980
112131
|
for (const descriptor of closedSessions) {
|
|
113981
112132
|
const force = opts?.force === true || descriptor.state === "FAILED";
|
|
113982
|
-
await
|
|
112133
|
+
await closePhysicalSession(descriptor, agentGetFn, force, opts?.signal);
|
|
113983
112134
|
}
|
|
113984
112135
|
return closedSessions.length;
|
|
113985
112136
|
}
|
|
@@ -113996,7 +112147,7 @@ async function failAndClose(sessionManager, sessionId, agentGetFn) {
|
|
|
113996
112147
|
}
|
|
113997
112148
|
const failed3 = sessionManager.get(sessionId);
|
|
113998
112149
|
if (failed3) {
|
|
113999
|
-
await
|
|
112150
|
+
await closePhysicalSession(failed3, agentGetFn, true);
|
|
114000
112151
|
}
|
|
114001
112152
|
}
|
|
114002
112153
|
async function closeAllRunSessions(sessionManager, agentGetFn, opts) {
|
|
@@ -118999,14 +117150,14 @@ var init_gitignore_reconcile = __esm(() => {
|
|
|
118999
117150
|
});
|
|
119000
117151
|
|
|
119001
117152
|
// src/review/language-commands.ts
|
|
119002
|
-
function resolveLanguageCommand(language, check2,
|
|
117153
|
+
function resolveLanguageCommand(language, check2, which2) {
|
|
119003
117154
|
const languageTable = LANGUAGE_COMMANDS[language];
|
|
119004
117155
|
if (!languageTable)
|
|
119005
117156
|
return null;
|
|
119006
117157
|
const entry2 = languageTable[check2];
|
|
119007
117158
|
if (!entry2)
|
|
119008
117159
|
return null;
|
|
119009
|
-
const binaryPath =
|
|
117160
|
+
const binaryPath = which2(entry2.binary);
|
|
119010
117161
|
if (!binaryPath)
|
|
119011
117162
|
return null;
|
|
119012
117163
|
return entry2.command;
|
|
@@ -129141,7 +127292,7 @@ async function checkCanonicalRulesLint(workdir) {
|
|
|
129141
127292
|
let ruleCount = 0;
|
|
129142
127293
|
try {
|
|
129143
127294
|
for (const root of roots) {
|
|
129144
|
-
const rules = await _checkCanonicalRulesDeps.loadCanonicalRules(root);
|
|
127295
|
+
const rules = await _checkCanonicalRulesDeps.loadCanonicalRules(root, { onInvalidFrontmatter: "throw" });
|
|
129145
127296
|
ruleCount += rules.length;
|
|
129146
127297
|
}
|
|
129147
127298
|
} catch (err) {
|
|
@@ -129155,6 +127306,16 @@ async function checkCanonicalRulesLint(workdir) {
|
|
|
129155
127306
|
message: `Canonical rules lint failed (${err.violations.length} violation(s)): ${detail}`
|
|
129156
127307
|
};
|
|
129157
127308
|
}
|
|
127309
|
+
if (err instanceof RulesFrontmatterLintError) {
|
|
127310
|
+
const first = err.issues[0];
|
|
127311
|
+
const detail = first ? `${first.file}: ${first.message}` : "unknown location";
|
|
127312
|
+
return {
|
|
127313
|
+
name: "canonical-rules-lint",
|
|
127314
|
+
tier: "blocker",
|
|
127315
|
+
passed: false,
|
|
127316
|
+
message: `Canonical rules lint failed (${err.issues.length} file(s) with invalid frontmatter): ${detail}`
|
|
127317
|
+
};
|
|
127318
|
+
}
|
|
129158
127319
|
return {
|
|
129159
127320
|
name: "canonical-rules-lint",
|
|
129160
127321
|
tier: "blocker",
|
|
@@ -129503,10 +127664,10 @@ async function findMissingNativeCredentials(config2) {
|
|
|
129503
127664
|
function describeMissingNativeCredentials(missing) {
|
|
129504
127665
|
const uses = missing.map(({ provider: provider2, tiers }) => `${provider2} (${tiers.map((tier) => `models.native.${tier}`).join(", ")})`).join("; ");
|
|
129505
127666
|
const logins = missing.map(({ provider: provider2 }) => `nax auth login ${provider2}`).join(" / ");
|
|
129506
|
-
return `The default native agent needs a credential for ${uses}, but none is stored or in the environment. ` + `Run ${logins}, set the provider's API key environment variable, point models.native at a provider you have ` + `credentials for, or set agent.default "claude" to use an
|
|
127667
|
+
return `The default native agent needs a credential for ${uses}, but none is stored or in the environment. ` + `Run ${logins}, set the provider's API key environment variable, point models.native at a provider you have ` + `credentials for, or set agent.default "claude" to use an ACP agent.`;
|
|
129507
127668
|
}
|
|
129508
127669
|
function describeCredentialFault(error48) {
|
|
129509
|
-
return `The default native agent's credentials could not be read (${error48.code}): ${error48.message} ` + `Fix the credential source, or set agent.default "claude" to use an
|
|
127670
|
+
return `The default native agent's credentials could not be read (${error48.code}): ${error48.message} ` + `Fix the credential source, or set agent.default "claude" to use an ACP agent.`;
|
|
129510
127671
|
}
|
|
129511
127672
|
async function checkNativeCredentials(config2) {
|
|
129512
127673
|
try {
|
|
@@ -131767,6 +129928,69 @@ function collectCanonicalRuleRoots(workdir, globCanonicalRuleFiles = _rulesLintD
|
|
|
131767
129928
|
}
|
|
131768
129929
|
return [...roots].sort();
|
|
131769
129930
|
}
|
|
129931
|
+
async function loadRootForLint(root, deps) {
|
|
129932
|
+
try {
|
|
129933
|
+
const rules = await deps.loadCanonicalRules(root, { onInvalidFrontmatter: "throw" });
|
|
129934
|
+
return { kind: "loaded", rules };
|
|
129935
|
+
} catch (err) {
|
|
129936
|
+
if (err instanceof RulesFrontmatterLintError)
|
|
129937
|
+
return { kind: "frontmatter-errors", issues: err.issues };
|
|
129938
|
+
return { kind: "failed", cause: err };
|
|
129939
|
+
}
|
|
129940
|
+
}
|
|
129941
|
+
function reportFrontmatterIssues(issues, root, logger) {
|
|
129942
|
+
for (const issue2 of issues) {
|
|
129943
|
+
logger.error("rules-lint", "Canonical rule frontmatter is invalid \u2014 nax will ignore this file at run time", {
|
|
129944
|
+
file: issue2.file,
|
|
129945
|
+
error: issue2.message,
|
|
129946
|
+
root,
|
|
129947
|
+
code: "INVALID_FRONTMATTER"
|
|
129948
|
+
});
|
|
129949
|
+
}
|
|
129950
|
+
}
|
|
129951
|
+
function lintRulesForRoot(rules, root, isSinglePackageRepo, deps, logger) {
|
|
129952
|
+
let warningCount = 0;
|
|
129953
|
+
for (const rule of rules) {
|
|
129954
|
+
for (const warning of rule.warnings ?? []) {
|
|
129955
|
+
warningCount++;
|
|
129956
|
+
logger.warn("rules-lint", `Rule frontmatter warning: ${warning}`, {
|
|
129957
|
+
file: rule.path ?? rule.fileName,
|
|
129958
|
+
root
|
|
129959
|
+
});
|
|
129960
|
+
}
|
|
129961
|
+
for (const pattern of rule.appliesTo ?? []) {
|
|
129962
|
+
const globResult = deps.globHasMatch(pattern, root);
|
|
129963
|
+
if (globResult === "match")
|
|
129964
|
+
continue;
|
|
129965
|
+
warningCount++;
|
|
129966
|
+
if (globResult === "unknown") {
|
|
129967
|
+
logger.warn("rules-lint", "Canonical rule appliesTo glob could not be verified within the dead-glob scan cap", {
|
|
129968
|
+
file: rule.path ?? rule.fileName,
|
|
129969
|
+
pattern,
|
|
129970
|
+
root,
|
|
129971
|
+
code: "GLOB_SCAN_UNKNOWN"
|
|
129972
|
+
});
|
|
129973
|
+
continue;
|
|
129974
|
+
}
|
|
129975
|
+
logger.warn("rules-lint", "Canonical rule appliesTo glob matches no files in the linted repository", {
|
|
129976
|
+
file: rule.path ?? rule.fileName,
|
|
129977
|
+
pattern,
|
|
129978
|
+
root
|
|
129979
|
+
});
|
|
129980
|
+
}
|
|
129981
|
+
if (isSinglePackageRepo && rule.paths && rule.paths.length > 0) {
|
|
129982
|
+
warningCount++;
|
|
129983
|
+
logger.warn("rules-lint", "Canonical rule declares paths: but the repository has no workspace packages \u2014 paths: is inert in single-package repos. Use appliesTo: for file globs.", {
|
|
129984
|
+
file: join135(root, CANONICAL_RULES_DIR, rule.path ?? rule.fileName),
|
|
129985
|
+
code: "INERT_PATHS",
|
|
129986
|
+
paths: rule.paths,
|
|
129987
|
+
root,
|
|
129988
|
+
warningCount
|
|
129989
|
+
});
|
|
129990
|
+
}
|
|
129991
|
+
}
|
|
129992
|
+
return warningCount;
|
|
129993
|
+
}
|
|
131770
129994
|
async function rulesLintCommand(options, deps = _rulesLintDeps) {
|
|
131771
129995
|
const workdir = options.dir ?? process.cwd();
|
|
131772
129996
|
const roots = collectCanonicalRuleRoots(workdir, deps.globCanonicalRuleFiles);
|
|
@@ -131779,52 +130003,24 @@ async function rulesLintCommand(options, deps = _rulesLintDeps) {
|
|
|
131779
130003
|
}
|
|
131780
130004
|
let totalRuleFiles = 0;
|
|
131781
130005
|
let warningCount = 0;
|
|
130006
|
+
const frontmatterIssues = [];
|
|
131782
130007
|
const failedRoots = [];
|
|
131783
130008
|
for (const root of roots) {
|
|
131784
|
-
|
|
131785
|
-
|
|
131786
|
-
|
|
131787
|
-
} catch (err) {
|
|
131788
|
-
failedRoots.push({ root, cause: err });
|
|
130009
|
+
const load = await loadRootForLint(root, deps);
|
|
130010
|
+
if (load.kind === "failed") {
|
|
130011
|
+
failedRoots.push({ root, cause: load.cause });
|
|
131789
130012
|
continue;
|
|
131790
130013
|
}
|
|
131791
|
-
|
|
131792
|
-
|
|
131793
|
-
|
|
131794
|
-
|
|
131795
|
-
logger.warn("rules-lint", `Rule frontmatter warning: ${warning}`, {
|
|
131796
|
-
file: rule.path ?? rule.fileName,
|
|
131797
|
-
root
|
|
131798
|
-
});
|
|
131799
|
-
}
|
|
131800
|
-
for (const pattern of rule.appliesTo ?? []) {
|
|
131801
|
-
const globResult = deps.globHasMatch(pattern, root);
|
|
131802
|
-
if (globResult === "match")
|
|
131803
|
-
continue;
|
|
131804
|
-
warningCount++;
|
|
131805
|
-
if (globResult === "unknown") {
|
|
131806
|
-
logger.warn("rules-lint", "Canonical rule appliesTo glob could not be verified within the dead-glob scan cap", { file: rule.path ?? rule.fileName, pattern, root, code: "GLOB_SCAN_UNKNOWN" });
|
|
131807
|
-
continue;
|
|
131808
|
-
}
|
|
131809
|
-
logger.warn("rules-lint", "Canonical rule appliesTo glob matches no files in the linted repository", {
|
|
131810
|
-
file: rule.path ?? rule.fileName,
|
|
131811
|
-
pattern,
|
|
131812
|
-
root
|
|
131813
|
-
});
|
|
131814
|
-
}
|
|
131815
|
-
if (isSinglePackageRepo && rule.paths && rule.paths.length > 0) {
|
|
131816
|
-
warningCount++;
|
|
131817
|
-
logger.warn("rules-lint", "Canonical rule declares paths: but the repository has no workspace packages \u2014 paths: is inert in single-package repos. Use appliesTo: for file globs.", {
|
|
131818
|
-
file: join135(root, CANONICAL_RULES_DIR, rule.path ?? rule.fileName),
|
|
131819
|
-
code: "INERT_PATHS",
|
|
131820
|
-
paths: rule.paths,
|
|
131821
|
-
root,
|
|
131822
|
-
warningCount
|
|
131823
|
-
});
|
|
131824
|
-
}
|
|
130014
|
+
if (load.kind === "frontmatter-errors") {
|
|
130015
|
+
reportFrontmatterIssues(load.issues, root, logger);
|
|
130016
|
+
frontmatterIssues.push(...load.issues);
|
|
130017
|
+
continue;
|
|
131825
130018
|
}
|
|
130019
|
+
const rules = load.rules;
|
|
130020
|
+
totalRuleFiles += rules.length;
|
|
130021
|
+
warningCount += lintRulesForRoot(rules, root, isSinglePackageRepo, deps, logger);
|
|
131826
130022
|
}
|
|
131827
|
-
if (totalRuleFiles === 0 && failedRoots.length === 0) {
|
|
130023
|
+
if (totalRuleFiles === 0 && failedRoots.length === 0 && frontmatterIssues.length === 0) {
|
|
131828
130024
|
warningCount++;
|
|
131829
130025
|
logger.warn("rules-lint", "Canonical rules store is empty \u2014 no rule files found across any rule root. Run `nax rules migrate` to seed the store.", { code: "EMPTY_STORE", roots: roots.length });
|
|
131830
130026
|
}
|
|
@@ -131836,6 +130032,9 @@ async function rulesLintCommand(options, deps = _rulesLintDeps) {
|
|
|
131836
130032
|
causes: failedRoots.map((f) => f.cause)
|
|
131837
130033
|
});
|
|
131838
130034
|
}
|
|
130035
|
+
if (frontmatterIssues.length > 0) {
|
|
130036
|
+
throw new NaxError(`Canonical rules lint failed: ${frontmatterIssues.length} rule file(s) have invalid frontmatter. nax ignores these at run time; fix them so the rules actually load.`, "RULES_LINT_FAILED", { stage: "rules-lint", errorCount: frontmatterIssues.length, issues: frontmatterIssues });
|
|
130037
|
+
}
|
|
131839
130038
|
const scopeLabel = roots.length === 1 ? "repo root" : `${roots.length} rule roots`;
|
|
131840
130039
|
if (warningCount > 0) {
|
|
131841
130040
|
console.log(`[WARN] Canonical rules lint completed with ${warningCount} warning(s) (${totalRuleFiles} file(s) across ${scopeLabel}).`);
|
|
@@ -146207,12 +144406,7 @@ __export(exports_preflight, {
|
|
|
146207
144406
|
function parseCompareList(input) {
|
|
146208
144407
|
return input.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
146209
144408
|
}
|
|
146210
|
-
function
|
|
146211
|
-
const agent = profileData.agent;
|
|
146212
|
-
const transport = agent?.acp?.transport;
|
|
146213
|
-
return transport === "acpx" || transport === "sdk" ? transport : base2;
|
|
146214
|
-
}
|
|
146215
|
-
async function validateContestants(names, projectRoot, deps = _preflightDeps, baseTransport = DEFAULT_ACP_TRANSPORT) {
|
|
144409
|
+
async function validateContestants(names, projectRoot, deps = _preflightDeps) {
|
|
146216
144410
|
const hasAcpAdapterEntry = deps.hasAcpAdapterEntry ?? _preflightDeps.hasAcpAdapterEntry;
|
|
146217
144411
|
const loadProfileFn = deps.loadProfile ?? _preflightDeps.loadProfile;
|
|
146218
144412
|
if (!hasAcpAdapterEntry || !loadProfileFn) {
|
|
@@ -146248,7 +144442,7 @@ async function validateContestants(names, projectRoot, deps = _preflightDeps, ba
|
|
|
146248
144442
|
});
|
|
146249
144443
|
continue;
|
|
146250
144444
|
}
|
|
146251
|
-
if (!await deps.isInstalled(resolvedAgent
|
|
144445
|
+
if (!await deps.isInstalled(resolvedAgent)) {
|
|
146252
144446
|
errors5.push({
|
|
146253
144447
|
agent: name,
|
|
146254
144448
|
reason: "dnf-not-installed",
|
|
@@ -146334,15 +144528,15 @@ var BAKEOFF_BRANCH_PREFIX = "nax/bakeoff-", _preflightDeps;
|
|
|
146334
144528
|
var init_preflight = __esm(() => {
|
|
146335
144529
|
init_internal();
|
|
146336
144530
|
init_agents();
|
|
146337
|
-
|
|
144531
|
+
init_acp2();
|
|
146338
144532
|
init_config();
|
|
146339
144533
|
init_profile();
|
|
146340
144534
|
init_errors4();
|
|
146341
144535
|
init_logger2();
|
|
146342
144536
|
init_git2();
|
|
146343
144537
|
_preflightDeps = {
|
|
146344
|
-
isInstalled: (agentName
|
|
146345
|
-
hasAcpAdapterEntry: (name) =>
|
|
144538
|
+
isInstalled: (agentName) => acpAdapterFor(agentName).isInstalled(),
|
|
144539
|
+
hasAcpAdapterEntry: (name) => ACP_AGENT_NAMES2.has(name),
|
|
146346
144540
|
loadProfile: (profileName, projectRoot) => loadProfile(profileName, projectRoot)
|
|
146347
144541
|
};
|
|
146348
144542
|
});
|
|
@@ -146523,7 +144717,7 @@ async function persistBakeoffResult(result2, outputDir) {
|
|
|
146523
144717
|
async function runBakeoff(options, deps = {}) {
|
|
146524
144718
|
const merged2 = { ..._coordinatorDeps, ...deps };
|
|
146525
144719
|
await reclaimStaleBakeoffBranches(options.projectRoot);
|
|
146526
|
-
const { validAgents, errors: errors5, profileData } = await merged2.validateContestants(options.agents, options.projectRoot
|
|
144720
|
+
const { validAgents, errors: errors5, profileData } = await merged2.validateContestants(options.agents, options.projectRoot);
|
|
146527
144721
|
const results = [];
|
|
146528
144722
|
for (const agent of validAgents) {
|
|
146529
144723
|
const contestantOptions = {
|