micro-models-agent 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +1408 -396
- package/dist/modules/browser/bridge-server.mjs +194 -0
- package/package.json +45 -45
package/dist/main.js
CHANGED
|
@@ -2162,7 +2162,7 @@ var init_defaults = __esm(() => {
|
|
|
2162
2162
|
init_config();
|
|
2163
2163
|
DEFAULTS = {
|
|
2164
2164
|
version: "2.0.0",
|
|
2165
|
-
model: "qwen3.5-9b",
|
|
2165
|
+
model: "qwen/qwen3.5-9b",
|
|
2166
2166
|
provider: {
|
|
2167
2167
|
type: "openai-compat",
|
|
2168
2168
|
baseUrl: "http://localhost:1234/v1",
|
|
@@ -2177,18 +2177,18 @@ var init_defaults = __esm(() => {
|
|
|
2177
2177
|
},
|
|
2178
2178
|
experts: {
|
|
2179
2179
|
code: {
|
|
2180
|
-
model: "qwen3.5-9b",
|
|
2180
|
+
model: "qwen/qwen3.5-9b",
|
|
2181
2181
|
tool_tags: ["file", "code", "shell"],
|
|
2182
2182
|
max_attempts: 3
|
|
2183
2183
|
},
|
|
2184
|
-
research: { model: "qwen3.5-9b", tool_tags: ["research"], max_attempts: 3 },
|
|
2184
|
+
research: { model: "qwen/qwen3.5-9b", tool_tags: ["research"], max_attempts: 3 },
|
|
2185
2185
|
browser: {
|
|
2186
|
-
model: "qwen3.5-9b",
|
|
2186
|
+
model: "qwen/qwen3.5-9b",
|
|
2187
2187
|
tool_tags: ["browser", "vision"],
|
|
2188
2188
|
max_attempts: 3
|
|
2189
2189
|
},
|
|
2190
2190
|
vision: {
|
|
2191
|
-
model: "qwen3.5-9b",
|
|
2191
|
+
model: "qwen/qwen3.5-9b",
|
|
2192
2192
|
tool_tags: ["browser", "vision", "file"],
|
|
2193
2193
|
max_attempts: 2
|
|
2194
2194
|
}
|
|
@@ -2225,7 +2225,8 @@ var init_defaults = __esm(() => {
|
|
|
2225
2225
|
headless: true,
|
|
2226
2226
|
maxElements: 30,
|
|
2227
2227
|
maxContentChars: 2500,
|
|
2228
|
-
maxConsoleEntries:
|
|
2228
|
+
maxConsoleEntries: 40,
|
|
2229
|
+
maxConsoleLineChars: 400,
|
|
2229
2230
|
viewportWidth: 1280,
|
|
2230
2231
|
viewportHeight: 720,
|
|
2231
2232
|
navigationTimeout: 15000
|
|
@@ -2457,7 +2458,7 @@ Command: {command}`,
|
|
|
2457
2458
|
"plan.step_status": "Step {step}: {status}",
|
|
2458
2459
|
"plan.no_active": "No active plan",
|
|
2459
2460
|
"plan.step_not_found": "Step not found",
|
|
2460
|
-
"plan.step_already_done": "Step {step} is already
|
|
2461
|
+
"plan.step_already_done": "Step {step} is already done — nothing to do. Plan progress:",
|
|
2461
2462
|
"plan.order_blocked": 'Cannot mark step {step} done: step {first} ("{desc}") is not finished yet. Complete earlier steps first, or mark step {first} status=skipped if it is not needed.',
|
|
2462
2463
|
"plan.show_header": "Plan status:",
|
|
2463
2464
|
"plan.show_empty": "(plan has no steps)",
|
|
@@ -3034,7 +3035,7 @@ var init_ru = __esm(() => {
|
|
|
3034
3035
|
"plan.step_status": "Шаг {step}: {status}",
|
|
3035
3036
|
"plan.no_active": "Нет активного плана",
|
|
3036
3037
|
"plan.step_not_found": "Шаг не найден",
|
|
3037
|
-
"plan.step_already_done": "Шаг {step} уже
|
|
3038
|
+
"plan.step_already_done": "Шаг {step} уже выполнен — ничего делать не нужно. Прогресс плана:",
|
|
3038
3039
|
"plan.order_blocked": "Нельзя отметить шаг {step} выполненным: шаг {first} («{desc}») ещё не завершён. Сначала завершите предыдущие шаги или отметьте шаг {first} status=skipped, если он не нужен.",
|
|
3039
3040
|
"plan.show_header": "Статус плана:",
|
|
3040
3041
|
"plan.show_empty": "(в плане нет шагов)",
|
|
@@ -10434,6 +10435,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
10434
10435
|
this.abortController = new AbortController;
|
|
10435
10436
|
let iteration = 0;
|
|
10436
10437
|
let lastText = "";
|
|
10438
|
+
let lastModelText = "";
|
|
10437
10439
|
let lastForcedCompactionIteration = -FORCED_COMPACTION_COOLDOWN;
|
|
10438
10440
|
let hallucinationRetries = 0;
|
|
10439
10441
|
let lastToolSignature = "";
|
|
@@ -10450,6 +10452,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
10450
10452
|
let emptyResponseExhausted = false;
|
|
10451
10453
|
let auditFailed = false;
|
|
10452
10454
|
let lastAuditSummary = "";
|
|
10455
|
+
let suppressRepetitionRetry = false;
|
|
10453
10456
|
let repeatedToolCount = 0;
|
|
10454
10457
|
const MAX_REPEATED_TOOL_CALLS = 2;
|
|
10455
10458
|
const allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
|
|
@@ -10737,9 +10740,12 @@ ${taskReminder}</system-summary>`
|
|
|
10737
10740
|
`));
|
|
10738
10741
|
}
|
|
10739
10742
|
}
|
|
10743
|
+
suppressRepetitionRetry = false;
|
|
10740
10744
|
continue;
|
|
10741
10745
|
}
|
|
10742
|
-
hallucinationDetector.getConfidenceCheck().setPreviousResponse(
|
|
10746
|
+
hallucinationDetector.getConfidenceCheck().setPreviousResponse(lastModelText);
|
|
10747
|
+
if (textContent)
|
|
10748
|
+
lastModelText = textContent;
|
|
10743
10749
|
const hallucinationResult = await hallucinationDetector.validate(textContent);
|
|
10744
10750
|
if (hallucinationResult.status === "block") {
|
|
10745
10751
|
logger.warn(`Response blocked: ${hallucinationResult.reason}`);
|
|
@@ -10771,30 +10777,45 @@ ${warnLine}
|
|
|
10771
10777
|
lastText = textContent;
|
|
10772
10778
|
break;
|
|
10773
10779
|
}
|
|
10774
|
-
if (
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10780
|
+
if (suppressRepetitionRetry && hallucinationResult.kind === "repetition") {
|
|
10781
|
+
suppressRepetitionRetry = false;
|
|
10782
|
+
logger.warn(`Audit-triggered re-answer repetition — not counted as hallucination retry`);
|
|
10783
|
+
const warnLine = `${t("hall.uncertainty_prefix").trim()} ${hallucinationResult.reason ?? ""}`;
|
|
10784
|
+
if (onMeta) {
|
|
10785
|
+
onMeta(`
|
|
10786
|
+
${pc2.yellow(warnLine)}
|
|
10787
|
+
`);
|
|
10788
|
+
} else if (onChunk) {
|
|
10789
|
+
onChunk(`
|
|
10790
|
+
${warnLine}
|
|
10791
|
+
`);
|
|
10792
|
+
}
|
|
10793
|
+
} else {
|
|
10794
|
+
if (hallucinationRetries >= MAX_HALLUCINATION_RETRIES) {
|
|
10795
|
+
logger.warn(`Hallucination retries exhausted (${MAX_HALLUCINATION_RETRIES}), returning error`);
|
|
10796
|
+
return {
|
|
10797
|
+
success: false,
|
|
10798
|
+
text: lastText,
|
|
10799
|
+
error: t("error.response_blocked", {
|
|
10800
|
+
reason: t("hall.max_retries_exhausted")
|
|
10801
|
+
}),
|
|
10802
|
+
iterationCount: iteration
|
|
10803
|
+
};
|
|
10804
|
+
}
|
|
10805
|
+
hallucinationRetries++;
|
|
10806
|
+
logger.warn(`Hallucination retry (${hallucinationRetries}/${MAX_HALLUCINATION_RETRIES}): ${hallucinationResult.reason}`);
|
|
10807
|
+
if (textContent) {
|
|
10808
|
+
contextManager.addMessage({
|
|
10809
|
+
role: "assistant",
|
|
10810
|
+
content: textContent
|
|
10811
|
+
});
|
|
10812
|
+
}
|
|
10788
10813
|
contextManager.addMessage({
|
|
10789
|
-
role: "
|
|
10790
|
-
content:
|
|
10814
|
+
role: "user",
|
|
10815
|
+
content: `<system-summary>[Retry context: ${hallucinationResult.reason}. Original task: "${input}". You must either call a needed tool or provide a substantive response. Empty replies are not allowed.]</system-summary>`
|
|
10791
10816
|
});
|
|
10817
|
+
continue;
|
|
10792
10818
|
}
|
|
10793
|
-
contextManager.addMessage({
|
|
10794
|
-
role: "user",
|
|
10795
|
-
content: `<system-summary>[Retry context: ${hallucinationResult.reason}. Original task: "${input}". You must either call a needed tool or provide a substantive response. Empty replies are not allowed.]</system-summary>`
|
|
10796
|
-
});
|
|
10797
|
-
continue;
|
|
10798
10819
|
}
|
|
10799
10820
|
if (textContent) {
|
|
10800
10821
|
contextManager.addMessage({ role: "assistant", content: textContent });
|
|
@@ -10846,6 +10867,7 @@ ${warnLine}
|
|
|
10846
10867
|
auditFailed = true;
|
|
10847
10868
|
break;
|
|
10848
10869
|
}
|
|
10870
|
+
suppressRepetitionRetry = true;
|
|
10849
10871
|
continue;
|
|
10850
10872
|
}
|
|
10851
10873
|
}
|
|
@@ -11295,13 +11317,18 @@ class ConfidenceCheck {
|
|
|
11295
11317
|
}
|
|
11296
11318
|
validate(response) {
|
|
11297
11319
|
if (!response || response.length < MIN_CHARS) {
|
|
11298
|
-
return {
|
|
11320
|
+
return {
|
|
11321
|
+
status: "retry",
|
|
11322
|
+
kind: "short",
|
|
11323
|
+
reason: t("hall.short_response")
|
|
11324
|
+
};
|
|
11299
11325
|
}
|
|
11300
11326
|
const wordCount = response.split(/\s+/).filter(Boolean).length;
|
|
11301
11327
|
const hasStructure = /```|^\s*[-*]\s|^\s*\d+\.\s|<[^>]+>/m.test(response);
|
|
11302
11328
|
if (wordCount < MIN_WORDS && !hasStructure) {
|
|
11303
11329
|
return {
|
|
11304
11330
|
status: "warn",
|
|
11331
|
+
kind: "short",
|
|
11305
11332
|
reason: t("hall.short_response")
|
|
11306
11333
|
};
|
|
11307
11334
|
}
|
|
@@ -11310,6 +11337,7 @@ class ConfidenceCheck {
|
|
|
11310
11337
|
if (overlap > 0.5) {
|
|
11311
11338
|
return {
|
|
11312
11339
|
status: "retry",
|
|
11340
|
+
kind: "repetition",
|
|
11313
11341
|
reason: t("hall.repetitive", { pct: Math.round(overlap * 100) })
|
|
11314
11342
|
};
|
|
11315
11343
|
}
|
|
@@ -11321,6 +11349,7 @@ class ConfidenceCheck {
|
|
|
11321
11349
|
if (diversity < 0.25) {
|
|
11322
11350
|
return {
|
|
11323
11351
|
status: "warn",
|
|
11352
|
+
kind: "diversity",
|
|
11324
11353
|
reason: t("hall.repetitive", {
|
|
11325
11354
|
pct: Math.round((1 - diversity) * 100)
|
|
11326
11355
|
})
|
|
@@ -11349,7 +11378,25 @@ function isJsMemberAccess(candidate) {
|
|
|
11349
11378
|
const m = lower.match(/^([\w-]+)\./);
|
|
11350
11379
|
return m !== null && JS_GLOBALS.has(m[1]);
|
|
11351
11380
|
}
|
|
11352
|
-
|
|
11381
|
+
function isFilePathLike(s) {
|
|
11382
|
+
const lower = s.toLowerCase();
|
|
11383
|
+
if (TECH_NAMES.has(lower))
|
|
11384
|
+
return false;
|
|
11385
|
+
if (!s.includes("/") && !s.includes("\\") && !/^\w+\.[a-z]{2,4}$/i.test(s))
|
|
11386
|
+
return false;
|
|
11387
|
+
if (isJsMemberAccess(s))
|
|
11388
|
+
return false;
|
|
11389
|
+
const ext = s.split(".").pop()?.toLowerCase() || "";
|
|
11390
|
+
return !NON_FILE_EXTENSIONS.has(ext);
|
|
11391
|
+
}
|
|
11392
|
+
function extractFileLikeTokens(text) {
|
|
11393
|
+
const matches = text.match(FILE_TOKEN_RE) || [];
|
|
11394
|
+
return [...new Set(matches.filter(isFilePathLike))];
|
|
11395
|
+
}
|
|
11396
|
+
function stripUrls(text) {
|
|
11397
|
+
return text.replace(/\bhttps?:\/\/[^\s"'<>]+/gi, " ");
|
|
11398
|
+
}
|
|
11399
|
+
var JS_GLOBALS, NON_FILE_EXTENSIONS, TECH_NAMES, FILE_TOKEN_RE;
|
|
11353
11400
|
var init_js_identifiers = __esm(() => {
|
|
11354
11401
|
JS_GLOBALS = new Set([
|
|
11355
11402
|
"process",
|
|
@@ -11407,22 +11454,46 @@ var init_js_identifiers = __esm(() => {
|
|
|
11407
11454
|
"deno",
|
|
11408
11455
|
"node"
|
|
11409
11456
|
]);
|
|
11457
|
+
NON_FILE_EXTENSIONS = new Set([
|
|
11458
|
+
"com",
|
|
11459
|
+
"org",
|
|
11460
|
+
"net",
|
|
11461
|
+
"gov",
|
|
11462
|
+
"edu",
|
|
11463
|
+
"io",
|
|
11464
|
+
"dev",
|
|
11465
|
+
"app",
|
|
11466
|
+
"co",
|
|
11467
|
+
"ai",
|
|
11468
|
+
"ru",
|
|
11469
|
+
"de",
|
|
11470
|
+
"fr",
|
|
11471
|
+
"uk",
|
|
11472
|
+
"us",
|
|
11473
|
+
"es",
|
|
11474
|
+
"it",
|
|
11475
|
+
"jp",
|
|
11476
|
+
"cn",
|
|
11477
|
+
"br"
|
|
11478
|
+
]);
|
|
11479
|
+
TECH_NAMES = new Set([
|
|
11480
|
+
"node.js",
|
|
11481
|
+
"react.js",
|
|
11482
|
+
"vue.js",
|
|
11483
|
+
"next.js",
|
|
11484
|
+
"angular.js",
|
|
11485
|
+
"express.js",
|
|
11486
|
+
"deno.js",
|
|
11487
|
+
"qwik.js",
|
|
11488
|
+
"svelte.js",
|
|
11489
|
+
"jquery.js"
|
|
11490
|
+
]);
|
|
11491
|
+
FILE_TOKEN_RE = /\b(?:[a-zA-Z]:[\\/])?[\w./\\-]+\.[a-z]{2,6}\b/gi;
|
|
11410
11492
|
});
|
|
11411
11493
|
|
|
11412
11494
|
// src/modules/hallucination/factual.ts
|
|
11413
11495
|
import { existsSync as existsSync22, readdirSync as readdirSync5 } from "fs";
|
|
11414
11496
|
import { resolve as resolve12, isAbsolute as isAbsolute2, join as join13 } from "path";
|
|
11415
|
-
function looksLikeFilePath(s) {
|
|
11416
|
-
const lower = s.toLowerCase();
|
|
11417
|
-
if (TECH_NAMES.has(lower))
|
|
11418
|
-
return false;
|
|
11419
|
-
if (!s.includes("/") && !s.includes("\\") && !s.match(/^\w+\.[a-z]{2,4}$/i))
|
|
11420
|
-
return false;
|
|
11421
|
-
if (isJsMemberAccess(s))
|
|
11422
|
-
return false;
|
|
11423
|
-
const ext = s.split(".").pop()?.toLowerCase() || "";
|
|
11424
|
-
return !NON_FILE_EXTENSIONS.has(ext);
|
|
11425
|
-
}
|
|
11426
11497
|
|
|
11427
11498
|
class FactualCheck {
|
|
11428
11499
|
baseDir;
|
|
@@ -11521,12 +11592,10 @@ class FactualCheck {
|
|
|
11521
11592
|
return count;
|
|
11522
11593
|
}
|
|
11523
11594
|
extractFilePaths(text) {
|
|
11524
|
-
|
|
11525
|
-
const matches = text.match(pattern) || [];
|
|
11526
|
-
return [...new Set(matches)].filter(looksLikeFilePath);
|
|
11595
|
+
return extractFileLikeTokens(stripUrls(text));
|
|
11527
11596
|
}
|
|
11528
11597
|
}
|
|
11529
|
-
var IGNORED_DIRS
|
|
11598
|
+
var IGNORED_DIRS;
|
|
11530
11599
|
var init_factual = __esm(() => {
|
|
11531
11600
|
init_i18n();
|
|
11532
11601
|
init_js_identifiers();
|
|
@@ -11539,40 +11608,6 @@ var init_factual = __esm(() => {
|
|
|
11539
11608
|
".mma",
|
|
11540
11609
|
"_testing"
|
|
11541
11610
|
]);
|
|
11542
|
-
NON_FILE_EXTENSIONS = new Set([
|
|
11543
|
-
"com",
|
|
11544
|
-
"org",
|
|
11545
|
-
"net",
|
|
11546
|
-
"gov",
|
|
11547
|
-
"edu",
|
|
11548
|
-
"io",
|
|
11549
|
-
"dev",
|
|
11550
|
-
"app",
|
|
11551
|
-
"co",
|
|
11552
|
-
"ai",
|
|
11553
|
-
"ru",
|
|
11554
|
-
"de",
|
|
11555
|
-
"fr",
|
|
11556
|
-
"uk",
|
|
11557
|
-
"us",
|
|
11558
|
-
"es",
|
|
11559
|
-
"it",
|
|
11560
|
-
"jp",
|
|
11561
|
-
"cn",
|
|
11562
|
-
"br"
|
|
11563
|
-
]);
|
|
11564
|
-
TECH_NAMES = new Set([
|
|
11565
|
-
"node.js",
|
|
11566
|
-
"react.js",
|
|
11567
|
-
"vue.js",
|
|
11568
|
-
"next.js",
|
|
11569
|
-
"angular.js",
|
|
11570
|
-
"express.js",
|
|
11571
|
-
"deno.js",
|
|
11572
|
-
"qwik.js",
|
|
11573
|
-
"svelte.js",
|
|
11574
|
-
"jquery.js"
|
|
11575
|
-
]);
|
|
11576
11611
|
});
|
|
11577
11612
|
|
|
11578
11613
|
// src/modules/hallucination/llm-judge.ts
|
|
@@ -13670,6 +13705,306 @@ var init_recall = __esm(() => {
|
|
|
13670
13705
|
};
|
|
13671
13706
|
});
|
|
13672
13707
|
|
|
13708
|
+
// src/modules/browser/bridge-client.ts
|
|
13709
|
+
var exports_bridge_client = {};
|
|
13710
|
+
__export(exports_bridge_client, {
|
|
13711
|
+
BridgeDriver: () => BridgeDriver
|
|
13712
|
+
});
|
|
13713
|
+
import { spawn as spawn4 } from "child_process";
|
|
13714
|
+
import { createInterface } from "readline";
|
|
13715
|
+
import { dirname as dirname6, join as join17 } from "path";
|
|
13716
|
+
import { fileURLToPath } from "url";
|
|
13717
|
+
function bridgeScriptPath() {
|
|
13718
|
+
return join17(dirname6(fileURLToPath(import.meta.url)), "bridge-server.mjs");
|
|
13719
|
+
}
|
|
13720
|
+
|
|
13721
|
+
class BridgeDriver {
|
|
13722
|
+
proc = null;
|
|
13723
|
+
rl = null;
|
|
13724
|
+
pending = new Map;
|
|
13725
|
+
nextId = 1;
|
|
13726
|
+
lastUrl = "";
|
|
13727
|
+
console = new ConsoleBuffer(500);
|
|
13728
|
+
network = [];
|
|
13729
|
+
maxConsoleLineChars;
|
|
13730
|
+
constructor(opts = {}) {
|
|
13731
|
+
this.maxConsoleLineChars = opts.maxConsoleLineChars ?? 400;
|
|
13732
|
+
}
|
|
13733
|
+
async send(cmd, params = {}) {
|
|
13734
|
+
if (!this.proc || !this.rl)
|
|
13735
|
+
throw new Error("Bridge is not running");
|
|
13736
|
+
const id = this.nextId++;
|
|
13737
|
+
const response = await new Promise((resolve15, reject) => {
|
|
13738
|
+
const timer = setTimeout(() => {
|
|
13739
|
+
this.pending.delete(id);
|
|
13740
|
+
reject(new Error(`Bridge timeout waiting for "${cmd}"`));
|
|
13741
|
+
}, BRIDGE_REQUEST_TIMEOUT_MS);
|
|
13742
|
+
this.pending.set(id, (resp) => {
|
|
13743
|
+
clearTimeout(timer);
|
|
13744
|
+
resolve15(resp);
|
|
13745
|
+
});
|
|
13746
|
+
this.proc.stdin.write(JSON.stringify({ id, cmd, params }) + `
|
|
13747
|
+
`);
|
|
13748
|
+
});
|
|
13749
|
+
this.drainEvents(response);
|
|
13750
|
+
if (!response.ok)
|
|
13751
|
+
throw new Error(response.error || `Bridge command failed: ${cmd}`);
|
|
13752
|
+
return response;
|
|
13753
|
+
}
|
|
13754
|
+
drainEvents(resp) {
|
|
13755
|
+
if (Array.isArray(resp.console)) {
|
|
13756
|
+
for (const entry of resp.console) {
|
|
13757
|
+
this.console.add(entry.type, entry.text);
|
|
13758
|
+
}
|
|
13759
|
+
}
|
|
13760
|
+
if (Array.isArray(resp.network)) {
|
|
13761
|
+
for (const err of resp.network)
|
|
13762
|
+
this.network.push(err);
|
|
13763
|
+
}
|
|
13764
|
+
if (resp.data && typeof resp.data.url === "string") {
|
|
13765
|
+
this.lastUrl = resp.data.url;
|
|
13766
|
+
}
|
|
13767
|
+
}
|
|
13768
|
+
async launch(cfg) {
|
|
13769
|
+
this.spawnBridge();
|
|
13770
|
+
await this.send("launch", {
|
|
13771
|
+
headless: cfg.headless,
|
|
13772
|
+
viewport: cfg.viewport,
|
|
13773
|
+
timeoutMs: cfg.timeoutMs,
|
|
13774
|
+
maxConsoleLineChars: this.maxConsoleLineChars
|
|
13775
|
+
});
|
|
13776
|
+
}
|
|
13777
|
+
spawnBridge() {
|
|
13778
|
+
const script = bridgeScriptPath();
|
|
13779
|
+
const proc = spawn4("node", [script], { stdio: ["pipe", "pipe", "pipe"], windowsHide: true });
|
|
13780
|
+
this.proc = proc;
|
|
13781
|
+
proc.stderr.on("data", () => {});
|
|
13782
|
+
const rl = createInterface({ input: proc.stdout });
|
|
13783
|
+
this.rl = rl;
|
|
13784
|
+
rl.on("line", (line) => {
|
|
13785
|
+
let resp;
|
|
13786
|
+
try {
|
|
13787
|
+
resp = JSON.parse(line);
|
|
13788
|
+
} catch {
|
|
13789
|
+
return;
|
|
13790
|
+
}
|
|
13791
|
+
const resolver = this.pending.get(resp.id);
|
|
13792
|
+
if (resolver) {
|
|
13793
|
+
this.pending.delete(resp.id);
|
|
13794
|
+
resolver(resp);
|
|
13795
|
+
}
|
|
13796
|
+
});
|
|
13797
|
+
proc.on("exit", () => {
|
|
13798
|
+
for (const [, resolver] of this.pending) {
|
|
13799
|
+
resolver({ id: -1, ok: false, error: "Bridge process exited" });
|
|
13800
|
+
}
|
|
13801
|
+
this.pending.clear();
|
|
13802
|
+
this.proc = null;
|
|
13803
|
+
this.rl = null;
|
|
13804
|
+
});
|
|
13805
|
+
}
|
|
13806
|
+
async goto(url, timeoutMs) {
|
|
13807
|
+
await this.send("goto", { url, timeoutMs });
|
|
13808
|
+
}
|
|
13809
|
+
async evaluate(js) {
|
|
13810
|
+
const resp = await this.send("evaluate", { js });
|
|
13811
|
+
return resp.data?.result;
|
|
13812
|
+
}
|
|
13813
|
+
async content() {
|
|
13814
|
+
const resp = await this.send("content");
|
|
13815
|
+
return String(resp.data?.html ?? "");
|
|
13816
|
+
}
|
|
13817
|
+
async title() {
|
|
13818
|
+
const resp = await this.send("title");
|
|
13819
|
+
return String(resp.data?.title ?? "");
|
|
13820
|
+
}
|
|
13821
|
+
url() {
|
|
13822
|
+
return this.lastUrl;
|
|
13823
|
+
}
|
|
13824
|
+
async waitForLoad(timeoutMs) {
|
|
13825
|
+
await this.send("waitLoad", { timeoutMs });
|
|
13826
|
+
}
|
|
13827
|
+
async screenshot() {
|
|
13828
|
+
const resp = await this.send("screenshot");
|
|
13829
|
+
return Buffer.from(String(resp.data?.base64 ?? ""), "base64");
|
|
13830
|
+
}
|
|
13831
|
+
async cookies() {
|
|
13832
|
+
const resp = await this.send("cookies");
|
|
13833
|
+
return resp.data?.cookies ?? [];
|
|
13834
|
+
}
|
|
13835
|
+
async addCookies(cookies) {
|
|
13836
|
+
await this.send("setCookies", { cookies });
|
|
13837
|
+
}
|
|
13838
|
+
async goBack(timeoutMs) {
|
|
13839
|
+
await this.send("back", { timeoutMs });
|
|
13840
|
+
}
|
|
13841
|
+
async goForward(timeoutMs) {
|
|
13842
|
+
await this.send("forward", { timeoutMs });
|
|
13843
|
+
}
|
|
13844
|
+
resetEventLog() {
|
|
13845
|
+
this.console.clear();
|
|
13846
|
+
this.network = [];
|
|
13847
|
+
}
|
|
13848
|
+
getConsole() {
|
|
13849
|
+
return this.console.getAll();
|
|
13850
|
+
}
|
|
13851
|
+
getNetworkErrors() {
|
|
13852
|
+
return this.network.slice(-15);
|
|
13853
|
+
}
|
|
13854
|
+
async close() {
|
|
13855
|
+
try {
|
|
13856
|
+
if (this.proc)
|
|
13857
|
+
await this.send("close");
|
|
13858
|
+
} catch {}
|
|
13859
|
+
this.dispose();
|
|
13860
|
+
}
|
|
13861
|
+
dispose() {
|
|
13862
|
+
if (this.proc) {
|
|
13863
|
+
this.proc.kill();
|
|
13864
|
+
this.proc = null;
|
|
13865
|
+
}
|
|
13866
|
+
if (this.rl) {
|
|
13867
|
+
this.rl.close();
|
|
13868
|
+
this.rl = null;
|
|
13869
|
+
}
|
|
13870
|
+
}
|
|
13871
|
+
}
|
|
13872
|
+
var BRIDGE_REQUEST_TIMEOUT_MS = 30000;
|
|
13873
|
+
var init_bridge_client = __esm(() => {
|
|
13874
|
+
init_session();
|
|
13875
|
+
});
|
|
13876
|
+
|
|
13877
|
+
// src/modules/browser/driver.ts
|
|
13878
|
+
import { chromium } from "playwright";
|
|
13879
|
+
|
|
13880
|
+
class PlaywrightDriver {
|
|
13881
|
+
browser = null;
|
|
13882
|
+
context = null;
|
|
13883
|
+
page = null;
|
|
13884
|
+
console = new ConsoleBuffer;
|
|
13885
|
+
network = [];
|
|
13886
|
+
async launch(cfg) {
|
|
13887
|
+
if (this.browser)
|
|
13888
|
+
return;
|
|
13889
|
+
this.browser = await chromium.launch({
|
|
13890
|
+
headless: cfg.headless,
|
|
13891
|
+
timeout: cfg.timeoutMs
|
|
13892
|
+
});
|
|
13893
|
+
this.context = await this.browser.newContext({ viewport: cfg.viewport });
|
|
13894
|
+
this.page = await this.context.newPage();
|
|
13895
|
+
this.page.setDefaultTimeout(cfg.timeoutMs);
|
|
13896
|
+
this.page.on("console", (msg) => this.console.add(msg.type(), msg.text()));
|
|
13897
|
+
this.page.on("pageerror", (err) => this.console.add("pageerror", `Page error: ${err.message}`));
|
|
13898
|
+
this.page.on("requestfailed", (req) => {
|
|
13899
|
+
const failure = req.failure();
|
|
13900
|
+
this.network.push({
|
|
13901
|
+
method: req.method(),
|
|
13902
|
+
url: req.url(),
|
|
13903
|
+
error: failure?.errorText || "unknown"
|
|
13904
|
+
});
|
|
13905
|
+
});
|
|
13906
|
+
}
|
|
13907
|
+
async goto(url, timeoutMs) {
|
|
13908
|
+
this.requirePage();
|
|
13909
|
+
this.console.clear();
|
|
13910
|
+
this.network = [];
|
|
13911
|
+
await this.page.goto(url, { waitUntil: "domcontentloaded", timeout: timeoutMs });
|
|
13912
|
+
}
|
|
13913
|
+
async evaluate(js) {
|
|
13914
|
+
return this.requirePage().evaluate(js);
|
|
13915
|
+
}
|
|
13916
|
+
async content() {
|
|
13917
|
+
return this.requirePage().content();
|
|
13918
|
+
}
|
|
13919
|
+
async title() {
|
|
13920
|
+
return this.requirePage().title();
|
|
13921
|
+
}
|
|
13922
|
+
url() {
|
|
13923
|
+
return this.page?.url() || "";
|
|
13924
|
+
}
|
|
13925
|
+
async waitForLoad(timeoutMs) {
|
|
13926
|
+
await this.requirePage().waitForLoadState("domcontentloaded", { timeout: timeoutMs }).catch(() => {});
|
|
13927
|
+
}
|
|
13928
|
+
async screenshot() {
|
|
13929
|
+
return this.requirePage().screenshot({ type: "png", fullPage: false });
|
|
13930
|
+
}
|
|
13931
|
+
async cookies() {
|
|
13932
|
+
if (!this.context)
|
|
13933
|
+
return [];
|
|
13934
|
+
return this.context.cookies();
|
|
13935
|
+
}
|
|
13936
|
+
async addCookies(cookies) {
|
|
13937
|
+
if (!this.context || cookies.length === 0)
|
|
13938
|
+
return;
|
|
13939
|
+
await this.context.addCookies(cookies);
|
|
13940
|
+
}
|
|
13941
|
+
async goBack(timeoutMs) {
|
|
13942
|
+
await this.requirePage().goBack({ waitUntil: "domcontentloaded", timeout: timeoutMs }).catch(() => {});
|
|
13943
|
+
}
|
|
13944
|
+
async goForward(timeoutMs) {
|
|
13945
|
+
await this.requirePage().goForward({ waitUntil: "domcontentloaded", timeout: timeoutMs }).catch(() => {});
|
|
13946
|
+
}
|
|
13947
|
+
resetEventLog() {
|
|
13948
|
+
this.console.clear();
|
|
13949
|
+
this.network = [];
|
|
13950
|
+
}
|
|
13951
|
+
getConsole() {
|
|
13952
|
+
return this.console.getAll();
|
|
13953
|
+
}
|
|
13954
|
+
getNetworkErrors() {
|
|
13955
|
+
return this.network.slice(-15);
|
|
13956
|
+
}
|
|
13957
|
+
async close() {
|
|
13958
|
+
if (this.page)
|
|
13959
|
+
await this.page.close().catch(() => {});
|
|
13960
|
+
if (this.context)
|
|
13961
|
+
await this.context.close().catch(() => {});
|
|
13962
|
+
if (this.browser)
|
|
13963
|
+
await this.browser.close().catch(() => {});
|
|
13964
|
+
this.page = null;
|
|
13965
|
+
this.context = null;
|
|
13966
|
+
this.browser = null;
|
|
13967
|
+
}
|
|
13968
|
+
dispose() {
|
|
13969
|
+
this.close().catch(() => {});
|
|
13970
|
+
}
|
|
13971
|
+
requirePage() {
|
|
13972
|
+
if (!this.page)
|
|
13973
|
+
throw new Error("No page open");
|
|
13974
|
+
return this.page;
|
|
13975
|
+
}
|
|
13976
|
+
}
|
|
13977
|
+
function createBrowserDriver(config) {
|
|
13978
|
+
const common = {
|
|
13979
|
+
headless: config.headless,
|
|
13980
|
+
viewport: { width: config.viewportWidth, height: config.viewportHeight },
|
|
13981
|
+
timeoutMs: config.navigationTimeout
|
|
13982
|
+
};
|
|
13983
|
+
return (async () => {
|
|
13984
|
+
if (process.versions.bun) {
|
|
13985
|
+
return launchBridge(config, common);
|
|
13986
|
+
}
|
|
13987
|
+
const direct = new PlaywrightDriver;
|
|
13988
|
+
try {
|
|
13989
|
+
await direct.launch({ ...common, timeoutMs: DIRECT_LAUNCH_TIMEOUT_MS });
|
|
13990
|
+
return direct;
|
|
13991
|
+
} catch {
|
|
13992
|
+
direct.dispose();
|
|
13993
|
+
}
|
|
13994
|
+
return launchBridge(config, common);
|
|
13995
|
+
})();
|
|
13996
|
+
}
|
|
13997
|
+
async function launchBridge(config, common) {
|
|
13998
|
+
const { BridgeDriver: BridgeDriver2 } = await Promise.resolve().then(() => (init_bridge_client(), exports_bridge_client));
|
|
13999
|
+
const bridge = new BridgeDriver2({ maxConsoleLineChars: config.maxConsoleLineChars });
|
|
14000
|
+
await bridge.launch(common);
|
|
14001
|
+
return bridge;
|
|
14002
|
+
}
|
|
14003
|
+
var DIRECT_LAUNCH_TIMEOUT_MS = 8000;
|
|
14004
|
+
var init_driver = __esm(() => {
|
|
14005
|
+
init_session();
|
|
14006
|
+
});
|
|
14007
|
+
|
|
13673
14008
|
// src/modules/browser/types.ts
|
|
13674
14009
|
var DEFAULT_BROWSER_CONFIG;
|
|
13675
14010
|
var init_types = __esm(() => {
|
|
@@ -13677,7 +14012,8 @@ var init_types = __esm(() => {
|
|
|
13677
14012
|
headless: true,
|
|
13678
14013
|
maxElements: 30,
|
|
13679
14014
|
maxContentChars: 2500,
|
|
13680
|
-
maxConsoleEntries:
|
|
14015
|
+
maxConsoleEntries: 40,
|
|
14016
|
+
maxConsoleLineChars: 400,
|
|
13681
14017
|
screenshotMaxWidth: 1280,
|
|
13682
14018
|
cookieDir: "",
|
|
13683
14019
|
viewportWidth: 1280,
|
|
@@ -13915,15 +14251,15 @@ function buildTextExtractionScript() {
|
|
|
13915
14251
|
|
|
13916
14252
|
// src/modules/browser/cookie-store.ts
|
|
13917
14253
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
13918
|
-
import { join as
|
|
14254
|
+
import { join as join18 } from "path";
|
|
13919
14255
|
|
|
13920
14256
|
class CookieStore {
|
|
13921
14257
|
filePath;
|
|
13922
14258
|
constructor(cookieDir) {
|
|
13923
|
-
this.filePath =
|
|
14259
|
+
this.filePath = join18(cookieDir, "cookies.json");
|
|
13924
14260
|
}
|
|
13925
14261
|
async save(cookies) {
|
|
13926
|
-
await mkdir(
|
|
14262
|
+
await mkdir(join18(this.filePath, ".."), { recursive: true });
|
|
13927
14263
|
await writeFile(this.filePath, JSON.stringify(cookies, null, 2), "utf-8");
|
|
13928
14264
|
}
|
|
13929
14265
|
async load() {
|
|
@@ -13941,10 +14277,6 @@ class CookieStore {
|
|
|
13941
14277
|
var init_cookie_store = () => {};
|
|
13942
14278
|
|
|
13943
14279
|
// src/modules/browser/session.ts
|
|
13944
|
-
import {
|
|
13945
|
-
chromium
|
|
13946
|
-
} from "playwright";
|
|
13947
|
-
|
|
13948
14280
|
class ConsoleBuffer {
|
|
13949
14281
|
entries = [];
|
|
13950
14282
|
maxEntries;
|
|
@@ -13998,9 +14330,7 @@ class BrowserActionTracker {
|
|
|
13998
14330
|
}
|
|
13999
14331
|
|
|
14000
14332
|
class BrowserSession {
|
|
14001
|
-
|
|
14002
|
-
context = null;
|
|
14003
|
-
page = null;
|
|
14333
|
+
driver = null;
|
|
14004
14334
|
config;
|
|
14005
14335
|
cookieStore;
|
|
14006
14336
|
state = {
|
|
@@ -14010,12 +14340,9 @@ class BrowserSession {
|
|
|
14010
14340
|
elementCount: 0
|
|
14011
14341
|
};
|
|
14012
14342
|
actionTracker = new BrowserActionTracker(3);
|
|
14013
|
-
consoleBuffer;
|
|
14014
|
-
networkErrors = [];
|
|
14015
14343
|
constructor(config) {
|
|
14016
14344
|
this.config = config;
|
|
14017
14345
|
this.cookieStore = new CookieStore(config.cookieDir);
|
|
14018
|
-
this.consoleBuffer = new ConsoleBuffer(config.maxConsoleEntries);
|
|
14019
14346
|
}
|
|
14020
14347
|
getState() {
|
|
14021
14348
|
return { ...this.state };
|
|
@@ -14061,7 +14388,7 @@ class BrowserSession {
|
|
|
14061
14388
|
};
|
|
14062
14389
|
}
|
|
14063
14390
|
if (action !== "open") {
|
|
14064
|
-
const warning = this.actionTracker.record(action, args, this.
|
|
14391
|
+
const warning = this.actionTracker.record(action, args, this.driver?.url() || "");
|
|
14065
14392
|
if (warning && result.success) {
|
|
14066
14393
|
result.output = result.output + `
|
|
14067
14394
|
|
|
@@ -14076,62 +14403,37 @@ class BrowserSession {
|
|
|
14076
14403
|
};
|
|
14077
14404
|
}
|
|
14078
14405
|
}
|
|
14079
|
-
async
|
|
14080
|
-
if (!this.
|
|
14406
|
+
async ensureDriver() {
|
|
14407
|
+
if (!this.driver) {
|
|
14081
14408
|
return { success: false, output: t("browser.no_page") };
|
|
14082
14409
|
}
|
|
14083
14410
|
return null;
|
|
14084
14411
|
}
|
|
14085
14412
|
async launch() {
|
|
14086
|
-
if (this.
|
|
14413
|
+
if (this.driver)
|
|
14087
14414
|
return;
|
|
14088
|
-
this.
|
|
14089
|
-
this.context = await this.browser.newContext({
|
|
14090
|
-
viewport: {
|
|
14091
|
-
width: this.config.viewportWidth,
|
|
14092
|
-
height: this.config.viewportHeight
|
|
14093
|
-
}
|
|
14094
|
-
});
|
|
14415
|
+
this.driver = await createBrowserDriver(this.config);
|
|
14095
14416
|
const savedCookies = await this.cookieStore.load();
|
|
14096
14417
|
if (savedCookies.length > 0) {
|
|
14097
|
-
await this.
|
|
14098
|
-
...c,
|
|
14099
|
-
sameSite: c.sameSite
|
|
14100
|
-
})));
|
|
14418
|
+
await this.driver.addCookies(savedCookies);
|
|
14101
14419
|
}
|
|
14102
|
-
this.page = await this.context.newPage();
|
|
14103
|
-
this.page.setDefaultTimeout(this.config.navigationTimeout);
|
|
14104
|
-
this.page.on("console", (msg) => {
|
|
14105
|
-
this.consoleBuffer.add(msg.type(), msg.text());
|
|
14106
|
-
});
|
|
14107
|
-
this.page.on("pageerror", (err) => {
|
|
14108
|
-
this.consoleBuffer.add("pageerror", `Page error: ${err.message}`);
|
|
14109
|
-
});
|
|
14110
|
-
this.page.on("requestfailed", (req) => {
|
|
14111
|
-
const failure = req.failure();
|
|
14112
|
-
this.networkErrors.push({
|
|
14113
|
-
method: req.method(),
|
|
14114
|
-
url: req.url(),
|
|
14115
|
-
error: failure?.errorText || "unknown"
|
|
14116
|
-
});
|
|
14117
|
-
});
|
|
14118
14420
|
}
|
|
14119
14421
|
async saveCookies() {
|
|
14120
|
-
if (!this.
|
|
14422
|
+
if (!this.driver)
|
|
14121
14423
|
return;
|
|
14122
|
-
const cookies = await this.
|
|
14424
|
+
const cookies = await this.driver.cookies();
|
|
14123
14425
|
await this.cookieStore.save(cookies);
|
|
14124
14426
|
}
|
|
14125
14427
|
async takeSnapshot() {
|
|
14126
|
-
if (!this.
|
|
14428
|
+
if (!this.driver)
|
|
14127
14429
|
return "No page open.";
|
|
14128
|
-
await this.
|
|
14129
|
-
const html = await this.
|
|
14130
|
-
const url = this.
|
|
14131
|
-
const title = await this.
|
|
14430
|
+
await this.driver.evaluate(buildIndexInjectionScript());
|
|
14431
|
+
const html = await this.driver.content();
|
|
14432
|
+
const url = this.driver.url();
|
|
14433
|
+
const title = await this.driver.title();
|
|
14132
14434
|
let content = "";
|
|
14133
14435
|
try {
|
|
14134
|
-
content = await this.
|
|
14436
|
+
content = String(await this.driver.evaluate(buildTextExtractionScript()));
|
|
14135
14437
|
} catch {
|
|
14136
14438
|
content = "";
|
|
14137
14439
|
}
|
|
@@ -14149,8 +14451,8 @@ class BrowserSession {
|
|
|
14149
14451
|
title,
|
|
14150
14452
|
elements,
|
|
14151
14453
|
content,
|
|
14152
|
-
console: this.
|
|
14153
|
-
networkErrors: this.
|
|
14454
|
+
console: this.driver.getConsole(),
|
|
14455
|
+
networkErrors: this.driver.getNetworkErrors(),
|
|
14154
14456
|
truncated
|
|
14155
14457
|
});
|
|
14156
14458
|
}
|
|
@@ -14162,16 +14464,12 @@ class BrowserSession {
|
|
|
14162
14464
|
url = isLocalhost ? "http://" + url : "https://" + url;
|
|
14163
14465
|
}
|
|
14164
14466
|
await this.launch();
|
|
14165
|
-
if (!this.
|
|
14467
|
+
if (!this.driver)
|
|
14166
14468
|
return { success: false, output: t("browser.create_page_failed") };
|
|
14167
14469
|
this.actionTracker.reset();
|
|
14168
|
-
this.
|
|
14169
|
-
this.networkErrors = [];
|
|
14470
|
+
this.driver.resetEventLog();
|
|
14170
14471
|
try {
|
|
14171
|
-
await this.
|
|
14172
|
-
waitUntil: "domcontentloaded",
|
|
14173
|
-
timeout: this.config.navigationTimeout
|
|
14174
|
-
});
|
|
14472
|
+
await this.driver.goto(url, this.config.navigationTimeout);
|
|
14175
14473
|
} catch (err) {
|
|
14176
14474
|
return {
|
|
14177
14475
|
success: false,
|
|
@@ -14183,18 +14481,17 @@ class BrowserSession {
|
|
|
14183
14481
|
return { success: true, output: snapshot };
|
|
14184
14482
|
}
|
|
14185
14483
|
async click(target) {
|
|
14186
|
-
const err = await this.
|
|
14484
|
+
const err = await this.ensureDriver();
|
|
14187
14485
|
if (err)
|
|
14188
14486
|
return err;
|
|
14189
|
-
if (!this.
|
|
14487
|
+
if (!this.driver)
|
|
14190
14488
|
return { success: false, output: "No page" };
|
|
14191
14489
|
if (!target || target < 1) {
|
|
14192
14490
|
return { success: false, output: t("browser.invalid_target") };
|
|
14193
14491
|
}
|
|
14194
14492
|
try {
|
|
14195
|
-
|
|
14196
|
-
await this.
|
|
14197
|
-
await this.page.waitForLoadState("domcontentloaded", { timeout: 5000 }).catch(() => {});
|
|
14493
|
+
await this.driver.evaluate(buildClickScript(target));
|
|
14494
|
+
await this.driver.waitForLoad(5000);
|
|
14198
14495
|
await new Promise((r) => setTimeout(r, 500));
|
|
14199
14496
|
const snapshot = await this.takeSnapshot();
|
|
14200
14497
|
await this.saveCookies();
|
|
@@ -14207,10 +14504,10 @@ class BrowserSession {
|
|
|
14207
14504
|
}
|
|
14208
14505
|
}
|
|
14209
14506
|
async type(target, text) {
|
|
14210
|
-
const err = await this.
|
|
14507
|
+
const err = await this.ensureDriver();
|
|
14211
14508
|
if (err)
|
|
14212
14509
|
return err;
|
|
14213
|
-
if (!this.
|
|
14510
|
+
if (!this.driver)
|
|
14214
14511
|
return { success: false, output: "No page" };
|
|
14215
14512
|
if (!target || target < 1) {
|
|
14216
14513
|
return { success: false, output: t("browser.invalid_target_short") };
|
|
@@ -14219,8 +14516,7 @@ class BrowserSession {
|
|
|
14219
14516
|
return { success: false, output: t("browser.text_required") };
|
|
14220
14517
|
}
|
|
14221
14518
|
try {
|
|
14222
|
-
|
|
14223
|
-
await this.page.evaluate(script);
|
|
14519
|
+
await this.driver.evaluate(buildTypeScript(target, text));
|
|
14224
14520
|
const snapshot = await this.takeSnapshot();
|
|
14225
14521
|
return { success: true, output: snapshot };
|
|
14226
14522
|
} catch (err2) {
|
|
@@ -14231,17 +14527,17 @@ class BrowserSession {
|
|
|
14231
14527
|
}
|
|
14232
14528
|
}
|
|
14233
14529
|
async scroll(direction) {
|
|
14234
|
-
const err = await this.
|
|
14530
|
+
const err = await this.ensureDriver();
|
|
14235
14531
|
if (err)
|
|
14236
14532
|
return err;
|
|
14237
|
-
if (!this.
|
|
14533
|
+
if (!this.driver)
|
|
14238
14534
|
return { success: false, output: "No page" };
|
|
14239
14535
|
const dir = direction;
|
|
14240
14536
|
if (!["up", "down", "top", "bottom"].includes(dir)) {
|
|
14241
14537
|
return { success: false, output: t("browser.direction_invalid") };
|
|
14242
14538
|
}
|
|
14243
14539
|
try {
|
|
14244
|
-
await this.
|
|
14540
|
+
await this.driver.evaluate(buildScrollScript(dir));
|
|
14245
14541
|
await new Promise((r) => setTimeout(r, 300));
|
|
14246
14542
|
const snapshot = await this.takeSnapshot();
|
|
14247
14543
|
return { success: true, output: snapshot };
|
|
@@ -14253,52 +14549,46 @@ class BrowserSession {
|
|
|
14253
14549
|
}
|
|
14254
14550
|
}
|
|
14255
14551
|
async back() {
|
|
14256
|
-
const err = await this.
|
|
14552
|
+
const err = await this.ensureDriver();
|
|
14257
14553
|
if (err)
|
|
14258
14554
|
return err;
|
|
14259
|
-
if (!this.
|
|
14555
|
+
if (!this.driver)
|
|
14260
14556
|
return { success: false, output: "No page" };
|
|
14261
|
-
await this.
|
|
14262
|
-
waitUntil: "domcontentloaded",
|
|
14263
|
-
timeout: this.config.navigationTimeout
|
|
14264
|
-
}).catch(() => {});
|
|
14557
|
+
await this.driver.goBack(this.config.navigationTimeout);
|
|
14265
14558
|
await new Promise((r) => setTimeout(r, 300));
|
|
14266
14559
|
const snapshot = await this.takeSnapshot();
|
|
14267
14560
|
return { success: true, output: snapshot };
|
|
14268
14561
|
}
|
|
14269
14562
|
async forward() {
|
|
14270
|
-
const err = await this.
|
|
14563
|
+
const err = await this.ensureDriver();
|
|
14271
14564
|
if (err)
|
|
14272
14565
|
return err;
|
|
14273
|
-
if (!this.
|
|
14566
|
+
if (!this.driver)
|
|
14274
14567
|
return { success: false, output: "No page" };
|
|
14275
|
-
await this.
|
|
14276
|
-
waitUntil: "domcontentloaded",
|
|
14277
|
-
timeout: this.config.navigationTimeout
|
|
14278
|
-
}).catch(() => {});
|
|
14568
|
+
await this.driver.goForward(this.config.navigationTimeout);
|
|
14279
14569
|
await new Promise((r) => setTimeout(r, 300));
|
|
14280
14570
|
const snapshot = await this.takeSnapshot();
|
|
14281
14571
|
return { success: true, output: snapshot };
|
|
14282
14572
|
}
|
|
14283
14573
|
async screenshot() {
|
|
14284
|
-
const err = await this.
|
|
14574
|
+
const err = await this.ensureDriver();
|
|
14285
14575
|
if (err)
|
|
14286
14576
|
return err;
|
|
14287
|
-
if (!this.
|
|
14577
|
+
if (!this.driver)
|
|
14288
14578
|
return { success: false, output: "No page" };
|
|
14289
|
-
const buffer = await this.
|
|
14579
|
+
const buffer = await this.driver.screenshot();
|
|
14290
14580
|
const snapshot = await this.takeSnapshot();
|
|
14291
14581
|
return { success: true, output: snapshot, screenshot: buffer };
|
|
14292
14582
|
}
|
|
14293
14583
|
async snapshot() {
|
|
14294
|
-
const err = await this.
|
|
14584
|
+
const err = await this.ensureDriver();
|
|
14295
14585
|
if (err)
|
|
14296
14586
|
return err;
|
|
14297
14587
|
const snap = await this.takeSnapshot();
|
|
14298
14588
|
return { success: true, output: snap };
|
|
14299
14589
|
}
|
|
14300
14590
|
async wait(ms) {
|
|
14301
|
-
const err = await this.
|
|
14591
|
+
const err = await this.ensureDriver();
|
|
14302
14592
|
if (err)
|
|
14303
14593
|
return err;
|
|
14304
14594
|
await new Promise((r) => setTimeout(r, Math.min(ms, 1e4)));
|
|
@@ -14307,40 +14597,34 @@ class BrowserSession {
|
|
|
14307
14597
|
}
|
|
14308
14598
|
async close() {
|
|
14309
14599
|
await this.saveCookies();
|
|
14310
|
-
if (this.
|
|
14311
|
-
await this.
|
|
14312
|
-
this.
|
|
14313
|
-
}
|
|
14314
|
-
if (this.context) {
|
|
14315
|
-
await this.context.close().catch(() => {});
|
|
14316
|
-
this.context = null;
|
|
14317
|
-
}
|
|
14318
|
-
if (this.browser) {
|
|
14319
|
-
await this.browser.close().catch(() => {});
|
|
14320
|
-
this.browser = null;
|
|
14600
|
+
if (this.driver) {
|
|
14601
|
+
await this.driver.close();
|
|
14602
|
+
this.driver = null;
|
|
14321
14603
|
}
|
|
14322
14604
|
this.state = { isOpen: false, url: null, title: null, elementCount: 0 };
|
|
14323
14605
|
return { success: true, output: t("browser.closed") };
|
|
14324
14606
|
}
|
|
14325
14607
|
}
|
|
14326
|
-
var CONSOLE_MAX_LINE =
|
|
14608
|
+
var CONSOLE_MAX_LINE = 400;
|
|
14327
14609
|
var init_session = __esm(() => {
|
|
14610
|
+
init_driver();
|
|
14328
14611
|
init_snapshot();
|
|
14329
14612
|
init_cookie_store();
|
|
14330
14613
|
init_i18n();
|
|
14331
14614
|
});
|
|
14332
14615
|
|
|
14333
14616
|
// src/tools/browser.ts
|
|
14334
|
-
import { join as
|
|
14617
|
+
import { join as join19 } from "path";
|
|
14335
14618
|
function getSession(ctx) {
|
|
14336
14619
|
if (!session) {
|
|
14337
|
-
const cookieDir =
|
|
14620
|
+
const cookieDir = join19(ctx.baseDir, ".mma", "browser");
|
|
14338
14621
|
session = new BrowserSession({
|
|
14339
14622
|
...DEFAULT_BROWSER_CONFIG,
|
|
14340
14623
|
headless: ctx.config.browser?.headless ?? true,
|
|
14341
14624
|
maxElements: ctx.config.browser?.maxElements ?? 30,
|
|
14342
14625
|
maxContentChars: ctx.config.browser?.maxContentChars ?? 2500,
|
|
14343
|
-
maxConsoleEntries: ctx.config.browser?.maxConsoleEntries ??
|
|
14626
|
+
maxConsoleEntries: ctx.config.browser?.maxConsoleEntries ?? 40,
|
|
14627
|
+
maxConsoleLineChars: ctx.config.browser?.maxConsoleLineChars ?? 400,
|
|
14344
14628
|
navigationTimeout: ctx.config.browser?.navigationTimeout ?? 15000,
|
|
14345
14629
|
viewportWidth: ctx.config.browser?.viewportWidth ?? 1280,
|
|
14346
14630
|
viewportHeight: ctx.config.browser?.viewportHeight ?? 720,
|
|
@@ -14467,8 +14751,8 @@ async function readClipboardFallback() {
|
|
|
14467
14751
|
const { platform: platform3 } = await import("os");
|
|
14468
14752
|
const { execSync } = await import("child_process");
|
|
14469
14753
|
const { readFileSync: readFileSync15, unlinkSync: unlinkSync4 } = await import("fs");
|
|
14470
|
-
const { join:
|
|
14471
|
-
const tmpPath =
|
|
14754
|
+
const { join: join20 } = await import("path");
|
|
14755
|
+
const tmpPath = join20(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
|
|
14472
14756
|
try {
|
|
14473
14757
|
if (platform3() === "linux") {
|
|
14474
14758
|
execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, { timeout: 5000 });
|
|
@@ -14748,7 +15032,7 @@ class ModuleRegistry {
|
|
|
14748
15032
|
|
|
14749
15033
|
// src/modules/plugins/loader.ts
|
|
14750
15034
|
import { readdirSync as readdirSync7, existsSync as existsSync25, statSync as statSync5 } from "fs";
|
|
14751
|
-
import { join as
|
|
15035
|
+
import { join as join20 } from "path";
|
|
14752
15036
|
|
|
14753
15037
|
class PluginLoader {
|
|
14754
15038
|
loadFromDir(dirPath, pluginManager, logger) {
|
|
@@ -14756,7 +15040,7 @@ class PluginLoader {
|
|
|
14756
15040
|
return;
|
|
14757
15041
|
const entries = readdirSync7(dirPath);
|
|
14758
15042
|
for (const entry of entries) {
|
|
14759
|
-
const fullPath =
|
|
15043
|
+
const fullPath = join20(dirPath, entry);
|
|
14760
15044
|
if (!statSync5(fullPath).isFile())
|
|
14761
15045
|
continue;
|
|
14762
15046
|
if (!entry.endsWith(".ts") && !entry.endsWith(".js"))
|
|
@@ -14779,9 +15063,9 @@ var init_loader = __esm(() => {
|
|
|
14779
15063
|
});
|
|
14780
15064
|
|
|
14781
15065
|
// src/modules/plugins/builtin/lint-on-write.ts
|
|
14782
|
-
import { spawn as
|
|
15066
|
+
import { spawn as spawn5, execSync } from "child_process";
|
|
14783
15067
|
import { existsSync as existsSync26, readFileSync as readFileSync15 } from "fs";
|
|
14784
|
-
import { resolve as resolve16, extname as extname4, join as
|
|
15068
|
+
import { resolve as resolve16, extname as extname4, join as join21 } from "path";
|
|
14785
15069
|
import { platform as platform3 } from "os";
|
|
14786
15070
|
function contentHash(content) {
|
|
14787
15071
|
let h = 5381;
|
|
@@ -14883,7 +15167,7 @@ class LintOnWritePlugin {
|
|
|
14883
15167
|
}
|
|
14884
15168
|
async runProjectLint(ctx, result) {
|
|
14885
15169
|
try {
|
|
14886
|
-
const packageJsonPath =
|
|
15170
|
+
const packageJsonPath = join21(ctx.baseDir, "package.json");
|
|
14887
15171
|
if (!existsSync26(packageJsonPath)) {
|
|
14888
15172
|
return;
|
|
14889
15173
|
}
|
|
@@ -14903,7 +15187,7 @@ class LintOnWritePlugin {
|
|
|
14903
15187
|
}
|
|
14904
15188
|
}
|
|
14905
15189
|
async runProjectTypeCheck(ctx, result) {
|
|
14906
|
-
const tsconfigPath =
|
|
15190
|
+
const tsconfigPath = join21(ctx.baseDir, "tsconfig.json");
|
|
14907
15191
|
if (!existsSync26(tsconfigPath)) {
|
|
14908
15192
|
return;
|
|
14909
15193
|
}
|
|
@@ -14946,7 +15230,7 @@ class LintOnWritePlugin {
|
|
|
14946
15230
|
}
|
|
14947
15231
|
function runAsync(command, cwd, timeoutMs) {
|
|
14948
15232
|
return new Promise((resolve17, reject) => {
|
|
14949
|
-
const child =
|
|
15233
|
+
const child = spawn5(command, {
|
|
14950
15234
|
cwd,
|
|
14951
15235
|
shell: true,
|
|
14952
15236
|
windowsHide: true,
|
|
@@ -15147,7 +15431,7 @@ var init_tracker = () => {};
|
|
|
15147
15431
|
|
|
15148
15432
|
// src/modules/execution/auditor.ts
|
|
15149
15433
|
import { existsSync as existsSync27, readdirSync as readdirSync8 } from "fs";
|
|
15150
|
-
import { resolve as resolve17, join as
|
|
15434
|
+
import { resolve as resolve17, join as join22 } from "path";
|
|
15151
15435
|
function findTestFile(dir, depth = 0) {
|
|
15152
15436
|
if (depth > 5)
|
|
15153
15437
|
return null;
|
|
@@ -15158,7 +15442,7 @@ function findTestFile(dir, depth = 0) {
|
|
|
15158
15442
|
return null;
|
|
15159
15443
|
}
|
|
15160
15444
|
for (const e of entries) {
|
|
15161
|
-
const full =
|
|
15445
|
+
const full = join22(dir, e.name);
|
|
15162
15446
|
if (e.isDirectory()) {
|
|
15163
15447
|
if (SKIP_DIRS.has(e.name))
|
|
15164
15448
|
continue;
|
|
@@ -15230,10 +15514,7 @@ class Auditor {
|
|
|
15230
15514
|
}
|
|
15231
15515
|
async audit(plan) {
|
|
15232
15516
|
const allStepText = plan.steps.map((s) => s.description.replace(/\([^)]*\)/g, " ")).join(" ");
|
|
15233
|
-
const
|
|
15234
|
-
const uniqueFiles = [
|
|
15235
|
-
...new Set(fileMatches.filter((f) => !isJsMemberAccess(f)))
|
|
15236
|
-
];
|
|
15517
|
+
const uniqueFiles = extractFileLikeTokens(stripUrls(allStepText));
|
|
15237
15518
|
const missingFiles = [];
|
|
15238
15519
|
const existingFiles = [];
|
|
15239
15520
|
for (const filePath of uniqueFiles) {
|
|
@@ -15318,7 +15599,7 @@ var init_auditor = __esm(() => {
|
|
|
15318
15599
|
|
|
15319
15600
|
// src/modules/execution/plan-store.ts
|
|
15320
15601
|
import { readFileSync as readFileSync16, writeFileSync as writeFileSync9, mkdirSync as mkdirSync13, existsSync as existsSync28, readdirSync as readdirSync9, rmSync } from "fs";
|
|
15321
|
-
import { join as
|
|
15602
|
+
import { join as join23 } from "path";
|
|
15322
15603
|
function readPlanFile(path, fallbackBaseDir) {
|
|
15323
15604
|
try {
|
|
15324
15605
|
const raw = readFileSync16(path, "utf-8");
|
|
@@ -15346,7 +15627,7 @@ function listDir(dir, baseDir) {
|
|
|
15346
15627
|
if (!existsSync28(dir))
|
|
15347
15628
|
return [];
|
|
15348
15629
|
const files = readdirSync9(dir).filter((f) => f.endsWith(".json"));
|
|
15349
|
-
return files.map((f) => readPlanFile(
|
|
15630
|
+
return files.map((f) => readPlanFile(join23(dir, f), baseDir)).filter((p) => p !== null);
|
|
15350
15631
|
}
|
|
15351
15632
|
function toMeta(plan, status) {
|
|
15352
15633
|
return {
|
|
@@ -15367,21 +15648,21 @@ class PlanStore {
|
|
|
15367
15648
|
archiveDir;
|
|
15368
15649
|
legacyPath;
|
|
15369
15650
|
constructor(baseDir) {
|
|
15370
|
-
const mmaDir =
|
|
15651
|
+
const mmaDir = join23(baseDir, ".mma");
|
|
15371
15652
|
if (!existsSync28(mmaDir))
|
|
15372
15653
|
mkdirSync13(mmaDir, { recursive: true });
|
|
15373
15654
|
this.baseDir = baseDir;
|
|
15374
|
-
this.plansDir =
|
|
15375
|
-
this.draftsDir =
|
|
15376
|
-
this.archiveDir =
|
|
15377
|
-
this.legacyPath =
|
|
15655
|
+
this.plansDir = join23(mmaDir, "plans");
|
|
15656
|
+
this.draftsDir = join23(this.plansDir, "drafts");
|
|
15657
|
+
this.archiveDir = join23(this.plansDir, "archive");
|
|
15658
|
+
this.legacyPath = join23(mmaDir, LEGACY_FILE);
|
|
15378
15659
|
for (const dir of [this.plansDir, this.draftsDir, this.archiveDir]) {
|
|
15379
15660
|
if (!existsSync28(dir))
|
|
15380
15661
|
mkdirSync13(dir, { recursive: true });
|
|
15381
15662
|
}
|
|
15382
15663
|
}
|
|
15383
15664
|
activePath() {
|
|
15384
|
-
return
|
|
15665
|
+
return join23(this.plansDir, "active.json");
|
|
15385
15666
|
}
|
|
15386
15667
|
saveActive(plan) {
|
|
15387
15668
|
writePlanFile(this.activePath(), plan);
|
|
@@ -15411,14 +15692,14 @@ class PlanStore {
|
|
|
15411
15692
|
rmSync(p, { force: true });
|
|
15412
15693
|
}
|
|
15413
15694
|
saveDraft(plan) {
|
|
15414
|
-
writePlanFile(
|
|
15695
|
+
writePlanFile(join23(this.draftsDir, `${plan.id}.json`), plan);
|
|
15415
15696
|
}
|
|
15416
15697
|
loadDraft(id) {
|
|
15417
|
-
const p =
|
|
15698
|
+
const p = join23(this.draftsDir, `${id}.json`);
|
|
15418
15699
|
return existsSync28(p) ? readPlanFile(p, this.baseDir) : null;
|
|
15419
15700
|
}
|
|
15420
15701
|
removeDraft(id) {
|
|
15421
|
-
const p =
|
|
15702
|
+
const p = join23(this.draftsDir, `${id}.json`);
|
|
15422
15703
|
if (existsSync28(p))
|
|
15423
15704
|
rmSync(p, { force: true });
|
|
15424
15705
|
}
|
|
@@ -15426,7 +15707,7 @@ class PlanStore {
|
|
|
15426
15707
|
return listDir(this.draftsDir, this.baseDir);
|
|
15427
15708
|
}
|
|
15428
15709
|
archivePlan(plan) {
|
|
15429
|
-
writePlanFile(
|
|
15710
|
+
writePlanFile(join23(this.archiveDir, `${plan.id}.json`), plan);
|
|
15430
15711
|
this.removeDraft(plan.id);
|
|
15431
15712
|
const active = this.loadActive();
|
|
15432
15713
|
if (active && active.id === plan.id) {
|
|
@@ -15437,7 +15718,7 @@ class PlanStore {
|
|
|
15437
15718
|
return listDir(this.archiveDir, this.baseDir);
|
|
15438
15719
|
}
|
|
15439
15720
|
removeArchived(id) {
|
|
15440
|
-
const p =
|
|
15721
|
+
const p = join23(this.archiveDir, `${id}.json`);
|
|
15441
15722
|
if (existsSync28(p))
|
|
15442
15723
|
rmSync(p, { force: true });
|
|
15443
15724
|
}
|
|
@@ -15781,11 +16062,15 @@ ${display}`,
|
|
|
15781
16062
|
}
|
|
15782
16063
|
const status = String(args.status || "done");
|
|
15783
16064
|
if (status === "done" && target.status === "done") {
|
|
16065
|
+
const progress2 = this.tracker.getProgressString();
|
|
16066
|
+
const display2 = this.tracker.toPromptBlock();
|
|
15784
16067
|
return {
|
|
15785
|
-
success:
|
|
15786
|
-
output: t("plan.step_already_done", {
|
|
16068
|
+
success: true,
|
|
16069
|
+
output: `${t("plan.step_already_done", {
|
|
15787
16070
|
step: String(stepId)
|
|
15788
|
-
})
|
|
16071
|
+
})}
|
|
16072
|
+
${progress2}`,
|
|
16073
|
+
display: display2
|
|
15789
16074
|
};
|
|
15790
16075
|
}
|
|
15791
16076
|
if (status === "done") {
|
|
@@ -16304,7 +16589,7 @@ import {
|
|
|
16304
16589
|
readdirSync as readdirSync10,
|
|
16305
16590
|
unlinkSync as unlinkSync4
|
|
16306
16591
|
} from "fs";
|
|
16307
|
-
import { join as
|
|
16592
|
+
import { join as join24 } from "path";
|
|
16308
16593
|
import { homedir as homedir8 } from "os";
|
|
16309
16594
|
|
|
16310
16595
|
class SessionFileEncryptor {
|
|
@@ -16313,7 +16598,7 @@ class SessionFileEncryptor {
|
|
|
16313
16598
|
constructor(config) {
|
|
16314
16599
|
this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
|
|
16315
16600
|
this.encryptor = new ConfigEncryptor({
|
|
16316
|
-
keyPath: config?.keyPath ||
|
|
16601
|
+
keyPath: config?.keyPath || join24(homedir8(), ".mma", ".session-encryption-key")
|
|
16317
16602
|
});
|
|
16318
16603
|
}
|
|
16319
16604
|
isEnabled() {
|
|
@@ -16399,7 +16684,7 @@ class SessionFileEncryptor {
|
|
|
16399
16684
|
return;
|
|
16400
16685
|
const files = readdirSync10(sessionDir);
|
|
16401
16686
|
for (const file of files) {
|
|
16402
|
-
const filePath =
|
|
16687
|
+
const filePath = join24(sessionDir, file);
|
|
16403
16688
|
if (existsSync30(filePath) && !file.endsWith(".enc")) {
|
|
16404
16689
|
try {
|
|
16405
16690
|
const content = readFileSync18(filePath, "utf8");
|
|
@@ -16416,7 +16701,7 @@ class SessionFileEncryptor {
|
|
|
16416
16701
|
const files = readdirSync10(sessionDir);
|
|
16417
16702
|
for (const file of files) {
|
|
16418
16703
|
if (file.endsWith(".enc")) {
|
|
16419
|
-
const encFilePath =
|
|
16704
|
+
const encFilePath = join24(sessionDir, file);
|
|
16420
16705
|
const decFilePath = encFilePath.slice(0, -4);
|
|
16421
16706
|
try {
|
|
16422
16707
|
const content = readFileSync18(encFilePath, "utf8");
|
|
@@ -16449,7 +16734,7 @@ import {
|
|
|
16449
16734
|
writeFileSync as writeFileSync11,
|
|
16450
16735
|
appendFileSync as appendFileSync6
|
|
16451
16736
|
} from "fs";
|
|
16452
|
-
import { join as
|
|
16737
|
+
import { join as join25 } from "path";
|
|
16453
16738
|
import { gzipSync } from "zlib";
|
|
16454
16739
|
|
|
16455
16740
|
class SessionStore {
|
|
@@ -16463,7 +16748,7 @@ class SessionStore {
|
|
|
16463
16748
|
}
|
|
16464
16749
|
}
|
|
16465
16750
|
getSessionDir(id) {
|
|
16466
|
-
return
|
|
16751
|
+
return join25(this.baseDir, id);
|
|
16467
16752
|
}
|
|
16468
16753
|
updateEncryption(config) {
|
|
16469
16754
|
if (config?.enabled) {
|
|
@@ -16479,16 +16764,16 @@ class SessionStore {
|
|
|
16479
16764
|
mkdirSync14(this.baseDir, { recursive: true });
|
|
16480
16765
|
}
|
|
16481
16766
|
sessionDir(id) {
|
|
16482
|
-
return
|
|
16767
|
+
return join25(this.baseDir, id);
|
|
16483
16768
|
}
|
|
16484
16769
|
metaPath(id) {
|
|
16485
|
-
return
|
|
16770
|
+
return join25(this.sessionDir(id), "meta.json");
|
|
16486
16771
|
}
|
|
16487
16772
|
historyPath(id) {
|
|
16488
|
-
return
|
|
16773
|
+
return join25(this.sessionDir(id), "history.jsonl");
|
|
16489
16774
|
}
|
|
16490
16775
|
sessionLogPath(id) {
|
|
16491
|
-
return
|
|
16776
|
+
return join25(this.sessionDir(id), "session.jsonl");
|
|
16492
16777
|
}
|
|
16493
16778
|
sessionExists(id) {
|
|
16494
16779
|
return existsSync31(this.metaPath(id));
|
|
@@ -16642,7 +16927,7 @@ class SessionStore {
|
|
|
16642
16927
|
if (existsSync31(historyPath)) {
|
|
16643
16928
|
const content = readFileSync19(historyPath, "utf-8");
|
|
16644
16929
|
const compressed = gzipSync(content);
|
|
16645
|
-
const gzPath =
|
|
16930
|
+
const gzPath = join25(this.baseDir, `${session2.id}.jsonl.gz`);
|
|
16646
16931
|
writeFileSync11(gzPath, compressed);
|
|
16647
16932
|
rmSync2(historyPath);
|
|
16648
16933
|
}
|
|
@@ -16853,7 +17138,7 @@ class ProfileCompressor {
|
|
|
16853
17138
|
|
|
16854
17139
|
// src/modules/user-profile/profile.ts
|
|
16855
17140
|
import { readFileSync as readFileSync20, writeFileSync as writeFileSync12, existsSync as existsSync32, mkdirSync as mkdirSync15 } from "fs";
|
|
16856
|
-
import { join as
|
|
17141
|
+
import { join as join26 } from "path";
|
|
16857
17142
|
import { homedir as homedir9, hostname, platform as platform4, type } from "os";
|
|
16858
17143
|
import { env } from "process";
|
|
16859
17144
|
|
|
@@ -16880,10 +17165,10 @@ class UserProfile {
|
|
|
16880
17165
|
if (!existsSync32(this.profileDir)) {
|
|
16881
17166
|
mkdirSync15(this.profileDir, { recursive: true });
|
|
16882
17167
|
}
|
|
16883
|
-
writeFileSync12(
|
|
17168
|
+
writeFileSync12(join26(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
|
|
16884
17169
|
}
|
|
16885
17170
|
load() {
|
|
16886
|
-
const path =
|
|
17171
|
+
const path = join26(this.profileDir, "profile.json");
|
|
16887
17172
|
if (!existsSync32(path))
|
|
16888
17173
|
return null;
|
|
16889
17174
|
try {
|
|
@@ -16923,7 +17208,7 @@ var init_profile = () => {};
|
|
|
16923
17208
|
|
|
16924
17209
|
// src/modules/skills/loader.ts
|
|
16925
17210
|
import { readdirSync as readdirSync12, readFileSync as readFileSync21, existsSync as existsSync33, statSync as statSync6 } from "fs";
|
|
16926
|
-
import { join as
|
|
17211
|
+
import { join as join27 } from "path";
|
|
16927
17212
|
|
|
16928
17213
|
class SkillsLoader {
|
|
16929
17214
|
loadFromDir(dirPath) {
|
|
@@ -16936,7 +17221,7 @@ class SkillsLoader {
|
|
|
16936
17221
|
scanDir(dirPath, skills) {
|
|
16937
17222
|
const entries = readdirSync12(dirPath);
|
|
16938
17223
|
for (const entry of entries) {
|
|
16939
|
-
const fullPath =
|
|
17224
|
+
const fullPath = join27(dirPath, entry);
|
|
16940
17225
|
const stat = statSync6(fullPath);
|
|
16941
17226
|
if (stat.isDirectory()) {
|
|
16942
17227
|
this.scanDir(fullPath, skills);
|
|
@@ -17173,12 +17458,14 @@ var init_browser2 = __esm(() => {
|
|
|
17173
17458
|
init_module4();
|
|
17174
17459
|
init_session();
|
|
17175
17460
|
init_cookie_store();
|
|
17461
|
+
init_driver();
|
|
17462
|
+
init_bridge_client();
|
|
17176
17463
|
init_snapshot();
|
|
17177
17464
|
init_types();
|
|
17178
17465
|
});
|
|
17179
17466
|
|
|
17180
17467
|
// src/modules/lsp/client.ts
|
|
17181
|
-
import { spawn as
|
|
17468
|
+
import { spawn as spawn6, execSync as execSync2 } from "child_process";
|
|
17182
17469
|
import { resolve as resolve19 } from "path";
|
|
17183
17470
|
|
|
17184
17471
|
class LspClient {
|
|
@@ -17242,7 +17529,7 @@ class LspClient {
|
|
|
17242
17529
|
}
|
|
17243
17530
|
return new Promise((resolve20, reject) => {
|
|
17244
17531
|
const args = config.args ?? [];
|
|
17245
|
-
const proc =
|
|
17532
|
+
const proc = spawn6(config.command, args, {
|
|
17246
17533
|
stdio: ["pipe", "pipe", "pipe"],
|
|
17247
17534
|
env: { ...process.env, ...config.env },
|
|
17248
17535
|
cwd: baseDir
|
|
@@ -17503,7 +17790,7 @@ var init_lsp = __esm(() => {
|
|
|
17503
17790
|
|
|
17504
17791
|
// src/modules/indexer/walker.ts
|
|
17505
17792
|
import { readdirSync as readdirSync13, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync35, watch } from "fs";
|
|
17506
|
-
import { join as
|
|
17793
|
+
import { join as join28, relative as relative2, extname as extname5 } from "path";
|
|
17507
17794
|
|
|
17508
17795
|
class Indexer {
|
|
17509
17796
|
baseDir;
|
|
@@ -17541,7 +17828,7 @@ class Indexer {
|
|
|
17541
17828
|
for (const entry of entries) {
|
|
17542
17829
|
if (count >= this.MAX_FILES)
|
|
17543
17830
|
return;
|
|
17544
|
-
const fullPath =
|
|
17831
|
+
const fullPath = join28(dir, entry);
|
|
17545
17832
|
const relPath = relative2(this.baseDir, fullPath);
|
|
17546
17833
|
const stat = statSync7(fullPath);
|
|
17547
17834
|
if (stat.isDirectory()) {
|
|
@@ -17605,13 +17892,13 @@ var init_walker = __esm(() => {
|
|
|
17605
17892
|
|
|
17606
17893
|
// src/modules/indexer/cache.ts
|
|
17607
17894
|
import { readFileSync as readFileSync23, writeFileSync as writeFileSync13, existsSync as existsSync36, mkdirSync as mkdirSync16, rmSync as rmSync3 } from "fs";
|
|
17608
|
-
import { join as
|
|
17895
|
+
import { join as join29 } from "path";
|
|
17609
17896
|
|
|
17610
17897
|
class IndexCache {
|
|
17611
17898
|
cachePath;
|
|
17612
17899
|
cache = null;
|
|
17613
17900
|
constructor(cacheDir) {
|
|
17614
|
-
this.cachePath =
|
|
17901
|
+
this.cachePath = join29(cacheDir, "index-cache.json");
|
|
17615
17902
|
}
|
|
17616
17903
|
load() {
|
|
17617
17904
|
if (this.cache)
|
|
@@ -17627,7 +17914,7 @@ class IndexCache {
|
|
|
17627
17914
|
}
|
|
17628
17915
|
save(result) {
|
|
17629
17916
|
this.cache = result;
|
|
17630
|
-
const dir =
|
|
17917
|
+
const dir = join29(this.cachePath, "..");
|
|
17631
17918
|
if (!existsSync36(dir))
|
|
17632
17919
|
mkdirSync16(dir, { recursive: true });
|
|
17633
17920
|
writeFileSync13(this.cachePath, JSON.stringify(result), "utf-8");
|
|
@@ -17644,7 +17931,7 @@ class IndexCache {
|
|
|
17644
17931
|
var init_cache = () => {};
|
|
17645
17932
|
|
|
17646
17933
|
// src/modules/indexer/module.ts
|
|
17647
|
-
import { dirname as
|
|
17934
|
+
import { dirname as dirname8 } from "path";
|
|
17648
17935
|
|
|
17649
17936
|
class IndexerModule {
|
|
17650
17937
|
name = "indexer";
|
|
@@ -17761,7 +18048,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
|
|
|
17761
18048
|
const counts = {};
|
|
17762
18049
|
for (const f of result.files) {
|
|
17763
18050
|
const normalized = f.path.replace(/\\/g, "/");
|
|
17764
|
-
const dir =
|
|
18051
|
+
const dir = dirname8(normalized);
|
|
17765
18052
|
const key = dir === "." ? "(root)" : dir;
|
|
17766
18053
|
counts[key] = (counts[key] || 0) + 1;
|
|
17767
18054
|
}
|
|
@@ -17992,13 +18279,13 @@ var init_mcp = __esm(() => {
|
|
|
17992
18279
|
|
|
17993
18280
|
// src/modules/memory/module.ts
|
|
17994
18281
|
import { homedir as homedir10 } from "os";
|
|
17995
|
-
import { join as
|
|
18282
|
+
import { join as join30 } from "path";
|
|
17996
18283
|
|
|
17997
18284
|
class MemoryModule {
|
|
17998
18285
|
name = "memory";
|
|
17999
18286
|
store;
|
|
18000
18287
|
constructor(memoryDir) {
|
|
18001
|
-
const dir = memoryDir ||
|
|
18288
|
+
const dir = memoryDir || join30(homedir10(), ".mma", "memory");
|
|
18002
18289
|
this.store = new MemoryStore(dir);
|
|
18003
18290
|
}
|
|
18004
18291
|
getSystemPromptBlock() {
|
|
@@ -18046,7 +18333,7 @@ __export(exports_bootstrap, {
|
|
|
18046
18333
|
bootstrap: () => bootstrap
|
|
18047
18334
|
});
|
|
18048
18335
|
import { homedir as homedir11 } from "os";
|
|
18049
|
-
import { join as
|
|
18336
|
+
import { join as join31, resolve as resolve21 } from "path";
|
|
18050
18337
|
import { existsSync as existsSync37, readFileSync as readFileSync24, writeFileSync as writeFileSync14 } from "fs";
|
|
18051
18338
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
18052
18339
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
@@ -18072,8 +18359,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
18072
18359
|
`);
|
|
18073
18360
|
}
|
|
18074
18361
|
async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
18075
|
-
const dir = configDir ||
|
|
18076
|
-
const projectConfigPath = projectDir ?
|
|
18362
|
+
const dir = configDir || join31(homedir11(), ".mma");
|
|
18363
|
+
const projectConfigPath = projectDir ? join31(projectDir, ".mmrc") : join31(process.cwd(), ".mmrc");
|
|
18077
18364
|
const config = loadConfig({ configDir: dir, projectConfigPath });
|
|
18078
18365
|
setLocale(config.locale);
|
|
18079
18366
|
try {
|
|
@@ -18083,7 +18370,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
18083
18370
|
}
|
|
18084
18371
|
} catch {}
|
|
18085
18372
|
const logger = new Logger(config.logLevel);
|
|
18086
|
-
logger.setLogDir(
|
|
18373
|
+
logger.setLogDir(join31(dir, "logs"));
|
|
18087
18374
|
logger.debug("MMA bootstrap", {
|
|
18088
18375
|
version: config.version,
|
|
18089
18376
|
model: config.model
|
|
@@ -18105,7 +18392,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
18105
18392
|
logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
|
|
18106
18393
|
}
|
|
18107
18394
|
}
|
|
18108
|
-
const profile = new UserProfile(
|
|
18395
|
+
const profile = new UserProfile(join31(dir));
|
|
18109
18396
|
profile.load() || profile.collect();
|
|
18110
18397
|
profile.save();
|
|
18111
18398
|
const llmProvider = new OpenAICompatProvider({
|
|
@@ -18117,7 +18404,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
18117
18404
|
rateLimits: config.security?.rateLimits
|
|
18118
18405
|
});
|
|
18119
18406
|
const baseDir = projectDir ? resolve21(projectDir) : process.cwd();
|
|
18120
|
-
const projectMapCacheDir =
|
|
18407
|
+
const projectMapCacheDir = join31(baseDir, ".mma");
|
|
18121
18408
|
const indexerModule = new IndexerModule({
|
|
18122
18409
|
baseDir,
|
|
18123
18410
|
cacheDir: projectMapCacheDir
|
|
@@ -18128,9 +18415,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
18128
18415
|
logger.warn(`Project indexing failed: ${err.message}`);
|
|
18129
18416
|
}
|
|
18130
18417
|
const skillsLoader = new SkillsLoader;
|
|
18131
|
-
const builtinDir =
|
|
18132
|
-
const globalDir =
|
|
18133
|
-
const projectSkillsDir =
|
|
18418
|
+
const builtinDir = join31(import.meta.dirname, "skills", "builtin");
|
|
18419
|
+
const globalDir = join31(homedir11(), ".agents", "skills");
|
|
18420
|
+
const projectSkillsDir = join31(baseDir, ".mma", "skills");
|
|
18134
18421
|
const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
|
|
18135
18422
|
const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
|
|
18136
18423
|
const skillsModule = new SkillsModule(availableSkills, skillsBudget);
|
|
@@ -18144,11 +18431,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
18144
18431
|
essential: true,
|
|
18145
18432
|
estimatedTokens: Math.ceil(systemInfoContent.length / 4)
|
|
18146
18433
|
};
|
|
18147
|
-
const agentsMdGlobal =
|
|
18434
|
+
const agentsMdGlobal = join31(dir, "AGENTS.md");
|
|
18148
18435
|
if (!existsSync37(agentsMdGlobal)) {
|
|
18149
18436
|
writeFileSync14(agentsMdGlobal, "", "utf-8");
|
|
18150
18437
|
}
|
|
18151
|
-
const sessionDir =
|
|
18438
|
+
const sessionDir = join31(dir, "sessions");
|
|
18152
18439
|
const sessionStore = new SessionStore(sessionDir);
|
|
18153
18440
|
sessionStore.init();
|
|
18154
18441
|
const sessionManager = new SessionManager(sessionStore, {
|
|
@@ -18215,7 +18502,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
18215
18502
|
const mcpModule = new MCPModule(config);
|
|
18216
18503
|
await mcpModule.initialize();
|
|
18217
18504
|
moduleRegistry.register(mcpModule);
|
|
18218
|
-
const memoryModule = new MemoryModule(
|
|
18505
|
+
const memoryModule = new MemoryModule(join31(dir, "memory"));
|
|
18219
18506
|
moduleRegistry.register(memoryModule);
|
|
18220
18507
|
if (config.browser.enabled) {
|
|
18221
18508
|
const browserModule = new BrowserModule;
|
|
@@ -18265,8 +18552,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
18265
18552
|
pluginManager.register(plugin);
|
|
18266
18553
|
pluginManager.register(plugin2);
|
|
18267
18554
|
const pluginLoader = new PluginLoader;
|
|
18268
|
-
const globalPluginsDir =
|
|
18269
|
-
const projectPluginsDir =
|
|
18555
|
+
const globalPluginsDir = join31(homedir11(), ".mma", "plugins");
|
|
18556
|
+
const projectPluginsDir = join31(baseDir, ".mma", "plugins");
|
|
18270
18557
|
pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
|
|
18271
18558
|
pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
|
|
18272
18559
|
contextManager.onCompact = (summary) => {
|
|
@@ -18284,9 +18571,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
18284
18571
|
const skipAgentsMd = noAgentsMd === true;
|
|
18285
18572
|
if (!skipAgentsMd) {
|
|
18286
18573
|
const agentsMdCandidates = [
|
|
18287
|
-
|
|
18288
|
-
|
|
18289
|
-
|
|
18574
|
+
join31(baseDir, "AGENTS.md"),
|
|
18575
|
+
join31(baseDir, ".mma", "AGENTS.md"),
|
|
18576
|
+
join31(dir, "AGENTS.md")
|
|
18290
18577
|
];
|
|
18291
18578
|
for (const p of agentsMdCandidates) {
|
|
18292
18579
|
if (existsSync37(p)) {
|
|
@@ -19043,7 +19330,7 @@ async function runSetup(externalRl) {
|
|
|
19043
19330
|
const idx = Math.max(0, Math.min(models.length - 1, (parseInt(choice) || 1) - 1));
|
|
19044
19331
|
model = models[idx];
|
|
19045
19332
|
} else {
|
|
19046
|
-
model = await ask(rl, t("setup.model_name"), "qwen3.5-9b");
|
|
19333
|
+
model = await ask(rl, t("setup.model_name"), "qwen/qwen3.5-9b");
|
|
19047
19334
|
}
|
|
19048
19335
|
const connected = await withSpinner(t("setup.testing_spinner", { model }), () => testChat(apiBase, apiKey, model));
|
|
19049
19336
|
if (connected) {
|
|
@@ -19141,7 +19428,7 @@ __export(exports_manifest, {
|
|
|
19141
19428
|
});
|
|
19142
19429
|
import { existsSync as existsSync38, readFileSync as readFileSync25, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
|
|
19143
19430
|
import { homedir as homedir13 } from "os";
|
|
19144
|
-
import { join as
|
|
19431
|
+
import { join as join33 } from "path";
|
|
19145
19432
|
function readManifest(path = MANIFEST_PATH) {
|
|
19146
19433
|
try {
|
|
19147
19434
|
if (existsSync38(path)) {
|
|
@@ -19152,7 +19439,7 @@ function readManifest(path = MANIFEST_PATH) {
|
|
|
19152
19439
|
return { version: 1, certifications: [] };
|
|
19153
19440
|
}
|
|
19154
19441
|
function saveManifest(m, path = MANIFEST_PATH) {
|
|
19155
|
-
mkdirSync17(
|
|
19442
|
+
mkdirSync17(join33(homedir13(), ".mma"), { recursive: true });
|
|
19156
19443
|
writeFileSync15(path, JSON.stringify(m, null, 2), "utf-8");
|
|
19157
19444
|
}
|
|
19158
19445
|
function upsertCertification(entry, path = MANIFEST_PATH) {
|
|
@@ -19187,7 +19474,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
|
|
|
19187
19474
|
}
|
|
19188
19475
|
var MANIFEST_PATH;
|
|
19189
19476
|
var init_manifest = __esm(() => {
|
|
19190
|
-
MANIFEST_PATH =
|
|
19477
|
+
MANIFEST_PATH = join33(homedir13(), ".mma", "certifications.json");
|
|
19191
19478
|
});
|
|
19192
19479
|
|
|
19193
19480
|
// node_modules/yaml/dist/nodes/identity.js
|
|
@@ -26311,7 +26598,7 @@ var init_scenarios = __esm(() => {
|
|
|
26311
26598
|
|
|
26312
26599
|
// src/modules/certification/loader.ts
|
|
26313
26600
|
import { existsSync as existsSync39, readdirSync as readdirSync14, readFileSync as readFileSync26 } from "fs";
|
|
26314
|
-
import { join as
|
|
26601
|
+
import { join as join34 } from "path";
|
|
26315
26602
|
function validateScenario(s) {
|
|
26316
26603
|
const errors2 = [];
|
|
26317
26604
|
const isSkip = s.mode === "skip";
|
|
@@ -26365,7 +26652,7 @@ function loadScenarios(userDir) {
|
|
|
26365
26652
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
|
|
26366
26653
|
continue;
|
|
26367
26654
|
try {
|
|
26368
|
-
const raw = readFileSync26(
|
|
26655
|
+
const raw = readFileSync26(join34(userDir, file), "utf-8");
|
|
26369
26656
|
const data = $parse(raw);
|
|
26370
26657
|
const parsed = normalizeScenario(data, file);
|
|
26371
26658
|
const errs = validateScenario(parsed);
|
|
@@ -26419,7 +26706,7 @@ var init_loader3 = __esm(() => {
|
|
|
26419
26706
|
|
|
26420
26707
|
// src/modules/certification/fact-checker.ts
|
|
26421
26708
|
import { existsSync as existsSync40, readFileSync as readFileSync27, statSync as statSync8 } from "fs";
|
|
26422
|
-
import { join as
|
|
26709
|
+
import { join as join35 } from "path";
|
|
26423
26710
|
function checkSandbox(sandboxDir, checks, exitCode, output) {
|
|
26424
26711
|
const failures = [];
|
|
26425
26712
|
for (const check of checks) {
|
|
@@ -26436,13 +26723,13 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
26436
26723
|
case "outputContains":
|
|
26437
26724
|
return output.includes(check.text);
|
|
26438
26725
|
case "fileExists":
|
|
26439
|
-
return isFile(
|
|
26726
|
+
return isFile(join35(sandboxDir, check.path));
|
|
26440
26727
|
case "fileNotExists":
|
|
26441
|
-
return !existsSync40(
|
|
26728
|
+
return !existsSync40(join35(sandboxDir, check.path));
|
|
26442
26729
|
case "dirExists":
|
|
26443
|
-
return isDir(
|
|
26730
|
+
return isDir(join35(sandboxDir, check.path));
|
|
26444
26731
|
case "fileContent": {
|
|
26445
|
-
const abs =
|
|
26732
|
+
const abs = join35(sandboxDir, check.path);
|
|
26446
26733
|
if (!isFile(abs))
|
|
26447
26734
|
return false;
|
|
26448
26735
|
const content = readFileSync27(abs, "utf-8");
|
|
@@ -26453,7 +26740,7 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
26453
26740
|
return false;
|
|
26454
26741
|
}
|
|
26455
26742
|
case "fileRegex": {
|
|
26456
|
-
const abs =
|
|
26743
|
+
const abs = join35(sandboxDir, check.path);
|
|
26457
26744
|
if (!isFile(abs))
|
|
26458
26745
|
return false;
|
|
26459
26746
|
return new RegExp(check.pattern).test(readFileSync27(abs, "utf-8"));
|
|
@@ -26501,10 +26788,10 @@ function describe(check) {
|
|
|
26501
26788
|
var init_fact_checker = () => {};
|
|
26502
26789
|
|
|
26503
26790
|
// src/modules/certification/runner.ts
|
|
26504
|
-
import { spawn as
|
|
26791
|
+
import { spawn as spawn7 } from "child_process";
|
|
26505
26792
|
import { existsSync as existsSync41, mkdirSync as mkdirSync18, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
|
|
26506
26793
|
import { platform as platform5 } from "os";
|
|
26507
|
-
import { join as
|
|
26794
|
+
import { join as join36, resolve as resolve22, dirname as dirname9 } from "path";
|
|
26508
26795
|
async function runScenario(scenario, opts) {
|
|
26509
26796
|
if (scenario.mode === "skip") {
|
|
26510
26797
|
return {
|
|
@@ -26523,7 +26810,7 @@ async function runScenario(scenario, opts) {
|
|
|
26523
26810
|
let passed = 0;
|
|
26524
26811
|
let firstError;
|
|
26525
26812
|
for (let i = 1;i <= reps; i++) {
|
|
26526
|
-
const sandbox =
|
|
26813
|
+
const sandbox = join36(opts.sandboxBase, `run-${scenario.id}-${i}`);
|
|
26527
26814
|
let failures = [];
|
|
26528
26815
|
let exitCode = -1;
|
|
26529
26816
|
let output = "";
|
|
@@ -26584,20 +26871,20 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
|
|
|
26584
26871
|
rmSync4(sandbox, { recursive: true, force: true });
|
|
26585
26872
|
mkdirSync18(sandbox, { recursive: true });
|
|
26586
26873
|
for (const f of scenario.fixtures ?? []) {
|
|
26587
|
-
const src =
|
|
26874
|
+
const src = join36(mmaRoot, f.source);
|
|
26588
26875
|
if (!existsSync41(src)) {
|
|
26589
26876
|
throw new Error(`fixture missing: ${f.source}`);
|
|
26590
26877
|
}
|
|
26591
|
-
const dest =
|
|
26592
|
-
mkdirSync18(
|
|
26878
|
+
const dest = join36(sandbox, f.dest);
|
|
26879
|
+
mkdirSync18(dirname9(dest), { recursive: true });
|
|
26593
26880
|
cpSync2(src, dest);
|
|
26594
26881
|
}
|
|
26595
26882
|
}
|
|
26596
26883
|
function resolveMmaEntry(mmaRoot) {
|
|
26597
|
-
const dev =
|
|
26884
|
+
const dev = join36(mmaRoot, "src", "cli", "main.ts");
|
|
26598
26885
|
if (existsSync41(dev))
|
|
26599
26886
|
return dev;
|
|
26600
|
-
return
|
|
26887
|
+
return join36(mmaRoot, "dist", "main.js");
|
|
26601
26888
|
}
|
|
26602
26889
|
function findMmaRoot(fromDir) {
|
|
26603
26890
|
const candidates = [
|
|
@@ -26605,7 +26892,7 @@ function findMmaRoot(fromDir) {
|
|
|
26605
26892
|
resolve22(fromDir, "..")
|
|
26606
26893
|
];
|
|
26607
26894
|
for (const c of candidates) {
|
|
26608
|
-
if (existsSync41(
|
|
26895
|
+
if (existsSync41(join36(c, "package.json")))
|
|
26609
26896
|
return c;
|
|
26610
26897
|
}
|
|
26611
26898
|
return process.cwd();
|
|
@@ -26615,7 +26902,7 @@ function killTree2(child) {
|
|
|
26615
26902
|
if (!pid)
|
|
26616
26903
|
return;
|
|
26617
26904
|
if (platform5() === "win32") {
|
|
26618
|
-
|
|
26905
|
+
spawn7("taskkill", ["/pid", String(pid), "/T", "/F"], {
|
|
26619
26906
|
windowsHide: true,
|
|
26620
26907
|
stdio: "ignore"
|
|
26621
26908
|
});
|
|
@@ -26630,7 +26917,7 @@ function killTree2(child) {
|
|
|
26630
26917
|
}
|
|
26631
26918
|
}
|
|
26632
26919
|
var defaultRunner = (env2, cwd, args, timeoutMs) => new Promise((resolvePromise) => {
|
|
26633
|
-
const child =
|
|
26920
|
+
const child = spawn7(process.execPath, args, {
|
|
26634
26921
|
cwd,
|
|
26635
26922
|
env: env2,
|
|
26636
26923
|
windowsHide: true,
|
|
@@ -26673,11 +26960,11 @@ __export(exports_cli, {
|
|
|
26673
26960
|
});
|
|
26674
26961
|
import { rmSync as rmSync5 } from "fs";
|
|
26675
26962
|
import { homedir as homedir14 } from "os";
|
|
26676
|
-
import { join as
|
|
26677
|
-
import { fileURLToPath } from "url";
|
|
26963
|
+
import { join as join37, dirname as dirname10 } from "path";
|
|
26964
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
26678
26965
|
import { existsSync as existsSync42, readFileSync as readFileSync28 } from "fs";
|
|
26679
26966
|
function readVersion() {
|
|
26680
|
-
const candidates = [
|
|
26967
|
+
const candidates = [join37(MMA_ROOT, "package.json")];
|
|
26681
26968
|
for (const p of candidates) {
|
|
26682
26969
|
if (existsSync42(p)) {
|
|
26683
26970
|
try {
|
|
@@ -26717,7 +27004,7 @@ async function certify(opts) {
|
|
|
26717
27004
|
return;
|
|
26718
27005
|
}
|
|
26719
27006
|
console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
|
|
26720
|
-
const sandboxBase =
|
|
27007
|
+
const sandboxBase = join37(process.cwd(), ".mma", "certification");
|
|
26721
27008
|
const results = [];
|
|
26722
27009
|
const total = selected.length;
|
|
26723
27010
|
let idx = 0;
|
|
@@ -26829,9 +27116,9 @@ var init_cli = __esm(() => {
|
|
|
26829
27116
|
init_loader3();
|
|
26830
27117
|
init_runner2();
|
|
26831
27118
|
init_manifest();
|
|
26832
|
-
HERE =
|
|
27119
|
+
HERE = dirname10(fileURLToPath2(import.meta.url));
|
|
26833
27120
|
MMA_ROOT = findMmaRoot(HERE);
|
|
26834
|
-
USER_SCENARIO_DIR =
|
|
27121
|
+
USER_SCENARIO_DIR = join37(homedir14(), ".mma", "certification", "scenarios");
|
|
26835
27122
|
});
|
|
26836
27123
|
|
|
26837
27124
|
// src/cli/repl-commands.ts
|
|
@@ -26840,15 +27127,15 @@ __export(exports_repl_commands, {
|
|
|
26840
27127
|
registerAllCommands: () => registerAllCommands,
|
|
26841
27128
|
COMMAND_GROUPS: () => COMMAND_GROUPS
|
|
26842
27129
|
});
|
|
26843
|
-
import { join as
|
|
27130
|
+
import { join as join39, dirname as dirname12 } from "path";
|
|
26844
27131
|
import { homedir as homedir16 } from "os";
|
|
26845
27132
|
import { existsSync as existsSync44, readFileSync as readFileSync30 } from "fs";
|
|
26846
|
-
import { fileURLToPath as
|
|
27133
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
26847
27134
|
function readVersion3() {
|
|
26848
|
-
const here =
|
|
27135
|
+
const here = dirname12(fileURLToPath4(import.meta.url));
|
|
26849
27136
|
const candidates = [
|
|
26850
|
-
|
|
26851
|
-
|
|
27137
|
+
join39(here, "..", "..", "package.json"),
|
|
27138
|
+
join39(here, "..", "package.json")
|
|
26852
27139
|
];
|
|
26853
27140
|
for (const p of candidates) {
|
|
26854
27141
|
if (existsSync44(p)) {
|
|
@@ -27016,7 +27303,7 @@ function registerMmaCommands(ctx) {
|
|
|
27016
27303
|
console.log(pc2.yellow(t("repl.wizard_running")));
|
|
27017
27304
|
await ctx.withExclusiveInput(async () => {
|
|
27018
27305
|
const answers = await runSetup(ctx.rl);
|
|
27019
|
-
const configPath =
|
|
27306
|
+
const configPath = join39(homedir16(), ".mma", "config.json");
|
|
27020
27307
|
ctx.config.provider.type = answers.provider;
|
|
27021
27308
|
ctx.config.provider.baseUrl = answers.apiBase;
|
|
27022
27309
|
ctx.config.provider.apiKey = answers.apiKey;
|
|
@@ -27070,7 +27357,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
27070
27357
|
return;
|
|
27071
27358
|
}
|
|
27072
27359
|
ctx.config.provider.type = name;
|
|
27073
|
-
const configPath =
|
|
27360
|
+
const configPath = join39(homedir16(), ".mma", "config.json");
|
|
27074
27361
|
saveConfig(ctx.config, configPath);
|
|
27075
27362
|
await ctx.agent.reconfigure(ctx.config);
|
|
27076
27363
|
console.log(pc2.green(t("repl.provider_set", { name })));
|
|
@@ -27126,7 +27413,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
27126
27413
|
return;
|
|
27127
27414
|
}
|
|
27128
27415
|
ctx.config.model = name;
|
|
27129
|
-
const configPath =
|
|
27416
|
+
const configPath = join39(homedir16(), ".mma", "config.json");
|
|
27130
27417
|
saveConfig(ctx.config, configPath);
|
|
27131
27418
|
await ctx.agent.reconfigure(ctx.config);
|
|
27132
27419
|
console.log(pc2.green(t("repl.model_set", { name })));
|
|
@@ -27151,7 +27438,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
27151
27438
|
return;
|
|
27152
27439
|
}
|
|
27153
27440
|
ctx.config.contextWindow = size;
|
|
27154
|
-
const configPath =
|
|
27441
|
+
const configPath = join39(homedir16(), ".mma", "config.json");
|
|
27155
27442
|
saveConfig(ctx.config, configPath);
|
|
27156
27443
|
await ctx.agent.reconfigure(ctx.config);
|
|
27157
27444
|
console.log(pc2.green(t("cli.context_set", { size })));
|
|
@@ -27170,10 +27457,10 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
27170
27457
|
ctx.agent.shutdown();
|
|
27171
27458
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
|
|
27172
27459
|
const { homedir: homedir17 } = await import("os");
|
|
27173
|
-
const { join:
|
|
27460
|
+
const { join: join40 } = await import("path");
|
|
27174
27461
|
const configDir = ctx.configDir;
|
|
27175
27462
|
const baseDir = ctx.baseDir;
|
|
27176
|
-
const projectConfigPath =
|
|
27463
|
+
const projectConfigPath = join40(baseDir, ".mmrc");
|
|
27177
27464
|
const freshConfig = loadConfig2({ configDir, projectConfigPath });
|
|
27178
27465
|
Object.assign(ctx.config, freshConfig);
|
|
27179
27466
|
const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
|
|
@@ -27473,14 +27760,14 @@ init_bootstrap();
|
|
|
27473
27760
|
init_config2();
|
|
27474
27761
|
init_setup();
|
|
27475
27762
|
init_i18n();
|
|
27476
|
-
import { join as
|
|
27763
|
+
import { join as join38, dirname as dirname11 } from "path";
|
|
27477
27764
|
import { homedir as homedir15 } from "os";
|
|
27478
27765
|
import { existsSync as existsSync43, readFileSync as readFileSync29 } from "fs";
|
|
27479
27766
|
|
|
27480
27767
|
// src/cli/security-commands.ts
|
|
27481
27768
|
init_bootstrap();
|
|
27482
27769
|
init_config2();
|
|
27483
|
-
import { join as
|
|
27770
|
+
import { join as join32 } from "path";
|
|
27484
27771
|
import { homedir as homedir12 } from "os";
|
|
27485
27772
|
|
|
27486
27773
|
// src/modules/security/security-policies.ts
|
|
@@ -28010,7 +28297,7 @@ function createSecurityCommand(program2) {
|
|
|
28010
28297
|
}
|
|
28011
28298
|
});
|
|
28012
28299
|
securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
|
|
28013
|
-
const configPath =
|
|
28300
|
+
const configPath = join32(homedir12(), ".mma", "config.json");
|
|
28014
28301
|
const { config: appConfig } = await bootstrap();
|
|
28015
28302
|
const validPresets = ["strict", "balanced", "permissive"];
|
|
28016
28303
|
if (!validPresets.includes(preset)) {
|
|
@@ -28025,7 +28312,7 @@ function createSecurityCommand(program2) {
|
|
|
28025
28312
|
console.log(t("cli.security.policy_description", { description: policy.description }));
|
|
28026
28313
|
});
|
|
28027
28314
|
securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
|
|
28028
|
-
const configPath =
|
|
28315
|
+
const configPath = join32(homedir12(), ".mma", "config.json");
|
|
28029
28316
|
const { config: appConfig } = await bootstrap();
|
|
28030
28317
|
appConfig.security = appConfig.security || {};
|
|
28031
28318
|
appConfig.security.sessionEncryption = {
|
|
@@ -28037,7 +28324,7 @@ function createSecurityCommand(program2) {
|
|
|
28037
28324
|
console.log(t("cli.security.encryption_enabled"));
|
|
28038
28325
|
});
|
|
28039
28326
|
securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
|
|
28040
|
-
const configPath =
|
|
28327
|
+
const configPath = join32(homedir12(), ".mma", "config.json");
|
|
28041
28328
|
const { config: appConfig } = await bootstrap();
|
|
28042
28329
|
appConfig.security = appConfig.security || {};
|
|
28043
28330
|
appConfig.security.sessionEncryption = {
|
|
@@ -28049,7 +28336,7 @@ function createSecurityCommand(program2) {
|
|
|
28049
28336
|
console.log(t("cli.security.encryption_disabled"));
|
|
28050
28337
|
});
|
|
28051
28338
|
securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
|
|
28052
|
-
const configPath =
|
|
28339
|
+
const configPath = join32(homedir12(), ".mma", "config.json");
|
|
28053
28340
|
const { config: appConfig } = await bootstrap();
|
|
28054
28341
|
appConfig.security = appConfig.security || {};
|
|
28055
28342
|
appConfig.security.auditNotifier = {
|
|
@@ -28063,7 +28350,7 @@ function createSecurityCommand(program2) {
|
|
|
28063
28350
|
console.log(t("cli.security.audit_enabled"));
|
|
28064
28351
|
});
|
|
28065
28352
|
securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
|
|
28066
|
-
const configPath =
|
|
28353
|
+
const configPath = join32(homedir12(), ".mma", "config.json");
|
|
28067
28354
|
const { config: appConfig } = await bootstrap();
|
|
28068
28355
|
appConfig.security = appConfig.security || {};
|
|
28069
28356
|
appConfig.security.auditNotifier = {
|
|
@@ -28095,12 +28382,12 @@ function createSecurityCommand(program2) {
|
|
|
28095
28382
|
}
|
|
28096
28383
|
|
|
28097
28384
|
// src/cli/commands.ts
|
|
28098
|
-
import { fileURLToPath as
|
|
28385
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
28099
28386
|
function readVersion2() {
|
|
28100
|
-
const here =
|
|
28387
|
+
const here = dirname11(fileURLToPath3(import.meta.url));
|
|
28101
28388
|
const candidates = [
|
|
28102
|
-
|
|
28103
|
-
|
|
28389
|
+
join38(here, "..", "..", "package.json"),
|
|
28390
|
+
join38(here, "..", "package.json")
|
|
28104
28391
|
];
|
|
28105
28392
|
for (const p of candidates) {
|
|
28106
28393
|
if (existsSync43(p)) {
|
|
@@ -28118,7 +28405,7 @@ function createProgram() {
|
|
|
28118
28405
|
const program2 = new Command().name("mma").description(t("cli.description")).version(version).option("--no-agents-md", t("cli.no_agents_md")).option("-d, --dir <path>", t("cli.dir")).option("-e, --exit-on-complete", t("cli.exit_on_complete")).option("-j, --json", t("cli.json"));
|
|
28119
28406
|
program2.command("init").description(t("cli.init")).action(async () => {
|
|
28120
28407
|
const answers = await runSetup();
|
|
28121
|
-
const configPath =
|
|
28408
|
+
const configPath = join38(homedir15(), ".mma", "config.json");
|
|
28122
28409
|
const { config } = await bootstrap();
|
|
28123
28410
|
config.provider.type = answers.provider;
|
|
28124
28411
|
config.provider.baseUrl = answers.apiBase;
|
|
@@ -28163,7 +28450,7 @@ function createProgram() {
|
|
|
28163
28450
|
});
|
|
28164
28451
|
const configCmd = program2.command("config").description(t("cli.manage_config"));
|
|
28165
28452
|
configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
|
|
28166
|
-
const configPath =
|
|
28453
|
+
const configPath = join38(homedir15(), ".mma", "config.json");
|
|
28167
28454
|
const { config } = await bootstrap();
|
|
28168
28455
|
const keys = key.split(".");
|
|
28169
28456
|
let obj = config;
|
|
@@ -28226,7 +28513,7 @@ function createProgram() {
|
|
|
28226
28513
|
console.log(t("cli.model_hint"));
|
|
28227
28514
|
});
|
|
28228
28515
|
model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
|
|
28229
|
-
const configPath =
|
|
28516
|
+
const configPath = join38(homedir15(), ".mma", "config.json");
|
|
28230
28517
|
const { config } = await bootstrap();
|
|
28231
28518
|
config.model = name;
|
|
28232
28519
|
saveConfig(config, configPath);
|
|
@@ -28262,7 +28549,7 @@ function createProgram() {
|
|
|
28262
28549
|
await uncertify2(name, config);
|
|
28263
28550
|
});
|
|
28264
28551
|
program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
|
|
28265
|
-
const configPath =
|
|
28552
|
+
const configPath = join38(homedir15(), ".mma", "config.json");
|
|
28266
28553
|
const { config } = await bootstrap();
|
|
28267
28554
|
const contextWindow = parseInt(size, 10);
|
|
28268
28555
|
if (isNaN(contextWindow) || contextWindow < 1024) {
|
|
@@ -28280,7 +28567,7 @@ function createProgram() {
|
|
|
28280
28567
|
console.log(t("cli.base_url"), config.provider.baseUrl);
|
|
28281
28568
|
});
|
|
28282
28569
|
provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
|
|
28283
|
-
const configPath =
|
|
28570
|
+
const configPath = join38(homedir15(), ".mma", "config.json");
|
|
28284
28571
|
const { config } = await bootstrap();
|
|
28285
28572
|
config.provider.type = name;
|
|
28286
28573
|
saveConfig(config, configPath);
|
|
@@ -28331,11 +28618,701 @@ init_bootstrap();
|
|
|
28331
28618
|
|
|
28332
28619
|
// src/cli/repl.ts
|
|
28333
28620
|
init_colors();
|
|
28621
|
+
import * as readline3 from "readline";
|
|
28622
|
+
|
|
28623
|
+
// src/ui/line-editor.ts
|
|
28624
|
+
init_string_width();
|
|
28334
28625
|
import * as readline2 from "readline";
|
|
28626
|
+
|
|
28627
|
+
// src/ui/line-math.ts
|
|
28628
|
+
init_string_width();
|
|
28629
|
+
var ANSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
28630
|
+
function stripAnsi2(s) {
|
|
28631
|
+
return s.replace(ANSI_RE, "");
|
|
28632
|
+
}
|
|
28633
|
+
function charLen(s) {
|
|
28634
|
+
return Array.from(s).length;
|
|
28635
|
+
}
|
|
28636
|
+
function wrapLine(line, width) {
|
|
28637
|
+
const w = width > 0 ? width : 80;
|
|
28638
|
+
const chars = Array.from(line);
|
|
28639
|
+
const rows = [];
|
|
28640
|
+
let start = 0;
|
|
28641
|
+
let cells = 0;
|
|
28642
|
+
for (let i = 0;i < chars.length; i++) {
|
|
28643
|
+
const ch = chars[i];
|
|
28644
|
+
if (ch === `
|
|
28645
|
+
`) {
|
|
28646
|
+
rows.push({ text: chars.slice(start, i).join(""), charStart: start });
|
|
28647
|
+
start = i + 1;
|
|
28648
|
+
cells = 0;
|
|
28649
|
+
continue;
|
|
28650
|
+
}
|
|
28651
|
+
const cw = stringWidth(ch);
|
|
28652
|
+
if (cells + cw > w && cells > 0) {
|
|
28653
|
+
rows.push({ text: chars.slice(start, i).join(""), charStart: start });
|
|
28654
|
+
start = i;
|
|
28655
|
+
cells = cw;
|
|
28656
|
+
} else {
|
|
28657
|
+
cells += cw;
|
|
28658
|
+
}
|
|
28659
|
+
}
|
|
28660
|
+
rows.push({ text: chars.slice(start).join(""), charStart: start });
|
|
28661
|
+
return rows;
|
|
28662
|
+
}
|
|
28663
|
+
function buildLayout(lines, width) {
|
|
28664
|
+
const rows = [];
|
|
28665
|
+
for (let b = 0;b < lines.length; b++) {
|
|
28666
|
+
for (const r of wrapLine(lines[b], width)) {
|
|
28667
|
+
rows.push({ bufRow: b, charStart: r.charStart, text: r.text });
|
|
28668
|
+
}
|
|
28669
|
+
}
|
|
28670
|
+
return rows;
|
|
28671
|
+
}
|
|
28672
|
+
function layoutIndexFor(rows, bufRow, col) {
|
|
28673
|
+
let idx = 0;
|
|
28674
|
+
for (let i = 0;i < rows.length; i++) {
|
|
28675
|
+
if (rows[i].bufRow === bufRow && rows[i].charStart <= col)
|
|
28676
|
+
idx = i;
|
|
28677
|
+
}
|
|
28678
|
+
return idx;
|
|
28679
|
+
}
|
|
28680
|
+
function visualColAt(rows, idx, col) {
|
|
28681
|
+
const r = rows[idx];
|
|
28682
|
+
const upTo = col - r.charStart;
|
|
28683
|
+
return stringWidth(Array.from(r.text).slice(0, upTo).join(""));
|
|
28684
|
+
}
|
|
28685
|
+
function charOffsetFor(rows, idx, visualCol) {
|
|
28686
|
+
const r = rows[idx];
|
|
28687
|
+
const chars = Array.from(r.text);
|
|
28688
|
+
let cells = 0;
|
|
28689
|
+
for (let i = 0;i < chars.length; i++) {
|
|
28690
|
+
const cw = stringWidth(chars[i]);
|
|
28691
|
+
if (cells + cw > visualCol)
|
|
28692
|
+
return r.charStart + i;
|
|
28693
|
+
cells += cw;
|
|
28694
|
+
}
|
|
28695
|
+
return r.charStart + chars.length;
|
|
28696
|
+
}
|
|
28697
|
+
|
|
28698
|
+
// src/ui/line-editor.ts
|
|
28699
|
+
class LineEditor {
|
|
28700
|
+
input;
|
|
28701
|
+
output;
|
|
28702
|
+
onKeyInput;
|
|
28703
|
+
promptStr;
|
|
28704
|
+
completer;
|
|
28705
|
+
history;
|
|
28706
|
+
historySize;
|
|
28707
|
+
lines = [""];
|
|
28708
|
+
row = 0;
|
|
28709
|
+
col = 0;
|
|
28710
|
+
historyIndex = -1;
|
|
28711
|
+
stash = null;
|
|
28712
|
+
isDone = false;
|
|
28713
|
+
isPaste = false;
|
|
28714
|
+
lastWasCR = false;
|
|
28715
|
+
questionCb = null;
|
|
28716
|
+
rawMode = false;
|
|
28717
|
+
listeners = {};
|
|
28718
|
+
constructor(opts) {
|
|
28719
|
+
this.input = opts.input;
|
|
28720
|
+
this.output = opts.output;
|
|
28721
|
+
this.promptStr = opts.prompt ?? "";
|
|
28722
|
+
this.completer = opts.completer;
|
|
28723
|
+
this.history = opts.history ?? [];
|
|
28724
|
+
this.historySize = opts.historySize ?? 50;
|
|
28725
|
+
if (this.history.length > this.historySize) {
|
|
28726
|
+
this.history = this.history.slice(-this.historySize);
|
|
28727
|
+
}
|
|
28728
|
+
if (this.input.isTTY) {
|
|
28729
|
+
this.rawMode = typeof this.input.setRawMode === "function";
|
|
28730
|
+
if (this.rawMode)
|
|
28731
|
+
this.input.setRawMode(true);
|
|
28732
|
+
this.enableTerminalProtocols();
|
|
28733
|
+
readline2.emitKeypressEvents(this.input);
|
|
28734
|
+
this.input.on("keypress", (str, key) => this.onKey(str, key));
|
|
28735
|
+
} else {
|
|
28736
|
+
this.input.on("data", (buf) => this.onData(buf));
|
|
28737
|
+
this.input.on("end", () => {
|
|
28738
|
+
const last = this.lines.join(`
|
|
28739
|
+
`);
|
|
28740
|
+
this.lines = [""];
|
|
28741
|
+
this.row = 0;
|
|
28742
|
+
this.col = 0;
|
|
28743
|
+
if (last)
|
|
28744
|
+
this.emitLine(last);
|
|
28745
|
+
this.emitClose();
|
|
28746
|
+
});
|
|
28747
|
+
}
|
|
28748
|
+
}
|
|
28749
|
+
on(event, listener) {
|
|
28750
|
+
if (event === "line") {
|
|
28751
|
+
this.listeners.line = listener;
|
|
28752
|
+
} else {
|
|
28753
|
+
this.listeners.close = listener;
|
|
28754
|
+
}
|
|
28755
|
+
return this;
|
|
28756
|
+
}
|
|
28757
|
+
setPrompt(prompt) {
|
|
28758
|
+
this.promptStr = prompt;
|
|
28759
|
+
if (this.input.isTTY)
|
|
28760
|
+
this.render();
|
|
28761
|
+
}
|
|
28762
|
+
prompt(_preserveCursor) {
|
|
28763
|
+
if (this.input.isTTY)
|
|
28764
|
+
this.render();
|
|
28765
|
+
}
|
|
28766
|
+
write(s) {
|
|
28767
|
+
this.insertText(s);
|
|
28768
|
+
}
|
|
28769
|
+
reset() {
|
|
28770
|
+
this.lines = [""];
|
|
28771
|
+
this.row = 0;
|
|
28772
|
+
this.col = 0;
|
|
28773
|
+
this.historyIndex = -1;
|
|
28774
|
+
this.stash = null;
|
|
28775
|
+
if (this.input.isTTY)
|
|
28776
|
+
this.render();
|
|
28777
|
+
}
|
|
28778
|
+
question(query, cb) {
|
|
28779
|
+
this.questionCb = cb;
|
|
28780
|
+
this.promptStr = query;
|
|
28781
|
+
this.lines = [""];
|
|
28782
|
+
this.row = 0;
|
|
28783
|
+
this.col = 0;
|
|
28784
|
+
if (this.input.isTTY)
|
|
28785
|
+
this.render();
|
|
28786
|
+
}
|
|
28787
|
+
close() {
|
|
28788
|
+
if (this.isDone)
|
|
28789
|
+
return;
|
|
28790
|
+
this.isDone = true;
|
|
28791
|
+
this.disableTerminalProtocols();
|
|
28792
|
+
if (this.rawMode && this.input.setRawMode) {
|
|
28793
|
+
this.input.setRawMode(false);
|
|
28794
|
+
}
|
|
28795
|
+
this.emitClose();
|
|
28796
|
+
}
|
|
28797
|
+
onData(buf) {
|
|
28798
|
+
if (this.isDone)
|
|
28799
|
+
return;
|
|
28800
|
+
let text = buf.toString("utf-8");
|
|
28801
|
+
text = text.replace(/\r\n/g, `
|
|
28802
|
+
`).replace(/\r/g, `
|
|
28803
|
+
`);
|
|
28804
|
+
const parts = text.split(`
|
|
28805
|
+
`);
|
|
28806
|
+
for (let i = 0;i < parts.length; i++) {
|
|
28807
|
+
if (i < parts.length - 1) {
|
|
28808
|
+
this.emitLine(parts[i]);
|
|
28809
|
+
this.lines = [""];
|
|
28810
|
+
this.row = 0;
|
|
28811
|
+
this.col = 0;
|
|
28812
|
+
} else if (parts[i]) {
|
|
28813
|
+
this.emitLine(parts[i]);
|
|
28814
|
+
this.lines = [""];
|
|
28815
|
+
this.row = 0;
|
|
28816
|
+
this.col = 0;
|
|
28817
|
+
}
|
|
28818
|
+
}
|
|
28819
|
+
}
|
|
28820
|
+
onKey(str, key) {
|
|
28821
|
+
if (this.isDone)
|
|
28822
|
+
return;
|
|
28823
|
+
if (this.onKeyInput && this.onKeyInput(str, key))
|
|
28824
|
+
return;
|
|
28825
|
+
const k = key;
|
|
28826
|
+
const name = k?.name ?? "undefined";
|
|
28827
|
+
const seq2 = k?.sequence ?? str ?? "";
|
|
28828
|
+
if (name === "undefined" && /^\x1b\[\d+(?:;\d+)?u$/.test(seq2)) {
|
|
28829
|
+
const m = seq2.match(/^\x1b\[(\d+)(?:;(\d+))?u$/);
|
|
28830
|
+
if (m && Number(m[1]) === 13 && Number(m[2] ?? 0) !== 0) {
|
|
28831
|
+
this.insertNewline();
|
|
28832
|
+
}
|
|
28833
|
+
return;
|
|
28834
|
+
}
|
|
28835
|
+
if (name === "paste-start" || seq2 === "\x1B[200~") {
|
|
28836
|
+
this.isPaste = true;
|
|
28837
|
+
return;
|
|
28838
|
+
}
|
|
28839
|
+
if (name === "paste-end" || seq2 === "\x1B[201~") {
|
|
28840
|
+
this.isPaste = false;
|
|
28841
|
+
this.render();
|
|
28842
|
+
return;
|
|
28843
|
+
}
|
|
28844
|
+
if (this.isPaste) {
|
|
28845
|
+
if (name === "return" || seq2 === "\r" || seq2 === `
|
|
28846
|
+
`) {
|
|
28847
|
+
this.insertText(`
|
|
28848
|
+
`);
|
|
28849
|
+
} else if (str) {
|
|
28850
|
+
this.insertText(str);
|
|
28851
|
+
}
|
|
28852
|
+
this.render();
|
|
28853
|
+
return;
|
|
28854
|
+
}
|
|
28855
|
+
if (name === "return" && (seq2 === "\x1B\r" || k.meta)) {
|
|
28856
|
+
this.insertNewline();
|
|
28857
|
+
return;
|
|
28858
|
+
}
|
|
28859
|
+
if (name === "undefined" && seq2 === "\x1B\r") {
|
|
28860
|
+
this.insertNewline();
|
|
28861
|
+
return;
|
|
28862
|
+
}
|
|
28863
|
+
if (k?.ctrl && name === "j") {
|
|
28864
|
+
this.insertNewline();
|
|
28865
|
+
return;
|
|
28866
|
+
}
|
|
28867
|
+
if (name === "escape")
|
|
28868
|
+
return;
|
|
28869
|
+
switch (name) {
|
|
28870
|
+
case "return":
|
|
28871
|
+
this.lastWasCR = true;
|
|
28872
|
+
this.submit();
|
|
28873
|
+
return;
|
|
28874
|
+
case "enter":
|
|
28875
|
+
if (this.lastWasCR) {
|
|
28876
|
+
this.lastWasCR = false;
|
|
28877
|
+
return;
|
|
28878
|
+
}
|
|
28879
|
+
this.insertNewline();
|
|
28880
|
+
return;
|
|
28881
|
+
case "backspace":
|
|
28882
|
+
this.lastWasCR = false;
|
|
28883
|
+
this.backspace();
|
|
28884
|
+
return;
|
|
28885
|
+
case "delete":
|
|
28886
|
+
this.lastWasCR = false;
|
|
28887
|
+
this.deleteForward();
|
|
28888
|
+
return;
|
|
28889
|
+
case "left":
|
|
28890
|
+
this.lastWasCR = false;
|
|
28891
|
+
this.moveLeft();
|
|
28892
|
+
return;
|
|
28893
|
+
case "right":
|
|
28894
|
+
this.lastWasCR = false;
|
|
28895
|
+
this.moveRight();
|
|
28896
|
+
return;
|
|
28897
|
+
case "up":
|
|
28898
|
+
this.lastWasCR = false;
|
|
28899
|
+
this.moveUp();
|
|
28900
|
+
return;
|
|
28901
|
+
case "down":
|
|
28902
|
+
this.lastWasCR = false;
|
|
28903
|
+
this.moveDown();
|
|
28904
|
+
return;
|
|
28905
|
+
case "home":
|
|
28906
|
+
this.lastWasCR = false;
|
|
28907
|
+
this.moveHome();
|
|
28908
|
+
return;
|
|
28909
|
+
case "end":
|
|
28910
|
+
this.lastWasCR = false;
|
|
28911
|
+
this.moveEnd();
|
|
28912
|
+
return;
|
|
28913
|
+
case "pageup":
|
|
28914
|
+
this.lastWasCR = false;
|
|
28915
|
+
this.moveToStart();
|
|
28916
|
+
return;
|
|
28917
|
+
case "pagedown":
|
|
28918
|
+
this.lastWasCR = false;
|
|
28919
|
+
this.moveToEnd();
|
|
28920
|
+
return;
|
|
28921
|
+
case "tab":
|
|
28922
|
+
this.lastWasCR = false;
|
|
28923
|
+
this.tabComplete();
|
|
28924
|
+
return;
|
|
28925
|
+
}
|
|
28926
|
+
if (k?.ctrl) {
|
|
28927
|
+
this.lastWasCR = false;
|
|
28928
|
+
switch (name) {
|
|
28929
|
+
case "c":
|
|
28930
|
+
this.ctrlC();
|
|
28931
|
+
return;
|
|
28932
|
+
case "d":
|
|
28933
|
+
this.ctrlD();
|
|
28934
|
+
return;
|
|
28935
|
+
case "a":
|
|
28936
|
+
this.moveHome();
|
|
28937
|
+
return;
|
|
28938
|
+
case "e":
|
|
28939
|
+
this.moveEnd();
|
|
28940
|
+
return;
|
|
28941
|
+
case "u":
|
|
28942
|
+
this.killToStart();
|
|
28943
|
+
return;
|
|
28944
|
+
case "k":
|
|
28945
|
+
this.killToEnd();
|
|
28946
|
+
return;
|
|
28947
|
+
case "w":
|
|
28948
|
+
this.killWordBefore();
|
|
28949
|
+
return;
|
|
28950
|
+
case "l":
|
|
28951
|
+
this.clearScreen();
|
|
28952
|
+
return;
|
|
28953
|
+
default:
|
|
28954
|
+
return;
|
|
28955
|
+
}
|
|
28956
|
+
}
|
|
28957
|
+
if (k?.meta) {
|
|
28958
|
+
this.lastWasCR = false;
|
|
28959
|
+
switch (name) {
|
|
28960
|
+
case "b":
|
|
28961
|
+
this.moveWordLeft();
|
|
28962
|
+
return;
|
|
28963
|
+
case "f":
|
|
28964
|
+
this.moveWordRight();
|
|
28965
|
+
return;
|
|
28966
|
+
case "d":
|
|
28967
|
+
this.killWordAfter();
|
|
28968
|
+
return;
|
|
28969
|
+
default:
|
|
28970
|
+
return;
|
|
28971
|
+
}
|
|
28972
|
+
}
|
|
28973
|
+
if (str && !/^[\u0000-\u001f\u007f]/.test(str)) {
|
|
28974
|
+
this.lastWasCR = false;
|
|
28975
|
+
this.insertText(str);
|
|
28976
|
+
}
|
|
28977
|
+
}
|
|
28978
|
+
submit() {
|
|
28979
|
+
if (this.questionCb) {
|
|
28980
|
+
const cb = this.questionCb;
|
|
28981
|
+
this.questionCb = null;
|
|
28982
|
+
const answer = this.lines.join(`
|
|
28983
|
+
`).trim();
|
|
28984
|
+
this.lines = [""];
|
|
28985
|
+
this.row = 0;
|
|
28986
|
+
this.col = 0;
|
|
28987
|
+
this.render();
|
|
28988
|
+
cb(answer);
|
|
28989
|
+
return;
|
|
28990
|
+
}
|
|
28991
|
+
const text = this.lines.join(`
|
|
28992
|
+
`);
|
|
28993
|
+
if (text.trim()) {
|
|
28994
|
+
this.history.push(text);
|
|
28995
|
+
if (this.history.length > this.historySize) {
|
|
28996
|
+
this.history = this.history.slice(-this.historySize);
|
|
28997
|
+
}
|
|
28998
|
+
}
|
|
28999
|
+
this.historyIndex = -1;
|
|
29000
|
+
this.stash = null;
|
|
29001
|
+
this.lines = [""];
|
|
29002
|
+
this.row = 0;
|
|
29003
|
+
this.col = 0;
|
|
29004
|
+
this.render();
|
|
29005
|
+
this.emitLine(text);
|
|
29006
|
+
}
|
|
29007
|
+
ctrlC() {
|
|
29008
|
+
this.lines = [""];
|
|
29009
|
+
this.row = 0;
|
|
29010
|
+
this.col = 0;
|
|
29011
|
+
this.render();
|
|
29012
|
+
process.emit("SIGINT");
|
|
29013
|
+
}
|
|
29014
|
+
ctrlD() {
|
|
29015
|
+
if (this.lines.length === 1 && this.lines[0] === "") {
|
|
29016
|
+
this.emitClose();
|
|
29017
|
+
} else {
|
|
29018
|
+
this.deleteForward();
|
|
29019
|
+
}
|
|
29020
|
+
}
|
|
29021
|
+
currentChars() {
|
|
29022
|
+
return Array.from(this.lines[this.row]);
|
|
29023
|
+
}
|
|
29024
|
+
setCurrentChars(chars) {
|
|
29025
|
+
this.lines[this.row] = chars.join("");
|
|
29026
|
+
}
|
|
29027
|
+
insertText(text) {
|
|
29028
|
+
const sanitized = text.replace(/\r\n/g, `
|
|
29029
|
+
`).replace(/\r/g, "");
|
|
29030
|
+
const chars = this.currentChars();
|
|
29031
|
+
const t2 = Array.from(sanitized);
|
|
29032
|
+
chars.splice(this.col, 0, ...t2);
|
|
29033
|
+
this.setCurrentChars(chars);
|
|
29034
|
+
this.col += t2.length;
|
|
29035
|
+
this.render();
|
|
29036
|
+
}
|
|
29037
|
+
insertNewline() {
|
|
29038
|
+
const chars = this.currentChars();
|
|
29039
|
+
const rest = chars.slice(this.col).join("");
|
|
29040
|
+
this.setCurrentChars(chars.slice(0, this.col));
|
|
29041
|
+
this.lines.splice(this.row + 1, 0, rest);
|
|
29042
|
+
this.row++;
|
|
29043
|
+
this.col = 0;
|
|
29044
|
+
this.render();
|
|
29045
|
+
}
|
|
29046
|
+
backspace() {
|
|
29047
|
+
const chars = this.currentChars();
|
|
29048
|
+
if (this.col > 0) {
|
|
29049
|
+
chars.splice(this.col - 1, 1);
|
|
29050
|
+
this.setCurrentChars(chars);
|
|
29051
|
+
this.col--;
|
|
29052
|
+
} else if (this.row > 0) {
|
|
29053
|
+
const prevLen = charLen(this.lines[this.row - 1]);
|
|
29054
|
+
this.lines[this.row - 1] = this.lines[this.row - 1] + this.lines[this.row];
|
|
29055
|
+
this.lines.splice(this.row, 1);
|
|
29056
|
+
this.row--;
|
|
29057
|
+
this.col = prevLen;
|
|
29058
|
+
}
|
|
29059
|
+
this.render();
|
|
29060
|
+
}
|
|
29061
|
+
deleteForward() {
|
|
29062
|
+
const chars = this.currentChars();
|
|
29063
|
+
if (this.col < chars.length) {
|
|
29064
|
+
chars.splice(this.col, 1);
|
|
29065
|
+
this.setCurrentChars(chars);
|
|
29066
|
+
} else if (this.row < this.lines.length - 1) {
|
|
29067
|
+
this.lines[this.row] = this.lines[this.row] + this.lines[this.row + 1];
|
|
29068
|
+
this.lines.splice(this.row + 1, 1);
|
|
29069
|
+
}
|
|
29070
|
+
this.render();
|
|
29071
|
+
}
|
|
29072
|
+
killToStart() {
|
|
29073
|
+
const chars = this.currentChars();
|
|
29074
|
+
this.setCurrentChars(chars.slice(this.col));
|
|
29075
|
+
this.col = 0;
|
|
29076
|
+
this.render();
|
|
29077
|
+
}
|
|
29078
|
+
killToEnd() {
|
|
29079
|
+
const chars = this.currentChars();
|
|
29080
|
+
this.setCurrentChars(chars.slice(0, this.col));
|
|
29081
|
+
this.render();
|
|
29082
|
+
}
|
|
29083
|
+
killWordBefore() {
|
|
29084
|
+
const chars = this.currentChars();
|
|
29085
|
+
let i = this.col;
|
|
29086
|
+
while (i > 0 && /\s/.test(chars[i - 1]))
|
|
29087
|
+
i--;
|
|
29088
|
+
while (i > 0 && !/\s/.test(chars[i - 1]))
|
|
29089
|
+
i--;
|
|
29090
|
+
chars.splice(i, this.col - i);
|
|
29091
|
+
this.setCurrentChars(chars);
|
|
29092
|
+
this.col = i;
|
|
29093
|
+
this.render();
|
|
29094
|
+
}
|
|
29095
|
+
killWordAfter() {
|
|
29096
|
+
const chars = this.currentChars();
|
|
29097
|
+
const n = chars.length;
|
|
29098
|
+
let i = this.col;
|
|
29099
|
+
while (i < n && /\s/.test(chars[i]))
|
|
29100
|
+
i++;
|
|
29101
|
+
while (i < n && !/\s/.test(chars[i]))
|
|
29102
|
+
i++;
|
|
29103
|
+
chars.splice(this.col, i - this.col);
|
|
29104
|
+
this.setCurrentChars(chars);
|
|
29105
|
+
this.render();
|
|
29106
|
+
}
|
|
29107
|
+
moveLeft() {
|
|
29108
|
+
if (this.col > 0) {
|
|
29109
|
+
this.col--;
|
|
29110
|
+
} else if (this.row > 0) {
|
|
29111
|
+
this.row--;
|
|
29112
|
+
this.col = charLen(this.lines[this.row]);
|
|
29113
|
+
}
|
|
29114
|
+
this.render();
|
|
29115
|
+
}
|
|
29116
|
+
moveRight() {
|
|
29117
|
+
if (this.col < charLen(this.lines[this.row])) {
|
|
29118
|
+
this.col++;
|
|
29119
|
+
} else if (this.row < this.lines.length - 1) {
|
|
29120
|
+
this.row++;
|
|
29121
|
+
this.col = 0;
|
|
29122
|
+
}
|
|
29123
|
+
this.render();
|
|
29124
|
+
}
|
|
29125
|
+
moveUp() {
|
|
29126
|
+
const layout = this.layout();
|
|
29127
|
+
const idx = layoutIndexFor(layout, this.row, this.col);
|
|
29128
|
+
const vcol = visualColAt(layout, idx, this.col);
|
|
29129
|
+
if (idx > 0) {
|
|
29130
|
+
const target = layout[idx - 1];
|
|
29131
|
+
this.row = target.bufRow;
|
|
29132
|
+
this.col = charOffsetFor(layout, idx - 1, vcol);
|
|
29133
|
+
this.render();
|
|
29134
|
+
} else {
|
|
29135
|
+
this.historyPrev();
|
|
29136
|
+
}
|
|
29137
|
+
}
|
|
29138
|
+
moveDown() {
|
|
29139
|
+
const layout = this.layout();
|
|
29140
|
+
const idx = layoutIndexFor(layout, this.row, this.col);
|
|
29141
|
+
const vcol = visualColAt(layout, idx, this.col);
|
|
29142
|
+
if (idx < layout.length - 1) {
|
|
29143
|
+
const target = layout[idx + 1];
|
|
29144
|
+
this.row = target.bufRow;
|
|
29145
|
+
this.col = charOffsetFor(layout, idx + 1, vcol);
|
|
29146
|
+
this.render();
|
|
29147
|
+
} else {
|
|
29148
|
+
this.historyNext();
|
|
29149
|
+
}
|
|
29150
|
+
}
|
|
29151
|
+
moveHome() {
|
|
29152
|
+
this.col = 0;
|
|
29153
|
+
this.render();
|
|
29154
|
+
}
|
|
29155
|
+
moveEnd() {
|
|
29156
|
+
this.col = charLen(this.lines[this.row]);
|
|
29157
|
+
this.render();
|
|
29158
|
+
}
|
|
29159
|
+
moveToStart() {
|
|
29160
|
+
this.row = 0;
|
|
29161
|
+
this.col = 0;
|
|
29162
|
+
this.render();
|
|
29163
|
+
}
|
|
29164
|
+
moveToEnd() {
|
|
29165
|
+
this.row = this.lines.length - 1;
|
|
29166
|
+
this.col = charLen(this.lines[this.row]);
|
|
29167
|
+
this.render();
|
|
29168
|
+
}
|
|
29169
|
+
moveWordLeft() {
|
|
29170
|
+
const chars = this.currentChars();
|
|
29171
|
+
let i = this.col;
|
|
29172
|
+
while (i > 0 && /\s/.test(chars[i - 1]))
|
|
29173
|
+
i--;
|
|
29174
|
+
while (i > 0 && !/\s/.test(chars[i - 1]))
|
|
29175
|
+
i--;
|
|
29176
|
+
this.col = i;
|
|
29177
|
+
this.render();
|
|
29178
|
+
}
|
|
29179
|
+
moveWordRight() {
|
|
29180
|
+
const chars = this.currentChars();
|
|
29181
|
+
const n = chars.length;
|
|
29182
|
+
let i = this.col;
|
|
29183
|
+
while (i < n && !/\s/.test(chars[i]))
|
|
29184
|
+
i++;
|
|
29185
|
+
while (i < n && /\s/.test(chars[i]))
|
|
29186
|
+
i++;
|
|
29187
|
+
this.col = i;
|
|
29188
|
+
this.render();
|
|
29189
|
+
}
|
|
29190
|
+
historyPrev() {
|
|
29191
|
+
if (this.history.length === 0)
|
|
29192
|
+
return;
|
|
29193
|
+
if (this.historyIndex === -1) {
|
|
29194
|
+
this.stash = {
|
|
29195
|
+
lines: this.lines.slice(),
|
|
29196
|
+
row: this.row,
|
|
29197
|
+
col: this.col
|
|
29198
|
+
};
|
|
29199
|
+
this.historyIndex = 0;
|
|
29200
|
+
} else if (this.historyIndex < this.history.length - 1) {
|
|
29201
|
+
this.historyIndex++;
|
|
29202
|
+
} else {
|
|
29203
|
+
return;
|
|
29204
|
+
}
|
|
29205
|
+
this.applyHistoryEntry();
|
|
29206
|
+
}
|
|
29207
|
+
historyNext() {
|
|
29208
|
+
if (this.historyIndex === -1)
|
|
29209
|
+
return;
|
|
29210
|
+
if (this.historyIndex > 0) {
|
|
29211
|
+
this.historyIndex--;
|
|
29212
|
+
this.applyHistoryEntry();
|
|
29213
|
+
} else if (this.stash) {
|
|
29214
|
+
this.lines = this.stash.lines.slice();
|
|
29215
|
+
this.row = this.stash.row;
|
|
29216
|
+
this.col = this.stash.col;
|
|
29217
|
+
this.historyIndex = -1;
|
|
29218
|
+
this.stash = null;
|
|
29219
|
+
this.render();
|
|
29220
|
+
}
|
|
29221
|
+
}
|
|
29222
|
+
applyHistoryEntry() {
|
|
29223
|
+
const entry = this.history[this.history.length - 1 - this.historyIndex];
|
|
29224
|
+
this.lines = entry.split(`
|
|
29225
|
+
`);
|
|
29226
|
+
if (this.lines.length === 0)
|
|
29227
|
+
this.lines = [""];
|
|
29228
|
+
this.row = this.lines.length - 1;
|
|
29229
|
+
this.col = charLen(this.lines[this.row]);
|
|
29230
|
+
this.render();
|
|
29231
|
+
}
|
|
29232
|
+
tabComplete() {
|
|
29233
|
+
if (!this.completer)
|
|
29234
|
+
return;
|
|
29235
|
+
const line = this.lines[this.row];
|
|
29236
|
+
const [matches, partial] = this.completer(line);
|
|
29237
|
+
if (matches.length === 0) {
|
|
29238
|
+
this.output.write("\x07");
|
|
29239
|
+
return;
|
|
29240
|
+
}
|
|
29241
|
+
if (matches.length === 1) {
|
|
29242
|
+
const from = line.lastIndexOf(partial);
|
|
29243
|
+
const head = line.slice(0, from);
|
|
29244
|
+
const tail = line.slice(from + partial.length);
|
|
29245
|
+
this.lines[this.row] = head + matches[0] + tail;
|
|
29246
|
+
this.col = charLen(head) + charLen(matches[0]);
|
|
29247
|
+
this.render();
|
|
29248
|
+
return;
|
|
29249
|
+
}
|
|
29250
|
+
const lines = matches.map((m) => " " + m);
|
|
29251
|
+
this.output.write(`\r
|
|
29252
|
+
` + lines.join(`\r
|
|
29253
|
+
`) + `\r
|
|
29254
|
+
`);
|
|
29255
|
+
this.output.write(`\x1B[${lines.length + 1}A`);
|
|
29256
|
+
this.render();
|
|
29257
|
+
}
|
|
29258
|
+
clearScreen() {
|
|
29259
|
+
this.output.write("\x1B[2J\x1B[H");
|
|
29260
|
+
this.render();
|
|
29261
|
+
}
|
|
29262
|
+
columns() {
|
|
29263
|
+
return this.output.columns || 80;
|
|
29264
|
+
}
|
|
29265
|
+
layout() {
|
|
29266
|
+
return buildLayout(this.lines, this.columns());
|
|
29267
|
+
}
|
|
29268
|
+
render() {
|
|
29269
|
+
if (!this.input.isTTY || this.isDone)
|
|
29270
|
+
return;
|
|
29271
|
+
const layout = this.layout();
|
|
29272
|
+
const promptWidth = stringWidth(stripAnsi2(this.promptStr));
|
|
29273
|
+
const idx = layoutIndexFor(layout, this.row, this.col);
|
|
29274
|
+
const vcol = visualColAt(layout, idx, this.col);
|
|
29275
|
+
const rowsAfter = layout.length - idx - 1;
|
|
29276
|
+
const ccol = (idx === 0 ? promptWidth : 0) + vcol;
|
|
29277
|
+
const out = ["\r"];
|
|
29278
|
+
for (let i = 0;i < layout.length; i++) {
|
|
29279
|
+
out.push("\x1B[2K");
|
|
29280
|
+
if (i === 0)
|
|
29281
|
+
out.push(this.promptStr);
|
|
29282
|
+
out.push(layout[i].text);
|
|
29283
|
+
if (i < layout.length - 1)
|
|
29284
|
+
out.push(`\r
|
|
29285
|
+
`);
|
|
29286
|
+
}
|
|
29287
|
+
out.push("\x1B[J");
|
|
29288
|
+
if (rowsAfter > 0)
|
|
29289
|
+
out.push(`\x1B[${rowsAfter}A`);
|
|
29290
|
+
out.push("\r");
|
|
29291
|
+
if (ccol > 0)
|
|
29292
|
+
out.push(`\x1B[${ccol}C`);
|
|
29293
|
+
this.output.write(out.join(""));
|
|
29294
|
+
}
|
|
29295
|
+
enableTerminalProtocols() {
|
|
29296
|
+
this.output.write("\x1B[?2004h");
|
|
29297
|
+
this.output.write("\x1B[>1u");
|
|
29298
|
+
}
|
|
29299
|
+
disableTerminalProtocols() {
|
|
29300
|
+
this.output.write("\x1B[?2004l");
|
|
29301
|
+
this.output.write("\x1B[<u");
|
|
29302
|
+
}
|
|
29303
|
+
emitLine(line) {
|
|
29304
|
+
this.listeners.line?.(line);
|
|
29305
|
+
}
|
|
29306
|
+
emitClose() {
|
|
29307
|
+
this.listeners.close?.();
|
|
29308
|
+
}
|
|
29309
|
+
}
|
|
29310
|
+
|
|
29311
|
+
// src/cli/repl.ts
|
|
28335
29312
|
import { existsSync as existsSync45, readFileSync as readFileSync31, writeFileSync as writeFileSync16 } from "fs";
|
|
28336
|
-
import { join as
|
|
29313
|
+
import { join as join40, dirname as dirname13 } from "path";
|
|
28337
29314
|
import { homedir as homedir17 } from "os";
|
|
28338
|
-
import { fileURLToPath as
|
|
29315
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
28339
29316
|
|
|
28340
29317
|
// src/cli/completer.ts
|
|
28341
29318
|
class SlashCommandProvider {
|
|
@@ -28633,14 +29610,6 @@ class FormattingStream {
|
|
|
28633
29610
|
return result;
|
|
28634
29611
|
}
|
|
28635
29612
|
}
|
|
28636
|
-
function formatMarkdown(text) {
|
|
28637
|
-
const lines = [];
|
|
28638
|
-
const stream = new FormattingStream((l) => lines.push(l));
|
|
28639
|
-
stream.write(text);
|
|
28640
|
-
stream.flush();
|
|
28641
|
-
return lines.join(`
|
|
28642
|
-
`);
|
|
28643
|
-
}
|
|
28644
29613
|
|
|
28645
29614
|
// src/ui/renderer.ts
|
|
28646
29615
|
init_spinner();
|
|
@@ -28845,10 +29814,10 @@ init_box();
|
|
|
28845
29814
|
init_i18n();
|
|
28846
29815
|
init_repl_commands();
|
|
28847
29816
|
function readVersion4() {
|
|
28848
|
-
const here =
|
|
29817
|
+
const here = dirname13(fileURLToPath5(import.meta.url));
|
|
28849
29818
|
const candidates = [
|
|
28850
|
-
|
|
28851
|
-
|
|
29819
|
+
join40(here, "..", "..", "package.json"),
|
|
29820
|
+
join40(here, "..", "package.json")
|
|
28852
29821
|
];
|
|
28853
29822
|
for (const p of candidates) {
|
|
28854
29823
|
if (existsSync45(p)) {
|
|
@@ -28893,6 +29862,7 @@ class Repl {
|
|
|
28893
29862
|
baseDir;
|
|
28894
29863
|
noAgentsMd;
|
|
28895
29864
|
pendingClipboardImage = null;
|
|
29865
|
+
exitOnClose = false;
|
|
28896
29866
|
rl;
|
|
28897
29867
|
agent;
|
|
28898
29868
|
config;
|
|
@@ -28900,19 +29870,32 @@ class Repl {
|
|
|
28900
29870
|
skillsModule;
|
|
28901
29871
|
pluginManager;
|
|
28902
29872
|
logger;
|
|
28903
|
-
constructor(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger) {
|
|
29873
|
+
constructor(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger, exitOnClose) {
|
|
28904
29874
|
this.agent = agent;
|
|
28905
29875
|
this.config = config;
|
|
29876
|
+
this.exitOnClose = exitOnClose === true;
|
|
28906
29877
|
this.sessionManager = sessionManager;
|
|
28907
29878
|
this.skillsModule = skillsModule;
|
|
28908
29879
|
this.pluginManager = pluginManager;
|
|
28909
29880
|
this.logger = logger;
|
|
28910
|
-
this.configDir = configDir ||
|
|
29881
|
+
this.configDir = configDir || join40(homedir17(), ".mma");
|
|
28911
29882
|
this.baseDir = baseDir || process.cwd();
|
|
28912
29883
|
this.noAgentsMd = noAgentsMd === true;
|
|
28913
|
-
this.historyPath =
|
|
29884
|
+
this.historyPath = join40(homedir17(), ".mma", "repl-history");
|
|
28914
29885
|
this.loadHistory();
|
|
28915
|
-
this.rl =
|
|
29886
|
+
this.rl = process.stdin.isTTY ? new LineEditor({
|
|
29887
|
+
input: process.stdin,
|
|
29888
|
+
output: process.stdout,
|
|
29889
|
+
prompt: pc2.cyan("> "),
|
|
29890
|
+
history: this.history,
|
|
29891
|
+
historySize: this.maxHistory,
|
|
29892
|
+
completer: (line) => {
|
|
29893
|
+
const [matches, partial] = this.completer.complete(line);
|
|
29894
|
+
if (matches.length > 0)
|
|
29895
|
+
return [matches, partial];
|
|
29896
|
+
return [[], line];
|
|
29897
|
+
}
|
|
29898
|
+
}) : readline3.createInterface({
|
|
28916
29899
|
input: process.stdin,
|
|
28917
29900
|
output: process.stdout,
|
|
28918
29901
|
prompt: pc2.cyan("> "),
|
|
@@ -29029,46 +30012,22 @@ class Repl {
|
|
|
29029
30012
|
});
|
|
29030
30013
|
this.rl.on("close", () => {
|
|
29031
30014
|
this.running = false;
|
|
30015
|
+
this.saveHistory();
|
|
30016
|
+
this.agent.shutdown();
|
|
30017
|
+
if (this.exitOnClose)
|
|
30018
|
+
process.exit(0);
|
|
29032
30019
|
});
|
|
29033
|
-
if (process.stdin.isTTY) {
|
|
29034
|
-
|
|
29035
|
-
|
|
29036
|
-
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
const withinWindow = now - this.lastEscTime < this.doubleEscDelay;
|
|
29040
|
-
this.lastEscTime = now;
|
|
29041
|
-
if (escBytes >= 2 || withinWindow) {
|
|
29042
|
-
this.lastEscTime = 0;
|
|
29043
|
-
if (this.agentRunning) {
|
|
29044
|
-
process.stdout.write(pc2.yellow(`
|
|
29045
|
-
${t("repl.interrupt")}
|
|
29046
|
-
`));
|
|
29047
|
-
this.agent.shutdown();
|
|
29048
|
-
}
|
|
29049
|
-
}
|
|
29050
|
-
return;
|
|
29051
|
-
}
|
|
29052
|
-
if (key.ctrl && key.name === "v" && !this.agentRunning) {
|
|
29053
|
-
try {
|
|
29054
|
-
const { readClipboardImage: readClipboardImage2, bufferToDataUrl: bufferToDataUrl2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
|
|
29055
|
-
const clipBuf = await readClipboardImage2();
|
|
29056
|
-
if (clipBuf) {
|
|
29057
|
-
const { dataUrl } = await bufferToDataUrl2(clipBuf);
|
|
29058
|
-
this.pendingClipboardImage = dataUrl;
|
|
29059
|
-
const sizeKb = Math.round(dataUrl.length * 3 / 4 / 1024);
|
|
29060
|
-
console.log(pc2.green(`
|
|
29061
|
-
${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
29062
|
-
this.rl.prompt();
|
|
29063
|
-
} else {
|
|
29064
|
-
console.log(pc2.yellow(`
|
|
29065
|
-
${t("image.clipboard_empty")}`));
|
|
29066
|
-
this.rl.prompt();
|
|
29067
|
-
}
|
|
29068
|
-
} catch {}
|
|
29069
|
-
}
|
|
30020
|
+
if (this.exitOnClose && !process.stdin.isTTY) {
|
|
30021
|
+
process.stdin.on("end", () => {
|
|
30022
|
+
this.running = false;
|
|
30023
|
+
this.saveHistory();
|
|
30024
|
+
this.agent.shutdown();
|
|
30025
|
+
process.exit(0);
|
|
29070
30026
|
});
|
|
29071
30027
|
}
|
|
30028
|
+
if (this.rl instanceof LineEditor) {
|
|
30029
|
+
this.rl.onKeyInput = (str, key) => this.handleSpecialKey(str, key);
|
|
30030
|
+
}
|
|
29072
30031
|
let forceExitTimer = null;
|
|
29073
30032
|
process.on("SIGINT", () => {
|
|
29074
30033
|
if (this.agentRunning) {
|
|
@@ -29084,6 +30043,51 @@ ${t("image.clipboard_empty")}`));
|
|
|
29084
30043
|
}
|
|
29085
30044
|
});
|
|
29086
30045
|
}
|
|
30046
|
+
handleSpecialKey(str, key) {
|
|
30047
|
+
if (key.name === "escape") {
|
|
30048
|
+
const escBytes = key.sequence ? (key.sequence.match(/\x1b/g) || []).length : 1;
|
|
30049
|
+
const now = Date.now();
|
|
30050
|
+
const withinWindow = now - this.lastEscTime < this.doubleEscDelay;
|
|
30051
|
+
this.lastEscTime = now;
|
|
30052
|
+
if (escBytes >= 2 || withinWindow) {
|
|
30053
|
+
this.lastEscTime = 0;
|
|
30054
|
+
if (this.agentRunning) {
|
|
30055
|
+
process.stdout.write(pc2.yellow(`
|
|
30056
|
+
${t("repl.interrupt")}
|
|
30057
|
+
`));
|
|
30058
|
+
this.agent.shutdown();
|
|
30059
|
+
}
|
|
30060
|
+
}
|
|
30061
|
+
return true;
|
|
30062
|
+
}
|
|
30063
|
+
if (key.ctrl && key.name === "v" && !this.agentRunning) {
|
|
30064
|
+
this.pasteClipboardImage();
|
|
30065
|
+
return true;
|
|
30066
|
+
}
|
|
30067
|
+
return false;
|
|
30068
|
+
}
|
|
30069
|
+
async pasteClipboardImage() {
|
|
30070
|
+
try {
|
|
30071
|
+
const { readClipboardImage: readClipboardImage2, bufferToDataUrl: bufferToDataUrl2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
|
|
30072
|
+
const clipBuf = await readClipboardImage2();
|
|
30073
|
+
if (clipBuf) {
|
|
30074
|
+
const { dataUrl } = await bufferToDataUrl2(clipBuf);
|
|
30075
|
+
this.pendingClipboardImage = dataUrl;
|
|
30076
|
+
const sizeKb = Math.round(dataUrl.length * 3 / 4 / 1024);
|
|
30077
|
+
console.log(pc2.green(`
|
|
30078
|
+
${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
30079
|
+
if (this.rl instanceof LineEditor)
|
|
30080
|
+
this.rl.reset();
|
|
30081
|
+
this.rl.prompt();
|
|
30082
|
+
} else {
|
|
30083
|
+
console.log(pc2.yellow(`
|
|
30084
|
+
${t("image.clipboard_empty")}`));
|
|
30085
|
+
if (this.rl instanceof LineEditor)
|
|
30086
|
+
this.rl.reset();
|
|
30087
|
+
this.rl.prompt();
|
|
30088
|
+
}
|
|
30089
|
+
} catch {}
|
|
30090
|
+
}
|
|
29087
30091
|
isMultiLineInput(line) {
|
|
29088
30092
|
if (line.endsWith("\\"))
|
|
29089
30093
|
return true;
|
|
@@ -29109,6 +30113,8 @@ ${t("image.clipboard_empty")}`));
|
|
|
29109
30113
|
this.pendingClipboardImage = null;
|
|
29110
30114
|
}
|
|
29111
30115
|
this.logger?.logREPL("user", input);
|
|
30116
|
+
if (this.rl instanceof LineEditor)
|
|
30117
|
+
this.rl.reset();
|
|
29112
30118
|
process.stdout.write(`
|
|
29113
30119
|
` + pc2.green(t("repl.agent")));
|
|
29114
30120
|
const renderer = new Renderer({
|
|
@@ -29264,9 +30270,9 @@ ${t("image.clipboard_empty")}`));
|
|
|
29264
30270
|
row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
|
|
29265
30271
|
} else {
|
|
29266
30272
|
const agentsMdCandidates = [
|
|
29267
|
-
|
|
29268
|
-
|
|
29269
|
-
|
|
30273
|
+
join40(this.baseDir, "AGENTS.md"),
|
|
30274
|
+
join40(this.baseDir, ".mma", "AGENTS.md"),
|
|
30275
|
+
join40(this.configDir, "AGENTS.md")
|
|
29270
30276
|
];
|
|
29271
30277
|
const foundAgents = agentsMdCandidates.filter((p) => existsSync45(p));
|
|
29272
30278
|
if (foundAgents.length > 0) {
|
|
@@ -29279,7 +30285,7 @@ ${t("image.clipboard_empty")}`));
|
|
|
29279
30285
|
}
|
|
29280
30286
|
const meta = this.sessionManager?.getActiveMeta();
|
|
29281
30287
|
if (meta) {
|
|
29282
|
-
const sessionPath =
|
|
30288
|
+
const sessionPath = join40(this.configDir, "sessions", meta.id);
|
|
29283
30289
|
row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
|
|
29284
30290
|
}
|
|
29285
30291
|
const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
|
|
@@ -29300,15 +30306,30 @@ ${t("image.clipboard_empty")}`));
|
|
|
29300
30306
|
}
|
|
29301
30307
|
}
|
|
29302
30308
|
|
|
30309
|
+
// src/cli/run-result.ts
|
|
30310
|
+
init_i18n();
|
|
30311
|
+
init_colors();
|
|
30312
|
+
function printRunResult(result, flush) {
|
|
30313
|
+
flush();
|
|
30314
|
+
if (result.success) {
|
|
30315
|
+
if (!result.text) {
|
|
30316
|
+
console.log(pc2.yellow(t("cli.no_output")));
|
|
30317
|
+
}
|
|
30318
|
+
return 0;
|
|
30319
|
+
}
|
|
30320
|
+
console.error(`${t("error.prefix")}${result.error}`);
|
|
30321
|
+
return 1;
|
|
30322
|
+
}
|
|
30323
|
+
|
|
29303
30324
|
// src/cli/main.ts
|
|
29304
30325
|
init_setup();
|
|
29305
30326
|
init_config2();
|
|
29306
30327
|
init_i18n();
|
|
29307
30328
|
init_colors();
|
|
29308
30329
|
import { existsSync as existsSync46, readFileSync as readFileSync32 } from "fs";
|
|
29309
|
-
import { join as
|
|
30330
|
+
import { join as join41, dirname as dirname14 } from "path";
|
|
29310
30331
|
import { homedir as homedir18 } from "os";
|
|
29311
|
-
import { fileURLToPath as
|
|
30332
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
29312
30333
|
|
|
29313
30334
|
// src/modules/updater/checker.ts
|
|
29314
30335
|
var defaultRunner2 = async (command, args, options) => {
|
|
@@ -29457,10 +30478,10 @@ class UpdaterModule {
|
|
|
29457
30478
|
}
|
|
29458
30479
|
// src/cli/main.ts
|
|
29459
30480
|
function readVersion5() {
|
|
29460
|
-
const here =
|
|
30481
|
+
const here = dirname14(fileURLToPath6(import.meta.url));
|
|
29461
30482
|
const candidates = [
|
|
29462
|
-
|
|
29463
|
-
|
|
30483
|
+
join41(here, "..", "..", "package.json"),
|
|
30484
|
+
join41(here, "..", "package.json")
|
|
29464
30485
|
];
|
|
29465
30486
|
for (const p of candidates) {
|
|
29466
30487
|
if (existsSync46(p)) {
|
|
@@ -29532,28 +30553,19 @@ async function main() {
|
|
|
29532
30553
|
}
|
|
29533
30554
|
});
|
|
29534
30555
|
renderer.flush();
|
|
29535
|
-
|
|
29536
|
-
if (!result.text) {
|
|
29537
|
-
console.log(pc2.yellow(t("cli.no_output")));
|
|
29538
|
-
}
|
|
29539
|
-
} else {
|
|
29540
|
-
console.error(`${t("error.prefix")}${result.error}`);
|
|
29541
|
-
if (result.text) {
|
|
29542
|
-
console.log(formatMarkdown(result.text));
|
|
29543
|
-
}
|
|
29544
|
-
process.exit(1);
|
|
29545
|
-
}
|
|
30556
|
+
const exitCode = printRunResult(result, () => renderer.flush());
|
|
29546
30557
|
agent.shutdown();
|
|
30558
|
+
process.exit(exitCode);
|
|
29547
30559
|
} else {
|
|
29548
|
-
const configPath =
|
|
30560
|
+
const configPath = join41(homedir18(), ".mma", "config.json");
|
|
29549
30561
|
if (!existsSync46(configPath)) {
|
|
29550
30562
|
console.log(pc2.yellow(`
|
|
29551
30563
|
` + t("cli.first_run") + `
|
|
29552
30564
|
`));
|
|
29553
30565
|
const answers = await runSetup();
|
|
29554
30566
|
const config2 = loadConfig({
|
|
29555
|
-
configDir:
|
|
29556
|
-
projectConfigPath: projectDir ?
|
|
30567
|
+
configDir: join41(homedir18(), ".mma"),
|
|
30568
|
+
projectConfigPath: projectDir ? join41(projectDir, ".mmrc") : join41(process.cwd(), ".mmrc")
|
|
29557
30569
|
});
|
|
29558
30570
|
config2.provider.type = answers.provider;
|
|
29559
30571
|
config2.provider.baseUrl = answers.apiBase;
|
|
@@ -29606,7 +30618,7 @@ async function main() {
|
|
|
29606
30618
|
logger
|
|
29607
30619
|
} = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
|
|
29608
30620
|
startAutoUpdate(config);
|
|
29609
|
-
const repl = new Repl(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger);
|
|
30621
|
+
const repl = new Repl(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger, true);
|
|
29610
30622
|
repl.start();
|
|
29611
30623
|
}
|
|
29612
30624
|
}
|