micro-models-agent 0.19.2 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -2548,14 +2548,19 @@ Available commands:`,
2548
2548
 
2549
2549
  Use this knowledge to answer the user's question.`,
2550
2550
  "exec.stuck": "Stuck on step {stepId}. Current: {description}. No progress for {iterations} iterations.",
2551
- "exec.stuck_recovery": "[Stuck detected: {iterations} iterations without progress. Stop repeating the same approach. Try a fundamentally different strategy: use a different tool (e.g., 'browser' tool for JavaScript-heavy websites instead of 'web_browse'), break the task into smaller parts, or explain to the user what went wrong and ask for guidance.]",
2551
+ "exec.stuck_recovery": '[STUCK: {iterations} iterations on step {stepId} — "{description}". You MUST change approach NOW. Concrete actions: (1) Check what this step needs are dependencies installed? (2) Use plan show to see the plan. (3) If commands fail create files directly via write_file. (4) After completing the step, call plan update step={stepId} status=done. Do NOT work on other steps until this one is finished.]',
2552
2552
  "exec.tool_errors": "Tool {tool} failed {count} times. Suggest alternative approach.",
2553
- "exec.tool_errors_recovery": "[Tool {tool} failed {count} times. Stop using this tool and try a different approach or explain the issue to the user.]",
2554
- "exec.repetitive_tool": "[You called {tool} {count} times in a row with the same arguments and result. Stop repeating try a different approach: create files, change arguments, or explain the problem to the user.]",
2555
- "exec.consecutive_failures_recovery": "[{count} consecutive tool calls failed. You are going in circles stop trying commands that keep failing. Explain the problem to the user, or try a completely different approach: write files directly, use a different tool, or break the task into smaller parts.]",
2556
- "exec.task_reminder": "[Remember the original task: {task}. Do not switch to unrelated tasks. If you cannot complete the original task, explain why to the user and ask for guidance.]",
2557
- "exec.plan_warning": '[⚠ Warning: you are working on step {step} - "{description}". Your {tool} call touches files not mentioned in the current step. Focus on the current step or update the plan via plan update.]',
2558
- "exec.off_track": `[ Outside plan: step {stepId} is "{description}", but you're using {tool} on a different path. Explain or return.]`,
2553
+ "exec.tool_errors_recovery": "[Tool {tool} failed {count} consecutive times. DO NOT use it again. Try a different approach: (1) create files directly via write_file, (2) use a different tool for the same task, (3) if nothing works — explain the problem and skip this step via plan update step=N status=skipped with a note why.]",
2554
+ "exec.repetitive_tool": "[REPETITION: you called {tool} {count} times with identical arguments and result. This is pointless. IMMEDIATELY change approach: create files directly, change arguments, or if it's a process check its status via process_log.]",
2555
+ "exec.consecutive_failures_recovery": "[{count} CONSECUTIVE TOOLS FAILED. Stop running commands. Here is what to do: (1) Create files directly via write_file instead of terminal commands. (2) Check if dependencies are installed (npm install). (3) Use list_dir to see what's in the project. (4) Do not attempt build/tests until all files are created.]",
2556
+ "exec.task_reminder": "[ORIGINAL TASK: {task}. You MUST work on this task only. Do not create files for other tasks. If you cannot complete it explain why and request help.]",
2557
+ "exec.plan_warning": '[⚠ PLAN: you are on step {step} "{description}", but calling {tool} with files outside this step. This is FORBIDDEN work STRICTLY on the current step. First complete it and call plan update step={step} status=done, only then move to the next.]',
2558
+ "exec.plan_blocked": "[ BLOCKED: {max} consecutive calls outside the current step. You are violating the plan. Return to step {step} and complete it. Other steps are blocked until this one is done.]",
2559
+ "exec.off_track": `[⚠ OFF PLAN: step {stepId} is "{description}", but you're using {tool} on a different path. Return to the current step immediately.]`,
2560
+ "exec.step_gate_deps": '[⚠ Step {step} "{description}": dependencies are not installed. First run the install command (npm install, pip install, etc.). Verify the lock file or dependency directory exists.]',
2561
+ "exec.step_gate_empty": "[⚠ Step {step}: files exist but appear empty: {files}. Add real code to these files before advancing to the next step.]",
2562
+ "exec.step_gate_ok": '[✓] Step {step} completed and verified. MOVING to step {nextStep}: "{nextDesc}". Work ONLY on this step.',
2563
+ "exec.step_gate_last": "[✓] Step {step} completed — that was the final step. Verify everything together and provide the final answer.]",
2559
2564
  "exec.audit_pass": "[✓] Task complete: {done}/{total} steps done, {files} files verified",
2560
2565
  "exec.audit_fail": "[✗] Task incomplete: {done}/{total} steps done, {files} files missing",
2561
2566
  "exec.audit_fail_typecheck": "[✗] Task incomplete: {done}/{total} steps done, {missing} files missing, typecheck error: {typeError}",
@@ -3040,14 +3045,19 @@ var init_ru = __esm(() => {
3040
3045
 
3041
3046
  Используйте эти знания для ответа на вопрос пользователя.`,
3042
3047
  "exec.stuck": "Застряли на шаге {stepId}. Текущий: {description}. Нет прогресса {iterations} итераций.",
3043
- "exec.stuck_recovery": "[Обнаружено застревание: {iterations} итераций без прогресса. Прекратите повторять тот же подход. Попробуйте принципиально другую стратегию: используйте другой инструмент (например, 'browser' для сайтов с JavaScript вместо 'web_browse'), разбейте задачу на подзадачи или объясните пользователю что пошло не так и спросите совета.]",
3048
+ "exec.stuck_recovery": '[ЗАСТРЕВАНИЕ: {iterations} итераций на шаге {stepId} "{description}". ВЫ ДОЛЖНЫ сменить подход прямо сейчас. Конкретные действия: (1) Проверьте что нужно для этого шага установлены ли зависимости? (2) Используйте plan show чтобы увидеть план. (3) Если команды не работают создайте файлы напрямую через write_file. (4) После завершения шага вызовите plan update step={stepId} status=done. НЕ переходите к другим шагам пока этот не завершён.]',
3044
3049
  "exec.tool_errors": "Инструмент {tool} сбоил {count} раз. Предложите другой подход.",
3045
- "exec.tool_errors_recovery": "[Инструмент {tool} сбоил {count} раз. Прекратите использовать этот инструмент и попробуйте другой подход или объясните проблему пользователю.]",
3046
- "exec.repetitive_tool": "[Вы вызвали {tool} {count} раз подряд с одинаковыми аргументами и результатом. Прекратите повторять попробуйте другой подход: создайте файлы, измените аргументы или объясните пользователю проблему.]",
3047
- "exec.consecutive_failures_recovery": "[{count} последовательных вызовов тулов завершились ошибкой. Вы ходите по кругу прекратите пытаться выполнить команды, которые постоянно падают. Объясните проблему пользователю или попробуйте совершенно другой подход: напишите файлы напрямую, используйте другой инструмент или разбейте задачу на части.]",
3048
- "exec.task_reminder": "[Напоминание о задаче: {task}. Не переключайтесь на посторонние задачи. Если не можете выполнить задачу — объясните почему и спросите совета.]",
3049
- "exec.plan_warning": '[⚠ Внимание: вы работаете над шагом {step} — "{description}". Ваш вызов {tool} касается файлов, не упомянутых в текущем шаге. Сосредоточьтесь на текущем шаге или обновите план через plan update.]',
3050
- "exec.off_track": '[ Вне плана: шаг {stepId} "{description}", но вы используете {tool} для другого пути. Объясните или вернитесь.]',
3050
+ "exec.tool_errors_recovery": "[Инструмент {tool} сбоил {count} раз подряд. НЕ ИСПОЛЬЗУЙТЕ его снова. Используйте другой подход: (1) создайте нужные файлы напрямую через write_file, (2) используйте другой инструмент для той же задачи, (3) если ничего не работает — объясните проблему и переходите к следующему шагу плана через plan update step=N status=skipped с пометкой почему.]",
3051
+ "exec.repetitive_tool": "[ПОВТОРЕНИЕ: вы вызвали {tool} {count} раз с одинаковыми аргументами и результатом. Это бессмысленно. НЕМЕДЛЕННО смените подход: создайте файлы напрямую, измените аргументы или, если это процесс — проверьте его статус через process_log.]",
3052
+ "exec.consecutive_failures_recovery": "[{count} ИНСТРУМЕНТОВ ПОДРЯД УПАЛИ. Хватит пытаться запускать команды. Вот что делать: (1) Создавайте файлы напрямую через write_file вместо команд терминала. (2) Проверьте, установлены ли зависимости (npm install). (3) Используйте list_dir чтобы увидеть что есть в проекте. (4) Не пытайтесь запустить сборку/тесты пока не созданы все файлы.]",
3053
+ "exec.task_reminder": "[ИСХОДНАЯ ЗАДАЧА: {task}. ВЫ ДОЛЖНЫ работать только над этой задачей. Не создавайте файлы для других задач. Если не можете выполнить — объясните почему и запросите помощь.]",
3054
+ "exec.plan_warning": '[⚠ ПЛАН: вы на шаге {step} — "{description}", но вызываете {tool} для файлов вне этого шага. Это ЗАПРЕЩЕНО работайте СТРОГО над текущим шагом. Сначала завершите его и вызовите plan update step={step} status=done, только потом переходите к следующему.]',
3055
+ "exec.plan_blocked": "[ ЗАБЛОКИРОВАНО: {max} вызова подряд вне текущего шага. Вы нарушаете план. Вернитесь к шагу {step} и завершите его. Другие шаги будут заблокированы пока текущий не выполнен.]",
3056
+ "exec.off_track": '[⚠ ВНЕ ПЛАНА: шаг {stepId} — "{description}", но вы используете {tool} для другого пути. Вернитесь к текущему шагу немедленно.]',
3057
+ "exec.step_gate_deps": '[⚠ Шаг {step} "{description}": зависимости не установлены. Сначала выполните команду установки (npm install, pip install и т.д.). Проверьте что lock-файл или директория зависимостей существует.]',
3058
+ "exec.step_gate_empty": "[⚠ Шаг {step}: файлы существуют, но выглядят пустыми: {files}. Добавьте реальный код в эти файлы перед тем как переходить к следующему шагу.]",
3059
+ "exec.step_gate_ok": '[✓] Шаг {step} завершён и проверен. ПЕРЕХОДИМ к шагу {nextStep}: "{nextDesc}". Работайте ТОЛЬКО над этим шагом.',
3060
+ "exec.step_gate_last": "[✓] Шаг {step} завершён — это был последний шаг. Проверьте всё вместе и предоставьте финальный ответ.]",
3051
3061
  "exec.audit_pass": "[✓] Задача выполнена: {done}/{total} шагов, {files} файлов проверено",
3052
3062
  "exec.audit_fail": "[✗] Задача не выполнена: {done}/{total} шагов, {files} файлов отсутствует",
3053
3063
  "exec.audit_fail_typecheck": "[✗] Задача не выполнена: {done}/{total} шагов, {missing} файлов отсутствует, ошибка typecheck: {typeError}",
@@ -12823,11 +12833,18 @@ class StuckDetector {
12823
12833
  if (!this.hasRepetitiveToolCalls())
12824
12834
  return "";
12825
12835
  const last = this.recentToolCalls[this.recentToolCalls.length - 1];
12826
- return t("exec.repetitive_tool", { tool: last.name, count: this.repetitionThreshold });
12836
+ return t("exec.repetitive_tool", {
12837
+ tool: last.name,
12838
+ count: this.repetitionThreshold
12839
+ });
12827
12840
  }
12828
12841
  getStuckReason() {
12829
12842
  if (this.isStuck()) {
12830
- return t("exec.stuck", { stepId: String(this.currentStepId), description: this.currentStepDescription, iterations: this.iterationsOnCurrentStep });
12843
+ return t("exec.stuck", {
12844
+ stepId: String(this.currentStepId ?? "?"),
12845
+ description: this.currentStepDescription,
12846
+ iterations: this.iterationsOnCurrentStep
12847
+ });
12831
12848
  }
12832
12849
  const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
12833
12850
  if (errorTool) {
@@ -12837,14 +12854,23 @@ class StuckDetector {
12837
12854
  }
12838
12855
  getRecoveryMessage() {
12839
12856
  if (this.isStuck()) {
12840
- return t("exec.stuck_recovery", { iterations: this.iterationsOnCurrentStep });
12857
+ return t("exec.stuck_recovery", {
12858
+ iterations: this.iterationsOnCurrentStep,
12859
+ stepId: String(this.currentStepId ?? "?"),
12860
+ description: this.currentStepDescription
12861
+ });
12841
12862
  }
12842
12863
  const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
12843
12864
  if (errorTool) {
12844
- return t("exec.tool_errors_recovery", { tool: errorTool[0], count: errorTool[1] });
12865
+ return t("exec.tool_errors_recovery", {
12866
+ tool: errorTool[0],
12867
+ count: errorTool[1]
12868
+ });
12845
12869
  }
12846
12870
  if (this.hasConsecutiveFailures()) {
12847
- return t("exec.consecutive_failures_recovery", { count: this.consecutiveFailures });
12871
+ return t("exec.consecutive_failures_recovery", {
12872
+ count: this.consecutiveFailures
12873
+ });
12848
12874
  }
12849
12875
  if (this.hasRepetitiveToolCalls()) {
12850
12876
  return this.getRepetitiveToolMessage();
@@ -12859,7 +12885,11 @@ class StuckDetector {
12859
12885
  const pathInCall = (toolArgStr.match(/\b[\w./-]+\.[a-z]+/gi) || []).map((p) => p.toLowerCase());
12860
12886
  const overlaps = pathInCall.some((p) => pathInStep.some((s) => p.includes(s) || s.includes(p)));
12861
12887
  if (!overlaps && pathInStep.length > 0 && pathInCall.length > 0) {
12862
- return t("exec.off_track", { stepId: String(this.currentStepId), description: this.currentStepDescription, tool: toolName });
12888
+ return t("exec.off_track", {
12889
+ stepId: String(this.currentStepId),
12890
+ description: this.currentStepDescription,
12891
+ tool: toolName
12892
+ });
12863
12893
  }
12864
12894
  return null;
12865
12895
  }
@@ -12948,8 +12978,53 @@ var init_auditor = __esm(() => {
12948
12978
  init_i18n();
12949
12979
  });
12950
12980
 
12981
+ // src/modules/execution/plan-persister.ts
12982
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11, existsSync as existsSync25 } from "fs";
12983
+ import { join as join18 } from "path";
12984
+
12985
+ class PlanPersister {
12986
+ filePath;
12987
+ constructor(baseDir) {
12988
+ const mmaDir = join18(baseDir, ".mma");
12989
+ if (!existsSync25(mmaDir)) {
12990
+ mkdirSync11(mmaDir, { recursive: true });
12991
+ }
12992
+ this.filePath = join18(mmaDir, "plan.json");
12993
+ }
12994
+ save(plan) {
12995
+ const file = {
12996
+ title: plan.title,
12997
+ steps: plan.steps,
12998
+ createdAt: plan.createdAt,
12999
+ updatedAt: new Date().toISOString()
13000
+ };
13001
+ writeFileSync9(this.filePath, JSON.stringify(file, null, 2), "utf-8");
13002
+ }
13003
+ load() {
13004
+ if (!existsSync25(this.filePath))
13005
+ return null;
13006
+ try {
13007
+ const raw = readFileSync14(this.filePath, "utf-8");
13008
+ const file = JSON.parse(raw);
13009
+ return {
13010
+ title: file.title,
13011
+ steps: file.steps,
13012
+ createdAt: file.createdAt
13013
+ };
13014
+ } catch {
13015
+ return null;
13016
+ }
13017
+ }
13018
+ clear() {
13019
+ if (existsSync25(this.filePath)) {
13020
+ writeFileSync9(this.filePath, "", "utf-8");
13021
+ }
13022
+ }
13023
+ }
13024
+ var init_plan_persister = () => {};
13025
+
12951
13026
  // src/modules/execution/module.ts
12952
- import { existsSync as existsSync25 } from "fs";
13027
+ import { existsSync as existsSync26, readFileSync as readFileSync15 } from "fs";
12953
13028
  import { resolve as resolve14 } from "path";
12954
13029
 
12955
13030
  class ExecutionModule {
@@ -12958,16 +13033,32 @@ class ExecutionModule {
12958
13033
  verifier;
12959
13034
  stuckDetector;
12960
13035
  auditor;
13036
+ persister;
12961
13037
  baseDir;
12962
13038
  lastRecoveryIteration = -STUCK_RECOVERY_COOLDOWN;
13039
+ consecutivePlanWarnings = 0;
13040
+ lastStepId = -1;
12963
13041
  constructor(baseDir, stuckThreshold = 8) {
12964
13042
  this.baseDir = baseDir;
12965
13043
  this.verifier = new StepVerifier(baseDir);
12966
13044
  this.stuckDetector = new StuckDetector(stuckThreshold);
12967
13045
  this.auditor = new Auditor(baseDir);
13046
+ this.persister = new PlanPersister(baseDir);
12968
13047
  }
12969
13048
  setPlan(plan) {
12970
13049
  this.tracker = new PlanTracker(plan);
13050
+ this.persister.save(plan);
13051
+ }
13052
+ restorePlan() {
13053
+ const plan = this.persister.load();
13054
+ if (!plan)
13055
+ return false;
13056
+ this.tracker = new PlanTracker(plan);
13057
+ while (this.tracker.getCurrentStep()?.status === "done" || this.tracker.getCurrentStep()?.status === "skipped") {
13058
+ if (!this.tracker.advance())
13059
+ break;
13060
+ }
13061
+ return true;
12971
13062
  }
12972
13063
  getTracker() {
12973
13064
  return this.tracker;
@@ -13055,6 +13146,7 @@ ${display}`,
13055
13146
  this.tracker.updateStepStatus(Number(args.step), args.status || "done");
13056
13147
  if (args.note)
13057
13148
  this.tracker.addNote(Number(args.step), String(args.note));
13149
+ this.persister.save(this.tracker.getPlan());
13058
13150
  const progress = this.tracker.getProgressString();
13059
13151
  const display = this.tracker.toPromptBlock();
13060
13152
  return {
@@ -13066,6 +13158,7 @@ ${progress}`,
13066
13158
  }
13067
13159
  if (action === "abort") {
13068
13160
  this.tracker = null;
13161
+ this.persister.clear();
13069
13162
  return { success: true, output: t("plan.aborted") };
13070
13163
  }
13071
13164
  if (!this.tracker) {
@@ -13160,10 +13253,16 @@ Sub-tasks: ${note}`
13160
13253
  onBeforeThink: (ctx) => {
13161
13254
  const step = this.tracker?.getCurrentStep();
13162
13255
  if (this.tracker && step) {
13256
+ if (step.id !== this.lastStepId) {
13257
+ this.consecutivePlanWarnings = 0;
13258
+ this.lastStepId = step.id;
13259
+ }
13163
13260
  this.stuckDetector.setCurrentStep(step.id, step.description);
13164
13261
  this.stuckDetector.recordIteration(step.id);
13165
13262
  } else {
13166
13263
  this.stuckDetector.reset();
13264
+ this.consecutivePlanWarnings = 0;
13265
+ this.lastStepId = -1;
13167
13266
  }
13168
13267
  const stuckReason = this.stuckDetector.getStuckReason();
13169
13268
  if (stuckReason) {
@@ -13190,6 +13289,16 @@ Sub-tasks: ${note}`
13190
13289
  role: "user",
13191
13290
  content: `<system-summary>${warning}</system-summary>`
13192
13291
  });
13292
+ this.consecutivePlanWarnings++;
13293
+ if (this.consecutivePlanWarnings >= MAX_PLAN_WARNINGS_BEFORE_BLOCK) {
13294
+ ctx.contextManager.addMessage({
13295
+ role: "user",
13296
+ content: `<system-summary>${t("exec.plan_blocked", { step: String(this.tracker?.getCurrentStep()?.id ?? "?"), max: MAX_PLAN_WARNINGS_BEFORE_BLOCK })}</system-summary>`
13297
+ });
13298
+ return false;
13299
+ }
13300
+ } else {
13301
+ this.consecutivePlanWarnings = 0;
13193
13302
  }
13194
13303
  return true;
13195
13304
  },
@@ -13207,7 +13316,7 @@ Sub-tasks: ${note}`
13207
13316
  this.stuckDetector.recordToolSuccess();
13208
13317
  }
13209
13318
  if (this.tracker && result.success && (call.name === "write_file" || call.name === "edit_file")) {
13210
- this.advancePlanIfStepComplete();
13319
+ this.advancePlanIfStepComplete(ctx.contextManager);
13211
13320
  }
13212
13321
  }
13213
13322
  };
@@ -13249,32 +13358,90 @@ Sub-tasks: ${note}`
13249
13358
  tool: call.name
13250
13359
  });
13251
13360
  }
13252
- advancePlanIfStepComplete() {
13361
+ advancePlanIfStepComplete(contextManager) {
13253
13362
  const step = this.tracker?.getCurrentStep();
13254
13363
  if (!step)
13255
13364
  return;
13365
+ const stepText = step.description.toLowerCase();
13256
13366
  const stepPaths = step.description.match(/\b[\w./\\-]+\.[a-z]+/gi) || [];
13367
+ const isDepsStep = stepText.includes("install") || stepText.includes("зависим") || stepText.includes("init") || stepText.includes("инициализац");
13368
+ if (isDepsStep) {
13369
+ const lockFiles = [
13370
+ "package-lock.json",
13371
+ "bun.lockb",
13372
+ "yarn.lock",
13373
+ "pnpm-lock.yaml",
13374
+ "node_modules",
13375
+ "go.sum",
13376
+ "Cargo.lock",
13377
+ "Pipfile.lock",
13378
+ "poetry.lock",
13379
+ "requirements.txt"
13380
+ ];
13381
+ const hasLockFile = lockFiles.some((f) => existsSync26(resolve14(this.baseDir, f)));
13382
+ if (!hasLockFile) {
13383
+ if (contextManager) {
13384
+ contextManager.addMessage({
13385
+ role: "user",
13386
+ content: `<system-summary>${t("exec.step_gate_deps", { step: String(step.id), description: step.description })}</system-summary>`
13387
+ });
13388
+ }
13389
+ return;
13390
+ }
13391
+ }
13257
13392
  if (stepPaths.length === 0)
13258
13393
  return;
13259
- const allExist = stepPaths.every((p) => existsSync25(resolve14(this.baseDir, p)));
13260
- if (allExist) {
13261
- this.tracker?.updateStepStatus(step.id, "done");
13262
- this.tracker?.advance();
13394
+ const allExist = stepPaths.every((p) => existsSync26(resolve14(this.baseDir, p)));
13395
+ if (!allExist)
13396
+ return;
13397
+ const emptyFiles = [];
13398
+ for (const p of stepPaths) {
13399
+ try {
13400
+ const content = readFileSync15(resolve14(this.baseDir, p), "utf-8");
13401
+ if (content.trim().length < 10) {
13402
+ emptyFiles.push(p);
13403
+ }
13404
+ } catch {}
13405
+ }
13406
+ if (emptyFiles.length > 0 && contextManager) {
13407
+ contextManager.addMessage({
13408
+ role: "user",
13409
+ content: `<system-summary>${t("exec.step_gate_empty", { step: String(step.id), files: emptyFiles.join(", ") })}</system-summary>`
13410
+ });
13411
+ return;
13412
+ }
13413
+ this.tracker?.updateStepStatus(step.id, "done");
13414
+ const hadNext = this.tracker?.advance() ?? false;
13415
+ if (this.tracker) {
13416
+ this.persister.save(this.tracker.getPlan());
13417
+ }
13418
+ if (contextManager) {
13419
+ const nextStep = hadNext ? this.tracker?.getCurrentStep() : null;
13420
+ const nextMsg = nextStep ? t("exec.step_gate_ok", {
13421
+ step: String(step.id),
13422
+ nextStep: String(nextStep.id),
13423
+ nextDesc: nextStep.description
13424
+ }) : t("exec.step_gate_last", { step: String(step.id) });
13425
+ contextManager.addMessage({
13426
+ role: "user",
13427
+ content: `<system-summary>${nextMsg}</system-summary>`
13428
+ });
13263
13429
  }
13264
13430
  }
13265
13431
  }
13266
- var STUCK_RECOVERY_COOLDOWN = 5;
13432
+ var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3;
13267
13433
  var init_module = __esm(() => {
13268
13434
  init_i18n();
13269
13435
  init_tracker();
13270
13436
  init_verifier();
13271
13437
  init_stuck_detector();
13272
13438
  init_auditor();
13439
+ init_plan_persister();
13273
13440
  });
13274
13441
 
13275
13442
  // src/modules/security/session-encryption.ts
13276
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, existsSync as existsSync26, readdirSync as readdirSync6, unlinkSync as unlinkSync3 } from "fs";
13277
- import { join as join18 } from "path";
13443
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, existsSync as existsSync27, readdirSync as readdirSync6, unlinkSync as unlinkSync3 } from "fs";
13444
+ import { join as join19 } from "path";
13278
13445
  import { homedir as homedir8 } from "os";
13279
13446
 
13280
13447
  class SessionFileEncryptor {
@@ -13283,7 +13450,7 @@ class SessionFileEncryptor {
13283
13450
  constructor(config) {
13284
13451
  this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
13285
13452
  this.encryptor = new ConfigEncryptor({
13286
- keyPath: config?.keyPath || join18(homedir8(), ".mma", ".session-encryption-key")
13453
+ keyPath: config?.keyPath || join19(homedir8(), ".mma", ".session-encryption-key")
13287
13454
  });
13288
13455
  }
13289
13456
  isEnabled() {
@@ -13323,23 +13490,23 @@ class SessionFileEncryptor {
13323
13490
  return lines.map((line) => this.decryptFileContent(line));
13324
13491
  }
13325
13492
  readSessionFile(filePath) {
13326
- const content = readFileSync14(filePath, "utf8");
13493
+ const content = readFileSync16(filePath, "utf8");
13327
13494
  return this.decryptFileContent(content);
13328
13495
  }
13329
13496
  writeSessionFile(filePath, content) {
13330
13497
  const encrypted = this.encryptFileContent(content);
13331
- writeFileSync9(filePath, encrypted, "utf8");
13498
+ writeFileSync10(filePath, encrypted, "utf8");
13332
13499
  }
13333
13500
  readSessionJSON(filePath) {
13334
- const content = readFileSync14(filePath, "utf8");
13501
+ const content = readFileSync16(filePath, "utf8");
13335
13502
  return this.decryptJSON(content);
13336
13503
  }
13337
13504
  writeSessionJSON(filePath, obj) {
13338
13505
  const content = this.encryptJSON(obj);
13339
- writeFileSync9(filePath, content, "utf8");
13506
+ writeFileSync10(filePath, content, "utf8");
13340
13507
  }
13341
13508
  readSessionJSONL(filePath) {
13342
- const content = readFileSync14(filePath, "utf8");
13509
+ const content = readFileSync16(filePath, "utf8");
13343
13510
  const lines = content.split(`
13344
13511
  `).filter((line) => line.trim());
13345
13512
  const decryptedLines = this.decryptJSONL(lines);
@@ -13347,7 +13514,7 @@ class SessionFileEncryptor {
13347
13514
  }
13348
13515
  appendToSessionJSONL(filePath, obj) {
13349
13516
  const encryptedLine = this.encryptFileContent(JSON.stringify(obj));
13350
- writeFileSync9(filePath, encryptedLine + `
13517
+ writeFileSync10(filePath, encryptedLine + `
13351
13518
  `, { flag: "a", encoding: "utf8" });
13352
13519
  }
13353
13520
  encryptSessionDirectory(sessionDir) {
@@ -13355,12 +13522,12 @@ class SessionFileEncryptor {
13355
13522
  return;
13356
13523
  const files = readdirSync6(sessionDir);
13357
13524
  for (const file of files) {
13358
- const filePath = join18(sessionDir, file);
13359
- if (existsSync26(filePath) && !file.endsWith(".enc")) {
13525
+ const filePath = join19(sessionDir, file);
13526
+ if (existsSync27(filePath) && !file.endsWith(".enc")) {
13360
13527
  try {
13361
- const content = readFileSync14(filePath, "utf8");
13528
+ const content = readFileSync16(filePath, "utf8");
13362
13529
  const encrypted = this.encryptFileContent(content);
13363
- writeFileSync9(filePath + ".enc", encrypted, "utf8");
13530
+ writeFileSync10(filePath + ".enc", encrypted, "utf8");
13364
13531
  unlinkSync3(filePath);
13365
13532
  } catch {}
13366
13533
  }
@@ -13372,12 +13539,12 @@ class SessionFileEncryptor {
13372
13539
  const files = readdirSync6(sessionDir);
13373
13540
  for (const file of files) {
13374
13541
  if (file.endsWith(".enc")) {
13375
- const encFilePath = join18(sessionDir, file);
13542
+ const encFilePath = join19(sessionDir, file);
13376
13543
  const decFilePath = encFilePath.slice(0, -4);
13377
13544
  try {
13378
- const content = readFileSync14(encFilePath, "utf8");
13545
+ const content = readFileSync16(encFilePath, "utf8");
13379
13546
  const decrypted = this.decryptFileContent(content);
13380
- writeFileSync9(decFilePath, decrypted, "utf8");
13547
+ writeFileSync10(decFilePath, decrypted, "utf8");
13381
13548
  unlinkSync3(encFilePath);
13382
13549
  } catch {}
13383
13550
  }
@@ -13397,15 +13564,15 @@ var init_session_encryption = __esm(() => {
13397
13564
 
13398
13565
  // src/modules/session/store.ts
13399
13566
  import {
13400
- existsSync as existsSync27,
13401
- mkdirSync as mkdirSync11,
13567
+ existsSync as existsSync28,
13568
+ mkdirSync as mkdirSync12,
13402
13569
  readdirSync as readdirSync7,
13403
- readFileSync as readFileSync15,
13570
+ readFileSync as readFileSync17,
13404
13571
  rmSync,
13405
- writeFileSync as writeFileSync10,
13572
+ writeFileSync as writeFileSync11,
13406
13573
  appendFileSync as appendFileSync5
13407
13574
  } from "fs";
13408
- import { join as join19 } from "path";
13575
+ import { join as join20 } from "path";
13409
13576
  import { gzipSync } from "zlib";
13410
13577
 
13411
13578
  class SessionStore {
@@ -13428,39 +13595,39 @@ class SessionStore {
13428
13595
  return this.encryptor?.isEnabled() ?? false;
13429
13596
  }
13430
13597
  init() {
13431
- mkdirSync11(this.baseDir, { recursive: true });
13598
+ mkdirSync12(this.baseDir, { recursive: true });
13432
13599
  }
13433
13600
  sessionDir(id) {
13434
- return join19(this.baseDir, id);
13601
+ return join20(this.baseDir, id);
13435
13602
  }
13436
13603
  metaPath(id) {
13437
- return join19(this.sessionDir(id), "meta.json");
13604
+ return join20(this.sessionDir(id), "meta.json");
13438
13605
  }
13439
13606
  historyPath(id) {
13440
- return join19(this.sessionDir(id), "history.jsonl");
13607
+ return join20(this.sessionDir(id), "history.jsonl");
13441
13608
  }
13442
13609
  sessionLogPath(id) {
13443
- return join19(this.sessionDir(id), "session.jsonl");
13610
+ return join20(this.sessionDir(id), "session.jsonl");
13444
13611
  }
13445
13612
  sessionExists(id) {
13446
- return existsSync27(this.metaPath(id));
13613
+ return existsSync28(this.metaPath(id));
13447
13614
  }
13448
13615
  saveMeta(id, meta) {
13449
13616
  const dir = this.sessionDir(id);
13450
- mkdirSync11(dir, { recursive: true });
13617
+ mkdirSync12(dir, { recursive: true });
13451
13618
  const content = JSON.stringify(meta, null, 2);
13452
13619
  if (this.encryptor) {
13453
- writeFileSync10(this.metaPath(id), this.encryptor.encryptFileContent(content), "utf-8");
13620
+ writeFileSync11(this.metaPath(id), this.encryptor.encryptFileContent(content), "utf-8");
13454
13621
  } else {
13455
- writeFileSync10(this.metaPath(id), content, "utf-8");
13622
+ writeFileSync11(this.metaPath(id), content, "utf-8");
13456
13623
  }
13457
13624
  }
13458
13625
  loadMeta(id) {
13459
13626
  const path = this.metaPath(id);
13460
- if (!existsSync27(path))
13627
+ if (!existsSync28(path))
13461
13628
  return null;
13462
13629
  try {
13463
- const raw = readFileSync15(path, "utf-8");
13630
+ const raw = readFileSync17(path, "utf-8");
13464
13631
  const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
13465
13632
  return JSON.parse(content);
13466
13633
  } catch {
@@ -13469,7 +13636,7 @@ class SessionStore {
13469
13636
  }
13470
13637
  appendMessage(id, msg) {
13471
13638
  const dir = this.sessionDir(id);
13472
- mkdirSync11(dir, { recursive: true });
13639
+ mkdirSync12(dir, { recursive: true });
13473
13640
  const line = JSON.stringify(msg);
13474
13641
  if (this.encryptor?.isEnabled()) {
13475
13642
  appendFileSync5(this.historyPath(id), this.encryptor.encryptFileContent(line) + `
@@ -13487,10 +13654,10 @@ class SessionStore {
13487
13654
  }
13488
13655
  loadHistory(id) {
13489
13656
  const path = this.historyPath(id);
13490
- if (!existsSync27(path))
13657
+ if (!existsSync28(path))
13491
13658
  return [];
13492
13659
  try {
13493
- const raw = readFileSync15(path, "utf-8");
13660
+ const raw = readFileSync17(path, "utf-8");
13494
13661
  const lines = raw.split(`
13495
13662
  `).filter(Boolean);
13496
13663
  if (this.encryptor?.isEnabled()) {
@@ -13504,7 +13671,7 @@ class SessionStore {
13504
13671
  }
13505
13672
  appendSessionLog(id, entry) {
13506
13673
  const dir = this.sessionDir(id);
13507
- mkdirSync11(dir, { recursive: true });
13674
+ mkdirSync12(dir, { recursive: true });
13508
13675
  const line = JSON.stringify(entry);
13509
13676
  if (this.encryptor?.isEnabled()) {
13510
13677
  appendFileSync5(this.sessionLogPath(id), this.encryptor.encryptFileContent(line) + `
@@ -13516,10 +13683,10 @@ class SessionStore {
13516
13683
  }
13517
13684
  loadSessionLog(id) {
13518
13685
  const path = this.sessionLogPath(id);
13519
- if (!existsSync27(path))
13686
+ if (!existsSync28(path))
13520
13687
  return [];
13521
13688
  try {
13522
- const raw = readFileSync15(path, "utf-8");
13689
+ const raw = readFileSync17(path, "utf-8");
13523
13690
  const lines = raw.split(`
13524
13691
  `).filter(Boolean);
13525
13692
  if (this.encryptor?.isEnabled()) {
@@ -13532,7 +13699,7 @@ class SessionStore {
13532
13699
  }
13533
13700
  }
13534
13701
  listSessions() {
13535
- if (!existsSync27(this.baseDir))
13702
+ if (!existsSync28(this.baseDir))
13536
13703
  return [];
13537
13704
  const entries = readdirSync7(this.baseDir, { withFileTypes: true });
13538
13705
  const sessions = [];
@@ -13548,7 +13715,7 @@ class SessionStore {
13548
13715
  }
13549
13716
  deleteSession(id) {
13550
13717
  const dir = this.sessionDir(id);
13551
- if (existsSync27(dir)) {
13718
+ if (existsSync28(dir)) {
13552
13719
  rmSync(dir, { recursive: true, force: true });
13553
13720
  }
13554
13721
  }
@@ -13560,11 +13727,11 @@ class SessionStore {
13560
13727
  const updatedAt = new Date(session2.updatedAt);
13561
13728
  if (updatedAt < thirtyDaysAgo) {
13562
13729
  const historyPath = this.historyPath(session2.id);
13563
- if (existsSync27(historyPath)) {
13564
- const content = readFileSync15(historyPath, "utf-8");
13730
+ if (existsSync28(historyPath)) {
13731
+ const content = readFileSync17(historyPath, "utf-8");
13565
13732
  const compressed = gzipSync(content);
13566
- const gzPath = join19(this.baseDir, `${session2.id}.jsonl.gz`);
13567
- writeFileSync10(gzPath, compressed);
13733
+ const gzPath = join20(this.baseDir, `${session2.id}.jsonl.gz`);
13734
+ writeFileSync11(gzPath, compressed);
13568
13735
  rmSync(historyPath);
13569
13736
  }
13570
13737
  }
@@ -13770,8 +13937,8 @@ class ProfileCompressor {
13770
13937
  }
13771
13938
 
13772
13939
  // src/modules/user-profile/profile.ts
13773
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync11, existsSync as existsSync28, mkdirSync as mkdirSync12 } from "fs";
13774
- import { join as join20 } from "path";
13940
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync29, mkdirSync as mkdirSync13 } from "fs";
13941
+ import { join as join21 } from "path";
13775
13942
  import { homedir as homedir9, hostname, platform as platform4, type } from "os";
13776
13943
  import { env } from "process";
13777
13944
 
@@ -13795,17 +13962,17 @@ class UserProfile {
13795
13962
  return this.info;
13796
13963
  }
13797
13964
  save() {
13798
- if (!existsSync28(this.profileDir)) {
13799
- mkdirSync12(this.profileDir, { recursive: true });
13965
+ if (!existsSync29(this.profileDir)) {
13966
+ mkdirSync13(this.profileDir, { recursive: true });
13800
13967
  }
13801
- writeFileSync11(join20(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
13968
+ writeFileSync12(join21(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
13802
13969
  }
13803
13970
  load() {
13804
- const path = join20(this.profileDir, "profile.json");
13805
- if (!existsSync28(path))
13971
+ const path = join21(this.profileDir, "profile.json");
13972
+ if (!existsSync29(path))
13806
13973
  return null;
13807
13974
  try {
13808
- const data = JSON.parse(readFileSync16(path, "utf-8"));
13975
+ const data = JSON.parse(readFileSync18(path, "utf-8"));
13809
13976
  this.info = {
13810
13977
  platform: data.platform,
13811
13978
  os: data.os,
@@ -13840,12 +14007,12 @@ class UserProfile {
13840
14007
  var init_profile = () => {};
13841
14008
 
13842
14009
  // src/modules/skills/loader.ts
13843
- import { readdirSync as readdirSync8, readFileSync as readFileSync17, existsSync as existsSync29, statSync as statSync5 } from "fs";
13844
- import { join as join21 } from "path";
14010
+ import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync30, statSync as statSync5 } from "fs";
14011
+ import { join as join22 } from "path";
13845
14012
 
13846
14013
  class SkillsLoader {
13847
14014
  loadFromDir(dirPath) {
13848
- if (!existsSync29(dirPath))
14015
+ if (!existsSync30(dirPath))
13849
14016
  return [];
13850
14017
  const skills = [];
13851
14018
  this.scanDir(dirPath, skills);
@@ -13854,7 +14021,7 @@ class SkillsLoader {
13854
14021
  scanDir(dirPath, skills) {
13855
14022
  const entries = readdirSync8(dirPath);
13856
14023
  for (const entry of entries) {
13857
- const fullPath = join21(dirPath, entry);
14024
+ const fullPath = join22(dirPath, entry);
13858
14025
  const stat = statSync5(fullPath);
13859
14026
  if (stat.isDirectory()) {
13860
14027
  this.scanDir(fullPath, skills);
@@ -13862,7 +14029,7 @@ class SkillsLoader {
13862
14029
  }
13863
14030
  if (!entry.endsWith(".md") && !entry.endsWith(".skill.md"))
13864
14031
  continue;
13865
- const content = readFileSync17(fullPath, "utf-8");
14032
+ const content = readFileSync19(fullPath, "utf-8");
13866
14033
  const parsed = this.parseSkillFile(content, fullPath);
13867
14034
  if (parsed)
13868
14035
  skills.push(parsed);
@@ -14134,8 +14301,8 @@ var init_browser2 = __esm(() => {
14134
14301
  });
14135
14302
 
14136
14303
  // src/modules/indexer/walker.ts
14137
- import { readdirSync as readdirSync9, readFileSync as readFileSync18, statSync as statSync6, existsSync as existsSync30, watch } from "fs";
14138
- import { join as join22, relative, extname as extname5 } from "path";
14304
+ import { readdirSync as readdirSync9, readFileSync as readFileSync20, statSync as statSync6, existsSync as existsSync31, watch } from "fs";
14305
+ import { join as join23, relative, extname as extname5 } from "path";
14139
14306
 
14140
14307
  class Indexer {
14141
14308
  baseDir;
@@ -14162,7 +14329,7 @@ class Indexer {
14162
14329
  let totalSize = 0;
14163
14330
  let count = 0;
14164
14331
  const walkDir = (dir) => {
14165
- if (!existsSync30(dir))
14332
+ if (!existsSync31(dir))
14166
14333
  return;
14167
14334
  let entries;
14168
14335
  try {
@@ -14173,7 +14340,7 @@ class Indexer {
14173
14340
  for (const entry of entries) {
14174
14341
  if (count >= this.MAX_FILES)
14175
14342
  return;
14176
- const fullPath = join22(dir, entry);
14343
+ const fullPath = join23(dir, entry);
14177
14344
  const relPath = relative(this.baseDir, fullPath);
14178
14345
  const stat = statSync6(fullPath);
14179
14346
  if (stat.isDirectory()) {
@@ -14184,7 +14351,7 @@ class Indexer {
14184
14351
  const ext = extname5(entry).toLowerCase();
14185
14352
  const language = LANGUAGES[ext];
14186
14353
  if (language) {
14187
- const content = readFileSync18(fullPath, "utf-8");
14354
+ const content = readFileSync20(fullPath, "utf-8");
14188
14355
  const exports = this.extractExports(content, language);
14189
14356
  files.push({ path: relPath, language, exports, size: stat.size });
14190
14357
  totalSize += stat.size;
@@ -14236,22 +14403,22 @@ var init_walker = __esm(() => {
14236
14403
  });
14237
14404
 
14238
14405
  // src/modules/indexer/cache.ts
14239
- import { readFileSync as readFileSync19, writeFileSync as writeFileSync12, existsSync as existsSync31, mkdirSync as mkdirSync13, rmSync as rmSync2 } from "fs";
14240
- import { join as join23 } from "path";
14406
+ import { readFileSync as readFileSync21, writeFileSync as writeFileSync13, existsSync as existsSync32, mkdirSync as mkdirSync14, rmSync as rmSync2 } from "fs";
14407
+ import { join as join24 } from "path";
14241
14408
 
14242
14409
  class IndexCache {
14243
14410
  cachePath;
14244
14411
  cache = null;
14245
14412
  constructor(cacheDir) {
14246
- this.cachePath = join23(cacheDir, "index-cache.json");
14413
+ this.cachePath = join24(cacheDir, "index-cache.json");
14247
14414
  }
14248
14415
  load() {
14249
14416
  if (this.cache)
14250
14417
  return this.cache;
14251
- if (!existsSync31(this.cachePath))
14418
+ if (!existsSync32(this.cachePath))
14252
14419
  return null;
14253
14420
  try {
14254
- this.cache = JSON.parse(readFileSync19(this.cachePath, "utf-8"));
14421
+ this.cache = JSON.parse(readFileSync21(this.cachePath, "utf-8"));
14255
14422
  return this.cache;
14256
14423
  } catch {
14257
14424
  return null;
@@ -14259,14 +14426,14 @@ class IndexCache {
14259
14426
  }
14260
14427
  save(result) {
14261
14428
  this.cache = result;
14262
- const dir = join23(this.cachePath, "..");
14263
- if (!existsSync31(dir))
14264
- mkdirSync13(dir, { recursive: true });
14265
- writeFileSync12(this.cachePath, JSON.stringify(result), "utf-8");
14429
+ const dir = join24(this.cachePath, "..");
14430
+ if (!existsSync32(dir))
14431
+ mkdirSync14(dir, { recursive: true });
14432
+ writeFileSync13(this.cachePath, JSON.stringify(result), "utf-8");
14266
14433
  }
14267
14434
  invalidate() {
14268
14435
  this.cache = null;
14269
- if (existsSync31(this.cachePath)) {
14436
+ if (existsSync32(this.cachePath)) {
14270
14437
  try {
14271
14438
  rmSync2(this.cachePath);
14272
14439
  } catch {}
@@ -14276,7 +14443,7 @@ class IndexCache {
14276
14443
  var init_cache = () => {};
14277
14444
 
14278
14445
  // src/modules/indexer/module.ts
14279
- import { dirname as dirname7 } from "path";
14446
+ import { dirname as dirname8 } from "path";
14280
14447
 
14281
14448
  class IndexerModule {
14282
14449
  name = "indexer";
@@ -14393,7 +14560,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
14393
14560
  const counts = {};
14394
14561
  for (const f of result.files) {
14395
14562
  const normalized = f.path.replace(/\\/g, "/");
14396
- const dir = dirname7(normalized);
14563
+ const dir = dirname8(normalized);
14397
14564
  const key = dir === "." ? "(root)" : dir;
14398
14565
  counts[key] = (counts[key] || 0) + 1;
14399
14566
  }
@@ -14624,13 +14791,13 @@ var init_mcp = __esm(() => {
14624
14791
 
14625
14792
  // src/modules/memory/module.ts
14626
14793
  import { homedir as homedir10 } from "os";
14627
- import { join as join24 } from "path";
14794
+ import { join as join25 } from "path";
14628
14795
 
14629
14796
  class MemoryModule {
14630
14797
  name = "memory";
14631
14798
  store;
14632
14799
  constructor(memoryDir) {
14633
- const dir = memoryDir || join24(homedir10(), ".mma", "memory");
14800
+ const dir = memoryDir || join25(homedir10(), ".mma", "memory");
14634
14801
  this.store = new MemoryStore(dir);
14635
14802
  }
14636
14803
  getSystemPromptBlock() {
@@ -14677,8 +14844,8 @@ __export(exports_bootstrap, {
14677
14844
  bootstrap: () => bootstrap
14678
14845
  });
14679
14846
  import { homedir as homedir11 } from "os";
14680
- import { join as join25, resolve as resolve15 } from "path";
14681
- import { existsSync as existsSync32, readFileSync as readFileSync20, writeFileSync as writeFileSync13 } from "fs";
14847
+ import { join as join26, resolve as resolve15 } from "path";
14848
+ import { existsSync as existsSync33, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "fs";
14682
14849
  function buildSystemInfo(config, baseDir, profileCompressed) {
14683
14850
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
14684
14851
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -14700,9 +14867,10 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
14700
14867
  if (isWin) {
14701
14868
  lines.push(``, `Windows environment — use Windows-compatible commands:`, `- Use "dir" instead of "ls". Use "dir /b" for bare listing.`, `- Use "type" or "Get-Content" instead of "cat".`, `- Use "cd" instead of "pwd". Use "echo %cd%" to print working directory.`, `- Use "copy" instead of "cp", "move" instead of "mv", "del" instead of "rm".`, `- Do not use "mkdir -p" — Windows mkdir creates intermediate dirs by default. Use the create_dir tool instead.`, `- Use forward slashes (/) or escaped backslashes (\\\\) in file paths.`, `- Your working directory is: ${baseDir}`);
14702
14869
  }
14703
- lines.push(``, `Bash tool rules:`, `- Use the "workdir" parameter to run commands in a specific directory. Do NOT chain "cd dir && cmd" — the security module blocks the "&&" operator.`, `- Run one command per tool call. Split multi-step shell operations into separate bash calls.`);
14870
+ lines.push(``, `Bash tool rules:`, `- Use the "workdir" parameter to run commands in a specific directory. Do NOT chain "cd dir && cmd" — the security module blocks the "&&" operator.`, `- Run one command per tool call. Split multi-step shell operations into separate bash calls.`, `- Background processes (dev servers, watchers, long-running npm install): use the "background: true" parameter or the tool will auto-detect and background them. Check output with process_log.`);
14871
+ lines.push(``, `=== DEVELOPMENT RULES — follow these strictly ===`, ``, `1. DEPENDENCIES FIRST: Before writing any source code, ALWAYS install project dependencies (e.g., "npm install", "pip install -r requirements.txt", "cargo build", "go mod tidy"). Verify the package manager's lock file or dependency directory exists. Never write code that imports/uses packages that aren't installed yet.`, `2. TOOLKIT/FWK FIRST: If the task specifies a framework or UI library, initialize and configure it BEFORE writing application code. Run its project init command first, then add components/modules. Never write your own version of what the framework already provides.`, `3. ONE STEP AT A TIME: Follow the plan sequentially. Complete step N before starting step N+1. When a step is done: verify the deliverables exist and have real content (not empty), then call "plan update step=N status=done". Do not redo completed work.`, `4. VERIFY YOUR WORK: After creating/modifying files, verify they exist on disk. After installing dependencies, verify the package manager completed successfully. After any command, check its output for errors. Don't assume operations succeeded.`, `5. NO PREMATURE WORK: Do not create files for future steps. Do not add imports/references to packages or modules that haven't been installed yet. Do not reference files or components that don't exist yet. Build incrementally — one layer at a time.`, `6. WHEN STUCK: If a command fails 2+ times, STOP and try a different approach. Write files directly instead of using commands. Ask the user for help. Never repeat the same failing command more than twice.`);
14704
14872
  if (config.autoPlan) {
14705
- lines.push(``, `Plan rule: For complex tasks with 3+ steps, you may create a plan using the "plan" tool. For simple questions, just answer directly.`);
14873
+ lines.push(``, `Plan rule (MANDATORY): For ANY task that requires creating files, installing packages, or multiple actions — you MUST create a plan using the "plan" tool BEFORE starting work. Each step must describe a concrete deliverable (specific files to create, packages to install, commands to run). Do not combine unrelated work into one step.`);
14706
14874
  }
14707
14875
  const hasMCP = config.mcpServers && Object.values(config.mcpServers).some((s) => s.enabled !== false);
14708
14876
  if (hasMCP) {
@@ -14712,8 +14880,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
14712
14880
  `);
14713
14881
  }
14714
14882
  async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14715
- const dir = configDir || join25(homedir11(), ".mma");
14716
- const projectConfigPath = projectDir ? join25(projectDir, ".mmrc") : join25(process.cwd(), ".mmrc");
14883
+ const dir = configDir || join26(homedir11(), ".mma");
14884
+ const projectConfigPath = projectDir ? join26(projectDir, ".mmrc") : join26(process.cwd(), ".mmrc");
14717
14885
  const config = loadConfig({ configDir: dir, projectConfigPath });
14718
14886
  setLocale(config.locale);
14719
14887
  try {
@@ -14723,7 +14891,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14723
14891
  }
14724
14892
  } catch {}
14725
14893
  const logger = new Logger(config.logLevel);
14726
- logger.setLogDir(join25(dir, "logs"));
14894
+ logger.setLogDir(join26(dir, "logs"));
14727
14895
  logger.debug("MMA bootstrap", {
14728
14896
  version: config.version,
14729
14897
  model: config.model
@@ -14745,7 +14913,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14745
14913
  logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
14746
14914
  }
14747
14915
  }
14748
- const profile = new UserProfile(join25(dir));
14916
+ const profile = new UserProfile(join26(dir));
14749
14917
  profile.load() || profile.collect();
14750
14918
  profile.save();
14751
14919
  const llmProvider = new OpenAICompatProvider({
@@ -14757,7 +14925,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14757
14925
  rateLimits: config.security?.rateLimits
14758
14926
  });
14759
14927
  const baseDir = projectDir ? resolve15(projectDir) : process.cwd();
14760
- const projectMapCacheDir = join25(baseDir, ".mma");
14928
+ const projectMapCacheDir = join26(baseDir, ".mma");
14761
14929
  const indexerModule = new IndexerModule({
14762
14930
  baseDir,
14763
14931
  cacheDir: projectMapCacheDir
@@ -14768,9 +14936,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14768
14936
  logger.warn(`Project indexing failed: ${err.message}`);
14769
14937
  }
14770
14938
  const skillsLoader = new SkillsLoader;
14771
- const builtinDir = join25(import.meta.dirname, "skills", "builtin");
14772
- const globalDir = join25(homedir11(), ".agents", "skills");
14773
- const projectSkillsDir = join25(baseDir, ".mma", "skills");
14939
+ const builtinDir = join26(import.meta.dirname, "skills", "builtin");
14940
+ const globalDir = join26(homedir11(), ".agents", "skills");
14941
+ const projectSkillsDir = join26(baseDir, ".mma", "skills");
14774
14942
  const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
14775
14943
  const skillsMatcher = new SkillsMatcher;
14776
14944
  const skillsBudget = Math.floor(config.contextWindow * 0.1);
@@ -14784,11 +14952,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14784
14952
  essential: true,
14785
14953
  estimatedTokens: 250
14786
14954
  };
14787
- const agentsMdGlobal = join25(dir, "AGENTS.md");
14788
- if (!existsSync32(agentsMdGlobal)) {
14789
- writeFileSync13(agentsMdGlobal, "", "utf-8");
14955
+ const agentsMdGlobal = join26(dir, "AGENTS.md");
14956
+ if (!existsSync33(agentsMdGlobal)) {
14957
+ writeFileSync14(agentsMdGlobal, "", "utf-8");
14790
14958
  }
14791
- const sessionDir = join25(dir, "sessions");
14959
+ const sessionDir = join26(dir, "sessions");
14792
14960
  const sessionStore = new SessionStore(sessionDir);
14793
14961
  sessionStore.init();
14794
14962
  const sessionManager = new SessionManager(sessionStore, {
@@ -14833,6 +15001,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14833
15001
  const hallucinationDetector = new HallucinationDetector;
14834
15002
  const moduleRegistry = new ModuleRegistry;
14835
15003
  const execModule = new ExecutionModule(baseDir, config.stuckThreshold);
15004
+ execModule.restorePlan();
14836
15005
  moduleRegistry.register(execModule);
14837
15006
  const sessionModule = new SessionModule(sessionManager);
14838
15007
  moduleRegistry.register(sessionModule);
@@ -14841,7 +15010,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14841
15010
  const mcpModule = new MCPModule(config);
14842
15011
  await mcpModule.initialize();
14843
15012
  moduleRegistry.register(mcpModule);
14844
- const memoryModule = new MemoryModule(join25(dir, "memory"));
15013
+ const memoryModule = new MemoryModule(join26(dir, "memory"));
14845
15014
  moduleRegistry.register(memoryModule);
14846
15015
  if (config.browser.enabled) {
14847
15016
  const browserModule = new BrowserModule;
@@ -14884,8 +15053,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14884
15053
  pluginManager.register(plugin);
14885
15054
  pluginManager.register(plugin2);
14886
15055
  const pluginLoader = new PluginLoader;
14887
- const globalPluginsDir = join25(homedir11(), ".mma", "plugins");
14888
- const projectPluginsDir = join25(dir, ".mma", "plugins");
15056
+ const globalPluginsDir = join26(homedir11(), ".mma", "plugins");
15057
+ const projectPluginsDir = join26(dir, ".mma", "plugins");
14889
15058
  pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
14890
15059
  pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
14891
15060
  contextManager.onCompact = (summary) => {
@@ -14903,13 +15072,13 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
14903
15072
  const skipAgentsMd = noAgentsMd === true;
14904
15073
  if (!skipAgentsMd) {
14905
15074
  const agentsMdCandidates = [
14906
- join25(baseDir, "AGENTS.md"),
14907
- join25(baseDir, ".mma", "AGENTS.md"),
14908
- join25(dir, "AGENTS.md")
15075
+ join26(baseDir, "AGENTS.md"),
15076
+ join26(baseDir, ".mma", "AGENTS.md"),
15077
+ join26(dir, "AGENTS.md")
14909
15078
  ];
14910
15079
  for (const p of agentsMdCandidates) {
14911
- if (existsSync32(p)) {
14912
- const content = readFileSync20(p, "utf-8").trim();
15080
+ if (existsSync33(p)) {
15081
+ const content = readFileSync22(p, "utf-8").trim();
14913
15082
  if (content) {
14914
15083
  agentsMdBlocks.push({
14915
15084
  content,
@@ -15742,14 +15911,14 @@ async function runSetup() {
15742
15911
 
15743
15912
  // src/cli/commands.ts
15744
15913
  init_i18n();
15745
- import { join as join27, dirname as dirname8 } from "path";
15914
+ import { join as join28, dirname as dirname9 } from "path";
15746
15915
  import { homedir as homedir13 } from "os";
15747
- import { existsSync as existsSync33, readFileSync as readFileSync21 } from "fs";
15916
+ import { existsSync as existsSync34, readFileSync as readFileSync23 } from "fs";
15748
15917
 
15749
15918
  // src/cli/security-commands.ts
15750
15919
  init_bootstrap();
15751
15920
  init_config();
15752
- import { join as join26 } from "path";
15921
+ import { join as join27 } from "path";
15753
15922
  import { homedir as homedir12 } from "os";
15754
15923
 
15755
15924
  // src/modules/security/security-policies.ts
@@ -16251,7 +16420,7 @@ function createSecurityCommand(program2) {
16251
16420
  }
16252
16421
  });
16253
16422
  securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
16254
- const configPath = join26(homedir12(), ".mma", "config.json");
16423
+ const configPath = join27(homedir12(), ".mma", "config.json");
16255
16424
  const { config: appConfig } = await bootstrap();
16256
16425
  const validPresets = ["strict", "balanced", "permissive"];
16257
16426
  if (!validPresets.includes(preset)) {
@@ -16266,7 +16435,7 @@ function createSecurityCommand(program2) {
16266
16435
  console.log(t("cli.security.policy_description", { description: policy.description }));
16267
16436
  });
16268
16437
  securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
16269
- const configPath = join26(homedir12(), ".mma", "config.json");
16438
+ const configPath = join27(homedir12(), ".mma", "config.json");
16270
16439
  const { config: appConfig } = await bootstrap();
16271
16440
  appConfig.security = appConfig.security || {};
16272
16441
  appConfig.security.sessionEncryption = {
@@ -16278,7 +16447,7 @@ function createSecurityCommand(program2) {
16278
16447
  console.log(t("cli.security.encryption_enabled"));
16279
16448
  });
16280
16449
  securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
16281
- const configPath = join26(homedir12(), ".mma", "config.json");
16450
+ const configPath = join27(homedir12(), ".mma", "config.json");
16282
16451
  const { config: appConfig } = await bootstrap();
16283
16452
  appConfig.security = appConfig.security || {};
16284
16453
  appConfig.security.sessionEncryption = {
@@ -16290,7 +16459,7 @@ function createSecurityCommand(program2) {
16290
16459
  console.log(t("cli.security.encryption_disabled"));
16291
16460
  });
16292
16461
  securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
16293
- const configPath = join26(homedir12(), ".mma", "config.json");
16462
+ const configPath = join27(homedir12(), ".mma", "config.json");
16294
16463
  const { config: appConfig } = await bootstrap();
16295
16464
  appConfig.security = appConfig.security || {};
16296
16465
  appConfig.security.auditNotifier = {
@@ -16304,7 +16473,7 @@ function createSecurityCommand(program2) {
16304
16473
  console.log(t("cli.security.audit_enabled"));
16305
16474
  });
16306
16475
  securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
16307
- const configPath = join26(homedir12(), ".mma", "config.json");
16476
+ const configPath = join27(homedir12(), ".mma", "config.json");
16308
16477
  const { config: appConfig } = await bootstrap();
16309
16478
  appConfig.security = appConfig.security || {};
16310
16479
  appConfig.security.auditNotifier = {
@@ -16338,14 +16507,14 @@ function createSecurityCommand(program2) {
16338
16507
  // src/cli/commands.ts
16339
16508
  import { fileURLToPath } from "url";
16340
16509
  function readVersion() {
16341
- const here = dirname8(fileURLToPath(import.meta.url));
16510
+ const here = dirname9(fileURLToPath(import.meta.url));
16342
16511
  const candidates = [
16343
- join27(here, "..", "..", "package.json"),
16344
- join27(here, "..", "package.json")
16512
+ join28(here, "..", "..", "package.json"),
16513
+ join28(here, "..", "package.json")
16345
16514
  ];
16346
16515
  for (const p of candidates) {
16347
- if (existsSync33(p)) {
16348
- const raw = JSON.parse(readFileSync21(p, "utf8"));
16516
+ if (existsSync34(p)) {
16517
+ const raw = JSON.parse(readFileSync23(p, "utf8"));
16349
16518
  if (raw.version)
16350
16519
  return raw.version;
16351
16520
  }
@@ -16357,7 +16526,7 @@ function createProgram() {
16357
16526
  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"));
16358
16527
  program2.command("init").description(t("cli.init")).action(async () => {
16359
16528
  const answers = await runSetup();
16360
- const configPath = join27(homedir13(), ".mma", "config.json");
16529
+ const configPath = join28(homedir13(), ".mma", "config.json");
16361
16530
  const { config } = await bootstrap();
16362
16531
  config.provider.type = answers.provider;
16363
16532
  config.provider.baseUrl = answers.apiBase;
@@ -16371,7 +16540,7 @@ function createProgram() {
16371
16540
  });
16372
16541
  const configCmd = program2.command("config").description(t("cli.manage_config"));
16373
16542
  configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
16374
- const configPath = join27(homedir13(), ".mma", "config.json");
16543
+ const configPath = join28(homedir13(), ".mma", "config.json");
16375
16544
  const { config } = await bootstrap();
16376
16545
  const keys = key.split(".");
16377
16546
  let obj = config;
@@ -16431,14 +16600,14 @@ function createProgram() {
16431
16600
  console.log(t("cli.model_hint"));
16432
16601
  });
16433
16602
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
16434
- const configPath = join27(homedir13(), ".mma", "config.json");
16603
+ const configPath = join28(homedir13(), ".mma", "config.json");
16435
16604
  const { config } = await bootstrap();
16436
16605
  config.model = name;
16437
16606
  saveConfig(config, configPath);
16438
16607
  console.log(t("cli.model_set", { name }));
16439
16608
  });
16440
16609
  program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
16441
- const configPath = join27(homedir13(), ".mma", "config.json");
16610
+ const configPath = join28(homedir13(), ".mma", "config.json");
16442
16611
  const { config } = await bootstrap();
16443
16612
  const contextWindow = parseInt(size, 10);
16444
16613
  if (isNaN(contextWindow) || contextWindow < 1024) {
@@ -16456,7 +16625,7 @@ function createProgram() {
16456
16625
  console.log(t("cli.base_url"), config.provider.baseUrl);
16457
16626
  });
16458
16627
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
16459
- const configPath = join27(homedir13(), ".mma", "config.json");
16628
+ const configPath = join28(homedir13(), ".mma", "config.json");
16460
16629
  const { config } = await bootstrap();
16461
16630
  config.provider.type = name;
16462
16631
  saveConfig(config, configPath);
@@ -16508,8 +16677,8 @@ init_bootstrap();
16508
16677
  // src/cli/repl.ts
16509
16678
  init_colors();
16510
16679
  import * as readline3 from "readline";
16511
- import { existsSync as existsSync34, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "fs";
16512
- import { join as join28, dirname as dirname9 } from "path";
16680
+ import { existsSync as existsSync35, readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "fs";
16681
+ import { join as join29, dirname as dirname10 } from "path";
16513
16682
  import { homedir as homedir14 } from "os";
16514
16683
  import { fileURLToPath as fileURLToPath2 } from "url";
16515
16684
 
@@ -16957,14 +17126,14 @@ init_table();
16957
17126
  init_i18n();
16958
17127
  init_config();
16959
17128
  function readVersion2() {
16960
- const here = dirname9(fileURLToPath2(import.meta.url));
17129
+ const here = dirname10(fileURLToPath2(import.meta.url));
16961
17130
  const candidates = [
16962
- join28(here, "..", "..", "package.json"),
16963
- join28(here, "..", "package.json")
17131
+ join29(here, "..", "..", "package.json"),
17132
+ join29(here, "..", "package.json")
16964
17133
  ];
16965
17134
  for (const p of candidates) {
16966
- if (existsSync34(p)) {
16967
- const raw = JSON.parse(readFileSync22(p, "utf8"));
17135
+ if (existsSync35(p)) {
17136
+ const raw = JSON.parse(readFileSync24(p, "utf8"));
16968
17137
  if (raw.version)
16969
17138
  return raw.version;
16970
17139
  }
@@ -17028,10 +17197,10 @@ class Repl {
17028
17197
  this.sessionManager = sessionManager;
17029
17198
  this.skillsModule = skillsModule;
17030
17199
  this.pluginManager = pluginManager;
17031
- this.configDir = configDir || join28(homedir14(), ".mma");
17200
+ this.configDir = configDir || join29(homedir14(), ".mma");
17032
17201
  this.baseDir = baseDir || process.cwd();
17033
17202
  this.noAgentsMd = noAgentsMd === true;
17034
- this.historyPath = join28(homedir14(), ".mma", "repl-history");
17203
+ this.historyPath = join29(homedir14(), ".mma", "repl-history");
17035
17204
  this.loadHistory();
17036
17205
  this.registerBuiltinCommands();
17037
17206
  this.registerMmaCommands();
@@ -17055,9 +17224,9 @@ class Repl {
17055
17224
  this.setupListeners();
17056
17225
  }
17057
17226
  loadHistory() {
17058
- if (existsSync34(this.historyPath)) {
17227
+ if (existsSync35(this.historyPath)) {
17059
17228
  try {
17060
- const raw = readFileSync22(this.historyPath, "utf-8");
17229
+ const raw = readFileSync24(this.historyPath, "utf-8");
17061
17230
  this.history = raw.split(`
17062
17231
  `).filter(Boolean).slice(-this.maxHistory);
17063
17232
  } catch {
@@ -17067,7 +17236,7 @@ class Repl {
17067
17236
  }
17068
17237
  saveHistory() {
17069
17238
  const allHistory = this.history.slice(-this.maxHistory);
17070
- writeFileSync14(this.historyPath, allHistory.join(`
17239
+ writeFileSync15(this.historyPath, allHistory.join(`
17071
17240
  `), "utf-8");
17072
17241
  }
17073
17242
  registerBuiltinCommands() {
@@ -17120,7 +17289,7 @@ class Repl {
17120
17289
  }
17121
17290
  try {
17122
17291
  const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
17123
- const { existsSync: existsSync35 } = await import("fs");
17292
+ const { existsSync: existsSync36 } = await import("fs");
17124
17293
  const { resolve: resolve16 } = await import("path");
17125
17294
  let dataUrl;
17126
17295
  let label;
@@ -17140,7 +17309,7 @@ class Repl {
17140
17309
  label = source;
17141
17310
  } else {
17142
17311
  const absPath = resolve16(process.cwd(), source);
17143
- if (!existsSync35(absPath)) {
17312
+ if (!existsSync36(absPath)) {
17144
17313
  console.log(pc.red(t("image.not_found", { path: source })));
17145
17314
  return;
17146
17315
  }
@@ -17217,7 +17386,7 @@ class Repl {
17217
17386
  action: async () => {
17218
17387
  console.log(pc.yellow(t("repl.wizard_running")));
17219
17388
  const answers = await runSetup();
17220
- const configPath = join28(homedir14(), ".mma", "config.json");
17389
+ const configPath = join29(homedir14(), ".mma", "config.json");
17221
17390
  this.config.provider.type = answers.provider;
17222
17391
  this.config.provider.baseUrl = answers.apiBase;
17223
17392
  this.config.provider.apiKey = answers.apiKey;
@@ -17247,7 +17416,7 @@ class Repl {
17247
17416
  return;
17248
17417
  }
17249
17418
  this.config.provider.type = name;
17250
- const configPath = join28(homedir14(), ".mma", "config.json");
17419
+ const configPath = join29(homedir14(), ".mma", "config.json");
17251
17420
  saveConfig(this.config, configPath);
17252
17421
  console.log(pc.green(t("repl.provider_set", { name })));
17253
17422
  return;
@@ -17299,7 +17468,7 @@ class Repl {
17299
17468
  return;
17300
17469
  }
17301
17470
  this.config.model = name;
17302
- const configPath = join28(homedir14(), ".mma", "config.json");
17471
+ const configPath = join29(homedir14(), ".mma", "config.json");
17303
17472
  saveConfig(this.config, configPath);
17304
17473
  console.log(pc.green(t("repl.model_set", { name })));
17305
17474
  return;
@@ -17323,7 +17492,7 @@ class Repl {
17323
17492
  return;
17324
17493
  }
17325
17494
  this.config.contextWindow = size;
17326
- const configPath = join28(homedir14(), ".mma", "config.json");
17495
+ const configPath = join29(homedir14(), ".mma", "config.json");
17327
17496
  saveConfig(this.config, configPath);
17328
17497
  console.log(pc.green(t("cli.context_set", { size })));
17329
17498
  }
@@ -17341,9 +17510,9 @@ class Repl {
17341
17510
  this.agent.shutdown();
17342
17511
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
17343
17512
  const { homedir: homedir15 } = await import("os");
17344
- const { join: join29 } = await import("path");
17345
- const configDir = join29(homedir15(), ".mma");
17346
- const projectConfigPath = join29(process.cwd(), ".mmrc");
17513
+ const { join: join30 } = await import("path");
17514
+ const configDir = join30(homedir15(), ".mma");
17515
+ const projectConfigPath = join30(process.cwd(), ".mmrc");
17347
17516
  const freshConfig = loadConfig2({ configDir, projectConfigPath });
17348
17517
  Object.assign(this.config, freshConfig);
17349
17518
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
@@ -17877,11 +18046,11 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
17877
18046
  row(t("repl.agents_label"), pc.red(t("repl.disabled")));
17878
18047
  } else {
17879
18048
  const agentsMdCandidates = [
17880
- join28(this.baseDir, "AGENTS.md"),
17881
- join28(this.baseDir, ".mma", "AGENTS.md"),
17882
- join28(this.configDir, "AGENTS.md")
18049
+ join29(this.baseDir, "AGENTS.md"),
18050
+ join29(this.baseDir, ".mma", "AGENTS.md"),
18051
+ join29(this.configDir, "AGENTS.md")
17883
18052
  ];
17884
- const foundAgents = agentsMdCandidates.filter((p) => existsSync34(p));
18053
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync35(p));
17885
18054
  if (foundAgents.length > 0) {
17886
18055
  for (const p of foundAgents) {
17887
18056
  row(t("repl.agents_label"), pc.dim(p));
@@ -17892,7 +18061,7 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
17892
18061
  }
17893
18062
  const meta = this.sessionManager?.getActiveMeta();
17894
18063
  if (meta) {
17895
- const sessionPath = join28(this.configDir, "sessions", meta.id);
18064
+ const sessionPath = join29(this.configDir, "sessions", meta.id);
17896
18065
  row(t("repl.session_label"), `${pc.cyan(meta.name)} ${pc.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc.dim(sessionPath)}`);
17897
18066
  }
17898
18067
  const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
@@ -17917,8 +18086,8 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
17917
18086
  init_config();
17918
18087
  init_i18n();
17919
18088
  init_colors();
17920
- import { existsSync as existsSync35 } from "fs";
17921
- import { join as join29 } from "path";
18089
+ import { existsSync as existsSync36 } from "fs";
18090
+ import { join as join30 } from "path";
17922
18091
  import { homedir as homedir15 } from "os";
17923
18092
  async function main() {
17924
18093
  const program2 = createProgram();
@@ -17982,8 +18151,8 @@ async function main() {
17982
18151
  }
17983
18152
  agent.shutdown();
17984
18153
  } else {
17985
- const configPath = join29(homedir15(), ".mma", "config.json");
17986
- if (!existsSync35(configPath)) {
18154
+ const configPath = join30(homedir15(), ".mma", "config.json");
18155
+ if (!existsSync36(configPath)) {
17987
18156
  console.log(pc.yellow(`
17988
18157
  ` + t("cli.first_run") + `
17989
18158
  `));
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: git-expert
3
+ description: Git branching, merge conflicts, rebasing, workflow strategies
4
+ keywords: [git, branch, merge, rebase, commit, conflict, workflow]
5
+ mma_version: 2
6
+ ---
7
+
8
+ # Git Expert
9
+
10
+ ## Branching Strategies
11
+
12
+ - **Feature branches**: `feature/xxx` from `main`, merge via PR
13
+ - **Hotfix**: `hotfix/xxx` from `main`, merge to both `main` and `develop`
14
+ - **Release**: `release/xxx` from `develop`, merge to `main` + `develop`
15
+
16
+ ## Conflict Resolution
17
+
18
+ 1. `git fetch origin` — get latest
19
+ 2. `git checkout your-branch`
20
+ 3. `git rebase origin/main` — apply your commits on top
21
+ 4. Resolve conflicts file by file
22
+ 5. `git add <files>` then `git rebase --continue`
23
+
24
+ ## Useful Commands
25
+
26
+ - `git log --oneline --graph --all` — visualize history
27
+ - `git diff --stat` — summary of changes
28
+ - `git stash pop` — restore stashed changes
29
+ - `git cherry-pick <commit>` — apply specific commit
30
+
31
+ ## Best Practices
32
+
33
+ - Commit often with clear messages
34
+ - Keep commits atomic (one logical change)
35
+ - Never force push to shared branches
36
+ - Use `git rebase -i` to clean up before PR
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: typescript-expert
3
+ description: TypeScript type system, generics, advanced patterns, compiler API
4
+ keywords: [typescript, types, generics, tsconfig, compiler, interface, type]
5
+ mma_version: 2
6
+ ---
7
+
8
+ # TypeScript Expert
9
+
10
+ ## Key Patterns
11
+
12
+ - Use `readonly` for immutable properties
13
+ - Prefer `interface` over `type` for object shapes
14
+ - Use `as const` for literal types
15
+ - Prefer `unknown` over `any` for type safety
16
+
17
+ ## Common Pitfalls
18
+
19
+ - Avoid `any` — use `unknown` + type guards
20
+ - Don't use `enum` — use `const` objects or union types
21
+ - Avoid `namespace` — use ES modules
22
+
23
+ ## Type Guards
24
+
25
+ ```ts
26
+ function isString(val: unknown): val is string {
27
+ return typeof val === 'string'
28
+ }
29
+ ```
30
+
31
+ ## Generics
32
+
33
+ - Use `extends` for constraints
34
+ - Use `infer` for conditional type extraction
35
+ - Prefer explicit over implicit for complex cases
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.19.2",
3
+ "version": "0.20.1",
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": {