micro-models-agent 0.27.0 → 0.28.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 (167) hide show
  1. package/dist/main.js +449 -237
  2. package/package.json +1 -1
  3. package/dist/cli/commands.js +0 -220
  4. package/dist/cli/completer.js +0 -168
  5. package/dist/cli/index.js +0 -2
  6. package/dist/cli/main.js +0 -113
  7. package/dist/cli/repl.js +0 -987
  8. package/dist/cli/security-commands.js +0 -166
  9. package/dist/cli/setup.js +0 -229
  10. package/dist/config/config.js +0 -186
  11. package/dist/config/defaults.js +0 -91
  12. package/dist/config/experts.js +0 -15
  13. package/dist/config/index.js +0 -3
  14. package/dist/config/security.js +0 -193
  15. package/dist/config/types.js +0 -1
  16. package/dist/core/agent-moe.js +0 -98
  17. package/dist/core/agent.js +0 -461
  18. package/dist/core/bootstrap.js +0 -321
  19. package/dist/core/index.js +0 -2
  20. package/dist/core/prompt-builder.js +0 -55
  21. package/dist/core/session-logger.js +0 -122
  22. package/dist/core/types.js +0 -1
  23. package/dist/i18n/en.json +0 -461
  24. package/dist/i18n/index.js +0 -43
  25. package/dist/i18n/ru.json +0 -461
  26. package/dist/index.js +0 -22
  27. package/dist/llm/image-utils.js +0 -144
  28. package/dist/llm/index.js +0 -4
  29. package/dist/llm/model-loader.js +0 -78
  30. package/dist/llm/openai-compat.js +0 -324
  31. package/dist/llm/orchestrator.js +0 -194
  32. package/dist/llm/provider.js +0 -10
  33. package/dist/llm/response.js +0 -39
  34. package/dist/llm/token-counter.js +0 -39
  35. package/dist/llm/types.js +0 -1
  36. package/dist/logger/app-logger.js +0 -76
  37. package/dist/logger/index.js +0 -1
  38. package/dist/migration/backup.js +0 -45
  39. package/dist/migration/detect.js +0 -50
  40. package/dist/migration/index.js +0 -2
  41. package/dist/modules/browser/actions.js +0 -46
  42. package/dist/modules/browser/cookie-store.js +0 -24
  43. package/dist/modules/browser/index.js +0 -5
  44. package/dist/modules/browser/module.js +0 -28
  45. package/dist/modules/browser/session.js +0 -287
  46. package/dist/modules/browser/snapshot.js +0 -114
  47. package/dist/modules/browser/types.js +0 -9
  48. package/dist/modules/context/history.js +0 -15
  49. package/dist/modules/context/index.js +0 -1
  50. package/dist/modules/context/manager.js +0 -240
  51. package/dist/modules/execution/auditor.js +0 -72
  52. package/dist/modules/execution/index.js +0 -6
  53. package/dist/modules/execution/module.js +0 -337
  54. package/dist/modules/execution/moe-executor.js +0 -209
  55. package/dist/modules/execution/plan-validator.js +0 -153
  56. package/dist/modules/execution/planner.js +0 -35
  57. package/dist/modules/execution/stuck-detector.js +0 -134
  58. package/dist/modules/execution/tracker.js +0 -53
  59. package/dist/modules/execution/types.js +0 -1
  60. package/dist/modules/execution/verifier.js +0 -149
  61. package/dist/modules/hallucination/confidence.js +0 -54
  62. package/dist/modules/hallucination/consistency.js +0 -60
  63. package/dist/modules/hallucination/detector.js +0 -41
  64. package/dist/modules/hallucination/factual.js +0 -170
  65. package/dist/modules/hallucination/index.js +0 -4
  66. package/dist/modules/index.js +0 -5
  67. package/dist/modules/indexer/cache.js +0 -38
  68. package/dist/modules/indexer/index.js +0 -3
  69. package/dist/modules/indexer/module.js +0 -192
  70. package/dist/modules/indexer/walker.js +0 -101
  71. package/dist/modules/mcp/client.js +0 -393
  72. package/dist/modules/mcp/index.js +0 -3
  73. package/dist/modules/mcp/module.js +0 -146
  74. package/dist/modules/mcp/registry.js +0 -15
  75. package/dist/modules/memory/index.js +0 -1
  76. package/dist/modules/memory/module.js +0 -48
  77. package/dist/modules/memory/search.js +0 -40
  78. package/dist/modules/memory/store.js +0 -65
  79. package/dist/modules/pipelines/engine.js +0 -60
  80. package/dist/modules/pipelines/index.js +0 -3
  81. package/dist/modules/pipelines/parser.js +0 -53
  82. package/dist/modules/pipelines/template.js +0 -14
  83. package/dist/modules/plugins/builtin/lint-on-write.js +0 -121
  84. package/dist/modules/plugins/builtin/notify.js +0 -8
  85. package/dist/modules/plugins/index.js +0 -1
  86. package/dist/modules/plugins/loader.js +0 -28
  87. package/dist/modules/plugins/manager.js +0 -161
  88. package/dist/modules/plugins/types.js +0 -1
  89. package/dist/modules/processes/detect.js +0 -34
  90. package/dist/modules/processes/index.js +0 -3
  91. package/dist/modules/processes/registry.js +0 -148
  92. package/dist/modules/processes/runner.js +0 -124
  93. package/dist/modules/registry.js +0 -45
  94. package/dist/modules/security/audit-log.js +0 -116
  95. package/dist/modules/security/audit-notifier.js +0 -292
  96. package/dist/modules/security/command-validator.js +0 -185
  97. package/dist/modules/security/content-scanner.js +0 -52
  98. package/dist/modules/security/data-sanitizer.js +0 -97
  99. package/dist/modules/security/encryption.js +0 -240
  100. package/dist/modules/security/index.js +0 -14
  101. package/dist/modules/security/network-validator.js +0 -79
  102. package/dist/modules/security/path-validator.js +0 -155
  103. package/dist/modules/security/rate-limiter.js +0 -119
  104. package/dist/modules/security/security-policies.js +0 -393
  105. package/dist/modules/security/session-encryption.js +0 -193
  106. package/dist/modules/security/session-isolation.js +0 -95
  107. package/dist/modules/session/index.js +0 -3
  108. package/dist/modules/session/manager.js +0 -167
  109. package/dist/modules/session/module.js +0 -24
  110. package/dist/modules/session/store.js +0 -174
  111. package/dist/modules/session/types.js +0 -1
  112. package/dist/modules/skills/index.js +0 -3
  113. package/dist/modules/skills/loader.js +0 -72
  114. package/dist/modules/skills/matcher.js +0 -27
  115. package/dist/modules/skills/module.js +0 -143
  116. package/dist/modules/types.js +0 -1
  117. package/dist/modules/updater/checker.js +0 -32
  118. package/dist/modules/updater/index.js +0 -1
  119. package/dist/modules/user-profile/compressor.js +0 -16
  120. package/dist/modules/user-profile/index.js +0 -1
  121. package/dist/modules/user-profile/profile.js +0 -68
  122. package/dist/tools/approve.js +0 -32
  123. package/dist/tools/attach-image.js +0 -89
  124. package/dist/tools/bash.js +0 -140
  125. package/dist/tools/browser.js +0 -97
  126. package/dist/tools/create-dir.js +0 -56
  127. package/dist/tools/delete-file.js +0 -63
  128. package/dist/tools/edit-file.js +0 -77
  129. package/dist/tools/executor.js +0 -95
  130. package/dist/tools/file-info.js +0 -45
  131. package/dist/tools/filter-tools.js +0 -10
  132. package/dist/tools/glob-tool.js +0 -26
  133. package/dist/tools/grep-tool.js +0 -64
  134. package/dist/tools/index.js +0 -52
  135. package/dist/tools/list-dir.js +0 -47
  136. package/dist/tools/load-skill.js +0 -48
  137. package/dist/tools/mcp-call.js +0 -68
  138. package/dist/tools/move-file.js +0 -84
  139. package/dist/tools/path-utils.js +0 -51
  140. package/dist/tools/pipeline-run.js +0 -144
  141. package/dist/tools/preview.js +0 -2
  142. package/dist/tools/process-kill.js +0 -29
  143. package/dist/tools/process-list.js +0 -38
  144. package/dist/tools/process-log.js +0 -41
  145. package/dist/tools/question.js +0 -142
  146. package/dist/tools/read-file.js +0 -73
  147. package/dist/tools/recall.js +0 -110
  148. package/dist/tools/registry.js +0 -36
  149. package/dist/tools/remember.js +0 -67
  150. package/dist/tools/scope-check.js +0 -30
  151. package/dist/tools/search-history.js +0 -64
  152. package/dist/tools/subagent.js +0 -142
  153. package/dist/tools/types.js +0 -1
  154. package/dist/tools/user-input.js +0 -123
  155. package/dist/tools/web-browse.js +0 -57
  156. package/dist/tools/web-fetch.js +0 -72
  157. package/dist/tools/web-search.js +0 -59
  158. package/dist/tools/write-file.js +0 -80
  159. package/dist/ui/box.js +0 -81
  160. package/dist/ui/colors.js +0 -4
  161. package/dist/ui/diff.js +0 -185
  162. package/dist/ui/index.js +0 -6
  163. package/dist/ui/md-formatter.js +0 -212
  164. package/dist/ui/output.js +0 -13
  165. package/dist/ui/renderer.js +0 -141
  166. package/dist/ui/spinner.js +0 -70
  167. package/dist/ui/table.js +0 -144
package/dist/main.js CHANGED
@@ -2229,7 +2229,9 @@ var init_defaults = __esm(() => {
2229
2229
  navigationTimeout: 15000
2230
2230
  },
2231
2231
  ui: {
2232
- spinner: true
2232
+ spinner: true,
2233
+ toolStyle: "inline",
2234
+ toolComments: true
2233
2235
  },
2234
2236
  mcpServers: {
2235
2237
  context7: {
@@ -2416,6 +2418,7 @@ Command: {command}`,
2416
2418
  "plan.step_marked": "Step {step} marked as {status}",
2417
2419
  "plan.aborted": "Plan aborted",
2418
2420
  "plan.unknown_action": "Unknown plan action: {action}",
2421
+ "plan.updated": "Plan updated: {title} ({steps} steps)",
2419
2422
  "plan.acknowledged": "Plan {action}: acknowledged",
2420
2423
  "plan.step_status": "Step {step}: {status}",
2421
2424
  "plan.no_active": "No active plan",
@@ -2960,6 +2963,7 @@ var init_ru = __esm(() => {
2960
2963
  "plan.step_marked": "Шаг {step} отмечен как {status}",
2961
2964
  "plan.aborted": "План отменён",
2962
2965
  "plan.unknown_action": "Неизвестное действие плана: {action}",
2966
+ "plan.updated": "План обновлён: {title} ({steps} шагов)",
2963
2967
  "plan.acknowledged": "План {action}: принято",
2964
2968
  "plan.step_status": "Шаг {step}: {status}",
2965
2969
  "plan.no_active": "Нет активного плана",
@@ -3349,7 +3353,10 @@ function flatten(obj, prefix = "") {
3349
3353
  if (typeof val === "string") {
3350
3354
  result[fullKey] = val;
3351
3355
  } else if (typeof val === "object" && val !== null) {
3352
- result = { ...result, ...flatten(val, fullKey) };
3356
+ result = {
3357
+ ...result,
3358
+ ...flatten(val, fullKey)
3359
+ };
3353
3360
  }
3354
3361
  }
3355
3362
  return result;
@@ -3362,7 +3369,7 @@ function setLocale(locale) {
3362
3369
  function t(key, params) {
3363
3370
  const localeDict = flat[currentLocale];
3364
3371
  const enDict = flat["en"];
3365
- let template = localeDict?.[key] || enDict?.[key];
3372
+ let template = localeDict?.[key] ?? enDict?.[key] ?? key;
3366
3373
  if (!template)
3367
3374
  return key;
3368
3375
  if (params) {
@@ -3684,7 +3691,13 @@ __export(exports_config, {
3684
3691
  saveConfig: () => saveConfig,
3685
3692
  loadConfig: () => loadConfig
3686
3693
  });
3687
- import { existsSync as existsSync4, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
3694
+ import {
3695
+ existsSync as existsSync4,
3696
+ readFileSync as readFileSync3,
3697
+ unlinkSync,
3698
+ writeFileSync as writeFileSync3,
3699
+ mkdirSync as mkdirSync2
3700
+ } from "fs";
3688
3701
  import { join as join4, dirname } from "path";
3689
3702
  function restoreDangerousPatterns(patterns, defaults) {
3690
3703
  const fallback = Array.isArray(defaults) ? defaults : [];
@@ -3758,12 +3771,21 @@ function applyEnvVars(config) {
3758
3771
  result.logLevel = env.MMA_LOG_LEVEL;
3759
3772
  if (env.MMA_LOCALE)
3760
3773
  result.locale = env.MMA_LOCALE;
3761
- if (env.MMA_CONTEXT_WINDOW)
3762
- result.contextWindow = parseInt(env.MMA_CONTEXT_WINDOW, 10);
3763
- if (env.MMA_MAX_TOOL_ITERATIONS)
3764
- result.maxToolIterations = parseInt(env.MMA_MAX_TOOL_ITERATIONS, 10);
3765
- if (env.MMA_STUCK_THRESHOLD)
3766
- result.stuckThreshold = parseInt(env.MMA_STUCK_THRESHOLD, 10);
3774
+ if (env.MMA_CONTEXT_WINDOW) {
3775
+ const v = parseInt(env.MMA_CONTEXT_WINDOW, 10);
3776
+ if (!isNaN(v))
3777
+ result.contextWindow = v;
3778
+ }
3779
+ if (env.MMA_MAX_TOOL_ITERATIONS) {
3780
+ const v = parseInt(env.MMA_MAX_TOOL_ITERATIONS, 10);
3781
+ if (!isNaN(v))
3782
+ result.maxToolIterations = v;
3783
+ }
3784
+ if (env.MMA_STUCK_THRESHOLD) {
3785
+ const v = parseInt(env.MMA_STUCK_THRESHOLD, 10);
3786
+ if (!isNaN(v))
3787
+ result.stuckThreshold = v;
3788
+ }
3767
3789
  if (env.MMA_AUTO_PLAN)
3768
3790
  result.autoPlan = env.MMA_AUTO_PLAN === "true";
3769
3791
  if (env.MMA_MOE_ENABLED)
@@ -3823,7 +3845,9 @@ function saveConfig(config, configPath) {
3823
3845
  mkdirSync2(dir, { recursive: true });
3824
3846
  try {
3825
3847
  const encryptor = new ConfigEncryptor;
3826
- const encryptedConfig = encryptor.encrypt({ ...config });
3848
+ const encryptedConfig = encryptor.encrypt({
3849
+ ...config
3850
+ });
3827
3851
  writeFileSync3(configPath, JSON.stringify(encryptedConfig, regexReplacer, 2), "utf-8");
3828
3852
  } catch (e) {
3829
3853
  console.warn(t("config.encryption_warning", { error: e.message }));
@@ -4514,12 +4538,12 @@ class OpenAICompatProvider {
4514
4538
  };
4515
4539
  this.rateLimiter = createRateLimiter(config.rateLimits);
4516
4540
  }
4517
- async* chat(messages, tools) {
4541
+ async* chat(messages, tools, signal) {
4518
4542
  if (!this.rateLimiter.canMakeRequest()) {
4519
4543
  throw new Error(`Rate limit exceeded: ${this.rateLimiter.getConfig().maxRequestsPerMinute} requests per minute`);
4520
4544
  }
4521
4545
  this.rateLimiter.recordRequest();
4522
- const streamResult = this.doStream(messages, tools);
4546
+ const streamResult = this.doStream(messages, tools, signal);
4523
4547
  let hasToolCall = false;
4524
4548
  let hasText = false;
4525
4549
  let reasoningAcc = "";
@@ -4534,13 +4558,13 @@ class OpenAICompatProvider {
4534
4558
  yield chunk;
4535
4559
  }
4536
4560
  if (!hasToolCall && !hasText) {
4537
- const fallback = await this.doNonStreaming(messages, tools);
4561
+ const fallback = await this.doNonStreaming(messages, tools, signal);
4538
4562
  for (const chunk of fallback) {
4539
4563
  yield chunk;
4540
4564
  }
4541
4565
  }
4542
4566
  }
4543
- async* doStream(messages, tools) {
4567
+ async* doStream(messages, tools, signal) {
4544
4568
  const body = {
4545
4569
  model: this.model,
4546
4570
  messages,
@@ -4567,11 +4591,23 @@ class OpenAICompatProvider {
4567
4591
  const controller = new AbortController;
4568
4592
  const totalTimeoutMs = 120000;
4569
4593
  const timeoutId = setTimeout(() => controller.abort(), totalTimeoutMs);
4594
+ const abortSignal = (() => {
4595
+ if (!signal)
4596
+ return controller.signal;
4597
+ try {
4598
+ return AbortSignal.any([controller.signal, signal]);
4599
+ } catch {
4600
+ signal.addEventListener("abort", () => controller.abort(), {
4601
+ once: true
4602
+ });
4603
+ return controller.signal;
4604
+ }
4605
+ })();
4570
4606
  const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
4571
4607
  method: "POST",
4572
4608
  headers,
4573
4609
  body: JSON.stringify(body),
4574
- signal: controller.signal
4610
+ signal: abortSignal
4575
4611
  });
4576
4612
  if (!response.ok) {
4577
4613
  clearTimeout(timeoutId);
@@ -4670,7 +4706,7 @@ class OpenAICompatProvider {
4670
4706
  reader.releaseLock();
4671
4707
  }
4672
4708
  }
4673
- async doNonStreaming(messages, tools) {
4709
+ async doNonStreaming(messages, tools, signal) {
4674
4710
  const body = {
4675
4711
  model: this.model,
4676
4712
  messages,
@@ -4698,7 +4734,8 @@ class OpenAICompatProvider {
4698
4734
  const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
4699
4735
  method: "POST",
4700
4736
  headers,
4701
- body: JSON.stringify(body)
4737
+ body: JSON.stringify(body),
4738
+ signal
4702
4739
  });
4703
4740
  if (!response.ok) {
4704
4741
  const errorText = await response.text();
@@ -4792,7 +4829,7 @@ class OpenAICompatProvider {
4792
4829
  if (attempt < maxRetries) {
4793
4830
  const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
4794
4831
  const jitter = Math.random() * baseDelay * 0.1;
4795
- await this.sleep(delay + jitter);
4832
+ await this.sleep(delay + jitter, init.signal ?? undefined);
4796
4833
  }
4797
4834
  }
4798
4835
  throw lastError ?? new Error(t("error.llm_retries"));
@@ -4800,8 +4837,23 @@ class OpenAICompatProvider {
4800
4837
  isRetryable(status) {
4801
4838
  return status === 429 || status >= 500;
4802
4839
  }
4803
- sleep(ms) {
4804
- return new Promise((resolve) => setTimeout(resolve, ms));
4840
+ sleep(ms, signal) {
4841
+ return new Promise((resolve, reject) => {
4842
+ if (signal?.aborted) {
4843
+ reject(new DOMException("Aborted", "AbortError"));
4844
+ return;
4845
+ }
4846
+ let timer;
4847
+ const onAbort = () => {
4848
+ clearTimeout(timer);
4849
+ reject(new DOMException("Aborted", "AbortError"));
4850
+ };
4851
+ timer = setTimeout(() => {
4852
+ signal?.removeEventListener("abort", onAbort);
4853
+ resolve();
4854
+ }, ms);
4855
+ signal?.addEventListener("abort", onAbort, { once: true });
4856
+ });
4805
4857
  }
4806
4858
  }
4807
4859
  var init_openai_compat = __esm(() => {
@@ -5959,9 +6011,9 @@ function formatLine(line, maxNumWidth) {
5959
6011
  const num = line.type === "remove" ? line.oldNum : line.newNum;
5960
6012
  const numStr = num !== null ? String(num).padStart(maxNumWidth) : " ".repeat(maxNumWidth);
5961
6013
  if (line.type === "remove") {
5962
- return pc.red(`${pc.bgRed(`${numStr} - ${line.content}`)}`);
6014
+ return `${numStr} ${pc.red("-")} ${line.content}`;
5963
6015
  } else if (line.type === "add") {
5964
- return pc.green(`${pc.bgGreen(`${numStr} + ${line.content}`)}`);
6016
+ return `${numStr} ${pc.green("+")} ${line.content}`;
5965
6017
  } else if (line.content === "...") {
5966
6018
  return pc.dim(` ${" ".repeat(maxNumWidth)}...`);
5967
6019
  } else {
@@ -5975,14 +6027,13 @@ function generateDiff(oldContent, newContent) {
5975
6027
  `);
5976
6028
  const newLines = newContent.split(`
5977
6029
  `);
5978
- if (oldLines.length === 1 && oldLines[0] === "" && newLines.length === 1 && newLines[0] === "") {
5979
- return "";
5980
- }
5981
6030
  const diff = buildDiff(oldLines, newLines);
5982
6031
  if (diff.length === 0)
5983
6032
  return "";
5984
- const maxOldNum = Math.max(...diff.filter((l) => l.oldNum !== null).map((l) => l.oldNum));
5985
- const maxNewNum = Math.max(...diff.filter((l) => l.newNum !== null).map((l) => l.newNum));
6033
+ const oldNums = diff.filter((l) => l.oldNum !== null).map((l) => l.oldNum);
6034
+ const newNums = diff.filter((l) => l.newNum !== null).map((l) => l.newNum);
6035
+ const maxOldNum = oldNums.length > 0 ? Math.max(...oldNums) : 0;
6036
+ const maxNewNum = newNums.length > 0 ? Math.max(...newNums) : 0;
5986
6037
  const maxNumWidth = Math.max(String(maxOldNum).length, String(maxNewNum).length, 3);
5987
6038
  let lines = diff.map((l) => formatLine(l, maxNumWidth));
5988
6039
  if (lines.length > MAX_DIFF_LINES) {
@@ -6000,7 +6051,7 @@ function generateNewFileDiff(content) {
6000
6051
  const diffLines = [];
6001
6052
  for (let i = 0;i < lines.length; i++) {
6002
6053
  const numStr = String(i + 1).padStart(maxNumWidth);
6003
- diffLines.push(pc.green(`${pc.bgGreen(`${numStr} + ${lines[i]}`)}`));
6054
+ diffLines.push(`${numStr} ${pc.green("+")} ${lines[i]}`);
6004
6055
  }
6005
6056
  if (diffLines.length > MAX_DIFF_LINES) {
6006
6057
  const truncated = diffLines.slice(0, MAX_DIFF_LINES);
@@ -6018,7 +6069,7 @@ function generateDeleteDiff(content) {
6018
6069
  const diffLines = [];
6019
6070
  for (let i = 0;i < lines.length; i++) {
6020
6071
  const numStr = String(i + 1).padStart(maxNumWidth);
6021
- diffLines.push(pc.red(`${pc.bgRed(`${numStr} - ${lines[i]}`)}`));
6072
+ diffLines.push(`${numStr} ${pc.red("-")} ${lines[i]}`);
6022
6073
  }
6023
6074
  if (diffLines.length > MAX_DIFF_LINES) {
6024
6075
  const truncated = diffLines.slice(0, MAX_DIFF_LINES);
@@ -6030,10 +6081,7 @@ function generateDeleteDiff(content) {
6030
6081
  `);
6031
6082
  }
6032
6083
  function generateMoveDiff(fromPath, toPath) {
6033
- return [
6034
- pc.red(` - ${fromPath}`),
6035
- pc.green(` + ${toPath}`)
6036
- ].join(`
6084
+ return [pc.red(` - ${fromPath}`), pc.green(` + ${toPath}`)].join(`
6037
6085
  `);
6038
6086
  }
6039
6087
  var CONTEXT_LINES = 3, MAX_DIFF_LINES = 100;
@@ -6220,7 +6268,7 @@ var init_glob_tool = __esm(() => {
6220
6268
  });
6221
6269
 
6222
6270
  // src/tools/grep-tool.ts
6223
- import { execFileSync, execSync } from "child_process";
6271
+ import { execFileSync } from "child_process";
6224
6272
  import { resolve as resolve7 } from "path";
6225
6273
  function truncateLines(output) {
6226
6274
  const lines = output.split(`
@@ -6243,8 +6291,14 @@ var init_grep_tool = __esm(() => {
6243
6291
  type: "object",
6244
6292
  properties: {
6245
6293
  pattern: { type: "string", description: "Regex pattern to search" },
6246
- include: { type: "string", description: "File pattern to filter (e.g. *.ts)" },
6247
- path: { type: "string", description: "Directory to search (defaults to baseDir)" }
6294
+ include: {
6295
+ type: "string",
6296
+ description: "File pattern to filter (e.g. *.ts)"
6297
+ },
6298
+ path: {
6299
+ type: "string",
6300
+ description: "Directory to search (defaults to baseDir)"
6301
+ }
6248
6302
  },
6249
6303
  required: ["pattern"]
6250
6304
  },
@@ -6262,22 +6316,34 @@ var init_grep_tool = __esm(() => {
6262
6316
  maxBuffer: 1024 * 1024,
6263
6317
  cwd: ctx.baseDir
6264
6318
  });
6265
- return { success: true, output: truncateLines(output || t("file.no_matches")) };
6319
+ return {
6320
+ success: true,
6321
+ output: truncateLines(output || t("file.no_matches"))
6322
+ };
6266
6323
  } catch (e) {
6267
6324
  if (e.status === 1)
6268
6325
  return { success: true, output: t("file.no_matches") };
6269
6326
  try {
6270
- const cmd = `grep -rn "${pattern.replace(/"/g, "\\\"")}" "${searchPath}"`;
6271
- const output = execSync(cmd, {
6327
+ const grepArgs = ["-rn", pattern, searchPath];
6328
+ if (args.include) {
6329
+ grepArgs.push("--include", String(args.include));
6330
+ }
6331
+ const output = execFileSync("grep", grepArgs, {
6272
6332
  encoding: "utf-8",
6273
6333
  maxBuffer: 1024 * 1024,
6274
6334
  cwd: ctx.baseDir
6275
6335
  });
6276
- return { success: true, output: truncateLines(output || t("file.no_matches")) };
6336
+ return {
6337
+ success: true,
6338
+ output: truncateLines(output || t("file.no_matches"))
6339
+ };
6277
6340
  } catch (e2) {
6278
6341
  if (e2.status === 1)
6279
6342
  return { success: true, output: t("file.no_matches") };
6280
- return { success: false, output: t("error.grep_failed", { message: e2.message }) };
6343
+ return {
6344
+ success: false,
6345
+ output: t("error.grep_failed", { message: e2.message })
6346
+ };
6281
6347
  }
6282
6348
  }
6283
6349
  }
@@ -6457,6 +6523,7 @@ var init_move_file = __esm(() => {
6457
6523
  init_audit_log();
6458
6524
  init_session_isolation();
6459
6525
  init_diff();
6526
+ init_path_utils();
6460
6527
  moveFileTool = {
6461
6528
  name: "move_file",
6462
6529
  description: "Move or rename a file or directory.",
@@ -6473,8 +6540,8 @@ var init_move_file = __esm(() => {
6473
6540
  const fromPath = String(args.from);
6474
6541
  const toPath = String(args.to);
6475
6542
  const baseDir = resolve9(ctx.baseDir);
6476
- const fromResolved = resolve9(baseDir, normalize3(fromPath));
6477
- const toResolved = resolve9(baseDir, normalize3(toPath));
6543
+ const fromResolved = safeResolvePath(baseDir, normalize3(fromPath));
6544
+ const toResolved = safeResolvePath(baseDir, normalize3(toPath));
6478
6545
  const securityConfig = ctx.sessionContext ? getSessionSecurityConfig(ctx.config, ctx.sessionContext) : ctx.config.security;
6479
6546
  const maxFileOps = securityConfig?.maxFileOperations ?? 100;
6480
6547
  const currentCount = ctx.fileOperationsCount ?? 0;
@@ -6791,7 +6858,19 @@ class ProcessRegistry {
6791
6858
  }
6792
6859
  this.children.set(id, child);
6793
6860
  entry.pid = child.pid ?? 0;
6794
- const decoder = platform() === "win32" ? new TextDecoder("ibm866") : null;
6861
+ const decoder = platform() === "win32" ? (() => {
6862
+ try {
6863
+ const cpOut = __require("child_process").execSync("chcp.com", {
6864
+ encoding: "utf-8",
6865
+ timeout: 2000,
6866
+ windowsHide: true
6867
+ }).toString();
6868
+ const m = cpOut.match(/(\d+)/);
6869
+ if (m)
6870
+ return new TextDecoder("ibm" + m[1]);
6871
+ } catch {}
6872
+ return null;
6873
+ })() : null;
6795
6874
  let buf = "";
6796
6875
  const pushLine = (line) => {
6797
6876
  if (entry.log.length >= MAX_LOG_LINES) {
@@ -8805,22 +8884,6 @@ class StuckDetector {
8805
8884
  }
8806
8885
  return "";
8807
8886
  }
8808
- checkOffTrack(toolName, call) {
8809
- if (!this.currentStepDescription)
8810
- return null;
8811
- const toolArgStr = JSON.stringify(call.arguments).toLowerCase();
8812
- const pathInStep = (this.currentStepDescription.match(/\b[\w./-]+\.[a-z]+/gi) || []).map((p) => p.toLowerCase());
8813
- const pathInCall = (toolArgStr.match(/\b[\w./-]+\.[a-z]+/gi) || []).map((p) => p.toLowerCase());
8814
- const overlaps = pathInCall.some((p) => pathInStep.some((s) => p.includes(s) || s.includes(p)));
8815
- if (!overlaps && pathInStep.length > 0 && pathInCall.length > 0) {
8816
- return t("exec.off_track", {
8817
- stepId: String(this.currentStepId),
8818
- description: this.currentStepDescription,
8819
- tool: toolName
8820
- });
8821
- }
8822
- return null;
8823
- }
8824
8887
  reset() {
8825
8888
  this.currentStepId = null;
8826
8889
  this.iterationsOnCurrentStep = 0;
@@ -9382,18 +9445,29 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
9382
9445
  ];
9383
9446
  const verification = await verifier.verifyMoEManifest(plan, config, knownTags);
9384
9447
  onPhase?.("thinking");
9385
- const verifyResult = await orchestrator.verifyAndMerge({
9386
- plan,
9387
- results: planResults.results.map((r) => ({
9388
- subtaskId: r.subtaskId,
9389
- success: r.success,
9390
- summary: r.summary,
9391
- result: r.result,
9392
- error: r.error
9393
- })),
9394
- verifierErrors: verification.errors,
9395
- verifierWarnings: verification.warnings
9396
- });
9448
+ let verifyResult;
9449
+ try {
9450
+ verifyResult = await orchestrator.verifyAndMerge({
9451
+ plan,
9452
+ results: planResults.results.map((r) => ({
9453
+ subtaskId: r.subtaskId,
9454
+ success: r.success,
9455
+ summary: r.summary,
9456
+ result: r.result,
9457
+ error: r.error
9458
+ })),
9459
+ verifierErrors: verification.errors,
9460
+ verifierWarnings: verification.warnings
9461
+ });
9462
+ } catch (err) {
9463
+ onPhase?.("done");
9464
+ return {
9465
+ success: false,
9466
+ text: `MoE verifyAndMerge crashed: ${err.message}`,
9467
+ error: err.message,
9468
+ iterationCount: 0
9469
+ };
9470
+ }
9397
9471
  onPhase?.("done");
9398
9472
  const outputLines = [`## MoE Execution Results
9399
9473
  `];
@@ -9547,6 +9621,18 @@ var init_store = __esm(() => {
9547
9621
 
9548
9622
  // src/core/agent.ts
9549
9623
  import { join as join10 } from "path";
9624
+ function isToolCallJson(text) {
9625
+ const trimmed = text.trim();
9626
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
9627
+ try {
9628
+ JSON.parse(trimmed);
9629
+ return true;
9630
+ } catch {
9631
+ return false;
9632
+ }
9633
+ }
9634
+ return false;
9635
+ }
9550
9636
 
9551
9637
  class Agent {
9552
9638
  deps;
@@ -9734,7 +9820,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
9734
9820
  const textChunks = [];
9735
9821
  this.emitPhase(iteration, "thinking", onPhase);
9736
9822
  try {
9737
- for await (const chunk of llmProvider.chat(history, allTools)) {
9823
+ for await (const chunk of llmProvider.chat(history, allTools, this.abortController?.signal)) {
9738
9824
  if (this.shutdownRequested)
9739
9825
  break;
9740
9826
  if (chunk.type === "text" && chunk.content) {
@@ -9776,6 +9862,10 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
9776
9862
  }
9777
9863
  }
9778
9864
  } catch (err) {
9865
+ if (this.shutdownRequested || err?.name === "AbortError") {
9866
+ logger.info("LLM call aborted (interrupt)");
9867
+ break;
9868
+ }
9779
9869
  logger.error(`LLM call failed: ${err.message}`);
9780
9870
  slog.logError(err.message);
9781
9871
  pluginManager.runOnError({ iteration, logger }, err);
@@ -9788,7 +9878,12 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
9788
9878
  } finally {
9789
9879
  this.emitPhase(iteration, "done", onPhase);
9790
9880
  }
9791
- if (!sawToolCall && textChunks.length > 0) {
9881
+ if (this.shutdownRequested) {
9882
+ break;
9883
+ }
9884
+ const toolComments = this.deps.config.ui?.toolComments ?? true;
9885
+ const showText = textChunks.length > 0 && (!sawToolCall || toolComments && !isToolCallJson(textContent));
9886
+ if (showText) {
9792
9887
  for (const chunk of textChunks) {
9793
9888
  const textOut = pluginManager.runOnText({ iteration, logger }, chunk);
9794
9889
  onChunk?.(textOut);
@@ -10080,6 +10175,7 @@ ${taskReminder}</system-summary>`
10080
10175
  });
10081
10176
  this.deps.llmProvider = newProvider;
10082
10177
  this.deps.toolExecutor.updateProvider(newProvider);
10178
+ this.deps.toolExecutor.ctx.llmProvider = newProvider;
10083
10179
  const newTokenCounter = new TokenCounter2(config.model);
10084
10180
  this.deps.contextManager.resize(config.contextWindow, config.contextBudget, newTokenCounter);
10085
10181
  this.deps.config = config;
@@ -10302,6 +10398,7 @@ class ContextManager {
10302
10398
  return totalTokens > this.budget.history * this.compactionThreshold;
10303
10399
  }
10304
10400
  compact() {
10401
+ this.iterationsSinceCompaction = 0;
10305
10402
  if (this.messages.length <= KEEP_LAST_N * 2)
10306
10403
  return;
10307
10404
  this.compactionCount++;
@@ -10320,7 +10417,7 @@ class ContextManager {
10320
10417
  if (this.errorFacts.length > 0) {
10321
10418
  parts.push(`[Errors: ${this.errorFacts.slice(-3).join("; ")}]`);
10322
10419
  }
10323
- const triedAndFailed = extractTriedAndFailed(this.messages);
10420
+ const triedAndFailed = extractTriedAndFailed(oldTurns);
10324
10421
  if (triedAndFailed.length > 0) {
10325
10422
  const lines = triedAndFailed.map((t2) => `- ${t2.tool}(${t2.args}): ${t2.error} (failed ${t2.count}x)`);
10326
10423
  parts.push(`[Already tried & failed — do NOT repeat:]
@@ -10956,6 +11053,8 @@ var init_subagent = __esm(() => {
10956
11053
  const subContextManager = new ContextManager(ctx.config.contextWindow, ctx.config.contextBudget);
10957
11054
  const subPluginManager = new PluginManager;
10958
11055
  const hallucinationDetector = new HallucinationDetector(ctx.baseDir, ctx.llmProvider);
11056
+ const parentScope = ctx.scope;
11057
+ ctx.toolExecutor.setScope(scope || { allowed_files: [], read_only_files: [] });
10959
11058
  const systemPrompt = {
10960
11059
  content: `You are a sub-agent working on a specific task. ${context ? `Context: ${context}` : ""}`,
10961
11060
  priority: "critical",
@@ -10980,21 +11079,24 @@ var init_subagent = __esm(() => {
10980
11079
  const fullTask = context ? `${task}
10981
11080
 
10982
11081
  Context: ${context}` : task;
10983
- const result = await subAgent.run(fullTask);
10984
- if (result.success) {
10985
- return {
11082
+ let scopeRestored = false;
11083
+ try {
11084
+ const result = await subAgent.run(fullTask);
11085
+ return result.success ? {
10986
11086
  success: true,
10987
11087
  output: `Sub-agent completed:
10988
11088
  ${result.text}
10989
11089
 
10990
11090
  Iterations: ${result.iterationCount}`
10991
- };
10992
- } else {
10993
- return {
11091
+ } : {
10994
11092
  success: false,
10995
11093
  output: `Sub-agent failed: ${result.error}
10996
11094
  Partial output: ${result.text}`
10997
11095
  };
11096
+ } finally {
11097
+ if (!scopeRestored) {
11098
+ ctx.toolExecutor.setScope(parentScope || { allowed_files: [], read_only_files: [] });
11099
+ }
10998
11100
  }
10999
11101
  } catch (e) {
11000
11102
  return { success: false, output: `Sub-agent error: ${e.message}` };
@@ -11716,19 +11818,25 @@ class MCPClient {
11716
11818
  env: { ...process.env, ...this.config.env },
11717
11819
  stdio: ["pipe", "pipe", "pipe"]
11718
11820
  });
11821
+ let _resolved = false;
11719
11822
  child.on("error", (err) => {
11720
11823
  this._connected = false;
11721
- reject(err);
11824
+ if (!_resolved) {
11825
+ _resolved = true;
11826
+ reject(err);
11827
+ }
11722
11828
  });
11723
11829
  child.on("exit", (code) => {
11724
11830
  this._connected = false;
11725
- if (code !== 0) {
11831
+ if (code !== 0 && !_resolved) {
11832
+ _resolved = true;
11726
11833
  reject(new Error(`MCP server exited with code ${code}`));
11727
11834
  }
11728
11835
  });
11729
11836
  child.on("spawn", () => {
11730
11837
  this._connected = true;
11731
11838
  this.process = child;
11839
+ _resolved = true;
11732
11840
  resolve12();
11733
11841
  });
11734
11842
  });
@@ -12114,8 +12222,14 @@ var init_search_history = __esm(() => {
12114
12222
  type: "object",
12115
12223
  properties: {
12116
12224
  query: { type: "string", description: "Search query" },
12117
- maxResults: { type: "number", description: "Maximum results (default 5)" },
12118
- sessionId: { type: "string", description: "Optional: limit search to a specific session" }
12225
+ maxResults: {
12226
+ type: "number",
12227
+ description: "Maximum results (default 5)"
12228
+ },
12229
+ sessionId: {
12230
+ type: "string",
12231
+ description: "Optional: limit search to a specific session"
12232
+ }
12119
12233
  },
12120
12234
  required: ["query"]
12121
12235
  },
@@ -12127,7 +12241,10 @@ var init_search_history = __esm(() => {
12127
12241
  const results = [];
12128
12242
  try {
12129
12243
  if (!fs.existsSync(sessionDir)) {
12130
- return { success: true, output: t("tool.no_sessions_dir", { dir: sessionDir }) };
12244
+ return {
12245
+ success: true,
12246
+ output: t("tool.no_sessions_dir", { dir: sessionDir })
12247
+ };
12131
12248
  }
12132
12249
  const entries = fs.readdirSync(sessionDir, { withFileTypes: true });
12133
12250
  for (const entry of entries) {
@@ -12143,10 +12260,19 @@ var init_search_history = __esm(() => {
12143
12260
  if (results.length === 0) {
12144
12261
  return { success: true, output: t("tool.no_history", { query }) };
12145
12262
  }
12146
- return { success: true, output: t("tool.history_results", { query, results: results.join(`
12147
- `) }) };
12263
+ return {
12264
+ success: true,
12265
+ output: t("tool.history_results", {
12266
+ query,
12267
+ results: results.join(`
12268
+ `)
12269
+ })
12270
+ };
12148
12271
  } catch (err) {
12149
- return { success: true, output: t("tool.history_error", { error: String(err) }) };
12272
+ return {
12273
+ success: false,
12274
+ output: t("tool.history_error", { error: String(err) })
12275
+ };
12150
12276
  }
12151
12277
  }
12152
12278
  };
@@ -12963,13 +13089,13 @@ async function readClipboardImage() {
12963
13089
  }
12964
13090
  async function readClipboardFallback() {
12965
13091
  const { platform: platform3 } = await import("os");
12966
- const { execSync: execSync2 } = await import("child_process");
13092
+ const { execSync } = await import("child_process");
12967
13093
  const { readFileSync: readFileSync13, unlinkSync: unlinkSync3 } = await import("fs");
12968
13094
  const { join: join16 } = await import("path");
12969
13095
  const tmpPath = join16(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
12970
13096
  try {
12971
13097
  if (platform3() === "linux") {
12972
- execSync2(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, { timeout: 5000 });
13098
+ execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, { timeout: 5000 });
12973
13099
  } else {
12974
13100
  return null;
12975
13101
  }
@@ -13282,6 +13408,8 @@ import { resolve as resolve13, extname as extname4, join as join17 } from "path"
13282
13408
  class LintOnWritePlugin {
13283
13409
  name = "lint-on-write";
13284
13410
  priority = 10;
13411
+ _checkPromise = null;
13412
+ _checkTimestamp = 0;
13285
13413
  async onAfterTool(ctx, call, result) {
13286
13414
  if (call.name !== "write_file" && call.name !== "edit_file") {
13287
13415
  return;
@@ -13364,8 +13492,8 @@ class LintOnWritePlugin {
13364
13492
  return;
13365
13493
  }
13366
13494
  const now = Date.now();
13367
- if (projectTypeCheckPromise && now - projectTypeCheckTimestamp < TYPE_CHECK_DEBOUNCE_MS) {
13368
- const error2 = await projectTypeCheckPromise;
13495
+ if (this._checkPromise && now - this._checkTimestamp < TYPE_CHECK_DEBOUNCE_MS) {
13496
+ const error2 = await this._checkPromise;
13369
13497
  if (error2) {
13370
13498
  result.output += `
13371
13499
 
@@ -13373,9 +13501,9 @@ class LintOnWritePlugin {
13373
13501
  }
13374
13502
  return;
13375
13503
  }
13376
- projectTypeCheckTimestamp = now;
13377
- projectTypeCheckPromise = this.runTscCheck(ctx.baseDir);
13378
- const error = await projectTypeCheckPromise;
13504
+ this._checkTimestamp = now;
13505
+ this._checkPromise = this.runTscCheck(ctx.baseDir);
13506
+ const error = await this._checkPromise;
13379
13507
  if (error) {
13380
13508
  result.output += `
13381
13509
 
@@ -13438,7 +13566,7 @@ function runAsync(command, cwd, timeoutMs) {
13438
13566
  });
13439
13567
  });
13440
13568
  }
13441
- var projectTypeCheckPromise = null, projectTypeCheckTimestamp = 0, TYPE_CHECK_DEBOUNCE_MS = 2000, plugin;
13569
+ var TYPE_CHECK_DEBOUNCE_MS = 2000, plugin;
13442
13570
  var init_lint_on_write = __esm(() => {
13443
13571
  plugin = new LintOnWritePlugin;
13444
13572
  });
@@ -13490,7 +13618,7 @@ class PlanCreator {
13490
13618
  const stepCount = stepDescriptions.length;
13491
13619
  return {
13492
13620
  id: generatePlanId(),
13493
- title: `[${stepCount} ст.] ${title}`,
13621
+ title: `[${stepCount}] ${title}`,
13494
13622
  steps: stepDescriptions.map((desc, i) => ({
13495
13623
  id: i + 1,
13496
13624
  description: desc,
@@ -13737,8 +13865,7 @@ var init_plan_coverage = __esm(() => {
13737
13865
  "css",
13738
13866
  "scss",
13739
13867
  "less",
13740
- "html",
13741
- "jsx"
13868
+ "html"
13742
13869
  ]);
13743
13870
  });
13744
13871
 
@@ -13757,6 +13884,7 @@ class ExecutionModule {
13757
13884
  lastRecoveryIteration = -STUCK_RECOVERY_COOLDOWN;
13758
13885
  consecutivePlanWarnings = 0;
13759
13886
  lastStepId = -1;
13887
+ _auditSkipsRemaining = 0;
13760
13888
  constructor(baseDir, stuckThreshold = 8) {
13761
13889
  this.baseDir = baseDir;
13762
13890
  this.verifier = new StepVerifier(baseDir);
@@ -13767,6 +13895,7 @@ class ExecutionModule {
13767
13895
  setPlan(plan) {
13768
13896
  this.tracker = new PlanTracker(plan);
13769
13897
  this.persister.save(plan);
13898
+ this._auditSkipsRemaining = 0;
13770
13899
  }
13771
13900
  restorePlan() {
13772
13901
  const plan = this.persister.load();
@@ -13774,6 +13903,7 @@ class ExecutionModule {
13774
13903
  return false;
13775
13904
  this.tracker = new PlanTracker(plan);
13776
13905
  this.tracker.syncCurrentStep();
13906
+ this._auditSkipsRemaining = 1;
13777
13907
  return true;
13778
13908
  }
13779
13909
  getTracker() {
@@ -13785,6 +13915,10 @@ class ExecutionModule {
13785
13915
  async runFinalAudit() {
13786
13916
  if (!this.tracker)
13787
13917
  return null;
13918
+ if (this._auditSkipsRemaining > 0) {
13919
+ this._auditSkipsRemaining--;
13920
+ return null;
13921
+ }
13788
13922
  const plan = this.tracker.getPlan();
13789
13923
  const audit = await this.auditor.audit(plan);
13790
13924
  const pendingSteps = plan.steps.filter((s) => s.status !== "done" && s.status !== "skipped").map((s) => `${s.id}. ${s.description}`);
@@ -13848,7 +13982,10 @@ Write CONCRETE steps with exact file paths and commands:
13848
13982
  const plan = PlanCreator.createPlan(title, steps, this.baseDir);
13849
13983
  this.setPlan(plan);
13850
13984
  const display = PlanCreator.toPromptBlock(plan, 0);
13851
- let output = t("plan.created", { title, steps: String(steps.length) });
13985
+ let output = t("plan.created", {
13986
+ title,
13987
+ steps: String(steps.length)
13988
+ });
13852
13989
  let displayOut = display;
13853
13990
  const taskText = this.getTaskText(_ctx);
13854
13991
  if (taskText) {
@@ -13897,6 +14034,22 @@ ${progress}`,
13897
14034
  display
13898
14035
  };
13899
14036
  }
14037
+ if (action === "update" && Array.isArray(args.steps) && args.steps.length > 0 && this.tracker) {
14038
+ const title = String(args.title || this.tracker.getPlan().title);
14039
+ const steps = args.steps.map(String);
14040
+ const plan = PlanCreator.createPlan(title, steps, this.baseDir);
14041
+ this.setPlan(plan);
14042
+ const display = PlanCreator.toPromptBlock(plan, 0);
14043
+ const output = t("plan.updated", {
14044
+ title,
14045
+ steps: String(steps.length)
14046
+ });
14047
+ return {
14048
+ success: true,
14049
+ output,
14050
+ display
14051
+ };
14052
+ }
13900
14053
  if (action === "abort") {
13901
14054
  this.tracker = null;
13902
14055
  this.persister.clear();
@@ -13943,9 +14096,20 @@ ${progress}`,
13943
14096
  };
13944
14097
  }
13945
14098
  if (action === "done") {
14099
+ if (!currentStep) {
14100
+ return { success: false, output: t("plan.step_not_found") };
14101
+ }
14102
+ this.tracker.updateStepStatus(currentStep.id, "done");
14103
+ this.tracker.syncCurrentStep();
14104
+ this.persister.save(this.tracker.getPlan());
14105
+ const display = this.tracker.toPromptBlock();
13946
14106
  return {
13947
14107
  success: true,
13948
- output: t("todo.marked_done", { count: "1" })
14108
+ output: t("plan.step_status", {
14109
+ step: String(currentStep.id),
14110
+ status: "done"
14111
+ }),
14112
+ display
13949
14113
  };
13950
14114
  }
13951
14115
  if (action === "list") {
@@ -14033,8 +14197,10 @@ Tool "${this.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
14033
14197
  }
14034
14198
  const hints = this.stuckDetector.getHints();
14035
14199
  if (hints.length > 0 && ctx.contextManager) {
14036
- const hintMsg = t("exec.hints", { hints: hints.map((h) => `- ${h}`).join(`
14037
- `) });
14200
+ const hintMsg = t("exec.hints", {
14201
+ hints: hints.map((h) => `- ${h}`).join(`
14202
+ `)
14203
+ });
14038
14204
  ctx.contextManager.addMessage({
14039
14205
  role: "user",
14040
14206
  content: `<system-summary>${hintMsg}</system-summary>`
@@ -14122,7 +14288,10 @@ Tool "${this.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
14122
14288
  const file = this.stuckDetector.getExcessiveRewriteFile();
14123
14289
  const count = this.stuckDetector.getFileRewriteCount(file);
14124
14290
  if (ctx.onMeta) {
14125
- ctx.onMeta(t("exec.file_rewrite_warning", { file, count: String(count) }));
14291
+ ctx.onMeta(t("exec.file_rewrite_warning", {
14292
+ file,
14293
+ count: String(count)
14294
+ }));
14126
14295
  }
14127
14296
  }
14128
14297
  }
@@ -14399,6 +14568,7 @@ import { gzipSync } from "zlib";
14399
14568
  class SessionStore {
14400
14569
  baseDir;
14401
14570
  encryptor = null;
14571
+ _metaCache = new Map;
14402
14572
  constructor(baseDir, encryptionConfig) {
14403
14573
  this.baseDir = baseDir;
14404
14574
  if (encryptionConfig?.enabled) {
@@ -14434,6 +14604,7 @@ class SessionStore {
14434
14604
  return existsSync29(this.metaPath(id));
14435
14605
  }
14436
14606
  saveMeta(id, meta) {
14607
+ this._metaCache.set(id, meta);
14437
14608
  const dir = this.sessionDir(id);
14438
14609
  mkdirSync12(dir, { recursive: true });
14439
14610
  const content = JSON.stringify(meta, null, 2);
@@ -14444,13 +14615,18 @@ class SessionStore {
14444
14615
  }
14445
14616
  }
14446
14617
  loadMeta(id) {
14618
+ const cached = this._metaCache.get(id);
14619
+ if (cached)
14620
+ return cached;
14447
14621
  const path = this.metaPath(id);
14448
14622
  if (!existsSync29(path))
14449
14623
  return null;
14450
14624
  try {
14451
14625
  const raw = readFileSync17(path, "utf-8");
14452
14626
  const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
14453
- return JSON.parse(content);
14627
+ const meta = JSON.parse(content);
14628
+ this._metaCache.set(id, meta);
14629
+ return meta;
14454
14630
  } catch {
14455
14631
  return null;
14456
14632
  }
@@ -14481,11 +14657,23 @@ class SessionStore {
14481
14657
  const raw = readFileSync17(path, "utf-8");
14482
14658
  const lines = raw.split(`
14483
14659
  `).filter(Boolean);
14660
+ const parseLine = (line) => {
14661
+ try {
14662
+ return JSON.parse(line);
14663
+ } catch {
14664
+ return null;
14665
+ }
14666
+ };
14484
14667
  if (this.encryptor?.isEnabled()) {
14485
- const decryptedLines = lines.map((line) => this.encryptor.decryptFileContent(line));
14486
- return decryptedLines.map((line) => JSON.parse(line));
14668
+ return lines.map((line) => {
14669
+ try {
14670
+ return this.encryptor.decryptFileContent(line);
14671
+ } catch {
14672
+ return null;
14673
+ }
14674
+ }).filter((l) => l !== null).map(parseLine).filter((m) => m !== null);
14487
14675
  }
14488
- return lines.map((line) => JSON.parse(line));
14676
+ return lines.map(parseLine).filter((m) => m !== null);
14489
14677
  } catch {
14490
14678
  return [];
14491
14679
  }
@@ -14510,11 +14698,23 @@ class SessionStore {
14510
14698
  const raw = readFileSync17(path, "utf-8");
14511
14699
  const lines = raw.split(`
14512
14700
  `).filter(Boolean);
14701
+ const parseLine = (line) => {
14702
+ try {
14703
+ return JSON.parse(line);
14704
+ } catch {
14705
+ return null;
14706
+ }
14707
+ };
14513
14708
  if (this.encryptor?.isEnabled()) {
14514
- const decryptedLines = lines.map((line) => this.encryptor.decryptFileContent(line));
14515
- return decryptedLines.map((line) => JSON.parse(line));
14709
+ return lines.map((line) => {
14710
+ try {
14711
+ return this.encryptor.decryptFileContent(line);
14712
+ } catch {
14713
+ return null;
14714
+ }
14715
+ }).filter((l) => l !== null).map(parseLine).filter((e) => e !== null);
14516
14716
  }
14517
- return lines.map((line) => JSON.parse(line));
14717
+ return lines.map(parseLine).filter((e) => e !== null);
14518
14718
  } catch {
14519
14719
  return [];
14520
14720
  }
@@ -14535,6 +14735,7 @@ class SessionStore {
14535
14735
  return sessions;
14536
14736
  }
14537
14737
  deleteSession(id) {
14738
+ this._metaCache.delete(id);
14538
14739
  const dir = this.sessionDir(id);
14539
14740
  if (existsSync29(dir)) {
14540
14741
  rmSync(dir, { recursive: true, force: true });
@@ -15122,7 +15323,7 @@ var init_browser2 = __esm(() => {
15122
15323
  });
15123
15324
 
15124
15325
  // src/modules/lsp/client.ts
15125
- import { spawn as spawn5, execSync as execSync2 } from "child_process";
15326
+ import { spawn as spawn5, execSync } from "child_process";
15126
15327
  import { resolve as resolve16 } from "path";
15127
15328
 
15128
15329
  class LspClient {
@@ -15179,7 +15380,7 @@ class LspClient {
15179
15380
  async startServer(config, baseDir) {
15180
15381
  if (config.autoInstall === false) {
15181
15382
  try {
15182
- execSync2(`where ${config.command}`, { stdio: "pipe", timeout: 3000 });
15383
+ execSync(`where ${config.command}`, { stdio: "pipe", timeout: 3000 });
15183
15384
  } catch {
15184
15385
  throw new Error(`${config.command} not found in PATH`);
15185
15386
  }
@@ -15227,6 +15428,11 @@ class LspClient {
15227
15428
  continue;
15228
15429
  }
15229
15430
  this.contentLength = parseInt(match[1], 10);
15431
+ if (this.contentLength > 10485760) {
15432
+ this.buffer = this.buffer.slice(headerEnd + 4);
15433
+ this.contentLength = -1;
15434
+ continue;
15435
+ }
15230
15436
  this.buffer = this.buffer.slice(headerEnd + 4);
15231
15437
  }
15232
15438
  if (this.buffer.length < this.contentLength)
@@ -16143,7 +16349,10 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
16143
16349
  const hallucinationDetector = new HallucinationDetector(baseDir, llmProvider);
16144
16350
  const moduleRegistry = new ModuleRegistry;
16145
16351
  const execModule = new ExecutionModule(baseDir, config.stuckThreshold);
16146
- execModule.restorePlan();
16352
+ const activeMeta = sessionManager.getActiveMeta();
16353
+ if (activeMeta && activeMeta.messageCount > 0) {
16354
+ execModule.restorePlan();
16355
+ }
16147
16356
  moduleRegistry.register(execModule);
16148
16357
  const sessionModule = new SessionModule(sessionManager);
16149
16358
  moduleRegistry.register(sessionModule);
@@ -16203,7 +16412,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
16203
16412
  pluginManager.register(plugin2);
16204
16413
  const pluginLoader = new PluginLoader;
16205
16414
  const globalPluginsDir = join26(homedir11(), ".mma", "plugins");
16206
- const projectPluginsDir = join26(dir, ".mma", "plugins");
16415
+ const projectPluginsDir = join26(baseDir, ".mma", "plugins");
16207
16416
  pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
16208
16417
  pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
16209
16418
  contextManager.onCompact = (summary) => {
@@ -16309,7 +16518,7 @@ function ansiRegex({ onlyFirst = false } = {}) {
16309
16518
  return new RegExp(pattern, onlyFirst ? undefined : "g");
16310
16519
  }
16311
16520
 
16312
- // node_modules/strip-ansi/index.js
16521
+ // node_modules/string-width/node_modules/strip-ansi/index.js
16313
16522
  function stripAnsi(string) {
16314
16523
  if (typeof string !== "string") {
16315
16524
  throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
@@ -16408,135 +16617,65 @@ var init_get_east_asian_width = __esm(() => {
16408
16617
  init_lookup();
16409
16618
  });
16410
16619
 
16620
+ // node_modules/emoji-regex/index.js
16621
+ var require_emoji_regex = __commonJS((exports, module) => {
16622
+ module.exports = () => {
16623
+ return /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26D3\uFE0F?(?:\u200D\uD83D\uDCA5)?|\u26F9(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF43\uDF45-\uDF4A\uDF4C-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDF44(?:\u200D\uD83D\uDFEB)?|\uDF4B(?:\u200D\uD83D\uDFE9)?|\uDFC3(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E-\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4\uDEB5](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE41\uDE43\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED8\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC26(?:\u200D(?:\u2B1B|\uD83D\uDD25))?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFE])))?))?|\uDD75(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|\uDE42(?:\u200D[\u2194\u2195]\uFE0F?)?|\uDEB6(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3C-\uDD3E\uDDB8\uDDB9\uDDCD\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE8A\uDE8E-\uDEC2\uDEC6\uDEC8\uDECD-\uDEDC\uDEDF-\uDEEA\uDEEF]|\uDDCE(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1|\uDDD1\u200D\uD83E\uDDD2(?:\u200D\uD83E\uDDD2)?|\uDDD2(?:\u200D\uD83E\uDDD2)?))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g;
16624
+ };
16625
+ });
16626
+
16411
16627
  // node_modules/string-width/index.js
16412
- function isDoubleWidthNonRgiEmojiSequence(segment) {
16413
- if (segment.length > 50) {
16414
- return false;
16415
- }
16416
- if (unqualifiedKeycapRegex.test(segment)) {
16417
- return true;
16418
- }
16419
- if (segment.includes("‍")) {
16420
- const pictographics = segment.match(extendedPictographicRegex);
16421
- return pictographics !== null && pictographics.length >= 2;
16422
- }
16423
- return false;
16424
- }
16425
- function baseVisible(segment) {
16426
- return segment.replace(leadingNonPrintingRegex, "");
16427
- }
16428
- function isZeroWidthCluster(segment) {
16429
- return zeroWidthClusterRegex.test(segment);
16430
- }
16431
- function isHangulLeadingJamo(codePoint) {
16432
- return codePoint >= 4352 && codePoint <= 4447 || codePoint >= 43360 && codePoint <= 43388;
16433
- }
16434
- function isHangulVowelJamo(codePoint) {
16435
- return codePoint >= 4448 && codePoint <= 4519 || codePoint >= 55216 && codePoint <= 55238;
16436
- }
16437
- function isHangulTrailingJamo(codePoint) {
16438
- return codePoint >= 4520 && codePoint <= 4607 || codePoint >= 55243 && codePoint <= 55291;
16439
- }
16440
- function isHangulJamo(codePoint) {
16441
- return isHangulLeadingJamo(codePoint) || isHangulVowelJamo(codePoint) || isHangulTrailingJamo(codePoint);
16442
- }
16443
- function hangulClusterWidth(visibleSegment, eastAsianWidthOptions) {
16444
- const codePoints = [];
16445
- for (const character of visibleSegment) {
16446
- if (zeroWidthClusterRegex.test(character)) {
16447
- continue;
16448
- }
16449
- codePoints.push(character.codePointAt(0));
16450
- }
16451
- if (codePoints.length === 0) {
16452
- return;
16453
- }
16454
- let width = 0;
16455
- for (let index = 0;index < codePoints.length; index++) {
16456
- const codePoint = codePoints[index];
16457
- if (!isHangulJamo(codePoint)) {
16458
- if (width === 0) {
16459
- return;
16460
- }
16461
- for (let remaining = index;remaining < codePoints.length; remaining++) {
16462
- width += eastAsianWidth(codePoints[remaining], eastAsianWidthOptions);
16463
- }
16464
- return width;
16465
- }
16466
- if (isHangulLeadingJamo(codePoint) && isHangulVowelJamo(codePoints[index + 1])) {
16467
- width += 2;
16468
- index += isHangulTrailingJamo(codePoints[index + 2]) ? 2 : 1;
16469
- continue;
16470
- }
16471
- width += eastAsianWidth(codePoint, eastAsianWidthOptions);
16472
- }
16473
- return width;
16474
- }
16475
- function trailingWidth(visibleSegment, eastAsianWidthOptions) {
16476
- let extra = 0;
16477
- let first = true;
16478
- for (const character of visibleSegment) {
16479
- if (first) {
16480
- first = false;
16481
- continue;
16482
- }
16483
- if (spacingMarkRegex.test(character) || character >= "＀" && character <= "￯") {
16484
- extra += eastAsianWidth(character.codePointAt(0), eastAsianWidthOptions);
16485
- }
16486
- }
16487
- return extra;
16488
- }
16489
- function stringWidth(input, options = {}) {
16490
- if (typeof input !== "string" || input.length === 0) {
16628
+ function stringWidth(string, options = {}) {
16629
+ if (typeof string !== "string" || string.length === 0) {
16491
16630
  return 0;
16492
16631
  }
16493
16632
  const {
16494
16633
  ambiguousIsNarrow = true,
16495
16634
  countAnsiEscapeCodes = false
16496
16635
  } = options;
16497
- let string = input;
16498
- if (!countAnsiEscapeCodes && (string.includes("\x1B") || string.includes("›"))) {
16636
+ if (!countAnsiEscapeCodes) {
16499
16637
  string = stripAnsi(string);
16500
16638
  }
16501
16639
  if (string.length === 0) {
16502
16640
  return 0;
16503
16641
  }
16504
- if (/^[\u0020-\u007E]*$/.test(string)) {
16505
- return string.length;
16506
- }
16507
16642
  let width = 0;
16508
16643
  const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow };
16509
- for (const { segment } of segmenter.segment(string)) {
16510
- if (isZeroWidthCluster(segment)) {
16644
+ for (const { segment: character } of segmenter.segment(string)) {
16645
+ const codePoint = character.codePointAt(0);
16646
+ if (codePoint <= 31 || codePoint >= 127 && codePoint <= 159) {
16511
16647
  continue;
16512
16648
  }
16513
- if (rgiEmojiRegex.test(segment) || isDoubleWidthNonRgiEmojiSequence(segment)) {
16514
- width += 2;
16649
+ if (codePoint >= 8203 && codePoint <= 8207 || codePoint === 65279) {
16650
+ continue;
16651
+ }
16652
+ if (codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071) {
16653
+ continue;
16654
+ }
16655
+ if (codePoint >= 55296 && codePoint <= 57343) {
16656
+ continue;
16657
+ }
16658
+ if (codePoint >= 65024 && codePoint <= 65039) {
16659
+ continue;
16660
+ }
16661
+ if (defaultIgnorableCodePointRegex.test(character)) {
16515
16662
  continue;
16516
16663
  }
16517
- const visibleSegment = baseVisible(segment);
16518
- const hangulWidth = hangulClusterWidth(visibleSegment, eastAsianWidthOptions);
16519
- if (hangulWidth !== undefined) {
16520
- width += hangulWidth;
16664
+ if (import_emoji_regex.default().test(character)) {
16665
+ width += 2;
16521
16666
  continue;
16522
16667
  }
16523
- const codePoint = visibleSegment.codePointAt(0);
16524
16668
  width += eastAsianWidth(codePoint, eastAsianWidthOptions);
16525
- width += trailingWidth(visibleSegment, eastAsianWidthOptions);
16526
16669
  }
16527
16670
  return width;
16528
16671
  }
16529
- var segmenter, zeroWidthClusterRegex, leadingNonPrintingRegex, spacingMarkRegex, rgiEmojiRegex, unqualifiedKeycapRegex, extendedPictographicRegex;
16672
+ var import_emoji_regex, segmenter, defaultIgnorableCodePointRegex;
16530
16673
  var init_string_width = __esm(() => {
16531
16674
  init_strip_ansi();
16532
16675
  init_get_east_asian_width();
16676
+ import_emoji_regex = __toESM(require_emoji_regex(), 1);
16533
16677
  segmenter = new Intl.Segmenter;
16534
- zeroWidthClusterRegex = /^(?:\p{Default_Ignorable_Code_Point}|\p{Control}|\p{Format}|\p{Nonspacing_Mark}|\p{Enclosing_Mark}|\p{Surrogate})+$/v;
16535
- leadingNonPrintingRegex = /^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Nonspacing_Mark}\p{Enclosing_Mark}\p{Surrogate}]+/v;
16536
- spacingMarkRegex = /\p{Spacing_Mark}/v;
16537
- rgiEmojiRegex = /^\p{RGI_Emoji}$/v;
16538
- unqualifiedKeycapRegex = /^[\d#*]\u20E3$/;
16539
- extendedPictographicRegex = /\p{Extended_Pictographic}/gu;
16678
+ defaultIgnorableCodePointRegex = /^\p{Default_Ignorable_Code_Point}$/u;
16540
16679
  });
16541
16680
 
16542
16681
  // src/ui/table.ts
@@ -16821,6 +16960,10 @@ function box(lines, opts = {}) {
16821
16960
  out.push(pc.dim(`└${"─".repeat(width - 2)}┘`));
16822
16961
  return out;
16823
16962
  }
16963
+ function divider(width) {
16964
+ const w = Math.min(width ?? getTerminalWidth(), 60);
16965
+ return pc.dim("─".repeat(w));
16966
+ }
16824
16967
  var init_box = __esm(() => {
16825
16968
  init_string_width();
16826
16969
  init_colors();
@@ -25090,12 +25233,13 @@ Excluded blocks: ${info.excluded.length}`));
25090
25233
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
25091
25234
  const { homedir: homedir17 } = await import("os");
25092
25235
  const { join: join35 } = await import("path");
25093
- const configDir = join35(homedir17(), ".mma");
25094
- const projectConfigPath = join35(process.cwd(), ".mmrc");
25236
+ const configDir = ctx.configDir;
25237
+ const baseDir = ctx.baseDir;
25238
+ const projectConfigPath = join35(baseDir, ".mmrc");
25095
25239
  const freshConfig = loadConfig2({ configDir, projectConfigPath });
25096
25240
  Object.assign(ctx.config, freshConfig);
25097
25241
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
25098
- const result = await bootstrap2(configDir, process.cwd(), false, false);
25242
+ const result = await bootstrap2(configDir, baseDir, false, false);
25099
25243
  ctx.agent = result.agent;
25100
25244
  ctx.sessionManager = result.sessionManager;
25101
25245
  ctx.skillsModule = result.skillsModule;
@@ -26563,6 +26707,28 @@ init_spinner();
26563
26707
  init_box();
26564
26708
  init_table();
26565
26709
  init_i18n();
26710
+ var GUTTER = " ";
26711
+ function toolMarker(tool) {
26712
+ switch (tool) {
26713
+ case "write_file":
26714
+ case "edit_file":
26715
+ case "create_dir":
26716
+ case "move_file":
26717
+ case "delete_file":
26718
+ return "←";
26719
+ case "read_file":
26720
+ case "list_dir":
26721
+ case "file_info":
26722
+ return "→";
26723
+ case "glob":
26724
+ case "grep":
26725
+ return "✱";
26726
+ case "bash":
26727
+ return "$";
26728
+ default:
26729
+ return "⚙";
26730
+ }
26731
+ }
26566
26732
  function isRichTerminal() {
26567
26733
  return Boolean(process.stdout.isTTY) && !process.env.CI;
26568
26734
  }
@@ -26592,12 +26758,14 @@ class Renderer {
26592
26758
  out;
26593
26759
  err;
26594
26760
  width;
26761
+ toolStyle;
26595
26762
  card = null;
26596
26763
  constructor(opts = {}) {
26597
26764
  this.rich = opts.rich ?? isRichTerminal();
26598
26765
  this.out = opts.out ?? process.stdout;
26599
26766
  this.err = opts.err ?? process.stderr;
26600
26767
  this.width = opts.width ?? getTerminalWidth();
26768
+ this.toolStyle = opts.toolStyle ?? "inline";
26601
26769
  this.spinner = new Spinner({
26602
26770
  enabled: this.rich && (opts.spinner ?? true),
26603
26771
  stream: this.err,
@@ -26614,11 +26782,24 @@ class Renderer {
26614
26782
  meta(chunk) {
26615
26783
  this.spinner.stop();
26616
26784
  if (this.card) {
26617
- this.card.body.push(chunk);
26785
+ if (this.toolStyle === "inline") {
26786
+ this.writeInlineBody(chunk);
26787
+ } else {
26788
+ this.card.body.push(chunk);
26789
+ }
26618
26790
  } else {
26619
26791
  this.out.write(chunk);
26620
26792
  }
26621
26793
  }
26794
+ writeInlineBody(chunk) {
26795
+ for (const line of chunk.split(`
26796
+ `)) {
26797
+ if (line.trim() === "")
26798
+ continue;
26799
+ this.out.write(`${GUTTER}${line}
26800
+ `);
26801
+ }
26802
+ }
26622
26803
  reasoning(chunk) {
26623
26804
  this.spinner.stop();
26624
26805
  this.out.write(pc.dim(chunk));
@@ -26640,6 +26821,13 @@ ${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
26640
26821
  return;
26641
26822
  }
26642
26823
  this.card = { tool, args, body: [], start: Date.now() };
26824
+ if (this.toolStyle === "inline") {
26825
+ const marker = toolMarker(tool);
26826
+ this.out.write(`
26827
+ ${pc.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
26828
+ `);
26829
+ return;
26830
+ }
26643
26831
  this.spinner.start(`${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}`);
26644
26832
  }
26645
26833
  toolEnd(_tool, duration, error, ctxDelta) {
@@ -26655,6 +26843,20 @@ ${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
26655
26843
  if (!this.card)
26656
26844
  return;
26657
26845
  const { tool, args, body } = this.card;
26846
+ const marker = error ? pc.red("✗") : pc.green("✓");
26847
+ let footer = `${marker} ${pc.dim(`${duration}ms`)}`;
26848
+ if (ctxDelta !== undefined && ctxDelta !== 0) {
26849
+ const deltaStr = ctxDelta > 0 ? pc.green(`+${ctxDelta}`) : pc.yellow(`${ctxDelta} ↓`);
26850
+ footer += ` ${pc.dim("ctx")} ${deltaStr}`;
26851
+ }
26852
+ if (this.toolStyle === "inline") {
26853
+ this.out.write(`${GUTTER}${footer}
26854
+ `);
26855
+ this.out.write(`${divider(this.width)}
26856
+ `);
26857
+ this.card = null;
26858
+ return;
26859
+ }
26658
26860
  const lines = [];
26659
26861
  const summary = summarizeArgs2(args);
26660
26862
  if (summary)
@@ -26666,12 +26868,6 @@ ${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
26666
26868
  lines.push(line);
26667
26869
  }
26668
26870
  }
26669
- const marker = error ? pc.red("✗") : pc.green("✓");
26670
- let footer = `${marker} ${pc.dim(`${duration}ms`)}`;
26671
- if (ctxDelta !== undefined && ctxDelta !== 0) {
26672
- const deltaStr = ctxDelta > 0 ? pc.green(`+${ctxDelta}`) : pc.yellow(`${ctxDelta} ↓`);
26673
- footer += ` ${pc.dim("ctx")} ${deltaStr}`;
26674
- }
26675
26871
  lines.push(footer);
26676
26872
  const title = `${marker} ${friendlyTool(tool)}`;
26677
26873
  for (const line of box(lines, { title, width: this.width })) {
@@ -26894,18 +27090,20 @@ class Repl {
26894
27090
  readline2.emitKeypressEvents(process.stdin);
26895
27091
  process.stdin.on("keypress", async (str, key) => {
26896
27092
  if (key.name === "escape") {
27093
+ const escBytes = key.sequence ? (key.sequence.match(/\x1b/g) || []).length : 1;
26897
27094
  const now = Date.now();
26898
- if (now - this.lastEscTime < this.doubleEscDelay) {
27095
+ const withinWindow = now - this.lastEscTime < this.doubleEscDelay;
27096
+ this.lastEscTime = now;
27097
+ if (escBytes >= 2 || withinWindow) {
27098
+ this.lastEscTime = 0;
26899
27099
  if (this.agentRunning) {
26900
27100
  process.stdout.write(pc.yellow(`
26901
27101
  ${t("repl.interrupt")}
26902
27102
  `));
26903
27103
  this.agent.shutdown();
26904
27104
  }
26905
- this.lastEscTime = 0;
26906
- return;
26907
27105
  }
26908
- this.lastEscTime = now;
27106
+ return;
26909
27107
  }
26910
27108
  if (key.ctrl && key.name === "v" && !this.agentRunning) {
26911
27109
  try {
@@ -26918,18 +27116,25 @@ ${t("repl.interrupt")}
26918
27116
  console.log(pc.green(`
26919
27117
  ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
26920
27118
  this.rl.prompt();
27119
+ } else {
27120
+ console.log(pc.yellow(`
27121
+ ${t("image.clipboard_empty")}`));
27122
+ this.rl.prompt();
26921
27123
  }
26922
27124
  } catch {}
26923
27125
  }
26924
27126
  });
26925
27127
  }
27128
+ let forceExitTimer = null;
26926
27129
  process.on("SIGINT", () => {
26927
27130
  if (this.agentRunning) {
26928
27131
  console.log(pc.yellow(`
26929
27132
  [Ctrl+C] Остановка агента... (ещё раз — принудительно)`));
26930
27133
  this.agent.shutdown();
26931
27134
  this.agentRunning = false;
26932
- setTimeout(() => process.exit(1), 2000).unref();
27135
+ if (forceExitTimer)
27136
+ clearTimeout(forceExitTimer);
27137
+ forceExitTimer = setTimeout(() => process.exit(1), 2000).unref();
26933
27138
  } else {
26934
27139
  process.exit(0);
26935
27140
  }
@@ -26962,7 +27167,8 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
26962
27167
  process.stdout.write(`
26963
27168
  ` + pc.green(t("repl.agent")));
26964
27169
  const renderer = new Renderer({
26965
- spinner: this.config.ui?.spinner ?? true
27170
+ spinner: this.config.ui?.spinner ?? true,
27171
+ toolStyle: this.config.ui?.toolStyle ?? "inline"
26966
27172
  });
26967
27173
  const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
26968
27174
  if (ev.type === "start") {
@@ -27179,7 +27385,10 @@ async function main() {
27179
27385
  `);
27180
27386
  process.exit(result2.success ? 0 : 1);
27181
27387
  }
27182
- const renderer = new Renderer({ spinner: config.ui?.spinner ?? true });
27388
+ const renderer = new Renderer({
27389
+ spinner: config.ui?.spinner ?? true,
27390
+ toolStyle: config.ui?.toolStyle ?? "inline"
27391
+ });
27183
27392
  const result = await agent.run(prompt, (chunk) => renderer.text(chunk), (meta) => renderer.meta(meta), (ev) => {
27184
27393
  if (ev.type === "start") {
27185
27394
  renderer.toolStart(ev.tool, ev.args);
@@ -27213,7 +27422,10 @@ async function main() {
27213
27422
  ` + t("cli.first_run") + `
27214
27423
  `));
27215
27424
  const answers = await runSetup();
27216
- const { config: config2 } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
27425
+ const config2 = loadConfig({
27426
+ configDir: join36(homedir18(), ".mma"),
27427
+ projectConfigPath: projectDir ? join36(projectDir, ".mmrc") : join36(process.cwd(), ".mmrc")
27428
+ });
27217
27429
  config2.provider.type = answers.provider;
27218
27430
  config2.provider.baseUrl = answers.apiBase;
27219
27431
  config2.provider.apiKey = answers.apiKey;