@agentv/core 0.5.0 → 0.5.1
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/dist/index.cjs +1151 -1151
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1151 -1151
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1112,1323 +1112,1323 @@ function formatTimeoutSuffix(timeoutMs) {
|
|
|
1112
1112
|
return ` after ${seconds}s`;
|
|
1113
1113
|
}
|
|
1114
1114
|
|
|
1115
|
-
// src/evaluation/providers/
|
|
1116
|
-
var
|
|
1117
|
-
var
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1115
|
+
// src/evaluation/providers/codex.ts
|
|
1116
|
+
var import_node_child_process2 = require("child_process");
|
|
1117
|
+
var import_node_fs3 = require("fs");
|
|
1118
|
+
var import_promises3 = require("fs/promises");
|
|
1119
|
+
var import_node_os = require("os");
|
|
1120
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
1121
|
+
var import_node_util2 = require("util");
|
|
1122
|
+
|
|
1123
|
+
// src/evaluation/providers/preread.ts
|
|
1124
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
1125
|
+
function buildPromptDocument(request, inputFiles, options) {
|
|
1126
|
+
const parts = [];
|
|
1127
|
+
const guidelineFiles = collectGuidelineFiles(
|
|
1128
|
+
inputFiles,
|
|
1129
|
+
options?.guidelinePatterns ?? request.guideline_patterns,
|
|
1130
|
+
options?.guidelineOverrides
|
|
1131
|
+
);
|
|
1132
|
+
const inputFilesList = collectInputFiles(inputFiles);
|
|
1133
|
+
const nonGuidelineInputFiles = inputFilesList.filter(
|
|
1134
|
+
(file) => !guidelineFiles.includes(file)
|
|
1135
|
+
);
|
|
1136
|
+
const prereadBlock = buildMandatoryPrereadBlock(guidelineFiles, nonGuidelineInputFiles);
|
|
1137
|
+
if (prereadBlock.length > 0) {
|
|
1138
|
+
parts.push("\n", prereadBlock);
|
|
1132
1139
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
return
|
|
1139
|
-
text: this.cannedResponse,
|
|
1140
|
-
raw: {
|
|
1141
|
-
prompt: request.prompt,
|
|
1142
|
-
guidelines: request.guidelines
|
|
1143
|
-
}
|
|
1144
|
-
};
|
|
1140
|
+
parts.push("\n[[ ## user_query ## ]]\n", request.prompt.trim());
|
|
1141
|
+
return parts.join("\n").trim();
|
|
1142
|
+
}
|
|
1143
|
+
function normalizeInputFiles2(inputFiles) {
|
|
1144
|
+
if (!inputFiles || inputFiles.length === 0) {
|
|
1145
|
+
return void 0;
|
|
1145
1146
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1147
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
1148
|
+
for (const inputFile of inputFiles) {
|
|
1149
|
+
const absolutePath = import_node_path4.default.resolve(inputFile);
|
|
1150
|
+
if (!deduped.has(absolutePath)) {
|
|
1151
|
+
deduped.set(absolutePath, absolutePath);
|
|
1151
1152
|
}
|
|
1152
|
-
return this.delayMs;
|
|
1153
1153
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
var BASE_TARGET_SCHEMA = import_zod.z.object({
|
|
1160
|
-
name: import_zod.z.string().min(1, "target name is required"),
|
|
1161
|
-
provider: import_zod.z.string().min(1, "provider is required"),
|
|
1162
|
-
settings: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
1163
|
-
judge_target: import_zod.z.string().optional(),
|
|
1164
|
-
workers: import_zod.z.number().int().min(1).optional()
|
|
1165
|
-
});
|
|
1166
|
-
var DEFAULT_AZURE_API_VERSION = "2024-10-01-preview";
|
|
1167
|
-
function normalizeAzureApiVersion(value) {
|
|
1168
|
-
if (!value) {
|
|
1169
|
-
return DEFAULT_AZURE_API_VERSION;
|
|
1154
|
+
return Array.from(deduped.values());
|
|
1155
|
+
}
|
|
1156
|
+
function collectGuidelineFiles(inputFiles, guidelinePatterns, overrides) {
|
|
1157
|
+
if (!inputFiles || inputFiles.length === 0) {
|
|
1158
|
+
return [];
|
|
1170
1159
|
}
|
|
1171
|
-
const
|
|
1172
|
-
|
|
1173
|
-
|
|
1160
|
+
const unique = /* @__PURE__ */ new Map();
|
|
1161
|
+
for (const inputFile of inputFiles) {
|
|
1162
|
+
const absolutePath = import_node_path4.default.resolve(inputFile);
|
|
1163
|
+
if (overrides?.has(absolutePath)) {
|
|
1164
|
+
if (!unique.has(absolutePath)) {
|
|
1165
|
+
unique.set(absolutePath, absolutePath);
|
|
1166
|
+
}
|
|
1167
|
+
continue;
|
|
1168
|
+
}
|
|
1169
|
+
const normalized = absolutePath.split(import_node_path4.default.sep).join("/");
|
|
1170
|
+
if (isGuidelineFile(normalized, guidelinePatterns)) {
|
|
1171
|
+
if (!unique.has(absolutePath)) {
|
|
1172
|
+
unique.set(absolutePath, absolutePath);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1174
1175
|
}
|
|
1175
|
-
|
|
1176
|
-
return withoutPrefix.length > 0 ? withoutPrefix : DEFAULT_AZURE_API_VERSION;
|
|
1176
|
+
return Array.from(unique.values());
|
|
1177
1177
|
}
|
|
1178
|
-
function
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
const providerBatching = resolveOptionalBoolean(
|
|
1182
|
-
parsed.settings?.provider_batching ?? parsed.settings?.providerBatching
|
|
1183
|
-
);
|
|
1184
|
-
switch (provider) {
|
|
1185
|
-
case "azure":
|
|
1186
|
-
case "azure-openai":
|
|
1187
|
-
return {
|
|
1188
|
-
kind: "azure",
|
|
1189
|
-
name: parsed.name,
|
|
1190
|
-
judgeTarget: parsed.judge_target,
|
|
1191
|
-
workers: parsed.workers,
|
|
1192
|
-
providerBatching,
|
|
1193
|
-
config: resolveAzureConfig(parsed, env)
|
|
1194
|
-
};
|
|
1195
|
-
case "anthropic":
|
|
1196
|
-
return {
|
|
1197
|
-
kind: "anthropic",
|
|
1198
|
-
name: parsed.name,
|
|
1199
|
-
judgeTarget: parsed.judge_target,
|
|
1200
|
-
workers: parsed.workers,
|
|
1201
|
-
providerBatching,
|
|
1202
|
-
config: resolveAnthropicConfig(parsed, env)
|
|
1203
|
-
};
|
|
1204
|
-
case "gemini":
|
|
1205
|
-
case "google":
|
|
1206
|
-
case "google-gemini":
|
|
1207
|
-
return {
|
|
1208
|
-
kind: "gemini",
|
|
1209
|
-
name: parsed.name,
|
|
1210
|
-
judgeTarget: parsed.judge_target,
|
|
1211
|
-
workers: parsed.workers,
|
|
1212
|
-
providerBatching,
|
|
1213
|
-
config: resolveGeminiConfig(parsed, env)
|
|
1214
|
-
};
|
|
1215
|
-
case "codex":
|
|
1216
|
-
case "codex-cli":
|
|
1217
|
-
return {
|
|
1218
|
-
kind: "codex",
|
|
1219
|
-
name: parsed.name,
|
|
1220
|
-
judgeTarget: parsed.judge_target,
|
|
1221
|
-
workers: parsed.workers,
|
|
1222
|
-
providerBatching,
|
|
1223
|
-
config: resolveCodexConfig(parsed, env)
|
|
1224
|
-
};
|
|
1225
|
-
case "mock":
|
|
1226
|
-
return {
|
|
1227
|
-
kind: "mock",
|
|
1228
|
-
name: parsed.name,
|
|
1229
|
-
judgeTarget: parsed.judge_target,
|
|
1230
|
-
workers: parsed.workers,
|
|
1231
|
-
providerBatching,
|
|
1232
|
-
config: resolveMockConfig(parsed)
|
|
1233
|
-
};
|
|
1234
|
-
case "vscode":
|
|
1235
|
-
case "vscode-insiders":
|
|
1236
|
-
return {
|
|
1237
|
-
kind: provider,
|
|
1238
|
-
name: parsed.name,
|
|
1239
|
-
judgeTarget: parsed.judge_target,
|
|
1240
|
-
workers: parsed.workers,
|
|
1241
|
-
providerBatching,
|
|
1242
|
-
config: resolveVSCodeConfig(parsed, env, provider === "vscode-insiders")
|
|
1243
|
-
};
|
|
1244
|
-
case "cli":
|
|
1245
|
-
return {
|
|
1246
|
-
kind: "cli",
|
|
1247
|
-
name: parsed.name,
|
|
1248
|
-
judgeTarget: parsed.judge_target,
|
|
1249
|
-
workers: parsed.workers,
|
|
1250
|
-
providerBatching,
|
|
1251
|
-
config: resolveCliConfig(parsed, env)
|
|
1252
|
-
};
|
|
1253
|
-
default:
|
|
1254
|
-
throw new Error(`Unsupported provider '${parsed.provider}' in target '${parsed.name}'`);
|
|
1178
|
+
function collectInputFiles(inputFiles) {
|
|
1179
|
+
if (!inputFiles || inputFiles.length === 0) {
|
|
1180
|
+
return [];
|
|
1255
1181
|
}
|
|
1182
|
+
const unique = /* @__PURE__ */ new Map();
|
|
1183
|
+
for (const inputFile of inputFiles) {
|
|
1184
|
+
const absolutePath = import_node_path4.default.resolve(inputFile);
|
|
1185
|
+
if (!unique.has(absolutePath)) {
|
|
1186
|
+
unique.set(absolutePath, absolutePath);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
return Array.from(unique.values());
|
|
1256
1190
|
}
|
|
1257
|
-
function
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
const resourceName = resolveString(endpointSource, env, `${target.name} endpoint`);
|
|
1266
|
-
const apiKey = resolveString(apiKeySource, env, `${target.name} api key`);
|
|
1267
|
-
const deploymentName = resolveString(deploymentSource, env, `${target.name} deployment`);
|
|
1268
|
-
const version = normalizeAzureApiVersion(
|
|
1269
|
-
resolveOptionalString(versionSource, env, `${target.name} api version`)
|
|
1270
|
-
);
|
|
1271
|
-
const temperature = resolveOptionalNumber(temperatureSource, `${target.name} temperature`);
|
|
1272
|
-
const maxOutputTokens = resolveOptionalNumber(
|
|
1273
|
-
maxTokensSource,
|
|
1274
|
-
`${target.name} max output tokens`
|
|
1275
|
-
);
|
|
1276
|
-
return {
|
|
1277
|
-
resourceName,
|
|
1278
|
-
deploymentName,
|
|
1279
|
-
apiKey,
|
|
1280
|
-
version,
|
|
1281
|
-
temperature,
|
|
1282
|
-
maxOutputTokens
|
|
1283
|
-
};
|
|
1284
|
-
}
|
|
1285
|
-
function resolveAnthropicConfig(target, env) {
|
|
1286
|
-
const settings = target.settings ?? {};
|
|
1287
|
-
const apiKeySource = settings.api_key ?? settings.apiKey;
|
|
1288
|
-
const modelSource = settings.model ?? settings.deployment ?? settings.variant;
|
|
1289
|
-
const temperatureSource = settings.temperature;
|
|
1290
|
-
const maxTokensSource = settings.max_output_tokens ?? settings.maxTokens;
|
|
1291
|
-
const thinkingBudgetSource = settings.thinking_budget ?? settings.thinkingBudget;
|
|
1292
|
-
const apiKey = resolveString(apiKeySource, env, `${target.name} Anthropic api key`);
|
|
1293
|
-
const model = resolveString(modelSource, env, `${target.name} Anthropic model`);
|
|
1294
|
-
return {
|
|
1295
|
-
apiKey,
|
|
1296
|
-
model,
|
|
1297
|
-
temperature: resolveOptionalNumber(temperatureSource, `${target.name} temperature`),
|
|
1298
|
-
maxOutputTokens: resolveOptionalNumber(maxTokensSource, `${target.name} max output tokens`),
|
|
1299
|
-
thinkingBudget: resolveOptionalNumber(thinkingBudgetSource, `${target.name} thinking budget`)
|
|
1300
|
-
};
|
|
1301
|
-
}
|
|
1302
|
-
function resolveGeminiConfig(target, env) {
|
|
1303
|
-
const settings = target.settings ?? {};
|
|
1304
|
-
const apiKeySource = settings.api_key ?? settings.apiKey;
|
|
1305
|
-
const modelSource = settings.model ?? settings.deployment ?? settings.variant;
|
|
1306
|
-
const temperatureSource = settings.temperature;
|
|
1307
|
-
const maxTokensSource = settings.max_output_tokens ?? settings.maxTokens;
|
|
1308
|
-
const apiKey = resolveString(apiKeySource, env, `${target.name} Google API key`);
|
|
1309
|
-
const model = resolveOptionalString(modelSource, env, `${target.name} Gemini model`, {
|
|
1310
|
-
allowLiteral: true,
|
|
1311
|
-
optionalEnv: true
|
|
1312
|
-
}) ?? "gemini-2.5-flash";
|
|
1313
|
-
return {
|
|
1314
|
-
apiKey,
|
|
1315
|
-
model,
|
|
1316
|
-
temperature: resolveOptionalNumber(temperatureSource, `${target.name} temperature`),
|
|
1317
|
-
maxOutputTokens: resolveOptionalNumber(maxTokensSource, `${target.name} max output tokens`)
|
|
1318
|
-
};
|
|
1319
|
-
}
|
|
1320
|
-
function resolveCodexConfig(target, env) {
|
|
1321
|
-
const settings = target.settings ?? {};
|
|
1322
|
-
const executableSource = settings.executable ?? settings.command ?? settings.binary;
|
|
1323
|
-
const argsSource = settings.args ?? settings.arguments;
|
|
1324
|
-
const cwdSource = settings.cwd;
|
|
1325
|
-
const timeoutSource = settings.timeout_seconds ?? settings.timeoutSeconds;
|
|
1326
|
-
const executable = resolveOptionalString(executableSource, env, `${target.name} codex executable`, {
|
|
1327
|
-
allowLiteral: true,
|
|
1328
|
-
optionalEnv: true
|
|
1329
|
-
}) ?? "codex";
|
|
1330
|
-
const args = resolveOptionalStringArray(argsSource, env, `${target.name} codex args`);
|
|
1331
|
-
const cwd = resolveOptionalString(cwdSource, env, `${target.name} codex cwd`, {
|
|
1332
|
-
allowLiteral: true,
|
|
1333
|
-
optionalEnv: true
|
|
1334
|
-
});
|
|
1335
|
-
const timeoutMs = resolveTimeoutMs(timeoutSource, `${target.name} codex timeout`);
|
|
1336
|
-
return {
|
|
1337
|
-
executable,
|
|
1338
|
-
args,
|
|
1339
|
-
cwd,
|
|
1340
|
-
timeoutMs
|
|
1341
|
-
};
|
|
1342
|
-
}
|
|
1343
|
-
function resolveMockConfig(target) {
|
|
1344
|
-
const settings = target.settings ?? {};
|
|
1345
|
-
const response = typeof settings.response === "string" ? settings.response : void 0;
|
|
1346
|
-
return { response };
|
|
1347
|
-
}
|
|
1348
|
-
function resolveVSCodeConfig(target, env, insiders) {
|
|
1349
|
-
const settings = target.settings ?? {};
|
|
1350
|
-
const workspaceTemplateEnvVar = resolveOptionalLiteralString(settings.workspace_template ?? settings.workspaceTemplate);
|
|
1351
|
-
const workspaceTemplate = workspaceTemplateEnvVar ? resolveOptionalString(workspaceTemplateEnvVar, env, `${target.name} workspace template path`, {
|
|
1352
|
-
allowLiteral: false,
|
|
1353
|
-
optionalEnv: true
|
|
1354
|
-
}) : void 0;
|
|
1355
|
-
const commandSource = settings.vscode_cmd ?? settings.command;
|
|
1356
|
-
const waitSource = settings.wait;
|
|
1357
|
-
const dryRunSource = settings.dry_run ?? settings.dryRun;
|
|
1358
|
-
const subagentRootSource = settings.subagent_root ?? settings.subagentRoot;
|
|
1359
|
-
const defaultCommand = insiders ? "code-insiders" : "code";
|
|
1360
|
-
const command = resolveOptionalLiteralString(commandSource) ?? defaultCommand;
|
|
1361
|
-
return {
|
|
1362
|
-
command,
|
|
1363
|
-
waitForResponse: resolveOptionalBoolean(waitSource) ?? true,
|
|
1364
|
-
dryRun: resolveOptionalBoolean(dryRunSource) ?? false,
|
|
1365
|
-
subagentRoot: resolveOptionalString(subagentRootSource, env, `${target.name} subagent root`, {
|
|
1366
|
-
allowLiteral: true,
|
|
1367
|
-
optionalEnv: true
|
|
1368
|
-
}),
|
|
1369
|
-
workspaceTemplate
|
|
1370
|
-
};
|
|
1371
|
-
}
|
|
1372
|
-
function resolveCliConfig(target, env) {
|
|
1373
|
-
const settings = target.settings ?? {};
|
|
1374
|
-
const commandTemplateSource = settings.command_template ?? settings.commandTemplate;
|
|
1375
|
-
const filesFormat = resolveOptionalLiteralString(
|
|
1376
|
-
settings.files_format ?? settings.filesFormat ?? settings.attachments_format ?? settings.attachmentsFormat
|
|
1377
|
-
);
|
|
1378
|
-
const cwd = resolveOptionalString(settings.cwd, env, `${target.name} working directory`, {
|
|
1379
|
-
allowLiteral: true,
|
|
1380
|
-
optionalEnv: true
|
|
1191
|
+
function buildMandatoryPrereadBlock(guidelineFiles, inputFiles) {
|
|
1192
|
+
if (guidelineFiles.length === 0 && inputFiles.length === 0) {
|
|
1193
|
+
return "";
|
|
1194
|
+
}
|
|
1195
|
+
const buildList = (files) => files.map((absolutePath) => {
|
|
1196
|
+
const fileName = import_node_path4.default.basename(absolutePath);
|
|
1197
|
+
const fileUri = pathToFileUri(absolutePath);
|
|
1198
|
+
return `* [${fileName}](${fileUri})`;
|
|
1381
1199
|
});
|
|
1382
|
-
const
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1200
|
+
const sections = [];
|
|
1201
|
+
if (guidelineFiles.length > 0) {
|
|
1202
|
+
sections.push(`Read all guideline files:
|
|
1203
|
+
${buildList(guidelineFiles).join("\n")}.`);
|
|
1204
|
+
}
|
|
1205
|
+
if (inputFiles.length > 0) {
|
|
1206
|
+
sections.push(`Read all input files:
|
|
1207
|
+
${buildList(inputFiles).join("\n")}.`);
|
|
1208
|
+
}
|
|
1209
|
+
sections.push(
|
|
1210
|
+
"If any file is missing, fail with ERROR: missing-file <filename> and stop.",
|
|
1211
|
+
"Then apply system_instructions on the user query below."
|
|
1390
1212
|
);
|
|
1391
|
-
|
|
1392
|
-
return {
|
|
1393
|
-
commandTemplate,
|
|
1394
|
-
filesFormat,
|
|
1395
|
-
cwd,
|
|
1396
|
-
env: envOverrides,
|
|
1397
|
-
timeoutMs,
|
|
1398
|
-
healthcheck
|
|
1399
|
-
};
|
|
1213
|
+
return sections.join("\n");
|
|
1400
1214
|
}
|
|
1401
|
-
function
|
|
1402
|
-
|
|
1403
|
-
|
|
1215
|
+
function pathToFileUri(filePath) {
|
|
1216
|
+
const absolutePath = import_node_path4.default.isAbsolute(filePath) ? filePath : import_node_path4.default.resolve(filePath);
|
|
1217
|
+
const normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
1218
|
+
if (/^[a-zA-Z]:\//.test(normalizedPath)) {
|
|
1219
|
+
return `file:///${normalizedPath}`;
|
|
1220
|
+
}
|
|
1221
|
+
return `file://${normalizedPath}`;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// src/evaluation/providers/codex.ts
|
|
1225
|
+
var execAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.exec);
|
|
1226
|
+
var WORKSPACE_PREFIX = "agentv-codex-";
|
|
1227
|
+
var PROMPT_FILENAME = "prompt.md";
|
|
1228
|
+
var FILES_DIR = "files";
|
|
1229
|
+
var JSONL_TYPE_ITEM_COMPLETED = "item.completed";
|
|
1230
|
+
var CodexProvider = class {
|
|
1231
|
+
id;
|
|
1232
|
+
kind = "codex";
|
|
1233
|
+
targetName;
|
|
1234
|
+
supportsBatch = false;
|
|
1235
|
+
config;
|
|
1236
|
+
runCodex;
|
|
1237
|
+
environmentCheck;
|
|
1238
|
+
resolvedExecutable;
|
|
1239
|
+
constructor(targetName, config, runner = defaultCodexRunner) {
|
|
1240
|
+
this.id = `codex:${targetName}`;
|
|
1241
|
+
this.targetName = targetName;
|
|
1242
|
+
this.config = config;
|
|
1243
|
+
this.runCodex = runner;
|
|
1244
|
+
}
|
|
1245
|
+
async invoke(request) {
|
|
1246
|
+
if (request.signal?.aborted) {
|
|
1247
|
+
throw new Error("Codex provider request was aborted before execution");
|
|
1248
|
+
}
|
|
1249
|
+
await this.ensureEnvironmentReady();
|
|
1250
|
+
const inputFiles = normalizeInputFiles2(request.inputFiles);
|
|
1251
|
+
const originalGuidelines = new Set(
|
|
1252
|
+
collectGuidelineFiles(inputFiles, request.guideline_patterns).map((file) => import_node_path5.default.resolve(file))
|
|
1253
|
+
);
|
|
1254
|
+
const workspaceRoot = await this.createWorkspace();
|
|
1255
|
+
try {
|
|
1256
|
+
const { mirroredInputFiles, guidelineMirrors } = await this.mirrorInputFiles(
|
|
1257
|
+
inputFiles,
|
|
1258
|
+
workspaceRoot,
|
|
1259
|
+
originalGuidelines
|
|
1260
|
+
);
|
|
1261
|
+
const promptContent = buildPromptDocument(request, mirroredInputFiles, {
|
|
1262
|
+
guidelinePatterns: request.guideline_patterns,
|
|
1263
|
+
guidelineOverrides: guidelineMirrors
|
|
1264
|
+
});
|
|
1265
|
+
const promptFile = import_node_path5.default.join(workspaceRoot, PROMPT_FILENAME);
|
|
1266
|
+
await (0, import_promises3.writeFile)(promptFile, promptContent, "utf8");
|
|
1267
|
+
const args = this.buildCodexArgs();
|
|
1268
|
+
const cwd = this.resolveCwd(workspaceRoot);
|
|
1269
|
+
const result = await this.executeCodex(args, cwd, promptContent, request.signal);
|
|
1270
|
+
if (result.timedOut) {
|
|
1271
|
+
throw new Error(
|
|
1272
|
+
`Codex CLI timed out${formatTimeoutSuffix2(this.config.timeoutMs ?? void 0)}`
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
if (result.exitCode !== 0) {
|
|
1276
|
+
const detail = pickDetail(result.stderr, result.stdout);
|
|
1277
|
+
const prefix = `Codex CLI exited with code ${result.exitCode}`;
|
|
1278
|
+
throw new Error(detail ? `${prefix}: ${detail}` : prefix);
|
|
1279
|
+
}
|
|
1280
|
+
const parsed = parseCodexJson(result.stdout);
|
|
1281
|
+
const assistantText = extractAssistantText(parsed);
|
|
1282
|
+
return {
|
|
1283
|
+
text: assistantText,
|
|
1284
|
+
raw: {
|
|
1285
|
+
response: parsed,
|
|
1286
|
+
stdout: result.stdout,
|
|
1287
|
+
stderr: result.stderr,
|
|
1288
|
+
exitCode: result.exitCode,
|
|
1289
|
+
args,
|
|
1290
|
+
executable: this.resolvedExecutable ?? this.config.executable,
|
|
1291
|
+
promptFile,
|
|
1292
|
+
workspace: workspaceRoot,
|
|
1293
|
+
inputFiles: mirroredInputFiles
|
|
1294
|
+
}
|
|
1295
|
+
};
|
|
1296
|
+
} finally {
|
|
1297
|
+
await this.cleanupWorkspace(workspaceRoot);
|
|
1298
|
+
}
|
|
1404
1299
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1300
|
+
async ensureEnvironmentReady() {
|
|
1301
|
+
if (!this.environmentCheck) {
|
|
1302
|
+
this.environmentCheck = this.validateEnvironment();
|
|
1303
|
+
}
|
|
1304
|
+
await this.environmentCheck;
|
|
1407
1305
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1306
|
+
async validateEnvironment() {
|
|
1307
|
+
this.resolvedExecutable = await locateExecutable(this.config.executable);
|
|
1308
|
+
}
|
|
1309
|
+
resolveCwd(workspaceRoot) {
|
|
1310
|
+
if (!this.config.cwd) {
|
|
1311
|
+
return workspaceRoot;
|
|
1413
1312
|
}
|
|
1414
|
-
|
|
1415
|
-
resolved[key] = resolvedValue;
|
|
1313
|
+
return import_node_path5.default.resolve(this.config.cwd);
|
|
1416
1314
|
}
|
|
1417
|
-
|
|
1315
|
+
buildCodexArgs() {
|
|
1316
|
+
const args = ["--ask-for-approval", "never", "exec", "--json", "--color", "never", "--skip-git-repo-check"];
|
|
1317
|
+
if (this.config.args && this.config.args.length > 0) {
|
|
1318
|
+
args.push(...this.config.args);
|
|
1319
|
+
}
|
|
1320
|
+
args.push("-");
|
|
1321
|
+
return args;
|
|
1322
|
+
}
|
|
1323
|
+
async executeCodex(args, cwd, promptContent, signal) {
|
|
1324
|
+
try {
|
|
1325
|
+
return await this.runCodex({
|
|
1326
|
+
executable: this.resolvedExecutable ?? this.config.executable,
|
|
1327
|
+
args,
|
|
1328
|
+
cwd,
|
|
1329
|
+
prompt: promptContent,
|
|
1330
|
+
timeoutMs: this.config.timeoutMs,
|
|
1331
|
+
env: process.env,
|
|
1332
|
+
signal
|
|
1333
|
+
});
|
|
1334
|
+
} catch (error) {
|
|
1335
|
+
const err = error;
|
|
1336
|
+
if (err.code === "ENOENT") {
|
|
1337
|
+
throw new Error(
|
|
1338
|
+
`Codex executable '${this.config.executable}' was not found. Update the target settings.executable or add it to PATH.`
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
throw error;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
async mirrorInputFiles(inputFiles, workspaceRoot, guidelineOriginals) {
|
|
1345
|
+
if (!inputFiles || inputFiles.length === 0) {
|
|
1346
|
+
return {
|
|
1347
|
+
mirroredInputFiles: void 0,
|
|
1348
|
+
guidelineMirrors: /* @__PURE__ */ new Set()
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
const filesRoot = import_node_path5.default.join(workspaceRoot, FILES_DIR);
|
|
1352
|
+
await (0, import_promises3.mkdir)(filesRoot, { recursive: true });
|
|
1353
|
+
const mirrored = [];
|
|
1354
|
+
const guidelineMirrors = /* @__PURE__ */ new Set();
|
|
1355
|
+
const nameCounts = /* @__PURE__ */ new Map();
|
|
1356
|
+
for (const inputFile of inputFiles) {
|
|
1357
|
+
const absoluteSource = import_node_path5.default.resolve(inputFile);
|
|
1358
|
+
const baseName = import_node_path5.default.basename(absoluteSource);
|
|
1359
|
+
const count = nameCounts.get(baseName) ?? 0;
|
|
1360
|
+
nameCounts.set(baseName, count + 1);
|
|
1361
|
+
const finalName = count === 0 ? baseName : `${baseName}.${count}`;
|
|
1362
|
+
const destination = import_node_path5.default.join(filesRoot, finalName);
|
|
1363
|
+
await (0, import_promises3.copyFile)(absoluteSource, destination);
|
|
1364
|
+
const resolvedDestination = import_node_path5.default.resolve(destination);
|
|
1365
|
+
mirrored.push(resolvedDestination);
|
|
1366
|
+
if (guidelineOriginals.has(absoluteSource)) {
|
|
1367
|
+
guidelineMirrors.add(resolvedDestination);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
return {
|
|
1371
|
+
mirroredInputFiles: mirrored,
|
|
1372
|
+
guidelineMirrors
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
async createWorkspace() {
|
|
1376
|
+
return await (0, import_promises3.mkdtemp)(import_node_path5.default.join((0, import_node_os.tmpdir)(), WORKSPACE_PREFIX));
|
|
1377
|
+
}
|
|
1378
|
+
async cleanupWorkspace(workspaceRoot) {
|
|
1379
|
+
try {
|
|
1380
|
+
await (0, import_promises3.rm)(workspaceRoot, { recursive: true, force: true });
|
|
1381
|
+
} catch {
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
};
|
|
1385
|
+
async function locateExecutable(candidate) {
|
|
1386
|
+
const includesPathSeparator = candidate.includes("/") || candidate.includes("\\");
|
|
1387
|
+
if (includesPathSeparator) {
|
|
1388
|
+
const resolved = import_node_path5.default.isAbsolute(candidate) ? candidate : import_node_path5.default.resolve(candidate);
|
|
1389
|
+
const executablePath = await ensureWindowsExecutableVariant(resolved);
|
|
1390
|
+
await (0, import_promises3.access)(executablePath, import_node_fs3.constants.F_OK);
|
|
1391
|
+
return executablePath;
|
|
1392
|
+
}
|
|
1393
|
+
const locator = process.platform === "win32" ? "where" : "which";
|
|
1394
|
+
try {
|
|
1395
|
+
const { stdout } = await execAsync2(`${locator} ${candidate}`);
|
|
1396
|
+
const lines = stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
1397
|
+
const preferred = selectExecutableCandidate(lines);
|
|
1398
|
+
if (preferred) {
|
|
1399
|
+
const executablePath = await ensureWindowsExecutableVariant(preferred);
|
|
1400
|
+
await (0, import_promises3.access)(executablePath, import_node_fs3.constants.F_OK);
|
|
1401
|
+
return executablePath;
|
|
1402
|
+
}
|
|
1403
|
+
} catch {
|
|
1404
|
+
}
|
|
1405
|
+
throw new Error(`Codex executable '${candidate}' was not found on PATH`);
|
|
1418
1406
|
}
|
|
1419
|
-
function
|
|
1420
|
-
|
|
1421
|
-
if (seconds === void 0) {
|
|
1407
|
+
function selectExecutableCandidate(candidates) {
|
|
1408
|
+
if (candidates.length === 0) {
|
|
1422
1409
|
return void 0;
|
|
1423
1410
|
}
|
|
1424
|
-
if (
|
|
1425
|
-
|
|
1411
|
+
if (process.platform !== "win32") {
|
|
1412
|
+
return candidates[0];
|
|
1426
1413
|
}
|
|
1427
|
-
|
|
1414
|
+
const extensions = getWindowsExecutableExtensions();
|
|
1415
|
+
for (const ext of extensions) {
|
|
1416
|
+
const match = candidates.find((candidate) => candidate.toLowerCase().endsWith(ext));
|
|
1417
|
+
if (match) {
|
|
1418
|
+
return match;
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return candidates[0];
|
|
1428
1422
|
}
|
|
1429
|
-
function
|
|
1430
|
-
if (
|
|
1431
|
-
return
|
|
1423
|
+
async function ensureWindowsExecutableVariant(candidate) {
|
|
1424
|
+
if (process.platform !== "win32") {
|
|
1425
|
+
return candidate;
|
|
1432
1426
|
}
|
|
1433
|
-
if (
|
|
1434
|
-
|
|
1427
|
+
if (hasExecutableExtension(candidate)) {
|
|
1428
|
+
return candidate;
|
|
1435
1429
|
}
|
|
1436
|
-
const
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
return {
|
|
1445
|
-
type: "http",
|
|
1446
|
-
url,
|
|
1447
|
-
timeoutMs
|
|
1448
|
-
};
|
|
1430
|
+
const extensions = getWindowsExecutableExtensions();
|
|
1431
|
+
for (const ext of extensions) {
|
|
1432
|
+
const withExtension = `${candidate}${ext}`;
|
|
1433
|
+
try {
|
|
1434
|
+
await (0, import_promises3.access)(withExtension, import_node_fs3.constants.F_OK);
|
|
1435
|
+
return withExtension;
|
|
1436
|
+
} catch {
|
|
1437
|
+
}
|
|
1449
1438
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
optionalEnv: true
|
|
1461
|
-
});
|
|
1462
|
-
return {
|
|
1463
|
-
type: "command",
|
|
1464
|
-
commandTemplate,
|
|
1465
|
-
timeoutMs,
|
|
1466
|
-
cwd
|
|
1467
|
-
};
|
|
1439
|
+
return candidate;
|
|
1440
|
+
}
|
|
1441
|
+
function hasExecutableExtension(candidate) {
|
|
1442
|
+
const lower = candidate.toLowerCase();
|
|
1443
|
+
return getWindowsExecutableExtensions().some((ext) => lower.endsWith(ext));
|
|
1444
|
+
}
|
|
1445
|
+
var DEFAULT_WINDOWS_EXTENSIONS = [".com", ".exe", ".bat", ".cmd", ".ps1"];
|
|
1446
|
+
function getWindowsExecutableExtensions() {
|
|
1447
|
+
if (process.platform !== "win32") {
|
|
1448
|
+
return [];
|
|
1468
1449
|
}
|
|
1469
|
-
|
|
1450
|
+
const fromEnv = process.env.PATHEXT?.split(";").map((ext) => ext.trim().toLowerCase()).filter((ext) => ext.length > 0);
|
|
1451
|
+
return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_WINDOWS_EXTENSIONS;
|
|
1470
1452
|
}
|
|
1471
|
-
function
|
|
1472
|
-
const
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1453
|
+
function parseCodexJson(output) {
|
|
1454
|
+
const trimmed = output.trim();
|
|
1455
|
+
if (trimmed.length === 0) {
|
|
1456
|
+
throw new Error("Codex CLI produced no output in --json mode");
|
|
1457
|
+
}
|
|
1458
|
+
try {
|
|
1459
|
+
return JSON.parse(trimmed);
|
|
1460
|
+
} catch {
|
|
1461
|
+
const lineObjects = parseJsonLines(trimmed);
|
|
1462
|
+
if (lineObjects) {
|
|
1463
|
+
return lineObjects;
|
|
1464
|
+
}
|
|
1465
|
+
const lastBrace = trimmed.lastIndexOf("{");
|
|
1466
|
+
if (lastBrace >= 0) {
|
|
1467
|
+
const candidate = trimmed.slice(lastBrace);
|
|
1468
|
+
try {
|
|
1469
|
+
return JSON.parse(candidate);
|
|
1470
|
+
} catch {
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
const preview = trimmed.slice(0, 200);
|
|
1474
|
+
throw new Error(`Codex CLI emitted invalid JSON: ${preview}${trimmed.length > 200 ? "\u2026" : ""}`);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
function extractAssistantText(parsed) {
|
|
1478
|
+
if (Array.isArray(parsed)) {
|
|
1479
|
+
const text = extractFromEventStream(parsed);
|
|
1480
|
+
if (text) {
|
|
1481
|
+
return text;
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1485
|
+
throw new Error("Codex CLI JSON response did not include an assistant message");
|
|
1486
|
+
}
|
|
1487
|
+
const record = parsed;
|
|
1488
|
+
const eventText = extractFromEvent(record);
|
|
1489
|
+
if (eventText) {
|
|
1490
|
+
return eventText;
|
|
1491
|
+
}
|
|
1492
|
+
const messages = Array.isArray(record.messages) ? record.messages : void 0;
|
|
1493
|
+
if (messages) {
|
|
1494
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
1495
|
+
const entry = messages[index];
|
|
1496
|
+
if (!entry || typeof entry !== "object") {
|
|
1497
|
+
continue;
|
|
1498
|
+
}
|
|
1499
|
+
const role = entry.role;
|
|
1500
|
+
if (role !== "assistant") {
|
|
1501
|
+
continue;
|
|
1502
|
+
}
|
|
1503
|
+
const content = entry.content;
|
|
1504
|
+
const flattened = flattenContent(content);
|
|
1505
|
+
if (flattened) {
|
|
1506
|
+
return flattened;
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
const response = record.response;
|
|
1511
|
+
if (response && typeof response === "object") {
|
|
1512
|
+
const content = response.content;
|
|
1513
|
+
const flattened = flattenContent(content);
|
|
1514
|
+
if (flattened) {
|
|
1515
|
+
return flattened;
|
|
1478
1516
|
}
|
|
1479
1517
|
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
for (const match of matches) {
|
|
1485
|
-
if (match[1]) {
|
|
1486
|
-
results.push(match[1]);
|
|
1487
|
-
}
|
|
1518
|
+
const output = record.output;
|
|
1519
|
+
const flattenedOutput = flattenContent(output);
|
|
1520
|
+
if (flattenedOutput) {
|
|
1521
|
+
return flattenedOutput;
|
|
1488
1522
|
}
|
|
1489
|
-
|
|
1523
|
+
throw new Error("Codex CLI JSON response did not include an assistant message");
|
|
1490
1524
|
}
|
|
1491
|
-
function
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1525
|
+
function extractFromEventStream(events) {
|
|
1526
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
1527
|
+
const candidate = events[index];
|
|
1528
|
+
const text = extractFromEvent(candidate);
|
|
1529
|
+
if (text) {
|
|
1530
|
+
return text;
|
|
1531
|
+
}
|
|
1498
1532
|
}
|
|
1499
|
-
return
|
|
1533
|
+
return void 0;
|
|
1500
1534
|
}
|
|
1501
|
-
function
|
|
1502
|
-
if (
|
|
1503
|
-
return void 0;
|
|
1504
|
-
}
|
|
1505
|
-
if (typeof source !== "string") {
|
|
1506
|
-
throw new Error(`${description} must be a string`);
|
|
1507
|
-
}
|
|
1508
|
-
const trimmed = source.trim();
|
|
1509
|
-
if (trimmed.length === 0) {
|
|
1535
|
+
function extractFromEvent(event) {
|
|
1536
|
+
if (!event || typeof event !== "object") {
|
|
1510
1537
|
return void 0;
|
|
1511
1538
|
}
|
|
1512
|
-
const
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1539
|
+
const record = event;
|
|
1540
|
+
const type = typeof record.type === "string" ? record.type : void 0;
|
|
1541
|
+
if (type === JSONL_TYPE_ITEM_COMPLETED) {
|
|
1542
|
+
const item = record.item;
|
|
1543
|
+
const text = extractFromItem(item);
|
|
1544
|
+
if (text) {
|
|
1545
|
+
return text;
|
|
1516
1546
|
}
|
|
1517
|
-
return envValue;
|
|
1518
1547
|
}
|
|
1519
|
-
const
|
|
1520
|
-
const
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
if (optionalEnv) {
|
|
1524
|
-
return void 0;
|
|
1525
|
-
}
|
|
1526
|
-
if (!allowLiteral) {
|
|
1527
|
-
throw new Error(`Environment variable '${trimmed}' required for ${description} is not set`);
|
|
1528
|
-
}
|
|
1548
|
+
const output = record.output ?? record.content;
|
|
1549
|
+
const flattened = flattenContent(output);
|
|
1550
|
+
if (flattened) {
|
|
1551
|
+
return flattened;
|
|
1529
1552
|
}
|
|
1530
|
-
return
|
|
1553
|
+
return void 0;
|
|
1531
1554
|
}
|
|
1532
|
-
function
|
|
1533
|
-
if (
|
|
1555
|
+
function extractFromItem(item) {
|
|
1556
|
+
if (!item || typeof item !== "object") {
|
|
1534
1557
|
return void 0;
|
|
1535
1558
|
}
|
|
1536
|
-
|
|
1537
|
-
|
|
1559
|
+
const record = item;
|
|
1560
|
+
const itemType = typeof record.type === "string" ? record.type : void 0;
|
|
1561
|
+
if (itemType === "agent_message" || itemType === "response" || itemType === "output") {
|
|
1562
|
+
const text = flattenContent(record.text ?? record.content ?? record.output);
|
|
1563
|
+
if (text) {
|
|
1564
|
+
return text;
|
|
1565
|
+
}
|
|
1538
1566
|
}
|
|
1539
|
-
|
|
1540
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
1567
|
+
return void 0;
|
|
1541
1568
|
}
|
|
1542
|
-
function
|
|
1543
|
-
if (
|
|
1544
|
-
return
|
|
1569
|
+
function flattenContent(value) {
|
|
1570
|
+
if (typeof value === "string") {
|
|
1571
|
+
return value;
|
|
1545
1572
|
}
|
|
1546
|
-
if (
|
|
1547
|
-
|
|
1573
|
+
if (Array.isArray(value)) {
|
|
1574
|
+
const parts = value.map((segment) => {
|
|
1575
|
+
if (typeof segment === "string") {
|
|
1576
|
+
return segment;
|
|
1577
|
+
}
|
|
1578
|
+
if (segment && typeof segment === "object" && "text" in segment) {
|
|
1579
|
+
const text = segment.text;
|
|
1580
|
+
return typeof text === "string" ? text : void 0;
|
|
1581
|
+
}
|
|
1582
|
+
return void 0;
|
|
1583
|
+
}).filter((part) => typeof part === "string" && part.length > 0);
|
|
1584
|
+
return parts.length > 0 ? parts.join(" \n") : void 0;
|
|
1548
1585
|
}
|
|
1549
|
-
if (typeof
|
|
1550
|
-
const
|
|
1551
|
-
|
|
1552
|
-
return numeric;
|
|
1553
|
-
}
|
|
1586
|
+
if (value && typeof value === "object" && "text" in value) {
|
|
1587
|
+
const text = value.text;
|
|
1588
|
+
return typeof text === "string" ? text : void 0;
|
|
1554
1589
|
}
|
|
1555
|
-
|
|
1590
|
+
return void 0;
|
|
1556
1591
|
}
|
|
1557
|
-
function
|
|
1558
|
-
|
|
1592
|
+
function parseJsonLines(output) {
|
|
1593
|
+
const lines = output.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
1594
|
+
if (lines.length <= 1) {
|
|
1559
1595
|
return void 0;
|
|
1560
1596
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
return true;
|
|
1568
|
-
}
|
|
1569
|
-
if (lowered === "false" || lowered === "0") {
|
|
1570
|
-
return false;
|
|
1597
|
+
const parsed = [];
|
|
1598
|
+
for (const line of lines) {
|
|
1599
|
+
try {
|
|
1600
|
+
parsed.push(JSON.parse(line));
|
|
1601
|
+
} catch {
|
|
1602
|
+
return void 0;
|
|
1571
1603
|
}
|
|
1572
1604
|
}
|
|
1573
|
-
|
|
1574
|
-
}
|
|
1575
|
-
function isLikelyEnvReference(value) {
|
|
1576
|
-
return /^[A-Z0-9_]+$/.test(value);
|
|
1605
|
+
return parsed;
|
|
1577
1606
|
}
|
|
1578
|
-
function
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
if (!Array.isArray(source)) {
|
|
1583
|
-
throw new Error(`${description} must be an array of strings`);
|
|
1607
|
+
function pickDetail(stderr, stdout) {
|
|
1608
|
+
const errorText = stderr.trim();
|
|
1609
|
+
if (errorText.length > 0) {
|
|
1610
|
+
return errorText;
|
|
1584
1611
|
}
|
|
1585
|
-
|
|
1586
|
-
|
|
1612
|
+
const stdoutText = stdout.trim();
|
|
1613
|
+
return stdoutText.length > 0 ? stdoutText : void 0;
|
|
1614
|
+
}
|
|
1615
|
+
function formatTimeoutSuffix2(timeoutMs) {
|
|
1616
|
+
if (!timeoutMs || timeoutMs <= 0) {
|
|
1617
|
+
return "";
|
|
1587
1618
|
}
|
|
1588
|
-
const
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1619
|
+
const seconds = Math.ceil(timeoutMs / 1e3);
|
|
1620
|
+
return ` after ${seconds}s`;
|
|
1621
|
+
}
|
|
1622
|
+
async function defaultCodexRunner(options) {
|
|
1623
|
+
return await new Promise((resolve, reject) => {
|
|
1624
|
+
const child = (0, import_node_child_process2.spawn)(options.executable, options.args, {
|
|
1625
|
+
cwd: options.cwd,
|
|
1626
|
+
env: options.env,
|
|
1627
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1628
|
+
shell: shouldShellExecute(options.executable)
|
|
1629
|
+
});
|
|
1630
|
+
let stdout = "";
|
|
1631
|
+
let stderr = "";
|
|
1632
|
+
let timedOut = false;
|
|
1633
|
+
const onAbort = () => {
|
|
1634
|
+
child.kill("SIGTERM");
|
|
1635
|
+
};
|
|
1636
|
+
if (options.signal) {
|
|
1637
|
+
if (options.signal.aborted) {
|
|
1638
|
+
onAbort();
|
|
1639
|
+
} else {
|
|
1640
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
1641
|
+
}
|
|
1593
1642
|
}
|
|
1594
|
-
|
|
1595
|
-
if (
|
|
1596
|
-
|
|
1643
|
+
let timeoutHandle;
|
|
1644
|
+
if (options.timeoutMs && options.timeoutMs > 0) {
|
|
1645
|
+
timeoutHandle = setTimeout(() => {
|
|
1646
|
+
timedOut = true;
|
|
1647
|
+
child.kill("SIGTERM");
|
|
1648
|
+
}, options.timeoutMs);
|
|
1649
|
+
timeoutHandle.unref?.();
|
|
1597
1650
|
}
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1651
|
+
child.stdout.setEncoding("utf8");
|
|
1652
|
+
child.stdout.on("data", (chunk) => {
|
|
1653
|
+
stdout += chunk;
|
|
1654
|
+
});
|
|
1655
|
+
child.stderr.setEncoding("utf8");
|
|
1656
|
+
child.stderr.on("data", (chunk) => {
|
|
1657
|
+
stderr += chunk;
|
|
1658
|
+
});
|
|
1659
|
+
child.stdin.end(options.prompt);
|
|
1660
|
+
const cleanup = () => {
|
|
1661
|
+
if (timeoutHandle) {
|
|
1662
|
+
clearTimeout(timeoutHandle);
|
|
1602
1663
|
}
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
}
|
|
1664
|
+
if (options.signal) {
|
|
1665
|
+
options.signal.removeEventListener("abort", onAbort);
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
child.on("error", (error) => {
|
|
1669
|
+
cleanup();
|
|
1670
|
+
reject(error);
|
|
1671
|
+
});
|
|
1672
|
+
child.on("close", (code) => {
|
|
1673
|
+
cleanup();
|
|
1674
|
+
resolve({
|
|
1675
|
+
stdout,
|
|
1676
|
+
stderr,
|
|
1677
|
+
exitCode: typeof code === "number" ? code : -1,
|
|
1678
|
+
timedOut
|
|
1679
|
+
});
|
|
1680
|
+
});
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
function shouldShellExecute(executable) {
|
|
1684
|
+
if (process.platform !== "win32") {
|
|
1685
|
+
return false;
|
|
1607
1686
|
}
|
|
1608
|
-
|
|
1687
|
+
const lower = executable.toLowerCase();
|
|
1688
|
+
return lower.endsWith(".cmd") || lower.endsWith(".bat") || lower.endsWith(".ps1");
|
|
1609
1689
|
}
|
|
1610
1690
|
|
|
1611
|
-
// src/evaluation/providers/
|
|
1612
|
-
var
|
|
1613
|
-
var
|
|
1614
|
-
var import_subagent = require("subagent");
|
|
1615
|
-
var VSCodeProvider = class {
|
|
1691
|
+
// src/evaluation/providers/mock.ts
|
|
1692
|
+
var DEFAULT_MOCK_RESPONSE = '{"answer":"Mock provider response. Configure targets.yaml to supply a custom value."}';
|
|
1693
|
+
var MockProvider = class {
|
|
1616
1694
|
id;
|
|
1617
|
-
kind;
|
|
1695
|
+
kind = "mock";
|
|
1618
1696
|
targetName;
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1697
|
+
cannedResponse;
|
|
1698
|
+
delayMs;
|
|
1699
|
+
delayMinMs;
|
|
1700
|
+
delayMaxMs;
|
|
1701
|
+
constructor(targetName, config) {
|
|
1702
|
+
this.id = `mock:${targetName}`;
|
|
1624
1703
|
this.targetName = targetName;
|
|
1625
|
-
this.
|
|
1704
|
+
this.cannedResponse = config.response ?? DEFAULT_MOCK_RESPONSE;
|
|
1705
|
+
this.delayMs = config.delayMs ?? 0;
|
|
1706
|
+
this.delayMinMs = config.delayMinMs ?? 0;
|
|
1707
|
+
this.delayMaxMs = config.delayMaxMs ?? 0;
|
|
1626
1708
|
}
|
|
1627
1709
|
async invoke(request) {
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
const inputFiles = normalizeAttachments(request.inputFiles);
|
|
1632
|
-
const promptContent = buildPromptDocument(request, inputFiles, request.guideline_patterns);
|
|
1633
|
-
const session = await (0, import_subagent.dispatchAgentSession)({
|
|
1634
|
-
userQuery: promptContent,
|
|
1635
|
-
extraAttachments: inputFiles,
|
|
1636
|
-
wait: this.config.waitForResponse,
|
|
1637
|
-
dryRun: this.config.dryRun,
|
|
1638
|
-
vscodeCmd: this.config.command,
|
|
1639
|
-
subagentRoot: this.config.subagentRoot,
|
|
1640
|
-
workspaceTemplate: this.config.workspaceTemplate,
|
|
1641
|
-
silent: true
|
|
1642
|
-
});
|
|
1643
|
-
if (session.exitCode !== 0 || !session.responseFile) {
|
|
1644
|
-
const failure = session.error ?? "VS Code subagent did not produce a response";
|
|
1645
|
-
throw new Error(failure);
|
|
1646
|
-
}
|
|
1647
|
-
if (this.config.dryRun) {
|
|
1648
|
-
return {
|
|
1649
|
-
text: "",
|
|
1650
|
-
raw: {
|
|
1651
|
-
session,
|
|
1652
|
-
inputFiles
|
|
1653
|
-
}
|
|
1654
|
-
};
|
|
1710
|
+
const delay = this.calculateDelay();
|
|
1711
|
+
if (delay > 0) {
|
|
1712
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1655
1713
|
}
|
|
1656
|
-
const responseText = await (0, import_promises3.readFile)(session.responseFile, "utf8");
|
|
1657
1714
|
return {
|
|
1658
|
-
text:
|
|
1715
|
+
text: this.cannedResponse,
|
|
1659
1716
|
raw: {
|
|
1660
|
-
|
|
1661
|
-
|
|
1717
|
+
prompt: request.prompt,
|
|
1718
|
+
guidelines: request.guidelines
|
|
1662
1719
|
}
|
|
1663
1720
|
};
|
|
1664
1721
|
}
|
|
1665
|
-
|
|
1666
|
-
if (
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
request: req,
|
|
1671
|
-
inputFiles: normalizeAttachments(req.inputFiles)
|
|
1672
|
-
}));
|
|
1673
|
-
const combinedInputFiles = mergeAttachments(
|
|
1674
|
-
normalizedRequests.map(({ inputFiles }) => inputFiles)
|
|
1675
|
-
);
|
|
1676
|
-
const userQueries = normalizedRequests.map(
|
|
1677
|
-
({ request, inputFiles }) => buildPromptDocument(request, inputFiles, request.guideline_patterns)
|
|
1678
|
-
);
|
|
1679
|
-
const session = await (0, import_subagent.dispatchBatchAgent)({
|
|
1680
|
-
userQueries,
|
|
1681
|
-
extraAttachments: combinedInputFiles,
|
|
1682
|
-
wait: this.config.waitForResponse,
|
|
1683
|
-
dryRun: this.config.dryRun,
|
|
1684
|
-
vscodeCmd: this.config.command,
|
|
1685
|
-
subagentRoot: this.config.subagentRoot,
|
|
1686
|
-
workspaceTemplate: this.config.workspaceTemplate,
|
|
1687
|
-
silent: true
|
|
1688
|
-
});
|
|
1689
|
-
if (session.exitCode !== 0 || !session.responseFiles) {
|
|
1690
|
-
const failure = session.error ?? "VS Code subagent did not produce batch responses";
|
|
1691
|
-
throw new Error(failure);
|
|
1692
|
-
}
|
|
1693
|
-
if (this.config.dryRun) {
|
|
1694
|
-
return normalizedRequests.map(({ inputFiles }) => ({
|
|
1695
|
-
text: "",
|
|
1696
|
-
raw: {
|
|
1697
|
-
session,
|
|
1698
|
-
inputFiles,
|
|
1699
|
-
allInputFiles: combinedInputFiles
|
|
1700
|
-
}
|
|
1701
|
-
}));
|
|
1702
|
-
}
|
|
1703
|
-
if (session.responseFiles.length !== requests.length) {
|
|
1704
|
-
throw new Error(
|
|
1705
|
-
`VS Code batch returned ${session.responseFiles.length} responses for ${requests.length} requests`
|
|
1706
|
-
);
|
|
1707
|
-
}
|
|
1708
|
-
const responses = [];
|
|
1709
|
-
for (const [index, responseFile] of session.responseFiles.entries()) {
|
|
1710
|
-
const responseText = await (0, import_promises3.readFile)(responseFile, "utf8");
|
|
1711
|
-
responses.push({
|
|
1712
|
-
text: responseText,
|
|
1713
|
-
raw: {
|
|
1714
|
-
session,
|
|
1715
|
-
inputFiles: normalizedRequests[index]?.inputFiles,
|
|
1716
|
-
allInputFiles: combinedInputFiles,
|
|
1717
|
-
responseFile
|
|
1718
|
-
}
|
|
1719
|
-
});
|
|
1722
|
+
calculateDelay() {
|
|
1723
|
+
if (this.delayMinMs > 0 || this.delayMaxMs > 0) {
|
|
1724
|
+
const min = Math.max(0, this.delayMinMs);
|
|
1725
|
+
const max = Math.max(min, this.delayMaxMs);
|
|
1726
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
1720
1727
|
}
|
|
1721
|
-
return
|
|
1728
|
+
return this.delayMs;
|
|
1722
1729
|
}
|
|
1723
1730
|
};
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
)
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
if (guidelineFiles.length === 0 && attachmentFiles.length === 0) {
|
|
1740
|
-
return "";
|
|
1731
|
+
|
|
1732
|
+
// src/evaluation/providers/targets.ts
|
|
1733
|
+
var import_zod = require("zod");
|
|
1734
|
+
var CLI_PLACEHOLDERS = /* @__PURE__ */ new Set(["PROMPT", "GUIDELINES", "EVAL_ID", "ATTEMPT", "FILES"]);
|
|
1735
|
+
var BASE_TARGET_SCHEMA = import_zod.z.object({
|
|
1736
|
+
name: import_zod.z.string().min(1, "target name is required"),
|
|
1737
|
+
provider: import_zod.z.string().min(1, "provider is required"),
|
|
1738
|
+
settings: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
1739
|
+
judge_target: import_zod.z.string().optional(),
|
|
1740
|
+
workers: import_zod.z.number().int().min(1).optional()
|
|
1741
|
+
});
|
|
1742
|
+
var DEFAULT_AZURE_API_VERSION = "2024-10-01-preview";
|
|
1743
|
+
function normalizeAzureApiVersion(value) {
|
|
1744
|
+
if (!value) {
|
|
1745
|
+
return DEFAULT_AZURE_API_VERSION;
|
|
1741
1746
|
}
|
|
1742
|
-
const
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
return `* [${fileName}](${fileUri})`;
|
|
1746
|
-
});
|
|
1747
|
-
const sections = [];
|
|
1748
|
-
if (guidelineFiles.length > 0) {
|
|
1749
|
-
sections.push(`Read all guideline files:
|
|
1750
|
-
${buildList(guidelineFiles).join("\n")}.`);
|
|
1747
|
+
const trimmed = value.trim();
|
|
1748
|
+
if (trimmed.length === 0) {
|
|
1749
|
+
return DEFAULT_AZURE_API_VERSION;
|
|
1751
1750
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1751
|
+
const withoutPrefix = trimmed.replace(/^api[-_]?version\s*=\s*/i, "").trim();
|
|
1752
|
+
return withoutPrefix.length > 0 ? withoutPrefix : DEFAULT_AZURE_API_VERSION;
|
|
1753
|
+
}
|
|
1754
|
+
function resolveTargetDefinition(definition, env = process.env) {
|
|
1755
|
+
const parsed = BASE_TARGET_SCHEMA.parse(definition);
|
|
1756
|
+
const provider = parsed.provider.toLowerCase();
|
|
1757
|
+
const providerBatching = resolveOptionalBoolean(
|
|
1758
|
+
parsed.settings?.provider_batching ?? parsed.settings?.providerBatching
|
|
1759
|
+
);
|
|
1760
|
+
switch (provider) {
|
|
1761
|
+
case "azure":
|
|
1762
|
+
case "azure-openai":
|
|
1763
|
+
return {
|
|
1764
|
+
kind: "azure",
|
|
1765
|
+
name: parsed.name,
|
|
1766
|
+
judgeTarget: parsed.judge_target,
|
|
1767
|
+
workers: parsed.workers,
|
|
1768
|
+
providerBatching,
|
|
1769
|
+
config: resolveAzureConfig(parsed, env)
|
|
1770
|
+
};
|
|
1771
|
+
case "anthropic":
|
|
1772
|
+
return {
|
|
1773
|
+
kind: "anthropic",
|
|
1774
|
+
name: parsed.name,
|
|
1775
|
+
judgeTarget: parsed.judge_target,
|
|
1776
|
+
workers: parsed.workers,
|
|
1777
|
+
providerBatching,
|
|
1778
|
+
config: resolveAnthropicConfig(parsed, env)
|
|
1779
|
+
};
|
|
1780
|
+
case "gemini":
|
|
1781
|
+
case "google":
|
|
1782
|
+
case "google-gemini":
|
|
1783
|
+
return {
|
|
1784
|
+
kind: "gemini",
|
|
1785
|
+
name: parsed.name,
|
|
1786
|
+
judgeTarget: parsed.judge_target,
|
|
1787
|
+
workers: parsed.workers,
|
|
1788
|
+
providerBatching,
|
|
1789
|
+
config: resolveGeminiConfig(parsed, env)
|
|
1790
|
+
};
|
|
1791
|
+
case "codex":
|
|
1792
|
+
case "codex-cli":
|
|
1793
|
+
return {
|
|
1794
|
+
kind: "codex",
|
|
1795
|
+
name: parsed.name,
|
|
1796
|
+
judgeTarget: parsed.judge_target,
|
|
1797
|
+
workers: parsed.workers,
|
|
1798
|
+
providerBatching,
|
|
1799
|
+
config: resolveCodexConfig(parsed, env)
|
|
1800
|
+
};
|
|
1801
|
+
case "mock":
|
|
1802
|
+
return {
|
|
1803
|
+
kind: "mock",
|
|
1804
|
+
name: parsed.name,
|
|
1805
|
+
judgeTarget: parsed.judge_target,
|
|
1806
|
+
workers: parsed.workers,
|
|
1807
|
+
providerBatching,
|
|
1808
|
+
config: resolveMockConfig(parsed)
|
|
1809
|
+
};
|
|
1810
|
+
case "vscode":
|
|
1811
|
+
case "vscode-insiders":
|
|
1812
|
+
return {
|
|
1813
|
+
kind: provider,
|
|
1814
|
+
name: parsed.name,
|
|
1815
|
+
judgeTarget: parsed.judge_target,
|
|
1816
|
+
workers: parsed.workers,
|
|
1817
|
+
providerBatching,
|
|
1818
|
+
config: resolveVSCodeConfig(parsed, env, provider === "vscode-insiders")
|
|
1819
|
+
};
|
|
1820
|
+
case "cli":
|
|
1821
|
+
return {
|
|
1822
|
+
kind: "cli",
|
|
1823
|
+
name: parsed.name,
|
|
1824
|
+
judgeTarget: parsed.judge_target,
|
|
1825
|
+
workers: parsed.workers,
|
|
1826
|
+
providerBatching,
|
|
1827
|
+
config: resolveCliConfig(parsed, env)
|
|
1828
|
+
};
|
|
1829
|
+
default:
|
|
1830
|
+
throw new Error(`Unsupported provider '${parsed.provider}' in target '${parsed.name}'`);
|
|
1755
1831
|
}
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1832
|
+
}
|
|
1833
|
+
function resolveAzureConfig(target, env) {
|
|
1834
|
+
const settings = target.settings ?? {};
|
|
1835
|
+
const endpointSource = settings.endpoint ?? settings.resource ?? settings.resourceName;
|
|
1836
|
+
const apiKeySource = settings.api_key ?? settings.apiKey;
|
|
1837
|
+
const deploymentSource = settings.deployment ?? settings.deploymentName ?? settings.model;
|
|
1838
|
+
const versionSource = settings.version ?? settings.api_version;
|
|
1839
|
+
const temperatureSource = settings.temperature;
|
|
1840
|
+
const maxTokensSource = settings.max_output_tokens ?? settings.maxTokens;
|
|
1841
|
+
const resourceName = resolveString(endpointSource, env, `${target.name} endpoint`);
|
|
1842
|
+
const apiKey = resolveString(apiKeySource, env, `${target.name} api key`);
|
|
1843
|
+
const deploymentName = resolveString(deploymentSource, env, `${target.name} deployment`);
|
|
1844
|
+
const version = normalizeAzureApiVersion(
|
|
1845
|
+
resolveOptionalString(versionSource, env, `${target.name} api version`)
|
|
1846
|
+
);
|
|
1847
|
+
const temperature = resolveOptionalNumber(temperatureSource, `${target.name} temperature`);
|
|
1848
|
+
const maxOutputTokens = resolveOptionalNumber(
|
|
1849
|
+
maxTokensSource,
|
|
1850
|
+
`${target.name} max output tokens`
|
|
1759
1851
|
);
|
|
1760
|
-
return
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
const absolutePath = import_node_path4.default.resolve(attachment);
|
|
1769
|
-
const normalized = absolutePath.split(import_node_path4.default.sep).join("/");
|
|
1770
|
-
if (isGuidelineFile(normalized, guidelinePatterns)) {
|
|
1771
|
-
if (!unique.has(absolutePath)) {
|
|
1772
|
-
unique.set(absolutePath, absolutePath);
|
|
1773
|
-
}
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1776
|
-
return Array.from(unique.values());
|
|
1852
|
+
return {
|
|
1853
|
+
resourceName,
|
|
1854
|
+
deploymentName,
|
|
1855
|
+
apiKey,
|
|
1856
|
+
version,
|
|
1857
|
+
temperature,
|
|
1858
|
+
maxOutputTokens
|
|
1859
|
+
};
|
|
1777
1860
|
}
|
|
1778
|
-
function
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
const
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1861
|
+
function resolveAnthropicConfig(target, env) {
|
|
1862
|
+
const settings = target.settings ?? {};
|
|
1863
|
+
const apiKeySource = settings.api_key ?? settings.apiKey;
|
|
1864
|
+
const modelSource = settings.model ?? settings.deployment ?? settings.variant;
|
|
1865
|
+
const temperatureSource = settings.temperature;
|
|
1866
|
+
const maxTokensSource = settings.max_output_tokens ?? settings.maxTokens;
|
|
1867
|
+
const thinkingBudgetSource = settings.thinking_budget ?? settings.thinkingBudget;
|
|
1868
|
+
const apiKey = resolveString(apiKeySource, env, `${target.name} Anthropic api key`);
|
|
1869
|
+
const model = resolveString(modelSource, env, `${target.name} Anthropic model`);
|
|
1870
|
+
return {
|
|
1871
|
+
apiKey,
|
|
1872
|
+
model,
|
|
1873
|
+
temperature: resolveOptionalNumber(temperatureSource, `${target.name} temperature`),
|
|
1874
|
+
maxOutputTokens: resolveOptionalNumber(maxTokensSource, `${target.name} max output tokens`),
|
|
1875
|
+
thinkingBudget: resolveOptionalNumber(thinkingBudgetSource, `${target.name} thinking budget`)
|
|
1876
|
+
};
|
|
1790
1877
|
}
|
|
1791
|
-
function
|
|
1792
|
-
const
|
|
1793
|
-
const
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1878
|
+
function resolveGeminiConfig(target, env) {
|
|
1879
|
+
const settings = target.settings ?? {};
|
|
1880
|
+
const apiKeySource = settings.api_key ?? settings.apiKey;
|
|
1881
|
+
const modelSource = settings.model ?? settings.deployment ?? settings.variant;
|
|
1882
|
+
const temperatureSource = settings.temperature;
|
|
1883
|
+
const maxTokensSource = settings.max_output_tokens ?? settings.maxTokens;
|
|
1884
|
+
const apiKey = resolveString(apiKeySource, env, `${target.name} Google API key`);
|
|
1885
|
+
const model = resolveOptionalString(modelSource, env, `${target.name} Gemini model`, {
|
|
1886
|
+
allowLiteral: true,
|
|
1887
|
+
optionalEnv: true
|
|
1888
|
+
}) ?? "gemini-2.5-flash";
|
|
1889
|
+
return {
|
|
1890
|
+
apiKey,
|
|
1891
|
+
model,
|
|
1892
|
+
temperature: resolveOptionalNumber(temperatureSource, `${target.name} temperature`),
|
|
1893
|
+
maxOutputTokens: resolveOptionalNumber(maxTokensSource, `${target.name} max output tokens`)
|
|
1894
|
+
};
|
|
1798
1895
|
}
|
|
1799
|
-
function
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
const
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1896
|
+
function resolveCodexConfig(target, env) {
|
|
1897
|
+
const settings = target.settings ?? {};
|
|
1898
|
+
const executableSource = settings.executable ?? settings.command ?? settings.binary;
|
|
1899
|
+
const argsSource = settings.args ?? settings.arguments;
|
|
1900
|
+
const cwdSource = settings.cwd;
|
|
1901
|
+
const timeoutSource = settings.timeout_seconds ?? settings.timeoutSeconds;
|
|
1902
|
+
const executable = resolveOptionalString(executableSource, env, `${target.name} codex executable`, {
|
|
1903
|
+
allowLiteral: true,
|
|
1904
|
+
optionalEnv: true
|
|
1905
|
+
}) ?? "codex";
|
|
1906
|
+
const args = resolveOptionalStringArray(argsSource, env, `${target.name} codex args`);
|
|
1907
|
+
const cwd = resolveOptionalString(cwdSource, env, `${target.name} codex cwd`, {
|
|
1908
|
+
allowLiteral: true,
|
|
1909
|
+
optionalEnv: true
|
|
1910
|
+
});
|
|
1911
|
+
const timeoutMs = resolveTimeoutMs(timeoutSource, `${target.name} codex timeout`);
|
|
1912
|
+
return {
|
|
1913
|
+
executable,
|
|
1914
|
+
args,
|
|
1915
|
+
cwd,
|
|
1916
|
+
timeoutMs
|
|
1917
|
+
};
|
|
1808
1918
|
}
|
|
1809
|
-
function
|
|
1810
|
-
const
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
for (const inputFile of list) {
|
|
1814
|
-
deduped.add(import_node_path4.default.resolve(inputFile));
|
|
1815
|
-
}
|
|
1816
|
-
}
|
|
1817
|
-
return deduped.size > 0 ? Array.from(deduped) : void 0;
|
|
1919
|
+
function resolveMockConfig(target) {
|
|
1920
|
+
const settings = target.settings ?? {};
|
|
1921
|
+
const response = typeof settings.response === "string" ? settings.response : void 0;
|
|
1922
|
+
return { response };
|
|
1818
1923
|
}
|
|
1819
|
-
|
|
1820
|
-
const
|
|
1821
|
-
const
|
|
1822
|
-
const
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
return {
|
|
1843
|
-
provisioned: true,
|
|
1844
|
-
message: `Provisioned ${count} subagent(s): ${result.created.length} created, ${result.skippedExisting.length} reused`
|
|
1845
|
-
};
|
|
1846
|
-
} catch (error) {
|
|
1847
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1848
|
-
if (verbose) {
|
|
1849
|
-
console.warn(`Provisioning failed (continuing anyway): ${errorMessage}`);
|
|
1850
|
-
}
|
|
1851
|
-
return {
|
|
1852
|
-
provisioned: false,
|
|
1853
|
-
message: `Provisioning failed: ${errorMessage}`
|
|
1854
|
-
};
|
|
1855
|
-
}
|
|
1924
|
+
function resolveVSCodeConfig(target, env, insiders) {
|
|
1925
|
+
const settings = target.settings ?? {};
|
|
1926
|
+
const workspaceTemplateEnvVar = resolveOptionalLiteralString(settings.workspace_template ?? settings.workspaceTemplate);
|
|
1927
|
+
const workspaceTemplate = workspaceTemplateEnvVar ? resolveOptionalString(workspaceTemplateEnvVar, env, `${target.name} workspace template path`, {
|
|
1928
|
+
allowLiteral: false,
|
|
1929
|
+
optionalEnv: true
|
|
1930
|
+
}) : void 0;
|
|
1931
|
+
const commandSource = settings.vscode_cmd ?? settings.command;
|
|
1932
|
+
const waitSource = settings.wait;
|
|
1933
|
+
const dryRunSource = settings.dry_run ?? settings.dryRun;
|
|
1934
|
+
const subagentRootSource = settings.subagent_root ?? settings.subagentRoot;
|
|
1935
|
+
const defaultCommand = insiders ? "code-insiders" : "code";
|
|
1936
|
+
const command = resolveOptionalLiteralString(commandSource) ?? defaultCommand;
|
|
1937
|
+
return {
|
|
1938
|
+
command,
|
|
1939
|
+
waitForResponse: resolveOptionalBoolean(waitSource) ?? true,
|
|
1940
|
+
dryRun: resolveOptionalBoolean(dryRunSource) ?? false,
|
|
1941
|
+
subagentRoot: resolveOptionalString(subagentRootSource, env, `${target.name} subagent root`, {
|
|
1942
|
+
allowLiteral: true,
|
|
1943
|
+
optionalEnv: true
|
|
1944
|
+
}),
|
|
1945
|
+
workspaceTemplate
|
|
1946
|
+
};
|
|
1856
1947
|
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
var import_node_os = require("os");
|
|
1863
|
-
var import_node_path6 = __toESM(require("path"), 1);
|
|
1864
|
-
var import_node_util2 = require("util");
|
|
1865
|
-
|
|
1866
|
-
// src/evaluation/providers/preread.ts
|
|
1867
|
-
var import_node_path5 = __toESM(require("path"), 1);
|
|
1868
|
-
function buildPromptDocument2(request, inputFiles, options) {
|
|
1869
|
-
const parts = [];
|
|
1870
|
-
const guidelineFiles = collectGuidelineFiles2(
|
|
1871
|
-
inputFiles,
|
|
1872
|
-
options?.guidelinePatterns ?? request.guideline_patterns,
|
|
1873
|
-
options?.guidelineOverrides
|
|
1948
|
+
function resolveCliConfig(target, env) {
|
|
1949
|
+
const settings = target.settings ?? {};
|
|
1950
|
+
const commandTemplateSource = settings.command_template ?? settings.commandTemplate;
|
|
1951
|
+
const filesFormat = resolveOptionalLiteralString(
|
|
1952
|
+
settings.files_format ?? settings.filesFormat ?? settings.attachments_format ?? settings.attachmentsFormat
|
|
1874
1953
|
);
|
|
1875
|
-
const
|
|
1876
|
-
|
|
1877
|
-
|
|
1954
|
+
const cwd = resolveOptionalString(settings.cwd, env, `${target.name} working directory`, {
|
|
1955
|
+
allowLiteral: true,
|
|
1956
|
+
optionalEnv: true
|
|
1957
|
+
});
|
|
1958
|
+
const envOverrides = resolveEnvOverrides(settings.env, env, target.name);
|
|
1959
|
+
const timeoutMs = resolveTimeoutMs(settings.timeout_seconds ?? settings.timeoutSeconds, `${target.name} timeout`);
|
|
1960
|
+
const healthcheck = resolveCliHealthcheck(settings.healthcheck, env, target.name);
|
|
1961
|
+
const commandTemplate = resolveString(
|
|
1962
|
+
commandTemplateSource,
|
|
1963
|
+
env,
|
|
1964
|
+
`${target.name} CLI command template`,
|
|
1965
|
+
true
|
|
1878
1966
|
);
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1967
|
+
assertSupportedCliPlaceholders(commandTemplate, `${target.name} CLI command template`);
|
|
1968
|
+
return {
|
|
1969
|
+
commandTemplate,
|
|
1970
|
+
filesFormat,
|
|
1971
|
+
cwd,
|
|
1972
|
+
env: envOverrides,
|
|
1973
|
+
timeoutMs,
|
|
1974
|
+
healthcheck
|
|
1975
|
+
};
|
|
1885
1976
|
}
|
|
1886
|
-
function
|
|
1887
|
-
if (
|
|
1977
|
+
function resolveEnvOverrides(source, env, targetName) {
|
|
1978
|
+
if (source === void 0 || source === null) {
|
|
1888
1979
|
return void 0;
|
|
1889
1980
|
}
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
const absolutePath = import_node_path5.default.resolve(inputFile);
|
|
1893
|
-
if (!deduped.has(absolutePath)) {
|
|
1894
|
-
deduped.set(absolutePath, absolutePath);
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
return Array.from(deduped.values());
|
|
1898
|
-
}
|
|
1899
|
-
function collectGuidelineFiles2(inputFiles, guidelinePatterns, overrides) {
|
|
1900
|
-
if (!inputFiles || inputFiles.length === 0) {
|
|
1901
|
-
return [];
|
|
1981
|
+
if (typeof source !== "object" || Array.isArray(source)) {
|
|
1982
|
+
throw new Error(`${targetName} env overrides must be an object map of strings`);
|
|
1902
1983
|
}
|
|
1903
|
-
const
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
if (
|
|
1907
|
-
|
|
1908
|
-
unique.set(absolutePath, absolutePath);
|
|
1909
|
-
}
|
|
1910
|
-
continue;
|
|
1911
|
-
}
|
|
1912
|
-
const normalized = absolutePath.split(import_node_path5.default.sep).join("/");
|
|
1913
|
-
if (isGuidelineFile(normalized, guidelinePatterns)) {
|
|
1914
|
-
if (!unique.has(absolutePath)) {
|
|
1915
|
-
unique.set(absolutePath, absolutePath);
|
|
1916
|
-
}
|
|
1984
|
+
const entries = Object.entries(source);
|
|
1985
|
+
const resolved = {};
|
|
1986
|
+
for (const [key, value] of entries) {
|
|
1987
|
+
if (typeof value !== "string") {
|
|
1988
|
+
throw new Error(`${targetName} env override '${key}' must be a string`);
|
|
1917
1989
|
}
|
|
1990
|
+
const resolvedValue = resolveString(value, env, `${targetName} env override '${key}'`);
|
|
1991
|
+
resolved[key] = resolvedValue;
|
|
1918
1992
|
}
|
|
1919
|
-
return
|
|
1993
|
+
return Object.keys(resolved).length > 0 ? resolved : void 0;
|
|
1920
1994
|
}
|
|
1921
|
-
function
|
|
1922
|
-
|
|
1923
|
-
|
|
1995
|
+
function resolveTimeoutMs(source, description) {
|
|
1996
|
+
const seconds = resolveOptionalNumber(source, `${description} (seconds)`);
|
|
1997
|
+
if (seconds === void 0) {
|
|
1998
|
+
return void 0;
|
|
1924
1999
|
}
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
const absolutePath = import_node_path5.default.resolve(inputFile);
|
|
1928
|
-
if (!unique.has(absolutePath)) {
|
|
1929
|
-
unique.set(absolutePath, absolutePath);
|
|
1930
|
-
}
|
|
2000
|
+
if (seconds <= 0) {
|
|
2001
|
+
throw new Error(`${description} must be greater than zero seconds`);
|
|
1931
2002
|
}
|
|
1932
|
-
return
|
|
2003
|
+
return Math.floor(seconds * 1e3);
|
|
1933
2004
|
}
|
|
1934
|
-
function
|
|
1935
|
-
if (
|
|
1936
|
-
return
|
|
1937
|
-
}
|
|
1938
|
-
const buildList = (files) => files.map((absolutePath) => {
|
|
1939
|
-
const fileName = import_node_path5.default.basename(absolutePath);
|
|
1940
|
-
const fileUri = pathToFileUri2(absolutePath);
|
|
1941
|
-
return `* [${fileName}](${fileUri})`;
|
|
1942
|
-
});
|
|
1943
|
-
const sections = [];
|
|
1944
|
-
if (guidelineFiles.length > 0) {
|
|
1945
|
-
sections.push(`Read all guideline files:
|
|
1946
|
-
${buildList(guidelineFiles).join("\n")}.`);
|
|
2005
|
+
function resolveCliHealthcheck(source, env, targetName) {
|
|
2006
|
+
if (source === void 0 || source === null) {
|
|
2007
|
+
return void 0;
|
|
1947
2008
|
}
|
|
1948
|
-
if (
|
|
1949
|
-
|
|
1950
|
-
${buildList(inputFiles).join("\n")}.`);
|
|
2009
|
+
if (typeof source !== "object" || Array.isArray(source)) {
|
|
2010
|
+
throw new Error(`${targetName} healthcheck must be an object`);
|
|
1951
2011
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
2012
|
+
const candidate = source;
|
|
2013
|
+
const type = candidate.type;
|
|
2014
|
+
const timeoutMs = resolveTimeoutMs(
|
|
2015
|
+
candidate.timeout_seconds ?? candidate.timeoutSeconds,
|
|
2016
|
+
`${targetName} healthcheck timeout`
|
|
1955
2017
|
);
|
|
1956
|
-
|
|
1957
|
-
}
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
}
|
|
1964
|
-
return `file://${normalizedPath}`;
|
|
1965
|
-
}
|
|
1966
|
-
|
|
1967
|
-
// src/evaluation/providers/codex.ts
|
|
1968
|
-
var execAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.exec);
|
|
1969
|
-
var WORKSPACE_PREFIX = "agentv-codex-";
|
|
1970
|
-
var PROMPT_FILENAME = "prompt.md";
|
|
1971
|
-
var FILES_DIR = "files";
|
|
1972
|
-
var JSONL_TYPE_ITEM_COMPLETED = "item.completed";
|
|
1973
|
-
var CodexProvider = class {
|
|
1974
|
-
id;
|
|
1975
|
-
kind = "codex";
|
|
1976
|
-
targetName;
|
|
1977
|
-
supportsBatch = false;
|
|
1978
|
-
config;
|
|
1979
|
-
runCodex;
|
|
1980
|
-
environmentCheck;
|
|
1981
|
-
resolvedExecutable;
|
|
1982
|
-
constructor(targetName, config, runner = defaultCodexRunner) {
|
|
1983
|
-
this.id = `codex:${targetName}`;
|
|
1984
|
-
this.targetName = targetName;
|
|
1985
|
-
this.config = config;
|
|
1986
|
-
this.runCodex = runner;
|
|
2018
|
+
if (type === "http") {
|
|
2019
|
+
const url = resolveString(candidate.url, env, `${targetName} healthcheck URL`);
|
|
2020
|
+
return {
|
|
2021
|
+
type: "http",
|
|
2022
|
+
url,
|
|
2023
|
+
timeoutMs
|
|
2024
|
+
};
|
|
1987
2025
|
}
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
const originalGuidelines = new Set(
|
|
1995
|
-
collectGuidelineFiles2(inputFiles, request.guideline_patterns).map((file) => import_node_path6.default.resolve(file))
|
|
2026
|
+
if (type === "command") {
|
|
2027
|
+
const commandTemplate = resolveString(
|
|
2028
|
+
candidate.command_template ?? candidate.commandTemplate,
|
|
2029
|
+
env,
|
|
2030
|
+
`${targetName} healthcheck command template`,
|
|
2031
|
+
true
|
|
1996
2032
|
);
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2033
|
+
assertSupportedCliPlaceholders(commandTemplate, `${targetName} healthcheck command template`);
|
|
2034
|
+
const cwd = resolveOptionalString(candidate.cwd, env, `${targetName} healthcheck cwd`, {
|
|
2035
|
+
allowLiteral: true,
|
|
2036
|
+
optionalEnv: true
|
|
2037
|
+
});
|
|
2038
|
+
return {
|
|
2039
|
+
type: "command",
|
|
2040
|
+
commandTemplate,
|
|
2041
|
+
timeoutMs,
|
|
2042
|
+
cwd
|
|
2043
|
+
};
|
|
2044
|
+
}
|
|
2045
|
+
throw new Error(`${targetName} healthcheck type must be 'http' or 'command'`);
|
|
2046
|
+
}
|
|
2047
|
+
function assertSupportedCliPlaceholders(template, description) {
|
|
2048
|
+
const placeholders = extractCliPlaceholders(template);
|
|
2049
|
+
for (const placeholder of placeholders) {
|
|
2050
|
+
if (!CLI_PLACEHOLDERS.has(placeholder)) {
|
|
2051
|
+
throw new Error(
|
|
2052
|
+
`${description} includes unsupported placeholder '{${placeholder}}'. Supported placeholders: ${Array.from(CLI_PLACEHOLDERS).join(", ")}`
|
|
2003
2053
|
);
|
|
2004
|
-
const promptContent = buildPromptDocument2(request, mirroredInputFiles, {
|
|
2005
|
-
guidelinePatterns: request.guideline_patterns,
|
|
2006
|
-
guidelineOverrides: guidelineMirrors
|
|
2007
|
-
});
|
|
2008
|
-
const promptFile = import_node_path6.default.join(workspaceRoot, PROMPT_FILENAME);
|
|
2009
|
-
await (0, import_promises4.writeFile)(promptFile, promptContent, "utf8");
|
|
2010
|
-
const args = this.buildCodexArgs();
|
|
2011
|
-
const cwd = this.resolveCwd(workspaceRoot);
|
|
2012
|
-
const result = await this.executeCodex(args, cwd, promptContent, request.signal);
|
|
2013
|
-
if (result.timedOut) {
|
|
2014
|
-
throw new Error(
|
|
2015
|
-
`Codex CLI timed out${formatTimeoutSuffix2(this.config.timeoutMs ?? void 0)}`
|
|
2016
|
-
);
|
|
2017
|
-
}
|
|
2018
|
-
if (result.exitCode !== 0) {
|
|
2019
|
-
const detail = pickDetail(result.stderr, result.stdout);
|
|
2020
|
-
const prefix = `Codex CLI exited with code ${result.exitCode}`;
|
|
2021
|
-
throw new Error(detail ? `${prefix}: ${detail}` : prefix);
|
|
2022
|
-
}
|
|
2023
|
-
const parsed = parseCodexJson(result.stdout);
|
|
2024
|
-
const assistantText = extractAssistantText(parsed);
|
|
2025
|
-
return {
|
|
2026
|
-
text: assistantText,
|
|
2027
|
-
raw: {
|
|
2028
|
-
response: parsed,
|
|
2029
|
-
stdout: result.stdout,
|
|
2030
|
-
stderr: result.stderr,
|
|
2031
|
-
exitCode: result.exitCode,
|
|
2032
|
-
args,
|
|
2033
|
-
executable: this.resolvedExecutable ?? this.config.executable,
|
|
2034
|
-
promptFile,
|
|
2035
|
-
workspace: workspaceRoot,
|
|
2036
|
-
inputFiles: mirroredInputFiles
|
|
2037
|
-
}
|
|
2038
|
-
};
|
|
2039
|
-
} finally {
|
|
2040
|
-
await this.cleanupWorkspace(workspaceRoot);
|
|
2041
2054
|
}
|
|
2042
2055
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2056
|
+
}
|
|
2057
|
+
function extractCliPlaceholders(template) {
|
|
2058
|
+
const matches = template.matchAll(/\{([A-Z_]+)\}/g);
|
|
2059
|
+
const results = [];
|
|
2060
|
+
for (const match of matches) {
|
|
2061
|
+
if (match[1]) {
|
|
2062
|
+
results.push(match[1]);
|
|
2046
2063
|
}
|
|
2047
|
-
await this.environmentCheck;
|
|
2048
2064
|
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2065
|
+
return results;
|
|
2066
|
+
}
|
|
2067
|
+
function resolveString(source, env, description, allowLiteral = false) {
|
|
2068
|
+
const value = resolveOptionalString(source, env, description, {
|
|
2069
|
+
allowLiteral,
|
|
2070
|
+
optionalEnv: false
|
|
2071
|
+
});
|
|
2072
|
+
if (value === void 0) {
|
|
2073
|
+
throw new Error(`${description} is required`);
|
|
2051
2074
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
return
|
|
2075
|
+
return value;
|
|
2076
|
+
}
|
|
2077
|
+
function resolveOptionalString(source, env, description, options) {
|
|
2078
|
+
if (source === void 0 || source === null) {
|
|
2079
|
+
return void 0;
|
|
2057
2080
|
}
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
if (this.config.args && this.config.args.length > 0) {
|
|
2061
|
-
args.push(...this.config.args);
|
|
2062
|
-
}
|
|
2063
|
-
args.push("-");
|
|
2064
|
-
return args;
|
|
2081
|
+
if (typeof source !== "string") {
|
|
2082
|
+
throw new Error(`${description} must be a string`);
|
|
2065
2083
|
}
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
executable: this.resolvedExecutable ?? this.config.executable,
|
|
2070
|
-
args,
|
|
2071
|
-
cwd,
|
|
2072
|
-
prompt: promptContent,
|
|
2073
|
-
timeoutMs: this.config.timeoutMs,
|
|
2074
|
-
env: process.env,
|
|
2075
|
-
signal
|
|
2076
|
-
});
|
|
2077
|
-
} catch (error) {
|
|
2078
|
-
const err = error;
|
|
2079
|
-
if (err.code === "ENOENT") {
|
|
2080
|
-
throw new Error(
|
|
2081
|
-
`Codex executable '${this.config.executable}' was not found. Update the target settings.executable or add it to PATH.`
|
|
2082
|
-
);
|
|
2083
|
-
}
|
|
2084
|
-
throw error;
|
|
2085
|
-
}
|
|
2084
|
+
const trimmed = source.trim();
|
|
2085
|
+
if (trimmed.length === 0) {
|
|
2086
|
+
return void 0;
|
|
2086
2087
|
}
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
guidelineMirrors: /* @__PURE__ */ new Set()
|
|
2092
|
-
};
|
|
2093
|
-
}
|
|
2094
|
-
const filesRoot = import_node_path6.default.join(workspaceRoot, FILES_DIR);
|
|
2095
|
-
await (0, import_promises4.mkdir)(filesRoot, { recursive: true });
|
|
2096
|
-
const mirrored = [];
|
|
2097
|
-
const guidelineMirrors = /* @__PURE__ */ new Set();
|
|
2098
|
-
const nameCounts = /* @__PURE__ */ new Map();
|
|
2099
|
-
for (const inputFile of inputFiles) {
|
|
2100
|
-
const absoluteSource = import_node_path6.default.resolve(inputFile);
|
|
2101
|
-
const baseName = import_node_path6.default.basename(absoluteSource);
|
|
2102
|
-
const count = nameCounts.get(baseName) ?? 0;
|
|
2103
|
-
nameCounts.set(baseName, count + 1);
|
|
2104
|
-
const finalName = count === 0 ? baseName : `${baseName}.${count}`;
|
|
2105
|
-
const destination = import_node_path6.default.join(filesRoot, finalName);
|
|
2106
|
-
await (0, import_promises4.copyFile)(absoluteSource, destination);
|
|
2107
|
-
const resolvedDestination = import_node_path6.default.resolve(destination);
|
|
2108
|
-
mirrored.push(resolvedDestination);
|
|
2109
|
-
if (guidelineOriginals.has(absoluteSource)) {
|
|
2110
|
-
guidelineMirrors.add(resolvedDestination);
|
|
2111
|
-
}
|
|
2088
|
+
const envValue = env[trimmed];
|
|
2089
|
+
if (envValue !== void 0) {
|
|
2090
|
+
if (envValue.trim().length === 0) {
|
|
2091
|
+
throw new Error(`Environment variable '${trimmed}' for ${description} is empty`);
|
|
2112
2092
|
}
|
|
2113
|
-
return
|
|
2114
|
-
mirroredInputFiles: mirrored,
|
|
2115
|
-
guidelineMirrors
|
|
2116
|
-
};
|
|
2117
|
-
}
|
|
2118
|
-
async createWorkspace() {
|
|
2119
|
-
return await (0, import_promises4.mkdtemp)(import_node_path6.default.join((0, import_node_os.tmpdir)(), WORKSPACE_PREFIX));
|
|
2093
|
+
return envValue;
|
|
2120
2094
|
}
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2095
|
+
const allowLiteral = options?.allowLiteral ?? false;
|
|
2096
|
+
const optionalEnv = options?.optionalEnv ?? false;
|
|
2097
|
+
const looksLikeEnv = isLikelyEnvReference(trimmed);
|
|
2098
|
+
if (looksLikeEnv) {
|
|
2099
|
+
if (optionalEnv) {
|
|
2100
|
+
return void 0;
|
|
2101
|
+
}
|
|
2102
|
+
if (!allowLiteral) {
|
|
2103
|
+
throw new Error(`Environment variable '${trimmed}' required for ${description} is not set`);
|
|
2125
2104
|
}
|
|
2126
2105
|
}
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
if (
|
|
2131
|
-
|
|
2132
|
-
const executablePath = await ensureWindowsExecutableVariant(resolved);
|
|
2133
|
-
await (0, import_promises4.access)(executablePath, import_node_fs3.constants.F_OK);
|
|
2134
|
-
return executablePath;
|
|
2106
|
+
return trimmed;
|
|
2107
|
+
}
|
|
2108
|
+
function resolveOptionalLiteralString(source) {
|
|
2109
|
+
if (source === void 0 || source === null) {
|
|
2110
|
+
return void 0;
|
|
2135
2111
|
}
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
const { stdout } = await execAsync2(`${locator} ${candidate}`);
|
|
2139
|
-
const lines = stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
2140
|
-
const preferred = selectExecutableCandidate(lines);
|
|
2141
|
-
if (preferred) {
|
|
2142
|
-
const executablePath = await ensureWindowsExecutableVariant(preferred);
|
|
2143
|
-
await (0, import_promises4.access)(executablePath, import_node_fs3.constants.F_OK);
|
|
2144
|
-
return executablePath;
|
|
2145
|
-
}
|
|
2146
|
-
} catch {
|
|
2112
|
+
if (typeof source !== "string") {
|
|
2113
|
+
throw new Error("expected string value");
|
|
2147
2114
|
}
|
|
2148
|
-
|
|
2115
|
+
const trimmed = source.trim();
|
|
2116
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
2149
2117
|
}
|
|
2150
|
-
function
|
|
2151
|
-
if (
|
|
2118
|
+
function resolveOptionalNumber(source, description) {
|
|
2119
|
+
if (source === void 0 || source === null || source === "") {
|
|
2152
2120
|
return void 0;
|
|
2153
2121
|
}
|
|
2154
|
-
if (
|
|
2155
|
-
return
|
|
2122
|
+
if (typeof source === "number") {
|
|
2123
|
+
return Number.isFinite(source) ? source : void 0;
|
|
2156
2124
|
}
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
return match;
|
|
2125
|
+
if (typeof source === "string") {
|
|
2126
|
+
const numeric = Number(source);
|
|
2127
|
+
if (Number.isFinite(numeric)) {
|
|
2128
|
+
return numeric;
|
|
2162
2129
|
}
|
|
2163
2130
|
}
|
|
2164
|
-
|
|
2131
|
+
throw new Error(`${description} must be a number`);
|
|
2165
2132
|
}
|
|
2166
|
-
|
|
2167
|
-
if (
|
|
2168
|
-
return
|
|
2133
|
+
function resolveOptionalBoolean(source) {
|
|
2134
|
+
if (source === void 0 || source === null || source === "") {
|
|
2135
|
+
return void 0;
|
|
2169
2136
|
}
|
|
2170
|
-
if (
|
|
2171
|
-
return
|
|
2137
|
+
if (typeof source === "boolean") {
|
|
2138
|
+
return source;
|
|
2172
2139
|
}
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2140
|
+
if (typeof source === "string") {
|
|
2141
|
+
const lowered = source.trim().toLowerCase();
|
|
2142
|
+
if (lowered === "true" || lowered === "1") {
|
|
2143
|
+
return true;
|
|
2144
|
+
}
|
|
2145
|
+
if (lowered === "false" || lowered === "0") {
|
|
2146
|
+
return false;
|
|
2180
2147
|
}
|
|
2181
2148
|
}
|
|
2182
|
-
|
|
2149
|
+
throw new Error("expected boolean value");
|
|
2183
2150
|
}
|
|
2184
|
-
function
|
|
2185
|
-
|
|
2186
|
-
return getWindowsExecutableExtensions().some((ext) => lower.endsWith(ext));
|
|
2151
|
+
function isLikelyEnvReference(value) {
|
|
2152
|
+
return /^[A-Z0-9_]+$/.test(value);
|
|
2187
2153
|
}
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
return [];
|
|
2154
|
+
function resolveOptionalStringArray(source, env, description) {
|
|
2155
|
+
if (source === void 0 || source === null) {
|
|
2156
|
+
return void 0;
|
|
2192
2157
|
}
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
}
|
|
2196
|
-
function parseCodexJson(output) {
|
|
2197
|
-
const trimmed = output.trim();
|
|
2198
|
-
if (trimmed.length === 0) {
|
|
2199
|
-
throw new Error("Codex CLI produced no output in --json mode");
|
|
2158
|
+
if (!Array.isArray(source)) {
|
|
2159
|
+
throw new Error(`${description} must be an array of strings`);
|
|
2200
2160
|
}
|
|
2201
|
-
|
|
2202
|
-
return
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2161
|
+
if (source.length === 0) {
|
|
2162
|
+
return void 0;
|
|
2163
|
+
}
|
|
2164
|
+
const resolved = [];
|
|
2165
|
+
for (let i = 0; i < source.length; i++) {
|
|
2166
|
+
const item = source[i];
|
|
2167
|
+
if (typeof item !== "string") {
|
|
2168
|
+
throw new Error(`${description}[${i}] must be a string`);
|
|
2207
2169
|
}
|
|
2208
|
-
const
|
|
2209
|
-
if (
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2170
|
+
const trimmed = item.trim();
|
|
2171
|
+
if (trimmed.length === 0) {
|
|
2172
|
+
throw new Error(`${description}[${i}] cannot be empty`);
|
|
2173
|
+
}
|
|
2174
|
+
const envValue = env[trimmed];
|
|
2175
|
+
if (envValue !== void 0) {
|
|
2176
|
+
if (envValue.trim().length === 0) {
|
|
2177
|
+
throw new Error(`Environment variable '${trimmed}' for ${description}[${i}] is empty`);
|
|
2214
2178
|
}
|
|
2179
|
+
resolved.push(envValue);
|
|
2180
|
+
} else {
|
|
2181
|
+
resolved.push(trimmed);
|
|
2215
2182
|
}
|
|
2216
|
-
const preview = trimmed.slice(0, 200);
|
|
2217
|
-
throw new Error(`Codex CLI emitted invalid JSON: ${preview}${trimmed.length > 200 ? "\u2026" : ""}`);
|
|
2218
2183
|
}
|
|
2184
|
+
return resolved.length > 0 ? resolved : void 0;
|
|
2219
2185
|
}
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2186
|
+
|
|
2187
|
+
// src/evaluation/providers/vscode.ts
|
|
2188
|
+
var import_promises4 = require("fs/promises");
|
|
2189
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
2190
|
+
var import_subagent = require("subagent");
|
|
2191
|
+
var VSCodeProvider = class {
|
|
2192
|
+
id;
|
|
2193
|
+
kind;
|
|
2194
|
+
targetName;
|
|
2195
|
+
supportsBatch = true;
|
|
2196
|
+
config;
|
|
2197
|
+
constructor(targetName, config, kind) {
|
|
2198
|
+
this.id = `${kind}:${targetName}`;
|
|
2199
|
+
this.kind = kind;
|
|
2200
|
+
this.targetName = targetName;
|
|
2201
|
+
this.config = config;
|
|
2234
2202
|
}
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2203
|
+
async invoke(request) {
|
|
2204
|
+
if (request.signal?.aborted) {
|
|
2205
|
+
throw new Error("VS Code provider request was aborted before dispatch");
|
|
2206
|
+
}
|
|
2207
|
+
const inputFiles = normalizeAttachments(request.inputFiles);
|
|
2208
|
+
const promptContent = buildPromptDocument2(request, inputFiles, request.guideline_patterns);
|
|
2209
|
+
const session = await (0, import_subagent.dispatchAgentSession)({
|
|
2210
|
+
userQuery: promptContent,
|
|
2211
|
+
extraAttachments: inputFiles,
|
|
2212
|
+
wait: this.config.waitForResponse,
|
|
2213
|
+
dryRun: this.config.dryRun,
|
|
2214
|
+
vscodeCmd: this.config.command,
|
|
2215
|
+
subagentRoot: this.config.subagentRoot,
|
|
2216
|
+
workspaceTemplate: this.config.workspaceTemplate,
|
|
2217
|
+
silent: true
|
|
2218
|
+
});
|
|
2219
|
+
if (session.exitCode !== 0 || !session.responseFile) {
|
|
2220
|
+
const failure = session.error ?? "VS Code subagent did not produce a response";
|
|
2221
|
+
throw new Error(failure);
|
|
2222
|
+
}
|
|
2223
|
+
if (this.config.dryRun) {
|
|
2224
|
+
return {
|
|
2225
|
+
text: "",
|
|
2226
|
+
raw: {
|
|
2227
|
+
session,
|
|
2228
|
+
inputFiles
|
|
2229
|
+
}
|
|
2230
|
+
};
|
|
2251
2231
|
}
|
|
2232
|
+
const responseText = await (0, import_promises4.readFile)(session.responseFile, "utf8");
|
|
2233
|
+
return {
|
|
2234
|
+
text: responseText,
|
|
2235
|
+
raw: {
|
|
2236
|
+
session,
|
|
2237
|
+
inputFiles
|
|
2238
|
+
}
|
|
2239
|
+
};
|
|
2252
2240
|
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2241
|
+
async invokeBatch(requests) {
|
|
2242
|
+
if (requests.length === 0) {
|
|
2243
|
+
return [];
|
|
2244
|
+
}
|
|
2245
|
+
const normalizedRequests = requests.map((req) => ({
|
|
2246
|
+
request: req,
|
|
2247
|
+
inputFiles: normalizeAttachments(req.inputFiles)
|
|
2248
|
+
}));
|
|
2249
|
+
const combinedInputFiles = mergeAttachments(
|
|
2250
|
+
normalizedRequests.map(({ inputFiles }) => inputFiles)
|
|
2251
|
+
);
|
|
2252
|
+
const userQueries = normalizedRequests.map(
|
|
2253
|
+
({ request, inputFiles }) => buildPromptDocument2(request, inputFiles, request.guideline_patterns)
|
|
2254
|
+
);
|
|
2255
|
+
const session = await (0, import_subagent.dispatchBatchAgent)({
|
|
2256
|
+
userQueries,
|
|
2257
|
+
extraAttachments: combinedInputFiles,
|
|
2258
|
+
wait: this.config.waitForResponse,
|
|
2259
|
+
dryRun: this.config.dryRun,
|
|
2260
|
+
vscodeCmd: this.config.command,
|
|
2261
|
+
subagentRoot: this.config.subagentRoot,
|
|
2262
|
+
workspaceTemplate: this.config.workspaceTemplate,
|
|
2263
|
+
silent: true
|
|
2264
|
+
});
|
|
2265
|
+
if (session.exitCode !== 0 || !session.responseFiles) {
|
|
2266
|
+
const failure = session.error ?? "VS Code subagent did not produce batch responses";
|
|
2267
|
+
throw new Error(failure);
|
|
2268
|
+
}
|
|
2269
|
+
if (this.config.dryRun) {
|
|
2270
|
+
return normalizedRequests.map(({ inputFiles }) => ({
|
|
2271
|
+
text: "",
|
|
2272
|
+
raw: {
|
|
2273
|
+
session,
|
|
2274
|
+
inputFiles,
|
|
2275
|
+
allInputFiles: combinedInputFiles
|
|
2276
|
+
}
|
|
2277
|
+
}));
|
|
2278
|
+
}
|
|
2279
|
+
if (session.responseFiles.length !== requests.length) {
|
|
2280
|
+
throw new Error(
|
|
2281
|
+
`VS Code batch returned ${session.responseFiles.length} responses for ${requests.length} requests`
|
|
2282
|
+
);
|
|
2259
2283
|
}
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
if (text) {
|
|
2273
|
-
return text;
|
|
2284
|
+
const responses = [];
|
|
2285
|
+
for (const [index, responseFile] of session.responseFiles.entries()) {
|
|
2286
|
+
const responseText = await (0, import_promises4.readFile)(responseFile, "utf8");
|
|
2287
|
+
responses.push({
|
|
2288
|
+
text: responseText,
|
|
2289
|
+
raw: {
|
|
2290
|
+
session,
|
|
2291
|
+
inputFiles: normalizedRequests[index]?.inputFiles,
|
|
2292
|
+
allInputFiles: combinedInputFiles,
|
|
2293
|
+
responseFile
|
|
2294
|
+
}
|
|
2295
|
+
});
|
|
2274
2296
|
}
|
|
2297
|
+
return responses;
|
|
2275
2298
|
}
|
|
2276
|
-
|
|
2299
|
+
};
|
|
2300
|
+
function buildPromptDocument2(request, attachments, guidelinePatterns) {
|
|
2301
|
+
const parts = [];
|
|
2302
|
+
const guidelineFiles = collectGuidelineFiles2(attachments, guidelinePatterns);
|
|
2303
|
+
const attachmentFiles = collectAttachmentFiles(attachments);
|
|
2304
|
+
const nonGuidelineAttachments = attachmentFiles.filter(
|
|
2305
|
+
(file) => !guidelineFiles.includes(file)
|
|
2306
|
+
);
|
|
2307
|
+
const prereadBlock = buildMandatoryPrereadBlock2(guidelineFiles, nonGuidelineAttachments);
|
|
2308
|
+
if (prereadBlock.length > 0) {
|
|
2309
|
+
parts.push("\n", prereadBlock);
|
|
2310
|
+
}
|
|
2311
|
+
parts.push("\n[[ ## user_query ## ]]\n", request.prompt.trim());
|
|
2312
|
+
return parts.join("\n").trim();
|
|
2277
2313
|
}
|
|
2278
|
-
function
|
|
2279
|
-
if (
|
|
2280
|
-
return
|
|
2314
|
+
function buildMandatoryPrereadBlock2(guidelineFiles, attachmentFiles) {
|
|
2315
|
+
if (guidelineFiles.length === 0 && attachmentFiles.length === 0) {
|
|
2316
|
+
return "";
|
|
2281
2317
|
}
|
|
2282
|
-
const
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2318
|
+
const buildList = (files) => files.map((absolutePath) => {
|
|
2319
|
+
const fileName = import_node_path6.default.basename(absolutePath);
|
|
2320
|
+
const fileUri = pathToFileUri2(absolutePath);
|
|
2321
|
+
return `* [${fileName}](${fileUri})`;
|
|
2322
|
+
});
|
|
2323
|
+
const sections = [];
|
|
2324
|
+
if (guidelineFiles.length > 0) {
|
|
2325
|
+
sections.push(`Read all guideline files:
|
|
2326
|
+
${buildList(guidelineFiles).join("\n")}.`);
|
|
2290
2327
|
}
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
return flattened;
|
|
2328
|
+
if (attachmentFiles.length > 0) {
|
|
2329
|
+
sections.push(`Read all attachment files:
|
|
2330
|
+
${buildList(attachmentFiles).join("\n")}.`);
|
|
2295
2331
|
}
|
|
2296
|
-
|
|
2332
|
+
sections.push(
|
|
2333
|
+
"If any file is missing, fail with ERROR: missing-file <filename> and stop.",
|
|
2334
|
+
"Then apply system_instructions on the user query below."
|
|
2335
|
+
);
|
|
2336
|
+
return sections.join("\n");
|
|
2297
2337
|
}
|
|
2298
|
-
function
|
|
2299
|
-
if (!
|
|
2300
|
-
return
|
|
2338
|
+
function collectGuidelineFiles2(attachments, guidelinePatterns) {
|
|
2339
|
+
if (!attachments || attachments.length === 0) {
|
|
2340
|
+
return [];
|
|
2301
2341
|
}
|
|
2302
|
-
const
|
|
2303
|
-
const
|
|
2304
|
-
|
|
2305
|
-
const
|
|
2306
|
-
if (
|
|
2307
|
-
|
|
2342
|
+
const unique = /* @__PURE__ */ new Map();
|
|
2343
|
+
for (const attachment of attachments) {
|
|
2344
|
+
const absolutePath = import_node_path6.default.resolve(attachment);
|
|
2345
|
+
const normalized = absolutePath.split(import_node_path6.default.sep).join("/");
|
|
2346
|
+
if (isGuidelineFile(normalized, guidelinePatterns)) {
|
|
2347
|
+
if (!unique.has(absolutePath)) {
|
|
2348
|
+
unique.set(absolutePath, absolutePath);
|
|
2349
|
+
}
|
|
2308
2350
|
}
|
|
2309
2351
|
}
|
|
2310
|
-
return
|
|
2352
|
+
return Array.from(unique.values());
|
|
2311
2353
|
}
|
|
2312
|
-
function
|
|
2313
|
-
if (
|
|
2314
|
-
return
|
|
2354
|
+
function collectAttachmentFiles(attachments) {
|
|
2355
|
+
if (!attachments || attachments.length === 0) {
|
|
2356
|
+
return [];
|
|
2315
2357
|
}
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
const text = segment.text;
|
|
2323
|
-
return typeof text === "string" ? text : void 0;
|
|
2324
|
-
}
|
|
2325
|
-
return void 0;
|
|
2326
|
-
}).filter((part) => typeof part === "string" && part.length > 0);
|
|
2327
|
-
return parts.length > 0 ? parts.join(" \n") : void 0;
|
|
2358
|
+
const unique = /* @__PURE__ */ new Map();
|
|
2359
|
+
for (const attachment of attachments) {
|
|
2360
|
+
const absolutePath = import_node_path6.default.resolve(attachment);
|
|
2361
|
+
if (!unique.has(absolutePath)) {
|
|
2362
|
+
unique.set(absolutePath, absolutePath);
|
|
2363
|
+
}
|
|
2328
2364
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2365
|
+
return Array.from(unique.values());
|
|
2366
|
+
}
|
|
2367
|
+
function pathToFileUri2(filePath) {
|
|
2368
|
+
const absolutePath = import_node_path6.default.isAbsolute(filePath) ? filePath : import_node_path6.default.resolve(filePath);
|
|
2369
|
+
const normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
2370
|
+
if (/^[a-zA-Z]:\//.test(normalizedPath)) {
|
|
2371
|
+
return `file:///${normalizedPath}`;
|
|
2332
2372
|
}
|
|
2333
|
-
return
|
|
2373
|
+
return `file://${normalizedPath}`;
|
|
2334
2374
|
}
|
|
2335
|
-
function
|
|
2336
|
-
|
|
2337
|
-
if (lines.length <= 1) {
|
|
2375
|
+
function normalizeAttachments(attachments) {
|
|
2376
|
+
if (!attachments || attachments.length === 0) {
|
|
2338
2377
|
return void 0;
|
|
2339
2378
|
}
|
|
2340
|
-
const
|
|
2341
|
-
for (const
|
|
2342
|
-
|
|
2343
|
-
parsed.push(JSON.parse(line));
|
|
2344
|
-
} catch {
|
|
2345
|
-
return void 0;
|
|
2346
|
-
}
|
|
2347
|
-
}
|
|
2348
|
-
return parsed;
|
|
2349
|
-
}
|
|
2350
|
-
function pickDetail(stderr, stdout) {
|
|
2351
|
-
const errorText = stderr.trim();
|
|
2352
|
-
if (errorText.length > 0) {
|
|
2353
|
-
return errorText;
|
|
2379
|
+
const deduped = /* @__PURE__ */ new Set();
|
|
2380
|
+
for (const attachment of attachments) {
|
|
2381
|
+
deduped.add(import_node_path6.default.resolve(attachment));
|
|
2354
2382
|
}
|
|
2355
|
-
|
|
2356
|
-
return stdoutText.length > 0 ? stdoutText : void 0;
|
|
2383
|
+
return Array.from(deduped);
|
|
2357
2384
|
}
|
|
2358
|
-
function
|
|
2359
|
-
|
|
2360
|
-
|
|
2385
|
+
function mergeAttachments(all) {
|
|
2386
|
+
const deduped = /* @__PURE__ */ new Set();
|
|
2387
|
+
for (const list of all) {
|
|
2388
|
+
if (!list) continue;
|
|
2389
|
+
for (const inputFile of list) {
|
|
2390
|
+
deduped.add(import_node_path6.default.resolve(inputFile));
|
|
2391
|
+
}
|
|
2361
2392
|
}
|
|
2362
|
-
|
|
2363
|
-
return ` after ${seconds}s`;
|
|
2393
|
+
return deduped.size > 0 ? Array.from(deduped) : void 0;
|
|
2364
2394
|
}
|
|
2365
|
-
async function
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
});
|
|
2373
|
-
let stdout = "";
|
|
2374
|
-
let stderr = "";
|
|
2375
|
-
let timedOut = false;
|
|
2376
|
-
const onAbort = () => {
|
|
2377
|
-
child.kill("SIGTERM");
|
|
2378
|
-
};
|
|
2379
|
-
if (options.signal) {
|
|
2380
|
-
if (options.signal.aborted) {
|
|
2381
|
-
onAbort();
|
|
2382
|
-
} else {
|
|
2383
|
-
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
|
-
let timeoutHandle;
|
|
2387
|
-
if (options.timeoutMs && options.timeoutMs > 0) {
|
|
2388
|
-
timeoutHandle = setTimeout(() => {
|
|
2389
|
-
timedOut = true;
|
|
2390
|
-
child.kill("SIGTERM");
|
|
2391
|
-
}, options.timeoutMs);
|
|
2392
|
-
timeoutHandle.unref?.();
|
|
2395
|
+
async function ensureVSCodeSubagents(options) {
|
|
2396
|
+
const { kind, count, verbose = false } = options;
|
|
2397
|
+
const vscodeCmd = kind === "vscode-insiders" ? "code-insiders" : "code";
|
|
2398
|
+
const subagentRoot = (0, import_subagent.getSubagentRoot)(vscodeCmd);
|
|
2399
|
+
try {
|
|
2400
|
+
if (verbose) {
|
|
2401
|
+
console.log(`Provisioning ${count} subagent(s) via: subagent ${vscodeCmd} provision`);
|
|
2393
2402
|
}
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
child.stderr.setEncoding("utf8");
|
|
2399
|
-
child.stderr.on("data", (chunk) => {
|
|
2400
|
-
stderr += chunk;
|
|
2403
|
+
const result = await (0, import_subagent.provisionSubagents)({
|
|
2404
|
+
targetRoot: subagentRoot,
|
|
2405
|
+
subagents: count,
|
|
2406
|
+
dryRun: false
|
|
2401
2407
|
});
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
clearTimeout(timeoutHandle);
|
|
2408
|
+
if (verbose) {
|
|
2409
|
+
if (result.created.length > 0) {
|
|
2410
|
+
console.log(`Created ${result.created.length} new subagent(s)`);
|
|
2406
2411
|
}
|
|
2407
|
-
if (
|
|
2408
|
-
|
|
2412
|
+
if (result.skippedExisting.length > 0) {
|
|
2413
|
+
console.log(`Reusing ${result.skippedExisting.length} existing unlocked subagent(s)`);
|
|
2409
2414
|
}
|
|
2415
|
+
console.log(`
|
|
2416
|
+
total unlocked subagents available: ${result.created.length + result.skippedExisting.length}`);
|
|
2417
|
+
}
|
|
2418
|
+
return {
|
|
2419
|
+
provisioned: true,
|
|
2420
|
+
message: `Provisioned ${count} subagent(s): ${result.created.length} created, ${result.skippedExisting.length} reused`
|
|
2421
|
+
};
|
|
2422
|
+
} catch (error) {
|
|
2423
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2424
|
+
if (verbose) {
|
|
2425
|
+
console.warn(`Provisioning failed (continuing anyway): ${errorMessage}`);
|
|
2426
|
+
}
|
|
2427
|
+
return {
|
|
2428
|
+
provisioned: false,
|
|
2429
|
+
message: `Provisioning failed: ${errorMessage}`
|
|
2410
2430
|
};
|
|
2411
|
-
child.on("error", (error) => {
|
|
2412
|
-
cleanup();
|
|
2413
|
-
reject(error);
|
|
2414
|
-
});
|
|
2415
|
-
child.on("close", (code) => {
|
|
2416
|
-
cleanup();
|
|
2417
|
-
resolve({
|
|
2418
|
-
stdout,
|
|
2419
|
-
stderr,
|
|
2420
|
-
exitCode: typeof code === "number" ? code : -1,
|
|
2421
|
-
timedOut
|
|
2422
|
-
});
|
|
2423
|
-
});
|
|
2424
|
-
});
|
|
2425
|
-
}
|
|
2426
|
-
function shouldShellExecute(executable) {
|
|
2427
|
-
if (process.platform !== "win32") {
|
|
2428
|
-
return false;
|
|
2429
2431
|
}
|
|
2430
|
-
const lower = executable.toLowerCase();
|
|
2431
|
-
return lower.endsWith(".cmd") || lower.endsWith(".bat") || lower.endsWith(".ps1");
|
|
2432
2432
|
}
|
|
2433
2433
|
|
|
2434
2434
|
// src/evaluation/providers/targets-file.ts
|