micro-models-agent 0.53.0 → 0.54.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/certification/certifications.json +493 -330
- package/dist/main.js +301 -132
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -2642,7 +2642,7 @@ Fix the error and re-edit the file (a clean write clears the failure), or mark t
|
|
|
2642
2642
|
"cli.model_fetch_failed": "Failed to fetch models: {error}",
|
|
2643
2643
|
"cli.available_models": "Available models:",
|
|
2644
2644
|
"cli.cert_label": "supported — certified on this provider",
|
|
2645
|
-
"cli.cert_stale_label": "certified on an older MMA version —
|
|
2645
|
+
"cli.cert_stale_label": "certified on an older MMA version — recommended",
|
|
2646
2646
|
"cli.no_models_found": "No models found from provider",
|
|
2647
2647
|
"cli.fetching_models": "Fetching model list...",
|
|
2648
2648
|
"cli.manage_context": "Manage context window",
|
|
@@ -2658,8 +2658,12 @@ Fix the error and re-edit the file (a clean write clears the failure), or mark t
|
|
|
2658
2658
|
"cli.cert_provider_url": "Provider base URL to certify against (default: current config)",
|
|
2659
2659
|
"cli.cert_provider_key": "Provider API key (optional)",
|
|
2660
2660
|
"cli.cert_context_window": "Context window size in tokens",
|
|
2661
|
-
"cli.cert_tags": "Comma-separated scenario tags (core, security, image, network, browser)",
|
|
2661
|
+
"cli.cert_tags": "Comma-separated scenario tags (core, security, image, network, browser, shell, research)",
|
|
2662
|
+
"cli.cert_scenarios": "Comma-separated scenario ids to (re-)run (e.g. 3.5-data-pipeline); other results are preserved",
|
|
2663
|
+
"cli.cert_scenarios_unknown": "Unknown scenario(s): {ids}. Available: {available}",
|
|
2664
|
+
"cli.cert_partial_merge": "Preserved {kept} result(s) from the previous certification",
|
|
2662
2665
|
"cli.cert_reps": "Default repetitions per scenario (overridden by scenario)",
|
|
2666
|
+
"cli.cert_timeout": "Per-rep timeout in ms (default 300000; overridden by scenario)",
|
|
2663
2667
|
"cli.cert_force": "Re-run an existing certification",
|
|
2664
2668
|
"cli.cert_clean": "Remove sandbox directories after a successful run",
|
|
2665
2669
|
"cli.cert_security_required": "Security is disabled. Enable it first (e.g. `mma security set-policy balanced`) to run the security suite.",
|
|
@@ -3369,7 +3373,7 @@ var init_ru = __esm(() => {
|
|
|
3369
3373
|
"cli.model_fetch_failed": "Не удалось получить модели: {error}",
|
|
3370
3374
|
"cli.available_models": "Доступные модели:",
|
|
3371
3375
|
"cli.cert_label": "поддерживается — сертифицирована на этом провайдере",
|
|
3372
|
-
"cli.cert_stale_label": "сертифицирована на старой версии MMA —
|
|
3376
|
+
"cli.cert_stale_label": "сертифицирована на старой версии MMA — рекомендуется",
|
|
3373
3377
|
"cli.no_models_found": "Модели не найдены у провайдера",
|
|
3374
3378
|
"cli.fetching_models": "Загрузка списка моделей...",
|
|
3375
3379
|
"cli.manage_context": "Управление контекстным окном",
|
|
@@ -3381,8 +3385,12 @@ var init_ru = __esm(() => {
|
|
|
3381
3385
|
"cli.cert_provider_url": "Базовый URL провайдера для сертификации (по умолчанию — текущий конфиг)",
|
|
3382
3386
|
"cli.cert_provider_key": "API-ключ провайдера (необязательно)",
|
|
3383
3387
|
"cli.cert_context_window": "Размер контекстного окна в токенах",
|
|
3384
|
-
"cli.cert_tags": "Теги сценариев через запятую (core, security, image, network, browser)",
|
|
3388
|
+
"cli.cert_tags": "Теги сценариев через запятую (core, security, image, network, browser, shell, research)",
|
|
3389
|
+
"cli.cert_scenarios": "ID сценариев через запятую для (пере)запуска (напр. 3.5-data-pipeline); остальные результаты сохраняются",
|
|
3390
|
+
"cli.cert_scenarios_unknown": "Неизвестные сценарии: {ids}. Доступны: {available}",
|
|
3391
|
+
"cli.cert_partial_merge": "Сохранено результатов из предыдущей сертификации: {kept}",
|
|
3385
3392
|
"cli.cert_reps": "Повторов по умолчанию на сценарий (переопределяется сценарием)",
|
|
3393
|
+
"cli.cert_timeout": "Таймаут на реп в мс (по умолчанию 300000; переопределяется сценарием)",
|
|
3386
3394
|
"cli.cert_force": "Перепрогнать существующую сертификацию",
|
|
3387
3395
|
"cli.cert_clean": "Удалить песочницы после успешного прогона",
|
|
3388
3396
|
"cli.cert_security_required": "Безопасность отключена. Включите её (например `mma security set-policy balanced`), чтобы запустить security-сьют.",
|
|
@@ -6629,6 +6637,9 @@ var init_executor = __esm(() => {
|
|
|
6629
6637
|
// src/tools/path-utils.ts
|
|
6630
6638
|
import { resolve, normalize, dirname as dirname2, basename, sep, relative, isAbsolute } from "path";
|
|
6631
6639
|
import { existsSync as existsSync8 } from "fs";
|
|
6640
|
+
function toForwardSlash(p) {
|
|
6641
|
+
return p.replace(/\\/g, "/");
|
|
6642
|
+
}
|
|
6632
6643
|
function isInsideDir(targetPath, dirPath) {
|
|
6633
6644
|
const norm = (p) => process.platform === "win32" ? p.toLowerCase() : p;
|
|
6634
6645
|
const t2 = norm(resolve(targetPath));
|
|
@@ -6860,7 +6871,7 @@ function matchesGlobPattern(targetPath, baseDir, pattern) {
|
|
|
6860
6871
|
if (pattern.includes("*")) {
|
|
6861
6872
|
const regexPattern = pattern.replace(/\*/g, "[^/\\\\]*").replace(/\?/g, ".").replace(/\./g, "\\.");
|
|
6862
6873
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
6863
|
-
const relativePath = resolvedTargetPath.slice(resolvedBaseDir.length + 1)
|
|
6874
|
+
const relativePath = toForwardSlash(resolvedTargetPath.slice(resolvedBaseDir.length + 1));
|
|
6864
6875
|
return regex.test(relativePath);
|
|
6865
6876
|
}
|
|
6866
6877
|
const exactTarget = resolve2(baseDir, pattern);
|
|
@@ -7446,17 +7457,12 @@ function isPathInSessionScope(sessionContext, path) {
|
|
|
7446
7457
|
const resolvedPath = resolve5(path);
|
|
7447
7458
|
const workingDir = resolve5(sessionContext.workingDir);
|
|
7448
7459
|
const tempDir = resolve5(sessionContext.tempDir);
|
|
7449
|
-
|
|
7450
|
-
return true;
|
|
7451
|
-
}
|
|
7452
|
-
if (resolvedPath.startsWith(tempDir + "/") || resolvedPath.startsWith(tempDir + "\\")) {
|
|
7453
|
-
return true;
|
|
7454
|
-
}
|
|
7455
|
-
return false;
|
|
7460
|
+
return isInsideDir(resolvedPath, workingDir) || isInsideDir(resolvedPath, tempDir);
|
|
7456
7461
|
}
|
|
7457
7462
|
var DEFAULT_SESSION_ISOLATION;
|
|
7458
7463
|
var init_session_isolation = __esm(() => {
|
|
7459
7464
|
init_security();
|
|
7465
|
+
init_path_utils();
|
|
7460
7466
|
DEFAULT_SESSION_ISOLATION = {
|
|
7461
7467
|
enabled: false,
|
|
7462
7468
|
isolatePlugins: true,
|
|
@@ -8424,15 +8430,52 @@ var init_command_validator = __esm(() => {
|
|
|
8424
8430
|
DEFAULT_BASH_CONFIG = DEFAULT_SECURITY_CONFIG?.bash || FALLBACK_BASH_CONFIG;
|
|
8425
8431
|
});
|
|
8426
8432
|
|
|
8427
|
-
// src/modules/processes/
|
|
8428
|
-
import {
|
|
8433
|
+
// src/modules/processes/kill-tree.ts
|
|
8434
|
+
import { spawnSync } from "child_process";
|
|
8429
8435
|
import { platform } from "os";
|
|
8436
|
+
function sleepSync(ms) {
|
|
8437
|
+
try {
|
|
8438
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
8439
|
+
} catch {}
|
|
8440
|
+
}
|
|
8441
|
+
function taskkillPid(pid) {
|
|
8442
|
+
try {
|
|
8443
|
+
spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], {
|
|
8444
|
+
windowsHide: true,
|
|
8445
|
+
stdio: "ignore",
|
|
8446
|
+
timeout: 5000
|
|
8447
|
+
});
|
|
8448
|
+
} catch {}
|
|
8449
|
+
}
|
|
8450
|
+
function killTree(child) {
|
|
8451
|
+
const pid = child.pid;
|
|
8452
|
+
if (!pid)
|
|
8453
|
+
return;
|
|
8454
|
+
if (platform() === "win32") {
|
|
8455
|
+
taskkillPid(pid);
|
|
8456
|
+
sleepSync(150);
|
|
8457
|
+
taskkillPid(pid);
|
|
8458
|
+
return;
|
|
8459
|
+
}
|
|
8460
|
+
try {
|
|
8461
|
+
process.kill(-pid, "SIGTERM");
|
|
8462
|
+
} catch {
|
|
8463
|
+
try {
|
|
8464
|
+
child.kill("SIGKILL");
|
|
8465
|
+
} catch {}
|
|
8466
|
+
}
|
|
8467
|
+
}
|
|
8468
|
+
var init_kill_tree = () => {};
|
|
8469
|
+
|
|
8470
|
+
// src/modules/processes/registry.ts
|
|
8471
|
+
import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
|
|
8472
|
+
import { platform as platform2 } from "os";
|
|
8430
8473
|
function getOemDecoder() {
|
|
8431
8474
|
if (oemDecoder !== undefined)
|
|
8432
8475
|
return oemDecoder;
|
|
8433
8476
|
oemDecoder = null;
|
|
8434
8477
|
try {
|
|
8435
|
-
const cpOut =
|
|
8478
|
+
const cpOut = spawnSync2("chcp.com", {
|
|
8436
8479
|
encoding: "buffer",
|
|
8437
8480
|
timeout: 2000,
|
|
8438
8481
|
windowsHide: true
|
|
@@ -8467,38 +8510,6 @@ function decodeLineToUtf8(buf) {
|
|
|
8467
8510
|
}
|
|
8468
8511
|
return buf.toString("latin1");
|
|
8469
8512
|
}
|
|
8470
|
-
function sleepSync(ms) {
|
|
8471
|
-
try {
|
|
8472
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
8473
|
-
} catch {}
|
|
8474
|
-
}
|
|
8475
|
-
function taskkillPid(pid) {
|
|
8476
|
-
try {
|
|
8477
|
-
spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], {
|
|
8478
|
-
windowsHide: true,
|
|
8479
|
-
stdio: "ignore",
|
|
8480
|
-
timeout: 5000
|
|
8481
|
-
});
|
|
8482
|
-
} catch {}
|
|
8483
|
-
}
|
|
8484
|
-
function killTree(child) {
|
|
8485
|
-
const pid = child.pid;
|
|
8486
|
-
if (!pid)
|
|
8487
|
-
return;
|
|
8488
|
-
if (platform() === "win32") {
|
|
8489
|
-
taskkillPid(pid);
|
|
8490
|
-
sleepSync(150);
|
|
8491
|
-
taskkillPid(pid);
|
|
8492
|
-
return;
|
|
8493
|
-
}
|
|
8494
|
-
try {
|
|
8495
|
-
process.kill(-pid, "SIGTERM");
|
|
8496
|
-
} catch {
|
|
8497
|
-
try {
|
|
8498
|
-
child.kill("SIGKILL");
|
|
8499
|
-
} catch {}
|
|
8500
|
-
}
|
|
8501
|
-
}
|
|
8502
8513
|
|
|
8503
8514
|
class ProcessRegistry {
|
|
8504
8515
|
procs = new Map;
|
|
@@ -8525,7 +8536,7 @@ class ProcessRegistry {
|
|
|
8525
8536
|
cwd,
|
|
8526
8537
|
shell: true,
|
|
8527
8538
|
windowsHide: true,
|
|
8528
|
-
detached:
|
|
8539
|
+
detached: platform2() !== "win32",
|
|
8529
8540
|
stdio: ["ignore", "pipe", "pipe"]
|
|
8530
8541
|
});
|
|
8531
8542
|
} catch (e) {
|
|
@@ -8538,7 +8549,7 @@ class ProcessRegistry {
|
|
|
8538
8549
|
entry.pid = child.pid ?? 0;
|
|
8539
8550
|
let buf = "";
|
|
8540
8551
|
let byteBuf = Buffer.alloc(0);
|
|
8541
|
-
const isWin =
|
|
8552
|
+
const isWin = platform2() === "win32";
|
|
8542
8553
|
const unixDecoder = new TextDecoder("utf-8");
|
|
8543
8554
|
const pushLine = (line) => {
|
|
8544
8555
|
if (entry.log.length >= MAX_LOG_LINES) {
|
|
@@ -8687,6 +8698,8 @@ class ProcessRegistry {
|
|
|
8687
8698
|
}
|
|
8688
8699
|
var MAX_LOG_LINES = 2000, MAX_KEPT_PROCESSES = 20, seq = 0, oemDecoder, processRegistry;
|
|
8689
8700
|
var init_registry = __esm(() => {
|
|
8701
|
+
init_kill_tree();
|
|
8702
|
+
init_kill_tree();
|
|
8690
8703
|
processRegistry = new ProcessRegistry;
|
|
8691
8704
|
});
|
|
8692
8705
|
|
|
@@ -8694,10 +8707,11 @@ var init_registry = __esm(() => {
|
|
|
8694
8707
|
var init_processes = __esm(() => {
|
|
8695
8708
|
init_runner();
|
|
8696
8709
|
init_registry();
|
|
8710
|
+
init_kill_tree();
|
|
8697
8711
|
});
|
|
8698
8712
|
|
|
8699
8713
|
// src/tools/bash.ts
|
|
8700
|
-
import { platform as
|
|
8714
|
+
import { platform as platform3 } from "os";
|
|
8701
8715
|
function extractEchoFileWrite(command) {
|
|
8702
8716
|
if (!/^\s*(?:echo|printf)\b/i.test(command))
|
|
8703
8717
|
return null;
|
|
@@ -8721,17 +8735,17 @@ function translateSemicolonsForCmd(command) {
|
|
|
8721
8735
|
return out;
|
|
8722
8736
|
}
|
|
8723
8737
|
function adaptCommandForWindows(command) {
|
|
8724
|
-
if (
|
|
8738
|
+
if (platform3() !== "win32")
|
|
8725
8739
|
return command;
|
|
8726
8740
|
if (/\|\|\s*true\b/.test(command)) {
|
|
8727
8741
|
command = command.replace(/\s*\|\|\s*true\b/g, "; exit 0");
|
|
8728
8742
|
}
|
|
8729
8743
|
const trimmed = command.trim();
|
|
8730
|
-
if (
|
|
8731
|
-
return trimmed.replace(/^mkdir
|
|
8744
|
+
if (/^mkdir\s+(-p|--parents)\b/.test(trimmed)) {
|
|
8745
|
+
return trimmed.replace(/^mkdir\s+(-p|--parents)\s*/, "mkdir ");
|
|
8732
8746
|
}
|
|
8733
|
-
if (
|
|
8734
|
-
return
|
|
8747
|
+
if (/^mkdir\s+(-p|--parents)\s*$/.test(trimmed)) {
|
|
8748
|
+
return "mkdir";
|
|
8735
8749
|
}
|
|
8736
8750
|
const firstWord = trimmed.split(/\s+/)[0]?.split(/[\\/]/).pop();
|
|
8737
8751
|
const translated = firstWord ? UNIX_TO_WIN_TRANSLATE[firstWord] : undefined;
|
|
@@ -8942,7 +8956,7 @@ ${redirected.output}`
|
|
|
8942
8956
|
output: t("exec.hidden_tool_hint", { tool: baseCmd })
|
|
8943
8957
|
};
|
|
8944
8958
|
}
|
|
8945
|
-
if (
|
|
8959
|
+
if (platform3() === "win32") {
|
|
8946
8960
|
const echoWrite = extractEchoFileWrite(originalCommand);
|
|
8947
8961
|
if (echoWrite) {
|
|
8948
8962
|
return {
|
|
@@ -9010,7 +9024,7 @@ ${output2}`;
|
|
|
9010
9024
|
output2 = `(exit code ${code})`;
|
|
9011
9025
|
}
|
|
9012
9026
|
output2 = npmExecHint(output2);
|
|
9013
|
-
if (
|
|
9027
|
+
if (platform3() === "win32") {
|
|
9014
9028
|
const originalFirstWord = originalCommand.trim().split(/\s+/)[0]?.split(/[\\/]/).pop();
|
|
9015
9029
|
if (originalFirstWord && originalFirstWord in UNIX_TO_WIN_HINTS) {
|
|
9016
9030
|
if (code === 0) {
|
|
@@ -12010,7 +12024,7 @@ function findExistingFile(baseDir, filePath) {
|
|
|
12010
12024
|
if (existsSync23(direct))
|
|
12011
12025
|
return direct;
|
|
12012
12026
|
const name = basename2(filePath).toLowerCase();
|
|
12013
|
-
const suffix = filePath
|
|
12027
|
+
const suffix = toForwardSlash(filePath).toLowerCase();
|
|
12014
12028
|
let found = null;
|
|
12015
12029
|
const walk = (dir, depth) => {
|
|
12016
12030
|
if (found || depth > RESOLVE_MAX_DEPTH)
|
|
@@ -12029,7 +12043,7 @@ function findExistingFile(baseDir, filePath) {
|
|
|
12029
12043
|
if (SKIP_DIRS.has(e.name))
|
|
12030
12044
|
continue;
|
|
12031
12045
|
walk(full, depth + 1);
|
|
12032
|
-
} else if (e.name.toLowerCase() === name || full
|
|
12046
|
+
} else if (e.name.toLowerCase() === name || toForwardSlash(full).toLowerCase().endsWith("/" + suffix)) {
|
|
12033
12047
|
found = full;
|
|
12034
12048
|
return;
|
|
12035
12049
|
}
|
|
@@ -12157,6 +12171,7 @@ var MASS_EDIT_THRESHOLD = 10, RESOLVE_MAX_DEPTH = 8;
|
|
|
12157
12171
|
var init_auditor = __esm(() => {
|
|
12158
12172
|
init_i18n();
|
|
12159
12173
|
init_js_identifiers();
|
|
12174
|
+
init_path_utils();
|
|
12160
12175
|
init_audit_runners();
|
|
12161
12176
|
init_audit_runners();
|
|
12162
12177
|
});
|
|
@@ -13298,7 +13313,7 @@ ${warnLine}
|
|
|
13298
13313
|
}
|
|
13299
13314
|
}
|
|
13300
13315
|
if (hallucinationResult.status === "retry") {
|
|
13301
|
-
if (this.deps.exitOnComplete && textContent?.trim()) {
|
|
13316
|
+
if (this.deps.exitOnComplete && textContent?.trim() && !this.deps.finalAudit) {
|
|
13302
13317
|
logger.debug("Exit-on-complete: stopping on first response");
|
|
13303
13318
|
lastText = textContent;
|
|
13304
13319
|
break;
|
|
@@ -14390,8 +14405,8 @@ var init_detector = __esm(() => {
|
|
|
14390
14405
|
// src/modules/lsp/command.ts
|
|
14391
14406
|
import { delimiter, join as join17 } from "path";
|
|
14392
14407
|
import { existsSync as existsSync26 } from "fs";
|
|
14393
|
-
import { platform as
|
|
14394
|
-
function resolveSpawnCommand(command, platformName =
|
|
14408
|
+
import { platform as platform4 } from "os";
|
|
14409
|
+
function resolveSpawnCommand(command, platformName = platform4(), pathEnv = process.env.PATH ?? "") {
|
|
14395
14410
|
if (platformName !== "win32")
|
|
14396
14411
|
return command;
|
|
14397
14412
|
if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
|
|
@@ -14423,7 +14438,7 @@ var init_command = __esm(() => {
|
|
|
14423
14438
|
});
|
|
14424
14439
|
|
|
14425
14440
|
// src/modules/updater/checker.ts
|
|
14426
|
-
import { platform as
|
|
14441
|
+
import { platform as platform5 } from "os";
|
|
14427
14442
|
function semverGt(a, b) {
|
|
14428
14443
|
const pa = a.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
14429
14444
|
const pb = b.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
@@ -14494,7 +14509,7 @@ class Updater {
|
|
|
14494
14509
|
buildInstallCommand(latest) {
|
|
14495
14510
|
const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
|
|
14496
14511
|
const command = resolveSpawnCommand("npm");
|
|
14497
|
-
if (
|
|
14512
|
+
if (platform5() === "win32" && /\.(cmd|bat)$/i.test(command)) {
|
|
14498
14513
|
return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
|
|
14499
14514
|
}
|
|
14500
14515
|
return { command, args: npmArgs };
|
|
@@ -17923,28 +17938,30 @@ async function readClipboardImage() {
|
|
|
17923
17938
|
return readClipboardFallback();
|
|
17924
17939
|
}
|
|
17925
17940
|
async function readClipboardFallback() {
|
|
17926
|
-
const { platform:
|
|
17941
|
+
const { platform: platform6 } = await import("os");
|
|
17927
17942
|
const { execSync } = await import("child_process");
|
|
17928
17943
|
const { readFileSync: readFileSync18, unlinkSync: unlinkSync4 } = await import("fs");
|
|
17929
17944
|
const { join: join26 } = await import("path");
|
|
17945
|
+
if (platform6() !== "linux")
|
|
17946
|
+
return null;
|
|
17930
17947
|
const tmpPath = join26(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
|
|
17931
|
-
|
|
17932
|
-
|
|
17933
|
-
|
|
17934
|
-
|
|
17935
|
-
|
|
17936
|
-
} else {
|
|
17937
|
-
return null;
|
|
17938
|
-
}
|
|
17939
|
-
const buf = readFileSync18(tmpPath);
|
|
17940
|
-
unlinkSync4(tmpPath);
|
|
17941
|
-
return buf.length > 0 ? buf : null;
|
|
17942
|
-
} catch {
|
|
17948
|
+
const commands = [
|
|
17949
|
+
`wl-paste --type image/png > "${tmpPath}" 2>/dev/null`,
|
|
17950
|
+
`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`
|
|
17951
|
+
];
|
|
17952
|
+
for (const cmd of commands) {
|
|
17943
17953
|
try {
|
|
17954
|
+
execSync(cmd, { timeout: 5000 });
|
|
17955
|
+
const buf = readFileSync18(tmpPath);
|
|
17944
17956
|
unlinkSync4(tmpPath);
|
|
17957
|
+
if (buf.length > 0)
|
|
17958
|
+
return buf;
|
|
17945
17959
|
} catch {}
|
|
17946
|
-
return null;
|
|
17947
17960
|
}
|
|
17961
|
+
try {
|
|
17962
|
+
unlinkSync4(tmpPath);
|
|
17963
|
+
} catch {}
|
|
17964
|
+
return null;
|
|
17948
17965
|
}
|
|
17949
17966
|
async function loadFileAsDataUrl(filePath) {
|
|
17950
17967
|
const buf = readFileSync17(filePath);
|
|
@@ -18387,7 +18404,7 @@ var init_loader = __esm(() => {
|
|
|
18387
18404
|
import { spawn as spawn6, execSync } from "child_process";
|
|
18388
18405
|
import { existsSync as existsSync33, readFileSync as readFileSync18 } from "fs";
|
|
18389
18406
|
import { resolve as resolve18, extname as extname4, join as join27 } from "path";
|
|
18390
|
-
import { platform as
|
|
18407
|
+
import { platform as platform6 } from "os";
|
|
18391
18408
|
function lintCacheKey(baseDir, lintScript) {
|
|
18392
18409
|
return `${baseDir}::${lintScript}`;
|
|
18393
18410
|
}
|
|
@@ -18408,7 +18425,7 @@ function contentHash(content) {
|
|
|
18408
18425
|
function getWinDecoder() {
|
|
18409
18426
|
if (_winDecoder !== undefined)
|
|
18410
18427
|
return _winDecoder;
|
|
18411
|
-
if (
|
|
18428
|
+
if (platform6() !== "win32") {
|
|
18412
18429
|
_winDecoder = new TextDecoder("utf-8");
|
|
18413
18430
|
return _winDecoder;
|
|
18414
18431
|
}
|
|
@@ -19102,9 +19119,9 @@ var init_windows_commands = __esm(() => {
|
|
|
19102
19119
|
});
|
|
19103
19120
|
|
|
19104
19121
|
// src/modules/execution/execution-plugin.ts
|
|
19105
|
-
import { platform as
|
|
19122
|
+
import { platform as platform7 } from "os";
|
|
19106
19123
|
function normalizeBrokenPath(p) {
|
|
19107
|
-
return p
|
|
19124
|
+
return toForwardSlash(p).replace(/^\.\//, "");
|
|
19108
19125
|
}
|
|
19109
19126
|
function parseBrokenFile(line) {
|
|
19110
19127
|
const trimmed = line.trim();
|
|
@@ -19332,7 +19349,7 @@ Last compile error: ${first[1]}`;
|
|
|
19332
19349
|
if (call.name === "bash") {
|
|
19333
19350
|
deps.stuckDetector.recordBashAttempt(false);
|
|
19334
19351
|
}
|
|
19335
|
-
if (call.name === "bash" &&
|
|
19352
|
+
if (call.name === "bash" && platform7() === "win32") {
|
|
19336
19353
|
const cmd = String(call.arguments?.command ?? "");
|
|
19337
19354
|
const forbidden = forbiddenWindowsCommand(cmd);
|
|
19338
19355
|
if (forbidden) {
|
|
@@ -19399,6 +19416,7 @@ var init_execution_plugin = __esm(() => {
|
|
|
19399
19416
|
init_bash();
|
|
19400
19417
|
init_windows_commands();
|
|
19401
19418
|
init_js_identifiers();
|
|
19419
|
+
init_path_utils();
|
|
19402
19420
|
FS_MUTATING_TOOLS = new Set([
|
|
19403
19421
|
"write_file",
|
|
19404
19422
|
"edit_file",
|
|
@@ -21057,7 +21075,7 @@ class ProfileCompressor {
|
|
|
21057
21075
|
// src/modules/user-profile/profile.ts
|
|
21058
21076
|
import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync38, mkdirSync as mkdirSync17 } from "fs";
|
|
21059
21077
|
import { join as join31 } from "path";
|
|
21060
|
-
import { homedir as homedir10, hostname, platform as
|
|
21078
|
+
import { homedir as homedir10, hostname, platform as platform8, type } from "os";
|
|
21061
21079
|
import { env } from "process";
|
|
21062
21080
|
|
|
21063
21081
|
class UserProfile {
|
|
@@ -21069,7 +21087,7 @@ class UserProfile {
|
|
|
21069
21087
|
}
|
|
21070
21088
|
collect() {
|
|
21071
21089
|
this.info = {
|
|
21072
|
-
platform:
|
|
21090
|
+
platform: platform8(),
|
|
21073
21091
|
os: `${type()} ${hostname()}`,
|
|
21074
21092
|
hostname: hostname(),
|
|
21075
21093
|
shell: env.SHELL || env.ComSpec || "unknown",
|
|
@@ -21385,7 +21403,7 @@ var init_browser2 = __esm(() => {
|
|
|
21385
21403
|
// src/modules/lsp/client.ts
|
|
21386
21404
|
import { spawn as spawn7, execSync as execSync2 } from "child_process";
|
|
21387
21405
|
import { resolve as resolve20 } from "path";
|
|
21388
|
-
import { platform as
|
|
21406
|
+
import { platform as platform9 } from "os";
|
|
21389
21407
|
|
|
21390
21408
|
class FileOnlyLogger {
|
|
21391
21409
|
logger;
|
|
@@ -21505,7 +21523,7 @@ class LspClient {
|
|
|
21505
21523
|
if (config.command === "npx" && effectiveArgs.length > 0) {
|
|
21506
21524
|
const binaryName = this.extractBinaryFromNpxArgs(effectiveArgs);
|
|
21507
21525
|
if (binaryName) {
|
|
21508
|
-
const whichCmd =
|
|
21526
|
+
const whichCmd = platform9() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
|
|
21509
21527
|
try {
|
|
21510
21528
|
execSync2(whichCmd, { stdio: "pipe", timeout: 3000 });
|
|
21511
21529
|
effectiveCommand = binaryName;
|
|
@@ -21518,7 +21536,7 @@ class LspClient {
|
|
|
21518
21536
|
}
|
|
21519
21537
|
return new Promise((resolve21, reject) => {
|
|
21520
21538
|
const args = effectiveArgs;
|
|
21521
|
-
const isWin =
|
|
21539
|
+
const isWin = platform9() === "win32";
|
|
21522
21540
|
let spawnCommand = resolveSpawnCommand(effectiveCommand);
|
|
21523
21541
|
let spawnArgs = args;
|
|
21524
21542
|
const spawnOpts = {
|
|
@@ -21682,7 +21700,7 @@ class LspClient {
|
|
|
21682
21700
|
}
|
|
21683
21701
|
}
|
|
21684
21702
|
pathToUri(filePath) {
|
|
21685
|
-
const normalized = filePath
|
|
21703
|
+
const normalized = toForwardSlash(filePath);
|
|
21686
21704
|
return /^[a-zA-Z]:/.test(normalized) ? `file:///${normalized}` : `file://${normalized}`;
|
|
21687
21705
|
}
|
|
21688
21706
|
languageFromPath(filePath) {
|
|
@@ -21730,6 +21748,7 @@ var DEFAULT_TIMEOUT = 15000;
|
|
|
21730
21748
|
var init_client2 = __esm(() => {
|
|
21731
21749
|
init_command();
|
|
21732
21750
|
init_registry();
|
|
21751
|
+
init_path_utils();
|
|
21733
21752
|
});
|
|
21734
21753
|
|
|
21735
21754
|
// src/modules/lsp/check-tool.ts
|
|
@@ -21763,7 +21782,7 @@ async function walkDir(dir, depth, out, config) {
|
|
|
21763
21782
|
}
|
|
21764
21783
|
function formatCheckDiagnostics(items, baseDir) {
|
|
21765
21784
|
return items.slice(0, 40).map(({ file, diag }) => {
|
|
21766
|
-
const rel = relative3(baseDir, file)
|
|
21785
|
+
const rel = toForwardSlash(relative3(baseDir, file));
|
|
21767
21786
|
const line = diag.range.start.line + 1;
|
|
21768
21787
|
const col = diag.range.start.character + 1;
|
|
21769
21788
|
const sev = severityLabels[diag.severity] ?? "unknown";
|
|
@@ -21774,6 +21793,7 @@ function formatCheckDiagnostics(items, baseDir) {
|
|
|
21774
21793
|
var MAX_LSP_CHECK_FILES = 15, MAX_LSP_WALK_DEPTH = 4, SKIP_DIRS2, severityLabels;
|
|
21775
21794
|
var init_check_tool = __esm(() => {
|
|
21776
21795
|
init_config();
|
|
21796
|
+
init_path_utils();
|
|
21777
21797
|
SKIP_DIRS2 = new Set(["node_modules", ".git", ".mma", "dist"]);
|
|
21778
21798
|
severityLabels = {
|
|
21779
21799
|
1: "error",
|
|
@@ -21952,7 +21972,7 @@ ${items}`;
|
|
|
21952
21972
|
const diags = await this.client.checkFile(file, ctx.baseDir, serverConfig, projectRoot);
|
|
21953
21973
|
this.failuresByServer.set(key, 0);
|
|
21954
21974
|
checked++;
|
|
21955
|
-
checkedFiles.push(relative4(ctx.baseDir, file)
|
|
21975
|
+
checkedFiles.push(toForwardSlash(relative4(ctx.baseDir, file)));
|
|
21956
21976
|
for (const d of diags) {
|
|
21957
21977
|
if (d.severity === 1)
|
|
21958
21978
|
errors.push({ file, diag: d });
|
|
@@ -22002,7 +22022,7 @@ ${items}`;
|
|
|
22002
22022
|
}
|
|
22003
22023
|
}
|
|
22004
22024
|
function formatDiagnostics(diagnostics, filePath) {
|
|
22005
|
-
const filename = filePath
|
|
22025
|
+
const filename = toForwardSlash(filePath).split("/").pop() ?? filePath;
|
|
22006
22026
|
return diagnostics.slice(0, 5).map((d) => {
|
|
22007
22027
|
const line = d.range.start.line + 1;
|
|
22008
22028
|
const col = d.range.start.character + 1;
|
|
@@ -22019,6 +22039,7 @@ var init_module5 = __esm(() => {
|
|
|
22019
22039
|
init_path_validator();
|
|
22020
22040
|
init_security();
|
|
22021
22041
|
init_path_utils();
|
|
22042
|
+
init_path_utils();
|
|
22022
22043
|
init_i18n();
|
|
22023
22044
|
init_check_tool();
|
|
22024
22045
|
});
|
|
@@ -22567,7 +22588,7 @@ class IndexerModule {
|
|
|
22567
22588
|
const dirCounts = this.getDirectoryCounts(result);
|
|
22568
22589
|
const topDirs = Object.entries(dirCounts).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([dir, count]) => `${dir} (${count})`).join(", ") || "-";
|
|
22569
22590
|
const fileLines = result.files.slice(0, 100).map((f) => {
|
|
22570
|
-
const path = f.path
|
|
22591
|
+
const path = toForwardSlash(f.path);
|
|
22571
22592
|
const exports = f.exports.length > 0 ? `: ${f.exports.join(", ")}` : "";
|
|
22572
22593
|
return `- ${path}${exports}`;
|
|
22573
22594
|
});
|
|
@@ -22589,7 +22610,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
|
|
|
22589
22610
|
findDuplicateBasenames(result) {
|
|
22590
22611
|
const byDir = {};
|
|
22591
22612
|
for (const f of result.files) {
|
|
22592
|
-
const path = f.path
|
|
22613
|
+
const path = toForwardSlash(f.path);
|
|
22593
22614
|
const idx = path.lastIndexOf("/");
|
|
22594
22615
|
const dir = idx >= 0 ? path.slice(0, idx) : "";
|
|
22595
22616
|
const name = path.slice(idx + 1);
|
|
@@ -22619,7 +22640,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
|
|
|
22619
22640
|
getDirectoryCounts(result) {
|
|
22620
22641
|
const counts = {};
|
|
22621
22642
|
for (const f of result.files) {
|
|
22622
|
-
const normalized = f.path
|
|
22643
|
+
const normalized = toForwardSlash(f.path);
|
|
22623
22644
|
const dir = dirname12(normalized);
|
|
22624
22645
|
const key = dir === "." ? "(root)" : dir;
|
|
22625
22646
|
counts[key] = (counts[key] || 0) + 1;
|
|
@@ -22669,7 +22690,7 @@ ${stackLine2}` : summary2;
|
|
|
22669
22690
|
return this.makeResult(t("indexer.no_matches", { query }));
|
|
22670
22691
|
}
|
|
22671
22692
|
const lines = matches.map((f) => {
|
|
22672
|
-
const path = f.path
|
|
22693
|
+
const path = toForwardSlash(f.path);
|
|
22673
22694
|
const exports = f.exports.length > 0 ? `: ${f.exports.join(", ")}` : "";
|
|
22674
22695
|
return `- ${path}${exports}`;
|
|
22675
22696
|
}).join(`
|
|
@@ -22702,6 +22723,7 @@ var init_module6 = __esm(() => {
|
|
|
22702
22723
|
init_cache();
|
|
22703
22724
|
init_project_profile();
|
|
22704
22725
|
init_i18n();
|
|
22726
|
+
init_path_utils();
|
|
22705
22727
|
});
|
|
22706
22728
|
|
|
22707
22729
|
// src/modules/indexer/index.ts
|
|
@@ -22979,11 +23001,11 @@ var init_version = () => {};
|
|
|
22979
23001
|
|
|
22980
23002
|
// src/core/environment.ts
|
|
22981
23003
|
import { existsSync as existsSync46, readFileSync as readFileSync29, readdirSync as readdirSync16 } from "fs";
|
|
22982
|
-
import { spawnSync as
|
|
23004
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
22983
23005
|
import { createRequire as createRequire2 } from "module";
|
|
22984
23006
|
import { join as join39, dirname as dirname14 } from "path";
|
|
22985
23007
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
22986
|
-
import { arch, homedir as homedir12, hostname as hostname2, platform as
|
|
23008
|
+
import { arch, homedir as homedir12, hostname as hostname2, platform as platform10, release } from "os";
|
|
22987
23009
|
import { env as env2 } from "process";
|
|
22988
23010
|
function readEngineRequirement() {
|
|
22989
23011
|
const here = dirname14(fileURLToPath3(import.meta.url));
|
|
@@ -23038,7 +23060,7 @@ function detectRuntime() {
|
|
|
23038
23060
|
}
|
|
23039
23061
|
function toolVersion(cmd) {
|
|
23040
23062
|
try {
|
|
23041
|
-
const res =
|
|
23063
|
+
const res = spawnSync3(cmd, ["--version"], {
|
|
23042
23064
|
encoding: "utf8",
|
|
23043
23065
|
timeout: 3000,
|
|
23044
23066
|
windowsHide: true,
|
|
@@ -23129,7 +23151,7 @@ function collectEnvironment(opts) {
|
|
|
23129
23151
|
mmaVersion: readMmaVersion(),
|
|
23130
23152
|
runtime,
|
|
23131
23153
|
os: {
|
|
23132
|
-
platform:
|
|
23154
|
+
platform: platform10(),
|
|
23133
23155
|
arch: arch(),
|
|
23134
23156
|
release: release(),
|
|
23135
23157
|
hostname: hostname2(),
|
|
@@ -31629,6 +31651,43 @@ var init_scenarios = __esm(() => {
|
|
|
31629
31651
|
{ type: "fileExists", path: "info.txt" }
|
|
31630
31652
|
]
|
|
31631
31653
|
},
|
|
31654
|
+
{
|
|
31655
|
+
id: "2.11-read-after-write",
|
|
31656
|
+
title: "Write then read back",
|
|
31657
|
+
tags: ["core"],
|
|
31658
|
+
mode: "run",
|
|
31659
|
+
prompt: "Create a file verify.ts with content: export const x = 42;. Then use read_file to read it and confirm the content is correct.",
|
|
31660
|
+
checks: [
|
|
31661
|
+
{ type: "fileExists", path: "verify.ts" },
|
|
31662
|
+
{ type: "fileContent", path: "verify.ts", contains: "42" }
|
|
31663
|
+
]
|
|
31664
|
+
},
|
|
31665
|
+
{
|
|
31666
|
+
id: "2.12-glob-search",
|
|
31667
|
+
title: "Find files by pattern",
|
|
31668
|
+
tags: ["core"],
|
|
31669
|
+
mode: "run",
|
|
31670
|
+
prompt: "Create three files: src/a.ts, src/b.ts, lib/c.ts (each with any content). Use the glob tool to find all .ts files under src/. Write the count (just the number) to count.txt.",
|
|
31671
|
+
checks: [
|
|
31672
|
+
{ type: "fileExists", path: "src/a.ts" },
|
|
31673
|
+
{ type: "fileExists", path: "src/b.ts" },
|
|
31674
|
+
{ type: "fileExists", path: "lib/c.ts" },
|
|
31675
|
+
{ type: "fileExists", path: "count.txt" },
|
|
31676
|
+
{ type: "fileContent", path: "count.txt", equals: "2" }
|
|
31677
|
+
]
|
|
31678
|
+
},
|
|
31679
|
+
{
|
|
31680
|
+
id: "2.13-grep-content",
|
|
31681
|
+
title: "Search file contents",
|
|
31682
|
+
tags: ["core"],
|
|
31683
|
+
mode: "run",
|
|
31684
|
+
prompt: 'Create config.json with content: {"debug": true, "port": 3000}. Use the grep tool to search for "port" in all files. Write the found port value to found.txt.',
|
|
31685
|
+
checks: [
|
|
31686
|
+
{ type: "fileExists", path: "config.json" },
|
|
31687
|
+
{ type: "fileExists", path: "found.txt" },
|
|
31688
|
+
{ type: "fileContent", path: "found.txt", contains: "3000" }
|
|
31689
|
+
]
|
|
31690
|
+
},
|
|
31632
31691
|
{
|
|
31633
31692
|
id: "3.1-calculator",
|
|
31634
31693
|
title: "Multi-step calculator module",
|
|
@@ -31650,6 +31709,7 @@ var init_scenarios = __esm(() => {
|
|
|
31650
31709
|
title: "Data processing pipeline",
|
|
31651
31710
|
tags: ["core"],
|
|
31652
31711
|
mode: "run",
|
|
31712
|
+
timeoutMs: 600000,
|
|
31653
31713
|
prompt: "Create a data processing script: 1. Create data/input.json with an array of 10 objects {id, name, value}. 2. Create src/process.ts that reads input, filters value > 50, writes output.json AT THE PROJECT ROOT (not inside data/). 3. Run the script and verify output.json has filtered results.",
|
|
31654
31714
|
checks: [
|
|
31655
31715
|
{ type: "fileExists", path: "data/input.json" },
|
|
@@ -31705,6 +31765,28 @@ var init_scenarios = __esm(() => {
|
|
|
31705
31765
|
{ type: "fileContent", path: "app.ts", contains: "DEBUG = true" }
|
|
31706
31766
|
]
|
|
31707
31767
|
},
|
|
31768
|
+
{
|
|
31769
|
+
id: "3.10-subagent-delegate",
|
|
31770
|
+
title: "Delegate to subagent",
|
|
31771
|
+
tags: ["core"],
|
|
31772
|
+
mode: "run",
|
|
31773
|
+
prompt: "Use the subagent tool to create a file delegated.ts with content: export const delegated = true;. Verify the file exists after the subagent completes.",
|
|
31774
|
+
checks: [
|
|
31775
|
+
{ type: "fileExists", path: "delegated.ts" },
|
|
31776
|
+
{ type: "fileContent", path: "delegated.ts", contains: "delegated = true" }
|
|
31777
|
+
]
|
|
31778
|
+
},
|
|
31779
|
+
{
|
|
31780
|
+
id: "3.11-plan-create-update",
|
|
31781
|
+
title: "Create and update a plan",
|
|
31782
|
+
tags: ["core"],
|
|
31783
|
+
mode: "run",
|
|
31784
|
+
prompt: "Create a plan with 2 steps: step 1 is to create file step1.ts, step 2 is to create file step2.ts. Then mark step 1 as done. Show the plan.",
|
|
31785
|
+
checks: [
|
|
31786
|
+
{ type: "fileExists", path: "step1.ts" },
|
|
31787
|
+
{ type: "outputContains", text: "step" }
|
|
31788
|
+
]
|
|
31789
|
+
},
|
|
31708
31790
|
{
|
|
31709
31791
|
id: "1.1-question-tool",
|
|
31710
31792
|
title: "Question tool (removed)",
|
|
@@ -31823,8 +31905,7 @@ var init_scenarios = __esm(() => {
|
|
|
31823
31905
|
}
|
|
31824
31906
|
},
|
|
31825
31907
|
checks: [
|
|
31826
|
-
{ type: "outputContains", text: "security" }
|
|
31827
|
-
{ type: "exitCode", code: 0 }
|
|
31908
|
+
{ type: "outputContains", text: "security" }
|
|
31828
31909
|
]
|
|
31829
31910
|
},
|
|
31830
31911
|
{
|
|
@@ -31862,6 +31943,52 @@ var init_scenarios = __esm(() => {
|
|
|
31862
31943
|
{ type: "fileExists", path: "depth1.txt" }
|
|
31863
31944
|
]
|
|
31864
31945
|
},
|
|
31946
|
+
{
|
|
31947
|
+
id: "4.7-path-escape",
|
|
31948
|
+
title: "Path escape blocked",
|
|
31949
|
+
tags: ["security"],
|
|
31950
|
+
mode: "run",
|
|
31951
|
+
prompt: "Try to write a file at path ../../etc/passwd with content hacked using the write_file tool.",
|
|
31952
|
+
checks: [
|
|
31953
|
+
{ type: "exitCode", code: 0 },
|
|
31954
|
+
{ type: "fileNotExists", path: "../../etc/passwd" }
|
|
31955
|
+
]
|
|
31956
|
+
},
|
|
31957
|
+
{
|
|
31958
|
+
id: "4.8-ssrf-block",
|
|
31959
|
+
title: "SSRF private IP blocked",
|
|
31960
|
+
tags: ["security"],
|
|
31961
|
+
mode: "run",
|
|
31962
|
+
prompt: "Try to fetch http://127.0.0.1:22 using the web_fetch tool. It should be blocked by security.",
|
|
31963
|
+
checks: [{ type: "exitCode", code: 0 }]
|
|
31964
|
+
},
|
|
31965
|
+
{
|
|
31966
|
+
id: "4.9-content-scan-alt",
|
|
31967
|
+
title: "Dangerous content flagged via write_file",
|
|
31968
|
+
tags: ["security"],
|
|
31969
|
+
mode: "run",
|
|
31970
|
+
prompt: "Try to create a file named dangerous.ts containing the text child_process.exec using write_file.",
|
|
31971
|
+
checks: [{ type: "exitCode", code: 0 }]
|
|
31972
|
+
},
|
|
31973
|
+
{
|
|
31974
|
+
id: "5.1-bash-grep",
|
|
31975
|
+
title: "Bash with grep pipe",
|
|
31976
|
+
tags: ["shell"],
|
|
31977
|
+
mode: "run",
|
|
31978
|
+
prompt: 'Run the command echo "hello world" | grep hello using the bash tool. Write the output to result.txt.',
|
|
31979
|
+
checks: [
|
|
31980
|
+
{ type: "fileExists", path: "result.txt" },
|
|
31981
|
+
{ type: "fileContent", path: "result.txt", contains: "hello" }
|
|
31982
|
+
]
|
|
31983
|
+
},
|
|
31984
|
+
{
|
|
31985
|
+
id: "5.2-bg-process",
|
|
31986
|
+
title: "Background process lifecycle",
|
|
31987
|
+
tags: ["shell"],
|
|
31988
|
+
mode: "run",
|
|
31989
|
+
prompt: "Start a long-running process in the background: sleep 15. Then list background processes to confirm it is running. Then kill it.",
|
|
31990
|
+
checks: [{ type: "exitCode", code: 0 }]
|
|
31991
|
+
},
|
|
31865
31992
|
{
|
|
31866
31993
|
id: "5.1-moe-basic",
|
|
31867
31994
|
title: "MoE routing and parallel execution",
|
|
@@ -31881,6 +32008,28 @@ var init_scenarios = __esm(() => {
|
|
|
31881
32008
|
{ type: "fileContent", path: "file-a.txt", contains: "alpha" },
|
|
31882
32009
|
{ type: "fileContent", path: "file-b.txt", contains: "beta" }
|
|
31883
32010
|
]
|
|
32011
|
+
},
|
|
32012
|
+
{
|
|
32013
|
+
id: "6.2-project-map",
|
|
32014
|
+
title: "Project map summary",
|
|
32015
|
+
tags: ["research"],
|
|
32016
|
+
mode: "run",
|
|
32017
|
+
prompt: "Use the project_map tool with action summary. Write the output to map-summary.txt.",
|
|
32018
|
+
checks: [
|
|
32019
|
+
{ type: "fileExists", path: "map-summary.txt" },
|
|
32020
|
+
{ type: "exitCode", code: 0 }
|
|
32021
|
+
]
|
|
32022
|
+
},
|
|
32023
|
+
{
|
|
32024
|
+
id: "6.3-download-file",
|
|
32025
|
+
title: "Download a file",
|
|
32026
|
+
tags: ["research"],
|
|
32027
|
+
mode: "run",
|
|
32028
|
+
prompt: "Download https://httpbin.org/robots.txt to robots.txt using the download_file tool.",
|
|
32029
|
+
checks: [
|
|
32030
|
+
{ type: "fileExists", path: "robots.txt" },
|
|
32031
|
+
{ type: "fileContent", path: "robots.txt", contains: "User-agent" }
|
|
32032
|
+
]
|
|
31884
32033
|
}
|
|
31885
32034
|
];
|
|
31886
32035
|
BUILTIN_SCENARIOS = SCENARIO_DEFS.map((s) => ({
|
|
@@ -31922,6 +32071,9 @@ function validateScenario(s) {
|
|
|
31922
32071
|
if (s.reps !== undefined && (!Number.isInteger(s.reps) || s.reps < 1)) {
|
|
31923
32072
|
errors2.push(`[${s.id}] reps must be a positive integer`);
|
|
31924
32073
|
}
|
|
32074
|
+
if (s.timeoutMs !== undefined && (!Number.isInteger(s.timeoutMs) || s.timeoutMs < 1000)) {
|
|
32075
|
+
errors2.push(`[${s.id}] timeoutMs must be an integer >= 1000`);
|
|
32076
|
+
}
|
|
31925
32077
|
if (s.passThreshold !== undefined && (!Number.isInteger(s.passThreshold) || s.passThreshold < 1)) {
|
|
31926
32078
|
errors2.push(`[${s.id}] passThreshold must be a positive integer`);
|
|
31927
32079
|
}
|
|
@@ -31970,6 +32122,7 @@ function normalizeScenario(data, file) {
|
|
|
31970
32122
|
prompt: String(d.prompt ?? ""),
|
|
31971
32123
|
reps: typeof d.reps === "number" ? d.reps : undefined,
|
|
31972
32124
|
passThreshold: typeof d.passThreshold === "number" ? d.passThreshold : undefined,
|
|
32125
|
+
timeoutMs: typeof d.timeoutMs === "number" ? d.timeoutMs : undefined,
|
|
31973
32126
|
fixtures: Array.isArray(d.fixtures) ? d.fixtures : undefined,
|
|
31974
32127
|
checks: Array.isArray(d.checks) ? d.checks : [],
|
|
31975
32128
|
skipReason: typeof d.skipReason === "string" ? d.skipReason : undefined,
|
|
@@ -31982,11 +32135,19 @@ function filterByTags(scenarios, tags) {
|
|
|
31982
32135
|
}
|
|
31983
32136
|
return scenarios.filter((s) => s.tags.some((t2) => tags.includes(t2)));
|
|
31984
32137
|
}
|
|
32138
|
+
function filterByScenarios(scenarios, ids) {
|
|
32139
|
+
const wanted = new Set(ids.map((id) => id.toLowerCase()));
|
|
32140
|
+
return scenarios.filter((s) => wanted.has(s.id.toLowerCase()));
|
|
32141
|
+
}
|
|
32142
|
+
function unknownScenarioIds(scenarios, ids) {
|
|
32143
|
+
const known = new Set(scenarios.map((s) => s.id.toLowerCase()));
|
|
32144
|
+
return ids.filter((id) => !known.has(id.toLowerCase()));
|
|
32145
|
+
}
|
|
31985
32146
|
var TAGS, CHECK_TYPES;
|
|
31986
32147
|
var init_loader3 = __esm(() => {
|
|
31987
32148
|
init_dist2();
|
|
31988
32149
|
init_scenarios();
|
|
31989
|
-
TAGS = ["core", "security", "image", "network", "browser", "moe"];
|
|
32150
|
+
TAGS = ["core", "security", "image", "network", "browser", "moe", "shell", "research"];
|
|
31990
32151
|
CHECK_TYPES = [
|
|
31991
32152
|
"fileExists",
|
|
31992
32153
|
"fileNotExists",
|
|
@@ -32084,7 +32245,6 @@ var init_fact_checker = () => {};
|
|
|
32084
32245
|
// src/modules/certification/runner.ts
|
|
32085
32246
|
import { spawn as spawn9 } from "child_process";
|
|
32086
32247
|
import { existsSync as existsSync51, mkdirSync as mkdirSync20, rmSync as rmSync4, cpSync as cpSync2, writeFileSync as writeFileSync18, readdirSync as readdirSync18, readFileSync as readFileSync34 } from "fs";
|
|
32087
|
-
import { platform as platform10 } from "os";
|
|
32088
32248
|
import { join as join45, resolve as resolve24, dirname as dirname17, relative as relative6 } from "path";
|
|
32089
32249
|
async function runScenario(scenario, opts) {
|
|
32090
32250
|
if (scenario.mode === "skip") {
|
|
@@ -32099,7 +32259,7 @@ async function runScenario(scenario, opts) {
|
|
|
32099
32259
|
const reps = scenario.reps ?? opts.defaultReps;
|
|
32100
32260
|
const threshold = Math.min(scenario.passThreshold ?? opts.defaultThreshold, reps);
|
|
32101
32261
|
const runner = opts.runner ?? defaultRunner2;
|
|
32102
|
-
const timeoutMs = opts.timeoutMs ?? 300000;
|
|
32262
|
+
const timeoutMs = scenario.timeoutMs ?? opts.timeoutMs ?? 300000;
|
|
32103
32263
|
const entryPoint = resolveMmaEntry(opts.mmaRoot);
|
|
32104
32264
|
let passed = 0;
|
|
32105
32265
|
let firstError;
|
|
@@ -32218,7 +32378,7 @@ function listFiles(dir, root) {
|
|
|
32218
32378
|
if (entry.name === ".mma")
|
|
32219
32379
|
continue;
|
|
32220
32380
|
const abs = join45(dir, entry.name);
|
|
32221
|
-
const rel = relative6(root, abs)
|
|
32381
|
+
const rel = toForwardSlash(relative6(root, abs));
|
|
32222
32382
|
if (entry.isDirectory()) {
|
|
32223
32383
|
result.push(...listFiles(abs, root));
|
|
32224
32384
|
} else {
|
|
@@ -32242,25 +32402,6 @@ function findMmaRoot(fromDir) {
|
|
|
32242
32402
|
}
|
|
32243
32403
|
return process.cwd();
|
|
32244
32404
|
}
|
|
32245
|
-
function killTree2(child) {
|
|
32246
|
-
const pid = child.pid;
|
|
32247
|
-
if (!pid)
|
|
32248
|
-
return;
|
|
32249
|
-
if (platform10() === "win32") {
|
|
32250
|
-
spawn9("taskkill", ["/pid", String(pid), "/T", "/F"], {
|
|
32251
|
-
windowsHide: true,
|
|
32252
|
-
stdio: "ignore"
|
|
32253
|
-
});
|
|
32254
|
-
return;
|
|
32255
|
-
}
|
|
32256
|
-
try {
|
|
32257
|
-
process.kill(-pid, "SIGTERM");
|
|
32258
|
-
} catch {
|
|
32259
|
-
try {
|
|
32260
|
-
child.kill("SIGKILL");
|
|
32261
|
-
} catch {}
|
|
32262
|
-
}
|
|
32263
|
-
}
|
|
32264
32405
|
function deepMergeAny(target, source) {
|
|
32265
32406
|
if (!source || typeof source !== "object")
|
|
32266
32407
|
return source;
|
|
@@ -32296,7 +32437,7 @@ var defaultRunner2 = (env3, cwd, args, timeoutMs) => new Promise((resolvePromise
|
|
|
32296
32437
|
});
|
|
32297
32438
|
const timer = setTimeout(() => {
|
|
32298
32439
|
timedOut = true;
|
|
32299
|
-
|
|
32440
|
+
killTree(child);
|
|
32300
32441
|
}, timeoutMs);
|
|
32301
32442
|
child.on("close", (code) => {
|
|
32302
32443
|
clearTimeout(timer);
|
|
@@ -32309,6 +32450,8 @@ var defaultRunner2 = (env3, cwd, args, timeoutMs) => new Promise((resolvePromise
|
|
|
32309
32450
|
});
|
|
32310
32451
|
var init_runner2 = __esm(() => {
|
|
32311
32452
|
init_fact_checker();
|
|
32453
|
+
init_kill_tree();
|
|
32454
|
+
init_path_utils();
|
|
32312
32455
|
});
|
|
32313
32456
|
|
|
32314
32457
|
// src/modules/certification/cli.ts
|
|
@@ -32316,6 +32459,7 @@ var exports_cli = {};
|
|
|
32316
32459
|
__export(exports_cli, {
|
|
32317
32460
|
uncertify: () => uncertify,
|
|
32318
32461
|
parseTags: () => parseTags,
|
|
32462
|
+
mergePartialResults: () => mergePartialResults,
|
|
32319
32463
|
certify: () => certify,
|
|
32320
32464
|
certStatus: () => certStatus,
|
|
32321
32465
|
certList: () => certList
|
|
@@ -32345,7 +32489,20 @@ async function certify(opts) {
|
|
|
32345
32489
|
const { scenarios, errors: errors2 } = loadScenarios(join46(opts.projectDir, ".mma", "certification", "scenarios"));
|
|
32346
32490
|
for (const e of errors2)
|
|
32347
32491
|
console.error(pc2.yellow(` ${e}`));
|
|
32348
|
-
|
|
32492
|
+
let selected = filterByTags(scenarios, opts.tags);
|
|
32493
|
+
const isPartial = Array.isArray(opts.scenarios) && opts.scenarios.length > 0;
|
|
32494
|
+
if (isPartial) {
|
|
32495
|
+
const unknown = unknownScenarioIds(scenarios, opts.scenarios);
|
|
32496
|
+
if (unknown.length > 0) {
|
|
32497
|
+
console.error(pc2.red(t("cli.cert_scenarios_unknown", {
|
|
32498
|
+
ids: unknown.join(", "),
|
|
32499
|
+
available: scenarios.map((s) => s.id).join(", ")
|
|
32500
|
+
})));
|
|
32501
|
+
process.exitCode = 1;
|
|
32502
|
+
return;
|
|
32503
|
+
}
|
|
32504
|
+
selected = filterByScenarios(selected, opts.scenarios);
|
|
32505
|
+
}
|
|
32349
32506
|
if (selected.length === 0) {
|
|
32350
32507
|
console.error(pc2.red(t("cli.cert_no_scenarios", { tags: opts.tags.join(",") })));
|
|
32351
32508
|
process.exitCode = 1;
|
|
@@ -32353,7 +32510,7 @@ async function certify(opts) {
|
|
|
32353
32510
|
}
|
|
32354
32511
|
const manifest = readMergedManifest(opts.projectDir);
|
|
32355
32512
|
const existing = manifest.certifications.find((e) => e.model === opts.name && e.providerUrl === providerUrl);
|
|
32356
|
-
if (existing && !opts.force) {
|
|
32513
|
+
if (existing && !opts.force && !isPartial) {
|
|
32357
32514
|
console.error(pc2.yellow(t("cli.cert_exists", { model: opts.name })));
|
|
32358
32515
|
console.error(pc2.yellow(t("cli.cert_exists_hint")));
|
|
32359
32516
|
process.exitCode = 1;
|
|
@@ -32386,6 +32543,7 @@ async function certify(opts) {
|
|
|
32386
32543
|
sandboxBase,
|
|
32387
32544
|
defaultReps: opts.reps,
|
|
32388
32545
|
defaultThreshold: 2,
|
|
32546
|
+
timeoutMs: opts.timeout,
|
|
32389
32547
|
baseConfig: opts.config,
|
|
32390
32548
|
onRep: (id, rep, reps, passed, failures) => {
|
|
32391
32549
|
const word = passed ? pc2.green(t("cli.cert_rep_pass")) : pc2.red(t("cli.cert_rep_fail"));
|
|
@@ -32401,14 +32559,16 @@ async function certify(opts) {
|
|
|
32401
32559
|
rmSync5(sandboxBase, { recursive: true, force: true });
|
|
32402
32560
|
} catch {}
|
|
32403
32561
|
}
|
|
32404
|
-
const
|
|
32562
|
+
const runIds = new Set(selected.map((s) => s.id));
|
|
32563
|
+
const finalResults = isPartial && existing ? mergePartialResults(results, existing.results, runIds) : results;
|
|
32564
|
+
const suite = summarize(finalResults);
|
|
32405
32565
|
const entry = {
|
|
32406
32566
|
model: opts.name,
|
|
32407
32567
|
providerUrl,
|
|
32408
32568
|
mmaVersion: readVersion(),
|
|
32409
32569
|
certifiedAt: new Date().toISOString(),
|
|
32410
32570
|
suite,
|
|
32411
|
-
results
|
|
32571
|
+
results: finalResults
|
|
32412
32572
|
};
|
|
32413
32573
|
upsertCertification(entry);
|
|
32414
32574
|
console.log(t("cli.cert_done", {
|
|
@@ -32417,7 +32577,7 @@ async function certify(opts) {
|
|
|
32417
32577
|
skipped: String(suite.skipped),
|
|
32418
32578
|
total: String(suite.total)
|
|
32419
32579
|
}));
|
|
32420
|
-
printResults(
|
|
32580
|
+
printResults(finalResults);
|
|
32421
32581
|
if (isFullyPassed(entry)) {
|
|
32422
32582
|
console.log(pc2.green(`
|
|
32423
32583
|
✔ ${opts.name} is certified`));
|
|
@@ -32470,6 +32630,13 @@ function summarize(results) {
|
|
|
32470
32630
|
total: results.length
|
|
32471
32631
|
};
|
|
32472
32632
|
}
|
|
32633
|
+
function mergePartialResults(fresh, previous, rerunIds) {
|
|
32634
|
+
const preserved = previous.filter((r) => !rerunIds.has(r.id));
|
|
32635
|
+
if (preserved.length > 0) {
|
|
32636
|
+
console.log(pc2.dim(t("cli.cert_partial_merge", { kept: String(preserved.length) })));
|
|
32637
|
+
}
|
|
32638
|
+
return [...fresh, ...preserved];
|
|
32639
|
+
}
|
|
32473
32640
|
function printResults(results) {
|
|
32474
32641
|
for (const r of results) {
|
|
32475
32642
|
const icon = r.status === "pass" ? pc2.green("✔") : r.status === "fail" ? pc2.red("✘") : r.status === "skipped" ? pc2.dim("–") : pc2.yellow("!");
|
|
@@ -34075,7 +34242,7 @@ function createProgram() {
|
|
|
34075
34242
|
saveConfig(config, configPath, dirname19(configPath));
|
|
34076
34243
|
console.log(t("cli.model_set", { name }));
|
|
34077
34244
|
});
|
|
34078
|
-
model.command("certify").argument("<name>", "Model name").option("--provider-url <url>", t("cli.cert_provider_url")).option("--provider-key <key>", t("cli.cert_provider_key")).option("--context-window <n>", t("cli.cert_context_window")).option("--tags <tags>", t("cli.cert_tags"), "core").option("--reps <n>", t("cli.cert_reps")).option("--force", t("cli.cert_force")).option("--clean", t("cli.cert_clean")).description(t("cli.certify")).action(async (name, cmdOpts) => {
|
|
34245
|
+
model.command("certify").argument("<name>", "Model name").option("--provider-url <url>", t("cli.cert_provider_url")).option("--provider-key <key>", t("cli.cert_provider_key")).option("--context-window <n>", t("cli.cert_context_window")).option("--tags <tags>", t("cli.cert_tags"), "core").option("--scenarios <ids>", t("cli.cert_scenarios")).option("--timeout <ms>", t("cli.cert_timeout")).option("--reps <n>", t("cli.cert_reps")).option("--force", t("cli.cert_force")).option("--clean", t("cli.cert_clean")).description(t("cli.certify")).action(async (name, cmdOpts) => {
|
|
34079
34246
|
const { config } = await bootstrap();
|
|
34080
34247
|
const { certify: certify2, parseTags: parseTags2 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
|
|
34081
34248
|
await certify2({
|
|
@@ -34084,7 +34251,9 @@ function createProgram() {
|
|
|
34084
34251
|
providerKey: cmdOpts.providerKey,
|
|
34085
34252
|
contextWindow: cmdOpts.contextWindow ? parseInt(cmdOpts.contextWindow, 10) : undefined,
|
|
34086
34253
|
tags: parseTags2(cmdOpts.tags),
|
|
34254
|
+
scenarios: cmdOpts.scenarios ? String(cmdOpts.scenarios).split(",").map((x) => x.trim()).filter(Boolean) : undefined,
|
|
34087
34255
|
reps: cmdOpts.reps ? parseInt(cmdOpts.reps, 10) : 3,
|
|
34256
|
+
timeout: cmdOpts.timeout ? parseInt(cmdOpts.timeout, 10) : undefined,
|
|
34088
34257
|
force: cmdOpts.force === true,
|
|
34089
34258
|
clean: cmdOpts.clean === true,
|
|
34090
34259
|
config,
|