micro-models-agent 0.35.5 → 0.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.js +242 -172
  2. package/package.json +45 -45
package/dist/main.js CHANGED
@@ -2142,7 +2142,7 @@ var init_config = __esm(() => {
2142
2142
  css: {
2143
2143
  command: "npx",
2144
2144
  args: ["vscode-css-languageserver", "--stdio"],
2145
- timeout: 1e4,
2145
+ timeout: 20000,
2146
2146
  autoInstall: true,
2147
2147
  workspaceMarkers: ["package.json"]
2148
2148
  }
@@ -2785,6 +2785,7 @@ Use this knowledge to answer the user's question.`,
2785
2785
  {hints}`,
2786
2786
  "exec.file_rewrite_warning": "⚠️ File {file} has been rewritten {count} times. Consider a different approach — the current fix strategy is not working.",
2787
2787
  "exec.forbidden_cmd": 'STOP using "{cmd}" via the bash tool — it is not a native Windows cmd.exe command and has failed repeatedly this session. Use the dedicated tool instead: grep → the grep tool, ls/dir → list_dir, find → glob, rm → delete_file, sed → edit_file, touch → write_file, which → `where`, cp/mv → move_file, diff → read_file. Do NOT call bash for this purpose again.',
2788
+ "exec.npm_exec_hint": '"could not determine executable to run" — no "bin" for that package/script. Use "npm run <script>" (script must exist in package.json) or "bunx <pkg>" for a package that declares a bin.',
2788
2789
  "hall.max_retries_exhausted": "Model returned empty or insufficient responses after multiple retries",
2789
2790
  "hall.short_response": "Response too short or empty",
2790
2791
  "hall.repetitive": "Response too repetitive ({pct}% overlap)",
@@ -3383,6 +3384,7 @@ var init_ru = __esm(() => {
3383
3384
  {hints}`,
3384
3385
  "exec.file_rewrite_warning": "⚠️ Файл {file} был перезаписан {count} раз. Попробуйте другой подход — текущая стратегия исправлений не работает.",
3385
3386
  "exec.forbidden_cmd": 'ПРЕКРАТИ использовать "{cmd}" через bash — это не команда Windows cmd.exe, и она уже неоднократно падала в этой сессии. Используй предназначенный тул: grep → тул grep, ls/dir → list_dir, find → glob, rm → delete_file, sed → edit_file, touch → write_file, which → `where`, cp/mv → move_file, diff → read_file. Больше не вызывай bash для этого.',
3387
+ "exec.npm_exec_hint": '"could not determine executable to run" — у пакета/скрипта нет "bin". Используй "npm run <script>" (скрипт должен быть в package.json) или "bunx <pkg>" для пакета с объявленным bin.',
3386
3388
  "hall.max_retries_exhausted": "Модель вернула пустой или недостаточный ответ после нескольких попыток",
3387
3389
  "hall.short_response": "Слишком короткий или пустой ответ",
3388
3390
  "hall.repetitive": "Слишком повторяющийся ответ ({pct}% совпадение)",
@@ -7555,7 +7557,15 @@ function emptyCliRunHint(command, output, code) {
7555
7557
  return null;
7556
7558
  return "the command exited 0 but printed NOTHING to stdout. If this should run a CLI program, the file probably has no entry point: read it with read_file and check the code actually calls its main function with command-line arguments (e.g. main(process.argv[2])) and prints results with console.log.";
7557
7559
  }
7558
- var BASH_GRACE_MS = 5000, SPAWN_SETTLE_MS = 100, bashGraceMs, FAILING_FIRST_WORDS, HARD_BLOCK_THRESHOLD = 3, UNIX_TO_WIN_HINTS, UNIX_TO_WIN_TRANSLATE, NEVER_TOOL_CALLS, CLI_FILE_RUN_RE, bashTool;
7560
+ function npmExecHint(output) {
7561
+ if (NPM_EXEC_RE.test(output)) {
7562
+ return `${output}
7563
+
7564
+ Hint: ${t("exec.npm_exec_hint")}`;
7565
+ }
7566
+ return output;
7567
+ }
7568
+ var BASH_GRACE_MS = 5000, SPAWN_SETTLE_MS = 100, bashGraceMs, FAILING_FIRST_WORDS, HARD_BLOCK_THRESHOLD = 3, UNIX_TO_WIN_HINTS, UNIX_TO_WIN_TRANSLATE, NEVER_TOOL_CALLS, CLI_FILE_RUN_RE, NPM_EXEC_RE, bashTool;
7559
7569
  var init_bash = __esm(() => {
7560
7570
  init_command_validator();
7561
7571
  init_audit_log();
@@ -7620,6 +7630,7 @@ var init_bash = __esm(() => {
7620
7630
  "awk"
7621
7631
  ]);
7622
7632
  CLI_FILE_RUN_RE = /\b(bun|node|deno|python|python3|tsx|ts-node|php|ruby|go\s+run)\S*\s+(run\s+)?["']?[\w./\\-]+\.(ts|js|tsx|jsx|mjs|cjs|py)\b/;
7633
+ NPM_EXEC_RE = /could not determine executable to run/i;
7623
7634
  bashTool = {
7624
7635
  name: "bash",
7625
7636
  description: `Execute a shell command and return its output. Use for running tests, build, git, and shell operations. Commands that are still running after a few seconds are automatically moved to the background and return a process id — manage them with process_list, process_log, process_kill. Set background=true to return a process id immediately for commands you know are long-running (dev servers, watchers).
@@ -7716,6 +7727,7 @@ ${output2}`;
7716
7727
  if (!output2 && code !== 0) {
7717
7728
  output2 = `(exit code ${code})`;
7718
7729
  }
7730
+ output2 = npmExecHint(output2);
7719
7731
  if (platform2() === "win32") {
7720
7732
  const originalFirstWord = originalCommand.trim().split(/\s+/)[0]?.split(/[\\/]/).pop();
7721
7733
  if (originalFirstWord && originalFirstWord in UNIX_TO_WIN_HINTS) {
@@ -10410,7 +10422,11 @@ class Agent {
10410
10422
  ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10411
10423
  }
10412
10424
  emitPhase(iteration, phase, onPhase) {
10413
- this.deps.pluginManager.runOnPhase?.({ iteration, logger: this.deps.logger }, phase);
10425
+ this.deps.pluginManager.runOnPhase?.({
10426
+ iteration,
10427
+ logger: this.deps.logger,
10428
+ contextManager: this.deps.contextManager
10429
+ }, phase);
10414
10430
  onPhase?.(phase);
10415
10431
  }
10416
10432
  async run(input, onChunk, onMeta, onTool, onPhase) {
@@ -10440,7 +10456,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10440
10456
  }
10441
10457
  pluginManager.runOnSessionStart({
10442
10458
  logger,
10443
- sessionManager: sessionManager?.getActiveMeta()
10459
+ sessionManager: sessionManager?.getActiveMeta(),
10460
+ contextManager
10444
10461
  });
10445
10462
  if (config.session?.baselineCheck !== false) {
10446
10463
  const verifier = new StepVerifier(baseDir);
@@ -10573,7 +10590,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10573
10590
  if (chunk.type === "reasoning" && chunk.content) {
10574
10591
  reasoningContent += chunk.content;
10575
10592
  if (config.showReasoning) {
10576
- const metaOut = pluginManager.runOnMeta({ iteration, logger }, chunk.content);
10593
+ const metaOut = pluginManager.runOnMeta({ iteration, logger, contextManager }, chunk.content);
10577
10594
  if (metaOut) {
10578
10595
  onMeta?.(pc2.dim(metaOut));
10579
10596
  }
@@ -10607,7 +10624,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10607
10624
  logger.logLLMResponse(config.model, textContent.length, Date.now() - llmStart, err.message, "agent");
10608
10625
  logger.error(`LLM call failed: ${err.message}`);
10609
10626
  slog.logError(err.message);
10610
- pluginManager.runOnError({ iteration, logger }, err);
10627
+ pluginManager.runOnError({ iteration, logger, contextManager }, err);
10611
10628
  return {
10612
10629
  success: false,
10613
10630
  text: lastText,
@@ -10626,7 +10643,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10626
10643
  const showText = textChunks.length > 0 && (!sawToolCall || toolComments && !isToolCallJson(textContent));
10627
10644
  if (showText) {
10628
10645
  for (const chunk of textChunks) {
10629
- const textOut = pluginManager.runOnText({ iteration, logger }, chunk);
10646
+ const textOut = pluginManager.runOnText({ iteration, logger, contextManager }, chunk);
10630
10647
  onChunk?.(textOut);
10631
10648
  }
10632
10649
  }
@@ -10638,7 +10655,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10638
10655
  } else if (reasoningContent) {
10639
10656
  llmResponse = { type: "reasoning", content: reasoningContent };
10640
10657
  }
10641
- pluginManager.runOnAfterThink({ iteration, logger }, llmResponse);
10658
+ pluginManager.runOnAfterThink({ iteration, logger, contextManager }, llmResponse);
10642
10659
  if (this.deps.exitOnComplete && sawToolCall) {
10643
10660
  const signature = toolCalls.map((tc) => `${tc.name}:${JSON.stringify(tc.arguments)}`).join("|");
10644
10661
  if (signature && signature === lastToolSignature) {
@@ -10679,7 +10696,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10679
10696
  toolName: call.name,
10680
10697
  args: call.arguments
10681
10698
  });
10682
- pluginManager.runOnToolStart({ iteration, logger }, { id: call.id, name: call.name, arguments: call.arguments });
10699
+ pluginManager.runOnToolStart({ iteration, logger, contextManager }, { id: call.id, name: call.name, arguments: call.arguments });
10683
10700
  onTool?.({ type: "start", tool: call.name, args: call.arguments });
10684
10701
  slog.logToolCall(call, iteration);
10685
10702
  const tokensBeforeTool = contextManager.getEstimatedTokens();
@@ -10695,13 +10712,13 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10695
10712
  hallucinationDetector.getConsistencyCheck().trackDeletedFile(filePath);
10696
10713
  }
10697
10714
  }
10698
- pluginManager.runOnToolEnd({ iteration, logger }, { id: call.id, name: call.name, arguments: call.arguments }, result, duration);
10715
+ pluginManager.runOnToolEnd({ iteration, logger, contextManager }, { id: call.id, name: call.name, arguments: call.arguments }, result, duration);
10699
10716
  if (result.display) {
10700
10717
  onMeta?.(`
10701
10718
  ` + result.display + `
10702
10719
  `);
10703
10720
  } else {
10704
- const metaOut = pluginManager.runOnMeta({ iteration, logger }, result.output);
10721
+ const metaOut = pluginManager.runOnMeta({ iteration, logger, contextManager }, result.output);
10705
10722
  onMeta?.(`
10706
10723
  ` + pc2.dim(metaOut) + `
10707
10724
  `);
@@ -11022,7 +11039,8 @@ ${warnLine}
11022
11039
  logger.closeSessionLog();
11023
11040
  pluginManager.runOnSessionEnd({
11024
11041
  logger,
11025
- sessionManager: sessionManager?.getActiveMeta()
11042
+ sessionManager: sessionManager?.getActiveMeta(),
11043
+ contextManager
11026
11044
  });
11027
11045
  }
11028
11046
  }
@@ -14210,6 +14228,7 @@ class BridgeDriver {
14210
14228
  proc = null;
14211
14229
  rl = null;
14212
14230
  pending = new Map;
14231
+ lastStderr = [];
14213
14232
  nextId = 1;
14214
14233
  lastUrl = "";
14215
14234
  console = new ConsoleBuffer(500);
@@ -14218,9 +14237,13 @@ class BridgeDriver {
14218
14237
  constructor(opts = {}) {
14219
14238
  this.maxConsoleLineChars = opts.maxConsoleLineChars ?? 400;
14220
14239
  }
14221
- async send(cmd, params = {}) {
14222
- if (!this.proc || !this.rl)
14223
- throw new Error("Bridge is not running");
14240
+ async send(cmd, params = {}, retried = false) {
14241
+ if (!this.proc || !this.rl) {
14242
+ if (retried || cmd === "close")
14243
+ throw new Error("Bridge is not running");
14244
+ this.spawnBridge();
14245
+ return this.send(cmd, params, true);
14246
+ }
14224
14247
  const id = this.nextId++;
14225
14248
  const response = await new Promise((resolve15, reject) => {
14226
14249
  const timer = setTimeout(() => {
@@ -14266,7 +14289,10 @@ class BridgeDriver {
14266
14289
  const script = bridgeScriptPath();
14267
14290
  const proc = spawn4("node", [script], { stdio: ["pipe", "pipe", "pipe"], windowsHide: true });
14268
14291
  this.proc = proc;
14269
- proc.stderr.on("data", () => {});
14292
+ this.lastStderr = [];
14293
+ proc.stderr.on("data", (chunk) => {
14294
+ this.lastStderr = [...this.lastStderr.slice(-4), chunk.toString()];
14295
+ });
14270
14296
  const rl = createInterface({ input: proc.stdout });
14271
14297
  this.rl = rl;
14272
14298
  rl.on("line", (line) => {
@@ -14282,15 +14308,28 @@ class BridgeDriver {
14282
14308
  resolver(resp);
14283
14309
  }
14284
14310
  });
14285
- proc.on("exit", () => {
14286
- for (const [, resolver] of this.pending) {
14287
- resolver({ id: -1, ok: false, error: "Bridge process exited" });
14288
- }
14289
- this.pending.clear();
14311
+ proc.on("error", (err) => {
14312
+ if (this.proc !== proc)
14313
+ return;
14314
+ this.failPending(`Bridge process failed to start: ${err.message}`);
14315
+ this.proc = null;
14316
+ this.rl = null;
14317
+ });
14318
+ proc.on("exit", (code) => {
14319
+ if (this.proc !== proc)
14320
+ return;
14321
+ const stderrTail = this.lastStderr.join("").trim();
14322
+ this.failPending(stderrTail ? `Bridge process exited (code ${code}): ${stderrTail.slice(0, 300)}` : `Bridge process exited (code ${code})`);
14290
14323
  this.proc = null;
14291
14324
  this.rl = null;
14292
14325
  });
14293
14326
  }
14327
+ failPending(error) {
14328
+ for (const [, resolver] of this.pending) {
14329
+ resolver({ id: -1, ok: false, error });
14330
+ }
14331
+ this.pending.clear();
14332
+ }
14294
14333
  async goto(url, timeoutMs) {
14295
14334
  await this.send("goto", { url, timeoutMs });
14296
14335
  }
@@ -15934,8 +15973,8 @@ class PlanTracker {
15934
15973
  var init_tracker = () => {};
15935
15974
 
15936
15975
  // src/modules/execution/audit-runners.ts
15937
- import { readdirSync as readdirSync8 } from "fs";
15938
- import { join as join23 } from "path";
15976
+ import { existsSync as existsSync28, readdirSync as readdirSync8 } from "fs";
15977
+ import { dirname as dirname10, join as join23, resolve as resolve17 } from "path";
15939
15978
  function findTestFile(dir, depth = 0) {
15940
15979
  if (depth > 5)
15941
15980
  return null;
@@ -15994,7 +16033,7 @@ async function runTests(baseDir) {
15994
16033
  return {
15995
16034
  checked: true,
15996
16035
  passed: entry.exitCode === 0,
15997
- failed: entry.exitCode === 0 ? 0 : -1,
16036
+ failed: entry.exitCode === 0 ? 0 : 1,
15998
16037
  passedCount: 0,
15999
16038
  detail: output.slice(0, 200).trim(),
16000
16039
  command: "bun test"
@@ -16015,6 +16054,25 @@ function parseTypecheckErrors(output) {
16015
16054
  `).find((l) => /error TS\d+/.test(l));
16016
16055
  return line ? line.trim().slice(0, 300) : null;
16017
16056
  }
16057
+ function findTypecheckRoot(baseDir, existingFiles = []) {
16058
+ const candidates = [baseDir, ...existingFiles];
16059
+ let best = null;
16060
+ for (const start of candidates) {
16061
+ let dir = resolve17(start);
16062
+ for (let depth = 0;depth <= 10; depth++) {
16063
+ if (existsSync28(join23(dir, "tsconfig.json"))) {
16064
+ if (!best || depth < best.depth)
16065
+ best = { depth, root: dir };
16066
+ break;
16067
+ }
16068
+ const parent = dirname10(dir);
16069
+ if (parent === dir)
16070
+ break;
16071
+ dir = parent;
16072
+ }
16073
+ }
16074
+ return best?.root ?? null;
16075
+ }
16018
16076
  async function runTypecheck(baseDir) {
16019
16077
  const entry = processRegistry.start("npx --no-install tsc --noEmit --skipLibCheck", baseDir);
16020
16078
  const exited = await processRegistry.waitForExit(entry.id, 90000);
@@ -16045,11 +16103,11 @@ var init_audit_runners = __esm(() => {
16045
16103
  });
16046
16104
 
16047
16105
  // src/modules/execution/auditor.ts
16048
- import { existsSync as existsSync28, readdirSync as readdirSync9 } from "fs";
16049
- import { resolve as resolve17, join as join24, basename as basename2 } from "path";
16106
+ import { existsSync as existsSync29, readdirSync as readdirSync9 } from "fs";
16107
+ import { resolve as resolve18, join as join24, basename as basename2 } from "path";
16050
16108
  function findExistingFile(baseDir, filePath) {
16051
- const direct = resolve17(baseDir, filePath);
16052
- if (existsSync28(direct))
16109
+ const direct = resolve18(baseDir, filePath);
16110
+ if (existsSync29(direct))
16053
16111
  return direct;
16054
16112
  const name = basename2(filePath).toLowerCase();
16055
16113
  const suffix = filePath.replace(/\\/g, "/").toLowerCase();
@@ -16097,8 +16155,9 @@ class Auditor {
16097
16155
  const existingFiles = [];
16098
16156
  const leftoverFiles = [];
16099
16157
  for (const filePath of createFiles) {
16100
- if (findExistingFile(this.baseDir, filePath)) {
16101
- existingFiles.push(filePath);
16158
+ const resolved = findExistingFile(this.baseDir, filePath);
16159
+ if (resolved) {
16160
+ existingFiles.push(resolved);
16102
16161
  } else {
16103
16162
  missingFiles.push(filePath);
16104
16163
  }
@@ -16117,11 +16176,14 @@ class Auditor {
16117
16176
  }
16118
16177
  }
16119
16178
  let typecheckError = null;
16120
- if (missingFiles.length === 0 && leftoverFiles.length === 0 && existsSync28(join24(this.baseDir, "tsconfig.json"))) {
16121
- try {
16122
- typecheckError = await runTypecheck(this.baseDir);
16123
- } catch {
16124
- typecheckError = null;
16179
+ if (missingFiles.length === 0 && leftoverFiles.length === 0) {
16180
+ const root = findTypecheckRoot(this.baseDir, existingFiles);
16181
+ if (root) {
16182
+ try {
16183
+ typecheckError = await runTypecheck(root);
16184
+ } catch {
16185
+ typecheckError = null;
16186
+ }
16125
16187
  }
16126
16188
  }
16127
16189
  const doneSteps = plan.steps.filter((s) => s.status === "done").length;
@@ -16134,7 +16196,7 @@ class Auditor {
16134
16196
  count: String(auditedFiles.length)
16135
16197
  });
16136
16198
  }
16137
- const testsFailing = testRun !== null && testRun.failed > 0;
16199
+ const testsFailing = testRun !== null && !testRun.passed;
16138
16200
  const typecheckFailing = typecheckError !== null;
16139
16201
  const passed = missingFiles.length === 0 && leftoverFiles.length === 0 && !testsFailing && !typecheckFailing;
16140
16202
  const stepsPending = terminalSteps < totalSteps;
@@ -16200,7 +16262,7 @@ var init_auditor = __esm(() => {
16200
16262
  });
16201
16263
 
16202
16264
  // src/modules/execution/plan-store.ts
16203
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync29, readdirSync as readdirSync10, rmSync } from "fs";
16265
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync30, readdirSync as readdirSync10, rmSync } from "fs";
16204
16266
  import { join as join25 } from "path";
16205
16267
  function readPlanFile(path, fallbackBaseDir) {
16206
16268
  try {
@@ -16226,7 +16288,7 @@ function writePlanFile(path, plan) {
16226
16288
  writeFileSync10(path, JSON.stringify(plan, null, 2), "utf-8");
16227
16289
  }
16228
16290
  function listDir(dir, baseDir) {
16229
- if (!existsSync29(dir))
16291
+ if (!existsSync30(dir))
16230
16292
  return [];
16231
16293
  const files = readdirSync10(dir).filter((f) => f.endsWith(".json"));
16232
16294
  return files.map((f) => readPlanFile(join25(dir, f), baseDir)).filter((p) => p !== null);
@@ -16251,7 +16313,7 @@ class PlanStore {
16251
16313
  legacyPath;
16252
16314
  constructor(baseDir) {
16253
16315
  const mmaDir = join25(baseDir, ".mma");
16254
- if (!existsSync29(mmaDir))
16316
+ if (!existsSync30(mmaDir))
16255
16317
  mkdirSync14(mmaDir, { recursive: true });
16256
16318
  this.baseDir = baseDir;
16257
16319
  this.plansDir = join25(mmaDir, "plans");
@@ -16259,7 +16321,7 @@ class PlanStore {
16259
16321
  this.archiveDir = join25(this.plansDir, "archive");
16260
16322
  this.legacyPath = join25(mmaDir, LEGACY_FILE);
16261
16323
  for (const dir of [this.plansDir, this.draftsDir, this.archiveDir]) {
16262
- if (!existsSync29(dir))
16324
+ if (!existsSync30(dir))
16263
16325
  mkdirSync14(dir, { recursive: true });
16264
16326
  }
16265
16327
  }
@@ -16271,12 +16333,12 @@ class PlanStore {
16271
16333
  }
16272
16334
  loadActive() {
16273
16335
  const activePath = this.activePath();
16274
- if (existsSync29(activePath)) {
16336
+ if (existsSync30(activePath)) {
16275
16337
  const plan = readPlanFile(activePath, this.baseDir);
16276
16338
  if (plan)
16277
16339
  return plan;
16278
16340
  }
16279
- if (existsSync29(this.legacyPath)) {
16341
+ if (existsSync30(this.legacyPath)) {
16280
16342
  const legacy = readPlanFile(this.legacyPath, this.baseDir);
16281
16343
  if (legacy) {
16282
16344
  this.saveActive(legacy);
@@ -16290,7 +16352,7 @@ class PlanStore {
16290
16352
  }
16291
16353
  clearActive() {
16292
16354
  const p = this.activePath();
16293
- if (existsSync29(p))
16355
+ if (existsSync30(p))
16294
16356
  rmSync(p, { force: true });
16295
16357
  }
16296
16358
  saveDraft(plan) {
@@ -16298,11 +16360,11 @@ class PlanStore {
16298
16360
  }
16299
16361
  loadDraft(id) {
16300
16362
  const p = join25(this.draftsDir, `${id}.json`);
16301
- return existsSync29(p) ? readPlanFile(p, this.baseDir) : null;
16363
+ return existsSync30(p) ? readPlanFile(p, this.baseDir) : null;
16302
16364
  }
16303
16365
  removeDraft(id) {
16304
16366
  const p = join25(this.draftsDir, `${id}.json`);
16305
- if (existsSync29(p))
16367
+ if (existsSync30(p))
16306
16368
  rmSync(p, { force: true });
16307
16369
  }
16308
16370
  listDrafts() {
@@ -16321,7 +16383,7 @@ class PlanStore {
16321
16383
  }
16322
16384
  removeArchived(id) {
16323
16385
  const p = join25(this.archiveDir, `${id}.json`);
16324
- if (existsSync29(p))
16386
+ if (existsSync30(p))
16325
16387
  rmSync(p, { force: true });
16326
16388
  }
16327
16389
  listAll() {
@@ -17098,8 +17160,8 @@ var init_execution_plugin = __esm(() => {
17098
17160
  });
17099
17161
 
17100
17162
  // src/modules/execution/module.ts
17101
- import { existsSync as existsSync30, readFileSync as readFileSync17 } from "fs";
17102
- import { resolve as resolve18 } from "path";
17163
+ import { existsSync as existsSync31, readFileSync as readFileSync17 } from "fs";
17164
+ import { resolve as resolve19 } from "path";
17103
17165
 
17104
17166
  class ExecutionModule {
17105
17167
  name = "execution";
@@ -17293,7 +17355,7 @@ class ExecutionModule {
17293
17355
  "poetry.lock",
17294
17356
  "requirements.txt"
17295
17357
  ];
17296
- const hasLockFile = lockFiles.some((f) => existsSync30(resolve18(this.baseDir, f)));
17358
+ const hasLockFile = lockFiles.some((f) => existsSync31(resolve19(this.baseDir, f)));
17297
17359
  if (!hasLockFile) {
17298
17360
  if (contextManager) {
17299
17361
  const hints = this.state.depsGateHints.get(step.id) || 0;
@@ -17313,8 +17375,8 @@ class ExecutionModule {
17313
17375
  }
17314
17376
  if (stepPaths.length === 0)
17315
17377
  return;
17316
- const allExist = stepPaths.every((p) => existsSync30(resolve18(this.baseDir, p)));
17317
- const allGone = stepPaths.every((p) => !existsSync30(resolve18(this.baseDir, p)));
17378
+ const allExist = stepPaths.every((p) => existsSync31(resolve19(this.baseDir, p)));
17379
+ const allGone = stepPaths.every((p) => !existsSync31(resolve19(this.baseDir, p)));
17318
17380
  const satisfied = step.kind === "delete" ? allGone && !allExist : allExist;
17319
17381
  if (!satisfied)
17320
17382
  return;
@@ -17322,7 +17384,7 @@ class ExecutionModule {
17322
17384
  const emptyFiles = [];
17323
17385
  for (const p of stepPaths) {
17324
17386
  try {
17325
- const content = readFileSync17(resolve18(this.baseDir, p), "utf-8");
17387
+ const content = readFileSync17(resolve19(this.baseDir, p), "utf-8");
17326
17388
  if (content.trim().length < 10) {
17327
17389
  emptyFiles.push(p);
17328
17390
  }
@@ -17420,7 +17482,7 @@ var init_module = __esm(() => {
17420
17482
  import {
17421
17483
  readFileSync as readFileSync18,
17422
17484
  writeFileSync as writeFileSync11,
17423
- existsSync as existsSync31,
17485
+ existsSync as existsSync32,
17424
17486
  readdirSync as readdirSync11,
17425
17487
  unlinkSync as unlinkSync4
17426
17488
  } from "fs";
@@ -17520,7 +17582,7 @@ class SessionFileEncryptor {
17520
17582
  const files = readdirSync11(sessionDir);
17521
17583
  for (const file of files) {
17522
17584
  const filePath = join26(sessionDir, file);
17523
- if (existsSync31(filePath) && !file.endsWith(".enc")) {
17585
+ if (existsSync32(filePath) && !file.endsWith(".enc")) {
17524
17586
  try {
17525
17587
  const content = readFileSync18(filePath, "utf8");
17526
17588
  const encrypted = this.encryptFileContent(content);
@@ -17561,7 +17623,7 @@ var init_session_encryption = __esm(() => {
17561
17623
 
17562
17624
  // src/modules/session/store.ts
17563
17625
  import {
17564
- existsSync as existsSync32,
17626
+ existsSync as existsSync33,
17565
17627
  mkdirSync as mkdirSync15,
17566
17628
  readdirSync as readdirSync12,
17567
17629
  readFileSync as readFileSync19,
@@ -17611,7 +17673,7 @@ class SessionStore {
17611
17673
  return join27(this.sessionDir(id), "session.jsonl");
17612
17674
  }
17613
17675
  sessionExists(id) {
17614
- return existsSync32(this.metaPath(id));
17676
+ return existsSync33(this.metaPath(id));
17615
17677
  }
17616
17678
  saveMeta(id, meta) {
17617
17679
  this._metaCache.set(id, meta);
@@ -17629,7 +17691,7 @@ class SessionStore {
17629
17691
  if (cached)
17630
17692
  return cached;
17631
17693
  const path = this.metaPath(id);
17632
- if (!existsSync32(path))
17694
+ if (!existsSync33(path))
17633
17695
  return null;
17634
17696
  try {
17635
17697
  const raw = readFileSync19(path, "utf-8");
@@ -17661,7 +17723,7 @@ class SessionStore {
17661
17723
  }
17662
17724
  loadHistory(id) {
17663
17725
  const path = this.historyPath(id);
17664
- if (!existsSync32(path))
17726
+ if (!existsSync33(path))
17665
17727
  return [];
17666
17728
  try {
17667
17729
  const raw = readFileSync19(path, "utf-8");
@@ -17702,7 +17764,7 @@ class SessionStore {
17702
17764
  }
17703
17765
  loadSessionLog(id) {
17704
17766
  const path = this.sessionLogPath(id);
17705
- if (!existsSync32(path))
17767
+ if (!existsSync33(path))
17706
17768
  return [];
17707
17769
  try {
17708
17770
  const raw = readFileSync19(path, "utf-8");
@@ -17730,7 +17792,7 @@ class SessionStore {
17730
17792
  }
17731
17793
  }
17732
17794
  listSessions() {
17733
- if (!existsSync32(this.baseDir))
17795
+ if (!existsSync33(this.baseDir))
17734
17796
  return [];
17735
17797
  const entries = readdirSync12(this.baseDir, { withFileTypes: true });
17736
17798
  const sessions = [];
@@ -17747,7 +17809,7 @@ class SessionStore {
17747
17809
  deleteSession(id) {
17748
17810
  this._metaCache.delete(id);
17749
17811
  const dir = this.sessionDir(id);
17750
- if (existsSync32(dir)) {
17812
+ if (existsSync33(dir)) {
17751
17813
  rmSync2(dir, { recursive: true, force: true });
17752
17814
  }
17753
17815
  }
@@ -17759,7 +17821,7 @@ class SessionStore {
17759
17821
  const updatedAt = new Date(session2.updatedAt);
17760
17822
  if (updatedAt < thirtyDaysAgo) {
17761
17823
  const historyPath = this.historyPath(session2.id);
17762
- if (existsSync32(historyPath)) {
17824
+ if (existsSync33(historyPath)) {
17763
17825
  const content = readFileSync19(historyPath, "utf-8");
17764
17826
  const compressed = gzipSync(content);
17765
17827
  const gzPath = join27(this.baseDir, `${session2.id}.jsonl.gz`);
@@ -17972,7 +18034,7 @@ class ProfileCompressor {
17972
18034
  }
17973
18035
 
17974
18036
  // src/modules/user-profile/profile.ts
17975
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync33, mkdirSync as mkdirSync16 } from "fs";
18037
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync34, mkdirSync as mkdirSync16 } from "fs";
17976
18038
  import { join as join28 } from "path";
17977
18039
  import { homedir as homedir9, hostname, platform as platform5, type } from "os";
17978
18040
  import { env } from "process";
@@ -17997,14 +18059,14 @@ class UserProfile {
17997
18059
  return this.info;
17998
18060
  }
17999
18061
  save() {
18000
- if (!existsSync33(this.profileDir)) {
18062
+ if (!existsSync34(this.profileDir)) {
18001
18063
  mkdirSync16(this.profileDir, { recursive: true });
18002
18064
  }
18003
18065
  writeFileSync13(join28(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
18004
18066
  }
18005
18067
  load() {
18006
18068
  const path = join28(this.profileDir, "profile.json");
18007
- if (!existsSync33(path))
18069
+ if (!existsSync34(path))
18008
18070
  return null;
18009
18071
  try {
18010
18072
  const data = JSON.parse(readFileSync20(path, "utf-8"));
@@ -18042,12 +18104,12 @@ class UserProfile {
18042
18104
  var init_profile = () => {};
18043
18105
 
18044
18106
  // src/modules/skills/loader.ts
18045
- import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as existsSync34, statSync as statSync6 } from "fs";
18107
+ import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as existsSync35, statSync as statSync6 } from "fs";
18046
18108
  import { join as join29 } from "path";
18047
18109
 
18048
18110
  class SkillsLoader {
18049
18111
  loadFromDir(dirPath) {
18050
- if (!existsSync34(dirPath))
18112
+ if (!existsSync35(dirPath))
18051
18113
  return [];
18052
18114
  const skills = [];
18053
18115
  this.scanDir(dirPath, skills);
@@ -18301,7 +18363,7 @@ var init_browser2 = __esm(() => {
18301
18363
 
18302
18364
  // src/modules/lsp/command.ts
18303
18365
  import { delimiter, join as join30 } from "path";
18304
- import { existsSync as existsSync35 } from "fs";
18366
+ import { existsSync as existsSync36 } from "fs";
18305
18367
  import { platform as platform6 } from "os";
18306
18368
  function resolveSpawnCommand(command, platformName = platform6(), pathEnv = process.env.PATH ?? "") {
18307
18369
  if (platformName !== "win32")
@@ -18313,7 +18375,7 @@ function resolveSpawnCommand(command, platformName = platform6(), pathEnv = proc
18313
18375
  for (const dir of dirs) {
18314
18376
  for (const ext of WIN_EXTS) {
18315
18377
  const candidate = join30(dir, `${command}${ext}`);
18316
- if (existsSync35(candidate))
18378
+ if (existsSync36(candidate))
18317
18379
  return `${command}${ext}`;
18318
18380
  }
18319
18381
  }
@@ -18335,11 +18397,8 @@ var init_command = __esm(() => {
18335
18397
  });
18336
18398
 
18337
18399
  // src/modules/lsp/client.ts
18338
- import {
18339
- spawn as spawn6,
18340
- execSync as execSync2
18341
- } from "child_process";
18342
- import { resolve as resolve19 } from "path";
18400
+ import { spawn as spawn6, execSync as execSync2 } from "child_process";
18401
+ import { resolve as resolve20 } from "path";
18343
18402
  import { platform as platform7 } from "os";
18344
18403
 
18345
18404
  class LspClient {
@@ -18357,25 +18416,32 @@ class LspClient {
18357
18416
  try {
18358
18417
  await this.startServer(config, projectRoot);
18359
18418
  const rootUri = this.pathToUri(projectRoot);
18360
- const initResult = await this.sendRequest("initialize", {
18419
+ const initParams = {
18361
18420
  processId: process.pid,
18362
18421
  rootUri,
18363
18422
  workspaceFolders: [{ uri: rootUri, name: "workspace" }],
18364
18423
  capabilities: { textDocument: { publishDiagnostics: {} } }
18365
- }, timeout);
18424
+ };
18425
+ try {
18426
+ await this.sendRequest("initialize", initParams, timeout);
18427
+ } catch (e) {
18428
+ if (!(e instanceof Error) || !e.message.includes("initialize"))
18429
+ throw e;
18430
+ await this.shutdown();
18431
+ await this.startServer(config, projectRoot);
18432
+ await this.sendRequest("initialize", initParams, timeout);
18433
+ }
18366
18434
  this.initialized = true;
18367
18435
  this.sendNotification("initialized", {});
18368
- const uri = this.pathToUri(resolve19(filePath));
18436
+ const uri = this.pathToUri(resolve20(filePath));
18369
18437
  const fs2 = await import("fs");
18370
18438
  const content = fs2.readFileSync(filePath, "utf-8");
18371
- const diagPromise = new Promise((resolve20) => {
18372
- this.diagnosticsResolve = resolve20;
18439
+ const diagPromise = new Promise((resolve21) => {
18440
+ this.diagnosticsResolve = resolve21;
18373
18441
  this.diagnostics = [];
18374
18442
  this.diagnosticsTimer = setTimeout(() => {
18375
- if (this.diagnosticsResolve) {
18376
- this.diagnosticsResolve([]);
18377
- this.diagnosticsResolve = null;
18378
- }
18443
+ this.diagnosticsResolve?.([]);
18444
+ this.diagnosticsResolve = null;
18379
18445
  }, timeout);
18380
18446
  });
18381
18447
  this.sendNotification("textDocument/didOpen", {
@@ -18401,7 +18467,7 @@ class LspClient {
18401
18467
  throw new Error(`${config.command} not found in PATH`);
18402
18468
  }
18403
18469
  }
18404
- return new Promise((resolve20, reject) => {
18470
+ return new Promise((resolve21, reject) => {
18405
18471
  const args = config.args ?? [];
18406
18472
  const isWin = platform7() === "win32";
18407
18473
  let spawnCommand = resolveSpawnCommand(config.command);
@@ -18423,13 +18489,12 @@ class LspClient {
18423
18489
  });
18424
18490
  proc.stderr.on("data", () => {});
18425
18491
  proc.once("spawn", () => {
18426
- resolve20();
18492
+ resolve21();
18427
18493
  });
18428
18494
  this.process = proc;
18429
18495
  setTimeout(() => {
18430
- if (!this.initialized && this.process) {
18496
+ if (!this.initialized && this.process)
18431
18497
  reject(new Error("LSP server start timeout"));
18432
- }
18433
18498
  }, config.timeout ?? 1e4);
18434
18499
  });
18435
18500
  }
@@ -18480,10 +18545,8 @@ class LspClient {
18480
18545
  clearTimeout(this.diagnosticsTimer);
18481
18546
  this.diagnosticsTimer = null;
18482
18547
  }
18483
- if (this.diagnosticsResolve) {
18484
- this.diagnosticsResolve(this.diagnostics);
18485
- this.diagnosticsResolve = null;
18486
- }
18548
+ this.diagnosticsResolve?.(this.diagnostics);
18549
+ this.diagnosticsResolve = null;
18487
18550
  }
18488
18551
  return;
18489
18552
  }
@@ -18500,9 +18563,9 @@ class LspClient {
18500
18563
  }
18501
18564
  }
18502
18565
  sendRequest(method, params, timeout) {
18503
- return new Promise((resolve20, reject) => {
18566
+ return new Promise((resolve21, reject) => {
18504
18567
  const id = ++this.requestId;
18505
- this.pending.set(id, { resolve: resolve20, reject });
18568
+ this.pending.set(id, { resolve: resolve21, reject });
18506
18569
  const message = JSON.stringify({ jsonrpc: "2.0", id, method, params });
18507
18570
  this.write(message);
18508
18571
  setTimeout(() => {
@@ -18542,6 +18605,8 @@ class LspClient {
18542
18605
  this.process = null;
18543
18606
  }
18544
18607
  this.initialized = false;
18608
+ this.buffer = "";
18609
+ this.contentLength = -1;
18545
18610
  if (this.diagnosticsTimer) {
18546
18611
  clearTimeout(this.diagnosticsTimer);
18547
18612
  this.diagnosticsTimer = null;
@@ -18550,10 +18615,7 @@ class LspClient {
18550
18615
  }
18551
18616
  pathToUri(filePath) {
18552
18617
  const normalized = filePath.replace(/\\/g, "/");
18553
- if (/^[a-zA-Z]:/.test(normalized)) {
18554
- return `file:///${normalized}`;
18555
- }
18556
- return `file://${normalized}`;
18618
+ return /^[a-zA-Z]:/.test(normalized) ? `file:///${normalized}` : `file://${normalized}`;
18557
18619
  }
18558
18620
  languageFromPath(filePath) {
18559
18621
  const ext = filePath.split(".").pop()?.toLowerCase();
@@ -18582,20 +18644,26 @@ var init_client2 = __esm(() => {
18582
18644
  });
18583
18645
 
18584
18646
  // src/modules/lsp/module.ts
18585
- import { existsSync as existsSync36 } from "fs";
18586
- import { resolve as resolve20 } from "path";
18647
+ import { existsSync as existsSync37 } from "fs";
18648
+ import { resolve as resolve21 } from "path";
18587
18649
 
18588
18650
  class LspModule {
18589
18651
  name = "lsp";
18590
18652
  config;
18591
18653
  client = new LspClient;
18592
- consecutiveFailures = 0;
18593
- lspDisabled = false;
18654
+ failuresByServer = new Map;
18655
+ disabledServers = new Set;
18594
18656
  constructor(config) {
18595
18657
  this.config = { ...DEFAULT_LSP_CONFIG, ...config };
18596
18658
  }
18597
18659
  isLspDisabled() {
18598
- return this.lspDisabled;
18660
+ return this.disabledServers.size > 0;
18661
+ }
18662
+ isServerDisabled(key) {
18663
+ return this.disabledServers.has(key);
18664
+ }
18665
+ serverKey(server) {
18666
+ return `${server.command}:${(server.args ?? []).join(" ")}`;
18599
18667
  }
18600
18668
  getPlugin() {
18601
18669
  const self = this;
@@ -18605,8 +18673,6 @@ class LspModule {
18605
18673
  onAfterTool: async (_ctx, call, result) => {
18606
18674
  if (!self.config.enabled)
18607
18675
  return;
18608
- if (self.lspDisabled)
18609
- return;
18610
18676
  if (call.name !== "write_file" && call.name !== "edit_file")
18611
18677
  return;
18612
18678
  if (!result.success)
@@ -18614,16 +18680,19 @@ class LspModule {
18614
18680
  const filePath = String(call.arguments.path ?? "");
18615
18681
  if (!filePath)
18616
18682
  return;
18617
- const fullPath = resolve20(_ctx.baseDir, filePath);
18618
- if (!existsSync36(fullPath))
18683
+ const fullPath = resolve21(_ctx.baseDir, filePath);
18684
+ if (!existsSync37(fullPath))
18619
18685
  return;
18620
18686
  const serverConfig = getServerForFile(fullPath, self.config);
18621
18687
  if (!serverConfig)
18622
18688
  return;
18689
+ const key = self.serverKey(serverConfig);
18690
+ if (self.disabledServers.has(key))
18691
+ return;
18623
18692
  const projectRoot = findProjectRoot(fullPath, _ctx.baseDir, serverConfig.workspaceMarkers ?? []);
18624
18693
  try {
18625
18694
  const diagnostics = await self.client.checkFile(fullPath, _ctx.baseDir, serverConfig, projectRoot);
18626
- self.consecutiveFailures = 0;
18695
+ self.failuresByServer.set(key, 0);
18627
18696
  const errors = diagnostics.filter((d) => d.severity === 1);
18628
18697
  const warnings = diagnostics.filter((d) => d.severity === 2);
18629
18698
  if (errors.length > 0) {
@@ -18642,12 +18711,13 @@ ${items}`;
18642
18711
  }
18643
18712
  } catch (e) {
18644
18713
  const msg = e instanceof Error ? e.message : String(e);
18645
- self.consecutiveFailures++;
18714
+ const failures = (self.failuresByServer.get(key) ?? 0) + 1;
18715
+ self.failuresByServer.set(key, failures);
18646
18716
  try {
18647
18717
  _ctx.logger?.warn(`LSP check failed for ${filePath}: ${msg}`);
18648
18718
  } catch {}
18649
- if (self.consecutiveFailures >= MAX_CONSECUTIVE_LSP_FAILURES) {
18650
- self.lspDisabled = true;
18719
+ if (failures >= MAX_CONSECUTIVE_LSP_FAILURES) {
18720
+ self.disabledServers.add(key);
18651
18721
  result.output += `
18652
18722
 
18653
18723
  [LSP disabled: ${t("lsp.unavailable")}]`;
@@ -18693,7 +18763,7 @@ var init_lsp = __esm(() => {
18693
18763
  });
18694
18764
 
18695
18765
  // src/modules/indexer/walker.ts
18696
- import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync37, watch } from "fs";
18766
+ import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync38, watch } from "fs";
18697
18767
  import { join as join31, relative as relative2, extname as extname5 } from "path";
18698
18768
 
18699
18769
  class Indexer {
@@ -18721,7 +18791,7 @@ class Indexer {
18721
18791
  let totalSize = 0;
18722
18792
  let count = 0;
18723
18793
  const walkDir = (dir) => {
18724
- if (!existsSync37(dir))
18794
+ if (!existsSync38(dir))
18725
18795
  return;
18726
18796
  let entries;
18727
18797
  try {
@@ -18795,7 +18865,7 @@ var init_walker = __esm(() => {
18795
18865
  });
18796
18866
 
18797
18867
  // src/modules/indexer/cache.ts
18798
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync38, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
18868
+ import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync39, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
18799
18869
  import { join as join32 } from "path";
18800
18870
 
18801
18871
  class IndexCache {
@@ -18807,7 +18877,7 @@ class IndexCache {
18807
18877
  load() {
18808
18878
  if (this.cache)
18809
18879
  return this.cache;
18810
- if (!existsSync38(this.cachePath))
18880
+ if (!existsSync39(this.cachePath))
18811
18881
  return null;
18812
18882
  try {
18813
18883
  this.cache = JSON.parse(readFileSync23(this.cachePath, "utf-8"));
@@ -18819,13 +18889,13 @@ class IndexCache {
18819
18889
  save(result) {
18820
18890
  this.cache = result;
18821
18891
  const dir = join32(this.cachePath, "..");
18822
- if (!existsSync38(dir))
18892
+ if (!existsSync39(dir))
18823
18893
  mkdirSync17(dir, { recursive: true });
18824
18894
  writeFileSync14(this.cachePath, JSON.stringify(result), "utf-8");
18825
18895
  }
18826
18896
  invalidate() {
18827
18897
  this.cache = null;
18828
- if (existsSync38(this.cachePath)) {
18898
+ if (existsSync39(this.cachePath)) {
18829
18899
  try {
18830
18900
  rmSync3(this.cachePath);
18831
18901
  } catch {}
@@ -18835,11 +18905,11 @@ class IndexCache {
18835
18905
  var init_cache = () => {};
18836
18906
 
18837
18907
  // src/modules/indexer/project-profile.ts
18838
- import { readFileSync as readFileSync24, existsSync as existsSync39 } from "fs";
18908
+ import { readFileSync as readFileSync24, existsSync as existsSync40 } from "fs";
18839
18909
  import { join as join33 } from "path";
18840
18910
  function detectManifest(baseDir) {
18841
18911
  for (const manifest of MANIFEST_ORDER) {
18842
- if (existsSync39(join33(baseDir, manifest)))
18912
+ if (existsSync40(join33(baseDir, manifest)))
18843
18913
  return manifest;
18844
18914
  }
18845
18915
  return null;
@@ -19003,7 +19073,7 @@ var init_project_profile = __esm(() => {
19003
19073
  });
19004
19074
 
19005
19075
  // src/modules/indexer/module.ts
19006
- import { dirname as dirname11 } from "path";
19076
+ import { dirname as dirname12 } from "path";
19007
19077
 
19008
19078
  class IndexerModule {
19009
19079
  name = "indexer";
@@ -19154,7 +19224,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
19154
19224
  const counts = {};
19155
19225
  for (const f of result.files) {
19156
19226
  const normalized = f.path.replace(/\\/g, "/");
19157
- const dir = dirname11(normalized);
19227
+ const dir = dirname12(normalized);
19158
19228
  const key = dir === "." ? "(root)" : dir;
19159
19229
  counts[key] = (counts[key] || 0) + 1;
19160
19230
  }
@@ -19493,8 +19563,8 @@ __export(exports_bootstrap, {
19493
19563
  bootstrap: () => bootstrap
19494
19564
  });
19495
19565
  import { homedir as homedir11 } from "os";
19496
- import { join as join35, resolve as resolve21 } from "path";
19497
- import { existsSync as existsSync40, readFileSync as readFileSync25, writeFileSync as writeFileSync15 } from "fs";
19566
+ import { join as join35, resolve as resolve22 } from "path";
19567
+ import { existsSync as existsSync41, readFileSync as readFileSync25, writeFileSync as writeFileSync15 } from "fs";
19498
19568
  function buildSystemInfo(config, baseDir, profileCompressed) {
19499
19569
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
19500
19570
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -19564,7 +19634,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
19564
19634
  retry: config.retry,
19565
19635
  rateLimits: config.security?.rateLimits
19566
19636
  });
19567
- const baseDir = projectDir ? resolve21(projectDir) : process.cwd();
19637
+ const baseDir = projectDir ? resolve22(projectDir) : process.cwd();
19568
19638
  const projectMapCacheDir = join35(baseDir, ".mma");
19569
19639
  const indexerModule = new IndexerModule({
19570
19640
  baseDir,
@@ -19593,7 +19663,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
19593
19663
  estimatedTokens: Math.ceil(systemInfoContent.length / 4)
19594
19664
  };
19595
19665
  const agentsMdGlobal = join35(dir, "AGENTS.md");
19596
- if (!existsSync40(agentsMdGlobal)) {
19666
+ if (!existsSync41(agentsMdGlobal)) {
19597
19667
  writeFileSync15(agentsMdGlobal, "", "utf-8");
19598
19668
  }
19599
19669
  const sessionDir = join35(dir, "sessions");
@@ -19738,7 +19808,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
19738
19808
  join35(dir, "AGENTS.md")
19739
19809
  ];
19740
19810
  for (const p of agentsMdCandidates) {
19741
- if (existsSync40(p)) {
19811
+ if (existsSync41(p)) {
19742
19812
  const content = readFileSync25(p, "utf-8").trim();
19743
19813
  if (content) {
19744
19814
  agentsMdBlocks.push({
@@ -20371,10 +20441,10 @@ function menuList(items) {
20371
20441
  console.log(l);
20372
20442
  }
20373
20443
  function ask(rl, question, defaultValue) {
20374
- return new Promise((resolve22) => {
20444
+ return new Promise((resolve23) => {
20375
20445
  const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
20376
20446
  rl.question(prompt, (answer) => {
20377
- resolve22(answer.trim() || defaultValue || "");
20447
+ resolve23(answer.trim() || defaultValue || "");
20378
20448
  });
20379
20449
  });
20380
20450
  }
@@ -20593,12 +20663,12 @@ __export(exports_manifest, {
20593
20663
  getCertMark: () => getCertMark,
20594
20664
  MANIFEST_PATH: () => MANIFEST_PATH
20595
20665
  });
20596
- import { existsSync as existsSync41, readFileSync as readFileSync26, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
20666
+ import { existsSync as existsSync42, readFileSync as readFileSync26, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
20597
20667
  import { homedir as homedir13 } from "os";
20598
20668
  import { join as join37 } from "path";
20599
20669
  function readManifest(path = MANIFEST_PATH) {
20600
20670
  try {
20601
- if (existsSync41(path)) {
20671
+ if (existsSync42(path)) {
20602
20672
  const raw = JSON.parse(readFileSync26(path, "utf-8"));
20603
20673
  return { version: 1, certifications: raw.certifications ?? [] };
20604
20674
  }
@@ -27764,7 +27834,7 @@ var init_scenarios = __esm(() => {
27764
27834
  });
27765
27835
 
27766
27836
  // src/modules/certification/loader.ts
27767
- import { existsSync as existsSync42, readdirSync as readdirSync15, readFileSync as readFileSync27 } from "fs";
27837
+ import { existsSync as existsSync43, readdirSync as readdirSync15, readFileSync as readFileSync27 } from "fs";
27768
27838
  import { join as join38 } from "path";
27769
27839
  function validateScenario(s) {
27770
27840
  const errors2 = [];
@@ -27814,7 +27884,7 @@ function loadScenarios(userDir) {
27814
27884
  else
27815
27885
  scenarios.push(s);
27816
27886
  }
27817
- if (userDir && existsSync42(userDir)) {
27887
+ if (userDir && existsSync43(userDir)) {
27818
27888
  for (const file of readdirSync15(userDir)) {
27819
27889
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
27820
27890
  continue;
@@ -27872,7 +27942,7 @@ var init_loader3 = __esm(() => {
27872
27942
  });
27873
27943
 
27874
27944
  // src/modules/certification/fact-checker.ts
27875
- import { existsSync as existsSync43, readFileSync as readFileSync28, statSync as statSync8 } from "fs";
27945
+ import { existsSync as existsSync44, readFileSync as readFileSync28, statSync as statSync8 } from "fs";
27876
27946
  import { join as join39 } from "path";
27877
27947
  function checkSandbox(sandboxDir, checks, exitCode, output) {
27878
27948
  const failures = [];
@@ -27892,7 +27962,7 @@ function runCheck(sandboxDir, check, exitCode, output) {
27892
27962
  case "fileExists":
27893
27963
  return isFile(join39(sandboxDir, check.path));
27894
27964
  case "fileNotExists":
27895
- return !existsSync43(join39(sandboxDir, check.path));
27965
+ return !existsSync44(join39(sandboxDir, check.path));
27896
27966
  case "dirExists":
27897
27967
  return isDir(join39(sandboxDir, check.path));
27898
27968
  case "fileContent": {
@@ -27918,14 +27988,14 @@ function runCheck(sandboxDir, check, exitCode, output) {
27918
27988
  }
27919
27989
  function isFile(p) {
27920
27990
  try {
27921
- return existsSync43(p) && statSync8(p).isFile();
27991
+ return existsSync44(p) && statSync8(p).isFile();
27922
27992
  } catch {
27923
27993
  return false;
27924
27994
  }
27925
27995
  }
27926
27996
  function isDir(p) {
27927
27997
  try {
27928
- return existsSync43(p) && statSync8(p).isDirectory();
27998
+ return existsSync44(p) && statSync8(p).isDirectory();
27929
27999
  } catch {
27930
28000
  return false;
27931
28001
  }
@@ -27956,9 +28026,9 @@ var init_fact_checker = () => {};
27956
28026
 
27957
28027
  // src/modules/certification/runner.ts
27958
28028
  import { spawn as spawn7 } from "child_process";
27959
- import { existsSync as existsSync44, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
28029
+ import { existsSync as existsSync45, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
27960
28030
  import { platform as platform8 } from "os";
27961
- import { join as join40, resolve as resolve22, dirname as dirname12 } from "path";
28031
+ import { join as join40, resolve as resolve23, dirname as dirname13 } from "path";
27962
28032
  async function runScenario(scenario, opts) {
27963
28033
  if (scenario.mode === "skip") {
27964
28034
  return {
@@ -28039,27 +28109,27 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
28039
28109
  mkdirSync19(sandbox, { recursive: true });
28040
28110
  for (const f of scenario.fixtures ?? []) {
28041
28111
  const src = join40(mmaRoot, f.source);
28042
- if (!existsSync44(src)) {
28112
+ if (!existsSync45(src)) {
28043
28113
  throw new Error(`fixture missing: ${f.source}`);
28044
28114
  }
28045
28115
  const dest = join40(sandbox, f.dest);
28046
- mkdirSync19(dirname12(dest), { recursive: true });
28116
+ mkdirSync19(dirname13(dest), { recursive: true });
28047
28117
  cpSync2(src, dest);
28048
28118
  }
28049
28119
  }
28050
28120
  function resolveMmaEntry(mmaRoot) {
28051
28121
  const dev = join40(mmaRoot, "src", "cli", "main.ts");
28052
- if (existsSync44(dev))
28122
+ if (existsSync45(dev))
28053
28123
  return dev;
28054
28124
  return join40(mmaRoot, "dist", "main.js");
28055
28125
  }
28056
28126
  function findMmaRoot(fromDir) {
28057
28127
  const candidates = [
28058
- resolve22(fromDir, "..", "..", ".."),
28059
- resolve22(fromDir, "..")
28128
+ resolve23(fromDir, "..", "..", ".."),
28129
+ resolve23(fromDir, "..")
28060
28130
  ];
28061
28131
  for (const c of candidates) {
28062
- if (existsSync44(join40(c, "package.json")))
28132
+ if (existsSync45(join40(c, "package.json")))
28063
28133
  return c;
28064
28134
  }
28065
28135
  return process.cwd();
@@ -28127,13 +28197,13 @@ __export(exports_cli, {
28127
28197
  });
28128
28198
  import { rmSync as rmSync5 } from "fs";
28129
28199
  import { homedir as homedir14 } from "os";
28130
- import { join as join41, dirname as dirname13 } from "path";
28200
+ import { join as join41, dirname as dirname14 } from "path";
28131
28201
  import { fileURLToPath as fileURLToPath2 } from "url";
28132
- import { existsSync as existsSync45, readFileSync as readFileSync29 } from "fs";
28202
+ import { existsSync as existsSync46, readFileSync as readFileSync29 } from "fs";
28133
28203
  function readVersion() {
28134
28204
  const candidates = [join41(MMA_ROOT, "package.json")];
28135
28205
  for (const p of candidates) {
28136
- if (existsSync45(p)) {
28206
+ if (existsSync46(p)) {
28137
28207
  try {
28138
28208
  const raw = JSON.parse(readFileSync29(p, "utf-8"));
28139
28209
  if (raw.version)
@@ -28283,7 +28353,7 @@ var init_cli = __esm(() => {
28283
28353
  init_loader3();
28284
28354
  init_runner2();
28285
28355
  init_manifest();
28286
- HERE = dirname13(fileURLToPath2(import.meta.url));
28356
+ HERE = dirname14(fileURLToPath2(import.meta.url));
28287
28357
  MMA_ROOT = findMmaRoot(HERE);
28288
28358
  USER_SCENARIO_DIR = join41(homedir14(), ".mma", "certification", "scenarios");
28289
28359
  });
@@ -28294,18 +28364,18 @@ __export(exports_repl_commands, {
28294
28364
  registerAllCommands: () => registerAllCommands,
28295
28365
  COMMAND_GROUPS: () => COMMAND_GROUPS
28296
28366
  });
28297
- import { join as join43, dirname as dirname15 } from "path";
28367
+ import { join as join43, dirname as dirname16 } from "path";
28298
28368
  import { homedir as homedir16 } from "os";
28299
- import { existsSync as existsSync47, readFileSync as readFileSync31 } from "fs";
28369
+ import { existsSync as existsSync48, readFileSync as readFileSync31 } from "fs";
28300
28370
  import { fileURLToPath as fileURLToPath4 } from "url";
28301
28371
  function readVersion3() {
28302
- const here = dirname15(fileURLToPath4(import.meta.url));
28372
+ const here = dirname16(fileURLToPath4(import.meta.url));
28303
28373
  const candidates = [
28304
28374
  join43(here, "..", "..", "package.json"),
28305
28375
  join43(here, "..", "package.json")
28306
28376
  ];
28307
28377
  for (const p of candidates) {
28308
- if (existsSync47(p)) {
28378
+ if (existsSync48(p)) {
28309
28379
  try {
28310
28380
  const raw = JSON.parse(readFileSync31(p, "utf8"));
28311
28381
  if (raw.version)
@@ -28371,8 +28441,8 @@ function registerMmaCommands(ctx) {
28371
28441
  }
28372
28442
  try {
28373
28443
  const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
28374
- const { existsSync: existsSync48 } = await import("fs");
28375
- const { resolve: resolve23 } = await import("path");
28444
+ const { existsSync: existsSync49 } = await import("fs");
28445
+ const { resolve: resolve24 } = await import("path");
28376
28446
  let dataUrl;
28377
28447
  let label;
28378
28448
  if (source.toLowerCase() === "clipboard") {
@@ -28390,8 +28460,8 @@ function registerMmaCommands(ctx) {
28390
28460
  dataUrl = result.dataUrl;
28391
28461
  label = source;
28392
28462
  } else {
28393
- const absPath = resolve23(process.cwd(), source);
28394
- if (!existsSync48(absPath)) {
28463
+ const absPath = resolve24(process.cwd(), source);
28464
+ if (!existsSync49(absPath)) {
28395
28465
  console.log(pc2.red(t("image.not_found", { path: source })));
28396
28466
  return;
28397
28467
  }
@@ -28927,9 +28997,9 @@ init_bootstrap();
28927
28997
  init_config2();
28928
28998
  init_setup();
28929
28999
  init_i18n();
28930
- import { join as join42, dirname as dirname14 } from "path";
29000
+ import { join as join42, dirname as dirname15 } from "path";
28931
29001
  import { homedir as homedir15 } from "os";
28932
- import { existsSync as existsSync46, readFileSync as readFileSync30 } from "fs";
29002
+ import { existsSync as existsSync47, readFileSync as readFileSync30 } from "fs";
28933
29003
 
28934
29004
  // src/cli/security-commands.ts
28935
29005
  init_bootstrap();
@@ -29551,13 +29621,13 @@ function createSecurityCommand(program2) {
29551
29621
  // src/cli/commands.ts
29552
29622
  import { fileURLToPath as fileURLToPath3 } from "url";
29553
29623
  function readVersion2() {
29554
- const here = dirname14(fileURLToPath3(import.meta.url));
29624
+ const here = dirname15(fileURLToPath3(import.meta.url));
29555
29625
  const candidates = [
29556
29626
  join42(here, "..", "..", "package.json"),
29557
29627
  join42(here, "..", "package.json")
29558
29628
  ];
29559
29629
  for (const p of candidates) {
29560
- if (existsSync46(p)) {
29630
+ if (existsSync47(p)) {
29561
29631
  try {
29562
29632
  const raw = JSON.parse(readFileSync30(p, "utf8"));
29563
29633
  if (raw.version)
@@ -30504,8 +30574,8 @@ class LineEditor {
30504
30574
  }
30505
30575
 
30506
30576
  // src/cli/repl.ts
30507
- import { existsSync as existsSync48, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
30508
- import { join as join44, dirname as dirname16 } from "path";
30577
+ import { existsSync as existsSync49, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
30578
+ import { join as join44, dirname as dirname17 } from "path";
30509
30579
  import { homedir as homedir17 } from "os";
30510
30580
  import { fileURLToPath as fileURLToPath5 } from "url";
30511
30581
 
@@ -31009,13 +31079,13 @@ init_box();
31009
31079
  init_i18n();
31010
31080
  init_repl_commands();
31011
31081
  function readVersion4() {
31012
- const here = dirname16(fileURLToPath5(import.meta.url));
31082
+ const here = dirname17(fileURLToPath5(import.meta.url));
31013
31083
  const candidates = [
31014
31084
  join44(here, "..", "..", "package.json"),
31015
31085
  join44(here, "..", "package.json")
31016
31086
  ];
31017
31087
  for (const p of candidates) {
31018
- if (existsSync48(p)) {
31088
+ if (existsSync49(p)) {
31019
31089
  try {
31020
31090
  const raw = JSON.parse(readFileSync32(p, "utf8"));
31021
31091
  if (raw.version)
@@ -31109,7 +31179,7 @@ class Repl {
31109
31179
  this.setupListeners();
31110
31180
  }
31111
31181
  loadHistory() {
31112
- if (existsSync48(this.historyPath)) {
31182
+ if (existsSync49(this.historyPath)) {
31113
31183
  try {
31114
31184
  const raw = readFileSync32(this.historyPath, "utf-8");
31115
31185
  this.history = raw.split(`
@@ -31472,7 +31542,7 @@ ${t("image.clipboard_empty")}`));
31472
31542
  join44(this.baseDir, ".mma", "AGENTS.md"),
31473
31543
  join44(this.configDir, "AGENTS.md")
31474
31544
  ];
31475
- const foundAgents = agentsMdCandidates.filter((p) => existsSync48(p));
31545
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync49(p));
31476
31546
  if (foundAgents.length > 0) {
31477
31547
  for (const p of foundAgents) {
31478
31548
  row(t("repl.agents_label"), pc2.dim(p));
@@ -31524,8 +31594,8 @@ init_setup();
31524
31594
  init_config2();
31525
31595
  init_i18n();
31526
31596
  init_colors();
31527
- import { existsSync as existsSync49, readFileSync as readFileSync33 } from "fs";
31528
- import { join as join45, dirname as dirname17 } from "path";
31597
+ import { existsSync as existsSync50, readFileSync as readFileSync33 } from "fs";
31598
+ import { join as join45, dirname as dirname18 } from "path";
31529
31599
  import { homedir as homedir18 } from "os";
31530
31600
  import { fileURLToPath as fileURLToPath6 } from "url";
31531
31601
 
@@ -31534,8 +31604,8 @@ init_command();
31534
31604
  import { platform as platform9 } from "os";
31535
31605
  var defaultRunner2 = async (command, args, options) => {
31536
31606
  const { execFile } = await import("child_process");
31537
- return new Promise((resolve23) => {
31538
- execFile(command, args, options, (err) => resolve23({ error: err?.message }));
31607
+ return new Promise((resolve24) => {
31608
+ execFile(command, args, options, (err) => resolve24({ error: err?.message }));
31539
31609
  });
31540
31610
  };
31541
31611
 
@@ -31687,13 +31757,13 @@ class UpdaterModule {
31687
31757
  }
31688
31758
  // src/cli/main.ts
31689
31759
  function readVersion5() {
31690
- const here = dirname17(fileURLToPath6(import.meta.url));
31760
+ const here = dirname18(fileURLToPath6(import.meta.url));
31691
31761
  const candidates = [
31692
31762
  join45(here, "..", "..", "package.json"),
31693
31763
  join45(here, "..", "package.json")
31694
31764
  ];
31695
31765
  for (const p of candidates) {
31696
- if (existsSync49(p)) {
31766
+ if (existsSync50(p)) {
31697
31767
  try {
31698
31768
  const raw = JSON.parse(readFileSync33(p, "utf8"));
31699
31769
  if (raw.version)
@@ -31767,7 +31837,7 @@ async function main() {
31767
31837
  process.exit(exitCode);
31768
31838
  } else {
31769
31839
  const configPath = join45(homedir18(), ".mma", "config.json");
31770
- if (!existsSync49(configPath)) {
31840
+ if (!existsSync50(configPath)) {
31771
31841
  console.log(pc2.yellow(`
31772
31842
  ` + t("cli.first_run") + `
31773
31843
  `));
package/package.json CHANGED
@@ -1,45 +1,45 @@
1
- {
2
- "name": "micro-models-agent",
3
- "version": "0.35.5",
4
- "description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
5
- "type": "module",
6
- "bin": {
7
- "mma": "bin/mma.mjs"
8
- },
9
- "files": [
10
- "dist/",
11
- "bin/"
12
- ],
13
- "engines": {
14
- "node": ">=20"
15
- },
16
- "scripts": {
17
- "mma": "bun run src/cli/main.ts",
18
- "build": "bun run build:tsc && bun run build:copy-assets",
19
- "build:tsc": "tsc -p tsconfig.build.json",
20
- "build:copy-assets": "bun run scripts/copy-assets.ts",
21
- "build:prod": "bun run 'build:bundle' && bun run 'build:copy-assets'",
22
- "build:clean": "cmd /c \"if exist dist rmdir /s /q dist\"",
23
- "build:bundle": "bun build ./src/cli/main.ts --outfile ./dist/main.js --target node --format esm --external playwright",
24
- "dev": "bun --watch src/cli/main.ts",
25
- "typecheck": "tsc --noEmit",
26
- "test": "bun test",
27
- "test:watch": "bun test --watch",
28
- "test:integration": "vitest run --config vitest.integration.config.ts"
29
- },
30
- "dependencies": {
31
- "commander": "^12.0.0",
32
- "js-tiktoken": "^1.0.0",
33
- "jsonrepair": "^3.15.0",
34
- "picocolors": "^1.1.1",
35
- "playwright": "^1.62.0",
36
- "string-width": "^8.2.2",
37
- "yaml": "^2.9.0"
38
- },
39
- "devDependencies": {
40
- "@types/bun": "^1.3.14",
41
- "@types/node": "^22.20.1",
42
- "typescript": "^5.9.3",
43
- "vitest": "^4.1.10"
44
- }
45
- }
1
+ {
2
+ "name": "micro-models-agent",
3
+ "version": "0.36.1",
4
+ "description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
5
+ "type": "module",
6
+ "bin": {
7
+ "mma": "bin/mma.mjs"
8
+ },
9
+ "files": [
10
+ "dist/",
11
+ "bin/"
12
+ ],
13
+ "engines": {
14
+ "node": ">=20"
15
+ },
16
+ "scripts": {
17
+ "mma": "bun run src/cli/main.ts",
18
+ "build": "bun run build:tsc && bun run build:copy-assets",
19
+ "build:tsc": "tsc -p tsconfig.build.json",
20
+ "build:copy-assets": "bun run scripts/copy-assets.ts",
21
+ "build:prod": "bun run 'build:bundle' && bun run 'build:copy-assets'",
22
+ "build:clean": "cmd /c \"if exist dist rmdir /s /q dist\"",
23
+ "build:bundle": "bun build ./src/cli/main.ts --outfile ./dist/main.js --target node --format esm --external playwright",
24
+ "dev": "bun --watch src/cli/main.ts",
25
+ "typecheck": "tsc --noEmit",
26
+ "test": "bun test",
27
+ "test:watch": "bun test --watch",
28
+ "test:integration": "vitest run --config vitest.integration.config.ts"
29
+ },
30
+ "dependencies": {
31
+ "commander": "^12.0.0",
32
+ "js-tiktoken": "^1.0.0",
33
+ "jsonrepair": "^3.15.0",
34
+ "picocolors": "^1.1.1",
35
+ "playwright": "^1.62.0",
36
+ "string-width": "^8.2.2",
37
+ "yaml": "^2.9.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/bun": "^1.3.14",
41
+ "@types/node": "^22.20.1",
42
+ "typescript": "^5.9.3",
43
+ "vitest": "^4.1.10"
44
+ }
45
+ }