micro-models-agent 0.61.0 → 0.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/CHANGELOG.md +619 -595
  2. package/README.md +358 -358
  3. package/dist/certification/certifications.json +493 -493
  4. package/dist/cli/commands.js +447 -0
  5. package/dist/cli/completer.js +167 -0
  6. package/dist/cli/index.js +2 -0
  7. package/dist/cli/main.js +153 -0
  8. package/dist/cli/plugin-commands.js +36 -0
  9. package/dist/cli/repl-commands.js +761 -0
  10. package/dist/cli/repl.js +702 -0
  11. package/dist/cli/run-result.js +33 -0
  12. package/dist/cli/security-commands.js +164 -0
  13. package/dist/cli/setup.js +237 -0
  14. package/dist/config/config.js +276 -0
  15. package/dist/config/defaults.js +141 -0
  16. package/dist/config/domains.js +179 -0
  17. package/dist/config/experts.js +15 -0
  18. package/dist/config/index.js +4 -0
  19. package/dist/config/security.js +213 -0
  20. package/dist/config/types.js +1 -0
  21. package/dist/core/agent-moe.js +102 -0
  22. package/dist/core/agent.js +1018 -0
  23. package/dist/core/bootstrap.js +481 -0
  24. package/dist/core/crash-handler.js +51 -0
  25. package/dist/core/environment.js +199 -0
  26. package/dist/core/index.js +2 -0
  27. package/dist/core/prompt-builder.js +76 -0
  28. package/dist/core/session-logger.js +251 -0
  29. package/dist/core/types.js +1 -0
  30. package/dist/core/version.js +26 -0
  31. package/dist/core/workspace.js +76 -0
  32. package/dist/i18n/en.json +776 -757
  33. package/dist/i18n/index.js +46 -0
  34. package/dist/i18n/ru.json +776 -757
  35. package/dist/index.js +22 -0
  36. package/dist/llm/image-utils.js +143 -0
  37. package/dist/llm/index.js +4 -0
  38. package/dist/llm/model-loader.js +78 -0
  39. package/dist/llm/openai-compat.js +497 -0
  40. package/dist/llm/orchestrator.js +200 -0
  41. package/dist/llm/provider.js +10 -0
  42. package/dist/llm/response.js +39 -0
  43. package/dist/llm/token-counter.js +39 -0
  44. package/dist/llm/types.js +1 -0
  45. package/dist/logger/app-logger.js +189 -0
  46. package/dist/logger/file-log.js +151 -0
  47. package/dist/logger/index.js +1 -0
  48. package/dist/main.js +1026 -417
  49. package/dist/migration/backup.js +45 -0
  50. package/dist/migration/detect.js +50 -0
  51. package/dist/migration/index.js +2 -0
  52. package/dist/modules/artifacts/store.js +61 -0
  53. package/dist/modules/browser/actions.js +76 -0
  54. package/dist/modules/browser/bridge-client.js +199 -0
  55. package/dist/modules/browser/bridge-path.js +10 -0
  56. package/dist/modules/browser/bridge-server.mjs +219 -219
  57. package/dist/modules/browser/cookie-store.js +24 -0
  58. package/dist/modules/browser/driver.js +136 -0
  59. package/dist/modules/browser/index.js +7 -0
  60. package/dist/modules/browser/module.js +29 -0
  61. package/dist/modules/browser/session.js +342 -0
  62. package/dist/modules/browser/snapshot.js +148 -0
  63. package/dist/modules/browser/types.js +12 -0
  64. package/dist/modules/certification/cli.js +213 -0
  65. package/dist/modules/certification/fact-checker.js +82 -0
  66. package/dist/modules/certification/loader.js +106 -0
  67. package/dist/modules/certification/manifest.js +58 -0
  68. package/dist/modules/certification/runner.js +245 -0
  69. package/dist/modules/certification/scenarios.js +407 -0
  70. package/dist/modules/certification/types.js +1 -0
  71. package/dist/modules/context/chunk-query.js +100 -0
  72. package/dist/modules/context/fact-extractor.js +168 -0
  73. package/dist/modules/context/history.js +15 -0
  74. package/dist/modules/context/index.js +1 -0
  75. package/dist/modules/context/manager.js +440 -0
  76. package/dist/modules/execution/audit-runners.js +206 -0
  77. package/dist/modules/execution/auditor.js +218 -0
  78. package/dist/modules/execution/execution-plugin.js +431 -0
  79. package/dist/modules/execution/index.js +8 -0
  80. package/dist/modules/execution/module.js +625 -0
  81. package/dist/modules/execution/moe-executor.js +304 -0
  82. package/dist/modules/execution/plan-coverage.js +68 -0
  83. package/dist/modules/execution/plan-persister.js +46 -0
  84. package/dist/modules/execution/plan-store.js +196 -0
  85. package/dist/modules/execution/plan-tool.js +677 -0
  86. package/dist/modules/execution/plan-validator.js +153 -0
  87. package/dist/modules/execution/planner.js +94 -0
  88. package/dist/modules/execution/stuck-detector.js +746 -0
  89. package/dist/modules/execution/tracker.js +69 -0
  90. package/dist/modules/execution/types.js +1 -0
  91. package/dist/modules/execution/verifier.js +235 -0
  92. package/dist/modules/execution/windows-commands.js +41 -0
  93. package/dist/modules/hallucination/confidence.js +66 -0
  94. package/dist/modules/hallucination/consistency.js +26 -0
  95. package/dist/modules/hallucination/detector.js +47 -0
  96. package/dist/modules/hallucination/factual.js +169 -0
  97. package/dist/modules/hallucination/index.js +5 -0
  98. package/dist/modules/hallucination/js-identifiers.js +262 -0
  99. package/dist/modules/hallucination/llm-judge.js +101 -0
  100. package/dist/modules/index.js +5 -0
  101. package/dist/modules/indexer/cache.js +40 -0
  102. package/dist/modules/indexer/index.js +3 -0
  103. package/dist/modules/indexer/module.js +246 -0
  104. package/dist/modules/indexer/project-profile.js +183 -0
  105. package/dist/modules/indexer/walker.js +101 -0
  106. package/dist/modules/lsp/check-tool.js +58 -0
  107. package/dist/modules/lsp/client.js +389 -0
  108. package/dist/modules/lsp/command.js +60 -0
  109. package/dist/modules/lsp/config.js +135 -0
  110. package/dist/modules/lsp/index.js +3 -0
  111. package/dist/modules/lsp/module.js +260 -0
  112. package/dist/modules/lsp/probe.js +86 -0
  113. package/dist/modules/lsp/project-root.js +32 -0
  114. package/dist/modules/lsp/startup-check.js +144 -0
  115. package/dist/modules/lsp/types.js +1 -0
  116. package/dist/modules/mcp/client.js +399 -0
  117. package/dist/modules/mcp/index.js +3 -0
  118. package/dist/modules/mcp/module.js +142 -0
  119. package/dist/modules/mcp/registry.js +15 -0
  120. package/dist/modules/memory/index.js +1 -0
  121. package/dist/modules/memory/module.js +96 -0
  122. package/dist/modules/memory/search.js +42 -0
  123. package/dist/modules/memory/store.js +69 -0
  124. package/dist/modules/pipelines/engine.js +60 -0
  125. package/dist/modules/pipelines/index.js +3 -0
  126. package/dist/modules/pipelines/parser.js +56 -0
  127. package/dist/modules/pipelines/template.js +14 -0
  128. package/dist/modules/plugins/builtin/lint-on-write.js +334 -0
  129. package/dist/modules/plugins/builtin/notify.js +9 -0
  130. package/dist/modules/plugins/index.js +1 -0
  131. package/dist/modules/plugins/loader.js +70 -0
  132. package/dist/modules/plugins/manager.js +261 -0
  133. package/dist/modules/plugins/types.js +1 -0
  134. package/dist/modules/pricing/index.js +61 -0
  135. package/dist/modules/pricing/prices.js +129 -0
  136. package/dist/modules/processes/detect.js +34 -0
  137. package/dist/modules/processes/index.js +2 -0
  138. package/dist/modules/processes/registry.js +327 -0
  139. package/dist/modules/processes/runner.js +23 -0
  140. package/dist/modules/providers/create.js +22 -0
  141. package/dist/modules/providers/fallback.js +79 -0
  142. package/dist/modules/providers/health.js +46 -0
  143. package/dist/modules/providers/index.js +5 -0
  144. package/dist/modules/providers/manager.js +161 -0
  145. package/dist/modules/providers/presets.js +128 -0
  146. package/dist/modules/providers/registry.js +22 -0
  147. package/dist/modules/providers/types.js +1 -0
  148. package/dist/modules/registry.js +48 -0
  149. package/dist/modules/security/audit-log.js +136 -0
  150. package/dist/modules/security/audit-notifier.js +292 -0
  151. package/dist/modules/security/command-validator.js +219 -0
  152. package/dist/modules/security/content-scanner.js +53 -0
  153. package/dist/modules/security/data-sanitizer.js +89 -0
  154. package/dist/modules/security/encryption.js +242 -0
  155. package/dist/modules/security/index.js +14 -0
  156. package/dist/modules/security/network-validator.js +88 -0
  157. package/dist/modules/security/path-validator.js +203 -0
  158. package/dist/modules/security/rate-limiter.js +119 -0
  159. package/dist/modules/security/security-policies.js +531 -0
  160. package/dist/modules/security/session-encryption.js +210 -0
  161. package/dist/modules/security/session-isolation.js +95 -0
  162. package/dist/modules/session/index.js +3 -0
  163. package/dist/modules/session/manager.js +172 -0
  164. package/dist/modules/session/module.js +24 -0
  165. package/dist/modules/session/store.js +222 -0
  166. package/dist/modules/session/types.js +1 -0
  167. package/dist/modules/skills/index.js +2 -0
  168. package/dist/modules/skills/loader.js +72 -0
  169. package/dist/modules/skills/matcher.js +27 -0
  170. package/dist/modules/skills/module.js +129 -0
  171. package/dist/modules/types.js +1 -0
  172. package/dist/modules/updater/checker.js +96 -0
  173. package/dist/modules/updater/index.js +2 -0
  174. package/dist/modules/updater/module.js +116 -0
  175. package/dist/modules/user-profile/compressor.js +16 -0
  176. package/dist/modules/user-profile/index.js +1 -0
  177. package/dist/modules/user-profile/profile.js +68 -0
  178. package/dist/skills/builtin/git.md +36 -36
  179. package/dist/skills/builtin/typescript.md +35 -35
  180. package/dist/tools/approve.js +33 -0
  181. package/dist/tools/attach-image.js +101 -0
  182. package/dist/tools/bash.js +519 -0
  183. package/dist/tools/browser.js +115 -0
  184. package/dist/tools/chunk-query.js +100 -0
  185. package/dist/tools/create-dir.js +56 -0
  186. package/dist/tools/delete-file.js +63 -0
  187. package/dist/tools/download-file.js +117 -0
  188. package/dist/tools/edit-file.js +80 -0
  189. package/dist/tools/enable-tools.js +59 -0
  190. package/dist/tools/executor.js +154 -0
  191. package/dist/tools/file-info.js +47 -0
  192. package/dist/tools/filter-tools.js +17 -0
  193. package/dist/tools/glob-tool.js +27 -0
  194. package/dist/tools/grep-tool.js +125 -0
  195. package/dist/tools/hidden-tools-block.js +37 -0
  196. package/dist/tools/index.js +78 -0
  197. package/dist/tools/list-dir.js +49 -0
  198. package/dist/tools/load-skill.js +43 -0
  199. package/dist/tools/mcp-call.js +69 -0
  200. package/dist/tools/move-file.js +86 -0
  201. package/dist/tools/path-utils.js +101 -0
  202. package/dist/tools/pipeline-run.js +145 -0
  203. package/dist/tools/preview.js +2 -0
  204. package/dist/tools/process-kill.js +40 -0
  205. package/dist/tools/process-list.js +37 -0
  206. package/dist/tools/process-log.js +54 -0
  207. package/dist/tools/question.js +141 -0
  208. package/dist/tools/read-file.js +179 -0
  209. package/dist/tools/recall.js +118 -0
  210. package/dist/tools/registry.js +47 -0
  211. package/dist/tools/remember.js +68 -0
  212. package/dist/tools/scope-check.js +32 -0
  213. package/dist/tools/search-history.js +85 -0
  214. package/dist/tools/subagent.js +196 -0
  215. package/dist/tools/types.js +1 -0
  216. package/dist/tools/user-input.js +123 -0
  217. package/dist/tools/web-browse.js +87 -0
  218. package/dist/tools/web-fetch.js +119 -0
  219. package/dist/tools/web-search.js +105 -0
  220. package/dist/tools/write-file.js +82 -0
  221. package/dist/ui/box.js +77 -0
  222. package/dist/ui/colors.js +4 -0
  223. package/dist/ui/diff.js +178 -0
  224. package/dist/ui/index.js +6 -0
  225. package/dist/ui/line-editor.js +822 -0
  226. package/dist/ui/line-math.js +73 -0
  227. package/dist/ui/md-formatter.js +212 -0
  228. package/dist/ui/output.js +13 -0
  229. package/dist/ui/plan-view.js +103 -0
  230. package/dist/ui/renderer.js +259 -0
  231. package/dist/ui/spinner.js +70 -0
  232. package/dist/ui/table.js +144 -0
  233. package/package.json +51 -51
package/dist/main.js CHANGED
@@ -3188,6 +3188,25 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
3188
3188
  "repl.cost": "Total cost: {cost}",
3189
3189
  "repl.cost_breakdown": "By provider: {breakdown}",
3190
3190
  "repl.tokens": "Tokens used: {tokens}",
3191
+ "repl.cache": "Cache: {hit}% hit · saved {saved}",
3192
+ "repl.cache_nosave": "Cache: {hit}% hit",
3193
+ "repl.prefix": "Prefix stable: {stable}% · broke: {cause}",
3194
+ "cache.cause.system": "system prompt",
3195
+ "cache.cause.tools": "tool set",
3196
+ "cache.cause.history": "history",
3197
+ "cache.cause.volatile": "volatile content",
3198
+ "cache.cause.unknown": "unknown",
3199
+ "cli.session_usage": "API usage: {prompt} prompt + {completion} completion = {total} tokens",
3200
+ "cli.session_cache": "Cache: {hit}% hit ({cached} cached / {uncached} uncached)",
3201
+ "cli.usage": "Show provider balance/usage (OpenRouter)",
3202
+ "cli.usage_unsupported": 'Provider "{provider}" does not expose an API balance. Only OpenRouter does; OpenCode Zen/Go show it in the web dashboard.',
3203
+ "cli.usage_no_key": "No API key configured for the active provider.",
3204
+ "cli.usage_error": "Failed to fetch balance: {error}",
3205
+ "cli.usage_key_usage": "Key usage: {usage}",
3206
+ "cli.usage_key_limit": "Key limit: {limit} · remaining {remaining}",
3207
+ "cli.usage_balance": "Balance: {balance}",
3208
+ "cli.usage_account": "Account: {credits} purchased · {used} used",
3209
+ "cli.usage_empty": "No balance information returned.",
3191
3210
  "repl.ctrl_c_interrupt": `
3192
3211
  [Ctrl+C] Stopping agent... (press again to force)`,
3193
3212
  "exec.stop_directive": 'STOP. Step {stepId} ("{description}") took {iterations} iterations with no progress. DO NOT continue this step. Immediately call: plan update step={stepId} status=done (if code works despite warnings) OR plan update step={stepId} status=skipped note="reason". Do NOT make any other tool calls before updating the plan.',
@@ -4005,6 +4024,25 @@ var init_ru = __esm(() => {
4005
4024
  "repl.cost": "Итого потрачено: {cost}",
4006
4025
  "repl.cost_breakdown": "По провайдерам: {breakdown}",
4007
4026
  "repl.tokens": "Потрачено токенов: {tokens}",
4027
+ "repl.cache": "Кеш: {hit}% попаданий · сэкономлено {saved}",
4028
+ "repl.cache_nosave": "Кеш: {hit}% попаданий",
4029
+ "repl.prefix": "Префикс стабилен: {stable}% · сломалось: {cause}",
4030
+ "cache.cause.system": "системный промпт",
4031
+ "cache.cause.tools": "набор инструментов",
4032
+ "cache.cause.history": "история",
4033
+ "cache.cause.volatile": "волатильное содержимое",
4034
+ "cache.cause.unknown": "неизвестно",
4035
+ "cli.session_usage": "API-использование: {prompt} prompt + {completion} completion = {total} токенов",
4036
+ "cli.session_cache": "Кеш: {hit}% попаданий ({cached} из кеша / {uncached} новых)",
4037
+ "cli.usage": "Показать баланс/расход провайдера (OpenRouter)",
4038
+ "cli.usage_unsupported": 'Провайдер "{provider}" не отдаёт баланс по API. Это умеет только OpenRouter; OpenCode Zen/Go показывают его в веб-дашборде.',
4039
+ "cli.usage_no_key": "Для активного провайдера не настроен API-ключ.",
4040
+ "cli.usage_error": "Не удалось получить баланс: {error}",
4041
+ "cli.usage_key_usage": "Расход по ключу: {usage}",
4042
+ "cli.usage_key_limit": "Лимит ключа: {limit} · осталось {remaining}",
4043
+ "cli.usage_balance": "Баланс: {balance}",
4044
+ "cli.usage_account": "Аккаунт: куплено {credits} · израсходовано {used}",
4045
+ "cli.usage_empty": "Провайдер не вернул данных о балансе.",
4008
4046
  "repl.ctrl_c_interrupt": `
4009
4047
  [Ctrl+C] Остановка агента... (ещё раз — принудительно)`,
4010
4048
  "exec.stop_directive": 'STOP. Step {stepId} ("{description}") took {iterations} iterations with no progress. DO NOT continue this step. Immediately call: plan update step={stepId} status=done (if code works despite warnings) OR plan update step={stepId} status=skipped note="reason". Do NOT make any other tool calls before updating the plan.',
@@ -5742,6 +5780,26 @@ var init_token_counter = __esm(() => {
5742
5780
  init_dist();
5743
5781
  });
5744
5782
 
5783
+ // src/core/version.ts
5784
+ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
5785
+ import { join as join9, dirname as dirname3 } from "path";
5786
+ import { fileURLToPath } from "url";
5787
+ function readMmaVersion() {
5788
+ const here = dirname3(fileURLToPath(import.meta.url));
5789
+ const candidates = [join9(here, "..", "..", "package.json"), join9(here, "..", "package.json")];
5790
+ for (const p of candidates) {
5791
+ if (existsSync9(p)) {
5792
+ try {
5793
+ const raw = JSON.parse(readFileSync5(p, "utf8"));
5794
+ if (raw.version)
5795
+ return raw.version;
5796
+ } catch {}
5797
+ }
5798
+ }
5799
+ return "0.0.0";
5800
+ }
5801
+ var init_version = () => {};
5802
+
5745
5803
  // src/modules/security/rate-limiter.ts
5746
5804
  class RateLimiter {
5747
5805
  config;
@@ -5873,11 +5931,83 @@ class StreamState {
5873
5931
  }
5874
5932
  }
5875
5933
 
5934
+ // src/llm/cache-usage.ts
5935
+ function num(value) {
5936
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
5937
+ }
5938
+ function isRecord(value) {
5939
+ return typeof value === "object" && value !== null;
5940
+ }
5941
+ function parseCacheUsage(usage, format, estimatedPromptTokens) {
5942
+ if (!isRecord(usage))
5943
+ return;
5944
+ switch (format) {
5945
+ case "openai": {
5946
+ const details = usage.prompt_tokens_details;
5947
+ if (!isRecord(details))
5948
+ return;
5949
+ const cached = num(details.cached_tokens);
5950
+ if (cached === undefined)
5951
+ return;
5952
+ const prompt = num(usage.prompt_tokens) ?? cached;
5953
+ const write = num(details.cache_write_tokens) ?? 0;
5954
+ return {
5955
+ cachedTokens: cached,
5956
+ cacheWriteTokens: write,
5957
+ uncachedTokens: Math.max(0, prompt - cached),
5958
+ source: "api"
5959
+ };
5960
+ }
5961
+ case "deepseek": {
5962
+ const hit = num(usage.prompt_cache_hit_tokens);
5963
+ const miss = num(usage.prompt_cache_miss_tokens);
5964
+ if (hit === undefined && miss === undefined)
5965
+ return;
5966
+ return {
5967
+ cachedTokens: hit ?? 0,
5968
+ cacheWriteTokens: 0,
5969
+ uncachedTokens: miss ?? 0,
5970
+ source: "api"
5971
+ };
5972
+ }
5973
+ case "anthropic": {
5974
+ const read = num(usage.cache_read_input_tokens);
5975
+ const creation = num(usage.cache_creation_input_tokens);
5976
+ if (read === undefined && creation === undefined)
5977
+ return;
5978
+ return {
5979
+ cachedTokens: read ?? 0,
5980
+ cacheWriteTokens: creation ?? 0,
5981
+ uncachedTokens: num(usage.input_tokens) ?? 0,
5982
+ source: "api"
5983
+ };
5984
+ }
5985
+ case "ollama": {
5986
+ const evaluated = num(usage.prompt_eval_count);
5987
+ if (evaluated === undefined || estimatedPromptTokens === undefined)
5988
+ return;
5989
+ return {
5990
+ cachedTokens: Math.max(0, estimatedPromptTokens - evaluated),
5991
+ cacheWriteTokens: 0,
5992
+ uncachedTokens: evaluated,
5993
+ source: "derived"
5994
+ };
5995
+ }
5996
+ default:
5997
+ return;
5998
+ }
5999
+ }
6000
+
5876
6001
  // src/llm/openai-compat.ts
5877
6002
  var exports_openai_compat = {};
5878
6003
  __export(exports_openai_compat, {
5879
6004
  OpenAICompatProvider: () => OpenAICompatProvider
5880
6005
  });
6006
+ function defaultUserAgent() {
6007
+ if (cachedUserAgent === null)
6008
+ cachedUserAgent = `micro-models-agent/${readMmaVersion()}`;
6009
+ return cachedUserAgent;
6010
+ }
5881
6011
  function buildRequestBody(opts) {
5882
6012
  const body = {
5883
6013
  model: opts.model,
@@ -5886,6 +6016,14 @@ function buildRequestBody(opts) {
5886
6016
  };
5887
6017
  if (opts.maxTokens !== undefined)
5888
6018
  body.max_tokens = opts.maxTokens;
6019
+ if (opts.cachePrompt)
6020
+ body.cache_prompt = true;
6021
+ if (opts.promptCacheKey)
6022
+ body.prompt_cache_key = opts.promptCacheKey;
6023
+ if (opts.sessionId)
6024
+ body.session_id = opts.sessionId;
6025
+ if (opts.stream && opts.streamUsage)
6026
+ body.stream_options = { include_usage: true };
5889
6027
  const strategy = opts.reasoningStrategy ?? "openai-effort";
5890
6028
  const level = opts.reasoningEffort;
5891
6029
  if (strategy === "openai-effort" && level && level !== "default") {
@@ -5917,10 +6055,16 @@ class OpenAICompatProvider {
5917
6055
  retryConfig;
5918
6056
  rateLimiter;
5919
6057
  debug;
6058
+ getSessionId;
6059
+ userAgent;
6060
+ cache;
6061
+ cacheReport;
5920
6062
  constructor(config) {
5921
6063
  this.config = config;
5922
6064
  this.model = config.model;
5923
6065
  this.contextWindow = config.contextWindow ?? 32768;
6066
+ this.cache = config.cache;
6067
+ this.cacheReport = config.cache?.report ?? "openai";
5924
6068
  this.tokenCounter = new TokenCounter;
5925
6069
  this.retryConfig = config.retry ?? {
5926
6070
  maxRetries: 3,
@@ -5930,6 +6074,8 @@ class OpenAICompatProvider {
5930
6074
  noDataTimeoutMs: 180000
5931
6075
  };
5932
6076
  this.rateLimiter = createRateLimiter(config.rateLimits);
6077
+ this.getSessionId = config.getSessionId;
6078
+ this.userAgent = config.userAgent ?? defaultUserAgent();
5933
6079
  this.debug = config.logger ? config.logger.debug.bind(config.logger) : null;
5934
6080
  }
5935
6081
  async* chat(messages, tools, signal, options) {
@@ -6021,7 +6167,8 @@ class OpenAICompatProvider {
6021
6167
  stream: true,
6022
6168
  maxTokens,
6023
6169
  reasoningEffort: options?.reasoningEffort,
6024
- reasoningStrategy: options?.reasoningStrategy
6170
+ reasoningStrategy: options?.reasoningStrategy,
6171
+ ...this.cacheHints()
6025
6172
  });
6026
6173
  this.debug?.("LLM stream request", {
6027
6174
  baseUrl: this.config.baseUrl,
@@ -6129,7 +6276,8 @@ class OpenAICompatProvider {
6129
6276
  st.usage = {
6130
6277
  promptTokens: parsed.usage.prompt_tokens ?? 0,
6131
6278
  completionTokens: parsed.usage.completion_tokens ?? 0,
6132
- totalTokens: parsed.usage.total_tokens ?? 0
6279
+ totalTokens: parsed.usage.total_tokens ?? 0,
6280
+ cache: parseCacheUsage(parsed.usage, this.cacheReport)
6133
6281
  };
6134
6282
  this.debug?.("LLM stream usage", { ...st.usage });
6135
6283
  } else if (parsed.error) {
@@ -6217,13 +6365,27 @@ class OpenAICompatProvider {
6217
6365
  }
6218
6366
  return st.sawDone;
6219
6367
  }
6368
+ cacheHints() {
6369
+ const sessionId = this.getSessionId?.();
6370
+ return {
6371
+ cachePrompt: this.cache?.requestCachePrompt === true,
6372
+ promptCacheKey: this.cache?.requestPromptCacheKey ? sessionId : undefined,
6373
+ sessionId: this.cache?.requestSessionId ? sessionId : undefined,
6374
+ streamUsage: this.cache?.requestStreamUsage === true
6375
+ };
6376
+ }
6220
6377
  buildRequestSetup(signal) {
6221
6378
  const headers = {
6222
- "Content-Type": "application/json"
6379
+ "Content-Type": "application/json",
6380
+ "User-Agent": this.userAgent
6223
6381
  };
6224
6382
  if (this.config.apiKey && this.config.apiKey !== "not-needed") {
6225
6383
  headers["Authorization"] = `Bearer ${this.config.apiKey}`;
6226
6384
  }
6385
+ const sessionId = this.getSessionId?.();
6386
+ const sendSessionHeader = this.cache ? this.cache.sessionHeader : true;
6387
+ if (sessionId && sendSessionHeader)
6388
+ headers["x-opencode-session"] = sessionId;
6227
6389
  const controller = new AbortController;
6228
6390
  let timedOut = false;
6229
6391
  const timeoutId = setTimeout(() => {
@@ -6261,7 +6423,8 @@ class OpenAICompatProvider {
6261
6423
  stream: false,
6262
6424
  maxTokens: options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096,
6263
6425
  reasoningEffort: options?.reasoningEffort,
6264
- reasoningStrategy: options?.reasoningStrategy
6426
+ reasoningStrategy: options?.reasoningStrategy,
6427
+ ...this.cacheHints()
6265
6428
  });
6266
6429
  const { headers, abortSignal, cleanup, isTimeout } = this.buildRequestSetup(signal);
6267
6430
  try {
@@ -6314,7 +6477,8 @@ class OpenAICompatProvider {
6314
6477
  usage: {
6315
6478
  promptTokens: data.usage.prompt_tokens ?? 0,
6316
6479
  completionTokens: data.usage.completion_tokens ?? 0,
6317
- totalTokens: data.usage.total_tokens ?? 0
6480
+ totalTokens: data.usage.total_tokens ?? 0,
6481
+ cache: parseCacheUsage(data.usage, this.cacheReport)
6318
6482
  }
6319
6483
  });
6320
6484
  }
@@ -6335,7 +6499,8 @@ class OpenAICompatProvider {
6335
6499
  try {
6336
6500
  const url = `${this.config.baseUrl.replace(/\/+$/, "")}/models`;
6337
6501
  const headers = {
6338
- "Content-Type": "application/json"
6502
+ "Content-Type": "application/json",
6503
+ "User-Agent": this.userAgent
6339
6504
  };
6340
6505
  if (this.config.apiKey && this.config.apiKey !== "not-needed") {
6341
6506
  headers["Authorization"] = `Bearer ${this.config.apiKey}`;
@@ -6409,10 +6574,11 @@ class OpenAICompatProvider {
6409
6574
  });
6410
6575
  }
6411
6576
  }
6412
- var REQUEST_TIMEOUT_MS = 120000, MAX_RATE_WAIT_MS = 30000;
6577
+ var REQUEST_TIMEOUT_MS = 120000, MAX_RATE_WAIT_MS = 30000, cachedUserAgent = null;
6413
6578
  var init_openai_compat = __esm(() => {
6414
6579
  init_token_counter();
6415
6580
  init_i18n();
6581
+ init_version();
6416
6582
  init_rate_limiter();
6417
6583
  init_llm_errors();
6418
6584
  });
@@ -6433,6 +6599,8 @@ function openaiCompat(opts) {
6433
6599
  retry,
6434
6600
  rateLimits,
6435
6601
  maxCompletionTokens: opts.maxCompletionTokens,
6602
+ getSessionId: opts.getSessionId,
6603
+ cache: opts.capabilities?.cache,
6436
6604
  logger: opts.logger
6437
6605
  });
6438
6606
  }
@@ -6450,7 +6618,17 @@ var init_presets = __esm(() => {
6450
6618
  reasoningStrategy: "prompt-tag",
6451
6619
  listModels: true,
6452
6620
  requiresKey: false,
6453
- auth: "bearer"
6621
+ auth: "bearer",
6622
+ cache: {
6623
+ mechanism: "local",
6624
+ report: "openai",
6625
+ sessionHeader: false,
6626
+ requestCachePrompt: false,
6627
+ requestPromptCacheKey: false,
6628
+ requestSessionId: false,
6629
+ requestCacheControl: false,
6630
+ requestStreamUsage: true
6631
+ }
6454
6632
  },
6455
6633
  create: openaiCompat
6456
6634
  };
@@ -6465,7 +6643,17 @@ var init_presets = __esm(() => {
6465
6643
  reasoningStrategy: "openai-effort",
6466
6644
  listModels: true,
6467
6645
  requiresKey: true,
6468
- auth: "bearer"
6646
+ auth: "bearer",
6647
+ cache: {
6648
+ mechanism: "auto",
6649
+ report: "openai",
6650
+ sessionHeader: false,
6651
+ requestCachePrompt: false,
6652
+ requestPromptCacheKey: false,
6653
+ requestSessionId: true,
6654
+ requestCacheControl: false,
6655
+ requestStreamUsage: true
6656
+ }
6469
6657
  },
6470
6658
  create: openaiCompat
6471
6659
  };
@@ -6480,7 +6668,17 @@ var init_presets = __esm(() => {
6480
6668
  reasoningStrategy: "openai-effort",
6481
6669
  listModels: true,
6482
6670
  requiresKey: true,
6483
- auth: "bearer"
6671
+ auth: "bearer",
6672
+ cache: {
6673
+ mechanism: "auto",
6674
+ report: "openai",
6675
+ sessionHeader: false,
6676
+ requestCachePrompt: false,
6677
+ requestPromptCacheKey: true,
6678
+ requestSessionId: false,
6679
+ requestCacheControl: false,
6680
+ requestStreamUsage: true
6681
+ }
6484
6682
  },
6485
6683
  create: openaiCompat
6486
6684
  };
@@ -6495,7 +6693,17 @@ var init_presets = __esm(() => {
6495
6693
  reasoningStrategy: "none",
6496
6694
  listModels: false,
6497
6695
  requiresKey: true,
6498
- auth: "header"
6696
+ auth: "header",
6697
+ cache: {
6698
+ mechanism: "explicit",
6699
+ report: "anthropic",
6700
+ sessionHeader: false,
6701
+ requestCachePrompt: false,
6702
+ requestPromptCacheKey: false,
6703
+ requestSessionId: false,
6704
+ requestCacheControl: true,
6705
+ requestStreamUsage: false
6706
+ }
6499
6707
  },
6500
6708
  create: openaiCompat
6501
6709
  };
@@ -6510,7 +6718,17 @@ var init_presets = __esm(() => {
6510
6718
  reasoningStrategy: "openai-effort",
6511
6719
  listModels: true,
6512
6720
  requiresKey: false,
6513
- auth: "bearer"
6721
+ auth: "bearer",
6722
+ cache: {
6723
+ mechanism: "auto",
6724
+ report: "openai",
6725
+ sessionHeader: true,
6726
+ requestCachePrompt: false,
6727
+ requestPromptCacheKey: false,
6728
+ requestSessionId: false,
6729
+ requestCacheControl: false,
6730
+ requestStreamUsage: true
6731
+ }
6514
6732
  },
6515
6733
  create: openaiCompat
6516
6734
  };
@@ -6525,7 +6743,17 @@ var init_presets = __esm(() => {
6525
6743
  reasoningStrategy: "openai-effort",
6526
6744
  listModels: true,
6527
6745
  requiresKey: false,
6528
- auth: "bearer"
6746
+ auth: "bearer",
6747
+ cache: {
6748
+ mechanism: "auto",
6749
+ report: "openai",
6750
+ sessionHeader: true,
6751
+ requestCachePrompt: false,
6752
+ requestPromptCacheKey: false,
6753
+ requestSessionId: false,
6754
+ requestCacheControl: false,
6755
+ requestStreamUsage: true
6756
+ }
6529
6757
  },
6530
6758
  create: openaiCompat
6531
6759
  };
@@ -6588,6 +6816,25 @@ var init_create = __esm(() => {
6588
6816
  init_presets();
6589
6817
  });
6590
6818
 
6819
+ // src/modules/providers/cache.ts
6820
+ function resolveCacheCapability(spec, override) {
6821
+ const base = spec?.capabilities.cache ?? NO_CACHE_CAPABILITY;
6822
+ return { ...base, ...override ?? {} };
6823
+ }
6824
+ var NO_CACHE_CAPABILITY;
6825
+ var init_cache = __esm(() => {
6826
+ NO_CACHE_CAPABILITY = {
6827
+ mechanism: "none",
6828
+ report: "none",
6829
+ sessionHeader: false,
6830
+ requestCachePrompt: false,
6831
+ requestPromptCacheKey: false,
6832
+ requestSessionId: false,
6833
+ requestCacheControl: false,
6834
+ requestStreamUsage: false
6835
+ };
6836
+ });
6837
+
6591
6838
  // src/modules/providers/manager.ts
6592
6839
  class ProviderManager {
6593
6840
  entries;
@@ -6710,17 +6957,26 @@ class ProviderManager {
6710
6957
  retry: entry.retry ?? this.opts.retry,
6711
6958
  rateLimits: entry.rateLimits ?? this.opts.rateLimits,
6712
6959
  maxCompletionTokens: entry.maxCompletionTokens,
6960
+ getSessionId: this.opts.getSessionId,
6961
+ capabilities: this.resolveCapabilities(entry),
6713
6962
  logger: this.opts.logger
6714
6963
  }, this.registry);
6715
6964
  this.cache.set(key, provider);
6716
6965
  return provider;
6717
6966
  }
6967
+ resolveCapabilities(entry) {
6968
+ const spec = this.registry.get(entry.type);
6969
+ if (!spec)
6970
+ return { cache: resolveCacheCapability(undefined, entry.cache) };
6971
+ return { ...spec.capabilities, cache: resolveCacheCapability(spec, entry.cache) };
6972
+ }
6718
6973
  resetCache() {
6719
6974
  this.cache.clear();
6720
6975
  }
6721
6976
  }
6722
6977
  var init_manager = __esm(() => {
6723
6978
  init_create();
6979
+ init_cache();
6724
6980
  init_presets();
6725
6981
  });
6726
6982
 
@@ -6794,11 +7050,12 @@ var init_fallback = __esm(() => {
6794
7050
  });
6795
7051
 
6796
7052
  // src/modules/providers/factory.ts
6797
- function buildActiveProvider(config, logger) {
7053
+ function buildActiveProvider(config, logger, opts) {
6798
7054
  const manager = new ProviderManager(config.provider, {
6799
7055
  contextWindow: config.contextWindow,
6800
7056
  retry: config.retry,
6801
7057
  rateLimits: config.security?.rateLimits,
7058
+ getSessionId: opts?.getSessionId,
6802
7059
  logger
6803
7060
  });
6804
7061
  manager.setModel(config.model);
@@ -7142,8 +7399,8 @@ var init_executor = __esm(() => {
7142
7399
  });
7143
7400
 
7144
7401
  // src/tools/path-utils.ts
7145
- import { resolve, normalize, dirname as dirname3, basename, sep, relative, isAbsolute } from "path";
7146
- import { existsSync as existsSync9 } from "fs";
7402
+ import { resolve, normalize, dirname as dirname4, basename, sep, relative, isAbsolute } from "path";
7403
+ import { existsSync as existsSync10 } from "fs";
7147
7404
  function toForwardSlash(p) {
7148
7405
  return p.replace(/\\/g, "/");
7149
7406
  }
@@ -7164,30 +7421,30 @@ function matchesScopeEntry(targetResolved, entryResolved) {
7164
7421
  function safeResolvePath(baseDir, userPath) {
7165
7422
  const asIs = resolve(normalize(userPath));
7166
7423
  if (userPath.startsWith("/") || userPath.startsWith("\\")) {
7167
- if (existsSync9(asIs) || existsSync9(dirname3(asIs)))
7424
+ if (existsSync10(asIs) || existsSync10(dirname4(asIs)))
7168
7425
  return asIs;
7169
7426
  }
7170
7427
  const norm = normalize(userPath);
7171
7428
  if (isAbsolute(norm)) {
7172
- if (existsSync9(norm) || existsSync9(dirname3(norm)))
7429
+ if (existsSync10(norm) || existsSync10(dirname4(norm)))
7173
7430
  return norm;
7174
7431
  const stripped2 = norm.replace(/^[/\\]/, "");
7175
7432
  const relativeCandidate = resolve(baseDir, stripped2);
7176
- if (existsSync9(relativeCandidate) || existsSync9(dirname3(relativeCandidate))) {
7433
+ if (existsSync10(relativeCandidate) || existsSync10(dirname4(relativeCandidate))) {
7177
7434
  return relativeCandidate;
7178
7435
  }
7179
7436
  return norm;
7180
7437
  }
7181
7438
  const stripped = norm.replace(/^[/\\]/, "");
7182
7439
  const resolved = resolve(baseDir, stripped);
7183
- if (existsSync9(resolved) || existsSync9(dirname3(resolved)))
7440
+ if (existsSync10(resolved) || existsSync10(dirname4(resolved)))
7184
7441
  return resolved;
7185
7442
  const baseNorm = normalize(baseDir);
7186
7443
  let cur = baseNorm;
7187
- while (cur && cur !== dirname3(cur)) {
7444
+ while (cur && cur !== dirname4(cur)) {
7188
7445
  const name = basename(cur);
7189
7446
  if (!name) {
7190
- cur = dirname3(cur);
7447
+ cur = dirname4(cur);
7191
7448
  continue;
7192
7449
  }
7193
7450
  let idx = stripped.toLowerCase().indexOf(name.toLowerCase());
@@ -7197,17 +7454,17 @@ function safeResolvePath(baseDir, userPath) {
7197
7454
  if (afterChar && afterChar !== "\\" && afterChar !== "/") {
7198
7455
  const fixed = stripped.slice(0, afterIdx) + sep + stripped.slice(afterIdx);
7199
7456
  const fixedResolved = resolve(baseDir, normalize(fixed));
7200
- if (existsSync9(fixedResolved) || existsSync9(dirname3(fixedResolved))) {
7457
+ if (existsSync10(fixedResolved) || existsSync10(dirname4(fixedResolved))) {
7201
7458
  return fixedResolved;
7202
7459
  }
7203
- const fromParent = resolve(dirname3(cur), normalize(fixed));
7204
- if (existsSync9(fromParent) || existsSync9(dirname3(fromParent))) {
7460
+ const fromParent = resolve(dirname4(cur), normalize(fixed));
7461
+ if (existsSync10(fromParent) || existsSync10(dirname4(fromParent))) {
7205
7462
  return fromParent;
7206
7463
  }
7207
7464
  }
7208
7465
  idx = stripped.toLowerCase().indexOf(name.toLowerCase(), idx + 1);
7209
7466
  }
7210
- cur = dirname3(cur);
7467
+ cur = dirname4(cur);
7211
7468
  }
7212
7469
  return resolved;
7213
7470
  }
@@ -7424,10 +7681,10 @@ __export(exports_audit_notifier, {
7424
7681
  DEFAULT_AUDIT_NOTIFIER_CONFIG: () => DEFAULT_AUDIT_NOTIFIER_CONFIG,
7425
7682
  AuditNotifier: () => AuditNotifier
7426
7683
  });
7427
- import { writeFileSync as writeFileSync5, appendFileSync as appendFileSync3, existsSync as existsSync10, mkdirSync as mkdirSync6 } from "fs";
7428
- import { join as join9, dirname as dirname4 } from "path";
7684
+ import { writeFileSync as writeFileSync5, appendFileSync as appendFileSync3, existsSync as existsSync11, mkdirSync as mkdirSync6 } from "fs";
7685
+ import { join as join10, dirname as dirname5 } from "path";
7429
7686
  import { homedir as homedir3 } from "os";
7430
- import { readFileSync as readFileSync5 } from "fs";
7687
+ import { readFileSync as readFileSync6 } from "fs";
7431
7688
 
7432
7689
  class AuditNotifier {
7433
7690
  config;
@@ -7452,7 +7709,7 @@ class AuditNotifier {
7452
7709
  }
7453
7710
  ensureLogDirectory() {
7454
7711
  if (this.config.filePath) {
7455
- const dir = dirname4(this.config.filePath);
7712
+ const dir = dirname5(this.config.filePath);
7456
7713
  mkdirSync6(dir, { recursive: true });
7457
7714
  }
7458
7715
  }
@@ -7582,11 +7839,11 @@ class AuditNotifier {
7582
7839
  }
7583
7840
  }
7584
7841
  readNotifications(limit = 100) {
7585
- if (!this.config.filePath || !existsSync10(this.config.filePath)) {
7842
+ if (!this.config.filePath || !existsSync11(this.config.filePath)) {
7586
7843
  return [];
7587
7844
  }
7588
7845
  try {
7589
- const content = readFileSync5(this.config.filePath, "utf8");
7846
+ const content = readFileSync6(this.config.filePath, "utf8");
7590
7847
  const lines = content.split(`
7591
7848
  `).filter(Boolean);
7592
7849
  return lines.slice(-limit).map((line) => JSON.parse(line));
@@ -7640,7 +7897,7 @@ var init_audit_notifier = __esm(() => {
7640
7897
  };
7641
7898
  DEFAULT_AUDIT_NOTIFIER_CONFIG = {
7642
7899
  enabled: false,
7643
- filePath: join9(homedir3(), ".mma", "logs", "audit-notifications.jsonl"),
7900
+ filePath: join10(homedir3(), ".mma", "logs", "audit-notifications.jsonl"),
7644
7901
  webhookTimeout: 5000,
7645
7902
  minSeverity: "medium",
7646
7903
  eventTypes: [
@@ -7657,26 +7914,26 @@ var init_audit_notifier = __esm(() => {
7657
7914
  });
7658
7915
 
7659
7916
  // src/modules/security/audit-log.ts
7660
- import { existsSync as existsSync11, mkdirSync as mkdirSync7, appendFileSync as appendFileSync4 } from "fs";
7661
- import { resolve as resolve3, join as join10 } from "path";
7917
+ import { existsSync as existsSync12, mkdirSync as mkdirSync7, appendFileSync as appendFileSync4 } from "fs";
7918
+ import { resolve as resolve3, join as join11 } from "path";
7662
7919
  import { homedir as homedir4 } from "os";
7663
7920
  function getAuditDir() {
7664
7921
  return _sessionAuditDir ?? _globalAuditDir;
7665
7922
  }
7666
7923
  function setAuditSessionDir(dir) {
7667
7924
  _sessionAuditDir = dir;
7668
- if (!existsSync11(dir)) {
7925
+ if (!existsSync12(dir)) {
7669
7926
  mkdirSync7(dir, { recursive: true, mode: 448 });
7670
7927
  }
7671
7928
  }
7672
7929
  function logAudit(entry) {
7673
7930
  const dir = getAuditDir();
7674
- if (!existsSync11(dir)) {
7931
+ if (!existsSync12(dir)) {
7675
7932
  mkdirSync7(dir, { recursive: true, mode: 448 });
7676
7933
  }
7677
7934
  try {
7678
7935
  const logEntry = JSON.stringify(entry);
7679
- appendFileSync4(join10(dir, "audit.jsonl"), logEntry + `
7936
+ appendFileSync4(join11(dir, "audit.jsonl"), logEntry + `
7680
7937
  `, "utf8");
7681
7938
  } catch {}
7682
7939
  try {
@@ -7740,7 +7997,7 @@ var init_audit_log = __esm(() => {
7740
7997
  });
7741
7998
 
7742
7999
  // src/tools/read-file.ts
7743
- import { readFileSync as readFileSync6, existsSync as existsSync12, statSync as statSync2, openSync, readSync, closeSync } from "fs";
8000
+ import { readFileSync as readFileSync7, existsSync as existsSync13, statSync as statSync2, openSync, readSync, closeSync } from "fs";
7744
8001
  import { extname } from "path";
7745
8002
  function readLineSlice(path, offset, limit) {
7746
8003
  const fd = openSync(path, "r");
@@ -7841,7 +8098,7 @@ var init_read_file = __esm(() => {
7841
8098
  })
7842
8099
  };
7843
8100
  }
7844
- if (!existsSync12(resolved)) {
8101
+ if (!existsSync13(resolved)) {
7845
8102
  const output = resolved !== path ? t("file.notfound_resolved", {
7846
8103
  path,
7847
8104
  resolved
@@ -7858,7 +8115,7 @@ var init_read_file = __esm(() => {
7858
8115
  total = slice.total;
7859
8116
  selected = slice.selected;
7860
8117
  } else {
7861
- const content = readFileSync6(resolved, "utf-8");
8118
+ const content = readFileSync7(resolved, "utf-8");
7862
8119
  lines = content.split(`
7863
8120
  `);
7864
8121
  total = lines.length;
@@ -7950,14 +8207,14 @@ __export(exports_session_isolation, {
7950
8207
  cleanupSessionTempDir: () => cleanupSessionTempDir,
7951
8208
  DEFAULT_SESSION_ISOLATION: () => DEFAULT_SESSION_ISOLATION
7952
8209
  });
7953
- import { join as join11, resolve as resolve5 } from "path";
8210
+ import { join as join12, resolve as resolve5 } from "path";
7954
8211
  import { homedir as homedir5 } from "os";
7955
- import { mkdirSync as mkdirSync8, existsSync as existsSync13 } from "fs";
8212
+ import { mkdirSync as mkdirSync8, existsSync as existsSync14 } from "fs";
7956
8213
  function createSessionContext(sessionId, projectDir, isolationConfig, securityOverrides) {
7957
8214
  const config = { ...DEFAULT_SESSION_ISOLATION, ...isolationConfig };
7958
- const baseDir = config.baseDir || join11(homedir5(), ".mma", "sessions", sessionId);
7959
- const tempDir = join11(baseDir, "temp");
7960
- if (config.isolateTempFiles && !existsSync13(tempDir)) {
8215
+ const baseDir = config.baseDir || join12(homedir5(), ".mma", "sessions", sessionId);
8216
+ const tempDir = join12(baseDir, "temp");
8217
+ if (config.isolateTempFiles && !existsSync14(tempDir)) {
7961
8218
  try {
7962
8219
  mkdirSync8(tempDir, { recursive: true, mode: 448 });
7963
8220
  } catch {}
@@ -8122,8 +8379,8 @@ function buildDiff(oldLines, newLines) {
8122
8379
  return result;
8123
8380
  }
8124
8381
  function formatLine(line, maxNumWidth) {
8125
- const num = line.type === "remove" ? line.oldNum : line.newNum;
8126
- const numStr = num !== null ? String(num).padStart(maxNumWidth) : " ".repeat(maxNumWidth);
8382
+ const num2 = line.type === "remove" ? line.oldNum : line.newNum;
8383
+ const numStr = num2 !== null ? String(num2).padStart(maxNumWidth) : " ".repeat(maxNumWidth);
8127
8384
  if (line.type === "remove") {
8128
8385
  return `${numStr} ${pc2.red("-")} ${line.content}`;
8129
8386
  } else if (line.type === "add") {
@@ -8207,8 +8464,8 @@ var init_diff = __esm(() => {
8207
8464
  });
8208
8465
 
8209
8466
  // src/tools/syntax-validator.ts
8210
- import { writeFileSync as writeFileSync6, existsSync as existsSync14, unlinkSync as unlinkSync3 } from "fs";
8211
- import { extname as extname2, dirname as dirname5 } from "path";
8467
+ import { writeFileSync as writeFileSync6, existsSync as existsSync15, unlinkSync as unlinkSync3 } from "fs";
8468
+ import { extname as extname2, dirname as dirname6 } from "path";
8212
8469
  import { spawn } from "child_process";
8213
8470
  function contentHash(content) {
8214
8471
  let h = 5381;
@@ -8272,7 +8529,7 @@ async function preValidateSyntax(filePath, content, baseDir) {
8272
8529
  const tmpFile = `${filePath}.tmp${ext}`;
8273
8530
  try {
8274
8531
  writeFileSync6(tmpFile, content, "utf-8");
8275
- await runCommand(`bun build --no-bundle --target=bun "${tmpFile}"`, dirname5(filePath), 5000);
8532
+ await runCommand(`bun build --no-bundle --target=bun "${tmpFile}"`, dirname6(filePath), 5000);
8276
8533
  SYNTAX_CACHE.set(filePath, { hash, error: null });
8277
8534
  return { valid: true };
8278
8535
  } catch (err) {
@@ -8284,7 +8541,7 @@ async function preValidateSyntax(filePath, content, baseDir) {
8284
8541
  return { valid: false, error };
8285
8542
  } finally {
8286
8543
  try {
8287
- if (existsSync14(tmpFile))
8544
+ if (existsSync15(tmpFile))
8288
8545
  unlinkSync3(tmpFile);
8289
8546
  } catch {}
8290
8547
  }
@@ -8298,7 +8555,7 @@ async function preValidateSyntax(filePath, content, baseDir) {
8298
8555
  const tmpFile = `${filePath}.tmp${ext}`;
8299
8556
  try {
8300
8557
  writeFileSync6(tmpFile, content, "utf-8");
8301
- await runCommand(`node --check "${tmpFile}"`, dirname5(filePath), 5000);
8558
+ await runCommand(`node --check "${tmpFile}"`, dirname6(filePath), 5000);
8302
8559
  SYNTAX_CACHE.set(filePath, { hash, error: null });
8303
8560
  return { valid: true };
8304
8561
  } catch (err) {
@@ -8310,7 +8567,7 @@ async function preValidateSyntax(filePath, content, baseDir) {
8310
8567
  return { valid: false, error };
8311
8568
  } finally {
8312
8569
  try {
8313
- if (existsSync14(tmpFile))
8570
+ if (existsSync15(tmpFile))
8314
8571
  unlinkSync3(tmpFile);
8315
8572
  } catch {}
8316
8573
  }
@@ -8350,8 +8607,8 @@ var init_syntax_validator = __esm(() => {
8350
8607
  });
8351
8608
 
8352
8609
  // src/tools/write-file.ts
8353
- import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync9, existsSync as existsSync15, readFileSync as readFileSync7 } from "fs";
8354
- import { dirname as dirname6 } from "path";
8610
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync9, existsSync as existsSync16, readFileSync as readFileSync8 } from "fs";
8611
+ import { dirname as dirname7 } from "path";
8355
8612
  var writeFileTool;
8356
8613
  var init_write_file = __esm(() => {
8357
8614
  init_i18n();
@@ -8409,8 +8666,8 @@ var init_write_file = __esm(() => {
8409
8666
  };
8410
8667
  }
8411
8668
  }
8412
- const dir = dirname6(resolved);
8413
- if (!existsSync15(dir)) {
8669
+ const dir = dirname7(resolved);
8670
+ if (!existsSync16(dir)) {
8414
8671
  mkdirSync9(dir, { recursive: true });
8415
8672
  }
8416
8673
  const validation = await preValidateSyntax(resolved, content, ctx.baseDir);
@@ -8421,10 +8678,10 @@ var init_write_file = __esm(() => {
8421
8678
  };
8422
8679
  }
8423
8680
  const conflicts = detectImportConflicts(content);
8424
- const fileExists = existsSync15(resolved);
8681
+ const fileExists = existsSync16(resolved);
8425
8682
  let oldContent = "";
8426
8683
  if (fileExists) {
8427
- oldContent = readFileSync7(resolved, "utf-8");
8684
+ oldContent = readFileSync8(resolved, "utf-8");
8428
8685
  }
8429
8686
  writeFileSync7(resolved, content, "utf-8");
8430
8687
  const diff = fileExists ? generateDiff(oldContent, content) : generateNewFileDiff(content);
@@ -8441,7 +8698,7 @@ var init_write_file = __esm(() => {
8441
8698
  });
8442
8699
 
8443
8700
  // src/tools/edit-file.ts
8444
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "fs";
8701
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
8445
8702
  var editFileTool;
8446
8703
  var init_edit_file = __esm(() => {
8447
8704
  init_i18n();
@@ -8489,7 +8746,7 @@ var init_edit_file = __esm(() => {
8489
8746
  })
8490
8747
  };
8491
8748
  }
8492
- const content = readFileSync8(resolved, "utf-8");
8749
+ const content = readFileSync9(resolved, "utf-8");
8493
8750
  const oldStr = String(args.old);
8494
8751
  const newStr = String(args.new);
8495
8752
  if (!content.includes(oldStr)) {
@@ -8697,7 +8954,7 @@ var init_grep_tool = __esm(() => {
8697
8954
  });
8698
8955
 
8699
8956
  // src/tools/list-dir.ts
8700
- import { readdirSync as readdirSync5, statSync as statSync3, existsSync as existsSync16 } from "fs";
8957
+ import { readdirSync as readdirSync5, statSync as statSync3, existsSync as existsSync17 } from "fs";
8701
8958
  import { resolve as resolve8 } from "path";
8702
8959
  var IGNORED_DIRS, listDirTool;
8703
8960
  var init_list_dir = __esm(() => {
@@ -8730,7 +8987,7 @@ var init_list_dir = __esm(() => {
8730
8987
  })
8731
8988
  };
8732
8989
  }
8733
- if (!existsSync16(resolved)) {
8990
+ if (!existsSync17(resolved)) {
8734
8991
  return { success: false, output: t("file.dir_notfound", { path }) };
8735
8992
  }
8736
8993
  const entries = readdirSync5(resolved).filter((e) => !IGNORED_DIRS.has(e));
@@ -8750,7 +9007,7 @@ var init_list_dir = __esm(() => {
8750
9007
  });
8751
9008
 
8752
9009
  // src/tools/create-dir.ts
8753
- import { mkdirSync as mkdirSync10, existsSync as existsSync17 } from "fs";
9010
+ import { mkdirSync as mkdirSync10, existsSync as existsSync18 } from "fs";
8754
9011
  var createDirTool;
8755
9012
  var init_create_dir = __esm(() => {
8756
9013
  init_i18n();
@@ -8793,7 +9050,7 @@ var init_create_dir = __esm(() => {
8793
9050
  })
8794
9051
  };
8795
9052
  }
8796
- if (!existsSync17(resolved)) {
9053
+ if (!existsSync18(resolved)) {
8797
9054
  mkdirSync10(resolved, { recursive: true });
8798
9055
  }
8799
9056
  ctx.fileOperationsCount = currentCount + 1;
@@ -8804,7 +9061,7 @@ var init_create_dir = __esm(() => {
8804
9061
  });
8805
9062
 
8806
9063
  // src/tools/delete-file.ts
8807
- import { unlinkSync as unlinkSync4, existsSync as existsSync18, statSync as statSync4, readFileSync as readFileSync9 } from "fs";
9064
+ import { unlinkSync as unlinkSync4, existsSync as existsSync19, statSync as statSync4, readFileSync as readFileSync10 } from "fs";
8808
9065
  var deleteFileTool;
8809
9066
  var init_delete_file = __esm(() => {
8810
9067
  init_i18n();
@@ -8848,13 +9105,13 @@ var init_delete_file = __esm(() => {
8848
9105
  })
8849
9106
  };
8850
9107
  }
8851
- if (!existsSync18(resolved)) {
9108
+ if (!existsSync19(resolved)) {
8852
9109
  return { success: false, output: t("file.notfound", { path }) };
8853
9110
  }
8854
9111
  if (statSync4(resolved).isDirectory()) {
8855
9112
  return { success: false, output: t("file.is_directory", { path }) };
8856
9113
  }
8857
- const content = readFileSync9(resolved, "utf-8");
9114
+ const content = readFileSync10(resolved, "utf-8");
8858
9115
  unlinkSync4(resolved);
8859
9116
  const diff = generateDeleteDiff(content);
8860
9117
  ctx.fileOperationsCount = currentCount + 1;
@@ -8865,8 +9122,8 @@ var init_delete_file = __esm(() => {
8865
9122
  });
8866
9123
 
8867
9124
  // src/tools/move-file.ts
8868
- import { renameSync as renameSync2, existsSync as existsSync19, mkdirSync as mkdirSync11 } from "fs";
8869
- import { resolve as resolve9, normalize as normalize3, dirname as dirname7 } from "path";
9125
+ import { renameSync as renameSync2, existsSync as existsSync20, mkdirSync as mkdirSync11 } from "fs";
9126
+ import { resolve as resolve9, normalize as normalize3, dirname as dirname8 } from "path";
8870
9127
  var moveFileTool;
8871
9128
  var init_move_file = __esm(() => {
8872
9129
  init_i18n();
@@ -8924,14 +9181,14 @@ var init_move_file = __esm(() => {
8924
9181
  })
8925
9182
  };
8926
9183
  }
8927
- if (!existsSync19(fromResolved)) {
9184
+ if (!existsSync20(fromResolved)) {
8928
9185
  return {
8929
9186
  success: false,
8930
9187
  output: t("file.not_found_short", { path: fromPath })
8931
9188
  };
8932
9189
  }
8933
- const toDir = dirname7(toResolved);
8934
- if (!existsSync19(toDir)) {
9190
+ const toDir = dirname8(toResolved);
9191
+ if (!existsSync20(toDir)) {
8935
9192
  mkdirSync11(toDir, { recursive: true });
8936
9193
  }
8937
9194
  renameSync2(fromResolved, toResolved);
@@ -8948,7 +9205,7 @@ var init_move_file = __esm(() => {
8948
9205
  });
8949
9206
 
8950
9207
  // src/tools/file-info.ts
8951
- import { statSync as statSync5, existsSync as existsSync20 } from "fs";
9208
+ import { statSync as statSync5, existsSync as existsSync21 } from "fs";
8952
9209
  var fileInfoTool;
8953
9210
  var init_file_info = __esm(() => {
8954
9211
  init_i18n();
@@ -8979,7 +9236,7 @@ var init_file_info = __esm(() => {
8979
9236
  })
8980
9237
  };
8981
9238
  }
8982
- if (!existsSync20(resolved)) {
9239
+ if (!existsSync21(resolved)) {
8983
9240
  return { success: false, output: t("file.not_found_short", { path }) };
8984
9241
  }
8985
9242
  const stat = statSync5(resolved);
@@ -10079,8 +10336,8 @@ var init_prompt_builder = __esm(() => {
10079
10336
  });
10080
10337
 
10081
10338
  // src/core/session-logger.ts
10082
- import { join as join12 } from "path";
10083
- import { readFileSync as readFileSync10, existsSync as existsSync21 } from "fs";
10339
+ import { join as join13 } from "path";
10340
+ import { readFileSync as readFileSync11, existsSync as existsSync22 } from "fs";
10084
10341
 
10085
10342
  class SessionLogger {
10086
10343
  session;
@@ -10258,7 +10515,12 @@ class SessionLogger {
10258
10515
  completionTokens: usage.completionTokens,
10259
10516
  totalTokens: usage.totalTokens,
10260
10517
  source: usage.source,
10261
- durationMs: usage.durationMs
10518
+ durationMs: usage.durationMs,
10519
+ cacheStable: usage.prefix ? Number(usage.prefix.stableRatio.toFixed(4)) : undefined,
10520
+ cacheCause: usage.prefix?.cause,
10521
+ cachedTokens: usage.cache?.cachedTokens,
10522
+ cacheWriteTokens: usage.cache?.cacheWriteTokens,
10523
+ cacheSource: usage.cache?.source
10262
10524
  });
10263
10525
  }
10264
10526
  logError(message) {
@@ -10288,10 +10550,10 @@ class SessionLogger {
10288
10550
  logSessionStart(data) {
10289
10551
  const meta = this.session?.getActiveMeta();
10290
10552
  if (meta) {
10291
- const logPath = join12(this.session.getSessionDirectory(meta.id), "session.jsonl");
10553
+ const logPath = join13(this.session.getSessionDirectory(meta.id), "session.jsonl");
10292
10554
  try {
10293
- if (existsSync21(logPath)) {
10294
- const content = readFileSync10(logPath, "utf-8");
10555
+ if (existsSync22(logPath)) {
10556
+ const content = readFileSync11(logPath, "utf-8");
10295
10557
  if (content.includes('"type":"session_start"'))
10296
10558
  return;
10297
10559
  }
@@ -10908,52 +11170,52 @@ ${output}
10908
11170
  }
10909
11171
  function parseNumber() {
10910
11172
  const start = i;
10911
- let num = "";
11173
+ let num2 = "";
10912
11174
  let invalid = false;
10913
11175
  if (text[i] === "-") {
10914
- num += text[i];
11176
+ num2 += text[i];
10915
11177
  i++;
10916
11178
  if (!isDigit(text[i]) && atEndOfNumber()) {
10917
- num += "0";
11179
+ num2 += "0";
10918
11180
  }
10919
11181
  }
10920
11182
  if (text[i] === "0" && isDigit(text[i + 1])) {
10921
11183
  invalid = true;
10922
11184
  }
10923
11185
  while (isDigit(text[i])) {
10924
- num += text[i];
11186
+ num2 += text[i];
10925
11187
  i++;
10926
11188
  }
10927
11189
  if (text[i] === ".") {
10928
- if (num === "" || num === "-") {
10929
- num += "0";
11190
+ if (num2 === "" || num2 === "-") {
11191
+ num2 += "0";
10930
11192
  }
10931
- num += text[i];
11193
+ num2 += text[i];
10932
11194
  i++;
10933
11195
  if (!isDigit(text[i])) {
10934
- num += "0";
11196
+ num2 += "0";
10935
11197
  }
10936
11198
  while (isDigit(text[i])) {
10937
- num += text[i];
11199
+ num2 += text[i];
10938
11200
  i++;
10939
11201
  }
10940
11202
  }
10941
11203
  if (i > start) {
10942
11204
  if (text[i] === "e" || text[i] === "E") {
10943
- if (num === "-") {
11205
+ if (num2 === "-") {
10944
11206
  invalid = true;
10945
11207
  }
10946
- num += text[i];
11208
+ num2 += text[i];
10947
11209
  i++;
10948
11210
  if (text[i] === "-" || text[i] === "+") {
10949
- num += text[i];
11211
+ num2 += text[i];
10950
11212
  i++;
10951
11213
  }
10952
11214
  if (!isDigit(text[i])) {
10953
- num += "0";
11215
+ num2 += "0";
10954
11216
  }
10955
11217
  while (isDigit(text[i])) {
10956
- num += text[i];
11218
+ num2 += text[i];
10957
11219
  i++;
10958
11220
  }
10959
11221
  }
@@ -10961,7 +11223,7 @@ ${output}
10961
11223
  i = start;
10962
11224
  return false;
10963
11225
  }
10964
- output += invalid ? `"${text.substring(start, i)}"` : num;
11226
+ output += invalid ? `"${text.substring(start, i)}"` : num2;
10965
11227
  return true;
10966
11228
  }
10967
11229
  return false;
@@ -11162,8 +11424,10 @@ ${PLAN_SYSTEM_PROMPT_RULES}`;
11162
11424
  class OrchestratorClient {
11163
11425
  config;
11164
11426
  provider = null;
11165
- constructor(config, defaultProvider) {
11427
+ getSessionId;
11428
+ constructor(config, defaultProvider, opts) {
11166
11429
  this.config = config;
11430
+ this.getSessionId = opts?.getSessionId;
11167
11431
  if (!config.model)
11168
11432
  return;
11169
11433
  if (config.provider) {
@@ -11183,6 +11447,7 @@ class OrchestratorClient {
11183
11447
  contextWindow: config.contextWindow ?? DEFAULT_ORCH_CONTEXT_WINDOW,
11184
11448
  retry: config.retry,
11185
11449
  rateLimits: config.rateLimits,
11450
+ getSessionId: this.getSessionId,
11186
11451
  logger: config.logger
11187
11452
  });
11188
11453
  manager.setModel(config.model);
@@ -12208,7 +12473,7 @@ var init_stuck_detector = __esm(() => {
12208
12473
  });
12209
12474
 
12210
12475
  // src/modules/artifacts/store.ts
12211
- import { existsSync as existsSync22, mkdirSync as mkdirSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "node:fs";
12476
+ import { existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "node:fs";
12212
12477
  import { resolve as resolve10, relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
12213
12478
 
12214
12479
  class ArtifactStore {
@@ -12246,9 +12511,9 @@ class ArtifactStore {
12246
12511
  const abs = resolve10(this.root, path);
12247
12512
  if (!ArtifactStore.isInside(this.root, abs))
12248
12513
  return null;
12249
- if (!existsSync22(abs))
12514
+ if (!existsSync23(abs))
12250
12515
  return null;
12251
- return readFileSync11(abs, "utf8");
12516
+ return readFileSync12(abs, "utf8");
12252
12517
  }
12253
12518
  summary(content, maxChars) {
12254
12519
  if (content.length <= maxChars)
@@ -12748,23 +13013,41 @@ var init_moe_executor = __esm(() => {
12748
13013
  });
12749
13014
 
12750
13015
  // src/modules/lsp/project-root.ts
12751
- import { existsSync as existsSync23 } from "fs";
12752
- import { dirname as dirname8, join as join13, relative as relative3, isAbsolute as isAbsolute3 } from "path";
13016
+ import { existsSync as existsSync24 } from "fs";
13017
+ import { dirname as dirname9, join as join14, relative as relative3, isAbsolute as isAbsolute3 } from "path";
13018
+ import { platform as platform4 } from "os";
13019
+ function resolveTscCommand(startDir, maxLevels = 8) {
13020
+ const runtime = process.execPath;
13021
+ let dir = startDir;
13022
+ for (let i = 0;i < maxLevels; i++) {
13023
+ const js = join14(dir, "node_modules", "typescript", "bin", "tsc");
13024
+ if (existsSync24(js))
13025
+ return `"${runtime}" "${js}"`;
13026
+ const stub = join14(dir, "node_modules", ".bin", platform4() === "win32" ? "tsc.cmd" : "tsc");
13027
+ if (existsSync24(stub))
13028
+ return `"${stub}"`;
13029
+ const parent = dirname9(dir);
13030
+ if (parent === dir)
13031
+ break;
13032
+ dir = parent;
13033
+ }
13034
+ return null;
13035
+ }
12753
13036
  function findProjectRoot(filePath, baseDir, markers) {
12754
13037
  if (!markers || markers.length === 0)
12755
13038
  return baseDir;
12756
- let dir = dirname8(filePath);
13039
+ let dir = dirname9(filePath);
12757
13040
  const root = baseDir.replace(/[\\/]+$/, "");
12758
13041
  const rel = relative3(root, dir);
12759
13042
  if (rel && rel.startsWith("..") || isAbsolute3(rel))
12760
13043
  dir = root;
12761
13044
  while (true) {
12762
- if (markers.some((m) => existsSync23(join13(dir, m)))) {
13045
+ if (markers.some((m) => existsSync24(join14(dir, m)))) {
12763
13046
  return dir;
12764
13047
  }
12765
13048
  if (dir === root)
12766
13049
  return dir;
12767
- const parent = dirname8(dir);
13050
+ const parent = dirname9(dir);
12768
13051
  if (parent === dir)
12769
13052
  return root;
12770
13053
  dir = parent;
@@ -12982,13 +13265,13 @@ var init_js_identifiers = __esm(() => {
12982
13265
  });
12983
13266
 
12984
13267
  // src/modules/execution/audit-runners.ts
12985
- import { existsSync as existsSync24, readdirSync as readdirSync6, readFileSync as readFileSync12 } from "fs";
12986
- import { dirname as dirname9, join as join14, resolve as resolve11 } from "path";
13268
+ import { existsSync as existsSync25, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
13269
+ import { dirname as dirname10, join as join15, resolve as resolve11 } from "path";
12987
13270
  function resolveTestCommand(dir) {
12988
- const pkgPath = join14(dir, "package.json");
12989
- if (existsSync24(pkgPath)) {
13271
+ const pkgPath = join15(dir, "package.json");
13272
+ if (existsSync25(pkgPath)) {
12990
13273
  try {
12991
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
13274
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
12992
13275
  const script = pkg?.scripts?.test;
12993
13276
  if (typeof script === "string" && script.trim())
12994
13277
  return script.trim();
@@ -13004,7 +13287,7 @@ function resolveTestCommand(dir) {
13004
13287
  "jest.config.cjs",
13005
13288
  "bunfig.toml"
13006
13289
  ]) {
13007
- if (existsSync24(join14(dir, f))) {
13290
+ if (existsSync25(join15(dir, f))) {
13008
13291
  if (f.startsWith("vitest"))
13009
13292
  return "bunx vitest run";
13010
13293
  if (f.startsWith("jest"))
@@ -13013,12 +13296,12 @@ function resolveTestCommand(dir) {
13013
13296
  return "bun test";
13014
13297
  }
13015
13298
  }
13016
- if (existsSync24(join14(dir, "pyproject.toml")) || existsSync24(join14(dir, "pytest.ini")) || existsSync24(join14(dir, "conftest.py"))) {
13299
+ if (existsSync25(join15(dir, "pyproject.toml")) || existsSync25(join15(dir, "pytest.ini")) || existsSync25(join15(dir, "conftest.py"))) {
13017
13300
  return "python -m pytest -q";
13018
13301
  }
13019
- if (existsSync24(join14(dir, "go.mod")))
13302
+ if (existsSync25(join15(dir, "go.mod")))
13020
13303
  return "go test ./...";
13021
- if (existsSync24(join14(dir, "Cargo.toml")))
13304
+ if (existsSync25(join15(dir, "Cargo.toml")))
13022
13305
  return "cargo test";
13023
13306
  return "bun test";
13024
13307
  }
@@ -13032,7 +13315,7 @@ function findTestFile(dir, depth = 0) {
13032
13315
  return null;
13033
13316
  }
13034
13317
  for (const e of entries) {
13035
- const full = join14(dir, e.name);
13318
+ const full = join15(dir, e.name);
13036
13319
  if (e.isDirectory()) {
13037
13320
  if (SKIP_DIRS.has(e.name))
13038
13321
  continue;
@@ -13108,12 +13391,12 @@ function findTypecheckRoot(baseDir, existingFiles = []) {
13108
13391
  for (const start of candidates) {
13109
13392
  let dir = resolve11(start);
13110
13393
  for (let depth = 0;depth <= 10; depth++) {
13111
- if (existsSync24(join14(dir, "tsconfig.json"))) {
13394
+ if (existsSync25(join15(dir, "tsconfig.json"))) {
13112
13395
  if (!best || depth < best.depth)
13113
13396
  best = { depth, root: dir };
13114
13397
  break;
13115
13398
  }
13116
- const parent = dirname9(dir);
13399
+ const parent = dirname10(dir);
13117
13400
  if (parent === dir)
13118
13401
  break;
13119
13402
  dir = parent;
@@ -13122,7 +13405,10 @@ function findTypecheckRoot(baseDir, existingFiles = []) {
13122
13405
  return best?.root ?? null;
13123
13406
  }
13124
13407
  async function runTypecheck(baseDir) {
13125
- const entry = processRegistry.start("npx --no-install tsc --noEmit --skipLibCheck", baseDir);
13408
+ const tsc = resolveTscCommand(baseDir);
13409
+ if (!tsc)
13410
+ return null;
13411
+ const entry = processRegistry.start(`${tsc} --noEmit --skipLibCheck`, baseDir);
13126
13412
  const exited = await processRegistry.waitForExit(entry.id, 90000);
13127
13413
  const output = entry.log.join(`
13128
13414
  `);
@@ -13135,6 +13421,7 @@ var SKIP_DIRS, TEST_EXT_RE, PY_TEST_RE, TEST_STEP_RE;
13135
13421
  var init_audit_runners = __esm(() => {
13136
13422
  init_bash();
13137
13423
  init_processes();
13424
+ init_project_root();
13138
13425
  SKIP_DIRS = new Set([
13139
13426
  "node_modules",
13140
13427
  ".git",
@@ -13152,11 +13439,11 @@ var init_audit_runners = __esm(() => {
13152
13439
  });
13153
13440
 
13154
13441
  // src/modules/execution/auditor.ts
13155
- import { existsSync as existsSync25, readdirSync as readdirSync7 } from "fs";
13156
- import { resolve as resolve12, join as join15, basename as basename2 } from "path";
13442
+ import { existsSync as existsSync26, readdirSync as readdirSync7 } from "fs";
13443
+ import { resolve as resolve12, join as join16, basename as basename2 } from "path";
13157
13444
  function findExistingFile(baseDir, filePath) {
13158
13445
  const direct = resolve12(baseDir, filePath);
13159
- if (existsSync25(direct))
13446
+ if (existsSync26(direct))
13160
13447
  return direct;
13161
13448
  const name = basename2(filePath).toLowerCase();
13162
13449
  const suffix = toForwardSlash(filePath).toLowerCase();
@@ -13173,7 +13460,7 @@ function findExistingFile(baseDir, filePath) {
13173
13460
  for (const e of entries) {
13174
13461
  if (found)
13175
13462
  return;
13176
- const full = join15(dir, e.name);
13463
+ const full = join16(dir, e.name);
13177
13464
  if (e.isDirectory()) {
13178
13465
  if (SKIP_DIRS.has(e.name))
13179
13466
  continue;
@@ -13312,8 +13599,8 @@ var init_auditor = __esm(() => {
13312
13599
  });
13313
13600
 
13314
13601
  // src/modules/execution/verifier.ts
13315
- import { existsSync as existsSync26, readFileSync as readFileSync13 } from "fs";
13316
- import { resolve as resolve13, extname as extname3, join as join16 } from "path";
13602
+ import { existsSync as existsSync27, readFileSync as readFileSync14 } from "fs";
13603
+ import { resolve as resolve13, extname as extname3, dirname as dirname11, join as join17 } from "path";
13317
13604
  import { spawn as spawn4 } from "child_process";
13318
13605
 
13319
13606
  class StepVerifier {
@@ -13323,7 +13610,7 @@ class StepVerifier {
13323
13610
  }
13324
13611
  async checkFileExists(path) {
13325
13612
  const resolved = resolve13(this.baseDir, path);
13326
- const exists = existsSync26(resolved);
13613
+ const exists = existsSync27(resolved);
13327
13614
  return {
13328
13615
  passed: exists,
13329
13616
  message: exists ? t("verify.file_exists", { path }) : t("verify.file_not_found", { path })
@@ -13342,11 +13629,14 @@ class StepVerifier {
13342
13629
  }
13343
13630
  async runTypeCheck() {
13344
13631
  const tsconfigPath = resolve13(this.baseDir, "tsconfig.json");
13345
- if (!existsSync26(tsconfigPath)) {
13632
+ if (!existsSync27(tsconfigPath)) {
13346
13633
  return { passed: true, message: "No tsconfig.json found — skipping type check" };
13347
13634
  }
13635
+ const tsc = resolveTscCommand(this.baseDir);
13636
+ if (!tsc)
13637
+ return { passed: true, message: "tsc not installed — skipping type check" };
13348
13638
  try {
13349
- await this.runAsync("npx tsc --noEmit", this.baseDir, 60000);
13639
+ await this.runAsync(`${tsc} --noEmit`, this.baseDir, 60000);
13350
13640
  return { passed: true, message: "TypeScript type check passed" };
13351
13641
  } catch (e) {
13352
13642
  const stderr = e.stderr?.toString() || e.stdout?.toString() || e.message;
@@ -13355,12 +13645,15 @@ class StepVerifier {
13355
13645
  }
13356
13646
  async runTypeCheckForFile(filePath) {
13357
13647
  const projectRoot = findProjectRoot(filePath, this.baseDir, ["tsconfig.json", "package.json"]);
13358
- const tsconfigPath = join16(projectRoot, "tsconfig.json");
13359
- if (!existsSync26(tsconfigPath)) {
13648
+ const tsconfigPath = join17(projectRoot, "tsconfig.json");
13649
+ if (!existsSync27(tsconfigPath)) {
13360
13650
  return { passed: true, message: "No tsconfig.json found — skipping type check" };
13361
13651
  }
13652
+ const tsc = resolveTscCommand(projectRoot);
13653
+ if (!tsc)
13654
+ return { passed: true, message: "tsc not installed — skipping type check" };
13362
13655
  try {
13363
- await this.runAsync("npx tsc --noEmit --skipLibCheck", projectRoot, 60000);
13656
+ await this.runAsync(`${tsc} --noEmit --skipLibCheck`, projectRoot, 60000);
13364
13657
  return { passed: true, message: "TypeScript type check passed" };
13365
13658
  } catch (e) {
13366
13659
  const stderr = e.stderr?.toString() || e.stdout?.toString() || e.message;
@@ -13369,7 +13662,7 @@ class StepVerifier {
13369
13662
  }
13370
13663
  async runTests() {
13371
13664
  const pkgPath = resolve13(this.baseDir, "package.json");
13372
- if (!existsSync26(pkgPath)) {
13665
+ if (!existsSync27(pkgPath)) {
13373
13666
  return { passed: true, message: "No package.json found — skipping tests" };
13374
13667
  }
13375
13668
  try {
@@ -13411,13 +13704,13 @@ class StepVerifier {
13411
13704
  const path = rest.slice(0, colon);
13412
13705
  const needle = rest.slice(colon + 1);
13413
13706
  const resolved = resolve13(this.baseDir, path);
13414
- if (!existsSync26(resolved)) {
13707
+ if (!existsSync27(resolved)) {
13415
13708
  const item = { passed: false, message: t("verify.file_not_found", { path }) };
13416
13709
  details.push(item);
13417
13710
  errors.push(`[${subtask.id}] ${item.message}`);
13418
13711
  continue;
13419
13712
  }
13420
- const content = readFileSync13(resolved, "utf-8");
13713
+ const content = readFileSync14(resolved, "utf-8");
13421
13714
  const passed = content.includes(needle);
13422
13715
  details.push({ passed, message: `substring "${needle}" in ${path}: ${passed}` });
13423
13716
  if (!passed)
@@ -13513,8 +13806,11 @@ class StepVerifier {
13513
13806
  async validateSyntax(filePath) {
13514
13807
  const ext = extname3(filePath);
13515
13808
  if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
13809
+ const tsc = resolveTscCommand(dirname11(filePath));
13810
+ if (!tsc)
13811
+ return true;
13516
13812
  try {
13517
- await this.runAsync(`npx tsc --noEmit --skipLibCheck "${filePath}"`, this.baseDir, 1e4);
13813
+ await this.runAsync(`${tsc} --noEmit --skipLibCheck "${filePath}"`, this.baseDir, 20000);
13518
13814
  return true;
13519
13815
  } catch (err) {
13520
13816
  if (err.status === 127 || err.message.includes("not found") || err.message.includes("ENOENT")) {
@@ -13603,7 +13899,7 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
13603
13899
  rateLimits: config.security?.rateLimits,
13604
13900
  logger,
13605
13901
  experts: config.experts
13606
- }, llmProvider);
13902
+ }, llmProvider, { getSessionId: () => sessionId });
13607
13903
  }
13608
13904
  if (!orchestrator.isEnabled()) {
13609
13905
  logger.warn("MoE enabled but no orchestrator model configured — falling back to single-agent. Set orchestrator.model to activate MoE.");
@@ -13844,11 +14140,18 @@ function resolvePrice(model, config) {
13844
14140
  return direct;
13845
14141
  return ZEN_PRICES[bare];
13846
14142
  }
13847
- function calculateCost(model, promptTokens, completionTokens, config) {
14143
+ function calculateCostDetailed(model, promptTokens, completionTokens, config, cache) {
13848
14144
  const price = resolvePrice(model, config);
13849
14145
  if (!price)
13850
14146
  return;
13851
- return promptTokens / 1e6 * price.input + completionTokens / 1e6 * price.output;
14147
+ const cached = Math.max(0, cache?.cachedTokens ?? 0);
14148
+ const write = Math.max(0, cache?.cacheWriteTokens ?? 0);
14149
+ const uncached = Math.max(0, promptTokens - cached);
14150
+ const cachedRate = price.cachedInput ?? price.input;
14151
+ const writeRate = price.cacheWrite ?? 0;
14152
+ const cost = uncached / 1e6 * price.input + cached / 1e6 * cachedRate + write / 1e6 * writeRate + completionTokens / 1e6 * price.output;
14153
+ const saved = cached / 1e6 * (price.input - cachedRate);
14154
+ return { cost, saved };
13852
14155
  }
13853
14156
  function formatCost(cost) {
13854
14157
  if (cost === 0)
@@ -13868,12 +14171,12 @@ var init_prices = __esm(() => {
13868
14171
  "nemotron-3-ultra-free": { input: 0, output: 0 },
13869
14172
  "nemotron-3.5-lightning-free": { input: 0, output: 0 },
13870
14173
  "muse-spark-1.2-contributor-free": { input: 0, output: 0 },
13871
- "minimax-m3": { input: 0.3, output: 1.2 },
13872
- "minimax-m2.7": { input: 0.3, output: 1.2 },
13873
- "minimax-m2.5": { input: 0.3, output: 1.2 },
13874
- "glm-5.2": { input: 1.4, output: 4.4 },
13875
- "glm-5.1": { input: 1.4, output: 4.4 },
13876
- "glm-5": { input: 1, output: 3.2 },
14174
+ "minimax-m3": { input: 0.3, output: 1.2, cachedInput: 0.06 },
14175
+ "minimax-m2.7": { input: 0.3, output: 1.2, cachedInput: 0.06 },
14176
+ "minimax-m2.5": { input: 0.3, output: 1.2, cachedInput: 0.06 },
14177
+ "glm-5.2": { input: 1.4, output: 4.4, cachedInput: 0.26 },
14178
+ "glm-5.1": { input: 1.4, output: 4.4, cachedInput: 0.26 },
14179
+ "glm-5": { input: 1, output: 3.2, cachedInput: 0.2 },
13877
14180
  "glm-5.3": { input: 1.4, output: 4.4 },
13878
14181
  "kimi-k2.7-code": { input: 0.95, output: 4 },
13879
14182
  "kimi-k3": { input: 3, output: 15 },
@@ -13935,6 +14238,7 @@ class CostTracker {
13935
14238
  config;
13936
14239
  model;
13937
14240
  _total = 0;
14241
+ _saved = 0;
13938
14242
  _known = false;
13939
14243
  byProvider = new Map;
13940
14244
  constructor(model, config) {
@@ -13944,24 +14248,28 @@ class CostTracker {
13944
14248
  setModel(model) {
13945
14249
  this.model = model;
13946
14250
  }
13947
- record(promptTokens, completionTokens, provider) {
14251
+ record(promptTokens, completionTokens, provider, cache) {
13948
14252
  const key = provider || "unknown";
13949
- const cost = calculateCost(this.model, promptTokens, completionTokens, this.config);
13950
- if (cost === undefined)
14253
+ const result = calculateCostDetailed(this.model, promptTokens, completionTokens, this.config, cache);
14254
+ if (!result)
13951
14255
  return;
13952
14256
  this._known = true;
13953
- this._total += cost;
14257
+ this._total += result.cost;
14258
+ this._saved += result.saved;
13954
14259
  let entry = this.byProvider.get(key);
13955
14260
  if (!entry) {
13956
14261
  entry = { total: 0, known: false };
13957
14262
  this.byProvider.set(key, entry);
13958
14263
  }
13959
14264
  entry.known = true;
13960
- entry.total += cost;
14265
+ entry.total += result.cost;
13961
14266
  }
13962
14267
  get total() {
13963
14268
  return this._known ? this._total : undefined;
13964
14269
  }
14270
+ get saved() {
14271
+ return this._known ? this._saved : undefined;
14272
+ }
13965
14273
  totalFor(provider) {
13966
14274
  const entry = this.byProvider.get(provider);
13967
14275
  return entry && entry.known ? entry.total : undefined;
@@ -14042,6 +14350,10 @@ function createLoopState() {
14042
14350
  apiCompletionChars: 0,
14043
14351
  estimatedPromptTokensTotal: 0,
14044
14352
  totalLlmDuration: 0,
14353
+ cacheCachedTotal: 0,
14354
+ cacheUncachedTotal: 0,
14355
+ cacheWriteTotal: 0,
14356
+ cacheSource: "none",
14045
14357
  auditRetries: 0,
14046
14358
  lastAuditSummary: "",
14047
14359
  emptyResponseRetries: 0,
@@ -14148,6 +14460,7 @@ class TokenTracker {
14148
14460
  }
14149
14461
  beginIteration(state, estimatedPromptTokens) {
14150
14462
  state.estimatedPromptTokensTotal += estimatedPromptTokens;
14463
+ state.cacheUsage = undefined;
14151
14464
  return {
14152
14465
  promptBefore: state.apiPromptTokens,
14153
14466
  completionBefore: state.apiCompletionTokens
@@ -14156,6 +14469,7 @@ class TokenTracker {
14156
14469
  recordApiUsage(state, baseline, usage) {
14157
14470
  state.apiPromptTokens = baseline.promptBefore + usage.promptTokens;
14158
14471
  state.apiCompletionTokens = baseline.completionBefore + usage.completionTokens;
14472
+ state.cacheUsage = usage.cache;
14159
14473
  }
14160
14474
  addCompletionChars(state, chars) {
14161
14475
  state.apiCompletionChars += chars;
@@ -14166,14 +14480,22 @@ class TokenTracker {
14166
14480
  const source = usagePrompt > 0 || usageCompletion > 0 ? "api" : "estimate";
14167
14481
  const prompt = source === "api" ? usagePrompt : contextTokens;
14168
14482
  const completion = source === "api" ? usageCompletion : estimateTokens(textContent);
14483
+ if (state.cacheUsage) {
14484
+ state.cacheCachedTotal += state.cacheUsage.cachedTokens;
14485
+ state.cacheUncachedTotal += state.cacheUsage.uncachedTokens;
14486
+ state.cacheWriteTotal += state.cacheUsage.cacheWriteTokens;
14487
+ state.cacheSource = state.cacheUsage.source;
14488
+ }
14169
14489
  slog.logLlmUsage(iteration, {
14170
14490
  promptTokens: prompt,
14171
14491
  completionTokens: completion,
14172
14492
  totalTokens: prompt + completion,
14173
14493
  source,
14174
- durationMs
14494
+ durationMs,
14495
+ prefix: state.prefixDelta,
14496
+ cache: state.cacheUsage
14175
14497
  });
14176
- this.costTracker.record(prompt, completion, this.getProviderName());
14498
+ this.costTracker.record(prompt, completion, this.getProviderName(), source === "api" ? state.cacheUsage : undefined);
14177
14499
  }
14178
14500
  resolveFinal(state) {
14179
14501
  if (state.apiPromptTokens > 0 || state.apiCompletionTokens > 0) {
@@ -14192,6 +14514,75 @@ var init_token_tracker = __esm(() => {
14192
14514
  init_token_counter();
14193
14515
  });
14194
14516
 
14517
+ // src/core/agent/prefix-monitor.ts
14518
+ function serializeTools(tools) {
14519
+ return tools.map((t2) => `${t2.name}\x01${t2.description}\x01${JSON.stringify(t2.parameters)}`).join("\x02");
14520
+ }
14521
+ function serializeMessages(messages) {
14522
+ return messages.map((m) => `${m.role}\x01${typeof m.content === "string" ? m.content : JSON.stringify(m.content)}`).join("\x02");
14523
+ }
14524
+ function buildPromptSnapshot(messages, tools) {
14525
+ const system = [];
14526
+ const rest = [];
14527
+ for (const m of messages) {
14528
+ if (m.role === "system")
14529
+ system.push(m);
14530
+ else
14531
+ rest.push(m);
14532
+ }
14533
+ return {
14534
+ system: serializeMessages(system),
14535
+ tools: serializeTools(tools),
14536
+ history: serializeMessages(rest)
14537
+ };
14538
+ }
14539
+ function frame(s) {
14540
+ const full = s.system + SEP + s.tools + SEP + s.history;
14541
+ const toolsStart = s.system.length + SEP.length;
14542
+ const historyStart = toolsStart + s.tools.length + SEP.length;
14543
+ return { full, toolsStart, historyStart };
14544
+ }
14545
+ function diffPrompt(prev, curr, countTokens) {
14546
+ const c = frame(curr);
14547
+ const currTokens = countTokens(c.full);
14548
+ if (!prev) {
14549
+ return {
14550
+ prevTokens: 0,
14551
+ currTokens,
14552
+ commonPrefixTokens: 0,
14553
+ stableRatio: 0,
14554
+ cause: "unknown"
14555
+ };
14556
+ }
14557
+ const p = frame(prev);
14558
+ const prevTokens = countTokens(p.full);
14559
+ const maxCp = Math.min(p.full.length, c.full.length);
14560
+ let cp = 0;
14561
+ while (cp < maxCp && p.full[cp] === c.full[cp])
14562
+ cp++;
14563
+ const commonPrefixTokens = countTokens(c.full.slice(0, cp));
14564
+ const stableRatio = currTokens === 0 ? 0 : Math.min(1, commonPrefixTokens / currTokens);
14565
+ if (cp === maxCp) {
14566
+ return { prevTokens, currTokens, commonPrefixTokens, stableRatio, cause: "none" };
14567
+ }
14568
+ let cause;
14569
+ if (cp >= c.historyStart)
14570
+ cause = "history";
14571
+ else if (cp >= c.toolsStart)
14572
+ cause = "tools";
14573
+ else
14574
+ cause = "system";
14575
+ const window = c.full.slice(Math.max(0, cp - 40), cp + 160) + p.full.slice(Math.max(0, cp - 40), cp + 160);
14576
+ if (VOLATILE_RE.test(window))
14577
+ cause = "volatile";
14578
+ return { prevTokens, currTokens, commonPrefixTokens, stableRatio, cause };
14579
+ }
14580
+ var SEP = `
14581
+ `, VOLATILE_RE;
14582
+ var init_prefix_monitor = __esm(() => {
14583
+ VOLATILE_RE = /(\d{4}-\d{2}-\d{2}|\d{2}:\d{2}:\d{2}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}|[A-Za-z]:\\|\\AppData\\|\\Temp\\|\/tmp\/)/;
14584
+ });
14585
+
14195
14586
  // src/core/agent/reasoning-resolver.ts
14196
14587
  class ReasoningEffortResolver {
14197
14588
  resolve(deps) {
@@ -14604,8 +14995,8 @@ var init_audit_gate = __esm(() => {
14604
14995
 
14605
14996
  // src/core/prompt-overflow.ts
14606
14997
  import { createHash } from "crypto";
14607
- import { existsSync as existsSync27, mkdirSync as mkdirSync13, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "fs";
14608
- import { join as join17 } from "path";
14998
+ import { existsSync as existsSync28, mkdirSync as mkdirSync13, readFileSync as readFileSync15, writeFileSync as writeFileSync10 } from "fs";
14999
+ import { join as join18 } from "path";
14609
15000
  function dryRunOverflow(allBlocks, systemBudget) {
14610
15001
  const builder = new PromptBuilder(systemBudget);
14611
15002
  builder.addBlocks(allBlocks);
@@ -14619,10 +15010,10 @@ function cacheKey(kind, content, maxTokens) {
14619
15010
  }
14620
15011
  function readCache(cacheDir, key) {
14621
15012
  try {
14622
- const path = join17(cacheDir, `${key}.md`);
14623
- if (!existsSync27(path))
15013
+ const path = join18(cacheDir, `${key}.md`);
15014
+ if (!existsSync28(path))
14624
15015
  return null;
14625
- const raw = readFileSync14(path, "utf-8").trim();
15016
+ const raw = readFileSync15(path, "utf-8").trim();
14626
15017
  if (!raw)
14627
15018
  return null;
14628
15019
  try {
@@ -14640,7 +15031,7 @@ function readCache(cacheDir, key) {
14640
15031
  function writeCache(cacheDir, key, entry) {
14641
15032
  try {
14642
15033
  mkdirSync13(cacheDir, { recursive: true });
14643
- writeFileSync10(join17(cacheDir, `${key}.md`), JSON.stringify(entry), "utf-8");
15034
+ writeFileSync10(join18(cacheDir, `${key}.md`), JSON.stringify(entry), "utf-8");
14644
15035
  } catch {}
14645
15036
  }
14646
15037
  async function collectText(provider, prompt, maxTokens) {
@@ -14800,7 +15191,7 @@ function contextWindowHint(config, configDir, recommended) {
14800
15191
  if (src.source === "global") {
14801
15192
  return `run "mma context ${recommended}"`;
14802
15193
  }
14803
- return `edit "${join17(configDir, "config", "provider.json")}" → provider.entries[label="${src.label}"].contextWindow = ${recommended}`;
15194
+ return `edit "${join18(configDir, "config", "provider.json")}" → provider.entries[label="${src.label}"].contextWindow = ${recommended}`;
14804
15195
  }
14805
15196
  function recommendContextSize(neededSystemTokens) {
14806
15197
  const sizes = [8192, 16384, 32768, 65536, 131072, 262144];
@@ -14850,7 +15241,7 @@ var init_prompt_overflow = __esm(() => {
14850
15241
  });
14851
15242
 
14852
15243
  // src/core/agent.ts
14853
- import { join as join18 } from "path";
15244
+ import { join as join19 } from "path";
14854
15245
  function mutationTargetKey(name, rawArgs) {
14855
15246
  let a = null;
14856
15247
  if (typeof rawArgs === "string") {
@@ -15005,7 +15396,7 @@ class Agent {
15005
15396
  includedTokens: dry.blocks.filter((b) => b.included).reduce((s, b) => s + b.tokens, 0),
15006
15397
  systemBudget,
15007
15398
  provider: cfg.instructions?.summarize === false ? null : this.deps.llmProvider,
15008
- cacheDir: join18(this.deps.baseDir, ".mma", "cache", "prompt-summaries"),
15399
+ cacheDir: join19(this.deps.baseDir, ".mma", "cache", "prompt-summaries"),
15009
15400
  logger: this.deps.logger
15010
15401
  });
15011
15402
  for (const r of res.replacements) {
@@ -15220,6 +15611,12 @@ class Agent {
15220
15611
  compactionService.compactIfNeeded(state);
15221
15612
  this.refreshSystemPrompt();
15222
15613
  const history = contextManager.getActiveHistory();
15614
+ const promptSnapshot = buildPromptSnapshot(history, allToolsForBudget);
15615
+ state.prefixDelta = diffPrompt(state.prevPrompt, promptSnapshot, estimateTokens);
15616
+ state.prevPrompt = promptSnapshot;
15617
+ if (state.prefixDelta.cause === "system" || state.prefixDelta.cause === "tools" || state.prefixDelta.cause === "history" || state.prefixDelta.cause === "volatile") {
15618
+ state.lastPrefixBreak = state.prefixDelta;
15619
+ }
15223
15620
  slog.logToolDefs(allToolsForBudget.length, allToolsForBudget.map((t2) => t2.name), state.iteration);
15224
15621
  if (state.iteration === 1) {
15225
15622
  const { blocks } = this.buildSystemPrompt();
@@ -15468,6 +15865,7 @@ class Agent {
15468
15865
  const tokensUsed = contextManager.getEstimatedTokens();
15469
15866
  const budget = contextManager.getBudget();
15470
15867
  const usageTokens = tokenTracker.resolveFinal(state);
15868
+ const cacheStats = this.buildCacheStats(state);
15471
15869
  if (state.iteration >= config.maxToolIterations && !state.finalAnswerAccepted) {
15472
15870
  return {
15473
15871
  success: false,
@@ -15481,6 +15879,7 @@ class Agent {
15481
15879
  totalTokens: usageTokens.total,
15482
15880
  totalCost: this.costTracker.total,
15483
15881
  costBreakdown: this.costTracker.breakdown(),
15882
+ cache: cacheStats,
15484
15883
  compactionCount: contextManager.getCompactionCount(),
15485
15884
  contextQuality: contextManager.getQuality()
15486
15885
  };
@@ -15497,18 +15896,38 @@ class Agent {
15497
15896
  totalTokens: usageTokens.total,
15498
15897
  totalCost: this.costTracker.total,
15499
15898
  costBreakdown: this.costTracker.breakdown(),
15899
+ cache: cacheStats,
15500
15900
  compactionCount: contextManager.getCompactionCount(),
15501
15901
  contextQuality: contextManager.getQuality(),
15502
15902
  llmDurationMs: state.totalLlmDuration
15503
15903
  };
15504
15904
  }
15905
+ buildCacheStats(state) {
15906
+ const hasTokens = state.cacheCachedTotal > 0 || state.cacheUncachedTotal > 0 || state.cacheWriteTotal > 0;
15907
+ const prefix = state.lastPrefixBreak ?? state.prefixDelta;
15908
+ if (!hasTokens && prefix?.stableRatio === undefined)
15909
+ return;
15910
+ const denom = state.cacheCachedTotal + state.cacheUncachedTotal;
15911
+ return {
15912
+ cachedTokens: state.cacheCachedTotal,
15913
+ uncachedTokens: state.cacheUncachedTotal,
15914
+ cacheWriteTokens: state.cacheWriteTotal,
15915
+ hitRate: denom > 0 ? state.cacheCachedTotal / denom : 0,
15916
+ saved: this.costTracker.saved,
15917
+ prefixStable: prefix?.stableRatio,
15918
+ prefixCause: prefix?.cause,
15919
+ source: state.cacheSource
15920
+ };
15921
+ }
15505
15922
  clearContext() {
15506
15923
  this.deps.contextManager.clear();
15507
15924
  this.systemPromptAdded = false;
15508
15925
  }
15509
15926
  async reconfigure(config) {
15510
15927
  const { TokenCounter: TokenCounter2 } = await Promise.resolve().then(() => (init_token_counter(), exports_token_counter));
15511
- const { provider: newProvider } = buildActiveProvider(config, this.deps.logger);
15928
+ const { provider: newProvider } = buildActiveProvider(config, this.deps.logger, {
15929
+ getSessionId: () => this.deps.sessionManager?.getActiveMeta()?.id
15930
+ });
15512
15931
  this.deps.llmProvider = newProvider;
15513
15932
  this.deps.toolExecutor.updateProvider(newProvider);
15514
15933
  const newTokenCounter = new TokenCounter2(config.model);
@@ -15519,7 +15938,9 @@ class Agent {
15519
15938
  this.costTracker.setModel(config.model);
15520
15939
  }
15521
15940
  setProvider(name, model) {
15522
- const { manager, provider } = buildActiveProvider(this.deps.config, this.deps.logger);
15941
+ const { manager, provider } = buildActiveProvider(this.deps.config, this.deps.logger, {
15942
+ getSessionId: () => this.deps.sessionManager?.getActiveMeta()?.id
15943
+ });
15523
15944
  manager.switch(name, model);
15524
15945
  const providerCfg = manager.toConfig();
15525
15946
  this.deps.config.provider = providerCfg;
@@ -15530,7 +15951,8 @@ class Agent {
15530
15951
  const manager = new ProviderManager(this.deps.config.provider, {
15531
15952
  contextWindow: this.deps.config.contextWindow,
15532
15953
  retry: this.deps.config.retry,
15533
- rateLimits: this.deps.config.security?.rateLimits
15954
+ rateLimits: this.deps.config.security?.rateLimits,
15955
+ getSessionId: () => this.deps.sessionManager?.getActiveMeta()?.id
15534
15956
  });
15535
15957
  const activeName = this.deps.config.provider.active;
15536
15958
  return manager.list().map((e) => ({
@@ -15544,6 +15966,7 @@ class Agent {
15544
15966
  contextWindow: this.deps.config.contextWindow,
15545
15967
  retry: this.deps.config.retry,
15546
15968
  rateLimits: this.deps.config.security?.rateLimits,
15969
+ getSessionId: () => this.deps.sessionManager?.getActiveMeta()?.id,
15547
15970
  logger: this.deps.logger
15548
15971
  });
15549
15972
  manager.setModel(this.deps.config.model);
@@ -15600,6 +16023,7 @@ var init_agent = __esm(() => {
15600
16023
  init_loop_state();
15601
16024
  init_compaction();
15602
16025
  init_token_tracker();
16026
+ init_prefix_monitor();
15603
16027
  init_reasoning_resolver();
15604
16028
  init_context_renderer();
15605
16029
  init_tool_batch();
@@ -16183,8 +16607,8 @@ var init_confidence = __esm(() => {
16183
16607
  });
16184
16608
 
16185
16609
  // src/modules/hallucination/factual.ts
16186
- import { existsSync as existsSync28, readdirSync as readdirSync8 } from "fs";
16187
- import { resolve as resolve14, isAbsolute as isAbsolute4, join as join19 } from "path";
16610
+ import { existsSync as existsSync29, readdirSync as readdirSync8 } from "fs";
16611
+ import { resolve as resolve14, isAbsolute as isAbsolute4, join as join20 } from "path";
16188
16612
 
16189
16613
  class FactualCheck {
16190
16614
  baseDir;
@@ -16227,13 +16651,13 @@ class FactualCheck {
16227
16651
  }
16228
16652
  pathExists(fp) {
16229
16653
  if (isAbsolute4(fp))
16230
- return existsSync28(fp);
16654
+ return existsSync29(fp);
16231
16655
  if (this.knownFiles.has(fp))
16232
16656
  return true;
16233
16657
  for (const cand of this.dotfileVariants(fp)) {
16234
16658
  if (this.knownFiles.has(cand))
16235
16659
  return true;
16236
- if (existsSync28(resolve14(this.baseDir, cand)))
16660
+ if (existsSync29(resolve14(this.baseDir, cand)))
16237
16661
  return true;
16238
16662
  }
16239
16663
  if (!fp.includes("/") && !fp.includes("\\")) {
@@ -16261,7 +16685,7 @@ class FactualCheck {
16261
16685
  }
16262
16686
  bareNameExists(name) {
16263
16687
  for (const cand of this.dotfileVariants(name)) {
16264
- if (existsSync28(resolve14(this.baseDir, cand)))
16688
+ if (existsSync29(resolve14(this.baseDir, cand)))
16265
16689
  return true;
16266
16690
  if (this.indexHas(cand))
16267
16691
  return true;
@@ -16307,7 +16731,7 @@ class FactualCheck {
16307
16731
  for (const entry of entries) {
16308
16732
  if (count >= FactualCheck.MAX_INDEXED_FILES)
16309
16733
  break;
16310
- const full = join19(dir, entry.name);
16734
+ const full = join20(dir, entry.name);
16311
16735
  if (entry.isDirectory()) {
16312
16736
  if (!IGNORED_DIRS2.has(entry.name)) {
16313
16737
  count = this.scanDir(full, index, count);
@@ -16489,10 +16913,10 @@ var init_detector = __esm(() => {
16489
16913
  });
16490
16914
 
16491
16915
  // src/modules/lsp/command.ts
16492
- import { delimiter, join as join20 } from "path";
16493
- import { existsSync as existsSync29 } from "fs";
16494
- import { platform as platform4 } from "os";
16495
- function resolveSpawnCommand(command, platformName = platform4(), pathEnv = process.env.PATH ?? "") {
16916
+ import { delimiter, join as join21 } from "path";
16917
+ import { existsSync as existsSync30 } from "fs";
16918
+ import { platform as platform5 } from "os";
16919
+ function resolveSpawnCommand(command, platformName = platform5(), pathEnv = process.env.PATH ?? "") {
16496
16920
  if (platformName !== "win32")
16497
16921
  return command;
16498
16922
  if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
@@ -16501,8 +16925,8 @@ function resolveSpawnCommand(command, platformName = platform4(), pathEnv = proc
16501
16925
  const dirs = pathEnv.split(delimiter).filter(Boolean);
16502
16926
  for (const dir of dirs) {
16503
16927
  for (const ext of WIN_EXTS) {
16504
- const candidate = join20(dir, `${command}${ext}`);
16505
- if (existsSync29(candidate))
16928
+ const candidate = join21(dir, `${command}${ext}`);
16929
+ if (existsSync30(candidate))
16506
16930
  return `${command}${ext}`;
16507
16931
  }
16508
16932
  }
@@ -16524,7 +16948,7 @@ var init_command = __esm(() => {
16524
16948
  });
16525
16949
 
16526
16950
  // src/modules/updater/checker.ts
16527
- import { platform as platform5 } from "os";
16951
+ import { platform as platform6 } from "os";
16528
16952
  function semverGt(a, b) {
16529
16953
  const pa = a.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
16530
16954
  const pb = b.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
@@ -16595,7 +17019,7 @@ class Updater {
16595
17019
  buildInstallCommand(latest) {
16596
17020
  const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
16597
17021
  const command = resolveSpawnCommand("npm");
16598
- if (platform5() === "win32" && /\.(cmd|bat)$/i.test(command)) {
17022
+ if (platform6() === "win32" && /\.(cmd|bat)$/i.test(command)) {
16599
17023
  return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
16600
17024
  }
16601
17025
  return { command, args: npmArgs };
@@ -17146,7 +17570,7 @@ var init_chunk_query = __esm(() => {
17146
17570
  });
17147
17571
 
17148
17572
  // src/tools/chunk-query.ts
17149
- import { readFileSync as readFileSync15 } from "node:fs";
17573
+ import { readFileSync as readFileSync16 } from "node:fs";
17150
17574
  import { resolve as resolve15 } from "node:path";
17151
17575
  var chunkQueryTool;
17152
17576
  var init_chunk_query2 = __esm(() => {
@@ -17219,7 +17643,7 @@ var init_chunk_query2 = __esm(() => {
17219
17643
  return { success: false, output: `[SCOPE] ${check.reason || "Path not allowed"}` };
17220
17644
  }
17221
17645
  try {
17222
- content = readFileSync15(resolvedInput, "utf8");
17646
+ content = readFileSync16(resolvedInput, "utf8");
17223
17647
  } catch (e) {
17224
17648
  return { success: false, output: `Cannot read ${inputPath}: ${e.message}` };
17225
17649
  }
@@ -17672,7 +18096,7 @@ var init_web_browse = __esm(() => {
17672
18096
 
17673
18097
  // src/tools/download-file.ts
17674
18098
  import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync14 } from "fs";
17675
- import { dirname as dirname11 } from "path";
18099
+ import { dirname as dirname12 } from "path";
17676
18100
  var MAX_DOWNLOAD_BYTES, downloadFileTool;
17677
18101
  var init_download_file = __esm(() => {
17678
18102
  init_i18n();
@@ -17760,7 +18184,7 @@ var init_download_file = __esm(() => {
17760
18184
  output: t("tool.download_too_large", { max: String(maxBytes) })
17761
18185
  };
17762
18186
  }
17763
- mkdirSync14(dirname11(resolved), { recursive: true });
18187
+ mkdirSync14(dirname12(resolved), { recursive: true });
17764
18188
  writeFileSync11(resolved, buffer);
17765
18189
  const contentType = response.headers.get("content-type")?.split(";")[0]?.trim() || "unknown";
17766
18190
  logNetworkRequest(ctx.sessionId, sanitizeUrl(url), true, `Status: ${response.status}`);
@@ -18627,7 +19051,7 @@ ${JSON.stringify(result, null, 2)}`
18627
19051
 
18628
19052
  // src/tools/search-history.ts
18629
19053
  import * as fs from "fs";
18630
- import { join as join21 } from "path";
19054
+ import { join as join22 } from "path";
18631
19055
  import { homedir as homedir6 } from "os";
18632
19056
  function searchFile(filePath, query, maxResults, results) {
18633
19057
  if (!fs.existsSync(filePath))
@@ -18672,7 +19096,7 @@ var init_search_history = __esm(() => {
18672
19096
  const query = String(args.query || "").toLowerCase();
18673
19097
  const maxResults = Number(args.maxResults) || 5;
18674
19098
  const sessionId = args.sessionId ? String(args.sessionId) : null;
18675
- const sessionDir = join21(homedir6(), ".mma", "sessions");
19099
+ const sessionDir = join22(homedir6(), ".mma", "sessions");
18676
19100
  const results = [];
18677
19101
  try {
18678
19102
  if (!fs.existsSync(sessionDir)) {
@@ -18687,7 +19111,7 @@ var init_search_history = __esm(() => {
18687
19111
  continue;
18688
19112
  if (sessionId && entry.name !== sessionId)
18689
19113
  continue;
18690
- const historyFile = join21(sessionDir, entry.name, "history.jsonl");
19114
+ const historyFile = join22(sessionDir, entry.name, "history.jsonl");
18691
19115
  searchFile(historyFile, query, maxResults, results);
18692
19116
  if (results.length >= maxResults)
18693
19117
  break;
@@ -18714,8 +19138,8 @@ var init_search_history = __esm(() => {
18714
19138
  });
18715
19139
 
18716
19140
  // src/modules/memory/search.ts
18717
- import { readFileSync as readFileSync17, existsSync as existsSync31 } from "fs";
18718
- import { join as join22 } from "path";
19141
+ import { readFileSync as readFileSync18, existsSync as existsSync32 } from "fs";
19142
+ import { join as join23 } from "path";
18719
19143
 
18720
19144
  class MemorySearch {
18721
19145
  memoryDir;
@@ -18726,10 +19150,10 @@ class MemorySearch {
18726
19150
  const results = [];
18727
19151
  const lowerQuery = query.toLowerCase();
18728
19152
  for (const name of MEMORY_FILES) {
18729
- const path = join22(this.memoryDir, `${name}.md`);
18730
- if (!existsSync31(path))
19153
+ const path = join23(this.memoryDir, `${name}.md`);
19154
+ if (!existsSync32(path))
18731
19155
  continue;
18732
- const content = readFileSync17(path, "utf-8");
19156
+ const content = readFileSync18(path, "utf-8");
18733
19157
  const lines = content.split(`
18734
19158
  `);
18735
19159
  for (const line of lines) {
@@ -18738,10 +19162,10 @@ class MemorySearch {
18738
19162
  }
18739
19163
  }
18740
19164
  }
18741
- const prefsPath = join22(this.memoryDir, "preferences.json");
18742
- if (existsSync31(prefsPath)) {
19165
+ const prefsPath = join23(this.memoryDir, "preferences.json");
19166
+ if (existsSync32(prefsPath)) {
18743
19167
  try {
18744
- const prefs = JSON.parse(readFileSync17(prefsPath, "utf-8"));
19168
+ const prefs = JSON.parse(readFileSync18(prefsPath, "utf-8"));
18745
19169
  for (const [key, value] of Object.entries(prefs)) {
18746
19170
  const searchStr = `${key}=${value}`;
18747
19171
  if (searchStr.toLowerCase().includes(lowerQuery)) {
@@ -18759,8 +19183,8 @@ var init_search = __esm(() => {
18759
19183
  });
18760
19184
 
18761
19185
  // src/modules/memory/store.ts
18762
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, appendFileSync as appendFileSync5, existsSync as existsSync32, mkdirSync as mkdirSync15 } from "fs";
18763
- import { join as join23 } from "path";
19186
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync12, appendFileSync as appendFileSync5, existsSync as existsSync33, mkdirSync as mkdirSync15 } from "fs";
19187
+ import { join as join24 } from "path";
18764
19188
 
18765
19189
  class MemoryStore {
18766
19190
  memoryDir;
@@ -18768,8 +19192,8 @@ class MemoryStore {
18768
19192
  this.memoryDir = memoryDir;
18769
19193
  this.ensureDir();
18770
19194
  for (const name of MEMORY_FILES2) {
18771
- const path = join23(this.memoryDir, `${name}.md`);
18772
- if (!existsSync32(path)) {
19195
+ const path = join24(this.memoryDir, `${name}.md`);
19196
+ if (!existsSync33(path)) {
18773
19197
  writeFileSync12(path, `# ${name.charAt(0).toUpperCase() + name.slice(1)}
18774
19198
 
18775
19199
  `, "utf-8");
@@ -18777,18 +19201,18 @@ class MemoryStore {
18777
19201
  }
18778
19202
  }
18779
19203
  ensureDir() {
18780
- if (!existsSync32(this.memoryDir)) {
19204
+ if (!existsSync33(this.memoryDir)) {
18781
19205
  mkdirSync15(this.memoryDir, { recursive: true });
18782
19206
  }
18783
19207
  }
18784
19208
  read(name) {
18785
- const path = join23(this.memoryDir, `${name}.md`);
18786
- if (!existsSync32(path))
19209
+ const path = join24(this.memoryDir, `${name}.md`);
19210
+ if (!existsSync33(path))
18787
19211
  return "";
18788
- return readFileSync18(path, "utf-8");
19212
+ return readFileSync19(path, "utf-8");
18789
19213
  }
18790
19214
  append(name, entry) {
18791
- const path = join23(this.memoryDir, `${name}.md`);
19215
+ const path = join24(this.memoryDir, `${name}.md`);
18792
19216
  const timestamp = new Date().toISOString().replace("T", " ").slice(0, 19);
18793
19217
  const formatted = `- **${timestamp}** — ${entry}
18794
19218
  `;
@@ -18799,14 +19223,14 @@ class MemoryStore {
18799
19223
  return searchModule.query(query);
18800
19224
  }
18801
19225
  prefsPath() {
18802
- return join23(this.memoryDir, "preferences.json");
19226
+ return join24(this.memoryDir, "preferences.json");
18803
19227
  }
18804
19228
  getPreferences() {
18805
19229
  const path = this.prefsPath();
18806
- if (!existsSync32(path))
19230
+ if (!existsSync33(path))
18807
19231
  return {};
18808
19232
  try {
18809
- return JSON.parse(readFileSync18(path, "utf-8"));
19233
+ return JSON.parse(readFileSync19(path, "utf-8"));
18810
19234
  } catch {
18811
19235
  return {};
18812
19236
  }
@@ -18839,7 +19263,7 @@ var init_store2 = __esm(() => {
18839
19263
 
18840
19264
  // src/tools/remember.ts
18841
19265
  import { homedir as homedir7 } from "os";
18842
- import { join as join24 } from "path";
19266
+ import { join as join25 } from "path";
18843
19267
  var CATEGORIES, rememberTool;
18844
19268
  var init_remember = __esm(() => {
18845
19269
  init_i18n();
@@ -18878,7 +19302,7 @@ var init_remember = __esm(() => {
18878
19302
  if (!CATEGORIES.includes(category)) {
18879
19303
  return { success: false, output: t("tool.invalid_params") };
18880
19304
  }
18881
- const memoryDir = join24(homedir7(), ".mma", "memory");
19305
+ const memoryDir = join25(homedir7(), ".mma", "memory");
18882
19306
  const store = new MemoryStore(memoryDir);
18883
19307
  try {
18884
19308
  if (category === "preferences") {
@@ -18911,7 +19335,7 @@ var init_remember = __esm(() => {
18911
19335
 
18912
19336
  // src/tools/recall.ts
18913
19337
  import { homedir as homedir8 } from "os";
18914
- import { join as join25 } from "path";
19338
+ import { join as join26 } from "path";
18915
19339
  function formatAll(store) {
18916
19340
  const parts = [];
18917
19341
  const prefs = store.getPreferences();
@@ -18995,7 +19419,7 @@ var init_recall = __esm(() => {
18995
19419
  handler: async (_ctx, args) => {
18996
19420
  const query = args.query ? String(args.query) : "";
18997
19421
  const category = args.category ? String(args.category) : "";
18998
- const memoryDir = join25(homedir8(), ".mma", "memory");
19422
+ const memoryDir = join26(homedir8(), ".mma", "memory");
18999
19423
  const store = new MemoryStore(memoryDir);
19000
19424
  try {
19001
19425
  if (!query && !category) {
@@ -19033,9 +19457,9 @@ var init_recall = __esm(() => {
19033
19457
  });
19034
19458
 
19035
19459
  // src/modules/browser/bridge-path.ts
19036
- import { existsSync as existsSync33 } from "fs";
19460
+ import { existsSync as existsSync34 } from "fs";
19037
19461
  function pickExistingPath(candidates, fallback = candidates[0]) {
19038
- return candidates.find((p) => existsSync33(p)) ?? fallback;
19462
+ return candidates.find((p) => existsSync34(p)) ?? fallback;
19039
19463
  }
19040
19464
  var init_bridge_path = () => {};
19041
19465
 
@@ -19046,13 +19470,13 @@ __export(exports_bridge_client, {
19046
19470
  });
19047
19471
  import { spawn as spawn6 } from "child_process";
19048
19472
  import { createInterface } from "readline";
19049
- import { dirname as dirname12, join as join26 } from "path";
19050
- import { fileURLToPath } from "url";
19473
+ import { dirname as dirname13, join as join27 } from "path";
19474
+ import { fileURLToPath as fileURLToPath2 } from "url";
19051
19475
  function bridgeScriptPath() {
19052
- const dir = dirname12(fileURLToPath(import.meta.url));
19476
+ const dir = dirname13(fileURLToPath2(import.meta.url));
19053
19477
  const candidates = [
19054
- join26(dir, "bridge-server.mjs"),
19055
- join26(dir, "modules", "browser", "bridge-server.mjs")
19478
+ join27(dir, "bridge-server.mjs"),
19479
+ join27(dir, "modules", "browser", "bridge-server.mjs")
19056
19480
  ];
19057
19481
  return pickExistingPath(candidates);
19058
19482
  }
@@ -19606,15 +20030,15 @@ function buildTextExtractionScript() {
19606
20030
 
19607
20031
  // src/modules/browser/cookie-store.ts
19608
20032
  import { readFile, writeFile, mkdir } from "fs/promises";
19609
- import { join as join27 } from "path";
20033
+ import { join as join28 } from "path";
19610
20034
 
19611
20035
  class CookieStore {
19612
20036
  filePath;
19613
20037
  constructor(cookieDir) {
19614
- this.filePath = join27(cookieDir, "cookies.json");
20038
+ this.filePath = join28(cookieDir, "cookies.json");
19615
20039
  }
19616
20040
  async save(cookies) {
19617
- await mkdir(join27(this.filePath, ".."), { recursive: true });
20041
+ await mkdir(join28(this.filePath, ".."), { recursive: true });
19618
20042
  await writeFile(this.filePath, JSON.stringify(cookies, null, 2), "utf-8");
19619
20043
  }
19620
20044
  async load() {
@@ -19972,10 +20396,10 @@ var init_session = __esm(() => {
19972
20396
  });
19973
20397
 
19974
20398
  // src/tools/browser.ts
19975
- import { join as join28 } from "path";
20399
+ import { join as join29 } from "path";
19976
20400
  function getSession(ctx) {
19977
20401
  if (!session) {
19978
- const cookieDir = join28(ctx.baseDir, ".mma", "browser");
20402
+ const cookieDir = join29(ctx.baseDir, ".mma", "browser");
19979
20403
  session = new BrowserSession({
19980
20404
  ...DEFAULT_BROWSER_CONFIG,
19981
20405
  headless: ctx.config.browser?.headless ?? true,
@@ -20101,7 +20525,7 @@ __export(exports_image_utils, {
20101
20525
  detectMime: () => detectMime,
20102
20526
  bufferToDataUrl: () => bufferToDataUrl
20103
20527
  });
20104
- import { readFileSync as readFileSync19 } from "fs";
20528
+ import { readFileSync as readFileSync20 } from "fs";
20105
20529
  import { extname as extname4 } from "path";
20106
20530
  function detectMime(filePath) {
20107
20531
  const ext = extname4(filePath).toLowerCase();
@@ -20120,13 +20544,13 @@ async function readClipboardImage() {
20120
20544
  return readClipboardFallback();
20121
20545
  }
20122
20546
  async function readClipboardFallback() {
20123
- const { platform: platform6 } = await import("os");
20547
+ const { platform: platform7 } = await import("os");
20124
20548
  const { execSync } = await import("child_process");
20125
- const { readFileSync: readFileSync20, unlinkSync: unlinkSync5 } = await import("fs");
20126
- const { join: join29 } = await import("path");
20127
- if (platform6() !== "linux")
20549
+ const { readFileSync: readFileSync21, unlinkSync: unlinkSync5 } = await import("fs");
20550
+ const { join: join30 } = await import("path");
20551
+ if (platform7() !== "linux")
20128
20552
  return null;
20129
- const tmpPath = join29(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
20553
+ const tmpPath = join30(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
20130
20554
  const commands = [
20131
20555
  `wl-paste --type image/png > "${tmpPath}" 2>/dev/null`,
20132
20556
  `xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`
@@ -20134,7 +20558,7 @@ async function readClipboardFallback() {
20134
20558
  for (const cmd of commands) {
20135
20559
  try {
20136
20560
  execSync(cmd, { timeout: 5000 });
20137
- const buf = readFileSync20(tmpPath);
20561
+ const buf = readFileSync21(tmpPath);
20138
20562
  unlinkSync5(tmpPath);
20139
20563
  if (buf.length > 0)
20140
20564
  return buf;
@@ -20146,7 +20570,7 @@ async function readClipboardFallback() {
20146
20570
  return null;
20147
20571
  }
20148
20572
  async function loadFileAsDataUrl(filePath) {
20149
- const buf = readFileSync19(filePath);
20573
+ const buf = readFileSync20(filePath);
20150
20574
  if (typeof Bun !== "undefined" && typeof Bun.Image !== "undefined") {
20151
20575
  try {
20152
20576
  const img = new Bun.Image(buf);
@@ -20206,7 +20630,7 @@ var init_image_utils = __esm(() => {
20206
20630
  });
20207
20631
 
20208
20632
  // src/tools/attach-image.ts
20209
- import { existsSync as existsSync34 } from "fs";
20633
+ import { existsSync as existsSync35 } from "fs";
20210
20634
  import { resolve as resolve16 } from "path";
20211
20635
  var attachImageTool;
20212
20636
  var init_attach_image = __esm(() => {
@@ -20258,7 +20682,7 @@ var init_attach_image = __esm(() => {
20258
20682
  dataUrl = result.dataUrl;
20259
20683
  } else {
20260
20684
  const absPath = resolve16(ctx.baseDir, source);
20261
- if (!existsSync34(absPath)) {
20685
+ if (!existsSync35(absPath)) {
20262
20686
  return {
20263
20687
  success: false,
20264
20688
  output: t("image.not_found", { path: source })
@@ -20567,16 +20991,16 @@ class ModuleRegistry {
20567
20991
  }
20568
20992
 
20569
20993
  // src/modules/plugins/loader.ts
20570
- import { readdirSync as readdirSync10, existsSync as existsSync35, statSync as statSync6 } from "fs";
20571
- import { join as join29, basename as basename3 } from "path";
20994
+ import { readdirSync as readdirSync10, existsSync as existsSync36, statSync as statSync6 } from "fs";
20995
+ import { join as join30, basename as basename3 } from "path";
20572
20996
 
20573
20997
  class PluginLoader {
20574
20998
  loadFromDir(dirPath, pluginManager, logger2, options) {
20575
- if (!existsSync35(dirPath))
20999
+ if (!existsSync36(dirPath))
20576
21000
  return;
20577
21001
  const entries = readdirSync10(dirPath).sort();
20578
21002
  for (const entry of entries) {
20579
- const fullPath = join29(dirPath, entry);
21003
+ const fullPath = join30(dirPath, entry);
20580
21004
  const stat = statSync6(fullPath);
20581
21005
  if (stat.isFile()) {
20582
21006
  if (!entry.endsWith(".ts") && !entry.endsWith(".js"))
@@ -20592,8 +21016,8 @@ class PluginLoader {
20592
21016
  }
20593
21017
  findEntryFile(dir) {
20594
21018
  for (const name of FOLDER_ENTRY_NAMES) {
20595
- const candidate = join29(dir, name);
20596
- if (existsSync35(candidate))
21019
+ const candidate = join30(dir, name);
21020
+ if (existsSync36(candidate))
20597
21021
  return candidate;
20598
21022
  }
20599
21023
  return null;
@@ -20798,9 +21222,9 @@ var init_auto_fixer = __esm(() => {
20798
21222
 
20799
21223
  // src/modules/plugins/builtin/lint-on-write.ts
20800
21224
  import { spawn as spawn7, execSync } from "child_process";
20801
- import { existsSync as existsSync36, readFileSync as readFileSync20, writeFileSync as writeFileSync13 } from "fs";
20802
- import { resolve as resolve17, extname as extname6, join as join30 } from "path";
20803
- import { platform as platform6 } from "os";
21225
+ import { existsSync as existsSync37, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
21226
+ import { resolve as resolve17, extname as extname6, join as join31 } from "path";
21227
+ import { platform as platform7 } from "os";
20804
21228
  function lintCacheKey(baseDir, lintScript) {
20805
21229
  return `${baseDir}::${lintScript}`;
20806
21230
  }
@@ -20821,7 +21245,7 @@ function contentHash2(content) {
20821
21245
  function getWinDecoder() {
20822
21246
  if (_winDecoder !== undefined)
20823
21247
  return _winDecoder;
20824
- if (platform6() !== "win32") {
21248
+ if (platform7() !== "win32") {
20825
21249
  _winDecoder = new TextDecoder("utf-8");
20826
21250
  return _winDecoder;
20827
21251
  }
@@ -20875,7 +21299,7 @@ class LintOnWritePlugin {
20875
21299
  if (!path)
20876
21300
  return;
20877
21301
  const fullPath = resolve17(ctx.baseDir, path);
20878
- if (!existsSync36(fullPath))
21302
+ if (!existsSync37(fullPath))
20879
21303
  return;
20880
21304
  const signal = ctx.signal;
20881
21305
  if (signal?.aborted)
@@ -20899,7 +21323,7 @@ class LintOnWritePlugin {
20899
21323
  if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
20900
21324
  let content = "";
20901
21325
  try {
20902
- content = readFileSync20(filePath, "utf-8");
21326
+ content = readFileSync21(filePath, "utf-8");
20903
21327
  } catch {
20904
21328
  return null;
20905
21329
  }
@@ -20941,11 +21365,11 @@ class LintOnWritePlugin {
20941
21365
  async runProjectLint(ctx, result, signal) {
20942
21366
  let lintScript;
20943
21367
  try {
20944
- const packageJsonPath = join30(ctx.baseDir, "package.json");
20945
- if (!existsSync36(packageJsonPath)) {
21368
+ const packageJsonPath = join31(ctx.baseDir, "package.json");
21369
+ if (!existsSync37(packageJsonPath)) {
20946
21370
  return;
20947
21371
  }
20948
- const packageJson = JSON.parse(readFileSync20(packageJsonPath, "utf-8"));
21372
+ const packageJson = JSON.parse(readFileSync21(packageJsonPath, "utf-8"));
20949
21373
  lintScript = packageJson.scripts?.lint;
20950
21374
  if (!lintScript) {
20951
21375
  return;
@@ -20978,8 +21402,12 @@ ${stdout}`;
20978
21402
  }
20979
21403
  async runProjectTypeCheck(filePath, baseDir, result, signal) {
20980
21404
  const projectRoot = findProjectRoot(filePath, baseDir, ["tsconfig.json", "package.json"]);
20981
- const tsconfigPath = join30(projectRoot, "tsconfig.json");
20982
- if (!existsSync36(tsconfigPath)) {
21405
+ const tsconfigPath = join31(projectRoot, "tsconfig.json");
21406
+ if (!existsSync37(tsconfigPath)) {
21407
+ return;
21408
+ }
21409
+ const tsc = resolveTscCommand(projectRoot);
21410
+ if (!tsc) {
20983
21411
  return;
20984
21412
  }
20985
21413
  const now = Date.now();
@@ -20993,14 +21421,14 @@ ${stdout}`;
20993
21421
  return;
20994
21422
  }
20995
21423
  this._checkTimestamp = now;
20996
- this._checkPromise = this.runTscCheck(projectRoot, signal);
21424
+ this._checkPromise = this.runTscCheck(tsc, projectRoot, signal);
20997
21425
  const error = await this._checkPromise;
20998
21426
  if (error) {
20999
- const { stdout, stderr } = await runAsync(`npx tsc --noEmit --skipLibCheck 2>&1`, projectRoot, 30000, signal).catch(() => ({ stdout: "", stderr: error }));
21427
+ const { stdout, stderr } = await runAsync(`${tsc} --noEmit --skipLibCheck 2>&1`, projectRoot, 30000, signal).catch(() => ({ stdout: "", stderr: error }));
21000
21428
  const output = stderr || stdout;
21001
21429
  const errors = parseTscOutput(output);
21002
21430
  if (errors.length > 0) {
21003
- const fixResult = autoFixErrors(filePath, readFileSync20(filePath, "utf-8"), errors);
21431
+ const fixResult = autoFixErrors(filePath, readFileSync21(filePath, "utf-8"), errors);
21004
21432
  if (fixResult.fixed) {
21005
21433
  writeFileSync13(filePath, fixResult.newContent, "utf-8");
21006
21434
  result.output += `
@@ -21025,9 +21453,9 @@ ${stdout}`;
21025
21453
  }
21026
21454
  }
21027
21455
  }
21028
- async runTscCheck(baseDir, signal) {
21456
+ async runTscCheck(tsc, baseDir, signal) {
21029
21457
  try {
21030
- const { stdout, stderr } = await runAsync(`npx tsc --noEmit --skipLibCheck`, baseDir, 30000, signal);
21458
+ const { stdout, stderr } = await runAsync(`${tsc} --noEmit --skipLibCheck`, baseDir, 30000, signal);
21031
21459
  return null;
21032
21460
  } catch (err) {
21033
21461
  if (err.status === 127 || err.message.includes("not found") || err.message.includes("ENOENT")) {
@@ -21265,11 +21693,11 @@ class PlanTracker {
21265
21693
  var init_tracker = () => {};
21266
21694
 
21267
21695
  // src/modules/execution/plan-store.ts
21268
- import { readFileSync as readFileSync21, writeFileSync as writeFileSync14, renameSync as renameSync3, mkdirSync as mkdirSync16, existsSync as existsSync37, readdirSync as readdirSync11, rmSync } from "fs";
21269
- import { join as join31 } from "path";
21696
+ import { readFileSync as readFileSync22, writeFileSync as writeFileSync14, renameSync as renameSync3, mkdirSync as mkdirSync16, existsSync as existsSync38, readdirSync as readdirSync11, rmSync } from "fs";
21697
+ import { join as join32 } from "path";
21270
21698
  function readPlanFile(path, fallbackBaseDir) {
21271
21699
  try {
21272
- const raw = readFileSync21(path, "utf-8");
21700
+ const raw = readFileSync22(path, "utf-8");
21273
21701
  if (!raw.trim())
21274
21702
  return null;
21275
21703
  const parsed = JSON.parse(raw);
@@ -21293,10 +21721,10 @@ function writePlanFile(path, plan) {
21293
21721
  renameSync3(tmpPath, path);
21294
21722
  }
21295
21723
  function listDir(dir, baseDir) {
21296
- if (!existsSync37(dir))
21724
+ if (!existsSync38(dir))
21297
21725
  return [];
21298
21726
  const files = readdirSync11(dir).filter((f) => f.endsWith(".json"));
21299
- return files.map((f) => readPlanFile(join31(dir, f), baseDir)).filter((p) => p !== null);
21727
+ return files.map((f) => readPlanFile(join32(dir, f), baseDir)).filter((p) => p !== null);
21300
21728
  }
21301
21729
  function toMeta(plan, status) {
21302
21730
  return {
@@ -21317,33 +21745,33 @@ class PlanStore {
21317
21745
  archiveDir;
21318
21746
  legacyPath;
21319
21747
  constructor(baseDir) {
21320
- const mmaDir = join31(baseDir, ".mma");
21321
- if (!existsSync37(mmaDir))
21748
+ const mmaDir = join32(baseDir, ".mma");
21749
+ if (!existsSync38(mmaDir))
21322
21750
  mkdirSync16(mmaDir, { recursive: true });
21323
21751
  this.baseDir = baseDir;
21324
- this.plansDir = join31(mmaDir, "plans");
21325
- this.draftsDir = join31(this.plansDir, "drafts");
21326
- this.archiveDir = join31(this.plansDir, "archive");
21327
- this.legacyPath = join31(mmaDir, LEGACY_FILE);
21752
+ this.plansDir = join32(mmaDir, "plans");
21753
+ this.draftsDir = join32(this.plansDir, "drafts");
21754
+ this.archiveDir = join32(this.plansDir, "archive");
21755
+ this.legacyPath = join32(mmaDir, LEGACY_FILE);
21328
21756
  for (const dir of [this.plansDir, this.draftsDir, this.archiveDir]) {
21329
- if (!existsSync37(dir))
21757
+ if (!existsSync38(dir))
21330
21758
  mkdirSync16(dir, { recursive: true });
21331
21759
  }
21332
21760
  }
21333
21761
  activePath() {
21334
- return join31(this.plansDir, "active.json");
21762
+ return join32(this.plansDir, "active.json");
21335
21763
  }
21336
21764
  saveActive(plan) {
21337
21765
  writePlanFile(this.activePath(), plan);
21338
21766
  }
21339
21767
  loadActive() {
21340
21768
  const activePath = this.activePath();
21341
- if (existsSync37(activePath)) {
21769
+ if (existsSync38(activePath)) {
21342
21770
  const plan = readPlanFile(activePath, this.baseDir);
21343
21771
  if (plan)
21344
21772
  return plan;
21345
21773
  }
21346
- if (existsSync37(this.legacyPath)) {
21774
+ if (existsSync38(this.legacyPath)) {
21347
21775
  const legacy = readPlanFile(this.legacyPath, this.baseDir);
21348
21776
  if (legacy) {
21349
21777
  this.saveActive(legacy);
@@ -21362,26 +21790,26 @@ class PlanStore {
21362
21790
  }
21363
21791
  clearActive() {
21364
21792
  const p = this.activePath();
21365
- if (existsSync37(p))
21793
+ if (existsSync38(p))
21366
21794
  rmSync(p, { force: true });
21367
21795
  }
21368
21796
  saveDraft(plan) {
21369
- writePlanFile(join31(this.draftsDir, `${plan.id}.json`), plan);
21797
+ writePlanFile(join32(this.draftsDir, `${plan.id}.json`), plan);
21370
21798
  }
21371
21799
  loadDraft(id) {
21372
- const p = join31(this.draftsDir, `${id}.json`);
21373
- return existsSync37(p) ? readPlanFile(p, this.baseDir) : null;
21800
+ const p = join32(this.draftsDir, `${id}.json`);
21801
+ return existsSync38(p) ? readPlanFile(p, this.baseDir) : null;
21374
21802
  }
21375
21803
  removeDraft(id) {
21376
- const p = join31(this.draftsDir, `${id}.json`);
21377
- if (existsSync37(p))
21804
+ const p = join32(this.draftsDir, `${id}.json`);
21805
+ if (existsSync38(p))
21378
21806
  rmSync(p, { force: true });
21379
21807
  }
21380
21808
  listDrafts() {
21381
21809
  return listDir(this.draftsDir, this.baseDir);
21382
21810
  }
21383
21811
  archivePlan(plan) {
21384
- writePlanFile(join31(this.archiveDir, `${plan.id}.json`), plan);
21812
+ writePlanFile(join32(this.archiveDir, `${plan.id}.json`), plan);
21385
21813
  this.removeDraft(plan.id);
21386
21814
  const active = this.loadActive();
21387
21815
  if (active && active.id === plan.id) {
@@ -21392,8 +21820,8 @@ class PlanStore {
21392
21820
  return listDir(this.archiveDir, this.baseDir);
21393
21821
  }
21394
21822
  removeArchived(id) {
21395
- const p = join31(this.archiveDir, `${id}.json`);
21396
- if (existsSync37(p))
21823
+ const p = join32(this.archiveDir, `${id}.json`);
21824
+ if (existsSync38(p))
21397
21825
  rmSync(p, { force: true });
21398
21826
  }
21399
21827
  listAll() {
@@ -21425,13 +21853,13 @@ class PlanStore {
21425
21853
  this.clearActive();
21426
21854
  return "active";
21427
21855
  }
21428
- const draftPath = join31(this.draftsDir, `${id}.json`);
21429
- if (existsSync37(draftPath)) {
21856
+ const draftPath = join32(this.draftsDir, `${id}.json`);
21857
+ if (existsSync38(draftPath)) {
21430
21858
  rmSync(draftPath, { force: true });
21431
21859
  return "draft";
21432
21860
  }
21433
- const archivedPath = join31(this.archiveDir, `${id}.json`);
21434
- if (existsSync37(archivedPath)) {
21861
+ const archivedPath = join32(this.archiveDir, `${id}.json`);
21862
+ if (existsSync38(archivedPath)) {
21435
21863
  rmSync(archivedPath, { force: true });
21436
21864
  return "archived";
21437
21865
  }
@@ -21513,7 +21941,7 @@ function switchStepToDelete(plan, step, save) {
21513
21941
  }
21514
21942
 
21515
21943
  // src/modules/execution/execution-plugin.ts
21516
- import { platform as platform7 } from "os";
21944
+ import { platform as platform8 } from "os";
21517
21945
  function normalizeBrokenPath(p) {
21518
21946
  return toForwardSlash(p).replace(/^\.\//, "");
21519
21947
  }
@@ -21746,7 +22174,7 @@ Last compile error: ${first[1]}`;
21746
22174
  if (call.name === "bash") {
21747
22175
  deps.stuckDetector.recordBashAttempt(false);
21748
22176
  }
21749
- if (call.name === "bash" && platform7() === "win32") {
22177
+ if (call.name === "bash" && platform8() === "win32") {
21750
22178
  const cmd = String(call.arguments?.command ?? "");
21751
22179
  const forbidden = forbiddenWindowsCommand(cmd);
21752
22180
  if (forbidden) {
@@ -22551,7 +22979,7 @@ var init_plan_tool = __esm(() => {
22551
22979
  });
22552
22980
 
22553
22981
  // src/modules/execution/module.ts
22554
- import { existsSync as existsSync38, readFileSync as readFileSync22 } from "fs";
22982
+ import { existsSync as existsSync39, readFileSync as readFileSync23 } from "fs";
22555
22983
  import { resolve as resolve18 } from "path";
22556
22984
 
22557
22985
  class ExecutionModule {
@@ -22910,7 +23338,7 @@ class ExecutionModule {
22910
23338
  "poetry.lock",
22911
23339
  "requirements.txt"
22912
23340
  ];
22913
- const hasLockFile = lockFiles.some((f) => existsSync38(resolve18(this.baseDir, f)));
23341
+ const hasLockFile = lockFiles.some((f) => existsSync39(resolve18(this.baseDir, f)));
22914
23342
  if (!hasLockFile) {
22915
23343
  if (contextManager) {
22916
23344
  const hints = this.state.depsGateHints.get(step.id) || 0;
@@ -22942,7 +23370,7 @@ class ExecutionModule {
22942
23370
  if (!r)
22943
23371
  continue;
22944
23372
  try {
22945
- const content = readFileSync22(r, "utf-8");
23373
+ const content = readFileSync23(r, "utf-8");
22946
23374
  if (content.trim().length < 10) {
22947
23375
  emptyFiles.push(r);
22948
23376
  }
@@ -23050,8 +23478,8 @@ var init_module = __esm(() => {
23050
23478
  });
23051
23479
 
23052
23480
  // src/modules/security/session-encryption.ts
23053
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync15, existsSync as existsSync39, readdirSync as readdirSync12, unlinkSync as unlinkSync5 } from "fs";
23054
- import { join as join32 } from "path";
23481
+ import { readFileSync as readFileSync24, writeFileSync as writeFileSync15, existsSync as existsSync40, readdirSync as readdirSync12, unlinkSync as unlinkSync5 } from "fs";
23482
+ import { join as join33 } from "path";
23055
23483
  import { homedir as homedir9 } from "os";
23056
23484
 
23057
23485
  class SessionFileEncryptor {
@@ -23060,7 +23488,7 @@ class SessionFileEncryptor {
23060
23488
  constructor(config) {
23061
23489
  this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
23062
23490
  this.encryptor = new ConfigEncryptor({
23063
- keyPath: config?.keyPath || join32(homedir9(), ".mma", ".session-encryption-key")
23491
+ keyPath: config?.keyPath || join33(homedir9(), ".mma", ".session-encryption-key")
23064
23492
  });
23065
23493
  }
23066
23494
  isEnabled() {
@@ -23112,7 +23540,7 @@ class SessionFileEncryptor {
23112
23540
  });
23113
23541
  }
23114
23542
  readSessionFile(filePath) {
23115
- const content = readFileSync23(filePath, "utf8");
23543
+ const content = readFileSync24(filePath, "utf8");
23116
23544
  return this.decryptFileContent(content);
23117
23545
  }
23118
23546
  writeSessionFile(filePath, content) {
@@ -23120,7 +23548,7 @@ class SessionFileEncryptor {
23120
23548
  writeFileSync15(filePath, encrypted, "utf8");
23121
23549
  }
23122
23550
  readSessionJSON(filePath) {
23123
- const content = readFileSync23(filePath, "utf8");
23551
+ const content = readFileSync24(filePath, "utf8");
23124
23552
  return this.decryptJSON(content);
23125
23553
  }
23126
23554
  writeSessionJSON(filePath, obj) {
@@ -23128,7 +23556,7 @@ class SessionFileEncryptor {
23128
23556
  writeFileSync15(filePath, content, "utf8");
23129
23557
  }
23130
23558
  readSessionJSONL(filePath) {
23131
- const content = readFileSync23(filePath, "utf8");
23559
+ const content = readFileSync24(filePath, "utf8");
23132
23560
  const lines = content.split(`
23133
23561
  `).filter((line) => line.trim());
23134
23562
  const decryptedLines = this.decryptJSONL(lines);
@@ -23153,10 +23581,10 @@ class SessionFileEncryptor {
23153
23581
  return;
23154
23582
  const files = readdirSync12(sessionDir);
23155
23583
  for (const file of files) {
23156
- const filePath = join32(sessionDir, file);
23157
- if (existsSync39(filePath) && !file.endsWith(".enc")) {
23584
+ const filePath = join33(sessionDir, file);
23585
+ if (existsSync40(filePath) && !file.endsWith(".enc")) {
23158
23586
  try {
23159
- const content = readFileSync23(filePath, "utf8");
23587
+ const content = readFileSync24(filePath, "utf8");
23160
23588
  const encrypted = this.encryptFileContent(content);
23161
23589
  writeFileSync15(filePath + ".enc", encrypted, "utf8");
23162
23590
  unlinkSync5(filePath);
@@ -23170,10 +23598,10 @@ class SessionFileEncryptor {
23170
23598
  const files = readdirSync12(sessionDir);
23171
23599
  for (const file of files) {
23172
23600
  if (file.endsWith(".enc")) {
23173
- const encFilePath = join32(sessionDir, file);
23601
+ const encFilePath = join33(sessionDir, file);
23174
23602
  const decFilePath = encFilePath.slice(0, -4);
23175
23603
  try {
23176
- const content = readFileSync23(encFilePath, "utf8");
23604
+ const content = readFileSync24(encFilePath, "utf8");
23177
23605
  const decrypted = this.decryptFileContent(content);
23178
23606
  writeFileSync15(decFilePath, decrypted, "utf8");
23179
23607
  unlinkSync5(encFilePath);
@@ -23195,15 +23623,15 @@ var init_session_encryption = __esm(() => {
23195
23623
 
23196
23624
  // src/modules/session/store.ts
23197
23625
  import {
23198
- existsSync as existsSync40,
23626
+ existsSync as existsSync41,
23199
23627
  mkdirSync as mkdirSync17,
23200
23628
  readdirSync as readdirSync13,
23201
- readFileSync as readFileSync24,
23629
+ readFileSync as readFileSync25,
23202
23630
  rmSync as rmSync2,
23203
23631
  writeFileSync as writeFileSync16,
23204
23632
  appendFileSync as appendFileSync6
23205
23633
  } from "fs";
23206
- import { join as join33 } from "path";
23634
+ import { join as join34 } from "path";
23207
23635
  import { gzipSync } from "zlib";
23208
23636
 
23209
23637
  class SessionStore {
@@ -23217,7 +23645,7 @@ class SessionStore {
23217
23645
  }
23218
23646
  }
23219
23647
  getSessionDir(id) {
23220
- return join33(this.baseDir, id);
23648
+ return join34(this.baseDir, id);
23221
23649
  }
23222
23650
  updateEncryption(config) {
23223
23651
  if (config?.enabled) {
@@ -23233,19 +23661,19 @@ class SessionStore {
23233
23661
  mkdirSync17(this.baseDir, { recursive: true, mode: 448 });
23234
23662
  }
23235
23663
  sessionDir(id) {
23236
- return join33(this.baseDir, id);
23664
+ return join34(this.baseDir, id);
23237
23665
  }
23238
23666
  metaPath(id) {
23239
- return join33(this.sessionDir(id), "meta.json");
23667
+ return join34(this.sessionDir(id), "meta.json");
23240
23668
  }
23241
23669
  historyPath(id) {
23242
- return join33(this.sessionDir(id), "history.jsonl");
23670
+ return join34(this.sessionDir(id), "history.jsonl");
23243
23671
  }
23244
23672
  sessionLogPath(id) {
23245
- return join33(this.sessionDir(id), "session.jsonl");
23673
+ return join34(this.sessionDir(id), "session.jsonl");
23246
23674
  }
23247
23675
  sessionExists(id) {
23248
- return existsSync40(this.metaPath(id));
23676
+ return existsSync41(this.metaPath(id));
23249
23677
  }
23250
23678
  saveMeta(id, meta) {
23251
23679
  this._metaCache.set(id, meta);
@@ -23263,10 +23691,10 @@ class SessionStore {
23263
23691
  if (cached)
23264
23692
  return cached;
23265
23693
  const path = this.metaPath(id);
23266
- if (!existsSync40(path))
23694
+ if (!existsSync41(path))
23267
23695
  return null;
23268
23696
  try {
23269
- const raw = readFileSync24(path, "utf-8");
23697
+ const raw = readFileSync25(path, "utf-8");
23270
23698
  const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
23271
23699
  const meta = JSON.parse(content);
23272
23700
  this._metaCache.set(id, meta);
@@ -23277,10 +23705,10 @@ class SessionStore {
23277
23705
  }
23278
23706
  readMetaFromDisk(id) {
23279
23707
  const path = this.metaPath(id);
23280
- if (!existsSync40(path))
23708
+ if (!existsSync41(path))
23281
23709
  return null;
23282
23710
  try {
23283
- const raw = readFileSync24(path, "utf-8");
23711
+ const raw = readFileSync25(path, "utf-8");
23284
23712
  const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
23285
23713
  return JSON.parse(content);
23286
23714
  } catch {
@@ -23307,10 +23735,10 @@ class SessionStore {
23307
23735
  }
23308
23736
  loadHistory(id) {
23309
23737
  const path = this.historyPath(id);
23310
- if (!existsSync40(path))
23738
+ if (!existsSync41(path))
23311
23739
  return [];
23312
23740
  try {
23313
- const raw = readFileSync24(path, "utf-8");
23741
+ const raw = readFileSync25(path, "utf-8");
23314
23742
  const lines = raw.split(`
23315
23743
  `).filter(Boolean);
23316
23744
  const parseLine = (line) => {
@@ -23348,10 +23776,10 @@ class SessionStore {
23348
23776
  }
23349
23777
  loadSessionLog(id) {
23350
23778
  const path = this.sessionLogPath(id);
23351
- if (!existsSync40(path))
23779
+ if (!existsSync41(path))
23352
23780
  return [];
23353
23781
  try {
23354
- const raw = readFileSync24(path, "utf-8");
23782
+ const raw = readFileSync25(path, "utf-8");
23355
23783
  const lines = raw.split(`
23356
23784
  `).filter(Boolean);
23357
23785
  const parseLine = (line) => {
@@ -23376,7 +23804,7 @@ class SessionStore {
23376
23804
  }
23377
23805
  }
23378
23806
  listSessions() {
23379
- if (!existsSync40(this.baseDir))
23807
+ if (!existsSync41(this.baseDir))
23380
23808
  return [];
23381
23809
  const entries = readdirSync13(this.baseDir, { withFileTypes: true });
23382
23810
  const sessions = [];
@@ -23393,7 +23821,7 @@ class SessionStore {
23393
23821
  deleteSession(id) {
23394
23822
  this._metaCache.delete(id);
23395
23823
  const dir = this.sessionDir(id);
23396
- if (existsSync40(dir)) {
23824
+ if (existsSync41(dir)) {
23397
23825
  rmSync2(dir, { recursive: true, force: true });
23398
23826
  }
23399
23827
  }
@@ -23405,10 +23833,10 @@ class SessionStore {
23405
23833
  const updatedAt = new Date(session2.updatedAt);
23406
23834
  if (updatedAt < thirtyDaysAgo) {
23407
23835
  const historyPath = this.historyPath(session2.id);
23408
- if (existsSync40(historyPath)) {
23409
- const content = readFileSync24(historyPath, "utf-8");
23836
+ if (existsSync41(historyPath)) {
23837
+ const content = readFileSync25(historyPath, "utf-8");
23410
23838
  const compressed = gzipSync(content);
23411
- const gzPath = join33(this.baseDir, `${session2.id}.jsonl.gz`);
23839
+ const gzPath = join34(this.baseDir, `${session2.id}.jsonl.gz`);
23412
23840
  writeFileSync16(gzPath, compressed);
23413
23841
  rmSync2(historyPath);
23414
23842
  const meta = this.loadMeta(session2.id);
@@ -23638,9 +24066,9 @@ class ProfileCompressor {
23638
24066
  }
23639
24067
 
23640
24068
  // src/modules/user-profile/profile.ts
23641
- import { readFileSync as readFileSync25, writeFileSync as writeFileSync17, existsSync as existsSync41, mkdirSync as mkdirSync18 } from "fs";
23642
- import { join as join34 } from "path";
23643
- import { homedir as homedir10, hostname, platform as platform8, type } from "os";
24069
+ import { readFileSync as readFileSync26, writeFileSync as writeFileSync17, existsSync as existsSync42, mkdirSync as mkdirSync18 } from "fs";
24070
+ import { join as join35 } from "path";
24071
+ import { homedir as homedir10, hostname, platform as platform9, type } from "os";
23644
24072
  import { env } from "process";
23645
24073
 
23646
24074
  class UserProfile {
@@ -23652,7 +24080,7 @@ class UserProfile {
23652
24080
  }
23653
24081
  collect() {
23654
24082
  this.info = {
23655
- platform: platform8(),
24083
+ platform: platform9(),
23656
24084
  os: `${type()} ${hostname()}`,
23657
24085
  hostname: hostname(),
23658
24086
  shell: env.SHELL || env.ComSpec || "unknown",
@@ -23663,17 +24091,17 @@ class UserProfile {
23663
24091
  return this.info;
23664
24092
  }
23665
24093
  save() {
23666
- if (!existsSync41(this.profileDir)) {
24094
+ if (!existsSync42(this.profileDir)) {
23667
24095
  mkdirSync18(this.profileDir, { recursive: true });
23668
24096
  }
23669
- writeFileSync17(join34(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
24097
+ writeFileSync17(join35(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
23670
24098
  }
23671
24099
  load() {
23672
- const path = join34(this.profileDir, "profile.json");
23673
- if (!existsSync41(path))
24100
+ const path = join35(this.profileDir, "profile.json");
24101
+ if (!existsSync42(path))
23674
24102
  return null;
23675
24103
  try {
23676
- const data = JSON.parse(readFileSync25(path, "utf-8"));
24104
+ const data = JSON.parse(readFileSync26(path, "utf-8"));
23677
24105
  this.info = {
23678
24106
  platform: data.platform,
23679
24107
  os: data.os,
@@ -23708,12 +24136,12 @@ class UserProfile {
23708
24136
  var init_profile = () => {};
23709
24137
 
23710
24138
  // src/modules/skills/loader.ts
23711
- import { readdirSync as readdirSync14, readFileSync as readFileSync26, existsSync as existsSync42, statSync as statSync7 } from "fs";
23712
- import { join as join35 } from "path";
24139
+ import { readdirSync as readdirSync14, readFileSync as readFileSync27, existsSync as existsSync43, statSync as statSync7 } from "fs";
24140
+ import { join as join36 } from "path";
23713
24141
 
23714
24142
  class SkillsLoader {
23715
24143
  loadFromDir(dirPath) {
23716
- if (!existsSync42(dirPath))
24144
+ if (!existsSync43(dirPath))
23717
24145
  return [];
23718
24146
  const skills = [];
23719
24147
  this.scanDir(dirPath, skills);
@@ -23722,7 +24150,7 @@ class SkillsLoader {
23722
24150
  scanDir(dirPath, skills) {
23723
24151
  const entries = readdirSync14(dirPath);
23724
24152
  for (const entry of entries) {
23725
- const fullPath = join35(dirPath, entry);
24153
+ const fullPath = join36(dirPath, entry);
23726
24154
  let stat;
23727
24155
  try {
23728
24156
  stat = statSync7(fullPath);
@@ -23735,7 +24163,7 @@ class SkillsLoader {
23735
24163
  }
23736
24164
  if (!entry.endsWith(".md") && !entry.endsWith(".skill.md"))
23737
24165
  continue;
23738
- const content = readFileSync26(fullPath, "utf-8");
24166
+ const content = readFileSync27(fullPath, "utf-8");
23739
24167
  const parsed = this.parseSkillFile(content, fullPath);
23740
24168
  if (parsed)
23741
24169
  skills.push(parsed);
@@ -23974,7 +24402,7 @@ var init_browser2 = __esm(() => {
23974
24402
  // src/modules/lsp/client.ts
23975
24403
  import { spawn as spawn8, execSync as execSync2 } from "child_process";
23976
24404
  import { resolve as resolve19 } from "path";
23977
- import { platform as platform9 } from "os";
24405
+ import { platform as platform10 } from "os";
23978
24406
 
23979
24407
  class FileOnlyLogger {
23980
24408
  logger;
@@ -24094,7 +24522,7 @@ class LspClient {
24094
24522
  if (config.command === "npx" && effectiveArgs.length > 0) {
24095
24523
  const binaryName = this.extractBinaryFromNpxArgs(effectiveArgs);
24096
24524
  if (binaryName) {
24097
- const whichCmd = platform9() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
24525
+ const whichCmd = platform10() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
24098
24526
  try {
24099
24527
  execSync2(whichCmd, { stdio: "pipe", timeout: 3000 });
24100
24528
  effectiveCommand = binaryName;
@@ -24107,7 +24535,7 @@ class LspClient {
24107
24535
  }
24108
24536
  return new Promise((resolve20, reject) => {
24109
24537
  const args = effectiveArgs;
24110
- const isWin = platform9() === "win32";
24538
+ const isWin = platform10() === "win32";
24111
24539
  let spawnCommand = resolveSpawnCommand(effectiveCommand);
24112
24540
  let spawnArgs = args;
24113
24541
  const spawnOpts = {
@@ -24382,11 +24810,11 @@ var init_check_tool = __esm(() => {
24382
24810
  });
24383
24811
 
24384
24812
  // src/modules/lsp/module.ts
24385
- import { existsSync as existsSync43 } from "fs";
24813
+ import { existsSync as existsSync44 } from "fs";
24386
24814
  import { relative as relative5, resolve as resolve21 } from "path";
24387
- import { join as join36 } from "path";
24815
+ import { join as join37 } from "path";
24388
24816
  function hasTypeEnvironment(projectRoot) {
24389
- return existsSync43(join36(projectRoot, "tsconfig.json")) || existsSync43(join36(projectRoot, "jsconfig.json")) || existsSync43(join36(projectRoot, "node_modules"));
24817
+ return existsSync44(join37(projectRoot, "tsconfig.json")) || existsSync44(join37(projectRoot, "jsconfig.json")) || existsSync44(join37(projectRoot, "node_modules"));
24390
24818
  }
24391
24819
 
24392
24820
  class LspModule {
@@ -24441,7 +24869,7 @@ class LspModule {
24441
24869
  if (!filePath)
24442
24870
  return;
24443
24871
  const fullPath = resolve21(_ctx.baseDir, filePath);
24444
- if (!existsSync43(fullPath))
24872
+ if (!existsSync44(fullPath))
24445
24873
  return;
24446
24874
  const serverConfig = getServerForFile(fullPath, self.config);
24447
24875
  if (!serverConfig)
@@ -24533,7 +24961,7 @@ ${items}`;
24533
24961
  })
24534
24962
  };
24535
24963
  }
24536
- if (!existsSync43(resolved)) {
24964
+ if (!existsSync44(resolved)) {
24537
24965
  return { success: false, output: t("lsp.check_notfound", { path }) };
24538
24966
  }
24539
24967
  const files = await collectCheckFiles(resolved, this.config);
@@ -24650,8 +25078,8 @@ var init_lsp = __esm(() => {
24650
25078
  });
24651
25079
 
24652
25080
  // src/modules/lsp/startup-check.ts
24653
- import { existsSync as existsSync44 } from "fs";
24654
- import { join as join37 } from "path";
25081
+ import { existsSync as existsSync45 } from "fs";
25082
+ import { join as join38 } from "path";
24655
25083
  import { spawn as spawn9 } from "child_process";
24656
25084
  async function runStartupHealthCheck(config, baseDir, deps = {}) {
24657
25085
  if (!config.enabled)
@@ -24678,7 +25106,7 @@ ${result.lines.join(`
24678
25106
  }
24679
25107
  async function runCheck(config, baseDir, deps) {
24680
25108
  const projectRoot = findProjectRoot(baseDir, baseDir, ["tsconfig.json", "package.json"]);
24681
- if (existsSync44(join37(projectRoot, "tsconfig.json"))) {
25109
+ if (existsSync45(join38(projectRoot, "tsconfig.json"))) {
24682
25110
  const runTsc = deps.runTsc ?? runTscDefault;
24683
25111
  const errors = await runTsc(projectRoot, STARTUP_CHECK_TIMEOUT_MS);
24684
25112
  if (errors.length === 0)
@@ -24713,8 +25141,11 @@ async function runCheck(config, baseDir, deps) {
24713
25141
  return { lines: lines.slice(0, STARTUP_CHECK_ERROR_CAP) };
24714
25142
  }
24715
25143
  async function runTscDefault(projectRoot, timeoutMs) {
25144
+ const tsc = resolveTscCommand(projectRoot);
25145
+ if (!tsc)
25146
+ return [];
24716
25147
  return new Promise((resolve22) => {
24717
- const child = spawn9("npx", ["tsc", "--noEmit", "--skipLibCheck"], {
25148
+ const child = spawn9(`${tsc} --noEmit --skipLibCheck`, {
24718
25149
  cwd: projectRoot,
24719
25150
  shell: true,
24720
25151
  windowsHide: true,
@@ -24951,8 +25382,8 @@ var init_symbols = __esm(() => {
24951
25382
  });
24952
25383
 
24953
25384
  // src/modules/indexer/walker.ts
24954
- import { readdirSync as readdirSync15, readFileSync as readFileSync27, statSync as statSync8, lstatSync, existsSync as existsSync45, watch } from "fs";
24955
- import { join as join38, relative as relative6, extname as extname7 } from "path";
25385
+ import { readdirSync as readdirSync15, readFileSync as readFileSync28, statSync as statSync8, lstatSync, existsSync as existsSync46, watch } from "fs";
25386
+ import { join as join39, relative as relative6, extname as extname7 } from "path";
24956
25387
  function isIgnoredDirName(name) {
24957
25388
  return IGNORE_DIRS.has(name.toLowerCase());
24958
25389
  }
@@ -24985,7 +25416,7 @@ class Indexer {
24985
25416
  let totalSize = 0;
24986
25417
  let count = 0;
24987
25418
  const walkDir2 = (dir) => {
24988
- if (!existsSync45(dir))
25419
+ if (!existsSync46(dir))
24989
25420
  return;
24990
25421
  let entries;
24991
25422
  try {
@@ -24996,7 +25427,7 @@ class Indexer {
24996
25427
  for (const entry of entries) {
24997
25428
  if (count >= this.MAX_FILES)
24998
25429
  return;
24999
- const fullPath = join38(dir, entry);
25430
+ const fullPath = join39(dir, entry);
25000
25431
  const relPath = relative6(this.baseDir, fullPath);
25001
25432
  try {
25002
25433
  const lst = lstatSync(fullPath, { throwIfNoEntry: false });
@@ -25011,7 +25442,7 @@ class Indexer {
25011
25442
  const ext = extname7(entry).toLowerCase();
25012
25443
  const language = languageIdForExt(ext);
25013
25444
  if (language) {
25014
- const content = readFileSync27(fullPath, "utf-8");
25445
+ const content = readFileSync28(fullPath, "utf-8");
25015
25446
  const exports = extractSymbols(content, language);
25016
25447
  files.push({ path: relPath, language, exports, size: stat2.size });
25017
25448
  totalSize += stat2.size;
@@ -25081,22 +25512,22 @@ var init_walker = __esm(() => {
25081
25512
  });
25082
25513
 
25083
25514
  // src/modules/indexer/cache.ts
25084
- import { readFileSync as readFileSync28, writeFileSync as writeFileSync18, existsSync as existsSync46, mkdirSync as mkdirSync19, rmSync as rmSync3 } from "fs";
25085
- import { join as join39 } from "path";
25515
+ import { readFileSync as readFileSync29, writeFileSync as writeFileSync18, existsSync as existsSync47, mkdirSync as mkdirSync19, rmSync as rmSync3 } from "fs";
25516
+ import { join as join40 } from "path";
25086
25517
 
25087
25518
  class IndexCache {
25088
25519
  cachePath;
25089
25520
  cache = null;
25090
25521
  constructor(cacheDir) {
25091
- this.cachePath = join39(cacheDir, "index-cache.json");
25522
+ this.cachePath = join40(cacheDir, "index-cache.json");
25092
25523
  }
25093
25524
  load() {
25094
25525
  if (this.cache)
25095
25526
  return this.cache;
25096
- if (!existsSync46(this.cachePath))
25527
+ if (!existsSync47(this.cachePath))
25097
25528
  return null;
25098
25529
  try {
25099
- this.cache = JSON.parse(readFileSync28(this.cachePath, "utf-8"));
25530
+ this.cache = JSON.parse(readFileSync29(this.cachePath, "utf-8"));
25100
25531
  return this.cache;
25101
25532
  } catch {
25102
25533
  return null;
@@ -25104,21 +25535,21 @@ class IndexCache {
25104
25535
  }
25105
25536
  save(result) {
25106
25537
  this.cache = result;
25107
- const dir = join39(this.cachePath, "..");
25108
- if (!existsSync46(dir))
25538
+ const dir = join40(this.cachePath, "..");
25539
+ if (!existsSync47(dir))
25109
25540
  mkdirSync19(dir, { recursive: true });
25110
25541
  writeFileSync18(this.cachePath, JSON.stringify(result), "utf-8");
25111
25542
  }
25112
25543
  invalidate() {
25113
25544
  this.cache = null;
25114
- if (existsSync46(this.cachePath)) {
25545
+ if (existsSync47(this.cachePath)) {
25115
25546
  try {
25116
25547
  rmSync3(this.cachePath);
25117
25548
  } catch {}
25118
25549
  }
25119
25550
  }
25120
25551
  }
25121
- var init_cache = () => {};
25552
+ var init_cache2 = () => {};
25122
25553
 
25123
25554
  // src/modules/indexer/map-select.ts
25124
25555
  function isNoiseFile(file) {
@@ -25186,11 +25617,11 @@ var init_map_select = __esm(() => {
25186
25617
  });
25187
25618
 
25188
25619
  // src/modules/indexer/project-profile.ts
25189
- import { readFileSync as readFileSync29, existsSync as existsSync47 } from "fs";
25190
- import { join as join40 } from "path";
25620
+ import { readFileSync as readFileSync30, existsSync as existsSync48 } from "fs";
25621
+ import { join as join41 } from "path";
25191
25622
  function detectManifest(baseDir) {
25192
25623
  for (const manifest of MANIFEST_ORDER) {
25193
- if (existsSync47(join40(baseDir, manifest)))
25624
+ if (existsSync48(join41(baseDir, manifest)))
25194
25625
  return manifest;
25195
25626
  }
25196
25627
  return null;
@@ -25207,7 +25638,7 @@ function cleanDependency(entry) {
25207
25638
  }
25208
25639
  function readPackageJson(baseDir) {
25209
25640
  try {
25210
- const raw = JSON.parse(readFileSync29(join40(baseDir, "package.json"), "utf-8"));
25641
+ const raw = JSON.parse(readFileSync30(join41(baseDir, "package.json"), "utf-8"));
25211
25642
  if (!raw || typeof raw !== "object")
25212
25643
  return null;
25213
25644
  const profile = {
@@ -25231,7 +25662,7 @@ function readPackageJson(baseDir) {
25231
25662
  }
25232
25663
  function readPyproject(baseDir) {
25233
25664
  try {
25234
- const content = readFileSync29(join40(baseDir, "pyproject.toml"), "utf-8");
25665
+ const content = readFileSync30(join41(baseDir, "pyproject.toml"), "utf-8");
25235
25666
  const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
25236
25667
  const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
25237
25668
  if (nameMatch)
@@ -25247,7 +25678,7 @@ function readPyproject(baseDir) {
25247
25678
  }
25248
25679
  function readCargo(baseDir) {
25249
25680
  try {
25250
- const content = readFileSync29(join40(baseDir, "Cargo.toml"), "utf-8");
25681
+ const content = readFileSync30(join41(baseDir, "Cargo.toml"), "utf-8");
25251
25682
  const profile = { runtime: "rust", deps: [], devDeps: [], scripts: {} };
25252
25683
  const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
25253
25684
  if (nameMatch)
@@ -25271,7 +25702,7 @@ function readCargo(baseDir) {
25271
25702
  }
25272
25703
  function readGoMod(baseDir) {
25273
25704
  try {
25274
- const content = readFileSync29(join40(baseDir, "go.mod"), "utf-8");
25705
+ const content = readFileSync30(join41(baseDir, "go.mod"), "utf-8");
25275
25706
  const profile = { runtime: "go", deps: [], devDeps: [], scripts: {} };
25276
25707
  const moduleMatch = content.match(/^module\s+(\S+)/m);
25277
25708
  if (moduleMatch)
@@ -25289,7 +25720,7 @@ function readGoMod(baseDir) {
25289
25720
  }
25290
25721
  function readRequirements(baseDir) {
25291
25722
  try {
25292
- const content = readFileSync29(join40(baseDir, "requirements.txt"), "utf-8");
25723
+ const content = readFileSync30(join41(baseDir, "requirements.txt"), "utf-8");
25293
25724
  const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
25294
25725
  for (const line of content.split(`
25295
25726
  `)) {
@@ -25354,7 +25785,7 @@ var init_project_profile = __esm(() => {
25354
25785
  });
25355
25786
 
25356
25787
  // src/modules/indexer/module.ts
25357
- import { dirname as dirname14 } from "path";
25788
+ import { dirname as dirname15 } from "path";
25358
25789
 
25359
25790
  class IndexerModule {
25360
25791
  name = "indexer";
@@ -25523,7 +25954,7 @@ ${t("indexer.and_more", { count: result.files.length - listed.length })}` : "";
25523
25954
  const counts = {};
25524
25955
  for (const f of result.files) {
25525
25956
  const normalized = toForwardSlash(f.path);
25526
- const dir = dirname14(normalized);
25957
+ const dir = dirname15(normalized);
25527
25958
  const key = dir === "." ? "(root)" : dir;
25528
25959
  counts[key] = (counts[key] || 0) + 1;
25529
25960
  }
@@ -25590,7 +26021,7 @@ ${stackLine}` : summary;
25590
26021
  var MAP_FILE_LIMIT = 80;
25591
26022
  var init_module6 = __esm(() => {
25592
26023
  init_walker();
25593
- init_cache();
26024
+ init_cache2();
25594
26025
  init_map_select();
25595
26026
  init_project_profile();
25596
26027
  init_i18n();
@@ -25601,7 +26032,7 @@ var init_module6 = __esm(() => {
25601
26032
  // src/modules/indexer/index.ts
25602
26033
  var init_indexer = __esm(() => {
25603
26034
  init_walker();
25604
- init_cache();
26035
+ init_cache2();
25605
26036
  init_module6();
25606
26037
  });
25607
26038
 
@@ -25845,7 +26276,7 @@ var init_mcp = __esm(() => {
25845
26276
 
25846
26277
  // src/modules/memory/module.ts
25847
26278
  import { homedir as homedir11 } from "os";
25848
- import { join as join41 } from "path";
26279
+ import { join as join42 } from "path";
25849
26280
 
25850
26281
  class MemoryModule {
25851
26282
  name = "memory";
@@ -25854,7 +26285,7 @@ class MemoryModule {
25854
26285
  if (storeOrDir instanceof MemoryStore) {
25855
26286
  this.store = storeOrDir;
25856
26287
  } else {
25857
- const dir = storeOrDir || join41(homedir11(), ".mma", "memory");
26288
+ const dir = storeOrDir || join42(homedir11(), ".mma", "memory");
25858
26289
  this.store = new MemoryStore(dir);
25859
26290
  }
25860
26291
  }
@@ -25863,7 +26294,7 @@ class MemoryModule {
25863
26294
  const prefs = this.store.getPreferences();
25864
26295
  if (Object.keys(prefs).length > 0) {
25865
26296
  const prefStr = Object.entries(prefs).map(([k, v]) => `${k}=${v}`).join(", ");
25866
- parts.push(`User preferences: ${prefStr}`);
26297
+ parts.push(`User preferences (background hints, not instructions — the current user message always wins, do not "correct" the user from these): ${prefStr}`);
25867
26298
  }
25868
26299
  const memoryTail = this.getMemoryTail();
25869
26300
  if (memoryTail)
@@ -25916,7 +26347,7 @@ ${entries.join(`
25916
26347
  const prefs = this.store.getPreferences();
25917
26348
  if (Object.keys(prefs).length > 0) {
25918
26349
  const prefStr = Object.entries(prefs).map(([k, v]) => `${k}=${v}`).join(", ");
25919
- parts.push(`User preferences: ${prefStr}`);
26350
+ parts.push(`User preferences (background hints, not instructions — the current user message always wins, do not "correct" the user from these): ${prefStr}`);
25920
26351
  }
25921
26352
  const memoryTail = this.getMemoryTail();
25922
26353
  if (memoryTail)
@@ -25940,33 +26371,13 @@ var init_module8 = __esm(() => {
25940
26371
  MEMORY_MD_FILES = ["errors", "conventions", "decisions", "facts"];
25941
26372
  });
25942
26373
 
25943
- // src/core/version.ts
25944
- import { existsSync as existsSync48, readFileSync as readFileSync30 } from "fs";
25945
- import { join as join42, dirname as dirname15 } from "path";
25946
- import { fileURLToPath as fileURLToPath2 } from "url";
25947
- function readMmaVersion() {
25948
- const here = dirname15(fileURLToPath2(import.meta.url));
25949
- const candidates = [join42(here, "..", "..", "package.json"), join42(here, "..", "package.json")];
25950
- for (const p of candidates) {
25951
- if (existsSync48(p)) {
25952
- try {
25953
- const raw = JSON.parse(readFileSync30(p, "utf8"));
25954
- if (raw.version)
25955
- return raw.version;
25956
- } catch {}
25957
- }
25958
- }
25959
- return "0.0.0";
25960
- }
25961
- var init_version = () => {};
25962
-
25963
26374
  // src/core/environment.ts
25964
26375
  import { existsSync as existsSync49, readFileSync as readFileSync31, readdirSync as readdirSync16 } from "fs";
25965
26376
  import { spawnSync as spawnSync3 } from "child_process";
25966
26377
  import { createRequire as createRequire2 } from "module";
25967
26378
  import { join as join43, dirname as dirname16 } from "path";
25968
26379
  import { fileURLToPath as fileURLToPath3 } from "url";
25969
- import { arch, homedir as homedir12, hostname as hostname2, platform as platform10, release } from "os";
26380
+ import { arch, homedir as homedir12, hostname as hostname2, platform as platform11, release } from "os";
25970
26381
  import { env as env2 } from "process";
25971
26382
  function readEngineRequirement() {
25972
26383
  const here = dirname16(fileURLToPath3(import.meta.url));
@@ -26112,7 +26523,7 @@ function collectEnvironment(opts) {
26112
26523
  mmaVersion: readMmaVersion(),
26113
26524
  runtime,
26114
26525
  os: {
26115
- platform: platform10(),
26526
+ platform: platform11(),
26116
26527
  arch: arch(),
26117
26528
  release: release(),
26118
26529
  hostname: hostname2(),
@@ -26469,6 +26880,7 @@ var init_set_thinking = __esm(() => {
26469
26880
  // src/core/bootstrap.ts
26470
26881
  var exports_bootstrap = {};
26471
26882
  __export(exports_bootstrap, {
26883
+ setOneShotMode: () => setOneShotMode,
26472
26884
  buildSystemInfo: () => buildSystemInfo,
26473
26885
  bootstrap: () => bootstrap
26474
26886
  });
@@ -26540,6 +26952,7 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
26540
26952
  `Reply in the user's language. Use tools for file ops (read/write/edit/delete), search (glob/grep), shell (bash), web, subagents, browser, MCP. Explain briefly if not obvious. On tool failure: analyze, fix the call, retry up to 2x with different approaches, then ask the user.`,
26541
26953
  `Design: YAGNI (no unneeded code), KISS (simple over clever), DRY (reuse existing utilities).`,
26542
26954
  `SCOPE DISCIPLINE: do ONLY what the user explicitly asked — no extra features, files, refactors, "improvements", or fixes beyond the request. Read-only requests ("расскажи", "покажи", "объясни", "check") mean READ-ONLY: inspect and answer, never create/modify/delete anything. If the task is ambiguous (what to create, where, which variant) or the request implies action on something you could not find — STOP and ask the user a short clarifying question in plain text instead of guessing.`,
26955
+ `INPUT PRIORITY: the current user message outranks stored memory/preferences/facts. Never override, reinterpret, or "correct" an explicit value the user states now (city, path, name, language, choice) because a stored preference disagrees — follow the user's current message. If they truly conflict or look like a typo, ask the user instead of assuming.`,
26543
26956
  `NOT FOUND ≠ MISSING PROJECT: a "not found" tool result means the PATH was wrong (typo, different location), not that the project does not exist. Before creating or scaffolding ANY project/files: first run list_dir on the working directory to see what is already there; if a user-named path is not found, list its parent directory to locate the real path. NEVER create a new project when the user asked about an existing one — inspect first, create only after confirming the workspace is empty AND the user asked for creation.`
26544
26957
  ];
26545
26958
  if (isWin) {
@@ -26583,6 +26996,9 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
26583
26996
  return lines.join(`
26584
26997
  `);
26585
26998
  }
26999
+ function setOneShotMode(value) {
27000
+ oneShotMode = value;
27001
+ }
26586
27002
  async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reasoningLevel) {
26587
27003
  const dir = configDir || process.env.MMA_CONFIG_DIR || join46(homedir15(), ".mma");
26588
27004
  const projectConfigPath = projectDir ? join46(projectDir, ".mmrc") : join46(process.cwd(), ".mmrc");
@@ -26645,7 +27061,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26645
27061
  const profile = new UserProfile(join46(dir));
26646
27062
  profile.load() || profile.collect();
26647
27063
  profile.save();
26648
- const llmProvider = buildActiveProvider(config, logger4).provider;
27064
+ let activeSessionManager;
27065
+ const getSessionId = () => activeSessionManager?.getActiveMeta()?.id;
27066
+ const llmProvider = buildActiveProvider(config, logger4, { getSessionId }).provider;
26649
27067
  const providerSpec = BUILTIN_PROVIDERS.find((p) => p.type === config.provider.type);
26650
27068
  const reasoningStrategy = providerSpec?.capabilities.reasoningStrategy ?? "none";
26651
27069
  let reasoningProbePromise = Promise.resolve(false);
@@ -26724,6 +27142,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26724
27142
  maxSessions: config.session.maxSessions,
26725
27143
  isolation: config.sessionIsolation
26726
27144
  });
27145
+ activeSessionManager = sessionManager;
26727
27146
  if (config.session.autoSave && !sessionManager.getActive()) {
26728
27147
  sessionManager.create();
26729
27148
  }
@@ -26815,7 +27234,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26815
27234
  moduleRegistry.register(lspModule);
26816
27235
  registerBuiltinPlugin(pluginManager, lspModule.getPlugin());
26817
27236
  let startupCheckBlock = null;
26818
- const startupCheckPromise = !exitOnComplete ? runStartupHealthCheck(config.lsp ?? DEFAULT_LSP_CONFIG, baseDir, { logger: lspLogger }) : Promise.resolve(null);
27237
+ const startupCheckPromise = !oneShotMode && !exitOnComplete ? runStartupHealthCheck(config.lsp ?? DEFAULT_LSP_CONFIG, baseDir, { logger: lspLogger }) : Promise.resolve(null);
26819
27238
  const moduleTools = moduleRegistry.collectToolDefinitions();
26820
27239
  for (const tool of moduleTools) {
26821
27240
  toolRegistry.register(tool);
@@ -26970,6 +27389,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26970
27389
  contextProbe: contextProbePromise
26971
27390
  };
26972
27391
  }
27392
+ var oneShotMode = false;
26973
27393
  var init_bootstrap = __esm(() => {
26974
27394
  init_config2();
26975
27395
  init_app_logger();
@@ -27445,9 +27865,9 @@ class Spinner {
27445
27865
  tick() {
27446
27866
  if (!this.timer)
27447
27867
  return;
27448
- const frame = FRAMES[this.frame % FRAMES.length];
27868
+ const frame2 = FRAMES[this.frame % FRAMES.length];
27449
27869
  this.frame++;
27450
- this.stream.write("\r" + pc2.cyan(frame) + " " + this.message + "\x1B[K");
27870
+ this.stream.write("\r" + pc2.cyan(frame2) + " " + this.message + "\x1B[K");
27451
27871
  }
27452
27872
  }
27453
27873
  var FRAMES;
@@ -30043,9 +30463,9 @@ var require_stringifyNumber = __commonJS((exports) => {
30043
30463
  function stringifyNumber({ format, minFractionDigits, tag, value }) {
30044
30464
  if (typeof value === "bigint")
30045
30465
  return String(value);
30046
- const num = typeof value === "number" ? value : Number(value);
30047
- if (!isFinite(num))
30048
- return isNaN(num) ? ".nan" : num < 0 ? "-.inf" : ".inf";
30466
+ const num3 = typeof value === "number" ? value : Number(value);
30467
+ if (!isFinite(num3))
30468
+ return isNaN(num3) ? ".nan" : num3 < 0 ? "-.inf" : ".inf";
30049
30469
  let n = Object.is(value, -0) ? "-0" : JSON.stringify(value);
30050
30470
  if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^-?\d/.test(n) && !n.includes("e")) {
30051
30471
  let i = n.indexOf(".");
@@ -30082,8 +30502,8 @@ var require_float = __commonJS((exports) => {
30082
30502
  test: /^[-+]?(?:\.[0-9]+|[0-9]+(?:\.[0-9]*)?)[eE][-+]?[0-9]+$/,
30083
30503
  resolve: (str) => parseFloat(str),
30084
30504
  stringify(node) {
30085
- const num = Number(node.value);
30086
- return isFinite(num) ? num.toExponential() : stringifyNumber.stringifyNumber(node);
30505
+ const num3 = Number(node.value);
30506
+ return isFinite(num3) ? num3.toExponential() : stringifyNumber.stringifyNumber(node);
30087
30507
  }
30088
30508
  };
30089
30509
  var float = {
@@ -30487,8 +30907,8 @@ var require_float2 = __commonJS((exports) => {
30487
30907
  test: /^[-+]?(?:[0-9][0-9_]*)?(?:\.[0-9_]*)?[eE][-+]?[0-9]+$/,
30488
30908
  resolve: (str) => parseFloat(str.replace(/_/g, "")),
30489
30909
  stringify(node) {
30490
- const num = Number(node.value);
30491
- return isFinite(num) ? num.toExponential() : stringifyNumber.stringifyNumber(node);
30910
+ const num3 = Number(node.value);
30911
+ return isFinite(num3) ? num3.toExponential() : stringifyNumber.stringifyNumber(node);
30492
30912
  }
30493
30913
  };
30494
30914
  var float = {
@@ -30678,23 +31098,23 @@ var require_timestamp = __commonJS((exports) => {
30678
31098
  function parseSexagesimal(str, asBigInt) {
30679
31099
  const sign = str[0];
30680
31100
  const parts = sign === "-" || sign === "+" ? str.substring(1) : str;
30681
- const num = (n) => asBigInt ? BigInt(n) : Number(n);
30682
- const res = parts.replace(/_/g, "").split(":").reduce((res2, p) => res2 * num(60) + num(p), num(0));
30683
- return sign === "-" ? num(-1) * res : res;
31101
+ const num3 = (n) => asBigInt ? BigInt(n) : Number(n);
31102
+ const res = parts.replace(/_/g, "").split(":").reduce((res2, p) => res2 * num3(60) + num3(p), num3(0));
31103
+ return sign === "-" ? num3(-1) * res : res;
30684
31104
  }
30685
31105
  function stringifySexagesimal(node) {
30686
31106
  let { value } = node;
30687
- let num = (n) => n;
31107
+ let num3 = (n) => n;
30688
31108
  if (typeof value === "bigint")
30689
- num = (n) => BigInt(n);
31109
+ num3 = (n) => BigInt(n);
30690
31110
  else if (isNaN(value) || !isFinite(value))
30691
31111
  return stringifyNumber.stringifyNumber(node);
30692
31112
  let sign = "";
30693
31113
  if (value < 0) {
30694
31114
  sign = "-";
30695
- value *= num(-1);
31115
+ value *= num3(-1);
30696
31116
  }
30697
- const _60 = num(60);
31117
+ const _60 = num3(60);
30698
31118
  const parts = [value % _60];
30699
31119
  if (value < 60) {
30700
31120
  parts.unshift(0);
@@ -37535,6 +37955,63 @@ init_version();
37535
37955
  init_map_command();
37536
37956
  init_budget();
37537
37957
 
37958
+ // src/llm/provider-budget.ts
37959
+ var DEFAULT_TIMEOUT_MS = 5000;
37960
+ function num2(value) {
37961
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
37962
+ }
37963
+ async function getJson(url, apiKey, timeoutMs) {
37964
+ const response = await fetch(url, {
37965
+ headers: { Authorization: `Bearer ${apiKey}` },
37966
+ signal: AbortSignal.timeout(timeoutMs)
37967
+ });
37968
+ if (!response.ok) {
37969
+ throw new Error(`HTTP ${response.status}`);
37970
+ }
37971
+ return response.json();
37972
+ }
37973
+ async function fetchProviderBudget(provider, baseUrl, apiKey, options) {
37974
+ if (provider !== "openrouter") {
37975
+ options.log("debug", `budget: provider "${provider}" does not expose an API balance`);
37976
+ return { budget: null, reason: "unsupported" };
37977
+ }
37978
+ if (!apiKey) {
37979
+ options.log("debug", "budget: no api key configured");
37980
+ return { budget: null, reason: "no-key" };
37981
+ }
37982
+ const base = baseUrl.replace(/\/$/, "");
37983
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
37984
+ try {
37985
+ const keyBody = await getJson(`${base}/key`, apiKey, timeoutMs);
37986
+ const data = keyBody?.data ?? {};
37987
+ const budget = { provider, source: "openrouter" };
37988
+ budget.keyLabel = typeof data.label === "string" ? data.label : undefined;
37989
+ budget.keyUsageUsd = num2(data.usage);
37990
+ budget.keyLimitUsd = num2(data.limit);
37991
+ budget.keyRemainingUsd = num2(data.limit_remaining);
37992
+ budget.isFreeTier = typeof data.is_free_tier === "boolean" ? data.is_free_tier : undefined;
37993
+ try {
37994
+ const creditsBody = await getJson(`${base}/credits`, apiKey, timeoutMs);
37995
+ const c = creditsBody?.data ?? {};
37996
+ budget.totalCreditsUsd = num2(c.total_credits);
37997
+ budget.totalUsageUsd = num2(c.total_usage);
37998
+ if (budget.totalCreditsUsd !== undefined && budget.totalUsageUsd !== undefined) {
37999
+ budget.balanceUsd = budget.totalCreditsUsd - budget.totalUsageUsd;
38000
+ }
38001
+ } catch (creditsErr) {
38002
+ options.log("debug", `budget: /credits unavailable (${creditsErr instanceof Error ? creditsErr.message : String(creditsErr)})`);
38003
+ }
38004
+ return { budget, reason: "ok" };
38005
+ } catch (err) {
38006
+ const message = err instanceof Error ? err.message : String(err);
38007
+ options.log("warn", `budget: request failed (${message})`);
38008
+ return { budget: null, reason: "error", error: message };
38009
+ }
38010
+ }
38011
+
38012
+ // src/cli/commands.ts
38013
+ init_prices();
38014
+
37538
38015
  // src/modules/updater/changelog-reader.ts
37539
38016
  import { readFileSync as readFileSync35, existsSync as existsSync53 } from "fs";
37540
38017
  import { dirname as dirname20, join as join48 } from "path";
@@ -37823,6 +38300,53 @@ function buildContextCommand(program2) {
37823
38300
  console.log(t("cli.context_set", { size: contextWindow }));
37824
38301
  });
37825
38302
  }
38303
+ function buildUsageCommand(program2) {
38304
+ program2.command("usage").description(t("cli.usage")).action(async () => {
38305
+ const { config, logger: logger4 } = await bootstrap();
38306
+ const { type: provider, baseUrl, apiKey } = config.provider;
38307
+ const result = await fetchProviderBudget(provider, baseUrl, apiKey, {
38308
+ log: (level, message) => level === "warn" ? logger4.warn(message) : logger4.debug(message)
38309
+ });
38310
+ if (result.reason === "unsupported") {
38311
+ console.log(t("cli.usage_unsupported", { provider }));
38312
+ return;
38313
+ }
38314
+ if (result.reason === "no-key") {
38315
+ console.log(t("cli.usage_no_key"));
38316
+ return;
38317
+ }
38318
+ if (result.reason === "error" || !result.budget) {
38319
+ console.log(t("cli.usage_error", { error: result.error ?? "" }));
38320
+ return;
38321
+ }
38322
+ const b = result.budget;
38323
+ let printed = false;
38324
+ if (b.keyUsageUsd !== undefined) {
38325
+ console.log(t("cli.usage_key_usage", { usage: formatCost(b.keyUsageUsd) }));
38326
+ printed = true;
38327
+ }
38328
+ if (b.keyLimitUsd !== undefined && b.keyRemainingUsd !== undefined) {
38329
+ console.log(t("cli.usage_key_limit", {
38330
+ limit: formatCost(b.keyLimitUsd),
38331
+ remaining: formatCost(b.keyRemainingUsd)
38332
+ }));
38333
+ printed = true;
38334
+ }
38335
+ if (b.balanceUsd !== undefined) {
38336
+ console.log(t("cli.usage_balance", { balance: formatCost(b.balanceUsd) }));
38337
+ printed = true;
38338
+ }
38339
+ if (b.totalCreditsUsd !== undefined && b.totalUsageUsd !== undefined) {
38340
+ console.log(t("cli.usage_account", {
38341
+ credits: formatCost(b.totalCreditsUsd),
38342
+ used: formatCost(b.totalUsageUsd)
38343
+ }));
38344
+ printed = true;
38345
+ }
38346
+ if (!printed)
38347
+ console.log(t("cli.usage_empty"));
38348
+ });
38349
+ }
37826
38350
  function buildMapCommand(program2) {
37827
38351
  program2.command("map").description(t("cli.map.description")).argument("[action]", t("cli.map.action"), "summary").argument("[query]", t("cli.map.query")).action(async (action, query) => {
37828
38352
  const { agent } = await bootstrap();
@@ -37979,6 +38503,31 @@ function buildSessionCommands(program2) {
37979
38503
  }
37980
38504
  }
37981
38505
  }
38506
+ const usageEvents = sessionManager.loadSessionLog(id).filter((e) => e.type === "llm_usage");
38507
+ if (usageEvents.length > 0) {
38508
+ let prompt = 0;
38509
+ let completion = 0;
38510
+ let cached = 0;
38511
+ for (const e of usageEvents) {
38512
+ prompt += e.promptTokens ?? 0;
38513
+ completion += e.completionTokens ?? 0;
38514
+ cached += e.cachedTokens ?? 0;
38515
+ }
38516
+ console.log("");
38517
+ console.log(pc2.cyan(t("cli.session_usage", {
38518
+ prompt,
38519
+ completion,
38520
+ total: prompt + completion
38521
+ })));
38522
+ if (cached > 0 && prompt > 0) {
38523
+ const hit = Math.round(cached / prompt * 100);
38524
+ console.log(pc2.dim(t("cli.session_cache", {
38525
+ hit,
38526
+ cached,
38527
+ uncached: Math.max(0, prompt - cached)
38528
+ })));
38529
+ }
38530
+ }
37982
38531
  });
37983
38532
  session2.command("delete").argument("<id>", "Session id").description(t("cli.delete_session")).action(async (id) => {
37984
38533
  const { sessionManager } = await bootstrap();
@@ -38018,6 +38567,7 @@ function createProgram() {
38018
38567
  buildConfigCommands(program2);
38019
38568
  buildModelCommands(program2);
38020
38569
  buildContextCommand(program2);
38570
+ buildUsageCommand(program2);
38021
38571
  buildMapCommand(program2);
38022
38572
  buildProviderCommands(program2);
38023
38573
  buildSessionCommands(program2);
@@ -38025,11 +38575,15 @@ function createProgram() {
38025
38575
  createPluginCommand(program2);
38026
38576
  buildChangelogCommand(program2);
38027
38577
  program2.argument("[prompt...]", "Prompt to execute").description("Run a single prompt").action((prompt) => {});
38028
- for (const cmd of program2.commands) {
38578
+ const attachOneShotExit = (cmd) => {
38029
38579
  cmd.hook("postAction", () => {
38030
38580
  process.exit(0);
38031
38581
  });
38032
- }
38582
+ for (const sub of cmd.commands)
38583
+ attachOneShotExit(sub);
38584
+ };
38585
+ for (const cmd of program2.commands)
38586
+ attachOneShotExit(cmd);
38033
38587
  return program2;
38034
38588
  }
38035
38589
 
@@ -39662,6 +40216,28 @@ function stepContextForTool(plan, tool, args) {
39662
40216
  // src/cli/repl.ts
39663
40217
  init_prices();
39664
40218
 
40219
+ // src/cli/cache-line.ts
40220
+ init_i18n();
40221
+ init_prices();
40222
+ function formatCacheLine(cache) {
40223
+ if (!cache)
40224
+ return;
40225
+ const total = cache.cachedTokens + cache.uncachedTokens;
40226
+ const hit = Math.round(cache.hitRate * 100);
40227
+ if (total > 0) {
40228
+ if (cache.saved !== undefined && cache.saved > 0) {
40229
+ return t("repl.cache", { hit, saved: formatCost(cache.saved) });
40230
+ }
40231
+ return t("repl.cache_nosave", { hit });
40232
+ }
40233
+ const broken = cache.prefixCause !== undefined && cache.prefixCause !== "none" && cache.prefixCause !== "unknown";
40234
+ if (broken && cache.prefixStable !== undefined && cache.prefixStable < 0.98) {
40235
+ const stable = Math.round(cache.prefixStable * 100);
40236
+ return t("repl.prefix", { stable, cause: t(`cache.cause.${cache.prefixCause}`) });
40237
+ }
40238
+ return;
40239
+ }
40240
+
39665
40241
  // src/ui/output.ts
39666
40242
  function writeWarning(text) {
39667
40243
  process.stdout.write(formatWarning(text) + `
@@ -40168,6 +40744,10 @@ ${t("image.clipboard_empty")}`));
40168
40744
  if (result.totalCost !== undefined && result.totalCost > 0) {
40169
40745
  console.log(pc2.yellow(` ${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
40170
40746
  }
40747
+ const cacheLine = formatCacheLine(result.cache);
40748
+ if (cacheLine) {
40749
+ console.log(pc2.dim(` ${cacheLine}`));
40750
+ }
40171
40751
  } else if (ui?.showCompaction && result.compactionCount !== undefined) {
40172
40752
  if (result.compactionCount > this.lastCompactionShown) {
40173
40753
  this.lastCompactionShown = result.compactionCount;
@@ -40352,6 +40932,10 @@ function printRunResult(result, flush) {
40352
40932
  } else if (result.totalTokens !== undefined && result.totalTokens > 0) {
40353
40933
  console.log(pc2.dim(`${t("repl.tokens", { tokens: result.totalTokens })}`));
40354
40934
  }
40935
+ const cacheLine = formatCacheLine(result.cache);
40936
+ if (cacheLine) {
40937
+ console.log(pc2.dim(` ${cacheLine}`));
40938
+ }
40355
40939
  if (!result.text) {
40356
40940
  console.log(pc2.yellow(t("cli.no_output")));
40357
40941
  }
@@ -40369,6 +40953,7 @@ init_colors();
40369
40953
  import { existsSync as existsSync61 } from "fs";
40370
40954
  import { join as join57, dirname as dirname25 } from "path";
40371
40955
  import { homedir as homedir20 } from "os";
40956
+ import { fileURLToPath as fileURLToPath6 } from "url";
40372
40957
 
40373
40958
  // src/modules/updater/index.ts
40374
40959
  init_checker();
@@ -40476,6 +41061,11 @@ ${t("cli.changelog_title", { version: result.latest })}
40476
41061
  await this.runOnce();
40477
41062
  }
40478
41063
  }
41064
+ // src/modules/updater/dev-detect.ts
41065
+ function isDevEntryPath(path) {
41066
+ const clean = path.split(/[?#]/)[0];
41067
+ return clean.endsWith(".ts") || clean.endsWith(".tsx") || clean.endsWith(".mts") || clean.endsWith(".cts");
41068
+ }
40479
41069
  // src/core/crash-handler.ts
40480
41070
  init_environment();
40481
41071
  init_data_sanitizer();
@@ -40564,6 +41154,8 @@ function closestCommand(input, known, maxDistance = 2) {
40564
41154
  // src/cli/main.ts
40565
41155
  init_utils();
40566
41156
  function startAutoUpdate(config) {
41157
+ if (isDevEntryPath(fileURLToPath6(import.meta.url)))
41158
+ return;
40567
41159
  try {
40568
41160
  const module = new UpdaterModule(config.updater, readMmaVersion(), "micro-models-agent", {
40569
41161
  info: (m) => process.stderr.write(pc2.dim(m) + `
@@ -40582,6 +41174,22 @@ function startAutoUpdate(config) {
40582
41174
  async function main() {
40583
41175
  installCrashHandlers();
40584
41176
  const program2 = createProgram();
41177
+ const valueOpts = new Set(["-d", "--dir", "--reasoning"]);
41178
+ const argv = process.argv.slice(2);
41179
+ let firstPositional;
41180
+ for (let i = 0;i < argv.length; i++) {
41181
+ const a = argv[i];
41182
+ if (a.startsWith("-")) {
41183
+ if (valueOpts.has(a))
41184
+ i++;
41185
+ continue;
41186
+ }
41187
+ firstPositional = a;
41188
+ break;
41189
+ }
41190
+ if (firstPositional && program2.commands.some((c) => c.name() === firstPositional)) {
41191
+ setOneShotMode(true);
41192
+ }
40585
41193
  program2.parse(process.argv);
40586
41194
  const cmdNames = new Set(program2.commands.map((c) => c.name()));
40587
41195
  const opts = program2.opts();
@@ -40633,7 +41241,8 @@ async function main() {
40633
41241
  completionTokens: result2.completionTokens ?? null,
40634
41242
  totalTokens: result2.totalTokens ?? null,
40635
41243
  totalCost: result2.totalCost ?? null,
40636
- costBreakdown: result2.costBreakdown ?? []
41244
+ costBreakdown: result2.costBreakdown ?? [],
41245
+ cache: result2.cache ?? null
40637
41246
  }, null, 2));
40638
41247
  process.stdout.write(`
40639
41248
  `);