micro-models-agent 0.33.2 → 0.33.4

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 +380 -157
  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",
@@ -2740,6 +2742,8 @@ Use this knowledge to answer the user's question.`,
2740
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.",
2741
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.",
2742
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.",
2743
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.',
2744
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.",
2745
2749
  "exec.off_track": 'Step {stepId} — "{description}" — but you are using {tool} on a different path. Return to the current step.',
@@ -3050,6 +3054,8 @@ var init_ru = __esm(() => {
3050
3054
  "todo.added": "Добавлено {count} задач: {items}",
3051
3055
  "todo.marked_done": "Отмечено выполненными: {count}",
3052
3056
  "todo.no_active": "Нет активных задач",
3057
+ "todo.no_items": "Не указаны подзадачи — укажите items для отметки выполненными",
3058
+ "todo.subtask_not_found": "Подзадачи не найдены: {items}",
3053
3059
  "todo.unknown_action": "Неизвестное действие todo: {action}",
3054
3060
  "todo.acknowledged": "Todo принято",
3055
3061
  "verify.passed": "Проверка пройдена",
@@ -3318,6 +3324,8 @@ var init_ru = __esm(() => {
3318
3324
  "exec.tool_errors_recovery": "Инструмент {tool} упал {count} раз подряд. Попробуйте альтернативу: создайте файлы напрямую через write_file, используйте другую команду, или пропустите этот шаг через plan update step=N status=skipped с пометкой почему.",
3319
3325
  "exec.repetitive_tool": "Инструмент {tool} вызван {count} раз с одинаковыми аргументами и результатом. Попробуйте другой подход — создайте файлы напрямую, измените аргументы или проверьте статус процесса через process_log.",
3320
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. Если не можете завершить задачу — спросите пользователя, а не перечитывайте одни и те же файлы.",
3321
3329
  "exec.plan_warning": 'Текущий шаг плана {step} — "{description}", но вызывается {tool} для файлов вне этого шага. Завершите текущий шаг, вызовите plan update step={step} status=done, затем переходите к следующему.',
3322
3330
  "exec.plan_blocked": "{max} вызовов подряд вне текущего шага. Завершите шаг {step} — остальные шаги ждут пока этот не будет выполнен.",
3323
3331
  "exec.off_track": 'Шаг {stepId} — "{description}", но используется {tool} для другого пути. Вернитесь к текущему шагу.',
@@ -6018,20 +6026,16 @@ function safeResolvePath(baseDir, userPath) {
6018
6026
  }
6019
6027
  var init_path_utils = () => {};
6020
6028
 
6021
- // src/tools/preview.ts
6022
- var MAX_PREVIEW_LINES = 15;
6023
-
6024
6029
  // src/tools/read-file.ts
6025
6030
  import { readFileSync as readFileSync5, existsSync as existsSync10 } from "fs";
6026
6031
  import { extname } from "path";
6027
- var DEFAULT_LIMIT, readFileTool;
6032
+ var DEFAULT_LIMIT = 300, readFileTool;
6028
6033
  var init_read_file = __esm(() => {
6029
6034
  init_i18n();
6030
6035
  init_path_validator();
6031
6036
  init_security();
6032
6037
  init_audit_log();
6033
6038
  init_path_utils();
6034
- DEFAULT_LIMIT = MAX_PREVIEW_LINES;
6035
6039
  readFileTool = {
6036
6040
  name: "read_file",
6037
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.`,
@@ -6540,6 +6544,9 @@ var init_edit_file = __esm(() => {
6540
6544
  };
6541
6545
  });
6542
6546
 
6547
+ // src/tools/preview.ts
6548
+ var MAX_PREVIEW_LINES = 15;
6549
+
6543
6550
  // src/tools/glob-tool.ts
6544
6551
  import { globSync } from "fs";
6545
6552
  var globTool;
@@ -9197,6 +9204,7 @@ class StuckDetector {
9197
9204
  lastBashCommand = "";
9198
9205
  lastBashOutput = "";
9199
9206
  emptyBashRunCount = 0;
9207
+ readOnlyStreak = 0;
9200
9208
  constructor(threshold = 6, errorThreshold = 3) {
9201
9209
  this.threshold = threshold;
9202
9210
  this.errorThreshold = errorThreshold;
@@ -9214,6 +9222,14 @@ class StuckDetector {
9214
9222
  if (this.recentToolCalls.length > this.maxRecentCalls) {
9215
9223
  this.recentToolCalls.shift();
9216
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;
9217
9233
  }
9218
9234
  recordToolError(toolName, output) {
9219
9235
  this.toolErrors.set(toolName, (this.toolErrors.get(toolName) || 0) + 1);
@@ -9331,6 +9347,9 @@ class StuckDetector {
9331
9347
  if (this.hasConsecutiveFailures()) {
9332
9348
  hints.push("Multiple different tools are failing. Check if the environment is set up correctly.");
9333
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
+ }
9334
9353
  return hints;
9335
9354
  }
9336
9355
  getActionableHints() {
@@ -9446,6 +9465,11 @@ class StuckDetector {
9446
9465
  if (errorTool) {
9447
9466
  return t("exec.tool_errors", { tool: errorTool[0], count: errorTool[1] });
9448
9467
  }
9468
+ if (this.hasReadOnlyLoop()) {
9469
+ return t("exec.read_only_loop", {
9470
+ count: String(this.readOnlyStreak)
9471
+ });
9472
+ }
9449
9473
  return "";
9450
9474
  }
9451
9475
  getRecoveryMessage() {
@@ -9471,6 +9495,11 @@ class StuckDetector {
9471
9495
  if (this.hasRepetitiveToolCalls()) {
9472
9496
  return this.getRepetitiveToolMessage();
9473
9497
  }
9498
+ if (this.hasReadOnlyLoop()) {
9499
+ return t("exec.read_only_loop_recovery", {
9500
+ count: String(this.readOnlyStreak)
9501
+ });
9502
+ }
9474
9503
  return "";
9475
9504
  }
9476
9505
  reset() {
@@ -9486,6 +9515,20 @@ class StuckDetector {
9486
9515
  this.lastBashCommand = "";
9487
9516
  this.lastBashOutput = "";
9488
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;
9489
9532
  }
9490
9533
  resetStepState(stepId) {
9491
9534
  this.currentStepId = stepId;
@@ -9499,10 +9542,33 @@ class StuckDetector {
9499
9542
  this.lastBashCommand = "";
9500
9543
  this.lastBashOutput = "";
9501
9544
  this.emptyBashRunCount = 0;
9545
+ this.readOnlyStreak = 0;
9502
9546
  }
9503
9547
  }
9548
+ var READ_ONLY_TOOLS, READ_ONLY_LOOP_THRESHOLD = 10;
9504
9549
  var init_stuck_detector = __esm(() => {
9505
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
+ ]);
9506
9572
  });
9507
9573
 
9508
9574
  // src/modules/artifacts/store.ts
@@ -10408,6 +10474,9 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10408
10474
  }).catch(() => {});
10409
10475
  }
10410
10476
  }
10477
+ if (typeof contextManager.resetUserTurn === "function") {
10478
+ contextManager.resetUserTurn();
10479
+ }
10411
10480
  contextManager.addMessage({ role: "user", content: input });
10412
10481
  slog.logUser(input);
10413
10482
  if (config.moe?.enabled) {
@@ -10447,6 +10516,9 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10447
10516
  const MAX_HALLUCINATION_RETRIES = 3;
10448
10517
  let consecutiveToolFailures = 0;
10449
10518
  const MAX_CONSECUTIVE_TOOL_FAILURES = 5;
10519
+ const toolFailureCounts = new Map;
10520
+ const memoryRuleRecorded = new Set;
10521
+ const MIN_REPEATED_TOOL_FAILURES = 3;
10450
10522
  let auditRetries = 0;
10451
10523
  const MAX_AUDIT_RETRIES = 3;
10452
10524
  let emptyResponseRetries = 0;
@@ -10686,6 +10758,25 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10686
10758
  contextManager.compact();
10687
10759
  logger.debug("Context compacted after tool result");
10688
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
+ }
10689
10780
  }
10690
10781
  if (anyToolFailed) {
10691
10782
  consecutiveToolFailures++;
@@ -11026,6 +11117,7 @@ class ContextManager {
11026
11117
  fileFacts = [];
11027
11118
  decisionFacts = [];
11028
11119
  errorFacts = [];
11120
+ lastUserTask = "";
11029
11121
  static MAX_FACTS = 20;
11030
11122
  tokenCounter;
11031
11123
  pendingImageParts = [];
@@ -11062,6 +11154,10 @@ class ContextManager {
11062
11154
  noteIteration() {
11063
11155
  this.iterationsSinceCompaction++;
11064
11156
  }
11157
+ resetUserTurn() {
11158
+ this.iterationsSinceCompaction = 0;
11159
+ this.lastUserTask = "";
11160
+ }
11065
11161
  getQuality() {
11066
11162
  const usedTokens = this.getEstimatedTokens();
11067
11163
  const tokenLoad = Math.max(0, 1 - usedTokens / this.budget.history);
@@ -11074,6 +11170,12 @@ class ContextManager {
11074
11170
  return Math.round(Math.min(100, Math.max(0, score * 100)));
11075
11171
  }
11076
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
+ }
11077
11179
  if (msg.role === "user" && this.pendingImageParts.length > 0) {
11078
11180
  const textPart = {
11079
11181
  type: "text",
@@ -11163,6 +11265,10 @@ class ContextManager {
11163
11265
  this.extractFacts(oldTurns);
11164
11266
  const parts = [];
11165
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
+ }
11166
11272
  if (this.fileFacts.length > 0) {
11167
11273
  parts.push(`[Files: ${this.fileFacts.slice(-15).join("; ")}]`);
11168
11274
  }
@@ -11202,10 +11308,12 @@ ${lines.join(`
11202
11308
  }
11203
11309
  }
11204
11310
  extractFacts(turns) {
11311
+ const DRIVE = "(?:[a-zA-Z]:[\\\\/])?";
11205
11312
  const filePatterns = [
11206
- /(?:Created|Updated|Written|Deleted|Moved) ([\w./\\-]+\.[a-z]+)/gi,
11207
- /Файл (?:создан|обновлён|записан|удалён|перемещён):? ([\w./\\-]+\.[a-z]+)/gi,
11208
- /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")
11209
11317
  ];
11210
11318
  const newFiles = [];
11211
11319
  const newDecisions = [];
@@ -11265,6 +11373,7 @@ ${lines.join(`
11265
11373
  this.iterationsSinceCompaction = 0;
11266
11374
  this.compactionCount = 0;
11267
11375
  this.peakTokens = 0;
11376
+ this.lastUserTask = "";
11268
11377
  }
11269
11378
  getEstimatedTokens() {
11270
11379
  return this.messages.reduce((sum, m) => sum + this.estimateMessageTokens(m), 0) + this.toolTokens;
@@ -15453,6 +15562,9 @@ class PlanCreator {
15453
15562
  const icon = step.status === "done" ? "[x]" : step.status === "in_progress" ? "[*]" : step.status === "failed" ? "[!]" : step.status === "skipped" ? "[-]" : "[ ]";
15454
15563
  const note = step.note ? ` — ${step.note}` : "";
15455
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
+ }
15456
15568
  }
15457
15569
  return lines.join(`
15458
15570
  `);
@@ -15521,7 +15633,40 @@ var init_tracker = () => {};
15521
15633
 
15522
15634
  // src/modules/execution/auditor.ts
15523
15635
  import { existsSync as existsSync27, readdirSync as readdirSync8 } from "fs";
15524
- 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
+ }
15525
15670
  function findTestFile(dir, depth = 0) {
15526
15671
  if (depth > 5)
15527
15672
  return null;
@@ -15608,8 +15753,8 @@ class Auditor {
15608
15753
  const missingFiles = [];
15609
15754
  const existingFiles = [];
15610
15755
  for (const filePath of uniqueFiles) {
15611
- const resolved = resolve17(this.baseDir, filePath);
15612
- if (existsSync27(resolved)) {
15756
+ const resolved = findExistingFile(this.baseDir, filePath);
15757
+ if (resolved) {
15613
15758
  existingFiles.push(filePath);
15614
15759
  } else {
15615
15760
  missingFiles.push(filePath);
@@ -15666,7 +15811,7 @@ class Auditor {
15666
15811
  };
15667
15812
  }
15668
15813
  }
15669
- 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;
15670
15815
  var init_auditor = __esm(() => {
15671
15816
  init_i18n();
15672
15817
  init_js_identifiers();
@@ -15859,7 +16004,7 @@ function extractFilePaths(text) {
15859
16004
  }
15860
16005
  return result;
15861
16006
  }
15862
- function basename2(p) {
16007
+ function basename3(p) {
15863
16008
  const parts = p.split(/[/\\]/);
15864
16009
  return parts[parts.length - 1] ?? p;
15865
16010
  }
@@ -15871,7 +16016,7 @@ function checkPlanCoverage(taskText, stepDescriptions) {
15871
16016
  `);
15872
16017
  const missing = taskPaths.filter((p) => {
15873
16018
  const lower = p.toLowerCase();
15874
- const base = basename2(lower);
16019
+ const base = basename3(lower);
15875
16020
  return !stepText.includes(lower) && !stepText.includes(base);
15876
16021
  });
15877
16022
  return { missing };
@@ -16133,6 +16278,23 @@ ${lines.join(`
16133
16278
  };
16134
16279
  }
16135
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
+ }
16136
16298
  if (!this.tracker) {
16137
16299
  return { success: false, output: t("plan.no_active") };
16138
16300
  }
@@ -16246,38 +16408,70 @@ ${progress}`,
16246
16408
  }
16247
16409
  if (action === "add" && Array.isArray(args.items)) {
16248
16410
  const items = args.items.map(String);
16249
- 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();
16250
16419
  return {
16251
16420
  success: true,
16252
16421
  output: t("todo.added", {
16253
16422
  count: String(items.length),
16254
16423
  items: items.join(", ")
16255
- })
16424
+ }),
16425
+ display
16256
16426
  };
16257
16427
  }
16258
16428
  if (action === "done") {
16259
- if (!currentStep) {
16260
- 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
+ };
16261
16435
  }
16262
- this.tracker.updateStepStatus(currentStep.id, "done");
16263
- 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;
16264
16454
  this.store.saveActive(this.tracker.getPlan());
16455
+ const doneCount = subs.filter((s) => s.done).length;
16265
16456
  const display = this.tracker.toPromptBlock();
16266
- return {
16267
- success: true,
16268
- output: t("plan.step_status", {
16269
- step: String(currentStep.id),
16270
- status: "done"
16271
- }),
16272
- display
16273
- };
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 };
16274
16466
  }
16275
16467
  if (action === "list") {
16276
- 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)"];
16277
16470
  return {
16278
16471
  success: true,
16279
16472
  output: `Step ${currentStep.id}: ${currentStep.description}
16280
- Sub-tasks: ${note}`
16473
+ ${lines.join(`
16474
+ `)}`
16281
16475
  };
16282
16476
  }
16283
16477
  return {
@@ -16322,7 +16516,7 @@ Sub-tasks: ${note}`
16322
16516
  }
16323
16517
  }
16324
16518
  if (this.tracker?.isComplete()) {
16325
- this.stuckDetector.reset();
16519
+ this.stuckDetector.resetStepProgress();
16326
16520
  this.consecutivePlanWarnings = 0;
16327
16521
  this.lastStepId = -1;
16328
16522
  this.stuckNotified = false;
@@ -16366,7 +16560,7 @@ Sub-tasks: ${note}`
16366
16560
  this.stuckNotified = true;
16367
16561
  }
16368
16562
  }
16369
- if (this.stuckDetector.isStuck() || this.stuckDetector.hasRepetitiveToolCalls()) {
16563
+ if (this.stuckDetector.isStuck() || this.stuckDetector.hasRepetitiveToolCalls() || this.stuckDetector.hasReadOnlyLoop()) {
16370
16564
  const currentIter = typeof ctx.iteration === "number" ? ctx.iteration : 0;
16371
16565
  if (currentIter - this.lastRecoveryIteration >= STUCK_RECOVERY_COOLDOWN) {
16372
16566
  const recovery = this.stuckDetector.getRecoveryMessage();
@@ -17554,6 +17748,31 @@ var init_browser2 = __esm(() => {
17554
17748
  init_types();
17555
17749
  });
17556
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
+
17557
17776
  // src/modules/lsp/client.ts
17558
17777
  import { spawn as spawn6, execSync as execSync2 } from "child_process";
17559
17778
  import { resolve as resolve19 } from "path";
@@ -17619,7 +17838,7 @@ class LspClient {
17619
17838
  }
17620
17839
  return new Promise((resolve20, reject) => {
17621
17840
  const args = config.args ?? [];
17622
- const proc = spawn6(config.command, args, {
17841
+ const proc = spawn6(resolveSpawnCommand(config.command), args, {
17623
17842
  stdio: ["pipe", "pipe", "pipe"],
17624
17843
  env: { ...process.env, ...config.env },
17625
17844
  cwd: baseDir
@@ -17784,10 +18003,12 @@ class LspClient {
17784
18003
  }
17785
18004
  }
17786
18005
  var DEFAULT_TIMEOUT = 15000;
17787
- var init_client2 = () => {};
18006
+ var init_client2 = __esm(() => {
18007
+ init_command();
18008
+ });
17788
18009
 
17789
18010
  // src/modules/lsp/module.ts
17790
- import { existsSync as existsSync34 } from "fs";
18011
+ import { existsSync as existsSync35 } from "fs";
17791
18012
  import { resolve as resolve20 } from "path";
17792
18013
 
17793
18014
  class LspModule {
@@ -17813,7 +18034,7 @@ class LspModule {
17813
18034
  if (!filePath)
17814
18035
  return;
17815
18036
  const fullPath = resolve20(_ctx.baseDir, filePath);
17816
- if (!existsSync34(fullPath))
18037
+ if (!existsSync35(fullPath))
17817
18038
  return;
17818
18039
  const serverConfig = getServerForFile(fullPath, self.config);
17819
18040
  if (!serverConfig)
@@ -17879,8 +18100,8 @@ var init_lsp = __esm(() => {
17879
18100
  });
17880
18101
 
17881
18102
  // src/modules/indexer/walker.ts
17882
- import { readdirSync as readdirSync13, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync35, watch } from "fs";
17883
- 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";
17884
18105
 
17885
18106
  class Indexer {
17886
18107
  baseDir;
@@ -17907,7 +18128,7 @@ class Indexer {
17907
18128
  let totalSize = 0;
17908
18129
  let count = 0;
17909
18130
  const walkDir = (dir) => {
17910
- if (!existsSync35(dir))
18131
+ if (!existsSync36(dir))
17911
18132
  return;
17912
18133
  let entries;
17913
18134
  try {
@@ -17918,7 +18139,7 @@ class Indexer {
17918
18139
  for (const entry of entries) {
17919
18140
  if (count >= this.MAX_FILES)
17920
18141
  return;
17921
- const fullPath = join28(dir, entry);
18142
+ const fullPath = join29(dir, entry);
17922
18143
  const relPath = relative2(this.baseDir, fullPath);
17923
18144
  const stat = statSync7(fullPath);
17924
18145
  if (stat.isDirectory()) {
@@ -17981,19 +18202,19 @@ var init_walker = __esm(() => {
17981
18202
  });
17982
18203
 
17983
18204
  // src/modules/indexer/cache.ts
17984
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync13, existsSync as existsSync36, mkdirSync as mkdirSync16, rmSync as rmSync3 } from "fs";
17985
- 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";
17986
18207
 
17987
18208
  class IndexCache {
17988
18209
  cachePath;
17989
18210
  cache = null;
17990
18211
  constructor(cacheDir) {
17991
- this.cachePath = join29(cacheDir, "index-cache.json");
18212
+ this.cachePath = join30(cacheDir, "index-cache.json");
17992
18213
  }
17993
18214
  load() {
17994
18215
  if (this.cache)
17995
18216
  return this.cache;
17996
- if (!existsSync36(this.cachePath))
18217
+ if (!existsSync37(this.cachePath))
17997
18218
  return null;
17998
18219
  try {
17999
18220
  this.cache = JSON.parse(readFileSync23(this.cachePath, "utf-8"));
@@ -18004,14 +18225,14 @@ class IndexCache {
18004
18225
  }
18005
18226
  save(result) {
18006
18227
  this.cache = result;
18007
- const dir = join29(this.cachePath, "..");
18008
- if (!existsSync36(dir))
18228
+ const dir = join30(this.cachePath, "..");
18229
+ if (!existsSync37(dir))
18009
18230
  mkdirSync16(dir, { recursive: true });
18010
18231
  writeFileSync13(this.cachePath, JSON.stringify(result), "utf-8");
18011
18232
  }
18012
18233
  invalidate() {
18013
18234
  this.cache = null;
18014
- if (existsSync36(this.cachePath)) {
18235
+ if (existsSync37(this.cachePath)) {
18015
18236
  try {
18016
18237
  rmSync3(this.cachePath);
18017
18238
  } catch {}
@@ -18369,13 +18590,13 @@ var init_mcp = __esm(() => {
18369
18590
 
18370
18591
  // src/modules/memory/module.ts
18371
18592
  import { homedir as homedir10 } from "os";
18372
- import { join as join30 } from "path";
18593
+ import { join as join31 } from "path";
18373
18594
 
18374
18595
  class MemoryModule {
18375
18596
  name = "memory";
18376
18597
  store;
18377
18598
  constructor(memoryDir) {
18378
- const dir = memoryDir || join30(homedir10(), ".mma", "memory");
18599
+ const dir = memoryDir || join31(homedir10(), ".mma", "memory");
18379
18600
  this.store = new MemoryStore(dir);
18380
18601
  }
18381
18602
  getSystemPromptBlock() {
@@ -18423,8 +18644,8 @@ __export(exports_bootstrap, {
18423
18644
  bootstrap: () => bootstrap
18424
18645
  });
18425
18646
  import { homedir as homedir11 } from "os";
18426
- import { join as join31, resolve as resolve21 } from "path";
18427
- 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";
18428
18649
  function buildSystemInfo(config, baseDir, profileCompressed) {
18429
18650
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
18430
18651
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -18449,8 +18670,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
18449
18670
  `);
18450
18671
  }
18451
18672
  async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18452
- const dir = configDir || join31(homedir11(), ".mma");
18453
- 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");
18454
18675
  const config = loadConfig({ configDir: dir, projectConfigPath });
18455
18676
  setLocale(config.locale);
18456
18677
  try {
@@ -18460,7 +18681,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18460
18681
  }
18461
18682
  } catch {}
18462
18683
  const logger = new Logger(config.logLevel);
18463
- logger.setLogDir(join31(dir, "logs"));
18684
+ logger.setLogDir(join32(dir, "logs"));
18464
18685
  logger.debug("MMA bootstrap", {
18465
18686
  version: config.version,
18466
18687
  model: config.model
@@ -18482,7 +18703,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18482
18703
  logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
18483
18704
  }
18484
18705
  }
18485
- const profile = new UserProfile(join31(dir));
18706
+ const profile = new UserProfile(join32(dir));
18486
18707
  profile.load() || profile.collect();
18487
18708
  profile.save();
18488
18709
  const llmProvider = new OpenAICompatProvider({
@@ -18494,7 +18715,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18494
18715
  rateLimits: config.security?.rateLimits
18495
18716
  });
18496
18717
  const baseDir = projectDir ? resolve21(projectDir) : process.cwd();
18497
- const projectMapCacheDir = join31(baseDir, ".mma");
18718
+ const projectMapCacheDir = join32(baseDir, ".mma");
18498
18719
  const indexerModule = new IndexerModule({
18499
18720
  baseDir,
18500
18721
  cacheDir: projectMapCacheDir
@@ -18505,9 +18726,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18505
18726
  logger.warn(`Project indexing failed: ${err.message}`);
18506
18727
  }
18507
18728
  const skillsLoader = new SkillsLoader;
18508
- const builtinDir = join31(import.meta.dirname, "skills", "builtin");
18509
- const globalDir = join31(homedir11(), ".agents", "skills");
18510
- 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");
18511
18732
  const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
18512
18733
  const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
18513
18734
  const skillsModule = new SkillsModule(availableSkills, skillsBudget);
@@ -18521,11 +18742,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18521
18742
  essential: true,
18522
18743
  estimatedTokens: Math.ceil(systemInfoContent.length / 4)
18523
18744
  };
18524
- const agentsMdGlobal = join31(dir, "AGENTS.md");
18525
- if (!existsSync37(agentsMdGlobal)) {
18745
+ const agentsMdGlobal = join32(dir, "AGENTS.md");
18746
+ if (!existsSync38(agentsMdGlobal)) {
18526
18747
  writeFileSync14(agentsMdGlobal, "", "utf-8");
18527
18748
  }
18528
- const sessionDir = join31(dir, "sessions");
18749
+ const sessionDir = join32(dir, "sessions");
18529
18750
  const sessionStore = new SessionStore(sessionDir);
18530
18751
  sessionStore.init();
18531
18752
  const sessionManager = new SessionManager(sessionStore, {
@@ -18592,7 +18813,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18592
18813
  const mcpModule = new MCPModule(config);
18593
18814
  await mcpModule.initialize();
18594
18815
  moduleRegistry.register(mcpModule);
18595
- const memoryModule = new MemoryModule(join31(dir, "memory"));
18816
+ const memoryModule = new MemoryModule(join32(dir, "memory"));
18596
18817
  moduleRegistry.register(memoryModule);
18597
18818
  if (config.browser.enabled) {
18598
18819
  const browserModule = new BrowserModule;
@@ -18642,8 +18863,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18642
18863
  pluginManager.register(plugin);
18643
18864
  pluginManager.register(plugin2);
18644
18865
  const pluginLoader = new PluginLoader;
18645
- const globalPluginsDir = join31(homedir11(), ".mma", "plugins");
18646
- const projectPluginsDir = join31(baseDir, ".mma", "plugins");
18866
+ const globalPluginsDir = join32(homedir11(), ".mma", "plugins");
18867
+ const projectPluginsDir = join32(baseDir, ".mma", "plugins");
18647
18868
  pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
18648
18869
  pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
18649
18870
  contextManager.onCompact = (summary) => {
@@ -18661,12 +18882,12 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18661
18882
  const skipAgentsMd = noAgentsMd === true;
18662
18883
  if (!skipAgentsMd) {
18663
18884
  const agentsMdCandidates = [
18664
- join31(baseDir, "AGENTS.md"),
18665
- join31(baseDir, ".mma", "AGENTS.md"),
18666
- join31(dir, "AGENTS.md")
18885
+ join32(baseDir, "AGENTS.md"),
18886
+ join32(baseDir, ".mma", "AGENTS.md"),
18887
+ join32(dir, "AGENTS.md")
18667
18888
  ];
18668
18889
  for (const p of agentsMdCandidates) {
18669
- if (existsSync37(p)) {
18890
+ if (existsSync38(p)) {
18670
18891
  const content = readFileSync24(p, "utf-8").trim();
18671
18892
  if (content) {
18672
18893
  agentsMdBlocks.push({
@@ -19516,12 +19737,12 @@ __export(exports_manifest, {
19516
19737
  getCertMark: () => getCertMark,
19517
19738
  MANIFEST_PATH: () => MANIFEST_PATH
19518
19739
  });
19519
- 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";
19520
19741
  import { homedir as homedir13 } from "os";
19521
- import { join as join33 } from "path";
19742
+ import { join as join34 } from "path";
19522
19743
  function readManifest(path = MANIFEST_PATH) {
19523
19744
  try {
19524
- if (existsSync38(path)) {
19745
+ if (existsSync39(path)) {
19525
19746
  const raw = JSON.parse(readFileSync25(path, "utf-8"));
19526
19747
  return { version: 1, certifications: raw.certifications ?? [] };
19527
19748
  }
@@ -19529,7 +19750,7 @@ function readManifest(path = MANIFEST_PATH) {
19529
19750
  return { version: 1, certifications: [] };
19530
19751
  }
19531
19752
  function saveManifest(m, path = MANIFEST_PATH) {
19532
- mkdirSync17(join33(homedir13(), ".mma"), { recursive: true });
19753
+ mkdirSync17(join34(homedir13(), ".mma"), { recursive: true });
19533
19754
  writeFileSync15(path, JSON.stringify(m, null, 2), "utf-8");
19534
19755
  }
19535
19756
  function upsertCertification(entry, path = MANIFEST_PATH) {
@@ -19564,7 +19785,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
19564
19785
  }
19565
19786
  var MANIFEST_PATH;
19566
19787
  var init_manifest = __esm(() => {
19567
- MANIFEST_PATH = join33(homedir13(), ".mma", "certifications.json");
19788
+ MANIFEST_PATH = join34(homedir13(), ".mma", "certifications.json");
19568
19789
  });
19569
19790
 
19570
19791
  // node_modules/yaml/dist/nodes/identity.js
@@ -26687,8 +26908,8 @@ var init_scenarios = __esm(() => {
26687
26908
  });
26688
26909
 
26689
26910
  // src/modules/certification/loader.ts
26690
- import { existsSync as existsSync39, readdirSync as readdirSync14, readFileSync as readFileSync26 } from "fs";
26691
- 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";
26692
26913
  function validateScenario(s) {
26693
26914
  const errors2 = [];
26694
26915
  const isSkip = s.mode === "skip";
@@ -26737,12 +26958,12 @@ function loadScenarios(userDir) {
26737
26958
  else
26738
26959
  scenarios.push(s);
26739
26960
  }
26740
- if (userDir && existsSync39(userDir)) {
26961
+ if (userDir && existsSync40(userDir)) {
26741
26962
  for (const file of readdirSync14(userDir)) {
26742
26963
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
26743
26964
  continue;
26744
26965
  try {
26745
- const raw = readFileSync26(join34(userDir, file), "utf-8");
26966
+ const raw = readFileSync26(join35(userDir, file), "utf-8");
26746
26967
  const data = $parse(raw);
26747
26968
  const parsed = normalizeScenario(data, file);
26748
26969
  const errs = validateScenario(parsed);
@@ -26795,8 +27016,8 @@ var init_loader3 = __esm(() => {
26795
27016
  });
26796
27017
 
26797
27018
  // src/modules/certification/fact-checker.ts
26798
- import { existsSync as existsSync40, readFileSync as readFileSync27, statSync as statSync8 } from "fs";
26799
- 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";
26800
27021
  function checkSandbox(sandboxDir, checks, exitCode, output) {
26801
27022
  const failures = [];
26802
27023
  for (const check of checks) {
@@ -26813,13 +27034,13 @@ function runCheck(sandboxDir, check, exitCode, output) {
26813
27034
  case "outputContains":
26814
27035
  return output.includes(check.text);
26815
27036
  case "fileExists":
26816
- return isFile(join35(sandboxDir, check.path));
27037
+ return isFile(join36(sandboxDir, check.path));
26817
27038
  case "fileNotExists":
26818
- return !existsSync40(join35(sandboxDir, check.path));
27039
+ return !existsSync41(join36(sandboxDir, check.path));
26819
27040
  case "dirExists":
26820
- return isDir(join35(sandboxDir, check.path));
27041
+ return isDir(join36(sandboxDir, check.path));
26821
27042
  case "fileContent": {
26822
- const abs = join35(sandboxDir, check.path);
27043
+ const abs = join36(sandboxDir, check.path);
26823
27044
  if (!isFile(abs))
26824
27045
  return false;
26825
27046
  const content = readFileSync27(abs, "utf-8");
@@ -26830,7 +27051,7 @@ function runCheck(sandboxDir, check, exitCode, output) {
26830
27051
  return false;
26831
27052
  }
26832
27053
  case "fileRegex": {
26833
- const abs = join35(sandboxDir, check.path);
27054
+ const abs = join36(sandboxDir, check.path);
26834
27055
  if (!isFile(abs))
26835
27056
  return false;
26836
27057
  return new RegExp(check.pattern).test(readFileSync27(abs, "utf-8"));
@@ -26841,14 +27062,14 @@ function runCheck(sandboxDir, check, exitCode, output) {
26841
27062
  }
26842
27063
  function isFile(p) {
26843
27064
  try {
26844
- return existsSync40(p) && statSync8(p).isFile();
27065
+ return existsSync41(p) && statSync8(p).isFile();
26845
27066
  } catch {
26846
27067
  return false;
26847
27068
  }
26848
27069
  }
26849
27070
  function isDir(p) {
26850
27071
  try {
26851
- return existsSync40(p) && statSync8(p).isDirectory();
27072
+ return existsSync41(p) && statSync8(p).isDirectory();
26852
27073
  } catch {
26853
27074
  return false;
26854
27075
  }
@@ -26879,9 +27100,9 @@ var init_fact_checker = () => {};
26879
27100
 
26880
27101
  // src/modules/certification/runner.ts
26881
27102
  import { spawn as spawn7 } from "child_process";
26882
- import { existsSync as existsSync41, mkdirSync as mkdirSync18, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
26883
- import { platform as platform5 } from "os";
26884
- 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";
26885
27106
  async function runScenario(scenario, opts) {
26886
27107
  if (scenario.mode === "skip") {
26887
27108
  return {
@@ -26900,7 +27121,7 @@ async function runScenario(scenario, opts) {
26900
27121
  let passed = 0;
26901
27122
  let firstError;
26902
27123
  for (let i = 1;i <= reps; i++) {
26903
- const sandbox = join36(opts.sandboxBase, `run-${scenario.id}-${i}`);
27124
+ const sandbox = join37(opts.sandboxBase, `run-${scenario.id}-${i}`);
26904
27125
  let failures = [];
26905
27126
  let exitCode = -1;
26906
27127
  let output = "";
@@ -26961,20 +27182,20 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
26961
27182
  rmSync4(sandbox, { recursive: true, force: true });
26962
27183
  mkdirSync18(sandbox, { recursive: true });
26963
27184
  for (const f of scenario.fixtures ?? []) {
26964
- const src = join36(mmaRoot, f.source);
26965
- if (!existsSync41(src)) {
27185
+ const src = join37(mmaRoot, f.source);
27186
+ if (!existsSync42(src)) {
26966
27187
  throw new Error(`fixture missing: ${f.source}`);
26967
27188
  }
26968
- const dest = join36(sandbox, f.dest);
27189
+ const dest = join37(sandbox, f.dest);
26969
27190
  mkdirSync18(dirname9(dest), { recursive: true });
26970
27191
  cpSync2(src, dest);
26971
27192
  }
26972
27193
  }
26973
27194
  function resolveMmaEntry(mmaRoot) {
26974
- const dev = join36(mmaRoot, "src", "cli", "main.ts");
26975
- if (existsSync41(dev))
27195
+ const dev = join37(mmaRoot, "src", "cli", "main.ts");
27196
+ if (existsSync42(dev))
26976
27197
  return dev;
26977
- return join36(mmaRoot, "dist", "main.js");
27198
+ return join37(mmaRoot, "dist", "main.js");
26978
27199
  }
26979
27200
  function findMmaRoot(fromDir) {
26980
27201
  const candidates = [
@@ -26982,7 +27203,7 @@ function findMmaRoot(fromDir) {
26982
27203
  resolve22(fromDir, "..")
26983
27204
  ];
26984
27205
  for (const c of candidates) {
26985
- if (existsSync41(join36(c, "package.json")))
27206
+ if (existsSync42(join37(c, "package.json")))
26986
27207
  return c;
26987
27208
  }
26988
27209
  return process.cwd();
@@ -26991,7 +27212,7 @@ function killTree2(child) {
26991
27212
  const pid = child.pid;
26992
27213
  if (!pid)
26993
27214
  return;
26994
- if (platform5() === "win32") {
27215
+ if (platform6() === "win32") {
26995
27216
  spawn7("taskkill", ["/pid", String(pid), "/T", "/F"], {
26996
27217
  windowsHide: true,
26997
27218
  stdio: "ignore"
@@ -27050,13 +27271,13 @@ __export(exports_cli, {
27050
27271
  });
27051
27272
  import { rmSync as rmSync5 } from "fs";
27052
27273
  import { homedir as homedir14 } from "os";
27053
- import { join as join37, dirname as dirname10 } from "path";
27274
+ import { join as join38, dirname as dirname10 } from "path";
27054
27275
  import { fileURLToPath as fileURLToPath2 } from "url";
27055
- import { existsSync as existsSync42, readFileSync as readFileSync28 } from "fs";
27276
+ import { existsSync as existsSync43, readFileSync as readFileSync28 } from "fs";
27056
27277
  function readVersion() {
27057
- const candidates = [join37(MMA_ROOT, "package.json")];
27278
+ const candidates = [join38(MMA_ROOT, "package.json")];
27058
27279
  for (const p of candidates) {
27059
- if (existsSync42(p)) {
27280
+ if (existsSync43(p)) {
27060
27281
  try {
27061
27282
  const raw = JSON.parse(readFileSync28(p, "utf-8"));
27062
27283
  if (raw.version)
@@ -27094,7 +27315,7 @@ async function certify(opts) {
27094
27315
  return;
27095
27316
  }
27096
27317
  console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
27097
- const sandboxBase = join37(process.cwd(), ".mma", "certification");
27318
+ const sandboxBase = join38(process.cwd(), ".mma", "certification");
27098
27319
  const results = [];
27099
27320
  const total = selected.length;
27100
27321
  let idx = 0;
@@ -27208,7 +27429,7 @@ var init_cli = __esm(() => {
27208
27429
  init_manifest();
27209
27430
  HERE = dirname10(fileURLToPath2(import.meta.url));
27210
27431
  MMA_ROOT = findMmaRoot(HERE);
27211
- USER_SCENARIO_DIR = join37(homedir14(), ".mma", "certification", "scenarios");
27432
+ USER_SCENARIO_DIR = join38(homedir14(), ".mma", "certification", "scenarios");
27212
27433
  });
27213
27434
 
27214
27435
  // src/cli/repl-commands.ts
@@ -27217,18 +27438,18 @@ __export(exports_repl_commands, {
27217
27438
  registerAllCommands: () => registerAllCommands,
27218
27439
  COMMAND_GROUPS: () => COMMAND_GROUPS
27219
27440
  });
27220
- import { join as join39, dirname as dirname12 } from "path";
27441
+ import { join as join40, dirname as dirname12 } from "path";
27221
27442
  import { homedir as homedir16 } from "os";
27222
- import { existsSync as existsSync44, readFileSync as readFileSync30 } from "fs";
27443
+ import { existsSync as existsSync45, readFileSync as readFileSync30 } from "fs";
27223
27444
  import { fileURLToPath as fileURLToPath4 } from "url";
27224
27445
  function readVersion3() {
27225
27446
  const here = dirname12(fileURLToPath4(import.meta.url));
27226
27447
  const candidates = [
27227
- join39(here, "..", "..", "package.json"),
27228
- join39(here, "..", "package.json")
27448
+ join40(here, "..", "..", "package.json"),
27449
+ join40(here, "..", "package.json")
27229
27450
  ];
27230
27451
  for (const p of candidates) {
27231
- if (existsSync44(p)) {
27452
+ if (existsSync45(p)) {
27232
27453
  try {
27233
27454
  const raw = JSON.parse(readFileSync30(p, "utf8"));
27234
27455
  if (raw.version)
@@ -27294,7 +27515,7 @@ function registerMmaCommands(ctx) {
27294
27515
  }
27295
27516
  try {
27296
27517
  const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
27297
- const { existsSync: existsSync45 } = await import("fs");
27518
+ const { existsSync: existsSync46 } = await import("fs");
27298
27519
  const { resolve: resolve23 } = await import("path");
27299
27520
  let dataUrl;
27300
27521
  let label;
@@ -27314,7 +27535,7 @@ function registerMmaCommands(ctx) {
27314
27535
  label = source;
27315
27536
  } else {
27316
27537
  const absPath = resolve23(process.cwd(), source);
27317
- if (!existsSync45(absPath)) {
27538
+ if (!existsSync46(absPath)) {
27318
27539
  console.log(pc2.red(t("image.not_found", { path: source })));
27319
27540
  return;
27320
27541
  }
@@ -27393,7 +27614,7 @@ function registerMmaCommands(ctx) {
27393
27614
  console.log(pc2.yellow(t("repl.wizard_running")));
27394
27615
  await ctx.withExclusiveInput(async () => {
27395
27616
  const answers = await runSetup(ctx.rl);
27396
- const configPath = join39(homedir16(), ".mma", "config.json");
27617
+ const configPath = join40(homedir16(), ".mma", "config.json");
27397
27618
  ctx.config.provider.type = answers.provider;
27398
27619
  ctx.config.provider.baseUrl = answers.apiBase;
27399
27620
  ctx.config.provider.apiKey = answers.apiKey;
@@ -27447,7 +27668,7 @@ Excluded blocks: ${info.excluded.length}`));
27447
27668
  return;
27448
27669
  }
27449
27670
  ctx.config.provider.type = name;
27450
- const configPath = join39(homedir16(), ".mma", "config.json");
27671
+ const configPath = join40(homedir16(), ".mma", "config.json");
27451
27672
  saveConfig(ctx.config, configPath);
27452
27673
  await ctx.agent.reconfigure(ctx.config);
27453
27674
  console.log(pc2.green(t("repl.provider_set", { name })));
@@ -27503,7 +27724,7 @@ Excluded blocks: ${info.excluded.length}`));
27503
27724
  return;
27504
27725
  }
27505
27726
  ctx.config.model = name;
27506
- const configPath = join39(homedir16(), ".mma", "config.json");
27727
+ const configPath = join40(homedir16(), ".mma", "config.json");
27507
27728
  saveConfig(ctx.config, configPath);
27508
27729
  await ctx.agent.reconfigure(ctx.config);
27509
27730
  console.log(pc2.green(t("repl.model_set", { name })));
@@ -27528,7 +27749,7 @@ Excluded blocks: ${info.excluded.length}`));
27528
27749
  return;
27529
27750
  }
27530
27751
  ctx.config.contextWindow = size;
27531
- const configPath = join39(homedir16(), ".mma", "config.json");
27752
+ const configPath = join40(homedir16(), ".mma", "config.json");
27532
27753
  saveConfig(ctx.config, configPath);
27533
27754
  await ctx.agent.reconfigure(ctx.config);
27534
27755
  console.log(pc2.green(t("cli.context_set", { size })));
@@ -27547,10 +27768,10 @@ Excluded blocks: ${info.excluded.length}`));
27547
27768
  ctx.agent.shutdown();
27548
27769
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
27549
27770
  const { homedir: homedir17 } = await import("os");
27550
- const { join: join40 } = await import("path");
27771
+ const { join: join41 } = await import("path");
27551
27772
  const configDir = ctx.configDir;
27552
27773
  const baseDir = ctx.baseDir;
27553
- const projectConfigPath = join40(baseDir, ".mmrc");
27774
+ const projectConfigPath = join41(baseDir, ".mmrc");
27554
27775
  const freshConfig = loadConfig2({ configDir, projectConfigPath });
27555
27776
  Object.assign(ctx.config, freshConfig);
27556
27777
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
@@ -27850,14 +28071,14 @@ init_bootstrap();
27850
28071
  init_config2();
27851
28072
  init_setup();
27852
28073
  init_i18n();
27853
- import { join as join38, dirname as dirname11 } from "path";
28074
+ import { join as join39, dirname as dirname11 } from "path";
27854
28075
  import { homedir as homedir15 } from "os";
27855
- import { existsSync as existsSync43, readFileSync as readFileSync29 } from "fs";
28076
+ import { existsSync as existsSync44, readFileSync as readFileSync29 } from "fs";
27856
28077
 
27857
28078
  // src/cli/security-commands.ts
27858
28079
  init_bootstrap();
27859
28080
  init_config2();
27860
- import { join as join32 } from "path";
28081
+ import { join as join33 } from "path";
27861
28082
  import { homedir as homedir12 } from "os";
27862
28083
 
27863
28084
  // src/modules/security/security-policies.ts
@@ -28387,7 +28608,7 @@ function createSecurityCommand(program2) {
28387
28608
  }
28388
28609
  });
28389
28610
  securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
28390
- const configPath = join32(homedir12(), ".mma", "config.json");
28611
+ const configPath = join33(homedir12(), ".mma", "config.json");
28391
28612
  const { config: appConfig } = await bootstrap();
28392
28613
  const validPresets = ["strict", "balanced", "permissive"];
28393
28614
  if (!validPresets.includes(preset)) {
@@ -28402,7 +28623,7 @@ function createSecurityCommand(program2) {
28402
28623
  console.log(t("cli.security.policy_description", { description: policy.description }));
28403
28624
  });
28404
28625
  securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
28405
- const configPath = join32(homedir12(), ".mma", "config.json");
28626
+ const configPath = join33(homedir12(), ".mma", "config.json");
28406
28627
  const { config: appConfig } = await bootstrap();
28407
28628
  appConfig.security = appConfig.security || {};
28408
28629
  appConfig.security.sessionEncryption = {
@@ -28414,7 +28635,7 @@ function createSecurityCommand(program2) {
28414
28635
  console.log(t("cli.security.encryption_enabled"));
28415
28636
  });
28416
28637
  securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
28417
- const configPath = join32(homedir12(), ".mma", "config.json");
28638
+ const configPath = join33(homedir12(), ".mma", "config.json");
28418
28639
  const { config: appConfig } = await bootstrap();
28419
28640
  appConfig.security = appConfig.security || {};
28420
28641
  appConfig.security.sessionEncryption = {
@@ -28426,7 +28647,7 @@ function createSecurityCommand(program2) {
28426
28647
  console.log(t("cli.security.encryption_disabled"));
28427
28648
  });
28428
28649
  securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
28429
- const configPath = join32(homedir12(), ".mma", "config.json");
28650
+ const configPath = join33(homedir12(), ".mma", "config.json");
28430
28651
  const { config: appConfig } = await bootstrap();
28431
28652
  appConfig.security = appConfig.security || {};
28432
28653
  appConfig.security.auditNotifier = {
@@ -28440,7 +28661,7 @@ function createSecurityCommand(program2) {
28440
28661
  console.log(t("cli.security.audit_enabled"));
28441
28662
  });
28442
28663
  securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
28443
- const configPath = join32(homedir12(), ".mma", "config.json");
28664
+ const configPath = join33(homedir12(), ".mma", "config.json");
28444
28665
  const { config: appConfig } = await bootstrap();
28445
28666
  appConfig.security = appConfig.security || {};
28446
28667
  appConfig.security.auditNotifier = {
@@ -28476,11 +28697,11 @@ import { fileURLToPath as fileURLToPath3 } from "url";
28476
28697
  function readVersion2() {
28477
28698
  const here = dirname11(fileURLToPath3(import.meta.url));
28478
28699
  const candidates = [
28479
- join38(here, "..", "..", "package.json"),
28480
- join38(here, "..", "package.json")
28700
+ join39(here, "..", "..", "package.json"),
28701
+ join39(here, "..", "package.json")
28481
28702
  ];
28482
28703
  for (const p of candidates) {
28483
- if (existsSync43(p)) {
28704
+ if (existsSync44(p)) {
28484
28705
  try {
28485
28706
  const raw = JSON.parse(readFileSync29(p, "utf8"));
28486
28707
  if (raw.version)
@@ -28495,7 +28716,7 @@ function createProgram() {
28495
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"));
28496
28717
  program2.command("init").description(t("cli.init")).action(async () => {
28497
28718
  const answers = await runSetup();
28498
- const configPath = join38(homedir15(), ".mma", "config.json");
28719
+ const configPath = join39(homedir15(), ".mma", "config.json");
28499
28720
  const { config } = await bootstrap();
28500
28721
  config.provider.type = answers.provider;
28501
28722
  config.provider.baseUrl = answers.apiBase;
@@ -28540,7 +28761,7 @@ function createProgram() {
28540
28761
  });
28541
28762
  const configCmd = program2.command("config").description(t("cli.manage_config"));
28542
28763
  configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
28543
- const configPath = join38(homedir15(), ".mma", "config.json");
28764
+ const configPath = join39(homedir15(), ".mma", "config.json");
28544
28765
  const { config } = await bootstrap();
28545
28766
  const keys = key.split(".");
28546
28767
  let obj = config;
@@ -28603,7 +28824,7 @@ function createProgram() {
28603
28824
  console.log(t("cli.model_hint"));
28604
28825
  });
28605
28826
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
28606
- const configPath = join38(homedir15(), ".mma", "config.json");
28827
+ const configPath = join39(homedir15(), ".mma", "config.json");
28607
28828
  const { config } = await bootstrap();
28608
28829
  config.model = name;
28609
28830
  saveConfig(config, configPath);
@@ -28639,7 +28860,7 @@ function createProgram() {
28639
28860
  await uncertify2(name, config);
28640
28861
  });
28641
28862
  program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
28642
- const configPath = join38(homedir15(), ".mma", "config.json");
28863
+ const configPath = join39(homedir15(), ".mma", "config.json");
28643
28864
  const { config } = await bootstrap();
28644
28865
  const contextWindow = parseInt(size, 10);
28645
28866
  if (isNaN(contextWindow) || contextWindow < 1024) {
@@ -28657,7 +28878,7 @@ function createProgram() {
28657
28878
  console.log(t("cli.base_url"), config.provider.baseUrl);
28658
28879
  });
28659
28880
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
28660
- const configPath = join38(homedir15(), ".mma", "config.json");
28881
+ const configPath = join39(homedir15(), ".mma", "config.json");
28661
28882
  const { config } = await bootstrap();
28662
28883
  config.provider.type = name;
28663
28884
  saveConfig(config, configPath);
@@ -29427,8 +29648,8 @@ class LineEditor {
29427
29648
  }
29428
29649
 
29429
29650
  // src/cli/repl.ts
29430
- import { existsSync as existsSync45, readFileSync as readFileSync31, writeFileSync as writeFileSync16 } from "fs";
29431
- 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";
29432
29653
  import { homedir as homedir17 } from "os";
29433
29654
  import { fileURLToPath as fileURLToPath5 } from "url";
29434
29655
 
@@ -29934,11 +30155,11 @@ init_repl_commands();
29934
30155
  function readVersion4() {
29935
30156
  const here = dirname13(fileURLToPath5(import.meta.url));
29936
30157
  const candidates = [
29937
- join40(here, "..", "..", "package.json"),
29938
- join40(here, "..", "package.json")
30158
+ join41(here, "..", "..", "package.json"),
30159
+ join41(here, "..", "package.json")
29939
30160
  ];
29940
30161
  for (const p of candidates) {
29941
- if (existsSync45(p)) {
30162
+ if (existsSync46(p)) {
29942
30163
  try {
29943
30164
  const raw = JSON.parse(readFileSync31(p, "utf8"));
29944
30165
  if (raw.version)
@@ -29996,10 +30217,10 @@ class Repl {
29996
30217
  this.skillsModule = skillsModule;
29997
30218
  this.pluginManager = pluginManager;
29998
30219
  this.logger = logger;
29999
- this.configDir = configDir || join40(homedir17(), ".mma");
30220
+ this.configDir = configDir || join41(homedir17(), ".mma");
30000
30221
  this.baseDir = baseDir || process.cwd();
30001
30222
  this.noAgentsMd = noAgentsMd === true;
30002
- this.historyPath = join40(homedir17(), ".mma", "repl-history");
30223
+ this.historyPath = join41(homedir17(), ".mma", "repl-history");
30003
30224
  this.loadHistory();
30004
30225
  this.rl = process.stdin.isTTY ? new LineEditor({
30005
30226
  input: process.stdin,
@@ -30032,7 +30253,7 @@ class Repl {
30032
30253
  this.setupListeners();
30033
30254
  }
30034
30255
  loadHistory() {
30035
- if (existsSync45(this.historyPath)) {
30256
+ if (existsSync46(this.historyPath)) {
30036
30257
  try {
30037
30258
  const raw = readFileSync31(this.historyPath, "utf-8");
30038
30259
  this.history = raw.split(`
@@ -30391,11 +30612,11 @@ ${t("image.clipboard_empty")}`));
30391
30612
  row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
30392
30613
  } else {
30393
30614
  const agentsMdCandidates = [
30394
- join40(this.baseDir, "AGENTS.md"),
30395
- join40(this.baseDir, ".mma", "AGENTS.md"),
30396
- join40(this.configDir, "AGENTS.md")
30615
+ join41(this.baseDir, "AGENTS.md"),
30616
+ join41(this.baseDir, ".mma", "AGENTS.md"),
30617
+ join41(this.configDir, "AGENTS.md")
30397
30618
  ];
30398
- const foundAgents = agentsMdCandidates.filter((p) => existsSync45(p));
30619
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync46(p));
30399
30620
  if (foundAgents.length > 0) {
30400
30621
  for (const p of foundAgents) {
30401
30622
  row(t("repl.agents_label"), pc2.dim(p));
@@ -30406,7 +30627,7 @@ ${t("image.clipboard_empty")}`));
30406
30627
  }
30407
30628
  const meta = this.sessionManager?.getActiveMeta();
30408
30629
  if (meta) {
30409
- const sessionPath = join40(this.configDir, "sessions", meta.id);
30630
+ const sessionPath = join41(this.configDir, "sessions", meta.id);
30410
30631
  row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
30411
30632
  }
30412
30633
  const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
@@ -30447,12 +30668,13 @@ init_setup();
30447
30668
  init_config2();
30448
30669
  init_i18n();
30449
30670
  init_colors();
30450
- import { existsSync as existsSync46, readFileSync as readFileSync32 } from "fs";
30451
- 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";
30452
30673
  import { homedir as homedir18 } from "os";
30453
30674
  import { fileURLToPath as fileURLToPath6 } from "url";
30454
30675
 
30455
30676
  // src/modules/updater/checker.ts
30677
+ init_command();
30456
30678
  var defaultRunner2 = async (command, args, options) => {
30457
30679
  const { execFile } = await import("child_process");
30458
30680
  return new Promise((resolve23) => {
@@ -30497,7 +30719,8 @@ class Updater {
30497
30719
  }
30498
30720
  async install(latest) {
30499
30721
  try {
30500
- const res = await this.runner("npm", ["install", "-g", `${this.packageName}@${latest}`], {
30722
+ const command = resolveSpawnCommand("npm");
30723
+ const res = await this.runner(command, ["install", "-g", `${this.packageName}@${latest}`], {
30501
30724
  timeout: 120000,
30502
30725
  windowsHide: true
30503
30726
  });
@@ -30601,11 +30824,11 @@ class UpdaterModule {
30601
30824
  function readVersion5() {
30602
30825
  const here = dirname14(fileURLToPath6(import.meta.url));
30603
30826
  const candidates = [
30604
- join41(here, "..", "..", "package.json"),
30605
- join41(here, "..", "package.json")
30827
+ join42(here, "..", "..", "package.json"),
30828
+ join42(here, "..", "package.json")
30606
30829
  ];
30607
30830
  for (const p of candidates) {
30608
- if (existsSync46(p)) {
30831
+ if (existsSync47(p)) {
30609
30832
  try {
30610
30833
  const raw = JSON.parse(readFileSync32(p, "utf8"));
30611
30834
  if (raw.version)
@@ -30678,15 +30901,15 @@ async function main() {
30678
30901
  agent.shutdown();
30679
30902
  process.exit(exitCode);
30680
30903
  } else {
30681
- const configPath = join41(homedir18(), ".mma", "config.json");
30682
- if (!existsSync46(configPath)) {
30904
+ const configPath = join42(homedir18(), ".mma", "config.json");
30905
+ if (!existsSync47(configPath)) {
30683
30906
  console.log(pc2.yellow(`
30684
30907
  ` + t("cli.first_run") + `
30685
30908
  `));
30686
30909
  const answers = await runSetup();
30687
30910
  const config2 = loadConfig({
30688
- configDir: join41(homedir18(), ".mma"),
30689
- projectConfigPath: projectDir ? join41(projectDir, ".mmrc") : join41(process.cwd(), ".mmrc")
30911
+ configDir: join42(homedir18(), ".mma"),
30912
+ projectConfigPath: projectDir ? join42(projectDir, ".mmrc") : join42(process.cwd(), ".mmrc")
30690
30913
  });
30691
30914
  config2.provider.type = answers.provider;
30692
30915
  config2.provider.baseUrl = answers.apiBase;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.33.2",
3
+ "version": "0.33.4",
4
4
  "description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
5
5
  "type": "module",
6
6
  "bin": {