micro-models-agent 0.34.0 → 0.35.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 +231 -57
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2372,9 +2372,12 @@ var init_en = __esm(() => {
2372
2372
  "tool.friendly.web_search": "Web search",
2373
2373
  "tool.friendly.web_fetch": "Fetching page",
2374
2374
  "tool.friendly.web_browse": "Browsing page",
2375
+ "tool.friendly.download_file": "Downloading file",
2375
2376
  "tool.web_fetch_result": "Fetched page: {url} — {chars} chars, {lines} lines{truncated}",
2376
2377
  "tool.web_browse_result": "Browsed page: {url} — {chars} chars, {lines} lines{truncated}",
2377
2378
  "tool.web_search_result": 'Search results for "{query}" — {count} results',
2379
+ "tool.downloaded": "Downloaded {url} → {path} ({size} bytes, {type})",
2380
+ "tool.download_too_large": "Download blocked: file exceeds the {max} bytes limit",
2378
2381
  "tool.friendly.browser": "Browser",
2379
2382
  "tool.friendly.subagent": "Sub-agent task",
2380
2383
  "tool.friendly.question": "Question to user",
@@ -2460,6 +2463,7 @@ Command: {command}`,
2460
2463
  "plan.step_not_found": "Step not found",
2461
2464
  "plan.step_already_done": "Step {step} is already done — nothing to do. Plan progress:",
2462
2465
  "plan.order_blocked": 'Cannot mark step {step} done: step {first} ("{desc}") is not finished yet. Complete earlier steps first, or mark step {first} status=skipped if it is not needed.',
2466
+ "plan.deliverables_missing": "Cannot mark step {step} done: the files it names do not exist yet: {files}. Create these files first (or mark the step status=skipped if they are not actually needed).",
2463
2467
  "plan.show_header": "Plan status:",
2464
2468
  "plan.show_empty": "(plan has no steps)",
2465
2469
  "plan.list_header": "Plans:",
@@ -2753,6 +2757,7 @@ Use this knowledge to answer the user's question.`,
2753
2757
  "exec.step_gate_ok": '[✓] Step {step} completed and verified. MOVING to step {nextStep}: "{nextDesc}". Work ONLY on this step.',
2754
2758
  "exec.step_gate_last": "[✓] Step {step} completed — that was the final step. Verify everything together and provide the final answer.]",
2755
2759
  "exec.audit_pass": "[✓] Task complete: {done}/{total} steps done, {files} files verified",
2760
+ "exec.audit_pending": "[✗] Task incomplete: {done}/{total} steps done — remaining steps are not marked done",
2756
2761
  "exec.audit_fail": "[✗] Task incomplete: {done}/{total} steps done, {files} files missing",
2757
2762
  "exec.audit_fail_tests": "[✗] Task incomplete: {done}/{total} steps done, tests FAILING: {failed} failed / {passed} passed — {detail}",
2758
2763
  "exec.audit_fail_typecheck": "[✗] Task incomplete: {done}/{total} steps done, {missing} files missing, typecheck error: {typeError}",
@@ -2957,9 +2962,12 @@ var init_ru = __esm(() => {
2957
2962
  "tool.friendly.web_search": "Поиск в интернете",
2958
2963
  "tool.friendly.web_fetch": "Загрузка страницы",
2959
2964
  "tool.friendly.web_browse": "Просмотр страницы",
2965
+ "tool.friendly.download_file": "Скачивание файла",
2960
2966
  "tool.web_fetch_result": "Загружена страница: {url} — {chars} симв., {lines} строк{truncated}",
2961
2967
  "tool.web_browse_result": "Просмотрена страница: {url} — {chars} симв., {lines} строк{truncated}",
2962
2968
  "tool.web_search_result": 'Результаты поиска "{query}" — {count} результатов',
2969
+ "tool.downloaded": "Скачано {url} → {path} ({size} байт, {type})",
2970
+ "tool.download_too_large": "Скачивание заблокировано: файл превышает лимит {max} байт",
2963
2971
  "tool.friendly.browser": "Браузер",
2964
2972
  "tool.friendly.subagent": "Задача подагенту",
2965
2973
  "tool.friendly.question": "Вопрос пользователю",
@@ -3045,6 +3053,7 @@ var init_ru = __esm(() => {
3045
3053
  "plan.step_not_found": "Шаг не найден",
3046
3054
  "plan.step_already_done": "Шаг {step} уже выполнен — ничего делать не нужно. Прогресс плана:",
3047
3055
  "plan.order_blocked": "Нельзя отметить шаг {step} выполненным: шаг {first} («{desc}») ещё не завершён. Сначала завершите предыдущие шаги или отметьте шаг {first} status=skipped, если он не нужен.",
3056
+ "plan.deliverables_missing": "Нельзя отметить шаг {step} выполненным: указанные в нём файлы ещё не существуют: {files}. Сначала создайте эти файлы (или отметьте шаг status=skipped, если они на самом деле не нужны).",
3048
3057
  "plan.show_header": "Статус плана:",
3049
3058
  "plan.show_empty": "(в плане нет шагов)",
3050
3059
  "plan.list_header": "Планы:",
@@ -3338,6 +3347,7 @@ var init_ru = __esm(() => {
3338
3347
  "exec.step_gate_ok": '[✓] Шаг {step} завершён и проверен. ПЕРЕХОДИМ к шагу {nextStep}: "{nextDesc}". Работайте ТОЛЬКО над этим шагом.',
3339
3348
  "exec.step_gate_last": "[✓] Шаг {step} завершён — это был последний шаг. Проверьте всё вместе и предоставьте финальный ответ.]",
3340
3349
  "exec.audit_pass": "[✓] Задача выполнена: {done}/{total} шагов, {files} файлов проверено",
3350
+ "exec.audit_pending": "[✗] Задача не выполнена: {done}/{total} шагов — оставшиеся шаги не отмечены выполненными",
3341
3351
  "exec.audit_fail": "[✗] Задача не выполнена: {done}/{total} шагов, {files} файлов отсутствует",
3342
3352
  "exec.audit_fail_tests": "[✗] Задача не выполнена: {done}/{total} шагов, тесты ПАДАЮТ: {failed} failed / {passed} passed — {detail}",
3343
3353
  "exec.audit_fail_typecheck": "[✗] Задача не выполнена: {done}/{total} шагов, {missing} файлов отсутствует, ошибка typecheck: {typeError}",
@@ -12825,6 +12835,120 @@ var init_web_browse = __esm(() => {
12825
12835
  };
12826
12836
  });
12827
12837
 
12838
+ // src/tools/download-file.ts
12839
+ import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync13 } from "fs";
12840
+ import { dirname as dirname6 } from "path";
12841
+ var MAX_DOWNLOAD_BYTES, downloadFileTool;
12842
+ var init_download_file = __esm(() => {
12843
+ init_i18n();
12844
+ init_network_validator();
12845
+ init_path_validator();
12846
+ init_audit_log();
12847
+ init_session_isolation();
12848
+ init_security();
12849
+ init_path_utils();
12850
+ MAX_DOWNLOAD_BYTES = 100 * 1024 * 1024;
12851
+ downloadFileTool = {
12852
+ name: "download_file",
12853
+ description: "Download a file (image, archive, binary, font, etc.) from a URL and save it to disk. Returns only the path, size and content type — read the saved file with read_file/attach_image afterwards. Use this for binary files; web_fetch/web_browse return text only and cannot save bytes.",
12854
+ tags: ["file", "research"],
12855
+ parameters: {
12856
+ type: "object",
12857
+ properties: {
12858
+ url: { type: "string", description: "URL to download" },
12859
+ path: {
12860
+ type: "string",
12861
+ description: "Destination path (relative to the working directory)"
12862
+ },
12863
+ max_bytes: {
12864
+ type: "number",
12865
+ description: "Optional size cap in bytes (default 100 MB)"
12866
+ }
12867
+ },
12868
+ required: ["url", "path"]
12869
+ },
12870
+ handler: async (ctx, args) => {
12871
+ const url = String(args.url || "").trim();
12872
+ const path = String(args.path || "").trim();
12873
+ if (!url || !path) {
12874
+ return { success: false, output: t("tool.invalid_params") };
12875
+ }
12876
+ const securityConfig = ctx.sessionContext ? getSessionSecurityConfig(ctx.config, ctx.sessionContext).network : ctx.config.security?.network || DEFAULT_SECURITY_CONFIG.network;
12877
+ const validation = isUrlAllowed(url, securityConfig);
12878
+ if (!validation.allowed) {
12879
+ logSecurityBlock(ctx.sessionId, "network_request", validation.reason || "URL blocked by security policy", sanitizeUrl(url));
12880
+ return {
12881
+ success: false,
12882
+ output: `[SECURITY BLOCKED] URL is not allowed: ${validation.reason}`
12883
+ };
12884
+ }
12885
+ const resolved = safeResolvePath(ctx.baseDir, path);
12886
+ const scopeCheck = isPathWritable(ctx.baseDir, resolved, ctx.scope, ctx.config.security?.paths);
12887
+ if (!scopeCheck.allowed) {
12888
+ logSecurityBlock(ctx.sessionId, "file_write", scopeCheck.reason || "Path not allowed", path);
12889
+ return {
12890
+ success: false,
12891
+ output: t("file.path_not_allowed", {
12892
+ path: `${path} — ${scopeCheck.reason}`
12893
+ })
12894
+ };
12895
+ }
12896
+ const maxBytes = Number(args.max_bytes) > 0 ? Number(args.max_bytes) : MAX_DOWNLOAD_BYTES;
12897
+ try {
12898
+ const response = await fetch(url, {
12899
+ signal: AbortSignal.timeout(securityConfig?.requestTimeout || 15000)
12900
+ });
12901
+ if (!response.ok) {
12902
+ logNetworkRequest(ctx.sessionId, sanitizeUrl(url), false, `Status: ${response.status}`);
12903
+ return {
12904
+ success: false,
12905
+ output: t("error.http", {
12906
+ status: response.status,
12907
+ statusText: response.statusText
12908
+ })
12909
+ };
12910
+ }
12911
+ const contentLength = Number(response.headers.get("content-length") || "0");
12912
+ if (contentLength > maxBytes) {
12913
+ logNetworkRequest(ctx.sessionId, sanitizeUrl(url), false, `Too large: ${contentLength}`);
12914
+ return {
12915
+ success: false,
12916
+ output: t("tool.download_too_large", { max: String(maxBytes) })
12917
+ };
12918
+ }
12919
+ const buffer = Buffer.from(await response.arrayBuffer());
12920
+ if (buffer.byteLength > maxBytes) {
12921
+ logNetworkRequest(ctx.sessionId, sanitizeUrl(url), false, `Too large: ${buffer.byteLength}`);
12922
+ return {
12923
+ success: false,
12924
+ output: t("tool.download_too_large", { max: String(maxBytes) })
12925
+ };
12926
+ }
12927
+ mkdirSync13(dirname6(resolved), { recursive: true });
12928
+ writeFileSync9(resolved, buffer);
12929
+ const contentType = response.headers.get("content-type")?.split(";")[0]?.trim() || "unknown";
12930
+ logNetworkRequest(ctx.sessionId, sanitizeUrl(url), true, `Status: ${response.status}`);
12931
+ logFileWrite(ctx.sessionId, resolved, true, `Downloaded ${buffer.byteLength} bytes`);
12932
+ return {
12933
+ success: true,
12934
+ output: t("tool.downloaded", {
12935
+ url: sanitizeUrl(url),
12936
+ path: resolved,
12937
+ size: String(buffer.byteLength),
12938
+ type: contentType
12939
+ })
12940
+ };
12941
+ } catch (e) {
12942
+ logNetworkRequest(ctx.sessionId, sanitizeUrl(url), false, `Error: ${e.message}`);
12943
+ return {
12944
+ success: false,
12945
+ output: t("error.fetch_failed", { message: e.message })
12946
+ };
12947
+ }
12948
+ }
12949
+ };
12950
+ });
12951
+
12828
12952
  // src/tools/load-skill.ts
12829
12953
  function createLoadSkillTool(skillsModule) {
12830
12954
  return {
@@ -13915,10 +14039,10 @@ __export(exports_bridge_client, {
13915
14039
  });
13916
14040
  import { spawn as spawn4 } from "child_process";
13917
14041
  import { createInterface } from "readline";
13918
- import { dirname as dirname6, join as join17 } from "path";
14042
+ import { dirname as dirname7, join as join17 } from "path";
13919
14043
  import { fileURLToPath } from "url";
13920
14044
  function bridgeScriptPath() {
13921
- return join17(dirname6(fileURLToPath(import.meta.url)), "bridge-server.mjs");
14045
+ return join17(dirname7(fileURLToPath(import.meta.url)), "bridge-server.mjs");
13922
14046
  }
13923
14047
 
13924
14048
  class BridgeDriver {
@@ -15145,6 +15269,7 @@ function registerAllTools(registry2, skillsModule) {
15145
15269
  webSearchTool,
15146
15270
  webFetchTool,
15147
15271
  webBrowseTool,
15272
+ downloadFileTool,
15148
15273
  pipelineRunTool,
15149
15274
  mcpCallTool,
15150
15275
  searchHistoryTool,
@@ -15178,6 +15303,7 @@ var init_tools = __esm(() => {
15178
15303
  init_web_search();
15179
15304
  init_web_fetch();
15180
15305
  init_web_browse();
15306
+ init_download_file();
15181
15307
  init_load_skill();
15182
15308
  init_pipeline_run();
15183
15309
  init_mcp_call();
@@ -15786,6 +15912,7 @@ class Auditor {
15786
15912
  }
15787
15913
  const testsFailing = testRun !== null && testRun.failed > 0;
15788
15914
  const passed = missingFiles.length === 0 && !testsFailing;
15915
+ const stepsPending = doneSteps < totalSteps;
15789
15916
  let summary;
15790
15917
  if (missingFiles.length > 0) {
15791
15918
  summary = t("exec.audit_fail", {
@@ -15801,6 +15928,11 @@ class Auditor {
15801
15928
  passed: String(testRun.passedCount),
15802
15929
  detail: testRun.detail
15803
15930
  });
15931
+ } else if (stepsPending) {
15932
+ summary = t("exec.audit_pending", {
15933
+ done: doneSteps,
15934
+ total: totalSteps
15935
+ });
15804
15936
  } else {
15805
15937
  summary = t("exec.audit_pass", {
15806
15938
  done: doneSteps,
@@ -15841,7 +15973,7 @@ var init_auditor = __esm(() => {
15841
15973
  });
15842
15974
 
15843
15975
  // src/modules/execution/plan-store.ts
15844
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync9, mkdirSync as mkdirSync13, existsSync as existsSync28, readdirSync as readdirSync9, rmSync } from "fs";
15976
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync28, readdirSync as readdirSync9, rmSync } from "fs";
15845
15977
  import { join as join23 } from "path";
15846
15978
  function readPlanFile(path, fallbackBaseDir) {
15847
15979
  try {
@@ -15864,7 +15996,7 @@ function readPlanFile(path, fallbackBaseDir) {
15864
15996
  }
15865
15997
  }
15866
15998
  function writePlanFile(path, plan) {
15867
- writeFileSync9(path, JSON.stringify(plan, null, 2), "utf-8");
15999
+ writeFileSync10(path, JSON.stringify(plan, null, 2), "utf-8");
15868
16000
  }
15869
16001
  function listDir(dir, baseDir) {
15870
16002
  if (!existsSync28(dir))
@@ -15893,7 +16025,7 @@ class PlanStore {
15893
16025
  constructor(baseDir) {
15894
16026
  const mmaDir = join23(baseDir, ".mma");
15895
16027
  if (!existsSync28(mmaDir))
15896
- mkdirSync13(mmaDir, { recursive: true });
16028
+ mkdirSync14(mmaDir, { recursive: true });
15897
16029
  this.baseDir = baseDir;
15898
16030
  this.plansDir = join23(mmaDir, "plans");
15899
16031
  this.draftsDir = join23(this.plansDir, "drafts");
@@ -15901,7 +16033,7 @@ class PlanStore {
15901
16033
  this.legacyPath = join23(mmaDir, LEGACY_FILE);
15902
16034
  for (const dir of [this.plansDir, this.draftsDir, this.archiveDir]) {
15903
16035
  if (!existsSync28(dir))
15904
- mkdirSync13(dir, { recursive: true });
16036
+ mkdirSync14(dir, { recursive: true });
15905
16037
  }
15906
16038
  }
15907
16039
  activePath() {
@@ -16346,6 +16478,18 @@ ${progress2}`,
16346
16478
  };
16347
16479
  }
16348
16480
  }
16481
+ if (status === "done") {
16482
+ const missing = this.missingStepDeliverables(target);
16483
+ if (missing.length > 0) {
16484
+ return {
16485
+ success: false,
16486
+ output: t("plan.deliverables_missing", {
16487
+ step: String(stepId),
16488
+ files: missing.join(", ")
16489
+ })
16490
+ };
16491
+ }
16492
+ }
16349
16493
  this.tracker.updateStepStatus(stepId, status);
16350
16494
  if (args.note)
16351
16495
  this.tracker.addNote(Number(args.step), String(args.note));
@@ -16850,6 +16994,12 @@ Tool "${this.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
16850
16994
  });
16851
16995
  }
16852
16996
  }
16997
+ missingStepDeliverables(step) {
16998
+ const tokens = extractFileLikeTokens(stripUrls(step.description));
16999
+ if (tokens.length === 0)
17000
+ return [];
17001
+ return tokens.filter((p) => !findExistingFile(this.baseDir, p));
17002
+ }
16853
17003
  getTaskText(ctx) {
16854
17004
  const manager = ctx?.contextManager;
16855
17005
  if (!manager)
@@ -16871,12 +17021,13 @@ var init_module = __esm(() => {
16871
17021
  init_plan_store();
16872
17022
  init_plan_coverage();
16873
17023
  init_bash();
17024
+ init_js_identifiers();
16874
17025
  });
16875
17026
 
16876
17027
  // src/modules/security/session-encryption.ts
16877
17028
  import {
16878
17029
  readFileSync as readFileSync18,
16879
- writeFileSync as writeFileSync10,
17030
+ writeFileSync as writeFileSync11,
16880
17031
  existsSync as existsSync30,
16881
17032
  readdirSync as readdirSync10,
16882
17033
  unlinkSync as unlinkSync4
@@ -16940,7 +17091,7 @@ class SessionFileEncryptor {
16940
17091
  }
16941
17092
  writeSessionFile(filePath, content) {
16942
17093
  const encrypted = this.encryptFileContent(content);
16943
- writeFileSync10(filePath, encrypted, "utf8");
17094
+ writeFileSync11(filePath, encrypted, "utf8");
16944
17095
  }
16945
17096
  readSessionJSON(filePath) {
16946
17097
  const content = readFileSync18(filePath, "utf8");
@@ -16948,7 +17099,7 @@ class SessionFileEncryptor {
16948
17099
  }
16949
17100
  writeSessionJSON(filePath, obj) {
16950
17101
  const content = this.encryptJSON(obj);
16951
- writeFileSync10(filePath, content, "utf8");
17102
+ writeFileSync11(filePath, content, "utf8");
16952
17103
  }
16953
17104
  readSessionJSONL(filePath) {
16954
17105
  const content = readFileSync18(filePath, "utf8");
@@ -16965,7 +17116,7 @@ class SessionFileEncryptor {
16965
17116
  }
16966
17117
  appendToSessionJSONL(filePath, obj) {
16967
17118
  const encryptedLine = this.encryptFileContent(JSON.stringify(obj));
16968
- writeFileSync10(filePath, encryptedLine + `
17119
+ writeFileSync11(filePath, encryptedLine + `
16969
17120
  `, {
16970
17121
  flag: "a",
16971
17122
  encoding: "utf8"
@@ -16981,7 +17132,7 @@ class SessionFileEncryptor {
16981
17132
  try {
16982
17133
  const content = readFileSync18(filePath, "utf8");
16983
17134
  const encrypted = this.encryptFileContent(content);
16984
- writeFileSync10(filePath + ".enc", encrypted, "utf8");
17135
+ writeFileSync11(filePath + ".enc", encrypted, "utf8");
16985
17136
  unlinkSync4(filePath);
16986
17137
  } catch {}
16987
17138
  }
@@ -16998,7 +17149,7 @@ class SessionFileEncryptor {
16998
17149
  try {
16999
17150
  const content = readFileSync18(encFilePath, "utf8");
17000
17151
  const decrypted = this.decryptFileContent(content);
17001
- writeFileSync10(decFilePath, decrypted, "utf8");
17152
+ writeFileSync11(decFilePath, decrypted, "utf8");
17002
17153
  unlinkSync4(encFilePath);
17003
17154
  } catch {}
17004
17155
  }
@@ -17019,11 +17170,11 @@ var init_session_encryption = __esm(() => {
17019
17170
  // src/modules/session/store.ts
17020
17171
  import {
17021
17172
  existsSync as existsSync31,
17022
- mkdirSync as mkdirSync14,
17173
+ mkdirSync as mkdirSync15,
17023
17174
  readdirSync as readdirSync11,
17024
17175
  readFileSync as readFileSync19,
17025
17176
  rmSync as rmSync2,
17026
- writeFileSync as writeFileSync11,
17177
+ writeFileSync as writeFileSync12,
17027
17178
  appendFileSync as appendFileSync6
17028
17179
  } from "fs";
17029
17180
  import { join as join25 } from "path";
@@ -17053,7 +17204,7 @@ class SessionStore {
17053
17204
  return this.encryptor?.isEnabled() ?? false;
17054
17205
  }
17055
17206
  init() {
17056
- mkdirSync14(this.baseDir, { recursive: true });
17207
+ mkdirSync15(this.baseDir, { recursive: true });
17057
17208
  }
17058
17209
  sessionDir(id) {
17059
17210
  return join25(this.baseDir, id);
@@ -17073,12 +17224,12 @@ class SessionStore {
17073
17224
  saveMeta(id, meta) {
17074
17225
  this._metaCache.set(id, meta);
17075
17226
  const dir = this.sessionDir(id);
17076
- mkdirSync14(dir, { recursive: true });
17227
+ mkdirSync15(dir, { recursive: true });
17077
17228
  const content = JSON.stringify(meta, null, 2);
17078
17229
  if (this.encryptor) {
17079
- writeFileSync11(this.metaPath(id), this.encryptor.encryptFileContent(content), "utf-8");
17230
+ writeFileSync12(this.metaPath(id), this.encryptor.encryptFileContent(content), "utf-8");
17080
17231
  } else {
17081
- writeFileSync11(this.metaPath(id), content, "utf-8");
17232
+ writeFileSync12(this.metaPath(id), content, "utf-8");
17082
17233
  }
17083
17234
  }
17084
17235
  loadMeta(id) {
@@ -17100,7 +17251,7 @@ class SessionStore {
17100
17251
  }
17101
17252
  appendMessage(id, msg) {
17102
17253
  const dir = this.sessionDir(id);
17103
- mkdirSync14(dir, { recursive: true });
17254
+ mkdirSync15(dir, { recursive: true });
17104
17255
  const line = JSON.stringify(msg);
17105
17256
  if (this.encryptor?.isEnabled()) {
17106
17257
  appendFileSync6(this.historyPath(id), this.encryptor.encryptFileContent(line) + `
@@ -17147,7 +17298,7 @@ class SessionStore {
17147
17298
  }
17148
17299
  appendSessionLog(id, entry) {
17149
17300
  const dir = this.sessionDir(id);
17150
- mkdirSync14(dir, { recursive: true });
17301
+ mkdirSync15(dir, { recursive: true });
17151
17302
  const line = JSON.stringify(entry);
17152
17303
  if (this.encryptor?.isEnabled()) {
17153
17304
  appendFileSync6(this.sessionLogPath(id), this.encryptor.encryptFileContent(line) + `
@@ -17220,7 +17371,7 @@ class SessionStore {
17220
17371
  const content = readFileSync19(historyPath, "utf-8");
17221
17372
  const compressed = gzipSync(content);
17222
17373
  const gzPath = join25(this.baseDir, `${session2.id}.jsonl.gz`);
17223
- writeFileSync11(gzPath, compressed);
17374
+ writeFileSync12(gzPath, compressed);
17224
17375
  rmSync2(historyPath);
17225
17376
  }
17226
17377
  }
@@ -17429,7 +17580,7 @@ class ProfileCompressor {
17429
17580
  }
17430
17581
 
17431
17582
  // src/modules/user-profile/profile.ts
17432
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync12, existsSync as existsSync32, mkdirSync as mkdirSync15 } from "fs";
17583
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync32, mkdirSync as mkdirSync16 } from "fs";
17433
17584
  import { join as join26 } from "path";
17434
17585
  import { homedir as homedir9, hostname, platform as platform4, type } from "os";
17435
17586
  import { env } from "process";
@@ -17455,9 +17606,9 @@ class UserProfile {
17455
17606
  }
17456
17607
  save() {
17457
17608
  if (!existsSync32(this.profileDir)) {
17458
- mkdirSync15(this.profileDir, { recursive: true });
17609
+ mkdirSync16(this.profileDir, { recursive: true });
17459
17610
  }
17460
- writeFileSync12(join26(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
17611
+ writeFileSync13(join26(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
17461
17612
  }
17462
17613
  load() {
17463
17614
  const path = join26(this.profileDir, "profile.json");
@@ -17776,14 +17927,28 @@ function resolveSpawnCommand(command, platformName = platform5(), pathEnv = proc
17776
17927
  }
17777
17928
  return command;
17778
17929
  }
17930
+ function buildWinCommandLine(command, args) {
17931
+ const quote = (part) => {
17932
+ if (part === "")
17933
+ return '""';
17934
+ if (!/[\s"&|^<>()%!]/.test(part))
17935
+ return part;
17936
+ return `"${part.replace(/"/g, "\\\"")}"`;
17937
+ };
17938
+ return [command, ...args].map(quote).join(" ");
17939
+ }
17779
17940
  var WIN_EXTS;
17780
17941
  var init_command = __esm(() => {
17781
17942
  WIN_EXTS = [".cmd", ".bat", ".exe", ".com"];
17782
17943
  });
17783
17944
 
17784
17945
  // src/modules/lsp/client.ts
17785
- import { spawn as spawn6, execSync as execSync2 } from "child_process";
17946
+ import {
17947
+ spawn as spawn6,
17948
+ execSync as execSync2
17949
+ } from "child_process";
17786
17950
  import { resolve as resolve19 } from "path";
17951
+ import { platform as platform6 } from "os";
17787
17952
 
17788
17953
  class LspClient {
17789
17954
  process = null;
@@ -17846,11 +18011,20 @@ class LspClient {
17846
18011
  }
17847
18012
  return new Promise((resolve20, reject) => {
17848
18013
  const args = config.args ?? [];
17849
- const proc = spawn6(resolveSpawnCommand(config.command), args, {
18014
+ const isWin = platform6() === "win32";
18015
+ let spawnCommand = resolveSpawnCommand(config.command);
18016
+ let spawnArgs = args;
18017
+ const spawnOpts = {
17850
18018
  stdio: ["pipe", "pipe", "pipe"],
17851
18019
  env: { ...process.env, ...config.env },
17852
18020
  cwd: baseDir
17853
- });
18021
+ };
18022
+ if (isWin) {
18023
+ spawnCommand = buildWinCommandLine(spawnCommand, args);
18024
+ spawnArgs = [];
18025
+ spawnOpts.shell = true;
18026
+ }
18027
+ const proc = spawn6(spawnCommand, spawnArgs, spawnOpts);
17854
18028
  proc.on("error", reject);
17855
18029
  proc.stdout.on("data", (chunk) => {
17856
18030
  this.handleData(chunk);
@@ -18210,7 +18384,7 @@ var init_walker = __esm(() => {
18210
18384
  });
18211
18385
 
18212
18386
  // src/modules/indexer/cache.ts
18213
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync13, existsSync as existsSync37, mkdirSync as mkdirSync16, rmSync as rmSync3 } from "fs";
18387
+ import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync37, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
18214
18388
  import { join as join30 } from "path";
18215
18389
 
18216
18390
  class IndexCache {
@@ -18235,8 +18409,8 @@ class IndexCache {
18235
18409
  this.cache = result;
18236
18410
  const dir = join30(this.cachePath, "..");
18237
18411
  if (!existsSync37(dir))
18238
- mkdirSync16(dir, { recursive: true });
18239
- writeFileSync13(this.cachePath, JSON.stringify(result), "utf-8");
18412
+ mkdirSync17(dir, { recursive: true });
18413
+ writeFileSync14(this.cachePath, JSON.stringify(result), "utf-8");
18240
18414
  }
18241
18415
  invalidate() {
18242
18416
  this.cache = null;
@@ -18418,7 +18592,7 @@ var init_project_profile = __esm(() => {
18418
18592
  });
18419
18593
 
18420
18594
  // src/modules/indexer/module.ts
18421
- import { dirname as dirname8 } from "path";
18595
+ import { dirname as dirname9 } from "path";
18422
18596
 
18423
18597
  class IndexerModule {
18424
18598
  name = "indexer";
@@ -18537,7 +18711,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
18537
18711
  const counts = {};
18538
18712
  for (const f of result.files) {
18539
18713
  const normalized = f.path.replace(/\\/g, "/");
18540
- const dir = dirname8(normalized);
18714
+ const dir = dirname9(normalized);
18541
18715
  const key = dir === "." ? "(root)" : dir;
18542
18716
  counts[key] = (counts[key] || 0) + 1;
18543
18717
  }
@@ -18830,7 +19004,7 @@ __export(exports_bootstrap, {
18830
19004
  });
18831
19005
  import { homedir as homedir11 } from "os";
18832
19006
  import { join as join33, resolve as resolve21 } from "path";
18833
- import { existsSync as existsSync39, readFileSync as readFileSync25, writeFileSync as writeFileSync14 } from "fs";
19007
+ import { existsSync as existsSync39, readFileSync as readFileSync25, writeFileSync as writeFileSync15 } from "fs";
18834
19008
  function buildSystemInfo(config, baseDir, profileCompressed) {
18835
19009
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
18836
19010
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -18929,7 +19103,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
18929
19103
  };
18930
19104
  const agentsMdGlobal = join33(dir, "AGENTS.md");
18931
19105
  if (!existsSync39(agentsMdGlobal)) {
18932
- writeFileSync14(agentsMdGlobal, "", "utf-8");
19106
+ writeFileSync15(agentsMdGlobal, "", "utf-8");
18933
19107
  }
18934
19108
  const sessionDir = join33(dir, "sessions");
18935
19109
  const sessionStore = new SessionStore(sessionDir);
@@ -19925,7 +20099,7 @@ __export(exports_manifest, {
19925
20099
  getCertMark: () => getCertMark,
19926
20100
  MANIFEST_PATH: () => MANIFEST_PATH
19927
20101
  });
19928
- import { existsSync as existsSync40, readFileSync as readFileSync26, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
20102
+ import { existsSync as existsSync40, readFileSync as readFileSync26, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
19929
20103
  import { homedir as homedir13 } from "os";
19930
20104
  import { join as join35 } from "path";
19931
20105
  function readManifest(path = MANIFEST_PATH) {
@@ -19938,8 +20112,8 @@ function readManifest(path = MANIFEST_PATH) {
19938
20112
  return { version: 1, certifications: [] };
19939
20113
  }
19940
20114
  function saveManifest(m, path = MANIFEST_PATH) {
19941
- mkdirSync17(join35(homedir13(), ".mma"), { recursive: true });
19942
- writeFileSync15(path, JSON.stringify(m, null, 2), "utf-8");
20115
+ mkdirSync18(join35(homedir13(), ".mma"), { recursive: true });
20116
+ writeFileSync16(path, JSON.stringify(m, null, 2), "utf-8");
19943
20117
  }
19944
20118
  function upsertCertification(entry, path = MANIFEST_PATH) {
19945
20119
  const m = readManifest(path);
@@ -27288,9 +27462,9 @@ var init_fact_checker = () => {};
27288
27462
 
27289
27463
  // src/modules/certification/runner.ts
27290
27464
  import { spawn as spawn7 } from "child_process";
27291
- import { existsSync as existsSync43, mkdirSync as mkdirSync18, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
27292
- import { platform as platform6 } from "os";
27293
- import { join as join38, resolve as resolve22, dirname as dirname9 } from "path";
27465
+ import { existsSync as existsSync43, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
27466
+ import { platform as platform7 } from "os";
27467
+ import { join as join38, resolve as resolve22, dirname as dirname10 } from "path";
27294
27468
  async function runScenario(scenario, opts) {
27295
27469
  if (scenario.mode === "skip") {
27296
27470
  return {
@@ -27368,14 +27542,14 @@ ${res.stderr}`;
27368
27542
  }
27369
27543
  function prepareSandbox(sandbox, scenario, mmaRoot) {
27370
27544
  rmSync4(sandbox, { recursive: true, force: true });
27371
- mkdirSync18(sandbox, { recursive: true });
27545
+ mkdirSync19(sandbox, { recursive: true });
27372
27546
  for (const f of scenario.fixtures ?? []) {
27373
27547
  const src = join38(mmaRoot, f.source);
27374
27548
  if (!existsSync43(src)) {
27375
27549
  throw new Error(`fixture missing: ${f.source}`);
27376
27550
  }
27377
27551
  const dest = join38(sandbox, f.dest);
27378
- mkdirSync18(dirname9(dest), { recursive: true });
27552
+ mkdirSync19(dirname10(dest), { recursive: true });
27379
27553
  cpSync2(src, dest);
27380
27554
  }
27381
27555
  }
@@ -27400,7 +27574,7 @@ function killTree2(child) {
27400
27574
  const pid = child.pid;
27401
27575
  if (!pid)
27402
27576
  return;
27403
- if (platform6() === "win32") {
27577
+ if (platform7() === "win32") {
27404
27578
  spawn7("taskkill", ["/pid", String(pid), "/T", "/F"], {
27405
27579
  windowsHide: true,
27406
27580
  stdio: "ignore"
@@ -27459,7 +27633,7 @@ __export(exports_cli, {
27459
27633
  });
27460
27634
  import { rmSync as rmSync5 } from "fs";
27461
27635
  import { homedir as homedir14 } from "os";
27462
- import { join as join39, dirname as dirname10 } from "path";
27636
+ import { join as join39, dirname as dirname11 } from "path";
27463
27637
  import { fileURLToPath as fileURLToPath2 } from "url";
27464
27638
  import { existsSync as existsSync44, readFileSync as readFileSync29 } from "fs";
27465
27639
  function readVersion() {
@@ -27615,7 +27789,7 @@ var init_cli = __esm(() => {
27615
27789
  init_loader3();
27616
27790
  init_runner2();
27617
27791
  init_manifest();
27618
- HERE = dirname10(fileURLToPath2(import.meta.url));
27792
+ HERE = dirname11(fileURLToPath2(import.meta.url));
27619
27793
  MMA_ROOT = findMmaRoot(HERE);
27620
27794
  USER_SCENARIO_DIR = join39(homedir14(), ".mma", "certification", "scenarios");
27621
27795
  });
@@ -27626,12 +27800,12 @@ __export(exports_repl_commands, {
27626
27800
  registerAllCommands: () => registerAllCommands,
27627
27801
  COMMAND_GROUPS: () => COMMAND_GROUPS
27628
27802
  });
27629
- import { join as join41, dirname as dirname12 } from "path";
27803
+ import { join as join41, dirname as dirname13 } from "path";
27630
27804
  import { homedir as homedir16 } from "os";
27631
27805
  import { existsSync as existsSync46, readFileSync as readFileSync31 } from "fs";
27632
27806
  import { fileURLToPath as fileURLToPath4 } from "url";
27633
27807
  function readVersion3() {
27634
- const here = dirname12(fileURLToPath4(import.meta.url));
27808
+ const here = dirname13(fileURLToPath4(import.meta.url));
27635
27809
  const candidates = [
27636
27810
  join41(here, "..", "..", "package.json"),
27637
27811
  join41(here, "..", "package.json")
@@ -28259,7 +28433,7 @@ init_bootstrap();
28259
28433
  init_config2();
28260
28434
  init_setup();
28261
28435
  init_i18n();
28262
- import { join as join40, dirname as dirname11 } from "path";
28436
+ import { join as join40, dirname as dirname12 } from "path";
28263
28437
  import { homedir as homedir15 } from "os";
28264
28438
  import { existsSync as existsSync45, readFileSync as readFileSync30 } from "fs";
28265
28439
 
@@ -28883,7 +29057,7 @@ function createSecurityCommand(program2) {
28883
29057
  // src/cli/commands.ts
28884
29058
  import { fileURLToPath as fileURLToPath3 } from "url";
28885
29059
  function readVersion2() {
28886
- const here = dirname11(fileURLToPath3(import.meta.url));
29060
+ const here = dirname12(fileURLToPath3(import.meta.url));
28887
29061
  const candidates = [
28888
29062
  join40(here, "..", "..", "package.json"),
28889
29063
  join40(here, "..", "package.json")
@@ -29836,8 +30010,8 @@ class LineEditor {
29836
30010
  }
29837
30011
 
29838
30012
  // src/cli/repl.ts
29839
- import { existsSync as existsSync47, readFileSync as readFileSync32, writeFileSync as writeFileSync16 } from "fs";
29840
- import { join as join42, dirname as dirname13 } from "path";
30013
+ import { existsSync as existsSync47, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
30014
+ import { join as join42, dirname as dirname14 } from "path";
29841
30015
  import { homedir as homedir17 } from "os";
29842
30016
  import { fileURLToPath as fileURLToPath5 } from "url";
29843
30017
 
@@ -30341,7 +30515,7 @@ init_box();
30341
30515
  init_i18n();
30342
30516
  init_repl_commands();
30343
30517
  function readVersion4() {
30344
- const here = dirname13(fileURLToPath5(import.meta.url));
30518
+ const here = dirname14(fileURLToPath5(import.meta.url));
30345
30519
  const candidates = [
30346
30520
  join42(here, "..", "..", "package.json"),
30347
30521
  join42(here, "..", "package.json")
@@ -30453,7 +30627,7 @@ class Repl {
30453
30627
  }
30454
30628
  saveHistory() {
30455
30629
  const allHistory = this.history.slice(-this.maxHistory);
30456
- writeFileSync16(this.historyPath, allHistory.join(`
30630
+ writeFileSync17(this.historyPath, allHistory.join(`
30457
30631
  `), "utf-8");
30458
30632
  }
30459
30633
  setupCompleter() {
@@ -30857,13 +31031,13 @@ init_config2();
30857
31031
  init_i18n();
30858
31032
  init_colors();
30859
31033
  import { existsSync as existsSync48, readFileSync as readFileSync33 } from "fs";
30860
- import { join as join43, dirname as dirname14 } from "path";
31034
+ import { join as join43, dirname as dirname15 } from "path";
30861
31035
  import { homedir as homedir18 } from "os";
30862
31036
  import { fileURLToPath as fileURLToPath6 } from "url";
30863
31037
 
30864
31038
  // src/modules/updater/checker.ts
30865
31039
  init_command();
30866
- import { platform as platform7 } from "os";
31040
+ import { platform as platform8 } from "os";
30867
31041
  var defaultRunner2 = async (command, args, options) => {
30868
31042
  const { execFile } = await import("child_process");
30869
31043
  return new Promise((resolve23) => {
@@ -30925,7 +31099,7 @@ class Updater {
30925
31099
  buildInstallCommand(latest) {
30926
31100
  const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
30927
31101
  const command = resolveSpawnCommand("npm");
30928
- if (platform7() === "win32" && /\.(cmd|bat)$/i.test(command)) {
31102
+ if (platform8() === "win32" && /\.(cmd|bat)$/i.test(command)) {
30929
31103
  return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
30930
31104
  }
30931
31105
  return { command, args: npmArgs };
@@ -31019,7 +31193,7 @@ class UpdaterModule {
31019
31193
  }
31020
31194
  // src/cli/main.ts
31021
31195
  function readVersion5() {
31022
- const here = dirname14(fileURLToPath6(import.meta.url));
31196
+ const here = dirname15(fileURLToPath6(import.meta.url));
31023
31197
  const candidates = [
31024
31198
  join43(here, "..", "..", "package.json"),
31025
31199
  join43(here, "..", "package.json")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.34.0",
3
+ "version": "0.35.1",
4
4
  "description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
5
5
  "type": "module",
6
6
  "bin": {