micro-models-agent 0.42.0 → 0.43.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 +349 -128
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2552,6 +2552,15 @@ Command: {command}`,
2552
2552
  "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.',
2553
2553
  "plan.id_ignored": 'note: plan ids are auto-generated; use "plan switch" to activate an existing plan by id.',
2554
2554
  "plan.existing_fresh": "note: the previous active plan had no progress and was preserved as a draft.",
2555
+ "plan.already_active": "Plan {id} is already active — nothing to switch.",
2556
+ "plan.already_archived": "Plan {id} is already archived — nothing to abort.",
2557
+ "plan.aborted_id": "Plan {id} aborted and archived.",
2558
+ "plan.delete_no_id": "Provide a plan id to delete (plan delete id=plan_xxx).",
2559
+ "plan.deleted": "Plan {id} deleted permanently.",
2560
+ "plan.purged": "Deleted {count} plan(s). Plan storage is empty.",
2561
+ "plan.no_deliverables": "note: step {step} names no files — its completion cannot be auto-verified; run an explicit check (e.g. build/tests) before your final answer.",
2562
+ "plan.list_legend": "[*] active · [ ] draft · [-] archived",
2563
+ "exec.plan_nudge": "You made {count} file-changing tool call(s) without a plan. For tasks that create or modify files, or span multiple steps, create a plan first (plan create) with concrete steps (exact filenames, commands, deliverables), then continue.",
2555
2564
  "todo.added": "Added {count} todo(s): {items}",
2556
2565
  "todo.marked_done": "Marked {count} item(s) as done",
2557
2566
  "todo.no_active": "No active todos",
@@ -3195,6 +3204,15 @@ var init_ru = __esm(() => {
3195
3204
  "plan.active_in_progress": 'Нельзя создать новый план: активный план {id} уже имеет прогресс ({done}/{total} выполнено, текущий: шаг {current}). Продолжай его — вызови "plan show", чтобы увидеть, и продолжай работу. Чтобы заменить план, сначала вызови "plan abort", затем "plan create".',
3196
3205
  "plan.id_ignored": 'примечание: id плана генерируется автоматически; используй "plan switch", чтобы активировать существующий план по id.',
3197
3206
  "plan.existing_fresh": "примечание: предыдущий активный план не имел прогресса и сохранён как черновик.",
3207
+ "plan.already_active": "План {id} уже активен — переключаться некуда.",
3208
+ "plan.already_archived": "План {id} уже в архиве — отменять нечего.",
3209
+ "plan.aborted_id": "План {id} отменён и архивирован.",
3210
+ "plan.delete_no_id": "Укажите id плана для удаления (plan delete id=plan_xxx).",
3211
+ "plan.deleted": "План {id} удалён окончательно.",
3212
+ "plan.purged": "Удалено планов: {count}. Хранилище планов пусто.",
3213
+ "plan.no_deliverables": "примечание: шаг {step} не называет файлов — его выполнение нельзя проверить автоматически; перед финальным ответом явно проверь результат (например, запусти сборку/тесты).",
3214
+ "plan.list_legend": "[*] активный · [ ] черновик · [-] архив",
3215
+ "exec.plan_nudge": "Ты сделал(а) {count} вызов(ов), изменяющих файлы, без плана. Для задач, создающих/изменяющих файлы или состоящих из нескольких шагов, сначала создай план (plan create) с конкретными шагами (точные имена файлов, команды, результаты), а потом продолжай.",
3198
3216
  "todo.added": "Добавлено {count} задач: {items}",
3199
3217
  "todo.marked_done": "Отмечено выполненными: {count}",
3200
3218
  "todo.no_active": "Нет активных задач",
@@ -10598,8 +10616,46 @@ var init_js_identifiers = __esm(() => {
10598
10616
  });
10599
10617
 
10600
10618
  // src/modules/execution/audit-runners.ts
10601
- import { existsSync as existsSync20, readdirSync as readdirSync5 } from "fs";
10619
+ import { existsSync as existsSync20, readdirSync as readdirSync5, readFileSync as readFileSync10 } from "fs";
10602
10620
  import { dirname as dirname7, join as join11, resolve as resolve11 } from "path";
10621
+ function resolveTestCommand(dir) {
10622
+ const pkgPath = join11(dir, "package.json");
10623
+ if (existsSync20(pkgPath)) {
10624
+ try {
10625
+ const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
10626
+ const script = pkg?.scripts?.test;
10627
+ if (typeof script === "string" && script.trim())
10628
+ return script.trim();
10629
+ } catch {}
10630
+ }
10631
+ for (const f of [
10632
+ "vitest.config.ts",
10633
+ "vitest.config.js",
10634
+ "vitest.config.mjs",
10635
+ "jest.config.js",
10636
+ "jest.config.ts",
10637
+ "jest.config.mjs",
10638
+ "jest.config.cjs",
10639
+ "bunfig.toml"
10640
+ ]) {
10641
+ if (existsSync20(join11(dir, f))) {
10642
+ if (f.startsWith("vitest"))
10643
+ return "bunx vitest run";
10644
+ if (f.startsWith("jest"))
10645
+ return "npx --no-install jest";
10646
+ if (f === "bunfig.toml")
10647
+ return "bun test";
10648
+ }
10649
+ }
10650
+ if (existsSync20(join11(dir, "pyproject.toml")) || existsSync20(join11(dir, "pytest.ini")) || existsSync20(join11(dir, "conftest.py"))) {
10651
+ return "python -m pytest -q";
10652
+ }
10653
+ if (existsSync20(join11(dir, "go.mod")))
10654
+ return "go test ./...";
10655
+ if (existsSync20(join11(dir, "Cargo.toml")))
10656
+ return "cargo test";
10657
+ return "bun test";
10658
+ }
10603
10659
  function findTestFile(dir, depth = 0) {
10604
10660
  if (depth > 5)
10605
10661
  return null;
@@ -10617,7 +10673,7 @@ function findTestFile(dir, depth = 0) {
10617
10673
  const found = findTestFile(full, depth + 1);
10618
10674
  if (found)
10619
10675
  return found;
10620
- } else if (TEST_EXT_RE.test(e.name)) {
10676
+ } else if (TEST_EXT_RE.test(e.name) || PY_TEST_RE.test(e.name)) {
10621
10677
  return full;
10622
10678
  }
10623
10679
  }
@@ -10638,7 +10694,8 @@ function extractFailingNames(output, limit = 5) {
10638
10694
  return names;
10639
10695
  }
10640
10696
  async function runTests(baseDir) {
10641
- const entry = processRegistry.start("bun test", baseDir);
10697
+ const command = resolveTestCommand(baseDir);
10698
+ const entry = processRegistry.start(command, baseDir);
10642
10699
  const exited = await processRegistry.waitForExit(entry.id, 90000);
10643
10700
  const output = entry.log.join(`
10644
10701
  `);
@@ -10649,8 +10706,8 @@ async function runTests(baseDir) {
10649
10706
  passed: true,
10650
10707
  failed: 0,
10651
10708
  passedCount: 0,
10652
- detail: "test run timed out after 90s — result unknown",
10653
- command: "bun test"
10709
+ detail: `test run timed out after 90s — result unknown`,
10710
+ command
10654
10711
  };
10655
10712
  }
10656
10713
  const run = detectTestResults(output);
@@ -10661,7 +10718,7 @@ async function runTests(baseDir) {
10661
10718
  failed: entry.exitCode === 0 ? 0 : 1,
10662
10719
  passedCount: 0,
10663
10720
  detail: output.slice(0, 200).trim(),
10664
- command: "bun test"
10721
+ command
10665
10722
  };
10666
10723
  }
10667
10724
  const names = extractFailingNames(output);
@@ -10671,7 +10728,7 @@ async function runTests(baseDir) {
10671
10728
  failed: run.failed,
10672
10729
  passedCount: run.passed,
10673
10730
  detail: names.length ? names.join("; ") : run.summary || `${run.failed} failed / ${run.passed} passed`,
10674
- command: "bun test"
10731
+ command
10675
10732
  };
10676
10733
  }
10677
10734
  function parseTypecheckErrors(output) {
@@ -10708,7 +10765,7 @@ async function runTypecheck(baseDir) {
10708
10765
  return null;
10709
10766
  return parseTypecheckErrors(output);
10710
10767
  }
10711
- var SKIP_DIRS, TEST_EXT_RE, TEST_STEP_RE;
10768
+ var SKIP_DIRS, TEST_EXT_RE, PY_TEST_RE, TEST_STEP_RE;
10712
10769
  var init_audit_runners = __esm(() => {
10713
10770
  init_bash();
10714
10771
  init_processes();
@@ -10724,6 +10781,7 @@ var init_audit_runners = __esm(() => {
10724
10781
  "vendor"
10725
10782
  ]);
10726
10783
  TEST_EXT_RE = /\.(test|spec)\.[jt]sx?$/i;
10784
+ PY_TEST_RE = /^test_.*\.py$|^.*_test\.py$/i;
10727
10785
  TEST_STEP_RE = /\b(test(ing|s)?|тест(ы|ирование|ировать)?|провер\w*\s+тест|запустить\s+тест)\b|bun test|npm test|vitest|pytest|go test|jest|mocha/i;
10728
10786
  });
10729
10787
 
@@ -13408,7 +13466,7 @@ ${joined}` }
13408
13466
  var DEFAULT_CHUNK_SYSTEM_PROMPT = 'Answer the query using ONLY the provided text. Be concise. If the text does not contain the answer, say "NO_EVIDENCE".', DEFAULT_SYNTHESIS_SYSTEM_PROMPT = "You are given a query and per-chunk answers over a large text. Produce the final answer to the query, combining evidence from the chunks. If no chunk had evidence, say so.";
13409
13467
 
13410
13468
  // src/tools/chunk-query.ts
13411
- import { readFileSync as readFileSync10 } from "node:fs";
13469
+ import { readFileSync as readFileSync11 } from "node:fs";
13412
13470
  import { resolve as resolve16 } from "node:path";
13413
13471
  var chunkQueryTool;
13414
13472
  var init_chunk_query = __esm(() => {
@@ -13477,7 +13535,7 @@ var init_chunk_query = __esm(() => {
13477
13535
  return { success: false, output: `[SCOPE] ${check.reason || "Path not allowed"}` };
13478
13536
  }
13479
13537
  try {
13480
- content = readFileSync10(resolve16(ctx.baseDir, inputPath), "utf8");
13538
+ content = readFileSync11(resolve16(ctx.baseDir, inputPath), "utf8");
13481
13539
  } catch (e) {
13482
13540
  return { success: false, output: `Cannot read ${inputPath}: ${e.message}` };
13483
13541
  }
@@ -14849,7 +14907,7 @@ var init_search_history = __esm(() => {
14849
14907
  });
14850
14908
 
14851
14909
  // src/modules/memory/search.ts
14852
- import { readFileSync as readFileSync12, existsSync as existsSync26 } from "fs";
14910
+ import { readFileSync as readFileSync13, existsSync as existsSync26 } from "fs";
14853
14911
  import { join as join17 } from "path";
14854
14912
 
14855
14913
  class MemorySearch {
@@ -14864,7 +14922,7 @@ class MemorySearch {
14864
14922
  const path = join17(this.memoryDir, `${name}.md`);
14865
14923
  if (!existsSync26(path))
14866
14924
  continue;
14867
- const content = readFileSync12(path, "utf-8");
14925
+ const content = readFileSync13(path, "utf-8");
14868
14926
  const lines = content.split(`
14869
14927
  `);
14870
14928
  for (const line of lines) {
@@ -14876,7 +14934,7 @@ class MemorySearch {
14876
14934
  const prefsPath = join17(this.memoryDir, "preferences.json");
14877
14935
  if (existsSync26(prefsPath)) {
14878
14936
  try {
14879
- const prefs = JSON.parse(readFileSync12(prefsPath, "utf-8"));
14937
+ const prefs = JSON.parse(readFileSync13(prefsPath, "utf-8"));
14880
14938
  for (const [key, value] of Object.entries(prefs)) {
14881
14939
  const searchStr = `${key}=${value}`;
14882
14940
  if (searchStr.toLowerCase().includes(lowerQuery)) {
@@ -14894,7 +14952,7 @@ var init_search = __esm(() => {
14894
14952
  });
14895
14953
 
14896
14954
  // src/modules/memory/store.ts
14897
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, existsSync as existsSync27, mkdirSync as mkdirSync13 } from "fs";
14955
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, existsSync as existsSync27, mkdirSync as mkdirSync13 } from "fs";
14898
14956
  import { join as join18 } from "path";
14899
14957
 
14900
14958
  class MemoryStore {
@@ -14920,7 +14978,7 @@ class MemoryStore {
14920
14978
  const path = join18(this.memoryDir, `${name}.md`);
14921
14979
  if (!existsSync27(path))
14922
14980
  return "";
14923
- return readFileSync13(path, "utf-8");
14981
+ return readFileSync14(path, "utf-8");
14924
14982
  }
14925
14983
  append(name, entry) {
14926
14984
  const path = join18(this.memoryDir, `${name}.md`);
@@ -14941,7 +14999,7 @@ class MemoryStore {
14941
14999
  if (!existsSync27(path))
14942
15000
  return {};
14943
15001
  try {
14944
- return JSON.parse(readFileSync13(path, "utf-8"));
15002
+ return JSON.parse(readFileSync14(path, "utf-8"));
14945
15003
  } catch {
14946
15004
  return {};
14947
15005
  }
@@ -16230,7 +16288,7 @@ __export(exports_image_utils, {
16230
16288
  detectMime: () => detectMime,
16231
16289
  bufferToDataUrl: () => bufferToDataUrl
16232
16290
  });
16233
- import { readFileSync as readFileSync14 } from "fs";
16291
+ import { readFileSync as readFileSync15 } from "fs";
16234
16292
  import { extname as extname3 } from "path";
16235
16293
  function detectMime(filePath) {
16236
16294
  const ext = extname3(filePath).toLowerCase();
@@ -16251,7 +16309,7 @@ async function readClipboardImage() {
16251
16309
  async function readClipboardFallback() {
16252
16310
  const { platform: platform5 } = await import("os");
16253
16311
  const { execSync } = await import("child_process");
16254
- const { readFileSync: readFileSync15, unlinkSync: unlinkSync4 } = await import("fs");
16312
+ const { readFileSync: readFileSync16, unlinkSync: unlinkSync4 } = await import("fs");
16255
16313
  const { join: join24 } = await import("path");
16256
16314
  const tmpPath = join24(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
16257
16315
  try {
@@ -16262,7 +16320,7 @@ async function readClipboardFallback() {
16262
16320
  } else {
16263
16321
  return null;
16264
16322
  }
16265
- const buf = readFileSync15(tmpPath);
16323
+ const buf = readFileSync16(tmpPath);
16266
16324
  unlinkSync4(tmpPath);
16267
16325
  return buf.length > 0 ? buf : null;
16268
16326
  } catch {
@@ -16273,7 +16331,7 @@ async function readClipboardFallback() {
16273
16331
  }
16274
16332
  }
16275
16333
  async function loadFileAsDataUrl(filePath) {
16276
- const buf = readFileSync14(filePath);
16334
+ const buf = readFileSync15(filePath);
16277
16335
  if (typeof Bun !== "undefined" && typeof Bun.Image !== "undefined") {
16278
16336
  try {
16279
16337
  const img = new Bun.Image(buf);
@@ -16700,7 +16758,7 @@ var init_loader = __esm(() => {
16700
16758
 
16701
16759
  // src/modules/plugins/builtin/lint-on-write.ts
16702
16760
  import { spawn as spawn5, execSync } from "child_process";
16703
- import { existsSync as existsSync31, readFileSync as readFileSync15 } from "fs";
16761
+ import { existsSync as existsSync31, readFileSync as readFileSync16 } from "fs";
16704
16762
  import { resolve as resolve18, extname as extname4, join as join25 } from "path";
16705
16763
  import { platform as platform5 } from "os";
16706
16764
  function contentHash(content) {
@@ -16765,7 +16823,7 @@ class LintOnWritePlugin {
16765
16823
  if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
16766
16824
  let content = "";
16767
16825
  try {
16768
- content = readFileSync15(filePath, "utf-8");
16826
+ content = readFileSync16(filePath, "utf-8");
16769
16827
  } catch {
16770
16828
  return null;
16771
16829
  }
@@ -16808,7 +16866,7 @@ class LintOnWritePlugin {
16808
16866
  if (!existsSync31(packageJsonPath)) {
16809
16867
  return;
16810
16868
  }
16811
- const packageJson = JSON.parse(readFileSync15(packageJsonPath, "utf-8"));
16869
+ const packageJson = JSON.parse(readFileSync16(packageJsonPath, "utf-8"));
16812
16870
  const lintScript = packageJson.scripts?.lint;
16813
16871
  if (!lintScript) {
16814
16872
  return;
@@ -16944,25 +17002,6 @@ function generatePlanId() {
16944
17002
  }
16945
17003
 
16946
17004
  class PlanCreator {
16947
- static isMultiStep(task) {
16948
- const fileCount = (task.match(/\b[\w./-]+\.[a-z]+\b/gi) || []).length;
16949
- if (fileCount > 1)
16950
- return true;
16951
- const actionWords = [
16952
- "implement",
16953
- "create",
16954
- "add",
16955
- "build",
16956
- "setup",
16957
- "configure",
16958
- "write",
16959
- "make",
16960
- "develop"
16961
- ];
16962
- const words = task.split(/\s+/);
16963
- const hasActionWord = actionWords.some((w) => task.toLowerCase().includes(w));
16964
- return hasActionWord && words.length > 8;
16965
- }
16966
17005
  static createPlan(title, stepDescriptions, baseDir, kinds) {
16967
17006
  const stepCount = stepDescriptions.length;
16968
17007
  return {
@@ -16983,16 +17022,17 @@ class PlanCreator {
16983
17022
  const baseTitle = plan.title.replace(/^\[\d+[^]]*\]\s*/, "");
16984
17023
  const newTitle = title || baseTitle;
16985
17024
  const totalSteps = kept.length + newSteps.length;
16986
- const added = newSteps.map((desc, i) => ({
16987
- id: kept.length + i + 1,
17025
+ const added = newSteps.map((desc) => ({
17026
+ id: -1,
16988
17027
  description: desc,
16989
17028
  status: "pending",
16990
17029
  kind: "create"
16991
17030
  }));
17031
+ const steps = [...kept, ...added].map((s, i) => ({ ...s, id: i + 1 }));
16992
17032
  return {
16993
17033
  id: plan.id,
16994
17034
  title: `[${totalSteps}] ${newTitle}`,
16995
- steps: [...kept, ...added],
17035
+ steps,
16996
17036
  createdAt: plan.createdAt,
16997
17037
  baseDir: plan.baseDir,
16998
17038
  name: plan.name
@@ -17000,10 +17040,13 @@ class PlanCreator {
17000
17040
  }
17001
17041
  static toPromptBlock(plan, currentStepIndex) {
17002
17042
  const date = plan.createdAt.slice(0, 10);
17043
+ const doneCount = plan.steps.filter((s) => s.status === "done").length;
17044
+ const terminal = plan.steps.every((s) => s.status === "done" || s.status === "skipped");
17045
+ const progress = terminal ? `${doneCount}/${plan.steps.length} done, complete` : `${doneCount}/${plan.steps.length} done, current: step ${currentStepIndex + 1}`;
17003
17046
  const lines = [
17004
17047
  `[${plan.id}] ${plan.title}`,
17005
17048
  `Dir: ${plan.baseDir}`,
17006
- `Created: ${date} | Progress: ${plan.steps.filter((s) => s.status === "done").length}/${plan.steps.length} done, current: step ${currentStepIndex + 1}`,
17049
+ `Created: ${date} | Progress: ${progress}`,
17007
17050
  ``
17008
17051
  ];
17009
17052
  for (const step of plan.steps) {
@@ -17080,11 +17123,11 @@ class PlanTracker {
17080
17123
  var init_tracker = () => {};
17081
17124
 
17082
17125
  // src/modules/execution/plan-store.ts
17083
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync32, readdirSync as readdirSync10, rmSync } from "fs";
17126
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync32, readdirSync as readdirSync10, rmSync } from "fs";
17084
17127
  import { join as join26 } from "path";
17085
17128
  function readPlanFile(path, fallbackBaseDir) {
17086
17129
  try {
17087
- const raw = readFileSync16(path, "utf-8");
17130
+ const raw = readFileSync17(path, "utf-8");
17088
17131
  if (!raw.trim())
17089
17132
  return null;
17090
17133
  const parsed = JSON.parse(raw);
@@ -17227,6 +17270,41 @@ class PlanStore {
17227
17270
  return { plan: archived, status: "archived" };
17228
17271
  return null;
17229
17272
  }
17273
+ deletePlan(id) {
17274
+ const active = this.loadActive();
17275
+ if (active && active.id === id) {
17276
+ this.clearActive();
17277
+ return "active";
17278
+ }
17279
+ const draftPath = join26(this.draftsDir, `${id}.json`);
17280
+ if (existsSync32(draftPath)) {
17281
+ rmSync(draftPath, { force: true });
17282
+ return "draft";
17283
+ }
17284
+ const archivedPath = join26(this.archiveDir, `${id}.json`);
17285
+ if (existsSync32(archivedPath)) {
17286
+ rmSync(archivedPath, { force: true });
17287
+ return "archived";
17288
+ }
17289
+ return null;
17290
+ }
17291
+ purgeAll() {
17292
+ let n = 0;
17293
+ const active = this.loadActive();
17294
+ if (active) {
17295
+ this.clearActive();
17296
+ n++;
17297
+ }
17298
+ for (const p of this.listDrafts()) {
17299
+ this.removeDraft(p.id);
17300
+ n++;
17301
+ }
17302
+ for (const p of this.listArchived()) {
17303
+ this.removeArchived(p.id);
17304
+ n++;
17305
+ }
17306
+ return n;
17307
+ }
17230
17308
  }
17231
17309
  var LEGACY_FILE = "plan.json";
17232
17310
  var init_plan_store = () => {};
@@ -17300,16 +17378,18 @@ function createPlanToolDefinitions(deps) {
17300
17378
  {
17301
17379
  name: "plan",
17302
17380
  alwaysOn: true,
17303
- description: `Create, update, show, abort, list, switch, or re-plan multi-step plans.
17381
+ description: `Create, update, show, abort, list, switch, delete, purge, or re-plan multi-step plans.
17304
17382
 
17305
17383
  Actions:
17306
17384
  - create: Start a new plan. Previous active plan is auto-preserved: incomplete → draft, complete → archive.
17307
17385
  - update: Mark step status (done/failed/skipped), or rebuild plan with new steps.
17308
17386
  - show: Print current plan checklist.
17309
- - abort: Archive current plan and clear active slot.
17387
+ - abort: Archive the current plan (or the plan given by id) and clear the active slot.
17310
17388
  - list: Show all plans (active, drafts, archived) with progress.
17311
17389
  - switch: Make a different plan active (by plan id).
17312
17390
  - re-plan: Iterative replanning: keep completed steps, replace remaining with new steps.
17391
+ - delete: Permanently delete a plan by id (plan delete id=plan_xxx).
17392
+ - purge: Delete ALL plans (active, drafts, archived).
17313
17393
 
17314
17394
  Write CONCRETE steps with exact file paths and commands:
17315
17395
  - Specify WHICH files to create with exact paths (e.g. "create src/components/Header.tsx with navigation and logo")
@@ -17324,7 +17404,17 @@ Write CONCRETE steps with exact file paths and commands:
17324
17404
  properties: {
17325
17405
  action: {
17326
17406
  type: "string",
17327
- enum: ["create", "update", "show", "abort", "list", "switch", "re-plan"]
17407
+ enum: [
17408
+ "create",
17409
+ "update",
17410
+ "show",
17411
+ "abort",
17412
+ "list",
17413
+ "switch",
17414
+ "re-plan",
17415
+ "delete",
17416
+ "purge"
17417
+ ]
17328
17418
  },
17329
17419
  title: { type: "string" },
17330
17420
  steps: { type: "array", items: { type: "string" } },
@@ -17352,6 +17442,8 @@ Write CONCRETE steps with exact file paths and commands:
17352
17442
  const namePart = m.name ? ` (${m.name})` : "";
17353
17443
  return `${icon} ${m.id}${namePart} — ${m.title} ${m.doneCount}/${m.stepCount}`;
17354
17444
  });
17445
+ lines.push("");
17446
+ lines.push(t("plan.list_legend"));
17355
17447
  return {
17356
17448
  success: true,
17357
17449
  output: `${t("plan.list_header")}
@@ -17371,6 +17463,16 @@ ${lines.join(`
17371
17463
  output: t("plan.not_found", { id: planId })
17372
17464
  };
17373
17465
  }
17466
+ if (found.status === "active") {
17467
+ return {
17468
+ success: true,
17469
+ output: t("plan.already_active", {
17470
+ id: found.plan.id,
17471
+ title: found.plan.title
17472
+ }),
17473
+ display: deps.trackerRef.current?.toPromptBlock()
17474
+ };
17475
+ }
17374
17476
  deps.preserveActive();
17375
17477
  if (found.status === "draft") {
17376
17478
  deps.store.removeDraft(found.plan.id);
@@ -17378,7 +17480,7 @@ ${lines.join(`
17378
17480
  deps.store.removeArchived(found.plan.id);
17379
17481
  }
17380
17482
  deps.setPlan(found.plan);
17381
- const display = PlanCreator.toPromptBlock(found.plan, 0);
17483
+ const display = deps.trackerRef.current?.toPromptBlock();
17382
17484
  return {
17383
17485
  success: true,
17384
17486
  output: t("plan.switched", {
@@ -17401,7 +17503,7 @@ ${lines.join(`
17401
17503
  const replanned = PlanCreator.replan(oldPlan, newSteps, args.title ? String(args.title) : undefined);
17402
17504
  const keptCount = replanned.steps.length - newSteps.length;
17403
17505
  deps.setPlan(replanned);
17404
- const display = PlanCreator.toPromptBlock(replanned, keptCount);
17506
+ const display = deps.trackerRef.current?.toPromptBlock();
17405
17507
  return {
17406
17508
  success: true,
17407
17509
  output: t("plan.replanned", {
@@ -17514,6 +17616,7 @@ ${display}`,
17514
17616
  if (tracker.isComplete()) {
17515
17617
  const plan = tracker.getPlan();
17516
17618
  deps.store.archivePlan(plan);
17619
+ deps.recordCompleted(plan);
17517
17620
  deps.trackerRef.current = null;
17518
17621
  const done = plan.steps.filter((s) => s.status === "done").length;
17519
17622
  return {
@@ -17580,9 +17683,13 @@ ${progress2}`,
17580
17683
  tracker.addNote(Number(args.step), String(args.note));
17581
17684
  tracker.syncCurrentStep();
17582
17685
  deps.store.saveActive(tracker.getPlan());
17686
+ const vacuousGate = status === "done" && !deps.hasStepDeliverables(target);
17687
+ const vacuousNote = vacuousGate ? `
17688
+ ${t("plan.no_deliverables", { step: String(stepId) })}` : "";
17583
17689
  if (tracker.isComplete()) {
17584
17690
  const plan = tracker.getPlan();
17585
17691
  deps.store.archivePlan(plan);
17692
+ deps.recordCompleted(plan);
17586
17693
  deps.trackerRef.current = null;
17587
17694
  const done = plan.steps.filter((s) => s.status === "done").length;
17588
17695
  return {
@@ -17592,7 +17699,7 @@ ${t("plan.completed_archived", {
17592
17699
  id: plan.id,
17593
17700
  done: String(done),
17594
17701
  total: String(plan.steps.length)
17595
- })}`
17702
+ })}${vacuousNote}`
17596
17703
  };
17597
17704
  }
17598
17705
  const progress = tracker.getProgressString();
@@ -17601,7 +17708,7 @@ ${t("plan.completed_archived", {
17601
17708
  return {
17602
17709
  success: true,
17603
17710
  output: `${t("plan.step_status", { step: String(args.step), status: String(args.status || "done") })}
17604
- ${progress}`,
17711
+ ${progress}${vacuousNote}`,
17605
17712
  display
17606
17713
  };
17607
17714
  }
@@ -17615,7 +17722,7 @@ ${progress}`,
17615
17722
  }
17616
17723
  const plan = PlanCreator.createPlan(title, steps, deps.baseDir, parsed.kinds ?? []);
17617
17724
  deps.setPlan(plan);
17618
- const display = PlanCreator.toPromptBlock(plan, 0);
17725
+ const display = deps.trackerRef.current?.toPromptBlock();
17619
17726
  const output = t("plan.updated", {
17620
17727
  title,
17621
17728
  steps: String(steps.length)
@@ -17627,14 +17734,71 @@ ${progress}`,
17627
17734
  };
17628
17735
  }
17629
17736
  if (action === "abort") {
17737
+ const planId = args.id ? String(args.id) : "";
17738
+ if (planId) {
17739
+ const found = deps.store.find(planId);
17740
+ if (!found) {
17741
+ return {
17742
+ success: false,
17743
+ output: t("plan.not_found", { id: planId })
17744
+ };
17745
+ }
17746
+ if (found.status === "archived") {
17747
+ return {
17748
+ success: false,
17749
+ output: t("plan.already_archived", { id: planId })
17750
+ };
17751
+ }
17752
+ deps.store.archivePlan(found.plan);
17753
+ if (found.status === "active") {
17754
+ deps.trackerRef.current = null;
17755
+ deps.clearCompleted();
17756
+ }
17757
+ return {
17758
+ success: true,
17759
+ output: t("plan.aborted_id", { id: found.plan.id })
17760
+ };
17761
+ }
17630
17762
  const tracker = deps.trackerRef.current;
17631
- if (tracker) {
17632
- deps.store.archivePlan(tracker.getPlan());
17763
+ if (!tracker) {
17764
+ return { success: false, output: t("plan.no_active") };
17633
17765
  }
17766
+ deps.store.archivePlan(tracker.getPlan());
17634
17767
  deps.trackerRef.current = null;
17635
17768
  deps.store.clearActive();
17769
+ deps.clearCompleted();
17636
17770
  return { success: true, output: t("plan.aborted") };
17637
17771
  }
17772
+ if (action === "delete") {
17773
+ const planId = String(args.id || "");
17774
+ if (!planId) {
17775
+ return { success: false, output: t("plan.delete_no_id") };
17776
+ }
17777
+ const deleted = deps.store.deletePlan(planId);
17778
+ if (!deleted) {
17779
+ return {
17780
+ success: false,
17781
+ output: t("plan.not_found", { id: planId })
17782
+ };
17783
+ }
17784
+ if (deleted === "active") {
17785
+ deps.trackerRef.current = null;
17786
+ deps.clearCompleted();
17787
+ }
17788
+ return {
17789
+ success: true,
17790
+ output: t("plan.deleted", { id: planId })
17791
+ };
17792
+ }
17793
+ if (action === "purge") {
17794
+ const count = deps.store.purgeAll();
17795
+ deps.trackerRef.current = null;
17796
+ deps.clearCompleted();
17797
+ return {
17798
+ success: true,
17799
+ output: t("plan.purged", { count: String(count) })
17800
+ };
17801
+ }
17638
17802
  if (!deps.trackerRef.current) {
17639
17803
  return { success: false, output: t("plan.no_active") };
17640
17804
  }
@@ -17825,6 +17989,8 @@ function createExecutionPlugin(deps) {
17825
17989
  deps.state.consecutivePlanWarnings = 0;
17826
17990
  deps.state.lastStepId = -1;
17827
17991
  deps.state.stuckNotified = false;
17992
+ deps.state.mutationsWithoutPlan = 0;
17993
+ deps.state.planNudgeSent = false;
17828
17994
  } else {
17829
17995
  const step = deps.trackerRef.current?.getCurrentStep();
17830
17996
  if (deps.trackerRef.current && step) {
@@ -17835,22 +18001,21 @@ function createExecutionPlugin(deps) {
17835
18001
  }
17836
18002
  deps.stuckDetector.setCurrentStep(step.id, step.description);
17837
18003
  deps.stuckDetector.recordIteration(step.id);
18004
+ deps.state.mutationsWithoutPlan = 0;
18005
+ deps.state.planNudgeSent = false;
17838
18006
  } else {
17839
18007
  deps.stuckDetector.reset();
17840
18008
  deps.state.consecutivePlanWarnings = 0;
17841
18009
  deps.state.lastStepId = -1;
17842
18010
  deps.state.stuckNotified = false;
17843
- const iter = typeof ctx.iteration === "number" ? ctx.iteration : 0;
17844
- if (iter === 3 && !deps.trackerRef.current && ctx.contextManager) {
18011
+ const mutations = deps.state.mutationsWithoutPlan;
18012
+ if (mutations >= PLAN_NUDGE_THRESHOLD && !deps.state.planNudgeSent && ctx.contextManager) {
18013
+ deps.state.planNudgeSent = true;
17845
18014
  ctx.contextManager.addMessage({
17846
18015
  role: "user",
17847
- content: `<system-summary>You have made 3 tool calls without creating a plan. For any task that involves creating files, installing packages, or multiple steps — you MUST use plan create BEFORE continuing. Use the plan tool now with concrete steps (exact filenames, commands, deliverables). Do NOT make any more write/edit/bash calls until you have a plan.</system-summary>`
17848
- });
17849
- }
17850
- if (iter >= 6 && !deps.trackerRef.current && ctx.contextManager) {
17851
- ctx.contextManager.addMessage({
17852
- role: "user",
17853
- content: `<system-summary>STOP. ${iter} iterations without a plan. You MUST call plan create RIGHT NOW. No more tool calls until you create a plan.</system-summary>`
18016
+ content: `<system-summary>${t("exec.plan_nudge", {
18017
+ count: String(mutations)
18018
+ })}</system-summary>`
17854
18019
  });
17855
18020
  }
17856
18021
  }
@@ -17943,6 +18108,9 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
17943
18108
  const args = ctx?.args;
17944
18109
  if (toolName && args) {
17945
18110
  deps.stuckDetector.recordToolCall(toolName, args);
18111
+ if (!deps.trackerRef.current && (toolName === "write_file" || toolName === "edit_file" || toolName === "bash" || toolName === "download_file")) {
18112
+ deps.state.mutationsWithoutPlan++;
18113
+ }
17946
18114
  }
17947
18115
  },
17948
18116
  onAfterTool: (ctx, call, result) => {
@@ -18029,7 +18197,7 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
18029
18197
  }
18030
18198
  };
18031
18199
  }
18032
- var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3, FORCE_SKIP_THRESHOLD = 10;
18200
+ var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3, FORCE_SKIP_THRESHOLD = 10, PLAN_NUDGE_THRESHOLD = 2;
18033
18201
  var init_execution_plugin = __esm(() => {
18034
18202
  init_i18n();
18035
18203
  init_bash();
@@ -18037,7 +18205,7 @@ var init_execution_plugin = __esm(() => {
18037
18205
  });
18038
18206
 
18039
18207
  // src/modules/execution/module.ts
18040
- import { existsSync as existsSync33, readFileSync as readFileSync17 } from "fs";
18208
+ import { existsSync as existsSync33, readFileSync as readFileSync18 } from "fs";
18041
18209
  import { resolve as resolve19 } from "path";
18042
18210
 
18043
18211
  class ExecutionModule {
@@ -18049,6 +18217,7 @@ class ExecutionModule {
18049
18217
  store;
18050
18218
  baseDir;
18051
18219
  _auditSkipsRemaining = 0;
18220
+ completedPlan = null;
18052
18221
  pendingMessages = [];
18053
18222
  forbiddenBashFailures = new Map;
18054
18223
  searchRunner;
@@ -18062,7 +18231,9 @@ class ExecutionModule {
18062
18231
  consecutivePlanWarnings: 0,
18063
18232
  lastStepId: -1,
18064
18233
  stuckNotified: false,
18065
- depsGateHints: new Map
18234
+ depsGateHints: new Map,
18235
+ mutationsWithoutPlan: 0,
18236
+ planNudgeSent: false
18066
18237
  };
18067
18238
  trackerRef = (() => {
18068
18239
  const self = this;
@@ -18087,9 +18258,17 @@ class ExecutionModule {
18087
18258
  }
18088
18259
  setPlan(plan) {
18089
18260
  this.tracker = new PlanTracker(plan);
18261
+ this.tracker.syncCurrentStep();
18090
18262
  this.store.saveActive(plan);
18263
+ this.completedPlan = null;
18091
18264
  this._auditSkipsRemaining = 0;
18092
18265
  }
18266
+ recordCompleted(plan) {
18267
+ this.completedPlan = plan;
18268
+ }
18269
+ clearCompleted() {
18270
+ this.completedPlan = null;
18271
+ }
18093
18272
  restorePlan() {
18094
18273
  const plan = this.store.loadActive();
18095
18274
  if (!plan)
@@ -18167,8 +18346,22 @@ class ExecutionModule {
18167
18346
  }).catch((e) => ctx.logger?.warn(`error web search: ${e.message}`));
18168
18347
  }
18169
18348
  async runFinalAudit() {
18170
- if (!this.tracker)
18171
- return null;
18349
+ if (!this.tracker) {
18350
+ if (!this.completedPlan)
18351
+ return null;
18352
+ const plan2 = this.completedPlan;
18353
+ const audit2 = await this.auditor.audit(plan2);
18354
+ const pendingSteps2 = plan2.steps.flatMap((s) => s.status !== "done" && s.status !== "skipped" ? [`${s.id}. ${s.description}`] : []);
18355
+ const done2 = plan2.steps.filter((s) => s.status === "done").length;
18356
+ return {
18357
+ passed: audit2.passed && pendingSteps2.length === 0,
18358
+ done: done2,
18359
+ total: plan2.steps.length,
18360
+ pendingSteps: pendingSteps2,
18361
+ missingFiles: audit2.missingFiles,
18362
+ summary: audit2.summary
18363
+ };
18364
+ }
18172
18365
  if (this._auditSkipsRemaining > 0) {
18173
18366
  this._auditSkipsRemaining--;
18174
18367
  return null;
@@ -18216,6 +18409,9 @@ class ExecutionModule {
18216
18409
  trackerRef: this.trackerRef,
18217
18410
  preserveActive: () => this.preserveActive(),
18218
18411
  setPlan: (p) => this.setPlan(p),
18412
+ recordCompleted: (p) => this.recordCompleted(p),
18413
+ clearCompleted: () => this.clearCompleted(),
18414
+ hasStepDeliverables: (s) => this.hasStepDeliverables(s),
18219
18415
  missingStepDeliverables: (s) => this.missingStepDeliverables(s),
18220
18416
  stillExistingDeliverables: (s) => this.stillExistingDeliverables(s),
18221
18417
  parseKinds: (a, st) => this.parseKinds(a, st),
@@ -18267,7 +18463,7 @@ class ExecutionModule {
18267
18463
  const stepPaths = extractFileLikeTokens(stripUrls(step.description)).map((p) => p.toLowerCase());
18268
18464
  if (stepPaths.length === 0)
18269
18465
  return null;
18270
- const argStr = JSON.stringify(call.arguments);
18466
+ const argStr = this.pathArgStrings(call.arguments).join(" ");
18271
18467
  const callPaths = extractFileLikeTokens(stripUrls(argStr)).map((p) => p.toLowerCase());
18272
18468
  if (callPaths.length === 0)
18273
18469
  return null;
@@ -18292,13 +18488,31 @@ class ExecutionModule {
18292
18488
  tool: call.name
18293
18489
  });
18294
18490
  }
18491
+ pathArgStrings(args) {
18492
+ if (!args)
18493
+ return [];
18494
+ const out = [];
18495
+ for (const [key, value] of Object.entries(args)) {
18496
+ if (!/path|file|dir|src|dst|source|target|input|output|destination|glob|workdir|cwd|command|pattern|query/i.test(key)) {
18497
+ continue;
18498
+ }
18499
+ if (typeof value === "string")
18500
+ out.push(value);
18501
+ else if (Array.isArray(value)) {
18502
+ for (const v of value)
18503
+ if (typeof v === "string")
18504
+ out.push(v);
18505
+ }
18506
+ }
18507
+ return out;
18508
+ }
18295
18509
  advancePlanIfStepComplete(contextManager, sessionLog) {
18296
18510
  const step = this.tracker?.getCurrentStep();
18297
18511
  if (!step)
18298
18512
  return;
18299
18513
  const stepText = step.description.toLowerCase();
18300
18514
  const stepPaths = extractFileLikeTokens(stripUrls(step.description)) || [];
18301
- const isDepsStep = stepText.includes("install") || stepText.includes("зависим") || stepText.includes("init") || stepText.includes("инициализац");
18515
+ const isDepsStep = /(?:npm|bun|yarn|pnpm|pip|pip3|pipenv|poetry|composer|deno|go|gem|cargo)\s+(?:install|add|init|i|get)\b|bun\s+(?:add|install)|npm\s+(?:i|install|add)|(?:install|установ\w*)\s+(?:dependencies|зависимост\w*|пакет\w*|packages?)/i.test(stepText);
18302
18516
  if (isDepsStep) {
18303
18517
  const lockFiles = [
18304
18518
  "package-lock.json",
@@ -18332,18 +18546,21 @@ class ExecutionModule {
18332
18546
  }
18333
18547
  if (stepPaths.length === 0)
18334
18548
  return;
18335
- const allExist = stepPaths.every((p) => existsSync33(resolve19(this.baseDir, p)));
18336
- const allGone = stepPaths.every((p) => !existsSync33(resolve19(this.baseDir, p)));
18549
+ const resolved = stepPaths.map((p) => findExistingFile(this.baseDir, p));
18550
+ const allExist = resolved.every((r) => r !== null);
18551
+ const allGone = resolved.every((r) => r === null);
18337
18552
  const satisfied = step.kind === "delete" ? allGone && !allExist : allExist;
18338
18553
  if (!satisfied)
18339
18554
  return;
18340
18555
  if (step.kind !== "delete") {
18341
18556
  const emptyFiles = [];
18342
- for (const p of stepPaths) {
18557
+ for (const r of resolved) {
18558
+ if (!r)
18559
+ continue;
18343
18560
  try {
18344
- const content = readFileSync17(resolve19(this.baseDir, p), "utf-8");
18561
+ const content = readFileSync18(r, "utf-8");
18345
18562
  if (content.trim().length < 10) {
18346
- emptyFiles.push(p);
18563
+ emptyFiles.push(r);
18347
18564
  }
18348
18565
  } catch {}
18349
18566
  }
@@ -18376,6 +18593,7 @@ class ExecutionModule {
18376
18593
  if (this.tracker?.isComplete()) {
18377
18594
  const completed = this.tracker.getPlan();
18378
18595
  this.store.archivePlan(completed);
18596
+ this.recordCompleted(completed);
18379
18597
  this.tracker = null;
18380
18598
  sessionLog?.plan("auto-archive", `Plan ${completed.id} complete — archived`);
18381
18599
  }
@@ -18392,6 +18610,9 @@ class ExecutionModule {
18392
18610
  return [];
18393
18611
  return tokens.filter((p) => findExistingFile(this.baseDir, p));
18394
18612
  }
18613
+ hasStepDeliverables(step) {
18614
+ return extractFileLikeTokens(stripUrls(step.description)).length > 0;
18615
+ }
18395
18616
  parseKinds(args, steps) {
18396
18617
  if (args.kinds === undefined)
18397
18618
  return { kinds: null, error: null };
@@ -18445,7 +18666,7 @@ var init_module = __esm(() => {
18445
18666
  });
18446
18667
 
18447
18668
  // src/modules/security/session-encryption.ts
18448
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync11, existsSync as existsSync34, readdirSync as readdirSync11, unlinkSync as unlinkSync4 } from "fs";
18669
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync11, existsSync as existsSync34, readdirSync as readdirSync11, unlinkSync as unlinkSync4 } from "fs";
18449
18670
  import { join as join27 } from "path";
18450
18671
  import { homedir as homedir8 } from "os";
18451
18672
 
@@ -18500,7 +18721,7 @@ class SessionFileEncryptor {
18500
18721
  return lines.map((line) => this.decryptFileContent(line));
18501
18722
  }
18502
18723
  readSessionFile(filePath) {
18503
- const content = readFileSync18(filePath, "utf8");
18724
+ const content = readFileSync19(filePath, "utf8");
18504
18725
  return this.decryptFileContent(content);
18505
18726
  }
18506
18727
  writeSessionFile(filePath, content) {
@@ -18508,7 +18729,7 @@ class SessionFileEncryptor {
18508
18729
  writeFileSync11(filePath, encrypted, "utf8");
18509
18730
  }
18510
18731
  readSessionJSON(filePath) {
18511
- const content = readFileSync18(filePath, "utf8");
18732
+ const content = readFileSync19(filePath, "utf8");
18512
18733
  return this.decryptJSON(content);
18513
18734
  }
18514
18735
  writeSessionJSON(filePath, obj) {
@@ -18516,7 +18737,7 @@ class SessionFileEncryptor {
18516
18737
  writeFileSync11(filePath, content, "utf8");
18517
18738
  }
18518
18739
  readSessionJSONL(filePath) {
18519
- const content = readFileSync18(filePath, "utf8");
18740
+ const content = readFileSync19(filePath, "utf8");
18520
18741
  const lines = content.split(`
18521
18742
  `).filter((line) => line.trim());
18522
18743
  const decryptedLines = this.decryptJSONL(lines);
@@ -18544,7 +18765,7 @@ class SessionFileEncryptor {
18544
18765
  const filePath = join27(sessionDir, file);
18545
18766
  if (existsSync34(filePath) && !file.endsWith(".enc")) {
18546
18767
  try {
18547
- const content = readFileSync18(filePath, "utf8");
18768
+ const content = readFileSync19(filePath, "utf8");
18548
18769
  const encrypted = this.encryptFileContent(content);
18549
18770
  writeFileSync11(filePath + ".enc", encrypted, "utf8");
18550
18771
  unlinkSync4(filePath);
@@ -18561,7 +18782,7 @@ class SessionFileEncryptor {
18561
18782
  const encFilePath = join27(sessionDir, file);
18562
18783
  const decFilePath = encFilePath.slice(0, -4);
18563
18784
  try {
18564
- const content = readFileSync18(encFilePath, "utf8");
18785
+ const content = readFileSync19(encFilePath, "utf8");
18565
18786
  const decrypted = this.decryptFileContent(content);
18566
18787
  writeFileSync11(decFilePath, decrypted, "utf8");
18567
18788
  unlinkSync4(encFilePath);
@@ -18586,7 +18807,7 @@ import {
18586
18807
  existsSync as existsSync35,
18587
18808
  mkdirSync as mkdirSync15,
18588
18809
  readdirSync as readdirSync12,
18589
- readFileSync as readFileSync19,
18810
+ readFileSync as readFileSync20,
18590
18811
  rmSync as rmSync2,
18591
18812
  writeFileSync as writeFileSync12,
18592
18813
  appendFileSync as appendFileSync6
@@ -18654,7 +18875,7 @@ class SessionStore {
18654
18875
  if (!existsSync35(path))
18655
18876
  return null;
18656
18877
  try {
18657
- const raw = readFileSync19(path, "utf-8");
18878
+ const raw = readFileSync20(path, "utf-8");
18658
18879
  const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
18659
18880
  const meta = JSON.parse(content);
18660
18881
  this._metaCache.set(id, meta);
@@ -18686,7 +18907,7 @@ class SessionStore {
18686
18907
  if (!existsSync35(path))
18687
18908
  return [];
18688
18909
  try {
18689
- const raw = readFileSync19(path, "utf-8");
18910
+ const raw = readFileSync20(path, "utf-8");
18690
18911
  const lines = raw.split(`
18691
18912
  `).filter(Boolean);
18692
18913
  const parseLine = (line) => {
@@ -18727,7 +18948,7 @@ class SessionStore {
18727
18948
  if (!existsSync35(path))
18728
18949
  return [];
18729
18950
  try {
18730
- const raw = readFileSync19(path, "utf-8");
18951
+ const raw = readFileSync20(path, "utf-8");
18731
18952
  const lines = raw.split(`
18732
18953
  `).filter(Boolean);
18733
18954
  const parseLine = (line) => {
@@ -18782,7 +19003,7 @@ class SessionStore {
18782
19003
  if (updatedAt < thirtyDaysAgo) {
18783
19004
  const historyPath = this.historyPath(session2.id);
18784
19005
  if (existsSync35(historyPath)) {
18785
- const content = readFileSync19(historyPath, "utf-8");
19006
+ const content = readFileSync20(historyPath, "utf-8");
18786
19007
  const compressed = gzipSync(content);
18787
19008
  const gzPath = join28(this.baseDir, `${session2.id}.jsonl.gz`);
18788
19009
  writeFileSync12(gzPath, compressed);
@@ -18994,7 +19215,7 @@ class ProfileCompressor {
18994
19215
  }
18995
19216
 
18996
19217
  // src/modules/user-profile/profile.ts
18997
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync36, mkdirSync as mkdirSync16 } from "fs";
19218
+ import { readFileSync as readFileSync21, writeFileSync as writeFileSync13, existsSync as existsSync36, mkdirSync as mkdirSync16 } from "fs";
18998
19219
  import { join as join29 } from "path";
18999
19220
  import { homedir as homedir9, hostname, platform as platform7, type } from "os";
19000
19221
  import { env } from "process";
@@ -19029,7 +19250,7 @@ class UserProfile {
19029
19250
  if (!existsSync36(path))
19030
19251
  return null;
19031
19252
  try {
19032
- const data = JSON.parse(readFileSync20(path, "utf-8"));
19253
+ const data = JSON.parse(readFileSync21(path, "utf-8"));
19033
19254
  this.info = {
19034
19255
  platform: data.platform,
19035
19256
  os: data.os,
@@ -19064,7 +19285,7 @@ class UserProfile {
19064
19285
  var init_profile = () => {};
19065
19286
 
19066
19287
  // src/modules/skills/loader.ts
19067
- import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as existsSync37, statSync as statSync6 } from "fs";
19288
+ import { readdirSync as readdirSync13, readFileSync as readFileSync22, existsSync as existsSync37, statSync as statSync6 } from "fs";
19068
19289
  import { join as join30 } from "path";
19069
19290
 
19070
19291
  class SkillsLoader {
@@ -19086,7 +19307,7 @@ class SkillsLoader {
19086
19307
  }
19087
19308
  if (!entry.endsWith(".md") && !entry.endsWith(".skill.md"))
19088
19309
  continue;
19089
- const content = readFileSync21(fullPath, "utf-8");
19310
+ const content = readFileSync22(fullPath, "utf-8");
19090
19311
  const parsed = this.parseSkillFile(content, fullPath);
19091
19312
  if (parsed)
19092
19313
  skills.push(parsed);
@@ -19988,7 +20209,7 @@ var init_startup_check = __esm(() => {
19988
20209
  });
19989
20210
 
19990
20211
  // src/modules/indexer/walker.ts
19991
- import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync40, watch } from "fs";
20212
+ import { readdirSync as readdirSync14, readFileSync as readFileSync23, statSync as statSync7, existsSync as existsSync40, watch } from "fs";
19992
20213
  import { join as join32, relative as relative4, extname as extname5 } from "path";
19993
20214
 
19994
20215
  class Indexer {
@@ -20038,7 +20259,7 @@ class Indexer {
20038
20259
  const ext = extname5(entry).toLowerCase();
20039
20260
  const language = LANGUAGES[ext];
20040
20261
  if (language) {
20041
- const content = readFileSync22(fullPath, "utf-8");
20262
+ const content = readFileSync23(fullPath, "utf-8");
20042
20263
  const exports = this.extractExports(content, language);
20043
20264
  files.push({ path: relPath, language, exports, size: stat2.size });
20044
20265
  totalSize += stat2.size;
@@ -20090,7 +20311,7 @@ var init_walker = __esm(() => {
20090
20311
  });
20091
20312
 
20092
20313
  // src/modules/indexer/cache.ts
20093
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync41, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
20314
+ import { readFileSync as readFileSync24, writeFileSync as writeFileSync14, existsSync as existsSync41, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
20094
20315
  import { join as join33 } from "path";
20095
20316
 
20096
20317
  class IndexCache {
@@ -20105,7 +20326,7 @@ class IndexCache {
20105
20326
  if (!existsSync41(this.cachePath))
20106
20327
  return null;
20107
20328
  try {
20108
- this.cache = JSON.parse(readFileSync23(this.cachePath, "utf-8"));
20329
+ this.cache = JSON.parse(readFileSync24(this.cachePath, "utf-8"));
20109
20330
  return this.cache;
20110
20331
  } catch {
20111
20332
  return null;
@@ -20130,7 +20351,7 @@ class IndexCache {
20130
20351
  var init_cache = () => {};
20131
20352
 
20132
20353
  // src/modules/indexer/project-profile.ts
20133
- import { readFileSync as readFileSync24, existsSync as existsSync42 } from "fs";
20354
+ import { readFileSync as readFileSync25, existsSync as existsSync42 } from "fs";
20134
20355
  import { join as join34 } from "path";
20135
20356
  function detectManifest(baseDir) {
20136
20357
  for (const manifest of MANIFEST_ORDER) {
@@ -20151,7 +20372,7 @@ function cleanDependency(entry) {
20151
20372
  }
20152
20373
  function readPackageJson(baseDir) {
20153
20374
  try {
20154
- const raw = JSON.parse(readFileSync24(join34(baseDir, "package.json"), "utf-8"));
20375
+ const raw = JSON.parse(readFileSync25(join34(baseDir, "package.json"), "utf-8"));
20155
20376
  if (!raw || typeof raw !== "object")
20156
20377
  return null;
20157
20378
  const profile = {
@@ -20175,7 +20396,7 @@ function readPackageJson(baseDir) {
20175
20396
  }
20176
20397
  function readPyproject(baseDir) {
20177
20398
  try {
20178
- const content = readFileSync24(join34(baseDir, "pyproject.toml"), "utf-8");
20399
+ const content = readFileSync25(join34(baseDir, "pyproject.toml"), "utf-8");
20179
20400
  const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
20180
20401
  const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
20181
20402
  if (nameMatch)
@@ -20191,7 +20412,7 @@ function readPyproject(baseDir) {
20191
20412
  }
20192
20413
  function readCargo(baseDir) {
20193
20414
  try {
20194
- const content = readFileSync24(join34(baseDir, "Cargo.toml"), "utf-8");
20415
+ const content = readFileSync25(join34(baseDir, "Cargo.toml"), "utf-8");
20195
20416
  const profile = { runtime: "rust", deps: [], devDeps: [], scripts: {} };
20196
20417
  const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
20197
20418
  if (nameMatch)
@@ -20215,7 +20436,7 @@ function readCargo(baseDir) {
20215
20436
  }
20216
20437
  function readGoMod(baseDir) {
20217
20438
  try {
20218
- const content = readFileSync24(join34(baseDir, "go.mod"), "utf-8");
20439
+ const content = readFileSync25(join34(baseDir, "go.mod"), "utf-8");
20219
20440
  const profile = { runtime: "go", deps: [], devDeps: [], scripts: {} };
20220
20441
  const moduleMatch = content.match(/^module\s+(\S+)/m);
20221
20442
  if (moduleMatch)
@@ -20233,7 +20454,7 @@ function readGoMod(baseDir) {
20233
20454
  }
20234
20455
  function readRequirements(baseDir) {
20235
20456
  try {
20236
- const content = readFileSync24(join34(baseDir, "requirements.txt"), "utf-8");
20457
+ const content = readFileSync25(join34(baseDir, "requirements.txt"), "utf-8");
20237
20458
  const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
20238
20459
  for (const line of content.split(`
20239
20460
  `)) {
@@ -20786,7 +21007,7 @@ var init_module8 = __esm(() => {
20786
21007
  });
20787
21008
 
20788
21009
  // src/core/version.ts
20789
- import { existsSync as existsSync43, readFileSync as readFileSync25 } from "fs";
21010
+ import { existsSync as existsSync43, readFileSync as readFileSync26 } from "fs";
20790
21011
  import { join as join36, dirname as dirname13 } from "path";
20791
21012
  import { fileURLToPath as fileURLToPath2 } from "url";
20792
21013
  function readMmaVersion() {
@@ -20795,7 +21016,7 @@ function readMmaVersion() {
20795
21016
  for (const p of candidates) {
20796
21017
  if (existsSync43(p)) {
20797
21018
  try {
20798
- const raw = JSON.parse(readFileSync25(p, "utf8"));
21019
+ const raw = JSON.parse(readFileSync26(p, "utf8"));
20799
21020
  if (raw.version)
20800
21021
  return raw.version;
20801
21022
  } catch {}
@@ -20813,7 +21034,7 @@ __export(exports_bootstrap, {
20813
21034
  });
20814
21035
  import { homedir as homedir11 } from "os";
20815
21036
  import { join as join37, resolve as resolve23 } from "path";
20816
- import { existsSync as existsSync44, readFileSync as readFileSync26, writeFileSync as writeFileSync15 } from "fs";
21037
+ import { existsSync as existsSync44, readFileSync as readFileSync27, writeFileSync as writeFileSync15 } from "fs";
20817
21038
  function buildSystemInfo(config, baseDir, profileCompressed) {
20818
21039
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
20819
21040
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -21073,7 +21294,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21073
21294
  ];
21074
21295
  for (const p of agentsMdCandidates) {
21075
21296
  if (existsSync44(p)) {
21076
- const content = readFileSync26(p, "utf-8").trim();
21297
+ const content = readFileSync27(p, "utf-8").trim();
21077
21298
  if (content) {
21078
21299
  agentsMdBlocks.push({
21079
21300
  content,
@@ -21937,13 +22158,13 @@ __export(exports_manifest, {
21937
22158
  getCertMark: () => getCertMark,
21938
22159
  MANIFEST_PATH: () => MANIFEST_PATH
21939
22160
  });
21940
- import { existsSync as existsSync45, readFileSync as readFileSync27, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
22161
+ import { existsSync as existsSync45, readFileSync as readFileSync28, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
21941
22162
  import { homedir as homedir13 } from "os";
21942
22163
  import { join as join39 } from "path";
21943
22164
  function readManifest(path = MANIFEST_PATH) {
21944
22165
  try {
21945
22166
  if (existsSync45(path)) {
21946
- const raw = JSON.parse(readFileSync27(path, "utf-8"));
22167
+ const raw = JSON.parse(readFileSync28(path, "utf-8"));
21947
22168
  return { version: 1, certifications: raw.certifications ?? [] };
21948
22169
  }
21949
22170
  } catch {}
@@ -29108,7 +29329,7 @@ var init_scenarios = __esm(() => {
29108
29329
  });
29109
29330
 
29110
29331
  // src/modules/certification/loader.ts
29111
- import { existsSync as existsSync46, readdirSync as readdirSync15, readFileSync as readFileSync28 } from "fs";
29332
+ import { existsSync as existsSync46, readdirSync as readdirSync15, readFileSync as readFileSync29 } from "fs";
29112
29333
  import { join as join40 } from "path";
29113
29334
  function validateScenario(s) {
29114
29335
  const errors2 = [];
@@ -29163,7 +29384,7 @@ function loadScenarios(userDir) {
29163
29384
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
29164
29385
  continue;
29165
29386
  try {
29166
- const raw = readFileSync28(join40(userDir, file), "utf-8");
29387
+ const raw = readFileSync29(join40(userDir, file), "utf-8");
29167
29388
  const data = $parse(raw);
29168
29389
  const parsed = normalizeScenario(data, file);
29169
29390
  const errs = validateScenario(parsed);
@@ -29216,7 +29437,7 @@ var init_loader3 = __esm(() => {
29216
29437
  });
29217
29438
 
29218
29439
  // src/modules/certification/fact-checker.ts
29219
- import { existsSync as existsSync47, readFileSync as readFileSync29, statSync as statSync8 } from "fs";
29440
+ import { existsSync as existsSync47, readFileSync as readFileSync30, statSync as statSync8 } from "fs";
29220
29441
  import { join as join41 } from "path";
29221
29442
  function checkSandbox(sandboxDir, checks, exitCode, output) {
29222
29443
  const failures = [];
@@ -29243,7 +29464,7 @@ function runCheck2(sandboxDir, check, exitCode, output) {
29243
29464
  const abs = join41(sandboxDir, check.path);
29244
29465
  if (!isFile(abs))
29245
29466
  return false;
29246
- const content = readFileSync29(abs, "utf-8");
29467
+ const content = readFileSync30(abs, "utf-8");
29247
29468
  if (check.contains !== undefined)
29248
29469
  return content.includes(check.contains);
29249
29470
  if (check.equals !== undefined)
@@ -29254,7 +29475,7 @@ function runCheck2(sandboxDir, check, exitCode, output) {
29254
29475
  const abs = join41(sandboxDir, check.path);
29255
29476
  if (!isFile(abs))
29256
29477
  return false;
29257
- return new RegExp(check.pattern).test(readFileSync29(abs, "utf-8"));
29478
+ return new RegExp(check.pattern).test(readFileSync30(abs, "utf-8"));
29258
29479
  }
29259
29480
  default:
29260
29481
  return false;
@@ -29470,13 +29691,13 @@ import { rmSync as rmSync5 } from "fs";
29470
29691
  import { homedir as homedir14 } from "os";
29471
29692
  import { join as join43, dirname as dirname15 } from "path";
29472
29693
  import { fileURLToPath as fileURLToPath3 } from "url";
29473
- import { existsSync as existsSync49, readFileSync as readFileSync30 } from "fs";
29694
+ import { existsSync as existsSync49, readFileSync as readFileSync31 } from "fs";
29474
29695
  function readVersion() {
29475
29696
  const candidates = [join43(MMA_ROOT, "package.json")];
29476
29697
  for (const p of candidates) {
29477
29698
  if (existsSync49(p)) {
29478
29699
  try {
29479
- const raw = JSON.parse(readFileSync30(p, "utf-8"));
29700
+ const raw = JSON.parse(readFileSync31(p, "utf-8"));
29480
29701
  if (raw.version)
29481
29702
  return raw.version;
29482
29703
  } catch {}
@@ -29637,7 +29858,7 @@ __export(exports_repl_commands, {
29637
29858
  });
29638
29859
  import { join as join45, dirname as dirname17 } from "path";
29639
29860
  import { homedir as homedir16 } from "os";
29640
- import { existsSync as existsSync51, readFileSync as readFileSync32 } from "fs";
29861
+ import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
29641
29862
  import { fileURLToPath as fileURLToPath5 } from "url";
29642
29863
  function readVersion3() {
29643
29864
  const here = dirname17(fileURLToPath5(import.meta.url));
@@ -29645,7 +29866,7 @@ function readVersion3() {
29645
29866
  for (const p of candidates) {
29646
29867
  if (existsSync51(p)) {
29647
29868
  try {
29648
- const raw = JSON.parse(readFileSync32(p, "utf8"));
29869
+ const raw = JSON.parse(readFileSync33(p, "utf8"));
29649
29870
  if (raw.version)
29650
29871
  return raw.version;
29651
29872
  } catch {}
@@ -30303,7 +30524,7 @@ init_setup();
30303
30524
  init_i18n();
30304
30525
  import { join as join44, dirname as dirname16 } from "path";
30305
30526
  import { homedir as homedir15 } from "os";
30306
- import { existsSync as existsSync50, readFileSync as readFileSync31 } from "fs";
30527
+ import { existsSync as existsSync50, readFileSync as readFileSync32 } from "fs";
30307
30528
 
30308
30529
  // src/cli/security-commands.ts
30309
30530
  init_bootstrap();
@@ -30945,7 +31166,7 @@ function readVersion2() {
30945
31166
  for (const p of candidates) {
30946
31167
  if (existsSync50(p)) {
30947
31168
  try {
30948
- const raw = JSON.parse(readFileSync31(p, "utf8"));
31169
+ const raw = JSON.parse(readFileSync32(p, "utf8"));
30949
31170
  if (raw.version)
30950
31171
  return raw.version;
30951
31172
  } catch {}
@@ -31928,7 +32149,7 @@ class LineEditor {
31928
32149
  }
31929
32150
 
31930
32151
  // src/cli/repl.ts
31931
- import { existsSync as existsSync53, readFileSync as readFileSync34, writeFileSync as writeFileSync17 } from "fs";
32152
+ import { existsSync as existsSync53, readFileSync as readFileSync35, writeFileSync as writeFileSync17 } from "fs";
31932
32153
  import { join as join47, dirname as dirname18 } from "path";
31933
32154
  import { homedir as homedir17 } from "os";
31934
32155
  import { fileURLToPath as fileURLToPath6 } from "url";
@@ -32517,14 +32738,14 @@ init_config();
32517
32738
  init_colors();
32518
32739
  init_js_identifiers();
32519
32740
  init_i18n();
32520
- import { existsSync as existsSync52, readFileSync as readFileSync33 } from "fs";
32741
+ import { existsSync as existsSync52, readFileSync as readFileSync34 } from "fs";
32521
32742
  import { join as join46 } from "path";
32522
32743
  function readActivePlan(baseDir) {
32523
32744
  const p = join46(baseDir, ".mma", "plans", "active.json");
32524
32745
  if (!existsSync52(p))
32525
32746
  return null;
32526
32747
  try {
32527
- const raw = readFileSync33(p, "utf-8");
32748
+ const raw = readFileSync34(p, "utf-8");
32528
32749
  if (!raw.trim())
32529
32750
  return null;
32530
32751
  const parsed = JSON.parse(raw);
@@ -32623,7 +32844,7 @@ function readVersion4() {
32623
32844
  for (const p of candidates) {
32624
32845
  if (existsSync53(p)) {
32625
32846
  try {
32626
- const raw = JSON.parse(readFileSync34(p, "utf8"));
32847
+ const raw = JSON.parse(readFileSync35(p, "utf8"));
32627
32848
  if (raw.version)
32628
32849
  return raw.version;
32629
32850
  } catch {}
@@ -32719,7 +32940,7 @@ class Repl {
32719
32940
  loadHistory() {
32720
32941
  if (existsSync53(this.historyPath)) {
32721
32942
  try {
32722
- const raw = readFileSync34(this.historyPath, "utf-8");
32943
+ const raw = readFileSync35(this.historyPath, "utf-8");
32723
32944
  this.history = raw.split(`
32724
32945
  `).filter(Boolean).slice(-this.maxHistory);
32725
32946
  } catch {
@@ -33192,7 +33413,7 @@ init_setup();
33192
33413
  init_config2();
33193
33414
  init_i18n();
33194
33415
  init_colors();
33195
- import { existsSync as existsSync54, readFileSync as readFileSync35 } from "fs";
33416
+ import { existsSync as existsSync54, readFileSync as readFileSync36 } from "fs";
33196
33417
  import { join as join48, dirname as dirname19 } from "path";
33197
33418
  import { homedir as homedir18 } from "os";
33198
33419
  import { fileURLToPath as fileURLToPath7 } from "url";
@@ -33301,7 +33522,7 @@ function readVersion5() {
33301
33522
  for (const p of candidates) {
33302
33523
  if (existsSync54(p)) {
33303
33524
  try {
33304
- const raw = JSON.parse(readFileSync35(p, "utf8"));
33525
+ const raw = JSON.parse(readFileSync36(p, "utf8"));
33305
33526
  if (raw.version)
33306
33527
  return raw.version;
33307
33528
  } catch {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.42.0",
3
+ "version": "0.43.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": {