micro-models-agent 0.33.1 → 0.33.3

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.
Files changed (2) hide show
  1. package/dist/main.js +502 -189
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2472,6 +2472,8 @@ Command: {command}`,
2472
2472
  "todo.added": "Added {count} todo(s): {items}",
2473
2473
  "todo.marked_done": "Marked {count} item(s) as done",
2474
2474
  "todo.no_active": "No active todos",
2475
+ "todo.no_items": "No todo items specified — provide items to mark done",
2476
+ "todo.subtask_not_found": "No matching sub-task(s) found for: {items}",
2475
2477
  "todo.unknown_action": "Unknown todo action: {action}",
2476
2478
  "todo.acknowledged": "Todo acknowledged",
2477
2479
  "verify.passed": "Verification passed",
@@ -2634,6 +2636,7 @@ Available commands:`,
2634
2636
  "repl.skill_unknown_sub": "Unknown skill subcommand: {subcmd}",
2635
2637
  "repl.skill_usage": "Usage: /skill [list|loaded|load|unload|search]",
2636
2638
  "repl.agent": "Agent: ",
2639
+ "repl.you": "You: ",
2637
2640
  "repl.interrupt": "Interrupted (Esc)",
2638
2641
  "repl.title": "MMA REPL v{version}",
2639
2642
  "repl.model": "Model:",
@@ -2739,6 +2742,8 @@ Use this knowledge to answer the user's question.`,
2739
2742
  "exec.tool_errors_recovery": "Tool {tool} has failed {count} times in a row. Try an alternative: create files directly via write_file, use a different command, or if nothing works — skip this step via plan update step=N status=skipped with a note explaining why.",
2740
2743
  "exec.repetitive_tool": "Called {tool} {count} times with identical arguments and result. Try a different approach — create files directly, change arguments, or check process status via process_log.",
2741
2744
  "exec.consecutive_failures_recovery": "{count} consecutive tool failures. Create files directly via write_file instead of terminal commands. Check that dependencies are installed (npm install). Do not run build/tests until all files are created.",
2745
+ "exec.read_only_loop": "No write/exec for {count} tool calls — the agent is only reading/exploring.",
2746
+ "exec.read_only_loop_recovery": "{count} consecutive read-only tool calls (read_file/glob/grep/browser) with no writes. STOP exploring and make the edit the task requires: read the file, then call write_file or edit_file. If you cannot finish the task, ask the user instead of re-reading the same files.",
2742
2747
  "exec.plan_warning": 'Current plan step {step} is "{description}", but {tool} is being called for files outside this step. Complete the current step first, then call plan update step={step} status=done before moving to the next step.',
2743
2748
  "exec.plan_blocked": "{max} consecutive calls outside the current step. Finish step {step} before proceeding — other steps should wait until this one is complete.",
2744
2749
  "exec.off_track": 'Step {stepId} — "{description}" — but you are using {tool} on a different path. Return to the current step.',
@@ -3049,6 +3054,8 @@ var init_ru = __esm(() => {
3049
3054
  "todo.added": "Добавлено {count} задач: {items}",
3050
3055
  "todo.marked_done": "Отмечено выполненными: {count}",
3051
3056
  "todo.no_active": "Нет активных задач",
3057
+ "todo.no_items": "Не указаны подзадачи — укажите items для отметки выполненными",
3058
+ "todo.subtask_not_found": "Подзадачи не найдены: {items}",
3052
3059
  "todo.unknown_action": "Неизвестное действие todo: {action}",
3053
3060
  "todo.acknowledged": "Todo принято",
3054
3061
  "verify.passed": "Проверка пройдена",
@@ -3207,6 +3214,7 @@ var init_ru = __esm(() => {
3207
3214
  "repl.skill_unknown_sub": "Неизвестная подкоманда скилла: {subcmd}",
3208
3215
  "repl.skill_usage": "Использование: /skill [list|loaded|load|unload|search]",
3209
3216
  "repl.agent": "Агент: ",
3217
+ "repl.you": "Вы: ",
3210
3218
  "repl.interrupt": "Прервано (Esc)",
3211
3219
  "repl.title": "MMA REPL v{version}",
3212
3220
  "repl.model": "Модель:",
@@ -3316,6 +3324,8 @@ var init_ru = __esm(() => {
3316
3324
  "exec.tool_errors_recovery": "Инструмент {tool} упал {count} раз подряд. Попробуйте альтернативу: создайте файлы напрямую через write_file, используйте другую команду, или пропустите этот шаг через plan update step=N status=skipped с пометкой почему.",
3317
3325
  "exec.repetitive_tool": "Инструмент {tool} вызван {count} раз с одинаковыми аргументами и результатом. Попробуйте другой подход — создайте файлы напрямую, измените аргументы или проверьте статус процесса через process_log.",
3318
3326
  "exec.consecutive_failures_recovery": "{count} инструментов подряд упали. Создавайте файлы напрямую через write_file вместо команд терминала. Проверьте что зависимости установлены (npm install). Не запускайте сборку/тесты пока не созданы все файлы.",
3327
+ "exec.read_only_loop": "Нет записи/выполнения за {count} вызовов — агент только читает/исследует.",
3328
+ "exec.read_only_loop_recovery": "{count} вызовов только для чтения подряд (read_file/glob/grep/browser) без записи. Хватит исследовать — внесите правку, которую требует задача: прочитайте файл, затем вызовите write_file или edit_file. Если не можете завершить задачу — спросите пользователя, а не перечитывайте одни и те же файлы.",
3319
3329
  "exec.plan_warning": 'Текущий шаг плана {step} — "{description}", но вызывается {tool} для файлов вне этого шага. Завершите текущий шаг, вызовите plan update step={step} status=done, затем переходите к следующему.',
3320
3330
  "exec.plan_blocked": "{max} вызовов подряд вне текущего шага. Завершите шаг {step} — остальные шаги ждут пока этот не будет выполнен.",
3321
3331
  "exec.off_track": 'Шаг {stepId} — "{description}", но используется {tool} для другого пути. Вернитесь к текущему шагу.',
@@ -6016,20 +6026,16 @@ function safeResolvePath(baseDir, userPath) {
6016
6026
  }
6017
6027
  var init_path_utils = () => {};
6018
6028
 
6019
- // src/tools/preview.ts
6020
- var MAX_PREVIEW_LINES = 15;
6021
-
6022
6029
  // src/tools/read-file.ts
6023
6030
  import { readFileSync as readFileSync5, existsSync as existsSync10 } from "fs";
6024
6031
  import { extname } from "path";
6025
- var DEFAULT_LIMIT, readFileTool;
6032
+ var DEFAULT_LIMIT = 300, readFileTool;
6026
6033
  var init_read_file = __esm(() => {
6027
6034
  init_i18n();
6028
6035
  init_path_validator();
6029
6036
  init_security();
6030
6037
  init_audit_log();
6031
6038
  init_path_utils();
6032
- DEFAULT_LIMIT = MAX_PREVIEW_LINES;
6033
6039
  readFileTool = {
6034
6040
  name: "read_file",
6035
6041
  description: `Read a file from the filesystem. Reads up to ${DEFAULT_LIMIT} lines at a time by default; use offset to page through large files.`,
@@ -6538,6 +6544,9 @@ var init_edit_file = __esm(() => {
6538
6544
  };
6539
6545
  });
6540
6546
 
6547
+ // src/tools/preview.ts
6548
+ var MAX_PREVIEW_LINES = 15;
6549
+
6541
6550
  // src/tools/glob-tool.ts
6542
6551
  import { globSync } from "fs";
6543
6552
  var globTool;
@@ -9195,6 +9204,7 @@ class StuckDetector {
9195
9204
  lastBashCommand = "";
9196
9205
  lastBashOutput = "";
9197
9206
  emptyBashRunCount = 0;
9207
+ readOnlyStreak = 0;
9198
9208
  constructor(threshold = 6, errorThreshold = 3) {
9199
9209
  this.threshold = threshold;
9200
9210
  this.errorThreshold = errorThreshold;
@@ -9212,6 +9222,14 @@ class StuckDetector {
9212
9222
  if (this.recentToolCalls.length > this.maxRecentCalls) {
9213
9223
  this.recentToolCalls.shift();
9214
9224
  }
9225
+ if (READ_ONLY_TOOLS.has(name)) {
9226
+ this.readOnlyStreak++;
9227
+ } else {
9228
+ this.readOnlyStreak = 0;
9229
+ }
9230
+ }
9231
+ hasReadOnlyLoop() {
9232
+ return this.readOnlyStreak >= READ_ONLY_LOOP_THRESHOLD;
9215
9233
  }
9216
9234
  recordToolError(toolName, output) {
9217
9235
  this.toolErrors.set(toolName, (this.toolErrors.get(toolName) || 0) + 1);
@@ -9329,6 +9347,9 @@ class StuckDetector {
9329
9347
  if (this.hasConsecutiveFailures()) {
9330
9348
  hints.push("Multiple different tools are failing. Check if the environment is set up correctly.");
9331
9349
  }
9350
+ if (this.hasReadOnlyLoop()) {
9351
+ hints.push("You have made many read-only tool calls (read_file/glob/grep/browser) without writing anything. Stop exploring — make the edit/write the task needs, or use the plan tool to decide next steps.");
9352
+ }
9332
9353
  return hints;
9333
9354
  }
9334
9355
  getActionableHints() {
@@ -9444,6 +9465,11 @@ class StuckDetector {
9444
9465
  if (errorTool) {
9445
9466
  return t("exec.tool_errors", { tool: errorTool[0], count: errorTool[1] });
9446
9467
  }
9468
+ if (this.hasReadOnlyLoop()) {
9469
+ return t("exec.read_only_loop", {
9470
+ count: String(this.readOnlyStreak)
9471
+ });
9472
+ }
9447
9473
  return "";
9448
9474
  }
9449
9475
  getRecoveryMessage() {
@@ -9469,6 +9495,11 @@ class StuckDetector {
9469
9495
  if (this.hasRepetitiveToolCalls()) {
9470
9496
  return this.getRepetitiveToolMessage();
9471
9497
  }
9498
+ if (this.hasReadOnlyLoop()) {
9499
+ return t("exec.read_only_loop_recovery", {
9500
+ count: String(this.readOnlyStreak)
9501
+ });
9502
+ }
9472
9503
  return "";
9473
9504
  }
9474
9505
  reset() {
@@ -9484,6 +9515,20 @@ class StuckDetector {
9484
9515
  this.lastBashCommand = "";
9485
9516
  this.lastBashOutput = "";
9486
9517
  this.emptyBashRunCount = 0;
9518
+ this.readOnlyStreak = 0;
9519
+ }
9520
+ resetStepProgress() {
9521
+ this.currentStepId = null;
9522
+ this.iterationsOnCurrentStep = 0;
9523
+ this.toolErrors.clear();
9524
+ this.consecutiveFailures = 0;
9525
+ this.lastFailedTool = "";
9526
+ this.lastErrorOutput = "";
9527
+ this.fileRewriteCount.clear();
9528
+ this.escalationCount = 0;
9529
+ this.lastBashCommand = "";
9530
+ this.lastBashOutput = "";
9531
+ this.emptyBashRunCount = 0;
9487
9532
  }
9488
9533
  resetStepState(stepId) {
9489
9534
  this.currentStepId = stepId;
@@ -9497,10 +9542,33 @@ class StuckDetector {
9497
9542
  this.lastBashCommand = "";
9498
9543
  this.lastBashOutput = "";
9499
9544
  this.emptyBashRunCount = 0;
9545
+ this.readOnlyStreak = 0;
9500
9546
  }
9501
9547
  }
9548
+ var READ_ONLY_TOOLS, READ_ONLY_LOOP_THRESHOLD = 10;
9502
9549
  var init_stuck_detector = __esm(() => {
9503
9550
  init_i18n();
9551
+ READ_ONLY_TOOLS = new Set([
9552
+ "read_file",
9553
+ "glob",
9554
+ "grep",
9555
+ "list_dir",
9556
+ "file_info",
9557
+ "browser",
9558
+ "web_search",
9559
+ "web_fetch",
9560
+ "web_browse",
9561
+ "search_history",
9562
+ "recall",
9563
+ "project_map",
9564
+ "chunk_query",
9565
+ "process_list",
9566
+ "process_log",
9567
+ "plan",
9568
+ "todo",
9569
+ "verify",
9570
+ "load_skill"
9571
+ ]);
9504
9572
  });
9505
9573
 
9506
9574
  // src/modules/artifacts/store.ts
@@ -10406,6 +10474,9 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10406
10474
  }).catch(() => {});
10407
10475
  }
10408
10476
  }
10477
+ if (typeof contextManager.resetUserTurn === "function") {
10478
+ contextManager.resetUserTurn();
10479
+ }
10409
10480
  contextManager.addMessage({ role: "user", content: input });
10410
10481
  slog.logUser(input);
10411
10482
  if (config.moe?.enabled) {
@@ -10445,6 +10516,9 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10445
10516
  const MAX_HALLUCINATION_RETRIES = 3;
10446
10517
  let consecutiveToolFailures = 0;
10447
10518
  const MAX_CONSECUTIVE_TOOL_FAILURES = 5;
10519
+ const toolFailureCounts = new Map;
10520
+ const memoryRuleRecorded = new Set;
10521
+ const MIN_REPEATED_TOOL_FAILURES = 3;
10448
10522
  let auditRetries = 0;
10449
10523
  const MAX_AUDIT_RETRIES = 3;
10450
10524
  let emptyResponseRetries = 0;
@@ -10684,6 +10758,25 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10684
10758
  contextManager.compact();
10685
10759
  logger.debug("Context compacted after tool result");
10686
10760
  }
10761
+ if (!result.success) {
10762
+ const key = call.name;
10763
+ const prev = toolFailureCounts.get(key) ?? { count: 0, error: "" };
10764
+ prev.count++;
10765
+ prev.error = String(result.output ?? "").slice(0, 200);
10766
+ toolFailureCounts.set(key, prev);
10767
+ if (prev.count >= MIN_REPEATED_TOOL_FAILURES && !memoryRuleRecorded.has(key)) {
10768
+ memoryRuleRecorded.add(key);
10769
+ if (sessionManager) {
10770
+ const activeSession = sessionManager.getActiveMeta();
10771
+ if (activeSession) {
10772
+ const memDir = join12(baseDir, ".mma", "memory");
10773
+ const memStore = new MemoryStore(memDir);
10774
+ memStore.appendRule("errors", `Tool ${key} failed ${prev.count}x (${prev.error})`, `Repeated ${key} failures suggest a systemic problem (config, environment, or a broken tool), not a one-off`, "Check the error message, verify the tool's dependencies are installed/configured, and consider a different tool");
10775
+ logger.warn(`Recorded repeated ${key} failures to memory (${prev.count}x)`);
10776
+ }
10777
+ }
10778
+ }
10779
+ }
10687
10780
  }
10688
10781
  if (anyToolFailed) {
10689
10782
  consecutiveToolFailures++;
@@ -11024,6 +11117,7 @@ class ContextManager {
11024
11117
  fileFacts = [];
11025
11118
  decisionFacts = [];
11026
11119
  errorFacts = [];
11120
+ lastUserTask = "";
11027
11121
  static MAX_FACTS = 20;
11028
11122
  tokenCounter;
11029
11123
  pendingImageParts = [];
@@ -11060,6 +11154,10 @@ class ContextManager {
11060
11154
  noteIteration() {
11061
11155
  this.iterationsSinceCompaction++;
11062
11156
  }
11157
+ resetUserTurn() {
11158
+ this.iterationsSinceCompaction = 0;
11159
+ this.lastUserTask = "";
11160
+ }
11063
11161
  getQuality() {
11064
11162
  const usedTokens = this.getEstimatedTokens();
11065
11163
  const tokenLoad = Math.max(0, 1 - usedTokens / this.budget.history);
@@ -11072,6 +11170,12 @@ class ContextManager {
11072
11170
  return Math.round(Math.min(100, Math.max(0, score * 100)));
11073
11171
  }
11074
11172
  addMessage(msg) {
11173
+ if (msg.role === "user" && !this.lastUserTask) {
11174
+ const text = typeof msg.content === "string" ? msg.content : getMessageText(msg.content);
11175
+ if (text.trim() && !text.startsWith("<system-summary>") && !text.includes("[Compressed:")) {
11176
+ this.lastUserTask = text.trim();
11177
+ }
11178
+ }
11075
11179
  if (msg.role === "user" && this.pendingImageParts.length > 0) {
11076
11180
  const textPart = {
11077
11181
  type: "text",
@@ -11161,6 +11265,10 @@ class ContextManager {
11161
11265
  this.extractFacts(oldTurns);
11162
11266
  const parts = [];
11163
11267
  parts.push(`[Compressed: ${oldTurns.length} old turns removed]`);
11268
+ if (this.lastUserTask) {
11269
+ const task = this.lastUserTask.slice(0, 400);
11270
+ parts.push(`[Task: ${task}]`);
11271
+ }
11164
11272
  if (this.fileFacts.length > 0) {
11165
11273
  parts.push(`[Files: ${this.fileFacts.slice(-15).join("; ")}]`);
11166
11274
  }
@@ -11200,10 +11308,12 @@ ${lines.join(`
11200
11308
  }
11201
11309
  }
11202
11310
  extractFacts(turns) {
11311
+ const DRIVE = "(?:[a-zA-Z]:[\\\\/])?";
11203
11312
  const filePatterns = [
11204
- /(?:Created|Updated|Written|Deleted|Moved) ([\w./\\-]+\.[a-z]+)/gi,
11205
- /Файл (?:создан|обновлён|записан|удалён|перемещён):? ([\w./\\-]+\.[a-z]+)/gi,
11206
- /file (?:created|updated|written|deleted|moved):? ([\w./\\-]+\.[a-z]+)/gi
11313
+ new RegExp(`(?:Created|Updated|Written|Deleted|Moved) ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
11314
+ new RegExp(`Replaced in ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
11315
+ new RegExp(`Файл (?:создан|обновлён|записан|удалён|перемещён):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
11316
+ new RegExp(`file (?:created|updated|written|deleted|moved):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi")
11207
11317
  ];
11208
11318
  const newFiles = [];
11209
11319
  const newDecisions = [];
@@ -11263,6 +11373,7 @@ ${lines.join(`
11263
11373
  this.iterationsSinceCompaction = 0;
11264
11374
  this.compactionCount = 0;
11265
11375
  this.peakTokens = 0;
11376
+ this.lastUserTask = "";
11266
11377
  }
11267
11378
  getEstimatedTokens() {
11268
11379
  return this.messages.reduce((sum, m) => sum + this.estimateMessageTokens(m), 0) + this.toolTokens;
@@ -11382,12 +11493,15 @@ function isFilePathLike(s) {
11382
11493
  const lower = s.toLowerCase();
11383
11494
  if (TECH_NAMES.has(lower))
11384
11495
  return false;
11385
- if (!s.includes("/") && !s.includes("\\") && !/^\w+\.[a-z]{2,4}$/i.test(s))
11386
- return false;
11387
11496
  if (isJsMemberAccess(s))
11388
11497
  return false;
11389
11498
  const ext = s.split(".").pop()?.toLowerCase() || "";
11390
- return !NON_FILE_EXTENSIONS.has(ext);
11499
+ if (!s.includes("/") && !s.includes("\\")) {
11500
+ if (!/^\w+\.[a-z]{1,6}$/i.test(s))
11501
+ return false;
11502
+ return FILE_EXTENSIONS.has(ext);
11503
+ }
11504
+ return true;
11391
11505
  }
11392
11506
  function extractFileLikeTokens(text) {
11393
11507
  const matches = text.match(FILE_TOKEN_RE) || [];
@@ -11396,7 +11510,7 @@ function extractFileLikeTokens(text) {
11396
11510
  function stripUrls(text) {
11397
11511
  return text.replace(/\bhttps?:\/\/[^\s"'<>]+/gi, " ");
11398
11512
  }
11399
- var JS_GLOBALS, NON_FILE_EXTENSIONS, TECH_NAMES, FILE_TOKEN_RE;
11513
+ var JS_GLOBALS, FILE_EXTENSIONS, TECH_NAMES, FILE_TOKEN_RE;
11400
11514
  var init_js_identifiers = __esm(() => {
11401
11515
  JS_GLOBALS = new Set([
11402
11516
  "process",
@@ -11454,27 +11568,110 @@ var init_js_identifiers = __esm(() => {
11454
11568
  "deno",
11455
11569
  "node"
11456
11570
  ]);
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"
11571
+ FILE_EXTENSIONS = new Set([
11572
+ "ts",
11573
+ "tsx",
11574
+ "js",
11575
+ "jsx",
11576
+ "mjs",
11577
+ "cjs",
11578
+ "py",
11579
+ "pyc",
11580
+ "rb",
11581
+ "go",
11582
+ "rs",
11583
+ "java",
11584
+ "jar",
11585
+ "kt",
11586
+ "kts",
11587
+ "c",
11588
+ "h",
11589
+ "cc",
11590
+ "cpp",
11591
+ "cxx",
11592
+ "hpp",
11593
+ "hh",
11594
+ "cs",
11595
+ "php",
11596
+ "swift",
11597
+ "m",
11598
+ "mm",
11599
+ "lua",
11600
+ "pl",
11601
+ "sh",
11602
+ "bash",
11603
+ "zsh",
11604
+ "fish",
11605
+ "bat",
11606
+ "cmd",
11607
+ "ps1",
11608
+ "vue",
11609
+ "svelte",
11610
+ "dart",
11611
+ "json",
11612
+ "jsonc",
11613
+ "json5",
11614
+ "yaml",
11615
+ "yml",
11616
+ "toml",
11617
+ "ini",
11618
+ "cfg",
11619
+ "conf",
11620
+ "env",
11621
+ "xml",
11622
+ "html",
11623
+ "htm",
11624
+ "md",
11625
+ "markdown",
11626
+ "rst",
11627
+ "txt",
11628
+ "log",
11629
+ "csv",
11630
+ "tsv",
11631
+ "lock",
11632
+ "sql",
11633
+ "sqlite",
11634
+ "db",
11635
+ "wasm",
11636
+ "map",
11637
+ "css",
11638
+ "scss",
11639
+ "sass",
11640
+ "less",
11641
+ "svg",
11642
+ "png",
11643
+ "jpg",
11644
+ "jpeg",
11645
+ "gif",
11646
+ "webp",
11647
+ "bmp",
11648
+ "ico",
11649
+ "avif",
11650
+ "tiff",
11651
+ "pdf",
11652
+ "doc",
11653
+ "docx",
11654
+ "xls",
11655
+ "xlsx",
11656
+ "ppt",
11657
+ "pptx",
11658
+ "odt",
11659
+ "ods",
11660
+ "zip",
11661
+ "gz",
11662
+ "tar",
11663
+ "tgz",
11664
+ "bz2",
11665
+ "xz",
11666
+ "7z",
11667
+ "rar",
11668
+ "bin",
11669
+ "exe",
11670
+ "dll",
11671
+ "so",
11672
+ "o",
11673
+ "a",
11674
+ "dylib"
11478
11675
  ]);
11479
11676
  TECH_NAMES = new Set([
11480
11677
  "node.js",
@@ -11488,7 +11685,7 @@ var init_js_identifiers = __esm(() => {
11488
11685
  "svelte.js",
11489
11686
  "jquery.js"
11490
11687
  ]);
11491
- FILE_TOKEN_RE = /\b(?:[a-zA-Z]:[\\/])?[\w./\\-]+\.[a-z]{2,6}\b/gi;
11688
+ FILE_TOKEN_RE = /\b(?:[a-zA-Z]:[\\/])?[\w./\\-]+\.[a-z]{1,6}\b/gi;
11492
11689
  });
11493
11690
 
11494
11691
  // src/modules/hallucination/factual.ts
@@ -12383,7 +12580,7 @@ var init_web_search = __esm(() => {
12383
12580
  init_session_isolation();
12384
12581
  webSearchTool = {
12385
12582
  name: "web_search",
12386
- description: "Search the web for information. Returns search results with titles and snippets.",
12583
+ description: "Search the web for information. Returns search results with titles and snippets. Use this for search queries instead of opening search engines (Google/Yandex/Bing) in the browser — they block headless browsers.",
12387
12584
  tags: ["research"],
12388
12585
  parameters: {
12389
12586
  type: "object",
@@ -14654,6 +14851,7 @@ function createBrowserTool() {
14654
14851
  description: [
14655
14852
  "Control a headless browser. Navigate pages, click elements, type text, scroll, take screenshots.",
14656
14853
  "Runs a real browser with JavaScript enabled — use it for JS-rendered sites (weather, dashboards, SPAs) where web_fetch/web_browse return empty content.",
14854
+ "Do NOT use it for search queries: search engines (Google, Yandex, Bing) block headless browsers with CAPTCHA/429/redirect pages — use the web_search tool for searching.",
14657
14855
  "Each snapshot returns: a numbered list of interactive elements, the visible page text (Content section), browser console messages, and network errors.",
14658
14856
  "Use the Content section to understand what the page says; use element numbers as targets for click/type.",
14659
14857
  "Actions: open (url), click (target), type (target, text), scroll (direction), back, forward, screenshot, snapshot, close, wait (ms)."
@@ -15364,6 +15562,9 @@ class PlanCreator {
15364
15562
  const icon = step.status === "done" ? "[x]" : step.status === "in_progress" ? "[*]" : step.status === "failed" ? "[!]" : step.status === "skipped" ? "[-]" : "[ ]";
15365
15563
  const note = step.note ? ` — ${step.note}` : "";
15366
15564
  lines.push(`${icon} ${step.id}. ${step.description}${note}`);
15565
+ for (const sub of step.subtasks ?? []) {
15566
+ lines.push(` ${sub.done ? "[x]" : "[ ]"} ${sub.text}`);
15567
+ }
15367
15568
  }
15368
15569
  return lines.join(`
15369
15570
  `);
@@ -15432,7 +15633,40 @@ var init_tracker = () => {};
15432
15633
 
15433
15634
  // src/modules/execution/auditor.ts
15434
15635
  import { existsSync as existsSync27, readdirSync as readdirSync8 } from "fs";
15435
- import { resolve as resolve17, join as join22 } from "path";
15636
+ import { resolve as resolve17, join as join22, basename as basename2 } from "path";
15637
+ function findExistingFile(baseDir, filePath) {
15638
+ const direct = resolve17(baseDir, filePath);
15639
+ if (existsSync27(direct))
15640
+ return direct;
15641
+ const name = basename2(filePath).toLowerCase();
15642
+ const suffix = filePath.replace(/\\/g, "/").toLowerCase();
15643
+ let found = null;
15644
+ const walk = (dir, depth) => {
15645
+ if (found || depth > RESOLVE_MAX_DEPTH)
15646
+ return;
15647
+ let entries;
15648
+ try {
15649
+ entries = readdirSync8(dir, { withFileTypes: true });
15650
+ } catch {
15651
+ return;
15652
+ }
15653
+ for (const e of entries) {
15654
+ if (found)
15655
+ return;
15656
+ const full = join22(dir, e.name);
15657
+ if (e.isDirectory()) {
15658
+ if (SKIP_DIRS.has(e.name))
15659
+ continue;
15660
+ walk(full, depth + 1);
15661
+ } else if (e.name.toLowerCase() === name || full.replace(/\\/g, "/").toLowerCase().endsWith("/" + suffix)) {
15662
+ found = full;
15663
+ return;
15664
+ }
15665
+ }
15666
+ };
15667
+ walk(baseDir, 0);
15668
+ return found;
15669
+ }
15436
15670
  function findTestFile(dir, depth = 0) {
15437
15671
  if (depth > 5)
15438
15672
  return null;
@@ -15519,8 +15753,8 @@ class Auditor {
15519
15753
  const missingFiles = [];
15520
15754
  const existingFiles = [];
15521
15755
  for (const filePath of uniqueFiles) {
15522
- const resolved = resolve17(this.baseDir, filePath);
15523
- if (existsSync27(resolved)) {
15756
+ const resolved = findExistingFile(this.baseDir, filePath);
15757
+ if (resolved) {
15524
15758
  existingFiles.push(filePath);
15525
15759
  } else {
15526
15760
  missingFiles.push(filePath);
@@ -15577,7 +15811,7 @@ class Auditor {
15577
15811
  };
15578
15812
  }
15579
15813
  }
15580
- var MASS_EDIT_THRESHOLD = 10, SKIP_DIRS, TEST_EXT_RE, TEST_STEP_RE;
15814
+ var MASS_EDIT_THRESHOLD = 10, SKIP_DIRS, TEST_EXT_RE, TEST_STEP_RE, RESOLVE_MAX_DEPTH = 8;
15581
15815
  var init_auditor = __esm(() => {
15582
15816
  init_i18n();
15583
15817
  init_js_identifiers();
@@ -15770,7 +16004,7 @@ function extractFilePaths(text) {
15770
16004
  }
15771
16005
  return result;
15772
16006
  }
15773
- function basename2(p) {
16007
+ function basename3(p) {
15774
16008
  const parts = p.split(/[/\\]/);
15775
16009
  return parts[parts.length - 1] ?? p;
15776
16010
  }
@@ -15782,7 +16016,7 @@ function checkPlanCoverage(taskText, stepDescriptions) {
15782
16016
  `);
15783
16017
  const missing = taskPaths.filter((p) => {
15784
16018
  const lower = p.toLowerCase();
15785
- const base = basename2(lower);
16019
+ const base = basename3(lower);
15786
16020
  return !stepText.includes(lower) && !stepText.includes(base);
15787
16021
  });
15788
16022
  return { missing };
@@ -16044,6 +16278,23 @@ ${lines.join(`
16044
16278
  };
16045
16279
  }
16046
16280
  if (action === "show") {
16281
+ const planId = args.id ? String(args.id) : "";
16282
+ if (planId && planId !== this.tracker?.getPlan()?.id) {
16283
+ const found = this.store.find(planId);
16284
+ if (!found) {
16285
+ return {
16286
+ success: false,
16287
+ output: t("plan.not_found", { id: planId })
16288
+ };
16289
+ }
16290
+ const display2 = PlanCreator.toPromptBlock(found.plan, 0);
16291
+ return {
16292
+ success: true,
16293
+ output: `${t("plan.show_header")}
16294
+ ${display2}`,
16295
+ display: display2
16296
+ };
16297
+ }
16047
16298
  if (!this.tracker) {
16048
16299
  return { success: false, output: t("plan.no_active") };
16049
16300
  }
@@ -16157,38 +16408,70 @@ ${progress}`,
16157
16408
  }
16158
16409
  if (action === "add" && Array.isArray(args.items)) {
16159
16410
  const items = args.items.map(String);
16160
- currentStep.note = currentStep.note ? `${currentStep.note}; ${items.join(", ")}` : items.join(", ");
16411
+ const existing = currentStep.subtasks ?? [];
16412
+ let nextId = existing.reduce((m, s) => Math.max(m, s.id), 0) + 1;
16413
+ for (const item of items) {
16414
+ existing.push({ id: nextId++, text: item, done: false });
16415
+ }
16416
+ currentStep.subtasks = existing;
16417
+ this.store.saveActive(this.tracker.getPlan());
16418
+ const display = this.tracker.toPromptBlock();
16161
16419
  return {
16162
16420
  success: true,
16163
16421
  output: t("todo.added", {
16164
16422
  count: String(items.length),
16165
16423
  items: items.join(", ")
16166
- })
16424
+ }),
16425
+ display
16167
16426
  };
16168
16427
  }
16169
16428
  if (action === "done") {
16170
- if (!currentStep) {
16171
- return { success: false, output: t("plan.step_not_found") };
16429
+ const items = Array.isArray(args.items) ? args.items.map(String) : [];
16430
+ if (items.length === 0) {
16431
+ return {
16432
+ success: false,
16433
+ output: t("todo.no_items")
16434
+ };
16172
16435
  }
16173
- this.tracker.updateStepStatus(currentStep.id, "done");
16174
- this.tracker.syncCurrentStep();
16436
+ const subs = currentStep.subtasks ?? [];
16437
+ let marked = 0;
16438
+ for (const item of items) {
16439
+ const sub = subs.find((s) => !s.done && s.text.toLowerCase() === item.toLowerCase());
16440
+ if (sub) {
16441
+ sub.done = true;
16442
+ marked++;
16443
+ }
16444
+ }
16445
+ if (marked === 0) {
16446
+ return {
16447
+ success: false,
16448
+ output: t("todo.subtask_not_found", {
16449
+ items: items.join(", ")
16450
+ })
16451
+ };
16452
+ }
16453
+ currentStep.subtasks = subs;
16175
16454
  this.store.saveActive(this.tracker.getPlan());
16455
+ const doneCount = subs.filter((s) => s.done).length;
16176
16456
  const display = this.tracker.toPromptBlock();
16177
- return {
16178
- success: true,
16179
- output: t("plan.step_status", {
16180
- step: String(currentStep.id),
16181
- status: "done"
16182
- }),
16183
- display
16184
- };
16457
+ let output = t("todo.marked_done", {
16458
+ count: String(marked)
16459
+ });
16460
+ output += ` (${doneCount}/${subs.length})`;
16461
+ if (doneCount === subs.length) {
16462
+ output += `
16463
+ All sub-tasks done — call plan update step=${currentStep.id} status=done to complete this step.`;
16464
+ }
16465
+ return { success: true, output, display };
16185
16466
  }
16186
16467
  if (action === "list") {
16187
- const note = currentStep.note || "(no sub-tasks)";
16468
+ const subs = currentStep.subtasks ?? [];
16469
+ const lines = subs.length ? subs.map((s) => `${s.done ? "[x]" : "[ ]"} ${s.text}`) : ["(no sub-tasks)"];
16188
16470
  return {
16189
16471
  success: true,
16190
16472
  output: `Step ${currentStep.id}: ${currentStep.description}
16191
- Sub-tasks: ${note}`
16473
+ ${lines.join(`
16474
+ `)}`
16192
16475
  };
16193
16476
  }
16194
16477
  return {
@@ -16233,7 +16516,7 @@ Sub-tasks: ${note}`
16233
16516
  }
16234
16517
  }
16235
16518
  if (this.tracker?.isComplete()) {
16236
- this.stuckDetector.reset();
16519
+ this.stuckDetector.resetStepProgress();
16237
16520
  this.consecutivePlanWarnings = 0;
16238
16521
  this.lastStepId = -1;
16239
16522
  this.stuckNotified = false;
@@ -16277,7 +16560,7 @@ Sub-tasks: ${note}`
16277
16560
  this.stuckNotified = true;
16278
16561
  }
16279
16562
  }
16280
- if (this.stuckDetector.isStuck() || this.stuckDetector.hasRepetitiveToolCalls()) {
16563
+ if (this.stuckDetector.isStuck() || this.stuckDetector.hasRepetitiveToolCalls() || this.stuckDetector.hasReadOnlyLoop()) {
16281
16564
  const currentIter = typeof ctx.iteration === "number" ? ctx.iteration : 0;
16282
16565
  if (currentIter - this.lastRecoveryIteration >= STUCK_RECOVERY_COOLDOWN) {
16283
16566
  const recovery = this.stuckDetector.getRecoveryMessage();
@@ -17465,6 +17748,31 @@ var init_browser2 = __esm(() => {
17465
17748
  init_types();
17466
17749
  });
17467
17750
 
17751
+ // src/modules/lsp/command.ts
17752
+ import { delimiter, join as join28 } from "path";
17753
+ import { existsSync as existsSync34 } from "fs";
17754
+ import { platform as platform5 } from "os";
17755
+ function resolveSpawnCommand(command, platformName = platform5(), pathEnv = process.env.PATH ?? "") {
17756
+ if (platformName !== "win32")
17757
+ return command;
17758
+ if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
17759
+ return command;
17760
+ }
17761
+ const dirs = pathEnv.split(delimiter).filter(Boolean);
17762
+ for (const dir of dirs) {
17763
+ for (const ext of WIN_EXTS) {
17764
+ const candidate = join28(dir, `${command}${ext}`);
17765
+ if (existsSync34(candidate))
17766
+ return `${command}${ext}`;
17767
+ }
17768
+ }
17769
+ return command;
17770
+ }
17771
+ var WIN_EXTS;
17772
+ var init_command = __esm(() => {
17773
+ WIN_EXTS = [".cmd", ".bat", ".exe", ".com"];
17774
+ });
17775
+
17468
17776
  // src/modules/lsp/client.ts
17469
17777
  import { spawn as spawn6, execSync as execSync2 } from "child_process";
17470
17778
  import { resolve as resolve19 } from "path";
@@ -17530,7 +17838,7 @@ class LspClient {
17530
17838
  }
17531
17839
  return new Promise((resolve20, reject) => {
17532
17840
  const args = config.args ?? [];
17533
- const proc = spawn6(config.command, args, {
17841
+ const proc = spawn6(resolveSpawnCommand(config.command), args, {
17534
17842
  stdio: ["pipe", "pipe", "pipe"],
17535
17843
  env: { ...process.env, ...config.env },
17536
17844
  cwd: baseDir
@@ -17695,10 +18003,12 @@ class LspClient {
17695
18003
  }
17696
18004
  }
17697
18005
  var DEFAULT_TIMEOUT = 15000;
17698
- var init_client2 = () => {};
18006
+ var init_client2 = __esm(() => {
18007
+ init_command();
18008
+ });
17699
18009
 
17700
18010
  // src/modules/lsp/module.ts
17701
- import { existsSync as existsSync34 } from "fs";
18011
+ import { existsSync as existsSync35 } from "fs";
17702
18012
  import { resolve as resolve20 } from "path";
17703
18013
 
17704
18014
  class LspModule {
@@ -17724,7 +18034,7 @@ class LspModule {
17724
18034
  if (!filePath)
17725
18035
  return;
17726
18036
  const fullPath = resolve20(_ctx.baseDir, filePath);
17727
- if (!existsSync34(fullPath))
18037
+ if (!existsSync35(fullPath))
17728
18038
  return;
17729
18039
  const serverConfig = getServerForFile(fullPath, self.config);
17730
18040
  if (!serverConfig)
@@ -17790,8 +18100,8 @@ var init_lsp = __esm(() => {
17790
18100
  });
17791
18101
 
17792
18102
  // src/modules/indexer/walker.ts
17793
- import { readdirSync as readdirSync13, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync35, watch } from "fs";
17794
- import { join as join28, relative as relative2, extname as extname5 } from "path";
18103
+ import { readdirSync as readdirSync13, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync36, watch } from "fs";
18104
+ import { join as join29, relative as relative2, extname as extname5 } from "path";
17795
18105
 
17796
18106
  class Indexer {
17797
18107
  baseDir;
@@ -17818,7 +18128,7 @@ class Indexer {
17818
18128
  let totalSize = 0;
17819
18129
  let count = 0;
17820
18130
  const walkDir = (dir) => {
17821
- if (!existsSync35(dir))
18131
+ if (!existsSync36(dir))
17822
18132
  return;
17823
18133
  let entries;
17824
18134
  try {
@@ -17829,7 +18139,7 @@ class Indexer {
17829
18139
  for (const entry of entries) {
17830
18140
  if (count >= this.MAX_FILES)
17831
18141
  return;
17832
- const fullPath = join28(dir, entry);
18142
+ const fullPath = join29(dir, entry);
17833
18143
  const relPath = relative2(this.baseDir, fullPath);
17834
18144
  const stat = statSync7(fullPath);
17835
18145
  if (stat.isDirectory()) {
@@ -17892,19 +18202,19 @@ var init_walker = __esm(() => {
17892
18202
  });
17893
18203
 
17894
18204
  // src/modules/indexer/cache.ts
17895
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync13, existsSync as existsSync36, mkdirSync as mkdirSync16, rmSync as rmSync3 } from "fs";
17896
- import { join as join29 } from "path";
18205
+ import { readFileSync as readFileSync23, writeFileSync as writeFileSync13, existsSync as existsSync37, mkdirSync as mkdirSync16, rmSync as rmSync3 } from "fs";
18206
+ import { join as join30 } from "path";
17897
18207
 
17898
18208
  class IndexCache {
17899
18209
  cachePath;
17900
18210
  cache = null;
17901
18211
  constructor(cacheDir) {
17902
- this.cachePath = join29(cacheDir, "index-cache.json");
18212
+ this.cachePath = join30(cacheDir, "index-cache.json");
17903
18213
  }
17904
18214
  load() {
17905
18215
  if (this.cache)
17906
18216
  return this.cache;
17907
- if (!existsSync36(this.cachePath))
18217
+ if (!existsSync37(this.cachePath))
17908
18218
  return null;
17909
18219
  try {
17910
18220
  this.cache = JSON.parse(readFileSync23(this.cachePath, "utf-8"));
@@ -17915,14 +18225,14 @@ class IndexCache {
17915
18225
  }
17916
18226
  save(result) {
17917
18227
  this.cache = result;
17918
- const dir = join29(this.cachePath, "..");
17919
- if (!existsSync36(dir))
18228
+ const dir = join30(this.cachePath, "..");
18229
+ if (!existsSync37(dir))
17920
18230
  mkdirSync16(dir, { recursive: true });
17921
18231
  writeFileSync13(this.cachePath, JSON.stringify(result), "utf-8");
17922
18232
  }
17923
18233
  invalidate() {
17924
18234
  this.cache = null;
17925
- if (existsSync36(this.cachePath)) {
18235
+ if (existsSync37(this.cachePath)) {
17926
18236
  try {
17927
18237
  rmSync3(this.cachePath);
17928
18238
  } catch {}
@@ -18280,13 +18590,13 @@ var init_mcp = __esm(() => {
18280
18590
 
18281
18591
  // src/modules/memory/module.ts
18282
18592
  import { homedir as homedir10 } from "os";
18283
- import { join as join30 } from "path";
18593
+ import { join as join31 } from "path";
18284
18594
 
18285
18595
  class MemoryModule {
18286
18596
  name = "memory";
18287
18597
  store;
18288
18598
  constructor(memoryDir) {
18289
- const dir = memoryDir || join30(homedir10(), ".mma", "memory");
18599
+ const dir = memoryDir || join31(homedir10(), ".mma", "memory");
18290
18600
  this.store = new MemoryStore(dir);
18291
18601
  }
18292
18602
  getSystemPromptBlock() {
@@ -18334,8 +18644,8 @@ __export(exports_bootstrap, {
18334
18644
  bootstrap: () => bootstrap
18335
18645
  });
18336
18646
  import { homedir as homedir11 } from "os";
18337
- import { join as join31, resolve as resolve21 } from "path";
18338
- import { existsSync as existsSync37, readFileSync as readFileSync24, writeFileSync as writeFileSync14 } from "fs";
18647
+ import { join as join32, resolve as resolve21 } from "path";
18648
+ import { existsSync as existsSync38, readFileSync as readFileSync24, writeFileSync as writeFileSync14 } from "fs";
18339
18649
  function buildSystemInfo(config, baseDir, profileCompressed) {
18340
18650
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
18341
18651
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -18360,8 +18670,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
18360
18670
  `);
18361
18671
  }
18362
18672
  async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18363
- const dir = configDir || join31(homedir11(), ".mma");
18364
- const projectConfigPath = projectDir ? join31(projectDir, ".mmrc") : join31(process.cwd(), ".mmrc");
18673
+ const dir = configDir || join32(homedir11(), ".mma");
18674
+ const projectConfigPath = projectDir ? join32(projectDir, ".mmrc") : join32(process.cwd(), ".mmrc");
18365
18675
  const config = loadConfig({ configDir: dir, projectConfigPath });
18366
18676
  setLocale(config.locale);
18367
18677
  try {
@@ -18371,7 +18681,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18371
18681
  }
18372
18682
  } catch {}
18373
18683
  const logger = new Logger(config.logLevel);
18374
- logger.setLogDir(join31(dir, "logs"));
18684
+ logger.setLogDir(join32(dir, "logs"));
18375
18685
  logger.debug("MMA bootstrap", {
18376
18686
  version: config.version,
18377
18687
  model: config.model
@@ -18393,7 +18703,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18393
18703
  logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
18394
18704
  }
18395
18705
  }
18396
- const profile = new UserProfile(join31(dir));
18706
+ const profile = new UserProfile(join32(dir));
18397
18707
  profile.load() || profile.collect();
18398
18708
  profile.save();
18399
18709
  const llmProvider = new OpenAICompatProvider({
@@ -18405,7 +18715,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18405
18715
  rateLimits: config.security?.rateLimits
18406
18716
  });
18407
18717
  const baseDir = projectDir ? resolve21(projectDir) : process.cwd();
18408
- const projectMapCacheDir = join31(baseDir, ".mma");
18718
+ const projectMapCacheDir = join32(baseDir, ".mma");
18409
18719
  const indexerModule = new IndexerModule({
18410
18720
  baseDir,
18411
18721
  cacheDir: projectMapCacheDir
@@ -18416,9 +18726,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18416
18726
  logger.warn(`Project indexing failed: ${err.message}`);
18417
18727
  }
18418
18728
  const skillsLoader = new SkillsLoader;
18419
- const builtinDir = join31(import.meta.dirname, "skills", "builtin");
18420
- const globalDir = join31(homedir11(), ".agents", "skills");
18421
- const projectSkillsDir = join31(baseDir, ".mma", "skills");
18729
+ const builtinDir = join32(import.meta.dirname, "skills", "builtin");
18730
+ const globalDir = join32(homedir11(), ".agents", "skills");
18731
+ const projectSkillsDir = join32(baseDir, ".mma", "skills");
18422
18732
  const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
18423
18733
  const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
18424
18734
  const skillsModule = new SkillsModule(availableSkills, skillsBudget);
@@ -18432,11 +18742,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18432
18742
  essential: true,
18433
18743
  estimatedTokens: Math.ceil(systemInfoContent.length / 4)
18434
18744
  };
18435
- const agentsMdGlobal = join31(dir, "AGENTS.md");
18436
- if (!existsSync37(agentsMdGlobal)) {
18745
+ const agentsMdGlobal = join32(dir, "AGENTS.md");
18746
+ if (!existsSync38(agentsMdGlobal)) {
18437
18747
  writeFileSync14(agentsMdGlobal, "", "utf-8");
18438
18748
  }
18439
- const sessionDir = join31(dir, "sessions");
18749
+ const sessionDir = join32(dir, "sessions");
18440
18750
  const sessionStore = new SessionStore(sessionDir);
18441
18751
  sessionStore.init();
18442
18752
  const sessionManager = new SessionManager(sessionStore, {
@@ -18503,7 +18813,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18503
18813
  const mcpModule = new MCPModule(config);
18504
18814
  await mcpModule.initialize();
18505
18815
  moduleRegistry.register(mcpModule);
18506
- const memoryModule = new MemoryModule(join31(dir, "memory"));
18816
+ const memoryModule = new MemoryModule(join32(dir, "memory"));
18507
18817
  moduleRegistry.register(memoryModule);
18508
18818
  if (config.browser.enabled) {
18509
18819
  const browserModule = new BrowserModule;
@@ -18553,8 +18863,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18553
18863
  pluginManager.register(plugin);
18554
18864
  pluginManager.register(plugin2);
18555
18865
  const pluginLoader = new PluginLoader;
18556
- const globalPluginsDir = join31(homedir11(), ".mma", "plugins");
18557
- const projectPluginsDir = join31(baseDir, ".mma", "plugins");
18866
+ const globalPluginsDir = join32(homedir11(), ".mma", "plugins");
18867
+ const projectPluginsDir = join32(baseDir, ".mma", "plugins");
18558
18868
  pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
18559
18869
  pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
18560
18870
  contextManager.onCompact = (summary) => {
@@ -18572,12 +18882,12 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18572
18882
  const skipAgentsMd = noAgentsMd === true;
18573
18883
  if (!skipAgentsMd) {
18574
18884
  const agentsMdCandidates = [
18575
- join31(baseDir, "AGENTS.md"),
18576
- join31(baseDir, ".mma", "AGENTS.md"),
18577
- join31(dir, "AGENTS.md")
18885
+ join32(baseDir, "AGENTS.md"),
18886
+ join32(baseDir, ".mma", "AGENTS.md"),
18887
+ join32(dir, "AGENTS.md")
18578
18888
  ];
18579
18889
  for (const p of agentsMdCandidates) {
18580
- if (existsSync37(p)) {
18890
+ if (existsSync38(p)) {
18581
18891
  const content = readFileSync24(p, "utf-8").trim();
18582
18892
  if (content) {
18583
18893
  agentsMdBlocks.push({
@@ -19427,12 +19737,12 @@ __export(exports_manifest, {
19427
19737
  getCertMark: () => getCertMark,
19428
19738
  MANIFEST_PATH: () => MANIFEST_PATH
19429
19739
  });
19430
- import { existsSync as existsSync38, readFileSync as readFileSync25, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
19740
+ import { existsSync as existsSync39, readFileSync as readFileSync25, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
19431
19741
  import { homedir as homedir13 } from "os";
19432
- import { join as join33 } from "path";
19742
+ import { join as join34 } from "path";
19433
19743
  function readManifest(path = MANIFEST_PATH) {
19434
19744
  try {
19435
- if (existsSync38(path)) {
19745
+ if (existsSync39(path)) {
19436
19746
  const raw = JSON.parse(readFileSync25(path, "utf-8"));
19437
19747
  return { version: 1, certifications: raw.certifications ?? [] };
19438
19748
  }
@@ -19440,7 +19750,7 @@ function readManifest(path = MANIFEST_PATH) {
19440
19750
  return { version: 1, certifications: [] };
19441
19751
  }
19442
19752
  function saveManifest(m, path = MANIFEST_PATH) {
19443
- mkdirSync17(join33(homedir13(), ".mma"), { recursive: true });
19753
+ mkdirSync17(join34(homedir13(), ".mma"), { recursive: true });
19444
19754
  writeFileSync15(path, JSON.stringify(m, null, 2), "utf-8");
19445
19755
  }
19446
19756
  function upsertCertification(entry, path = MANIFEST_PATH) {
@@ -19475,7 +19785,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
19475
19785
  }
19476
19786
  var MANIFEST_PATH;
19477
19787
  var init_manifest = __esm(() => {
19478
- MANIFEST_PATH = join33(homedir13(), ".mma", "certifications.json");
19788
+ MANIFEST_PATH = join34(homedir13(), ".mma", "certifications.json");
19479
19789
  });
19480
19790
 
19481
19791
  // node_modules/yaml/dist/nodes/identity.js
@@ -26598,8 +26908,8 @@ var init_scenarios = __esm(() => {
26598
26908
  });
26599
26909
 
26600
26910
  // src/modules/certification/loader.ts
26601
- import { existsSync as existsSync39, readdirSync as readdirSync14, readFileSync as readFileSync26 } from "fs";
26602
- import { join as join34 } from "path";
26911
+ import { existsSync as existsSync40, readdirSync as readdirSync14, readFileSync as readFileSync26 } from "fs";
26912
+ import { join as join35 } from "path";
26603
26913
  function validateScenario(s) {
26604
26914
  const errors2 = [];
26605
26915
  const isSkip = s.mode === "skip";
@@ -26648,12 +26958,12 @@ function loadScenarios(userDir) {
26648
26958
  else
26649
26959
  scenarios.push(s);
26650
26960
  }
26651
- if (userDir && existsSync39(userDir)) {
26961
+ if (userDir && existsSync40(userDir)) {
26652
26962
  for (const file of readdirSync14(userDir)) {
26653
26963
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
26654
26964
  continue;
26655
26965
  try {
26656
- const raw = readFileSync26(join34(userDir, file), "utf-8");
26966
+ const raw = readFileSync26(join35(userDir, file), "utf-8");
26657
26967
  const data = $parse(raw);
26658
26968
  const parsed = normalizeScenario(data, file);
26659
26969
  const errs = validateScenario(parsed);
@@ -26706,8 +27016,8 @@ var init_loader3 = __esm(() => {
26706
27016
  });
26707
27017
 
26708
27018
  // src/modules/certification/fact-checker.ts
26709
- import { existsSync as existsSync40, readFileSync as readFileSync27, statSync as statSync8 } from "fs";
26710
- import { join as join35 } from "path";
27019
+ import { existsSync as existsSync41, readFileSync as readFileSync27, statSync as statSync8 } from "fs";
27020
+ import { join as join36 } from "path";
26711
27021
  function checkSandbox(sandboxDir, checks, exitCode, output) {
26712
27022
  const failures = [];
26713
27023
  for (const check of checks) {
@@ -26724,13 +27034,13 @@ function runCheck(sandboxDir, check, exitCode, output) {
26724
27034
  case "outputContains":
26725
27035
  return output.includes(check.text);
26726
27036
  case "fileExists":
26727
- return isFile(join35(sandboxDir, check.path));
27037
+ return isFile(join36(sandboxDir, check.path));
26728
27038
  case "fileNotExists":
26729
- return !existsSync40(join35(sandboxDir, check.path));
27039
+ return !existsSync41(join36(sandboxDir, check.path));
26730
27040
  case "dirExists":
26731
- return isDir(join35(sandboxDir, check.path));
27041
+ return isDir(join36(sandboxDir, check.path));
26732
27042
  case "fileContent": {
26733
- const abs = join35(sandboxDir, check.path);
27043
+ const abs = join36(sandboxDir, check.path);
26734
27044
  if (!isFile(abs))
26735
27045
  return false;
26736
27046
  const content = readFileSync27(abs, "utf-8");
@@ -26741,7 +27051,7 @@ function runCheck(sandboxDir, check, exitCode, output) {
26741
27051
  return false;
26742
27052
  }
26743
27053
  case "fileRegex": {
26744
- const abs = join35(sandboxDir, check.path);
27054
+ const abs = join36(sandboxDir, check.path);
26745
27055
  if (!isFile(abs))
26746
27056
  return false;
26747
27057
  return new RegExp(check.pattern).test(readFileSync27(abs, "utf-8"));
@@ -26752,14 +27062,14 @@ function runCheck(sandboxDir, check, exitCode, output) {
26752
27062
  }
26753
27063
  function isFile(p) {
26754
27064
  try {
26755
- return existsSync40(p) && statSync8(p).isFile();
27065
+ return existsSync41(p) && statSync8(p).isFile();
26756
27066
  } catch {
26757
27067
  return false;
26758
27068
  }
26759
27069
  }
26760
27070
  function isDir(p) {
26761
27071
  try {
26762
- return existsSync40(p) && statSync8(p).isDirectory();
27072
+ return existsSync41(p) && statSync8(p).isDirectory();
26763
27073
  } catch {
26764
27074
  return false;
26765
27075
  }
@@ -26790,9 +27100,9 @@ var init_fact_checker = () => {};
26790
27100
 
26791
27101
  // src/modules/certification/runner.ts
26792
27102
  import { spawn as spawn7 } from "child_process";
26793
- import { existsSync as existsSync41, mkdirSync as mkdirSync18, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
26794
- import { platform as platform5 } from "os";
26795
- import { join as join36, resolve as resolve22, dirname as dirname9 } from "path";
27103
+ import { existsSync as existsSync42, mkdirSync as mkdirSync18, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
27104
+ import { platform as platform6 } from "os";
27105
+ import { join as join37, resolve as resolve22, dirname as dirname9 } from "path";
26796
27106
  async function runScenario(scenario, opts) {
26797
27107
  if (scenario.mode === "skip") {
26798
27108
  return {
@@ -26811,7 +27121,7 @@ async function runScenario(scenario, opts) {
26811
27121
  let passed = 0;
26812
27122
  let firstError;
26813
27123
  for (let i = 1;i <= reps; i++) {
26814
- const sandbox = join36(opts.sandboxBase, `run-${scenario.id}-${i}`);
27124
+ const sandbox = join37(opts.sandboxBase, `run-${scenario.id}-${i}`);
26815
27125
  let failures = [];
26816
27126
  let exitCode = -1;
26817
27127
  let output = "";
@@ -26872,20 +27182,20 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
26872
27182
  rmSync4(sandbox, { recursive: true, force: true });
26873
27183
  mkdirSync18(sandbox, { recursive: true });
26874
27184
  for (const f of scenario.fixtures ?? []) {
26875
- const src = join36(mmaRoot, f.source);
26876
- if (!existsSync41(src)) {
27185
+ const src = join37(mmaRoot, f.source);
27186
+ if (!existsSync42(src)) {
26877
27187
  throw new Error(`fixture missing: ${f.source}`);
26878
27188
  }
26879
- const dest = join36(sandbox, f.dest);
27189
+ const dest = join37(sandbox, f.dest);
26880
27190
  mkdirSync18(dirname9(dest), { recursive: true });
26881
27191
  cpSync2(src, dest);
26882
27192
  }
26883
27193
  }
26884
27194
  function resolveMmaEntry(mmaRoot) {
26885
- const dev = join36(mmaRoot, "src", "cli", "main.ts");
26886
- if (existsSync41(dev))
27195
+ const dev = join37(mmaRoot, "src", "cli", "main.ts");
27196
+ if (existsSync42(dev))
26887
27197
  return dev;
26888
- return join36(mmaRoot, "dist", "main.js");
27198
+ return join37(mmaRoot, "dist", "main.js");
26889
27199
  }
26890
27200
  function findMmaRoot(fromDir) {
26891
27201
  const candidates = [
@@ -26893,7 +27203,7 @@ function findMmaRoot(fromDir) {
26893
27203
  resolve22(fromDir, "..")
26894
27204
  ];
26895
27205
  for (const c of candidates) {
26896
- if (existsSync41(join36(c, "package.json")))
27206
+ if (existsSync42(join37(c, "package.json")))
26897
27207
  return c;
26898
27208
  }
26899
27209
  return process.cwd();
@@ -26902,7 +27212,7 @@ function killTree2(child) {
26902
27212
  const pid = child.pid;
26903
27213
  if (!pid)
26904
27214
  return;
26905
- if (platform5() === "win32") {
27215
+ if (platform6() === "win32") {
26906
27216
  spawn7("taskkill", ["/pid", String(pid), "/T", "/F"], {
26907
27217
  windowsHide: true,
26908
27218
  stdio: "ignore"
@@ -26961,13 +27271,13 @@ __export(exports_cli, {
26961
27271
  });
26962
27272
  import { rmSync as rmSync5 } from "fs";
26963
27273
  import { homedir as homedir14 } from "os";
26964
- import { join as join37, dirname as dirname10 } from "path";
27274
+ import { join as join38, dirname as dirname10 } from "path";
26965
27275
  import { fileURLToPath as fileURLToPath2 } from "url";
26966
- import { existsSync as existsSync42, readFileSync as readFileSync28 } from "fs";
27276
+ import { existsSync as existsSync43, readFileSync as readFileSync28 } from "fs";
26967
27277
  function readVersion() {
26968
- const candidates = [join37(MMA_ROOT, "package.json")];
27278
+ const candidates = [join38(MMA_ROOT, "package.json")];
26969
27279
  for (const p of candidates) {
26970
- if (existsSync42(p)) {
27280
+ if (existsSync43(p)) {
26971
27281
  try {
26972
27282
  const raw = JSON.parse(readFileSync28(p, "utf-8"));
26973
27283
  if (raw.version)
@@ -27005,7 +27315,7 @@ async function certify(opts) {
27005
27315
  return;
27006
27316
  }
27007
27317
  console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
27008
- const sandboxBase = join37(process.cwd(), ".mma", "certification");
27318
+ const sandboxBase = join38(process.cwd(), ".mma", "certification");
27009
27319
  const results = [];
27010
27320
  const total = selected.length;
27011
27321
  let idx = 0;
@@ -27119,7 +27429,7 @@ var init_cli = __esm(() => {
27119
27429
  init_manifest();
27120
27430
  HERE = dirname10(fileURLToPath2(import.meta.url));
27121
27431
  MMA_ROOT = findMmaRoot(HERE);
27122
- USER_SCENARIO_DIR = join37(homedir14(), ".mma", "certification", "scenarios");
27432
+ USER_SCENARIO_DIR = join38(homedir14(), ".mma", "certification", "scenarios");
27123
27433
  });
27124
27434
 
27125
27435
  // src/cli/repl-commands.ts
@@ -27128,18 +27438,18 @@ __export(exports_repl_commands, {
27128
27438
  registerAllCommands: () => registerAllCommands,
27129
27439
  COMMAND_GROUPS: () => COMMAND_GROUPS
27130
27440
  });
27131
- import { join as join39, dirname as dirname12 } from "path";
27441
+ import { join as join40, dirname as dirname12 } from "path";
27132
27442
  import { homedir as homedir16 } from "os";
27133
- import { existsSync as existsSync44, readFileSync as readFileSync30 } from "fs";
27443
+ import { existsSync as existsSync45, readFileSync as readFileSync30 } from "fs";
27134
27444
  import { fileURLToPath as fileURLToPath4 } from "url";
27135
27445
  function readVersion3() {
27136
27446
  const here = dirname12(fileURLToPath4(import.meta.url));
27137
27447
  const candidates = [
27138
- join39(here, "..", "..", "package.json"),
27139
- join39(here, "..", "package.json")
27448
+ join40(here, "..", "..", "package.json"),
27449
+ join40(here, "..", "package.json")
27140
27450
  ];
27141
27451
  for (const p of candidates) {
27142
- if (existsSync44(p)) {
27452
+ if (existsSync45(p)) {
27143
27453
  try {
27144
27454
  const raw = JSON.parse(readFileSync30(p, "utf8"));
27145
27455
  if (raw.version)
@@ -27205,7 +27515,7 @@ function registerMmaCommands(ctx) {
27205
27515
  }
27206
27516
  try {
27207
27517
  const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
27208
- const { existsSync: existsSync45 } = await import("fs");
27518
+ const { existsSync: existsSync46 } = await import("fs");
27209
27519
  const { resolve: resolve23 } = await import("path");
27210
27520
  let dataUrl;
27211
27521
  let label;
@@ -27225,7 +27535,7 @@ function registerMmaCommands(ctx) {
27225
27535
  label = source;
27226
27536
  } else {
27227
27537
  const absPath = resolve23(process.cwd(), source);
27228
- if (!existsSync45(absPath)) {
27538
+ if (!existsSync46(absPath)) {
27229
27539
  console.log(pc2.red(t("image.not_found", { path: source })));
27230
27540
  return;
27231
27541
  }
@@ -27304,7 +27614,7 @@ function registerMmaCommands(ctx) {
27304
27614
  console.log(pc2.yellow(t("repl.wizard_running")));
27305
27615
  await ctx.withExclusiveInput(async () => {
27306
27616
  const answers = await runSetup(ctx.rl);
27307
- const configPath = join39(homedir16(), ".mma", "config.json");
27617
+ const configPath = join40(homedir16(), ".mma", "config.json");
27308
27618
  ctx.config.provider.type = answers.provider;
27309
27619
  ctx.config.provider.baseUrl = answers.apiBase;
27310
27620
  ctx.config.provider.apiKey = answers.apiKey;
@@ -27358,7 +27668,7 @@ Excluded blocks: ${info.excluded.length}`));
27358
27668
  return;
27359
27669
  }
27360
27670
  ctx.config.provider.type = name;
27361
- const configPath = join39(homedir16(), ".mma", "config.json");
27671
+ const configPath = join40(homedir16(), ".mma", "config.json");
27362
27672
  saveConfig(ctx.config, configPath);
27363
27673
  await ctx.agent.reconfigure(ctx.config);
27364
27674
  console.log(pc2.green(t("repl.provider_set", { name })));
@@ -27414,7 +27724,7 @@ Excluded blocks: ${info.excluded.length}`));
27414
27724
  return;
27415
27725
  }
27416
27726
  ctx.config.model = name;
27417
- const configPath = join39(homedir16(), ".mma", "config.json");
27727
+ const configPath = join40(homedir16(), ".mma", "config.json");
27418
27728
  saveConfig(ctx.config, configPath);
27419
27729
  await ctx.agent.reconfigure(ctx.config);
27420
27730
  console.log(pc2.green(t("repl.model_set", { name })));
@@ -27439,7 +27749,7 @@ Excluded blocks: ${info.excluded.length}`));
27439
27749
  return;
27440
27750
  }
27441
27751
  ctx.config.contextWindow = size;
27442
- const configPath = join39(homedir16(), ".mma", "config.json");
27752
+ const configPath = join40(homedir16(), ".mma", "config.json");
27443
27753
  saveConfig(ctx.config, configPath);
27444
27754
  await ctx.agent.reconfigure(ctx.config);
27445
27755
  console.log(pc2.green(t("cli.context_set", { size })));
@@ -27458,10 +27768,10 @@ Excluded blocks: ${info.excluded.length}`));
27458
27768
  ctx.agent.shutdown();
27459
27769
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
27460
27770
  const { homedir: homedir17 } = await import("os");
27461
- const { join: join40 } = await import("path");
27771
+ const { join: join41 } = await import("path");
27462
27772
  const configDir = ctx.configDir;
27463
27773
  const baseDir = ctx.baseDir;
27464
- const projectConfigPath = join40(baseDir, ".mmrc");
27774
+ const projectConfigPath = join41(baseDir, ".mmrc");
27465
27775
  const freshConfig = loadConfig2({ configDir, projectConfigPath });
27466
27776
  Object.assign(ctx.config, freshConfig);
27467
27777
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
@@ -27761,14 +28071,14 @@ init_bootstrap();
27761
28071
  init_config2();
27762
28072
  init_setup();
27763
28073
  init_i18n();
27764
- import { join as join38, dirname as dirname11 } from "path";
28074
+ import { join as join39, dirname as dirname11 } from "path";
27765
28075
  import { homedir as homedir15 } from "os";
27766
- import { existsSync as existsSync43, readFileSync as readFileSync29 } from "fs";
28076
+ import { existsSync as existsSync44, readFileSync as readFileSync29 } from "fs";
27767
28077
 
27768
28078
  // src/cli/security-commands.ts
27769
28079
  init_bootstrap();
27770
28080
  init_config2();
27771
- import { join as join32 } from "path";
28081
+ import { join as join33 } from "path";
27772
28082
  import { homedir as homedir12 } from "os";
27773
28083
 
27774
28084
  // src/modules/security/security-policies.ts
@@ -28298,7 +28608,7 @@ function createSecurityCommand(program2) {
28298
28608
  }
28299
28609
  });
28300
28610
  securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
28301
- const configPath = join32(homedir12(), ".mma", "config.json");
28611
+ const configPath = join33(homedir12(), ".mma", "config.json");
28302
28612
  const { config: appConfig } = await bootstrap();
28303
28613
  const validPresets = ["strict", "balanced", "permissive"];
28304
28614
  if (!validPresets.includes(preset)) {
@@ -28313,7 +28623,7 @@ function createSecurityCommand(program2) {
28313
28623
  console.log(t("cli.security.policy_description", { description: policy.description }));
28314
28624
  });
28315
28625
  securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
28316
- const configPath = join32(homedir12(), ".mma", "config.json");
28626
+ const configPath = join33(homedir12(), ".mma", "config.json");
28317
28627
  const { config: appConfig } = await bootstrap();
28318
28628
  appConfig.security = appConfig.security || {};
28319
28629
  appConfig.security.sessionEncryption = {
@@ -28325,7 +28635,7 @@ function createSecurityCommand(program2) {
28325
28635
  console.log(t("cli.security.encryption_enabled"));
28326
28636
  });
28327
28637
  securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
28328
- const configPath = join32(homedir12(), ".mma", "config.json");
28638
+ const configPath = join33(homedir12(), ".mma", "config.json");
28329
28639
  const { config: appConfig } = await bootstrap();
28330
28640
  appConfig.security = appConfig.security || {};
28331
28641
  appConfig.security.sessionEncryption = {
@@ -28337,7 +28647,7 @@ function createSecurityCommand(program2) {
28337
28647
  console.log(t("cli.security.encryption_disabled"));
28338
28648
  });
28339
28649
  securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
28340
- const configPath = join32(homedir12(), ".mma", "config.json");
28650
+ const configPath = join33(homedir12(), ".mma", "config.json");
28341
28651
  const { config: appConfig } = await bootstrap();
28342
28652
  appConfig.security = appConfig.security || {};
28343
28653
  appConfig.security.auditNotifier = {
@@ -28351,7 +28661,7 @@ function createSecurityCommand(program2) {
28351
28661
  console.log(t("cli.security.audit_enabled"));
28352
28662
  });
28353
28663
  securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
28354
- const configPath = join32(homedir12(), ".mma", "config.json");
28664
+ const configPath = join33(homedir12(), ".mma", "config.json");
28355
28665
  const { config: appConfig } = await bootstrap();
28356
28666
  appConfig.security = appConfig.security || {};
28357
28667
  appConfig.security.auditNotifier = {
@@ -28387,11 +28697,11 @@ import { fileURLToPath as fileURLToPath3 } from "url";
28387
28697
  function readVersion2() {
28388
28698
  const here = dirname11(fileURLToPath3(import.meta.url));
28389
28699
  const candidates = [
28390
- join38(here, "..", "..", "package.json"),
28391
- join38(here, "..", "package.json")
28700
+ join39(here, "..", "..", "package.json"),
28701
+ join39(here, "..", "package.json")
28392
28702
  ];
28393
28703
  for (const p of candidates) {
28394
- if (existsSync43(p)) {
28704
+ if (existsSync44(p)) {
28395
28705
  try {
28396
28706
  const raw = JSON.parse(readFileSync29(p, "utf8"));
28397
28707
  if (raw.version)
@@ -28406,7 +28716,7 @@ function createProgram() {
28406
28716
  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"));
28407
28717
  program2.command("init").description(t("cli.init")).action(async () => {
28408
28718
  const answers = await runSetup();
28409
- const configPath = join38(homedir15(), ".mma", "config.json");
28719
+ const configPath = join39(homedir15(), ".mma", "config.json");
28410
28720
  const { config } = await bootstrap();
28411
28721
  config.provider.type = answers.provider;
28412
28722
  config.provider.baseUrl = answers.apiBase;
@@ -28451,7 +28761,7 @@ function createProgram() {
28451
28761
  });
28452
28762
  const configCmd = program2.command("config").description(t("cli.manage_config"));
28453
28763
  configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
28454
- const configPath = join38(homedir15(), ".mma", "config.json");
28764
+ const configPath = join39(homedir15(), ".mma", "config.json");
28455
28765
  const { config } = await bootstrap();
28456
28766
  const keys = key.split(".");
28457
28767
  let obj = config;
@@ -28514,7 +28824,7 @@ function createProgram() {
28514
28824
  console.log(t("cli.model_hint"));
28515
28825
  });
28516
28826
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
28517
- const configPath = join38(homedir15(), ".mma", "config.json");
28827
+ const configPath = join39(homedir15(), ".mma", "config.json");
28518
28828
  const { config } = await bootstrap();
28519
28829
  config.model = name;
28520
28830
  saveConfig(config, configPath);
@@ -28550,7 +28860,7 @@ function createProgram() {
28550
28860
  await uncertify2(name, config);
28551
28861
  });
28552
28862
  program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
28553
- const configPath = join38(homedir15(), ".mma", "config.json");
28863
+ const configPath = join39(homedir15(), ".mma", "config.json");
28554
28864
  const { config } = await bootstrap();
28555
28865
  const contextWindow = parseInt(size, 10);
28556
28866
  if (isNaN(contextWindow) || contextWindow < 1024) {
@@ -28568,7 +28878,7 @@ function createProgram() {
28568
28878
  console.log(t("cli.base_url"), config.provider.baseUrl);
28569
28879
  });
28570
28880
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
28571
- const configPath = join38(homedir15(), ".mma", "config.json");
28881
+ const configPath = join39(homedir15(), ".mma", "config.json");
28572
28882
  const { config } = await bootstrap();
28573
28883
  config.provider.type = name;
28574
28884
  saveConfig(config, configPath);
@@ -29338,8 +29648,8 @@ class LineEditor {
29338
29648
  }
29339
29649
 
29340
29650
  // src/cli/repl.ts
29341
- import { existsSync as existsSync45, readFileSync as readFileSync31, writeFileSync as writeFileSync16 } from "fs";
29342
- import { join as join40, dirname as dirname13 } from "path";
29651
+ import { existsSync as existsSync46, readFileSync as readFileSync31, writeFileSync as writeFileSync16 } from "fs";
29652
+ import { join as join41, dirname as dirname13 } from "path";
29343
29653
  import { homedir as homedir17 } from "os";
29344
29654
  import { fileURLToPath as fileURLToPath5 } from "url";
29345
29655
 
@@ -29845,11 +30155,11 @@ init_repl_commands();
29845
30155
  function readVersion4() {
29846
30156
  const here = dirname13(fileURLToPath5(import.meta.url));
29847
30157
  const candidates = [
29848
- join40(here, "..", "..", "package.json"),
29849
- join40(here, "..", "package.json")
30158
+ join41(here, "..", "..", "package.json"),
30159
+ join41(here, "..", "package.json")
29850
30160
  ];
29851
30161
  for (const p of candidates) {
29852
- if (existsSync45(p)) {
30162
+ if (existsSync46(p)) {
29853
30163
  try {
29854
30164
  const raw = JSON.parse(readFileSync31(p, "utf8"));
29855
30165
  if (raw.version)
@@ -29907,15 +30217,15 @@ class Repl {
29907
30217
  this.skillsModule = skillsModule;
29908
30218
  this.pluginManager = pluginManager;
29909
30219
  this.logger = logger;
29910
- this.configDir = configDir || join40(homedir17(), ".mma");
30220
+ this.configDir = configDir || join41(homedir17(), ".mma");
29911
30221
  this.baseDir = baseDir || process.cwd();
29912
30222
  this.noAgentsMd = noAgentsMd === true;
29913
- this.historyPath = join40(homedir17(), ".mma", "repl-history");
30223
+ this.historyPath = join41(homedir17(), ".mma", "repl-history");
29914
30224
  this.loadHistory();
29915
30225
  this.rl = process.stdin.isTTY ? new LineEditor({
29916
30226
  input: process.stdin,
29917
30227
  output: process.stdout,
29918
- prompt: pc2.cyan("> "),
30228
+ prompt: pc2.cyan(t("repl.you")),
29919
30229
  history: this.history,
29920
30230
  historySize: this.maxHistory,
29921
30231
  completer: (line) => {
@@ -29927,7 +30237,7 @@ class Repl {
29927
30237
  }) : readline3.createInterface({
29928
30238
  input: process.stdin,
29929
30239
  output: process.stdout,
29930
- prompt: pc2.cyan("> "),
30240
+ prompt: pc2.cyan(t("repl.you")),
29931
30241
  history: this.history,
29932
30242
  historySize: this.maxHistory,
29933
30243
  tabSize: 2,
@@ -29943,7 +30253,7 @@ class Repl {
29943
30253
  this.setupListeners();
29944
30254
  }
29945
30255
  loadHistory() {
29946
- if (existsSync45(this.historyPath)) {
30256
+ if (existsSync46(this.historyPath)) {
29947
30257
  try {
29948
30258
  const raw = readFileSync31(this.historyPath, "utf-8");
29949
30259
  this.history = raw.split(`
@@ -30010,11 +30320,11 @@ class Repl {
30010
30320
  }
30011
30321
  }
30012
30322
  if (this.running) {
30013
- this.rl.setPrompt(pc2.cyan("> "));
30323
+ this.rl.setPrompt(pc2.cyan(t("repl.you")));
30014
30324
  this.rl.prompt();
30015
30325
  }
30016
30326
  } else {
30017
- this.rl.setPrompt(pc2.cyan("... "));
30327
+ this.rl.setPrompt(pc2.cyan(t("repl.you") + "… "));
30018
30328
  this.rl.prompt();
30019
30329
  }
30020
30330
  return;
@@ -30022,7 +30332,7 @@ class Repl {
30022
30332
  if (this.isMultiLineInput(trimmed)) {
30023
30333
  inMultiLine = true;
30024
30334
  multiLineBuffer = trimmed;
30025
- this.rl.setPrompt(pc2.cyan("... "));
30335
+ this.rl.setPrompt(pc2.cyan(t("repl.you") + "… "));
30026
30336
  this.rl.prompt();
30027
30337
  return;
30028
30338
  }
@@ -30144,7 +30454,7 @@ ${t("image.clipboard_empty")}`));
30144
30454
  this.logger?.logREPL("user", input);
30145
30455
  if (this.rl instanceof LineEditor)
30146
30456
  this.rl.reset();
30147
- process.stdout.write(`
30457
+ process.stdout.write("\r" + divider() + `
30148
30458
  ` + pc2.green(t("repl.agent")));
30149
30459
  const renderer = new Renderer({
30150
30460
  spinner: this.config.ui?.spinner ?? true,
@@ -30171,6 +30481,9 @@ ${t("image.clipboard_empty")}`));
30171
30481
  console.error(pc2.red(`${t("error.prefix")}${result.error}`));
30172
30482
  }
30173
30483
  this.showContextBar(result);
30484
+ process.stdout.write(`
30485
+ ` + divider() + `
30486
+ `);
30174
30487
  } finally {
30175
30488
  this.agentRunning = false;
30176
30489
  }
@@ -30299,11 +30612,11 @@ ${t("image.clipboard_empty")}`));
30299
30612
  row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
30300
30613
  } else {
30301
30614
  const agentsMdCandidates = [
30302
- join40(this.baseDir, "AGENTS.md"),
30303
- join40(this.baseDir, ".mma", "AGENTS.md"),
30304
- join40(this.configDir, "AGENTS.md")
30615
+ join41(this.baseDir, "AGENTS.md"),
30616
+ join41(this.baseDir, ".mma", "AGENTS.md"),
30617
+ join41(this.configDir, "AGENTS.md")
30305
30618
  ];
30306
- const foundAgents = agentsMdCandidates.filter((p) => existsSync45(p));
30619
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync46(p));
30307
30620
  if (foundAgents.length > 0) {
30308
30621
  for (const p of foundAgents) {
30309
30622
  row(t("repl.agents_label"), pc2.dim(p));
@@ -30314,7 +30627,7 @@ ${t("image.clipboard_empty")}`));
30314
30627
  }
30315
30628
  const meta = this.sessionManager?.getActiveMeta();
30316
30629
  if (meta) {
30317
- const sessionPath = join40(this.configDir, "sessions", meta.id);
30630
+ const sessionPath = join41(this.configDir, "sessions", meta.id);
30318
30631
  row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
30319
30632
  }
30320
30633
  const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
@@ -30355,8 +30668,8 @@ init_setup();
30355
30668
  init_config2();
30356
30669
  init_i18n();
30357
30670
  init_colors();
30358
- import { existsSync as existsSync46, readFileSync as readFileSync32 } from "fs";
30359
- import { join as join41, dirname as dirname14 } from "path";
30671
+ import { existsSync as existsSync47, readFileSync as readFileSync32 } from "fs";
30672
+ import { join as join42, dirname as dirname14 } from "path";
30360
30673
  import { homedir as homedir18 } from "os";
30361
30674
  import { fileURLToPath as fileURLToPath6 } from "url";
30362
30675
 
@@ -30509,11 +30822,11 @@ class UpdaterModule {
30509
30822
  function readVersion5() {
30510
30823
  const here = dirname14(fileURLToPath6(import.meta.url));
30511
30824
  const candidates = [
30512
- join41(here, "..", "..", "package.json"),
30513
- join41(here, "..", "package.json")
30825
+ join42(here, "..", "..", "package.json"),
30826
+ join42(here, "..", "package.json")
30514
30827
  ];
30515
30828
  for (const p of candidates) {
30516
- if (existsSync46(p)) {
30829
+ if (existsSync47(p)) {
30517
30830
  try {
30518
30831
  const raw = JSON.parse(readFileSync32(p, "utf8"));
30519
30832
  if (raw.version)
@@ -30586,15 +30899,15 @@ async function main() {
30586
30899
  agent.shutdown();
30587
30900
  process.exit(exitCode);
30588
30901
  } else {
30589
- const configPath = join41(homedir18(), ".mma", "config.json");
30590
- if (!existsSync46(configPath)) {
30902
+ const configPath = join42(homedir18(), ".mma", "config.json");
30903
+ if (!existsSync47(configPath)) {
30591
30904
  console.log(pc2.yellow(`
30592
30905
  ` + t("cli.first_run") + `
30593
30906
  `));
30594
30907
  const answers = await runSetup();
30595
30908
  const config2 = loadConfig({
30596
- configDir: join41(homedir18(), ".mma"),
30597
- projectConfigPath: projectDir ? join41(projectDir, ".mmrc") : join41(process.cwd(), ".mmrc")
30909
+ configDir: join42(homedir18(), ".mma"),
30910
+ projectConfigPath: projectDir ? join42(projectDir, ".mmrc") : join42(process.cwd(), ".mmrc")
30598
30911
  });
30599
30912
  config2.provider.type = answers.provider;
30600
30913
  config2.provider.baseUrl = answers.apiBase;