micro-models-agent 0.36.3 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.js +407 -139
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2393,6 +2393,7 @@ var init_en = __esm(() => {
2393
2393
  "tool.friendly.search_history": "Searching history",
2394
2394
  "tool.friendly.pipeline_run": "Running pipeline",
2395
2395
  "tool.friendly.mcp_call": "MCP call",
2396
+ "tool.friendly.lsp_check": "Checking code",
2396
2397
  "tool.truncated": "[Truncated: {tokens} tokens removed]",
2397
2398
  "tool.subagent_queued": "Sub-agent task queued: {task}",
2398
2399
  "tool.subagent_artifact": `Sub-agent completed. Full result saved to artifact: {path}
@@ -2485,6 +2486,9 @@ Command: {command}`,
2485
2486
  "plan.switched": "Switched to plan {id}: {title}",
2486
2487
  "plan.replanned": "Plan re-planned: {kept} completed steps kept, {steps} new steps added",
2487
2488
  "plan.replan_no_steps": "Provide new steps for re-planning",
2489
+ "plan.active_in_progress": 'Cannot create a new plan: active plan {id} already has progress ({done}/{total} done, current: step {current}). Resume it — use "plan show" to view, then continue working. To replace it, call "plan abort" first, then "plan create" again.',
2490
+ "plan.id_ignored": 'note: plan ids are auto-generated; use "plan switch" to activate an existing plan by id.',
2491
+ "plan.existing_fresh": "note: the previous active plan had no progress and was preserved as a draft.",
2488
2492
  "todo.added": "Added {count} todo(s): {items}",
2489
2493
  "todo.marked_done": "Marked {count} item(s) as done",
2490
2494
  "todo.no_active": "No active todos",
@@ -2500,6 +2504,11 @@ Command: {command}`,
2500
2504
  "verify.script_failed": "Script '{script}' failed: {message}",
2501
2505
  "verify.syntax_error": "Syntax error in: {path}",
2502
2506
  "lsp.unavailable": "static checks are unavailable (server not found). Verify via the project's own build/test instead.",
2507
+ "lsp.check_disabled": "LSP checks are disabled in the config.",
2508
+ "lsp.check_no_path": "Provide a path (file or directory) to check.",
2509
+ "lsp.check_notfound": "Path not found: {path}",
2510
+ "lsp.check_unsupported": "No LSP server configured for: {path}",
2511
+ "lsp.check_clean": "No errors or warnings detected ({count} file(s) checked).",
2503
2512
  "cli.description": "Micro Models Agent — AI coding agent for small models",
2504
2513
  "cli.init": "Run interactive setup wizard",
2505
2514
  "cli.config_saved": "Configuration saved to ~/.mma/config.json",
@@ -2992,6 +3001,7 @@ var init_ru = __esm(() => {
2992
3001
  "tool.friendly.search_history": "Поиск в истории",
2993
3002
  "tool.friendly.pipeline_run": "Запуск пайплайна",
2994
3003
  "tool.friendly.mcp_call": "MCP вызов",
3004
+ "tool.friendly.lsp_check": "Проверка кода",
2995
3005
  "tool.truncated": "[Обрезано: удалено {tokens} токенов]",
2996
3006
  "tool.subagent_queued": "Задача подагенту добавлена: {task}",
2997
3007
  "tool.subagent_artifact": `Суб-агент завершён. Полный результат сохранён в артефакт: {path}
@@ -3084,6 +3094,9 @@ var init_ru = __esm(() => {
3084
3094
  "plan.switched": "Переключено на план {id}: {title}",
3085
3095
  "plan.replanned": "План перепланирован: {kept} выполненных шагов сохранено, {steps} новых шагов добавлено",
3086
3096
  "plan.replan_no_steps": "Укажите новые шаги для перепланирования",
3097
+ "plan.active_in_progress": 'Нельзя создать новый план: активный план {id} уже имеет прогресс ({done}/{total} выполнено, текущий: шаг {current}). Продолжай его — вызови "plan show", чтобы увидеть, и продолжай работу. Чтобы заменить план, сначала вызови "plan abort", затем "plan create".',
3098
+ "plan.id_ignored": 'примечание: id плана генерируется автоматически; используй "plan switch", чтобы активировать существующий план по id.',
3099
+ "plan.existing_fresh": "примечание: предыдущий активный план не имел прогресса и сохранён как черновик.",
3087
3100
  "todo.added": "Добавлено {count} задач: {items}",
3088
3101
  "todo.marked_done": "Отмечено выполненными: {count}",
3089
3102
  "todo.no_active": "Нет активных задач",
@@ -3099,6 +3112,11 @@ var init_ru = __esm(() => {
3099
3112
  "verify.script_failed": "Скрипт '{script}' не пройден: {message}",
3100
3113
  "verify.syntax_error": "Синтаксическая ошибка в: {path}",
3101
3114
  "lsp.unavailable": "статические проверки недоступны (сервер не найден). Проверяйте через собственный build/test проекта.",
3115
+ "lsp.check_disabled": "LSP-проверки отключены в конфигурации.",
3116
+ "lsp.check_no_path": "Укажите путь (файл или каталог) для проверки.",
3117
+ "lsp.check_notfound": "Путь не найден: {path}",
3118
+ "lsp.check_unsupported": "Для файла не настроен LSP-сервер: {path}",
3119
+ "lsp.check_clean": "Ошибок и предупреждений не обнаружено (проверено файлов: {count}).",
3102
3120
  "cli.description": "Micro Models Agent — ИИ-агент для кодинга на малых моделях",
3103
3121
  "cli.init": "Запустить мастер настройки",
3104
3122
  "cli.config_saved": "Конфигурация сохранена в ~/.mma/config.json",
@@ -11196,6 +11214,7 @@ class FactExtractor {
11196
11214
  deletedFacts = [];
11197
11215
  decisionFacts = [];
11198
11216
  errorFacts = [];
11217
+ readFacts = [];
11199
11218
  static MAX_FACTS = 20;
11200
11219
  get errorCount() {
11201
11220
  return this.errorFacts.length;
@@ -11211,13 +11230,19 @@ class FactExtractor {
11211
11230
  new RegExp(`Deleted ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
11212
11231
  new RegExp(`(?:Удалён|Файл удалён):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi")
11213
11232
  ];
11233
+ const readPatterns = [
11234
+ new RegExp(`── (${DRIVE}[\\w./\\\\-]+\\.[a-z]+) \\(`, "gi")
11235
+ ];
11214
11236
  const newFiles = [];
11215
11237
  const newDeleted = [];
11216
11238
  const newDecisions = [];
11217
11239
  const newErrors = [];
11240
+ const newReads = [];
11218
11241
  const lastEvent = new Map;
11219
11242
  for (const msg of turns) {
11220
11243
  const content = getMessageText(msg.content);
11244
+ if (msg.role === "system")
11245
+ continue;
11221
11246
  if (msg.role === "user" && (content.startsWith("<system-summary>") || content.includes("[Compressed:"))) {
11222
11247
  continue;
11223
11248
  }
@@ -11234,6 +11259,11 @@ class FactExtractor {
11234
11259
  lastEvent.set(match[1], "deleted");
11235
11260
  }
11236
11261
  }
11262
+ for (const pattern of readPatterns) {
11263
+ for (const match of content.matchAll(pattern)) {
11264
+ newReads.push(match[1]);
11265
+ }
11266
+ }
11237
11267
  if (content.includes("Plan:") && content.includes("[")) {
11238
11268
  const planLine = content.split(`
11239
11269
  `).find((line) => line.includes("Plan:"));
@@ -11249,11 +11279,13 @@ class FactExtractor {
11249
11279
  newDecisions.push(line.trim().slice(0, 200));
11250
11280
  }
11251
11281
  }
11252
- if (content.includes("Error:") || content.includes("failed") || content.includes("Ошибка:") || content.includes("не удалось")) {
11253
- const line = content.split(`
11282
+ if (msg.role === "tool" || msg.role === "assistant") {
11283
+ if (content.includes("Error:") || content.includes("failed") || content.includes("Ошибка:") || content.includes("не удалось")) {
11284
+ const line = content.split(`
11254
11285
  `).find((l) => l.includes("Error:") || l.includes("failed") || l.includes("Ошибка:") || l.includes("не удалось"));
11255
- if (line)
11256
- newErrors.push(line.trim().slice(0, 250));
11286
+ if (line)
11287
+ newErrors.push(line.trim().slice(0, 250));
11288
+ }
11257
11289
  }
11258
11290
  }
11259
11291
  const dedup = (arr) => [...new Set(arr)];
@@ -11263,6 +11295,7 @@ class FactExtractor {
11263
11295
  this.deletedFacts = dedup([...this.deletedFacts, ...finalDeleted].filter((p) => !finalFiles.includes(p))).slice(-FactExtractor.MAX_FACTS);
11264
11296
  this.decisionFacts = dedup([...this.decisionFacts, ...newDecisions]).slice(-FactExtractor.MAX_FACTS);
11265
11297
  this.errorFacts = dedup([...this.errorFacts, ...newErrors]).slice(-FactExtractor.MAX_FACTS);
11298
+ this.readFacts = dedup([...this.readFacts, ...newReads]).slice(-FactExtractor.MAX_FACTS);
11266
11299
  }
11267
11300
  filesLine() {
11268
11301
  const deletedSet = new Set(this.deletedFacts);
@@ -11286,6 +11319,11 @@ class FactExtractor {
11286
11319
  return null;
11287
11320
  return `[Errors: ${this.errorFacts.slice(-3).join("; ")}]`;
11288
11321
  }
11322
+ readLine() {
11323
+ if (this.readFacts.length === 0)
11324
+ return null;
11325
+ return `[Read: ${this.readFacts.slice(-12).join("; ")}]`;
11326
+ }
11289
11327
  }
11290
11328
  var init_fact_extractor = () => {};
11291
11329
 
@@ -11358,12 +11396,16 @@ class ContextManager {
11358
11396
  pendingImageParts = [];
11359
11397
  toolTokens = 0;
11360
11398
  onCompact = null;
11399
+ planSummaryProvider = null;
11361
11400
  constructor(contextWindow, contextBudget, tokenCounter) {
11362
11401
  this.contextWindow = contextWindow;
11363
11402
  this.compactionThreshold = contextBudget?.compactionThreshold ?? 0.75;
11364
11403
  this.budget = this.calculateBudget(contextWindow, contextBudget);
11365
11404
  this.tokenCounter = tokenCounter ?? null;
11366
11405
  }
11406
+ setPlanSummaryProvider(fn) {
11407
+ this.planSummaryProvider = fn;
11408
+ }
11367
11409
  calculateBudget(window, contextBudget) {
11368
11410
  if (contextBudget) {
11369
11411
  const systemPrompt = Math.floor(window * contextBudget.systemPrompt);
@@ -11516,12 +11558,18 @@ class ContextManager {
11516
11558
  if (this.lastUserFeedback && !task.startsWith(this.lastUserFeedback)) {
11517
11559
  parts.push(`[User feedback: ${this.lastUserFeedback}]`);
11518
11560
  }
11561
+ const planLine = this.planSummaryProvider?.();
11562
+ if (planLine)
11563
+ parts.push(`[Plan: ${planLine}]`);
11519
11564
  const filesLine = this.facts.filesLine();
11520
11565
  if (filesLine)
11521
11566
  parts.push(filesLine);
11522
11567
  const deletedLine = this.facts.deletedLine();
11523
11568
  if (deletedLine)
11524
11569
  parts.push(deletedLine);
11570
+ const readLine = this.facts.readLine();
11571
+ if (readLine)
11572
+ parts.push(readLine);
11525
11573
  const decisionsLine = this.facts.decisionsLine();
11526
11574
  if (decisionsLine)
11527
11575
  parts.push(decisionsLine);
@@ -14372,6 +14420,13 @@ var init_recall = __esm(() => {
14372
14420
  };
14373
14421
  });
14374
14422
 
14423
+ // src/modules/browser/bridge-path.ts
14424
+ import { existsSync as existsSync25 } from "fs";
14425
+ function pickExistingPath(candidates, fallback = candidates[0]) {
14426
+ return candidates.find((p) => existsSync25(p)) ?? fallback;
14427
+ }
14428
+ var init_bridge_path = () => {};
14429
+
14375
14430
  // src/modules/browser/bridge-client.ts
14376
14431
  var exports_bridge_client = {};
14377
14432
  __export(exports_bridge_client, {
@@ -14382,7 +14437,12 @@ import { createInterface } from "readline";
14382
14437
  import { dirname as dirname9, join as join18 } from "path";
14383
14438
  import { fileURLToPath } from "url";
14384
14439
  function bridgeScriptPath() {
14385
- return join18(dirname9(fileURLToPath(import.meta.url)), "bridge-server.mjs");
14440
+ const dir = dirname9(fileURLToPath(import.meta.url));
14441
+ const candidates = [
14442
+ join18(dir, "bridge-server.mjs"),
14443
+ join18(dir, "modules", "browser", "bridge-server.mjs")
14444
+ ];
14445
+ return pickExistingPath(candidates);
14386
14446
  }
14387
14447
 
14388
14448
  class BridgeDriver {
@@ -14560,6 +14620,7 @@ class BridgeDriver {
14560
14620
  var BRIDGE_REQUEST_TIMEOUT_MS = 30000;
14561
14621
  var init_bridge_client = __esm(() => {
14562
14622
  init_session();
14623
+ init_bridge_path();
14563
14624
  });
14564
14625
 
14565
14626
  // src/modules/browser/driver.ts
@@ -15520,7 +15581,7 @@ var init_image_utils = __esm(() => {
15520
15581
  });
15521
15582
 
15522
15583
  // src/tools/attach-image.ts
15523
- import { existsSync as existsSync25 } from "fs";
15584
+ import { existsSync as existsSync26 } from "fs";
15524
15585
  import { resolve as resolve15 } from "path";
15525
15586
  var attachImageTool;
15526
15587
  var init_attach_image = __esm(() => {
@@ -15563,7 +15624,7 @@ var init_attach_image = __esm(() => {
15563
15624
  dataUrl = result.dataUrl;
15564
15625
  } else {
15565
15626
  const absPath = resolve15(ctx.baseDir, source);
15566
- if (!existsSync25(absPath)) {
15627
+ if (!existsSync26(absPath)) {
15567
15628
  return {
15568
15629
  success: false,
15569
15630
  output: t("image.not_found", { path: source })
@@ -15725,40 +15786,59 @@ class ModuleRegistry {
15725
15786
  }
15726
15787
 
15727
15788
  // src/modules/plugins/loader.ts
15728
- import { readdirSync as readdirSync7, existsSync as existsSync26, statSync as statSync5 } from "fs";
15729
- import { join as join21 } from "path";
15789
+ import { readdirSync as readdirSync7, existsSync as existsSync27, statSync as statSync5 } from "fs";
15790
+ import { join as join21, basename as basename2 } from "path";
15730
15791
 
15731
15792
  class PluginLoader {
15732
15793
  loadFromDir(dirPath, pluginManager, logger) {
15733
- if (!existsSync26(dirPath))
15794
+ if (!existsSync27(dirPath))
15734
15795
  return;
15735
- const entries = readdirSync7(dirPath);
15796
+ const entries = readdirSync7(dirPath).sort();
15736
15797
  for (const entry of entries) {
15737
15798
  const fullPath = join21(dirPath, entry);
15738
- if (!statSync5(fullPath).isFile())
15739
- continue;
15740
- if (!entry.endsWith(".ts") && !entry.endsWith(".js"))
15741
- continue;
15742
- try {
15743
- const mod = __require(fullPath);
15744
- const plugin = mod.default || mod.plugin;
15745
- if (plugin && plugin.name) {
15746
- pluginManager.register(plugin);
15747
- logger?.warn(t("plugin.loaded", { name: plugin.name }));
15799
+ const stat = statSync5(fullPath);
15800
+ if (stat.isFile()) {
15801
+ if (!entry.endsWith(".ts") && !entry.endsWith(".js"))
15802
+ continue;
15803
+ this.tryLoad(fullPath, entry, pluginManager, logger);
15804
+ } else if (stat.isDirectory()) {
15805
+ const entryFile = this.findEntryFile(fullPath);
15806
+ if (entryFile) {
15807
+ this.tryLoad(entryFile, `${entry}/${basename2(entryFile)}`, pluginManager, logger);
15748
15808
  }
15749
- } catch (e) {
15750
- logger?.warn(t("plugin.skipped", { entry, message: e.message }));
15751
15809
  }
15752
15810
  }
15753
15811
  }
15812
+ findEntryFile(dir) {
15813
+ for (const name of FOLDER_ENTRY_NAMES) {
15814
+ const candidate = join21(dir, name);
15815
+ if (existsSync27(candidate))
15816
+ return candidate;
15817
+ }
15818
+ return null;
15819
+ }
15820
+ tryLoad(fullPath, label, pluginManager, logger) {
15821
+ try {
15822
+ const mod = __require(fullPath);
15823
+ const plugin = mod.default || mod.plugin;
15824
+ if (plugin && plugin.name) {
15825
+ pluginManager.register(plugin);
15826
+ logger?.warn(t("plugin.loaded", { name: plugin.name }));
15827
+ }
15828
+ } catch (e) {
15829
+ logger?.warn(t("plugin.skipped", { entry: label, message: e.message }));
15830
+ }
15831
+ }
15754
15832
  }
15833
+ var FOLDER_ENTRY_NAMES;
15755
15834
  var init_loader = __esm(() => {
15756
15835
  init_i18n();
15836
+ FOLDER_ENTRY_NAMES = ["plugin.ts", "plugin.js", "index.ts", "index.js"];
15757
15837
  });
15758
15838
 
15759
15839
  // src/modules/plugins/builtin/lint-on-write.ts
15760
15840
  import { spawn as spawn5, execSync } from "child_process";
15761
- import { existsSync as existsSync27, readFileSync as readFileSync15 } from "fs";
15841
+ import { existsSync as existsSync28, readFileSync as readFileSync15 } from "fs";
15762
15842
  import { resolve as resolve16, extname as extname4, join as join22 } from "path";
15763
15843
  import { platform as platform3 } from "os";
15764
15844
  function contentHash(content) {
@@ -15805,7 +15885,7 @@ class LintOnWritePlugin {
15805
15885
  if (!path)
15806
15886
  return;
15807
15887
  const fullPath = resolve16(ctx.baseDir, path);
15808
- if (!existsSync27(fullPath))
15888
+ if (!existsSync28(fullPath))
15809
15889
  return;
15810
15890
  const ext = extname4(fullPath);
15811
15891
  const syntaxError = await this.checkSyntax(fullPath, ext, ctx.baseDir);
@@ -15862,7 +15942,7 @@ class LintOnWritePlugin {
15862
15942
  async runProjectLint(ctx, result) {
15863
15943
  try {
15864
15944
  const packageJsonPath = join22(ctx.baseDir, "package.json");
15865
- if (!existsSync27(packageJsonPath)) {
15945
+ if (!existsSync28(packageJsonPath)) {
15866
15946
  return;
15867
15947
  }
15868
15948
  const packageJson = JSON.parse(readFileSync15(packageJsonPath, "utf-8"));
@@ -15886,7 +15966,7 @@ class LintOnWritePlugin {
15886
15966
  "package.json"
15887
15967
  ]);
15888
15968
  const tsconfigPath = join22(projectRoot, "tsconfig.json");
15889
- if (!existsSync27(tsconfigPath)) {
15969
+ if (!existsSync28(tsconfigPath)) {
15890
15970
  return;
15891
15971
  }
15892
15972
  const now = Date.now();
@@ -16134,7 +16214,7 @@ class PlanTracker {
16134
16214
  var init_tracker = () => {};
16135
16215
 
16136
16216
  // src/modules/execution/audit-runners.ts
16137
- import { existsSync as existsSync28, readdirSync as readdirSync8 } from "fs";
16217
+ import { existsSync as existsSync29, readdirSync as readdirSync8 } from "fs";
16138
16218
  import { dirname as dirname10, join as join23, resolve as resolve17 } from "path";
16139
16219
  function findTestFile(dir, depth = 0) {
16140
16220
  if (depth > 5)
@@ -16221,7 +16301,7 @@ function findTypecheckRoot(baseDir, existingFiles = []) {
16221
16301
  for (const start of candidates) {
16222
16302
  let dir = resolve17(start);
16223
16303
  for (let depth = 0;depth <= 10; depth++) {
16224
- if (existsSync28(join23(dir, "tsconfig.json"))) {
16304
+ if (existsSync29(join23(dir, "tsconfig.json"))) {
16225
16305
  if (!best || depth < best.depth)
16226
16306
  best = { depth, root: dir };
16227
16307
  break;
@@ -16264,13 +16344,13 @@ var init_audit_runners = __esm(() => {
16264
16344
  });
16265
16345
 
16266
16346
  // src/modules/execution/auditor.ts
16267
- import { existsSync as existsSync29, readdirSync as readdirSync9 } from "fs";
16268
- import { resolve as resolve18, join as join24, basename as basename2 } from "path";
16347
+ import { existsSync as existsSync30, readdirSync as readdirSync9 } from "fs";
16348
+ import { resolve as resolve18, join as join24, basename as basename3 } from "path";
16269
16349
  function findExistingFile(baseDir, filePath) {
16270
16350
  const direct = resolve18(baseDir, filePath);
16271
- if (existsSync29(direct))
16351
+ if (existsSync30(direct))
16272
16352
  return direct;
16273
- const name = basename2(filePath).toLowerCase();
16353
+ const name = basename3(filePath).toLowerCase();
16274
16354
  const suffix = filePath.replace(/\\/g, "/").toLowerCase();
16275
16355
  let found = null;
16276
16356
  const walk = (dir, depth) => {
@@ -16423,7 +16503,7 @@ var init_auditor = __esm(() => {
16423
16503
  });
16424
16504
 
16425
16505
  // src/modules/execution/plan-store.ts
16426
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync30, readdirSync as readdirSync10, rmSync } from "fs";
16506
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync31, readdirSync as readdirSync10, rmSync } from "fs";
16427
16507
  import { join as join25 } from "path";
16428
16508
  function readPlanFile(path, fallbackBaseDir) {
16429
16509
  try {
@@ -16449,7 +16529,7 @@ function writePlanFile(path, plan) {
16449
16529
  writeFileSync10(path, JSON.stringify(plan, null, 2), "utf-8");
16450
16530
  }
16451
16531
  function listDir(dir, baseDir) {
16452
- if (!existsSync30(dir))
16532
+ if (!existsSync31(dir))
16453
16533
  return [];
16454
16534
  const files = readdirSync10(dir).filter((f) => f.endsWith(".json"));
16455
16535
  return files.map((f) => readPlanFile(join25(dir, f), baseDir)).filter((p) => p !== null);
@@ -16474,7 +16554,7 @@ class PlanStore {
16474
16554
  legacyPath;
16475
16555
  constructor(baseDir) {
16476
16556
  const mmaDir = join25(baseDir, ".mma");
16477
- if (!existsSync30(mmaDir))
16557
+ if (!existsSync31(mmaDir))
16478
16558
  mkdirSync14(mmaDir, { recursive: true });
16479
16559
  this.baseDir = baseDir;
16480
16560
  this.plansDir = join25(mmaDir, "plans");
@@ -16482,7 +16562,7 @@ class PlanStore {
16482
16562
  this.archiveDir = join25(this.plansDir, "archive");
16483
16563
  this.legacyPath = join25(mmaDir, LEGACY_FILE);
16484
16564
  for (const dir of [this.plansDir, this.draftsDir, this.archiveDir]) {
16485
- if (!existsSync30(dir))
16565
+ if (!existsSync31(dir))
16486
16566
  mkdirSync14(dir, { recursive: true });
16487
16567
  }
16488
16568
  }
@@ -16494,12 +16574,12 @@ class PlanStore {
16494
16574
  }
16495
16575
  loadActive() {
16496
16576
  const activePath = this.activePath();
16497
- if (existsSync30(activePath)) {
16577
+ if (existsSync31(activePath)) {
16498
16578
  const plan = readPlanFile(activePath, this.baseDir);
16499
16579
  if (plan)
16500
16580
  return plan;
16501
16581
  }
16502
- if (existsSync30(this.legacyPath)) {
16582
+ if (existsSync31(this.legacyPath)) {
16503
16583
  const legacy = readPlanFile(this.legacyPath, this.baseDir);
16504
16584
  if (legacy) {
16505
16585
  this.saveActive(legacy);
@@ -16513,7 +16593,7 @@ class PlanStore {
16513
16593
  }
16514
16594
  clearActive() {
16515
16595
  const p = this.activePath();
16516
- if (existsSync30(p))
16596
+ if (existsSync31(p))
16517
16597
  rmSync(p, { force: true });
16518
16598
  }
16519
16599
  saveDraft(plan) {
@@ -16521,11 +16601,11 @@ class PlanStore {
16521
16601
  }
16522
16602
  loadDraft(id) {
16523
16603
  const p = join25(this.draftsDir, `${id}.json`);
16524
- return existsSync30(p) ? readPlanFile(p, this.baseDir) : null;
16604
+ return existsSync31(p) ? readPlanFile(p, this.baseDir) : null;
16525
16605
  }
16526
16606
  removeDraft(id) {
16527
16607
  const p = join25(this.draftsDir, `${id}.json`);
16528
- if (existsSync30(p))
16608
+ if (existsSync31(p))
16529
16609
  rmSync(p, { force: true });
16530
16610
  }
16531
16611
  listDrafts() {
@@ -16544,7 +16624,7 @@ class PlanStore {
16544
16624
  }
16545
16625
  removeArchived(id) {
16546
16626
  const p = join25(this.archiveDir, `${id}.json`);
16547
- if (existsSync30(p))
16627
+ if (existsSync31(p))
16548
16628
  rmSync(p, { force: true });
16549
16629
  }
16550
16630
  listAll() {
@@ -16594,7 +16674,7 @@ function extractFilePaths(text) {
16594
16674
  }
16595
16675
  return result;
16596
16676
  }
16597
- function basename3(p) {
16677
+ function basename4(p) {
16598
16678
  const parts = p.split(/[/\\]/);
16599
16679
  return parts[parts.length - 1] ?? p;
16600
16680
  }
@@ -16606,7 +16686,7 @@ function checkPlanCoverage(taskText, stepDescriptions) {
16606
16686
  `);
16607
16687
  const missing = taskPaths.filter((p) => {
16608
16688
  const lower = p.toLowerCase();
16609
- const base = basename3(lower);
16689
+ const base = basename4(lower);
16610
16690
  return !stepText.includes(lower) && !stepText.includes(base);
16611
16691
  });
16612
16692
  return { missing };
@@ -16771,6 +16851,23 @@ ${lines.join(`
16771
16851
  if (parsed.error) {
16772
16852
  return { success: false, output: parsed.error };
16773
16853
  }
16854
+ const existing = deps.trackerRef.current;
16855
+ if (existing) {
16856
+ const activePlan = existing.getPlan();
16857
+ const progressed = activePlan.steps.some((s) => s.status === "done" || s.status === "failed" || s.status === "skipped");
16858
+ if (progressed) {
16859
+ const done = activePlan.steps.filter((s) => s.status === "done").length;
16860
+ return {
16861
+ success: false,
16862
+ output: t("plan.active_in_progress", {
16863
+ id: activePlan.id,
16864
+ done: String(done),
16865
+ total: String(activePlan.steps.length),
16866
+ current: String(existing.getCurrentStepIndex() + 1)
16867
+ })
16868
+ };
16869
+ }
16870
+ }
16774
16871
  deps.preserveActive();
16775
16872
  const plan = PlanCreator.createPlan(title, steps, deps.baseDir, parsed.kinds ?? []);
16776
16873
  deps.setPlan(plan);
@@ -16779,6 +16876,14 @@ ${lines.join(`
16779
16876
  title,
16780
16877
  steps: String(steps.length)
16781
16878
  });
16879
+ if (args.id) {
16880
+ output += `
16881
+ ${t("plan.id_ignored")}`;
16882
+ }
16883
+ if (existing) {
16884
+ output += `
16885
+ ${t("plan.existing_fresh")}`;
16886
+ }
16782
16887
  let displayOut = display;
16783
16888
  const taskText = deps.getTaskText(_ctx);
16784
16889
  if (taskText) {
@@ -17321,7 +17426,7 @@ var init_execution_plugin = __esm(() => {
17321
17426
  });
17322
17427
 
17323
17428
  // src/modules/execution/module.ts
17324
- import { existsSync as existsSync31, readFileSync as readFileSync17 } from "fs";
17429
+ import { existsSync as existsSync32, readFileSync as readFileSync17 } from "fs";
17325
17430
  import { resolve as resolve19 } from "path";
17326
17431
 
17327
17432
  class ExecutionModule {
@@ -17414,6 +17519,14 @@ class ExecutionModule {
17414
17519
  estimatedTokens: 200
17415
17520
  };
17416
17521
  }
17522
+ getPlanSummary() {
17523
+ if (!this.tracker)
17524
+ return null;
17525
+ const plan = this.tracker.getPlan();
17526
+ const done = plan.steps.filter((s) => s.status === "done").length;
17527
+ const current = this.tracker.getCurrentStepIndex() + 1;
17528
+ return `[${plan.id}] "${plan.title}" ${done}/${plan.steps.length} done, current: step ${current} — continue it (plan show / re-plan), do NOT create a new plan`;
17529
+ }
17417
17530
  getToolDefinitions() {
17418
17531
  return createPlanToolDefinitions({
17419
17532
  store: this.store,
@@ -17516,7 +17629,7 @@ class ExecutionModule {
17516
17629
  "poetry.lock",
17517
17630
  "requirements.txt"
17518
17631
  ];
17519
- const hasLockFile = lockFiles.some((f) => existsSync31(resolve19(this.baseDir, f)));
17632
+ const hasLockFile = lockFiles.some((f) => existsSync32(resolve19(this.baseDir, f)));
17520
17633
  if (!hasLockFile) {
17521
17634
  if (contextManager) {
17522
17635
  const hints = this.state.depsGateHints.get(step.id) || 0;
@@ -17536,8 +17649,8 @@ class ExecutionModule {
17536
17649
  }
17537
17650
  if (stepPaths.length === 0)
17538
17651
  return;
17539
- const allExist = stepPaths.every((p) => existsSync31(resolve19(this.baseDir, p)));
17540
- const allGone = stepPaths.every((p) => !existsSync31(resolve19(this.baseDir, p)));
17652
+ const allExist = stepPaths.every((p) => existsSync32(resolve19(this.baseDir, p)));
17653
+ const allGone = stepPaths.every((p) => !existsSync32(resolve19(this.baseDir, p)));
17541
17654
  const satisfied = step.kind === "delete" ? allGone && !allExist : allExist;
17542
17655
  if (!satisfied)
17543
17656
  return;
@@ -17643,7 +17756,7 @@ var init_module = __esm(() => {
17643
17756
  import {
17644
17757
  readFileSync as readFileSync18,
17645
17758
  writeFileSync as writeFileSync11,
17646
- existsSync as existsSync32,
17759
+ existsSync as existsSync33,
17647
17760
  readdirSync as readdirSync11,
17648
17761
  unlinkSync as unlinkSync4
17649
17762
  } from "fs";
@@ -17743,7 +17856,7 @@ class SessionFileEncryptor {
17743
17856
  const files = readdirSync11(sessionDir);
17744
17857
  for (const file of files) {
17745
17858
  const filePath = join26(sessionDir, file);
17746
- if (existsSync32(filePath) && !file.endsWith(".enc")) {
17859
+ if (existsSync33(filePath) && !file.endsWith(".enc")) {
17747
17860
  try {
17748
17861
  const content = readFileSync18(filePath, "utf8");
17749
17862
  const encrypted = this.encryptFileContent(content);
@@ -17784,7 +17897,7 @@ var init_session_encryption = __esm(() => {
17784
17897
 
17785
17898
  // src/modules/session/store.ts
17786
17899
  import {
17787
- existsSync as existsSync33,
17900
+ existsSync as existsSync34,
17788
17901
  mkdirSync as mkdirSync15,
17789
17902
  readdirSync as readdirSync12,
17790
17903
  readFileSync as readFileSync19,
@@ -17834,7 +17947,7 @@ class SessionStore {
17834
17947
  return join27(this.sessionDir(id), "session.jsonl");
17835
17948
  }
17836
17949
  sessionExists(id) {
17837
- return existsSync33(this.metaPath(id));
17950
+ return existsSync34(this.metaPath(id));
17838
17951
  }
17839
17952
  saveMeta(id, meta) {
17840
17953
  this._metaCache.set(id, meta);
@@ -17852,7 +17965,7 @@ class SessionStore {
17852
17965
  if (cached)
17853
17966
  return cached;
17854
17967
  const path = this.metaPath(id);
17855
- if (!existsSync33(path))
17968
+ if (!existsSync34(path))
17856
17969
  return null;
17857
17970
  try {
17858
17971
  const raw = readFileSync19(path, "utf-8");
@@ -17884,7 +17997,7 @@ class SessionStore {
17884
17997
  }
17885
17998
  loadHistory(id) {
17886
17999
  const path = this.historyPath(id);
17887
- if (!existsSync33(path))
18000
+ if (!existsSync34(path))
17888
18001
  return [];
17889
18002
  try {
17890
18003
  const raw = readFileSync19(path, "utf-8");
@@ -17925,7 +18038,7 @@ class SessionStore {
17925
18038
  }
17926
18039
  loadSessionLog(id) {
17927
18040
  const path = this.sessionLogPath(id);
17928
- if (!existsSync33(path))
18041
+ if (!existsSync34(path))
17929
18042
  return [];
17930
18043
  try {
17931
18044
  const raw = readFileSync19(path, "utf-8");
@@ -17953,7 +18066,7 @@ class SessionStore {
17953
18066
  }
17954
18067
  }
17955
18068
  listSessions() {
17956
- if (!existsSync33(this.baseDir))
18069
+ if (!existsSync34(this.baseDir))
17957
18070
  return [];
17958
18071
  const entries = readdirSync12(this.baseDir, { withFileTypes: true });
17959
18072
  const sessions = [];
@@ -17970,7 +18083,7 @@ class SessionStore {
17970
18083
  deleteSession(id) {
17971
18084
  this._metaCache.delete(id);
17972
18085
  const dir = this.sessionDir(id);
17973
- if (existsSync33(dir)) {
18086
+ if (existsSync34(dir)) {
17974
18087
  rmSync2(dir, { recursive: true, force: true });
17975
18088
  }
17976
18089
  }
@@ -17982,7 +18095,7 @@ class SessionStore {
17982
18095
  const updatedAt = new Date(session2.updatedAt);
17983
18096
  if (updatedAt < thirtyDaysAgo) {
17984
18097
  const historyPath = this.historyPath(session2.id);
17985
- if (existsSync33(historyPath)) {
18098
+ if (existsSync34(historyPath)) {
17986
18099
  const content = readFileSync19(historyPath, "utf-8");
17987
18100
  const compressed = gzipSync(content);
17988
18101
  const gzPath = join27(this.baseDir, `${session2.id}.jsonl.gz`);
@@ -18195,7 +18308,7 @@ class ProfileCompressor {
18195
18308
  }
18196
18309
 
18197
18310
  // src/modules/user-profile/profile.ts
18198
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync34, mkdirSync as mkdirSync16 } from "fs";
18311
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync35, mkdirSync as mkdirSync16 } from "fs";
18199
18312
  import { join as join28 } from "path";
18200
18313
  import { homedir as homedir9, hostname, platform as platform5, type } from "os";
18201
18314
  import { env } from "process";
@@ -18220,14 +18333,14 @@ class UserProfile {
18220
18333
  return this.info;
18221
18334
  }
18222
18335
  save() {
18223
- if (!existsSync34(this.profileDir)) {
18336
+ if (!existsSync35(this.profileDir)) {
18224
18337
  mkdirSync16(this.profileDir, { recursive: true });
18225
18338
  }
18226
18339
  writeFileSync13(join28(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
18227
18340
  }
18228
18341
  load() {
18229
18342
  const path = join28(this.profileDir, "profile.json");
18230
- if (!existsSync34(path))
18343
+ if (!existsSync35(path))
18231
18344
  return null;
18232
18345
  try {
18233
18346
  const data = JSON.parse(readFileSync20(path, "utf-8"));
@@ -18265,12 +18378,12 @@ class UserProfile {
18265
18378
  var init_profile = () => {};
18266
18379
 
18267
18380
  // src/modules/skills/loader.ts
18268
- import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as existsSync35, statSync as statSync6 } from "fs";
18381
+ import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as existsSync36, statSync as statSync6 } from "fs";
18269
18382
  import { join as join29 } from "path";
18270
18383
 
18271
18384
  class SkillsLoader {
18272
18385
  loadFromDir(dirPath) {
18273
- if (!existsSync35(dirPath))
18386
+ if (!existsSync36(dirPath))
18274
18387
  return [];
18275
18388
  const skills = [];
18276
18389
  this.scanDir(dirPath, skills);
@@ -18524,7 +18637,7 @@ var init_browser2 = __esm(() => {
18524
18637
 
18525
18638
  // src/modules/lsp/command.ts
18526
18639
  import { delimiter, join as join30 } from "path";
18527
- import { existsSync as existsSync36 } from "fs";
18640
+ import { existsSync as existsSync37 } from "fs";
18528
18641
  import { platform as platform6 } from "os";
18529
18642
  function resolveSpawnCommand(command, platformName = platform6(), pathEnv = process.env.PATH ?? "") {
18530
18643
  if (platformName !== "win32")
@@ -18536,7 +18649,7 @@ function resolveSpawnCommand(command, platformName = platform6(), pathEnv = proc
18536
18649
  for (const dir of dirs) {
18537
18650
  for (const ext of WIN_EXTS) {
18538
18651
  const candidate = join30(dir, `${command}${ext}`);
18539
- if (existsSync36(candidate))
18652
+ if (existsSync37(candidate))
18540
18653
  return `${command}${ext}`;
18541
18654
  }
18542
18655
  }
@@ -18804,18 +18917,70 @@ var init_client2 = __esm(() => {
18804
18917
  init_command();
18805
18918
  });
18806
18919
 
18920
+ // src/modules/lsp/check-tool.ts
18921
+ import { readdir, stat } from "fs/promises";
18922
+ import { resolve as resolve21, relative as relative2 } from "path";
18923
+ async function collectCheckFiles(resolved, config) {
18924
+ const info = await stat(resolved).catch(() => null);
18925
+ if (!info)
18926
+ return [];
18927
+ if (info.isFile())
18928
+ return [resolved];
18929
+ const out = [];
18930
+ await walkDir(resolved, 0, out, config);
18931
+ return out;
18932
+ }
18933
+ async function walkDir(dir, depth, out, config) {
18934
+ if (depth > MAX_LSP_WALK_DEPTH || out.length >= MAX_LSP_CHECK_FILES)
18935
+ return;
18936
+ const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
18937
+ for (const entry of entries) {
18938
+ if (out.length >= MAX_LSP_CHECK_FILES)
18939
+ break;
18940
+ if (entry.isDirectory()) {
18941
+ if (SKIP_DIRS2.has(entry.name))
18942
+ continue;
18943
+ await walkDir(resolve21(dir, entry.name), depth + 1, out, config);
18944
+ } else if (entry.isFile() && getServerForFile(resolve21(dir, entry.name), config)) {
18945
+ out.push(resolve21(dir, entry.name));
18946
+ }
18947
+ }
18948
+ }
18949
+ function formatCheckDiagnostics(items, baseDir) {
18950
+ return items.slice(0, 40).map(({ file, diag }) => {
18951
+ const rel = relative2(baseDir, file).replace(/\\/g, "/");
18952
+ const line = diag.range.start.line + 1;
18953
+ const col = diag.range.start.character + 1;
18954
+ const sev = severityLabels[diag.severity] ?? "unknown";
18955
+ return ` ${rel}(${line},${col}): ${sev}: ${diag.message}`;
18956
+ }).join(`
18957
+ `);
18958
+ }
18959
+ var MAX_LSP_CHECK_FILES = 15, MAX_LSP_WALK_DEPTH = 4, SKIP_DIRS2, severityLabels;
18960
+ var init_check_tool = __esm(() => {
18961
+ init_config();
18962
+ SKIP_DIRS2 = new Set(["node_modules", ".git", ".mma", "dist"]);
18963
+ severityLabels = {
18964
+ 1: "error",
18965
+ 2: "warning",
18966
+ 3: "info",
18967
+ 4: "hint"
18968
+ };
18969
+ });
18970
+
18807
18971
  // src/modules/lsp/module.ts
18808
- import { existsSync as existsSync37 } from "fs";
18809
- import { resolve as resolve21 } from "path";
18972
+ import { existsSync as existsSync38 } from "fs";
18973
+ import { resolve as resolve22 } from "path";
18810
18974
 
18811
18975
  class LspModule {
18812
18976
  name = "lsp";
18813
18977
  config;
18814
- client = new LspClient;
18978
+ client;
18815
18979
  failuresByServer = new Map;
18816
18980
  disabledServers = new Set;
18817
- constructor(config) {
18981
+ constructor(config, client) {
18818
18982
  this.config = { ...DEFAULT_LSP_CONFIG, ...config };
18983
+ this.client = client ?? new LspClient;
18819
18984
  }
18820
18985
  isLspDisabled() {
18821
18986
  return this.disabledServers.size > 0;
@@ -18841,8 +19006,8 @@ class LspModule {
18841
19006
  const filePath = String(call.arguments.path ?? "");
18842
19007
  if (!filePath)
18843
19008
  return;
18844
- const fullPath = resolve21(_ctx.baseDir, filePath);
18845
- if (!existsSync37(fullPath))
19009
+ const fullPath = resolve22(_ctx.baseDir, filePath);
19010
+ if (!existsSync38(fullPath))
18846
19011
  return;
18847
19012
  const serverConfig = getServerForFile(fullPath, self.config);
18848
19013
  if (!serverConfig)
@@ -18891,6 +19056,110 @@ ${items}`;
18891
19056
  }
18892
19057
  };
18893
19058
  }
19059
+ getToolDefinitions() {
19060
+ const self = this;
19061
+ return [
19062
+ {
19063
+ name: "lsp_check",
19064
+ description: 'Run static checks (LSP diagnostics) on a file or directory. For "check for errors" tasks: pass a file to check it, or a directory to check its source files (capped at 15). Returns [LSP errors] / [LSP warnings] for files with a configured LSP server.',
19065
+ tags: ["code", "check"],
19066
+ boundedOutput: true,
19067
+ timeoutMs: 90000,
19068
+ parameters: {
19069
+ type: "object",
19070
+ properties: {
19071
+ path: {
19072
+ type: "string",
19073
+ description: "File or directory to check"
19074
+ }
19075
+ },
19076
+ required: ["path"]
19077
+ },
19078
+ handler: async (ctx, args) => self.runCheck(ctx, args)
19079
+ }
19080
+ ];
19081
+ }
19082
+ async runCheck(ctx, args) {
19083
+ if (!this.config.enabled) {
19084
+ return { success: false, output: t("lsp.check_disabled") };
19085
+ }
19086
+ const path = String(args.path ?? "");
19087
+ if (!path)
19088
+ return { success: false, output: t("lsp.check_no_path") };
19089
+ const resolved = safeResolvePath(ctx.baseDir, path);
19090
+ const securityPaths = ctx.config?.security?.paths || DEFAULT_SECURITY_CONFIG.paths;
19091
+ const scopeCheck = isPathInScope(ctx.baseDir, resolved, ctx.scope, securityPaths);
19092
+ if (!scopeCheck.allowed) {
19093
+ return {
19094
+ success: false,
19095
+ output: t("file.path_not_allowed", {
19096
+ path: `${path} — ${scopeCheck.reason}`
19097
+ })
19098
+ };
19099
+ }
19100
+ if (!existsSync38(resolved)) {
19101
+ return { success: false, output: t("lsp.check_notfound", { path }) };
19102
+ }
19103
+ const files = await collectCheckFiles(resolved, this.config);
19104
+ const errors = [];
19105
+ const warnings = [];
19106
+ const notes = [];
19107
+ let checked = 0;
19108
+ for (const file of files) {
19109
+ const serverConfig = getServerForFile(file, this.config);
19110
+ if (!serverConfig)
19111
+ continue;
19112
+ const key = this.serverKey(serverConfig);
19113
+ if (this.disabledServers.has(key))
19114
+ continue;
19115
+ const projectRoot = findProjectRoot(file, ctx.baseDir, serverConfig.workspaceMarkers ?? []);
19116
+ try {
19117
+ const diags = await this.client.checkFile(file, ctx.baseDir, serverConfig, projectRoot);
19118
+ this.failuresByServer.set(key, 0);
19119
+ checked++;
19120
+ for (const d of diags) {
19121
+ if (d.severity === 1)
19122
+ errors.push({ file, diag: d });
19123
+ else if (d.severity === 2)
19124
+ warnings.push({ file, diag: d });
19125
+ }
19126
+ } catch (e) {
19127
+ const msg = e instanceof Error ? e.message : String(e);
19128
+ const failures = (this.failuresByServer.get(key) ?? 0) + 1;
19129
+ this.failuresByServer.set(key, failures);
19130
+ try {
19131
+ ctx.logger?.warn(`LSP check failed for ${file}: ${msg}`);
19132
+ } catch {}
19133
+ if (failures >= MAX_CONSECUTIVE_LSP_FAILURES) {
19134
+ this.disabledServers.add(key);
19135
+ notes.push(`[LSP disabled: ${t("lsp.unavailable")}]`);
19136
+ } else {
19137
+ notes.push(`[LSP check failed for ${file}: ${msg}]`);
19138
+ }
19139
+ }
19140
+ }
19141
+ const lines = [];
19142
+ if (errors.length > 0) {
19143
+ lines.push(`[LSP errors] (${errors.length}):`);
19144
+ lines.push(formatCheckDiagnostics(errors, ctx.baseDir));
19145
+ }
19146
+ if (warnings.length > 0) {
19147
+ lines.push(`[LSP warnings] (${warnings.length}):`);
19148
+ lines.push(formatCheckDiagnostics(warnings, ctx.baseDir));
19149
+ }
19150
+ if (checked > 0 && errors.length === 0 && warnings.length === 0) {
19151
+ lines.push(t("lsp.check_clean", { count: String(checked) }));
19152
+ }
19153
+ lines.push(...notes);
19154
+ if (lines.length === 0) {
19155
+ return {
19156
+ success: true,
19157
+ output: t("lsp.check_clean", { count: String(checked) })
19158
+ };
19159
+ }
19160
+ return { success: errors.length === 0, output: lines.join(`
19161
+ `) };
19162
+ }
18894
19163
  }
18895
19164
  function formatDiagnostics(diagnostics, filePath) {
18896
19165
  const filename = filePath.replace(/\\/g, "/").split("/").pop() ?? filePath;
@@ -18902,18 +19171,16 @@ function formatDiagnostics(diagnostics, filePath) {
18902
19171
  }).join(`
18903
19172
  `);
18904
19173
  }
18905
- var severityLabels, MAX_CONSECUTIVE_LSP_FAILURES = 3;
19174
+ var MAX_CONSECUTIVE_LSP_FAILURES = 3;
18906
19175
  var init_module5 = __esm(() => {
18907
19176
  init_client2();
18908
19177
  init_config();
18909
19178
  init_project_root();
19179
+ init_path_validator();
19180
+ init_security();
19181
+ init_path_utils();
18910
19182
  init_i18n();
18911
- severityLabels = {
18912
- 1: "error",
18913
- 2: "warning",
18914
- 3: "info",
18915
- 4: "hint"
18916
- };
19183
+ init_check_tool();
18917
19184
  });
18918
19185
 
18919
19186
  // src/modules/lsp/index.ts
@@ -18924,8 +19191,8 @@ var init_lsp = __esm(() => {
18924
19191
  });
18925
19192
 
18926
19193
  // src/modules/indexer/walker.ts
18927
- import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync38, watch } from "fs";
18928
- import { join as join31, relative as relative2, extname as extname5 } from "path";
19194
+ import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync39, watch } from "fs";
19195
+ import { join as join31, relative as relative3, extname as extname5 } from "path";
18929
19196
 
18930
19197
  class Indexer {
18931
19198
  baseDir;
@@ -18951,8 +19218,8 @@ class Indexer {
18951
19218
  const files = [];
18952
19219
  let totalSize = 0;
18953
19220
  let count = 0;
18954
- const walkDir = (dir) => {
18955
- if (!existsSync38(dir))
19221
+ const walkDir2 = (dir) => {
19222
+ if (!existsSync39(dir))
18956
19223
  return;
18957
19224
  let entries;
18958
19225
  try {
@@ -18964,26 +19231,26 @@ class Indexer {
18964
19231
  if (count >= this.MAX_FILES)
18965
19232
  return;
18966
19233
  const fullPath = join31(dir, entry);
18967
- const relPath = relative2(this.baseDir, fullPath);
18968
- const stat = statSync7(fullPath);
18969
- if (stat.isDirectory()) {
19234
+ const relPath = relative3(this.baseDir, fullPath);
19235
+ const stat2 = statSync7(fullPath);
19236
+ if (stat2.isDirectory()) {
18970
19237
  if (!IGNORE_DIRS.has(entry)) {
18971
- walkDir(fullPath);
19238
+ walkDir2(fullPath);
18972
19239
  }
18973
- } else if (stat.isFile()) {
19240
+ } else if (stat2.isFile()) {
18974
19241
  const ext = extname5(entry).toLowerCase();
18975
19242
  const language = LANGUAGES[ext];
18976
19243
  if (language) {
18977
19244
  const content = readFileSync22(fullPath, "utf-8");
18978
19245
  const exports = this.extractExports(content, language);
18979
- files.push({ path: relPath, language, exports, size: stat.size });
18980
- totalSize += stat.size;
19246
+ files.push({ path: relPath, language, exports, size: stat2.size });
19247
+ totalSize += stat2.size;
18981
19248
  count++;
18982
19249
  }
18983
19250
  }
18984
19251
  }
18985
19252
  };
18986
- walkDir(this.baseDir);
19253
+ walkDir2(this.baseDir);
18987
19254
  return { files, totalSize };
18988
19255
  }
18989
19256
  extractExports(content, language) {
@@ -19026,7 +19293,7 @@ var init_walker = __esm(() => {
19026
19293
  });
19027
19294
 
19028
19295
  // src/modules/indexer/cache.ts
19029
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync39, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
19296
+ import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync40, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
19030
19297
  import { join as join32 } from "path";
19031
19298
 
19032
19299
  class IndexCache {
@@ -19038,7 +19305,7 @@ class IndexCache {
19038
19305
  load() {
19039
19306
  if (this.cache)
19040
19307
  return this.cache;
19041
- if (!existsSync39(this.cachePath))
19308
+ if (!existsSync40(this.cachePath))
19042
19309
  return null;
19043
19310
  try {
19044
19311
  this.cache = JSON.parse(readFileSync23(this.cachePath, "utf-8"));
@@ -19050,13 +19317,13 @@ class IndexCache {
19050
19317
  save(result) {
19051
19318
  this.cache = result;
19052
19319
  const dir = join32(this.cachePath, "..");
19053
- if (!existsSync39(dir))
19320
+ if (!existsSync40(dir))
19054
19321
  mkdirSync17(dir, { recursive: true });
19055
19322
  writeFileSync14(this.cachePath, JSON.stringify(result), "utf-8");
19056
19323
  }
19057
19324
  invalidate() {
19058
19325
  this.cache = null;
19059
- if (existsSync39(this.cachePath)) {
19326
+ if (existsSync40(this.cachePath)) {
19060
19327
  try {
19061
19328
  rmSync3(this.cachePath);
19062
19329
  } catch {}
@@ -19066,11 +19333,11 @@ class IndexCache {
19066
19333
  var init_cache = () => {};
19067
19334
 
19068
19335
  // src/modules/indexer/project-profile.ts
19069
- import { readFileSync as readFileSync24, existsSync as existsSync40 } from "fs";
19336
+ import { readFileSync as readFileSync24, existsSync as existsSync41 } from "fs";
19070
19337
  import { join as join33 } from "path";
19071
19338
  function detectManifest(baseDir) {
19072
19339
  for (const manifest of MANIFEST_ORDER) {
19073
- if (existsSync40(join33(baseDir, manifest)))
19340
+ if (existsSync41(join33(baseDir, manifest)))
19074
19341
  return manifest;
19075
19342
  }
19076
19343
  return null;
@@ -19724,8 +19991,8 @@ __export(exports_bootstrap, {
19724
19991
  bootstrap: () => bootstrap
19725
19992
  });
19726
19993
  import { homedir as homedir11 } from "os";
19727
- import { join as join35, resolve as resolve22 } from "path";
19728
- import { existsSync as existsSync41, readFileSync as readFileSync25, writeFileSync as writeFileSync15 } from "fs";
19994
+ import { join as join35, resolve as resolve23 } from "path";
19995
+ import { existsSync as existsSync42, readFileSync as readFileSync25, writeFileSync as writeFileSync15 } from "fs";
19729
19996
  function buildSystemInfo(config, baseDir, profileCompressed) {
19730
19997
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
19731
19998
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -19738,7 +20005,7 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
19738
20005
  lines.push(`Windows (PowerShell): use list_dir/read_file/delete_file/create_dir tools instead of dir/type/del/mkdir. No PowerShell cmdlets (Get-Content, Select-Object, Write-Output), no head/tail/grep/cat. Use forward slashes in paths. CWD: ${baseDir}`);
19739
20006
  }
19740
20007
  lines.push(`Runtime: Bun is available — run TypeScript directly with "bun <file.ts>" and tests with "bun test" (no tsx/ts-node/npm install needed for that).`);
19741
- lines.push(`Bash: use "workdir" param instead of "cd dir && cmd". One command per call. Long-running processes: pass "background: true" (id immediately), otherwise auto-backgrounded after a few seconds — check with process_log.`, `DEVELOPMENT RULES (strict): 1) install deps BEFORE writing source (npm/pip/cargo, verify lockfile exists; never import uninstalled packages); 2) framework/toolkit init BEFORE app code; 3) follow plan sequentially, after each step verify deliverables exist with real content, then "plan update step=N status=done"; 4) verify work on disk + command output — don't assume success; 5) no premature work (no files/imports for future steps); 6) stuck after 2+ failures: STOP, try a different approach, write files directly, ask the user.`, `PLAN QUALITY: each step = CONCRETE deliverables (exact file paths with extensions, exact packages, exact commands). Vague steps ("Setup the project") forbidden. Cover init → deps → framework → code → verification. 5-8 steps.`);
20008
+ lines.push(`Bash: use "workdir" param instead of "cd dir && cmd". One command per call. Long-running processes: pass "background: true" (id immediately), otherwise auto-backgrounded after a few seconds — check with process_log.`, `DEVELOPMENT RULES (strict): 1) install deps BEFORE writing source (npm/pip/cargo, verify lockfile exists; never import uninstalled packages); 2) framework/toolkit init BEFORE app code; 3) follow plan sequentially, after each step verify deliverables exist with real content, then "plan update step=N status=done"; 4) verify work on disk + command output — don't assume success; 5) no premature work (no files/imports for future steps); 6) stuck after 2+ failures: STOP, try a different approach, write files directly, ask the user.`, `PLAN QUALITY: each step = CONCRETE deliverables (exact file paths with extensions, exact packages, exact commands). Vague steps ("Setup the project") forbidden. Cover init → deps → framework → code → verification. 5-8 steps.`, `For "check/fix errors" tasks, each verification step must name the exact command that proves the errors are gone — "bun run build", "bun test", or the "lsp_check" tool — and the step is done only after that check reports clean.`);
19742
20009
  if (config.autoPlan) {
19743
20010
  lines.push(`Plan rule (MANDATORY): any task creating files, installing packages, or requiring multiple actions MUST create a plan with the "plan" tool BEFORE starting. Each step = a concrete deliverable.`);
19744
20011
  }
@@ -19795,7 +20062,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
19795
20062
  retry: config.retry,
19796
20063
  rateLimits: config.security?.rateLimits
19797
20064
  });
19798
- const baseDir = projectDir ? resolve22(projectDir) : process.cwd();
20065
+ const baseDir = projectDir ? resolve23(projectDir) : process.cwd();
19799
20066
  const projectMapCacheDir = join35(baseDir, ".mma");
19800
20067
  const indexerModule = new IndexerModule({
19801
20068
  baseDir,
@@ -19824,7 +20091,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
19824
20091
  estimatedTokens: Math.ceil(systemInfoContent.length / 4)
19825
20092
  };
19826
20093
  const agentsMdGlobal = join35(dir, "AGENTS.md");
19827
- if (!existsSync41(agentsMdGlobal)) {
20094
+ if (!existsSync42(agentsMdGlobal)) {
19828
20095
  writeFileSync15(agentsMdGlobal, "", "utf-8");
19829
20096
  }
19830
20097
  const sessionDir = join35(dir, "sessions");
@@ -19960,6 +20227,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
19960
20227
  timestamp: new Date().toISOString()
19961
20228
  });
19962
20229
  };
20230
+ contextManager.setPlanSummaryProvider(() => execModule.getPlanSummary());
19963
20231
  const agentsMdBlocks = [];
19964
20232
  const skipAgentsMd = noAgentsMd === true;
19965
20233
  if (!skipAgentsMd) {
@@ -19969,7 +20237,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
19969
20237
  join35(dir, "AGENTS.md")
19970
20238
  ];
19971
20239
  for (const p of agentsMdCandidates) {
19972
- if (existsSync41(p)) {
20240
+ if (existsSync42(p)) {
19973
20241
  const content = readFileSync25(p, "utf-8").trim();
19974
20242
  if (content) {
19975
20243
  agentsMdBlocks.push({
@@ -20602,10 +20870,10 @@ function menuList(items) {
20602
20870
  console.log(l);
20603
20871
  }
20604
20872
  function ask(rl, question, defaultValue) {
20605
- return new Promise((resolve23) => {
20873
+ return new Promise((resolve24) => {
20606
20874
  const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
20607
20875
  rl.question(prompt, (answer) => {
20608
- resolve23(answer.trim() || defaultValue || "");
20876
+ resolve24(answer.trim() || defaultValue || "");
20609
20877
  });
20610
20878
  });
20611
20879
  }
@@ -20824,12 +21092,12 @@ __export(exports_manifest, {
20824
21092
  getCertMark: () => getCertMark,
20825
21093
  MANIFEST_PATH: () => MANIFEST_PATH
20826
21094
  });
20827
- import { existsSync as existsSync42, readFileSync as readFileSync26, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
21095
+ import { existsSync as existsSync43, readFileSync as readFileSync26, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
20828
21096
  import { homedir as homedir13 } from "os";
20829
21097
  import { join as join37 } from "path";
20830
21098
  function readManifest(path = MANIFEST_PATH) {
20831
21099
  try {
20832
- if (existsSync42(path)) {
21100
+ if (existsSync43(path)) {
20833
21101
  const raw = JSON.parse(readFileSync26(path, "utf-8"));
20834
21102
  return { version: 1, certifications: raw.certifications ?? [] };
20835
21103
  }
@@ -27995,7 +28263,7 @@ var init_scenarios = __esm(() => {
27995
28263
  });
27996
28264
 
27997
28265
  // src/modules/certification/loader.ts
27998
- import { existsSync as existsSync43, readdirSync as readdirSync15, readFileSync as readFileSync27 } from "fs";
28266
+ import { existsSync as existsSync44, readdirSync as readdirSync15, readFileSync as readFileSync27 } from "fs";
27999
28267
  import { join as join38 } from "path";
28000
28268
  function validateScenario(s) {
28001
28269
  const errors2 = [];
@@ -28045,7 +28313,7 @@ function loadScenarios(userDir) {
28045
28313
  else
28046
28314
  scenarios.push(s);
28047
28315
  }
28048
- if (userDir && existsSync43(userDir)) {
28316
+ if (userDir && existsSync44(userDir)) {
28049
28317
  for (const file of readdirSync15(userDir)) {
28050
28318
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
28051
28319
  continue;
@@ -28103,7 +28371,7 @@ var init_loader3 = __esm(() => {
28103
28371
  });
28104
28372
 
28105
28373
  // src/modules/certification/fact-checker.ts
28106
- import { existsSync as existsSync44, readFileSync as readFileSync28, statSync as statSync8 } from "fs";
28374
+ import { existsSync as existsSync45, readFileSync as readFileSync28, statSync as statSync8 } from "fs";
28107
28375
  import { join as join39 } from "path";
28108
28376
  function checkSandbox(sandboxDir, checks, exitCode, output) {
28109
28377
  const failures = [];
@@ -28123,7 +28391,7 @@ function runCheck(sandboxDir, check, exitCode, output) {
28123
28391
  case "fileExists":
28124
28392
  return isFile(join39(sandboxDir, check.path));
28125
28393
  case "fileNotExists":
28126
- return !existsSync44(join39(sandboxDir, check.path));
28394
+ return !existsSync45(join39(sandboxDir, check.path));
28127
28395
  case "dirExists":
28128
28396
  return isDir(join39(sandboxDir, check.path));
28129
28397
  case "fileContent": {
@@ -28149,14 +28417,14 @@ function runCheck(sandboxDir, check, exitCode, output) {
28149
28417
  }
28150
28418
  function isFile(p) {
28151
28419
  try {
28152
- return existsSync44(p) && statSync8(p).isFile();
28420
+ return existsSync45(p) && statSync8(p).isFile();
28153
28421
  } catch {
28154
28422
  return false;
28155
28423
  }
28156
28424
  }
28157
28425
  function isDir(p) {
28158
28426
  try {
28159
- return existsSync44(p) && statSync8(p).isDirectory();
28427
+ return existsSync45(p) && statSync8(p).isDirectory();
28160
28428
  } catch {
28161
28429
  return false;
28162
28430
  }
@@ -28187,9 +28455,9 @@ var init_fact_checker = () => {};
28187
28455
 
28188
28456
  // src/modules/certification/runner.ts
28189
28457
  import { spawn as spawn7 } from "child_process";
28190
- import { existsSync as existsSync45, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
28458
+ import { existsSync as existsSync46, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
28191
28459
  import { platform as platform8 } from "os";
28192
- import { join as join40, resolve as resolve23, dirname as dirname13 } from "path";
28460
+ import { join as join40, resolve as resolve24, dirname as dirname13 } from "path";
28193
28461
  async function runScenario(scenario, opts) {
28194
28462
  if (scenario.mode === "skip") {
28195
28463
  return {
@@ -28270,7 +28538,7 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
28270
28538
  mkdirSync19(sandbox, { recursive: true });
28271
28539
  for (const f of scenario.fixtures ?? []) {
28272
28540
  const src = join40(mmaRoot, f.source);
28273
- if (!existsSync45(src)) {
28541
+ if (!existsSync46(src)) {
28274
28542
  throw new Error(`fixture missing: ${f.source}`);
28275
28543
  }
28276
28544
  const dest = join40(sandbox, f.dest);
@@ -28280,17 +28548,17 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
28280
28548
  }
28281
28549
  function resolveMmaEntry(mmaRoot) {
28282
28550
  const dev = join40(mmaRoot, "src", "cli", "main.ts");
28283
- if (existsSync45(dev))
28551
+ if (existsSync46(dev))
28284
28552
  return dev;
28285
28553
  return join40(mmaRoot, "dist", "main.js");
28286
28554
  }
28287
28555
  function findMmaRoot(fromDir) {
28288
28556
  const candidates = [
28289
- resolve23(fromDir, "..", "..", ".."),
28290
- resolve23(fromDir, "..")
28557
+ resolve24(fromDir, "..", "..", ".."),
28558
+ resolve24(fromDir, "..")
28291
28559
  ];
28292
28560
  for (const c of candidates) {
28293
- if (existsSync45(join40(c, "package.json")))
28561
+ if (existsSync46(join40(c, "package.json")))
28294
28562
  return c;
28295
28563
  }
28296
28564
  return process.cwd();
@@ -28360,11 +28628,11 @@ import { rmSync as rmSync5 } from "fs";
28360
28628
  import { homedir as homedir14 } from "os";
28361
28629
  import { join as join41, dirname as dirname14 } from "path";
28362
28630
  import { fileURLToPath as fileURLToPath2 } from "url";
28363
- import { existsSync as existsSync46, readFileSync as readFileSync29 } from "fs";
28631
+ import { existsSync as existsSync47, readFileSync as readFileSync29 } from "fs";
28364
28632
  function readVersion() {
28365
28633
  const candidates = [join41(MMA_ROOT, "package.json")];
28366
28634
  for (const p of candidates) {
28367
- if (existsSync46(p)) {
28635
+ if (existsSync47(p)) {
28368
28636
  try {
28369
28637
  const raw = JSON.parse(readFileSync29(p, "utf-8"));
28370
28638
  if (raw.version)
@@ -28527,7 +28795,7 @@ __export(exports_repl_commands, {
28527
28795
  });
28528
28796
  import { join as join43, dirname as dirname16 } from "path";
28529
28797
  import { homedir as homedir16 } from "os";
28530
- import { existsSync as existsSync48, readFileSync as readFileSync31 } from "fs";
28798
+ import { existsSync as existsSync49, readFileSync as readFileSync31 } from "fs";
28531
28799
  import { fileURLToPath as fileURLToPath4 } from "url";
28532
28800
  function readVersion3() {
28533
28801
  const here = dirname16(fileURLToPath4(import.meta.url));
@@ -28536,7 +28804,7 @@ function readVersion3() {
28536
28804
  join43(here, "..", "package.json")
28537
28805
  ];
28538
28806
  for (const p of candidates) {
28539
- if (existsSync48(p)) {
28807
+ if (existsSync49(p)) {
28540
28808
  try {
28541
28809
  const raw = JSON.parse(readFileSync31(p, "utf8"));
28542
28810
  if (raw.version)
@@ -28602,8 +28870,8 @@ function registerMmaCommands(ctx) {
28602
28870
  }
28603
28871
  try {
28604
28872
  const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
28605
- const { existsSync: existsSync49 } = await import("fs");
28606
- const { resolve: resolve24 } = await import("path");
28873
+ const { existsSync: existsSync50 } = await import("fs");
28874
+ const { resolve: resolve25 } = await import("path");
28607
28875
  let dataUrl;
28608
28876
  let label;
28609
28877
  if (source.toLowerCase() === "clipboard") {
@@ -28621,8 +28889,8 @@ function registerMmaCommands(ctx) {
28621
28889
  dataUrl = result.dataUrl;
28622
28890
  label = source;
28623
28891
  } else {
28624
- const absPath = resolve24(process.cwd(), source);
28625
- if (!existsSync49(absPath)) {
28892
+ const absPath = resolve25(process.cwd(), source);
28893
+ if (!existsSync50(absPath)) {
28626
28894
  console.log(pc2.red(t("image.not_found", { path: source })));
28627
28895
  return;
28628
28896
  }
@@ -29160,7 +29428,7 @@ init_setup();
29160
29428
  init_i18n();
29161
29429
  import { join as join42, dirname as dirname15 } from "path";
29162
29430
  import { homedir as homedir15 } from "os";
29163
- import { existsSync as existsSync47, readFileSync as readFileSync30 } from "fs";
29431
+ import { existsSync as existsSync48, readFileSync as readFileSync30 } from "fs";
29164
29432
 
29165
29433
  // src/cli/security-commands.ts
29166
29434
  init_bootstrap();
@@ -29788,7 +30056,7 @@ function readVersion2() {
29788
30056
  join42(here, "..", "package.json")
29789
30057
  ];
29790
30058
  for (const p of candidates) {
29791
- if (existsSync47(p)) {
30059
+ if (existsSync48(p)) {
29792
30060
  try {
29793
30061
  const raw = JSON.parse(readFileSync30(p, "utf8"));
29794
30062
  if (raw.version)
@@ -30772,7 +31040,7 @@ class LineEditor {
30772
31040
  }
30773
31041
 
30774
31042
  // src/cli/repl.ts
30775
- import { existsSync as existsSync49, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
31043
+ import { existsSync as existsSync50, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
30776
31044
  import { join as join44, dirname as dirname17 } from "path";
30777
31045
  import { homedir as homedir17 } from "os";
30778
31046
  import { fileURLToPath as fileURLToPath5 } from "url";
@@ -31283,7 +31551,7 @@ function readVersion4() {
31283
31551
  join44(here, "..", "package.json")
31284
31552
  ];
31285
31553
  for (const p of candidates) {
31286
- if (existsSync49(p)) {
31554
+ if (existsSync50(p)) {
31287
31555
  try {
31288
31556
  const raw = JSON.parse(readFileSync32(p, "utf8"));
31289
31557
  if (raw.version)
@@ -31377,7 +31645,7 @@ class Repl {
31377
31645
  this.setupListeners();
31378
31646
  }
31379
31647
  loadHistory() {
31380
- if (existsSync49(this.historyPath)) {
31648
+ if (existsSync50(this.historyPath)) {
31381
31649
  try {
31382
31650
  const raw = readFileSync32(this.historyPath, "utf-8");
31383
31651
  this.history = raw.split(`
@@ -31740,7 +32008,7 @@ ${t("image.clipboard_empty")}`));
31740
32008
  join44(this.baseDir, ".mma", "AGENTS.md"),
31741
32009
  join44(this.configDir, "AGENTS.md")
31742
32010
  ];
31743
- const foundAgents = agentsMdCandidates.filter((p) => existsSync49(p));
32011
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync50(p));
31744
32012
  if (foundAgents.length > 0) {
31745
32013
  for (const p of foundAgents) {
31746
32014
  row(t("repl.agents_label"), pc2.dim(p));
@@ -31792,7 +32060,7 @@ init_setup();
31792
32060
  init_config2();
31793
32061
  init_i18n();
31794
32062
  init_colors();
31795
- import { existsSync as existsSync50, readFileSync as readFileSync33 } from "fs";
32063
+ import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
31796
32064
  import { join as join45, dirname as dirname18 } from "path";
31797
32065
  import { homedir as homedir18 } from "os";
31798
32066
  import { fileURLToPath as fileURLToPath6 } from "url";
@@ -31813,8 +32081,8 @@ function semverGt(a, b) {
31813
32081
  }
31814
32082
  var defaultRunner2 = async (command, args, options) => {
31815
32083
  const { execFile } = await import("child_process");
31816
- return new Promise((resolve24) => {
31817
- execFile(command, args, options, (err) => resolve24({ error: err?.message }));
32084
+ return new Promise((resolve25) => {
32085
+ execFile(command, args, options, (err) => resolve25({ error: err?.message }));
31818
32086
  });
31819
32087
  };
31820
32088
 
@@ -31979,7 +32247,7 @@ function readVersion5() {
31979
32247
  join45(here, "..", "package.json")
31980
32248
  ];
31981
32249
  for (const p of candidates) {
31982
- if (existsSync50(p)) {
32250
+ if (existsSync51(p)) {
31983
32251
  try {
31984
32252
  const raw = JSON.parse(readFileSync33(p, "utf8"));
31985
32253
  if (raw.version)
@@ -32065,7 +32333,7 @@ async function main() {
32065
32333
  process.exit(exitCode);
32066
32334
  } else {
32067
32335
  const configPath = join45(homedir18(), ".mma", "config.json");
32068
- if (!existsSync50(configPath)) {
32336
+ if (!existsSync51(configPath)) {
32069
32337
  console.log(pc2.yellow(`
32070
32338
  ` + t("cli.first_run") + `
32071
32339
  `));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.36.3",
3
+ "version": "0.38.0",
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": {