micro-models-agent 2.11.0 → 2.12.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 (347) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/assets/js/tabs.js +22 -3
  3. package/dist/cli/cache-line.js +1 -0
  4. package/dist/cli/command-suggest.js +5 -4
  5. package/dist/cli/commands.js +231 -122
  6. package/dist/cli/completer.js +132 -31
  7. package/dist/cli/index.js +1 -0
  8. package/dist/cli/json-payload.js +4 -4
  9. package/dist/cli/main.js +166 -61
  10. package/dist/cli/onboarding-commands.js +126 -0
  11. package/dist/cli/plugin-commands.js +2 -1
  12. package/dist/cli/relaunch.js +16 -13
  13. package/dist/cli/repl-commands-lsp.js +75 -0
  14. package/dist/cli/repl-commands-skills.js +105 -0
  15. package/dist/cli/repl-commands.js +589 -266
  16. package/dist/cli/repl.js +436 -177
  17. package/dist/cli/run-result.js +5 -6
  18. package/dist/cli/security-commands.js +37 -28
  19. package/dist/cli/setup-order.js +4 -55
  20. package/dist/cli/setup-prompt.js +3 -2
  21. package/dist/cli/setup.js +27 -107
  22. package/dist/cli/web-command.js +98 -0
  23. package/dist/config/budget.js +5 -5
  24. package/dist/config/config.js +103 -96
  25. package/dist/config/defaults.js +38 -8
  26. package/dist/config/domains.js +24 -27
  27. package/dist/config/env.js +46 -0
  28. package/dist/config/experts.js +2 -0
  29. package/dist/config/index.js +1 -0
  30. package/dist/config/paths.js +56 -0
  31. package/dist/config/redact.js +44 -0
  32. package/dist/config/registry-extra.js +334 -0
  33. package/dist/config/registry.js +584 -0
  34. package/dist/config/security.js +35 -36
  35. package/dist/config/timeouts.js +74 -0
  36. package/dist/config/utils.js +16 -15
  37. package/dist/core/agent/artifact-progress.js +59 -0
  38. package/dist/core/agent/artifact-resolve.js +79 -0
  39. package/dist/core/agent/audit-gate.js +7 -3
  40. package/dist/core/agent/compaction.js +2 -2
  41. package/dist/core/agent/constants.js +33 -4
  42. package/dist/core/agent/context-log.js +454 -0
  43. package/dist/core/agent/context-renderer.js +5 -0
  44. package/dist/core/agent/critic-gate.js +132 -0
  45. package/dist/core/agent/hallucination-gate.js +148 -38
  46. package/dist/core/agent/loop-state.js +15 -0
  47. package/dist/core/agent/prefix-monitor.js +1 -1
  48. package/dist/core/agent/reasoning-resolver.js +10 -1
  49. package/dist/core/agent/token-tracker.js +7 -4
  50. package/dist/core/agent/tool-batch.js +93 -18
  51. package/dist/core/agent/tool-images.js +18 -0
  52. package/dist/core/agent/tool-output.js +65 -11
  53. package/dist/core/agent/tool-pairing.js +60 -0
  54. package/dist/core/agent-moe.js +25 -24
  55. package/dist/core/agent.js +429 -108
  56. package/dist/core/bootstrap/agent-phase.js +66 -0
  57. package/dist/core/bootstrap/config-phase.js +86 -0
  58. package/dist/core/bootstrap/modules-phase.js +269 -0
  59. package/dist/core/bootstrap/provider-phase.js +183 -0
  60. package/dist/core/bootstrap/session-phase.js +204 -0
  61. package/dist/core/bootstrap/state.js +94 -0
  62. package/dist/core/bootstrap/workspace-phase.js +115 -0
  63. package/dist/core/bootstrap.js +92 -660
  64. package/dist/core/crash-handler.js +17 -7
  65. package/dist/core/environment.js +37 -12
  66. package/dist/core/host-plan.js +43 -0
  67. package/dist/core/host.js +23 -0
  68. package/dist/core/index.js +1 -0
  69. package/dist/core/prompt-builder.js +17 -1
  70. package/dist/core/prompt-overflow.js +42 -43
  71. package/dist/core/session-logger.js +122 -30
  72. package/dist/core/system-prompt.js +117 -0
  73. package/dist/core/version.js +6 -4
  74. package/dist/core/web-host.js +34 -0
  75. package/dist/core/workspace.js +19 -15
  76. package/dist/i18n/index.js +37 -3
  77. package/dist/index.js +7 -3
  78. package/dist/llm/image-utils.js +55 -64
  79. package/dist/llm/llm-errors.js +9 -0
  80. package/dist/llm/model-loader.js +10 -32
  81. package/dist/llm/models-dev.js +121 -0
  82. package/dist/llm/openai-compat.js +146 -73
  83. package/dist/llm/orchestrator.js +33 -11
  84. package/dist/llm/provider-budget.js +2 -2
  85. package/dist/llm/provider-context.js +233 -0
  86. package/dist/llm/provider.js +1 -1
  87. package/dist/llm/response.js +5 -0
  88. package/dist/llm/token-counter.js +27 -11
  89. package/dist/logger/app-logger.js +48 -22
  90. package/dist/logger/file-log.js +28 -19
  91. package/dist/logger/index.js +1 -0
  92. package/dist/main.js +273 -47
  93. package/dist/migration/backup.js +14 -3
  94. package/dist/migration/detect.js +12 -3
  95. package/dist/migration/index.js +1 -0
  96. package/dist/modules/artifacts/store.js +9 -8
  97. package/dist/modules/browser/actions.js +6 -0
  98. package/dist/modules/browser/bridge-client.js +14 -12
  99. package/dist/modules/browser/bridge-path.js +4 -4
  100. package/dist/modules/browser/console-buffer.js +37 -0
  101. package/dist/modules/browser/cookie-store.js +5 -0
  102. package/dist/modules/browser/driver-types.js +1 -0
  103. package/dist/modules/browser/driver.js +19 -11
  104. package/dist/modules/browser/index.js +3 -1
  105. package/dist/modules/browser/module.js +2 -1
  106. package/dist/modules/browser/session.js +10 -30
  107. package/dist/modules/browser/snapshot.js +19 -13
  108. package/dist/modules/browser/types.js +1 -0
  109. package/dist/modules/certification/cli.js +28 -20
  110. package/dist/modules/certification/fact-checker.js +9 -1
  111. package/dist/modules/certification/loader.js +9 -2
  112. package/dist/modules/certification/manifest.js +83 -21
  113. package/dist/modules/certification/runner.js +23 -13
  114. package/dist/modules/certification/scenarios.js +20 -20
  115. package/dist/modules/certification/syntax-scenarios.js +1 -2
  116. package/dist/modules/context/chunk-query.js +11 -9
  117. package/dist/modules/context/fact-extractor.js +37 -39
  118. package/dist/modules/context/index.js +1 -0
  119. package/dist/modules/context/manager.js +106 -80
  120. package/dist/modules/critic/client.js +176 -0
  121. package/dist/modules/critic/evidence.js +81 -0
  122. package/dist/modules/critic/provider.js +45 -0
  123. package/dist/modules/critic/tools.js +78 -0
  124. package/dist/modules/critic/types.js +1 -0
  125. package/dist/modules/execution/audit-runners.js +28 -34
  126. package/dist/modules/execution/auditor.js +53 -49
  127. package/dist/modules/execution/execution-plugin.js +142 -102
  128. package/dist/modules/execution/index.js +1 -1
  129. package/dist/modules/execution/input-from.js +37 -13
  130. package/dist/modules/execution/module.js +368 -191
  131. package/dist/modules/execution/moe-executor.js +53 -26
  132. package/dist/modules/execution/plan-actions.js +320 -202
  133. package/dist/modules/execution/plan-checks.js +35 -0
  134. package/dist/modules/execution/plan-coverage.js +36 -33
  135. package/dist/modules/execution/plan-steps.js +11 -3
  136. package/dist/modules/execution/plan-store.js +83 -17
  137. package/dist/modules/execution/plan-tool.js +89 -35
  138. package/dist/modules/execution/plan-validator.js +30 -10
  139. package/dist/modules/execution/planner.js +22 -13
  140. package/dist/modules/execution/stuck-detector.js +196 -93
  141. package/dist/modules/execution/tracker.js +22 -8
  142. package/dist/modules/execution/verifier.js +69 -48
  143. package/dist/modules/execution/windows-commands.js +12 -12
  144. package/dist/modules/hallucination/artifact-claim.js +93 -0
  145. package/dist/modules/hallucination/confidence.js +13 -11
  146. package/dist/modules/hallucination/consistency.js +10 -2
  147. package/dist/modules/hallucination/detector.js +10 -5
  148. package/dist/modules/hallucination/factual.js +43 -26
  149. package/dist/modules/hallucination/index.js +1 -0
  150. package/dist/modules/hallucination/js-identifiers.js +44 -45
  151. package/dist/modules/hallucination/llm-judge.js +17 -12
  152. package/dist/modules/hallucination/success-claim.js +59 -0
  153. package/dist/modules/indexer/cache.js +52 -4
  154. package/dist/modules/indexer/index.js +1 -0
  155. package/dist/modules/indexer/map-command.js +2 -4
  156. package/dist/modules/indexer/map-select.js +16 -16
  157. package/dist/modules/indexer/module.js +47 -12
  158. package/dist/modules/indexer/project-profile.js +8 -7
  159. package/dist/modules/indexer/symbols.js +15 -15
  160. package/dist/modules/indexer/walker.js +159 -29
  161. package/dist/modules/lsp/check-tool.js +7 -5
  162. package/dist/modules/lsp/client.js +39 -39
  163. package/dist/modules/lsp/command.js +17 -24
  164. package/dist/modules/lsp/config.js +12 -11
  165. package/dist/modules/lsp/index.js +1 -0
  166. package/dist/modules/lsp/module.js +48 -46
  167. package/dist/modules/lsp/probe.js +13 -14
  168. package/dist/modules/lsp/project-root.js +14 -17
  169. package/dist/modules/lsp/startup-check.js +18 -16
  170. package/dist/modules/mcp/client.js +59 -62
  171. package/dist/modules/mcp/index.js +1 -0
  172. package/dist/modules/mcp/module.js +66 -37
  173. package/dist/modules/mcp/registry.js +5 -0
  174. package/dist/modules/memory/index.js +1 -0
  175. package/dist/modules/memory/module.js +12 -8
  176. package/dist/modules/memory/search.js +4 -1
  177. package/dist/modules/memory/store.js +40 -2
  178. package/dist/modules/onboarding/init.js +47 -0
  179. package/dist/modules/onboarding/meet.js +30 -0
  180. package/dist/modules/onboarding/mode.js +30 -0
  181. package/dist/modules/onboarding/prompts.js +43 -0
  182. package/dist/modules/pipelines/engine.js +10 -0
  183. package/dist/modules/pipelines/index.js +1 -0
  184. package/dist/modules/pipelines/parser.js +4 -1
  185. package/dist/modules/pipelines/template.js +4 -0
  186. package/dist/modules/plugins/builtin/lint-on-write.js +80 -67
  187. package/dist/modules/plugins/builtin/notify.js +2 -0
  188. package/dist/modules/plugins/index.js +1 -0
  189. package/dist/modules/plugins/loader.js +18 -3
  190. package/dist/modules/plugins/manager.js +37 -17
  191. package/dist/modules/pricing/index.js +10 -11
  192. package/dist/modules/pricing/prices.js +12 -12
  193. package/dist/modules/processes/index.js +1 -0
  194. package/dist/modules/processes/kill-tree.js +27 -31
  195. package/dist/modules/processes/registry.js +44 -25
  196. package/dist/modules/processes/runner.js +4 -4
  197. package/dist/modules/providers/capabilities.js +28 -0
  198. package/dist/modules/providers/create.js +3 -4
  199. package/dist/modules/providers/factory.js +7 -7
  200. package/dist/modules/providers/fallback.js +12 -12
  201. package/dist/modules/providers/health.js +4 -4
  202. package/dist/modules/providers/manager.js +50 -19
  203. package/dist/modules/providers/naming.js +15 -0
  204. package/dist/modules/providers/preflight.js +71 -0
  205. package/dist/modules/providers/presets.js +39 -8
  206. package/dist/modules/providers/registry.js +7 -2
  207. package/dist/modules/reasoning/policy.js +8 -6
  208. package/dist/modules/reasoning/probe.js +30 -25
  209. package/dist/modules/security/audit-log.js +19 -36
  210. package/dist/modules/security/audit-notifier.js +35 -75
  211. package/dist/modules/security/command-validator.js +99 -51
  212. package/dist/modules/security/content-scanner.js +8 -8
  213. package/dist/modules/security/data-sanitizer.js +9 -16
  214. package/dist/modules/security/encryption.js +32 -52
  215. package/dist/modules/security/index.js +2 -1
  216. package/dist/modules/security/network-validator.js +120 -43
  217. package/dist/modules/security/path-validator.js +61 -46
  218. package/dist/modules/security/protected-paths.js +73 -0
  219. package/dist/modules/security/rate-limiter.js +17 -49
  220. package/dist/modules/security/security-policies.js +25 -57
  221. package/dist/modules/security/session-encryption.js +32 -71
  222. package/dist/modules/security/session-isolation.js +15 -28
  223. package/dist/modules/session/auto-name.js +63 -0
  224. package/dist/modules/session/export.js +98 -0
  225. package/dist/modules/session/index.js +1 -0
  226. package/dist/modules/session/manager.js +79 -28
  227. package/dist/modules/session/module.js +4 -3
  228. package/dist/modules/session/store.js +57 -20
  229. package/dist/modules/setup/answers.js +35 -0
  230. package/dist/modules/setup/apply.js +79 -0
  231. package/dist/modules/setup/discovery.js +72 -0
  232. package/dist/modules/skills/index.js +1 -0
  233. package/dist/modules/skills/loader.js +9 -1
  234. package/dist/modules/skills/module.js +11 -0
  235. package/dist/modules/updater/changelog-reader.js +15 -16
  236. package/dist/modules/updater/checker.js +9 -4
  237. package/dist/modules/updater/dev-detect.js +7 -6
  238. package/dist/modules/updater/index.js +1 -0
  239. package/dist/modules/updater/module.js +17 -15
  240. package/dist/modules/user-profile/compressor.js +2 -0
  241. package/dist/modules/user-profile/index.js +1 -0
  242. package/dist/modules/user-profile/profile.js +10 -1
  243. package/dist/modules/webui/answer-api.js +29 -0
  244. package/dist/modules/webui/assets.js +50 -0
  245. package/dist/modules/webui/body.js +21 -0
  246. package/dist/modules/webui/commands-settings.js +209 -0
  247. package/dist/modules/webui/commands-shared.js +60 -0
  248. package/dist/modules/webui/commands.js +174 -0
  249. package/dist/modules/webui/config-api.js +134 -0
  250. package/dist/modules/webui/file-api.js +202 -0
  251. package/dist/modules/webui/forward.js +159 -0
  252. package/dist/modules/webui/history-api.js +112 -0
  253. package/dist/modules/webui/host-state.js +60 -0
  254. package/dist/modules/webui/i18n-api.js +9 -0
  255. package/dist/modules/webui/limits.js +6 -0
  256. package/dist/modules/webui/log-forward.js +20 -0
  257. package/dist/modules/webui/memory-commands.js +64 -0
  258. package/dist/modules/webui/model-cache.js +18 -0
  259. package/dist/modules/webui/module.js +148 -0
  260. package/dist/modules/webui/persist.js +24 -0
  261. package/dist/modules/webui/prompt-io.js +97 -0
  262. package/dist/modules/webui/providers-api.js +337 -0
  263. package/dist/modules/webui/providers-view.js +56 -0
  264. package/dist/modules/webui/reasoning-view.js +15 -0
  265. package/dist/modules/webui/run-agent.js +81 -0
  266. package/dist/modules/webui/server.js +284 -0
  267. package/dist/modules/webui/sessions-api.js +178 -0
  268. package/dist/modules/webui/settings-api.js +561 -0
  269. package/dist/modules/webui/setup-api.js +201 -0
  270. package/dist/modules/webui/state.js +74 -0
  271. package/dist/modules/webui/util.js +261 -0
  272. package/dist/output/bus.js +7 -2
  273. package/dist/output/channel.js +80 -28
  274. package/dist/output/format.js +2 -1
  275. package/dist/output/index.js +1 -0
  276. package/dist/output/json-sink.js +5 -3
  277. package/dist/output/machine.js +4 -3
  278. package/dist/output/session-sink.js +4 -4
  279. package/dist/tools/approve.js +4 -0
  280. package/dist/tools/attach-image.js +5 -4
  281. package/dist/tools/auto-fixer.js +26 -44
  282. package/dist/tools/auto-tags.js +83 -0
  283. package/dist/tools/bash.js +193 -116
  284. package/dist/tools/browser.js +76 -31
  285. package/dist/tools/chunk-query.js +14 -6
  286. package/dist/tools/create-dir.js +9 -5
  287. package/dist/tools/delete-file.js +9 -5
  288. package/dist/tools/download-file.js +32 -7
  289. package/dist/tools/edit-file.js +52 -14
  290. package/dist/tools/enable-tools.js +6 -6
  291. package/dist/tools/executor.js +132 -27
  292. package/dist/tools/file-info.js +3 -1
  293. package/dist/tools/filter-tools.js +3 -3
  294. package/dist/tools/glob-tool.js +4 -1
  295. package/dist/tools/grep-tool.js +13 -10
  296. package/dist/tools/hidden-tools-block.js +6 -6
  297. package/dist/tools/index.js +16 -8
  298. package/dist/tools/list-dir.js +4 -2
  299. package/dist/tools/load-skill.js +7 -0
  300. package/dist/tools/mcp-call.js +15 -4
  301. package/dist/tools/meet-done.js +14 -0
  302. package/dist/tools/move-file.js +14 -7
  303. package/dist/tools/path-utils.js +29 -29
  304. package/dist/tools/pipeline-run.js +29 -7
  305. package/dist/tools/preview.js +1 -1
  306. package/dist/tools/process-ids.js +31 -0
  307. package/dist/tools/process-kill.js +9 -16
  308. package/dist/tools/process-list.js +1 -0
  309. package/dist/tools/process-log.js +11 -16
  310. package/dist/tools/process-wait.js +63 -0
  311. package/dist/tools/prompt-io.js +4 -3
  312. package/dist/tools/question.js +172 -25
  313. package/dist/tools/read-file.js +55 -34
  314. package/dist/tools/recall.js +14 -8
  315. package/dist/tools/registry.js +6 -5
  316. package/dist/tools/remember.js +8 -4
  317. package/dist/tools/scope-request.js +11 -6
  318. package/dist/tools/search-history.js +5 -2
  319. package/dist/tools/session-info.js +2 -0
  320. package/dist/tools/set-thinking.js +8 -4
  321. package/dist/tools/subagent.js +59 -39
  322. package/dist/tools/syntax-validator.js +292 -90
  323. package/dist/tools/user-input.js +22 -18
  324. package/dist/tools/web-browse.js +9 -3
  325. package/dist/tools/web-fetch.js +12 -23
  326. package/dist/tools/web-search.js +7 -5
  327. package/dist/tools/write-file.js +45 -15
  328. package/dist/ui/action-log.js +13 -0
  329. package/dist/ui/box.js +4 -3
  330. package/dist/ui/colors.js +2 -0
  331. package/dist/ui/diff.js +6 -5
  332. package/dist/ui/index.js +1 -0
  333. package/dist/ui/line-editor.js +230 -122
  334. package/dist/ui/line-math.js +10 -2
  335. package/dist/ui/md-formatter.js +57 -37
  336. package/dist/ui/output.js +8 -3
  337. package/dist/ui/plan-view.js +21 -10
  338. package/dist/ui/renderer.js +393 -67
  339. package/dist/ui/spinner.js +16 -5
  340. package/dist/ui/table.js +15 -17
  341. package/dist/ui/theme.js +143 -0
  342. package/dist/utils/child-run.js +20 -0
  343. package/dist/utils/error.js +1 -1
  344. package/dist/utils/index.js +2 -0
  345. package/dist/utils/retry.js +2 -2
  346. package/dist/utils/truncate.js +1 -1
  347. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -9386,6 +9386,13 @@ function defaultUserAgent() {
9386
9386
  cachedUserAgent = `micro-models-agent/${readMmaVersion()}`;
9387
9387
  return cachedUserAgent;
9388
9388
  }
9389
+ function normalizeReasoningEffort(level) {
9390
+ if (!level || level === "default" || level === "none")
9391
+ return;
9392
+ if (level === "max")
9393
+ return "high";
9394
+ return level;
9395
+ }
9389
9396
  function buildRequestBody(opts) {
9390
9397
  const body = {
9391
9398
  model: opts.model,
@@ -9403,13 +9410,15 @@ function buildRequestBody(opts) {
9403
9410
  if (opts.stream && opts.streamUsage)
9404
9411
  body.stream_options = { include_usage: true };
9405
9412
  const strategy = opts.reasoningStrategy ?? "openai-effort";
9406
- const level = opts.reasoningEffort;
9407
- if (strategy === "openai-effort" && level && level !== "default") {
9408
- body.reasoning_effort = level;
9413
+ const effort = normalizeReasoningEffort(opts.reasoningEffort);
9414
+ if (strategy === "openai-effort") {
9415
+ if (effort)
9416
+ body.reasoning_effort = effort;
9409
9417
  } else if (strategy === "template-kwarg") {
9410
- body.chat_template_kwargs = { enable_thinking: level !== "none" };
9411
- } else if (strategy === "prompt-tag" && level && level !== "default") {
9412
- body.reasoning_effort = level;
9418
+ body.chat_template_kwargs = { enable_thinking: opts.reasoningEffort !== "none" };
9419
+ } else if (strategy === "prompt-tag") {
9420
+ if (effort)
9421
+ body.reasoning_effort = effort;
9413
9422
  }
9414
9423
  if (opts.tools && opts.tools.length > 0) {
9415
9424
  body.tools = opts.tools.map((t2) => ({
@@ -10281,6 +10290,14 @@ var init_cache = __esm(() => {
10281
10290
  });
10282
10291
 
10283
10292
  // src/modules/providers/manager.ts
10293
+ var exports_manager = {};
10294
+ __export(exports_manager, {
10295
+ reasoningStrategyForProvider: () => reasoningStrategyForProvider,
10296
+ presetOf: () => presetOf,
10297
+ activeProviderEndpoint: () => activeProviderEndpoint,
10298
+ ProviderManager: () => ProviderManager
10299
+ });
10300
+
10284
10301
  class ProviderManager {
10285
10302
  entries;
10286
10303
  lastKnownFallback;
@@ -10420,6 +10437,12 @@ class ProviderManager {
10420
10437
  this.cache.clear();
10421
10438
  }
10422
10439
  }
10440
+ function presetOf(type) {
10441
+ const spec = BUILTIN_PROVIDERS.find((p) => p.type === type);
10442
+ if (!spec)
10443
+ return;
10444
+ return { label: spec.label, baseUrl: spec.baseUrl };
10445
+ }
10423
10446
  function activeProviderEndpoint(config) {
10424
10447
  const entries = Array.isArray(config?.entries) ? config.entries : [];
10425
10448
  const active = entries.find((e) => e.label === config?.active || e.type === config?.active) ?? entries[0];
@@ -10428,6 +10451,10 @@ function activeProviderEndpoint(config) {
10428
10451
  }
10429
10452
  return { baseUrl: config?.baseUrl ?? "", apiKey: config?.apiKey, type: config?.type ?? "openai-compat" };
10430
10453
  }
10454
+ function reasoningStrategyForProvider(config) {
10455
+ const type = activeProviderEndpoint(config).type;
10456
+ return BUILTIN_PROVIDERS.find((p) => p.type === type)?.capabilities.reasoningStrategy ?? "none";
10457
+ }
10431
10458
  var init_manager = __esm(() => {
10432
10459
  init_create();
10433
10460
  init_cache();
@@ -10629,6 +10656,8 @@ function cachePath2() {
10629
10656
  async function probeReasoningSupport(provider, strategy, signal) {
10630
10657
  if (strategy === "none")
10631
10658
  return false;
10659
+ if (strategy === "openai-effort")
10660
+ return true;
10632
10661
  try {
10633
10662
  let hasReasoning = false;
10634
10663
  for await (const chunk of provider.chat(PROBE_MESSAGES, undefined, signal, {
@@ -10775,8 +10804,7 @@ async function setupProviderPhase(config, logger, dir) {
10775
10804
  const builtProvider = buildActiveProvider(config, logger, { getSessionId });
10776
10805
  const providerManager = builtProvider.manager;
10777
10806
  const llmProvider = builtProvider.provider;
10778
- const providerSpec = BUILTIN_PROVIDERS.find((p) => p.type === config.provider.type);
10779
- const reasoningStrategy = providerSpec?.capabilities.reasoningStrategy ?? "none";
10807
+ const reasoningStrategy = reasoningStrategyForProvider(config.provider);
10780
10808
  let reasoningProbePromise = Promise.resolve(false);
10781
10809
  if (config.reasoning && config.reasoning.mode !== "none" && reasoningStrategy !== "none") {
10782
10810
  reasoningProbePromise = (async () => {
@@ -10816,7 +10844,6 @@ var init_provider_phase = __esm(() => {
10816
10844
  init_model_loader();
10817
10845
  init_factory();
10818
10846
  init_manager();
10819
- init_presets();
10820
10847
  init_profile();
10821
10848
  init_i18n();
10822
10849
  });
@@ -20991,6 +21018,55 @@ class ReasoningEffortResolver {
20991
21018
  }
20992
21019
  var init_reasoning_resolver = () => {};
20993
21020
 
21021
+ // src/core/agent/tool-pairing.ts
21022
+ function repairToolCallPairing(messages) {
21023
+ const out = [];
21024
+ let pending = [];
21025
+ const closePending = () => {
21026
+ for (const call of pending) {
21027
+ out.push({
21028
+ role: "tool",
21029
+ name: call.name,
21030
+ content: UNRESOLVED_TOOL_RESULT,
21031
+ tool_call_id: call.id,
21032
+ success: false,
21033
+ blocked: true
21034
+ });
21035
+ }
21036
+ pending = [];
21037
+ };
21038
+ for (const msg of messages) {
21039
+ if (msg.role === "assistant" && msg.tool_calls?.length) {
21040
+ const last = out[out.length - 1];
21041
+ if (last?.role === "assistant" && last.tool_calls?.length) {
21042
+ const merged = {
21043
+ ...last,
21044
+ tool_calls: [...last.tool_calls, ...msg.tool_calls]
21045
+ };
21046
+ out[out.length - 1] = merged;
21047
+ pending = merged.tool_calls.map((tc) => ({ id: tc.id, name: tc.function.name }));
21048
+ continue;
21049
+ }
21050
+ closePending();
21051
+ out.push(msg);
21052
+ pending = msg.tool_calls.map((tc) => ({ id: tc.id, name: tc.function.name }));
21053
+ continue;
21054
+ }
21055
+ if (msg.role === "tool" && msg.tool_call_id) {
21056
+ if (pending.some((c) => c.id === msg.tool_call_id)) {
21057
+ out.push(msg);
21058
+ pending = pending.filter((c) => c.id !== msg.tool_call_id);
21059
+ }
21060
+ continue;
21061
+ }
21062
+ closePending();
21063
+ out.push(msg);
21064
+ }
21065
+ closePending();
21066
+ return out;
21067
+ }
21068
+ var UNRESOLVED_TOOL_RESULT = "[Result unavailable]";
21069
+
20994
21070
  // src/core/agent/context-renderer.ts
20995
21071
  class ContextRenderer {
20996
21072
  lastCompactionShown = 0;
@@ -22927,7 +23003,7 @@ class Agent {
22927
23003
  });
22928
23004
  compactionService.compactIfNeeded(state);
22929
23005
  this.refreshSystemPrompt();
22930
- const history = contextManager.getActiveHistory();
23006
+ const history = repairToolCallPairing(contextManager.getActiveHistory());
22931
23007
  const promptSnapshot = buildPromptSnapshot(history, allToolsForBudget);
22932
23008
  state.prefixDelta = diffPrompt(state.prevPrompt, promptSnapshot, estimateTokens);
22933
23009
  state.prevPrompt = promptSnapshot;
@@ -23351,6 +23427,13 @@ class Agent {
23351
23427
  if (this.deps.configRef)
23352
23428
  this.deps.configRef.current = config;
23353
23429
  this.costTracker.setModel(config.model);
23430
+ this.applyReasoningStrategy(config.provider);
23431
+ }
23432
+ applyReasoningStrategy(provider) {
23433
+ const strategy = reasoningStrategyForProvider(provider);
23434
+ this.deps.reasoningStrategy = strategy;
23435
+ if (strategy === "none")
23436
+ this.probePassed = false;
23354
23437
  }
23355
23438
  setProvider(name, model) {
23356
23439
  const { manager, provider } = buildActiveProvider(this.deps.config, this.deps.logger, {
@@ -23359,6 +23442,7 @@ class Agent {
23359
23442
  manager.switch(name, model);
23360
23443
  const providerCfg = manager.toConfig();
23361
23444
  this.deps.config.provider = providerCfg;
23445
+ this.applyReasoningStrategy(providerCfg);
23362
23446
  this.deps.llmProvider = provider;
23363
23447
  this.deps.getProviderName = () => manager.activeName;
23364
23448
  this.deps.toolExecutor.updateProvider(provider);
@@ -30508,6 +30592,33 @@ class PlanStore {
30508
30592
  activePath() {
30509
30593
  return join44(this.plansDir, "active.json");
30510
30594
  }
30595
+ sessionsDir() {
30596
+ return join44(this.plansDir, "sessions");
30597
+ }
30598
+ sessionActivePath(sessionId) {
30599
+ if (!/^[A-Za-z0-9_-]+$/.test(sessionId)) {
30600
+ throw new Error(`invalid session id: ${sessionId}`);
30601
+ }
30602
+ return join44(this.sessionsDir(), sessionId, "active.json");
30603
+ }
30604
+ saveSessionActive(sessionId, plan) {
30605
+ const p = this.sessionActivePath(sessionId);
30606
+ const dir = join44(this.sessionsDir(), sessionId);
30607
+ if (!existsSync50(dir))
30608
+ mkdirSync24(dir, { recursive: true });
30609
+ writePlanFile(p, plan);
30610
+ }
30611
+ loadSessionActive(sessionId) {
30612
+ const p = this.sessionActivePath(sessionId);
30613
+ if (!existsSync50(p))
30614
+ return null;
30615
+ return readPlanFile(p, this.baseDir);
30616
+ }
30617
+ clearSessionActive(sessionId) {
30618
+ const p = this.sessionActivePath(sessionId);
30619
+ if (existsSync50(p))
30620
+ rmSync3(p, { force: true });
30621
+ }
30511
30622
  saveActive(plan) {
30512
30623
  writePlanFile(this.activePath(), plan);
30513
30624
  }
@@ -31033,7 +31144,7 @@ Last compile error: ${first[1]}`;
31033
31144
  }
31034
31145
  }
31035
31146
  if (result.success && FS_MUTATING_TOOLS.has(call.name)) {
31036
- deps.advancePlanIfStepComplete(ctx.contextManager, ctx.sessionLog);
31147
+ deps.advancePlanIfStepComplete(ctx.sessionLog);
31037
31148
  }
31038
31149
  deps.maybeSearchError(ctx, call);
31039
31150
  }
@@ -31982,6 +32093,7 @@ function planPathToken(p) {
31982
32093
  class ExecutionModule {
31983
32094
  name = "execution";
31984
32095
  tracker = null;
32096
+ sessionId = null;
31985
32097
  verifier;
31986
32098
  stuckDetector;
31987
32099
  auditor;
@@ -32018,9 +32130,20 @@ class ExecutionModule {
32018
32130
  },
32019
32131
  set current(v) {
32020
32132
  self.tracker = v;
32133
+ self.flushSessionPlan();
32021
32134
  }
32022
32135
  };
32023
32136
  })();
32137
+ flushSessionPlan() {
32138
+ if (!this.sessionId)
32139
+ return;
32140
+ try {
32141
+ if (this.tracker)
32142
+ this.store.saveSessionActive(this.sessionId, this.tracker.getPlan());
32143
+ else
32144
+ this.store.clearSessionActive(this.sessionId);
32145
+ } catch {}
32146
+ }
32024
32147
  constructor(baseDir, stuckThreshold = 6, webSearchThreshold = 5, searchRunner = performWebSearch, errorSearchCooldownMs = EXECUTION_ERROR_SEARCH_MIN_INTERVAL_MS) {
32025
32148
  this.baseDir = baseDir;
32026
32149
  this.verifier = new StepVerifier(baseDir);
@@ -32034,9 +32157,69 @@ class ExecutionModule {
32034
32157
  this.tracker = new PlanTracker(plan);
32035
32158
  this.tracker.syncCurrentStep();
32036
32159
  this.store.saveActive(plan);
32160
+ if (this.sessionId) {
32161
+ try {
32162
+ this.store.saveSessionActive(this.sessionId, plan);
32163
+ } catch {}
32164
+ }
32037
32165
  this.completedPlan = null;
32038
32166
  this._auditSkipsRemaining = 0;
32039
32167
  }
32168
+ switchSession(id) {
32169
+ const prev = this.sessionId;
32170
+ if (prev === id)
32171
+ return;
32172
+ if (this.tracker) {
32173
+ try {
32174
+ this.store.saveSessionActive(prev ?? id ?? "", this.tracker.getPlan());
32175
+ } catch {}
32176
+ } else if (prev) {
32177
+ try {
32178
+ this.store.clearSessionActive(prev);
32179
+ } catch {}
32180
+ }
32181
+ this.sessionId = id;
32182
+ this.completedPlan = null;
32183
+ if (!id) {
32184
+ this.tracker = null;
32185
+ this._auditSkipsRemaining = 0;
32186
+ return;
32187
+ }
32188
+ let plan = null;
32189
+ try {
32190
+ plan = this.store.loadSessionActive(id);
32191
+ } catch {
32192
+ plan = null;
32193
+ }
32194
+ if (!plan) {
32195
+ this.tracker = null;
32196
+ this._auditSkipsRemaining = 0;
32197
+ return;
32198
+ }
32199
+ const restored = new PlanTracker(plan);
32200
+ if (restored.isComplete()) {
32201
+ this.store.archivePlan(plan);
32202
+ try {
32203
+ this.store.clearSessionActive(id);
32204
+ } catch {}
32205
+ this.tracker = null;
32206
+ return;
32207
+ }
32208
+ this.tracker = restored;
32209
+ this.tracker.syncCurrentStep();
32210
+ this._auditSkipsRemaining = 1;
32211
+ }
32212
+ forgetSession(id) {
32213
+ try {
32214
+ this.store.clearSessionActive(id);
32215
+ } catch {}
32216
+ if (this.sessionId === id) {
32217
+ this.sessionId = null;
32218
+ this.tracker = null;
32219
+ this.completedPlan = null;
32220
+ this._auditSkipsRemaining = 0;
32221
+ }
32222
+ }
32040
32223
  setHallucinationDetector(detector) {
32041
32224
  this.hallucinationDetector = detector;
32042
32225
  }
@@ -32167,6 +32350,7 @@ class ExecutionModule {
32167
32350
  const done2 = plan2.steps.filter((s) => s.status === "done").length;
32168
32351
  if (autoClosed2 > 0) {
32169
32352
  this.store.saveActive(plan2);
32353
+ this.flushSessionPlan();
32170
32354
  }
32171
32355
  return {
32172
32356
  passed: audit2.passed && pendingSteps2.length === 0,
@@ -32185,6 +32369,7 @@ class ExecutionModule {
32185
32369
  const autoClosed = this.autoCloseEvidenceSteps(plan);
32186
32370
  if (autoClosed > 0) {
32187
32371
  this.store.saveActive(plan);
32372
+ this.flushSessionPlan();
32188
32373
  }
32189
32374
  const audit = await this.auditor.audit(plan);
32190
32375
  const pendingSteps = plan.steps.flatMap((s) => s.status !== "done" && s.status !== "skipped" ? [`${s.id}. ${s.description}`] : []);
@@ -32261,7 +32446,7 @@ class ExecutionModule {
32261
32446
  state: this.state,
32262
32447
  store: this.store,
32263
32448
  checkPlanAlignment: (call) => this.checkPlanAlignment(call),
32264
- advancePlanIfStepComplete: (cm, sl) => this.advancePlanIfStepComplete(cm, sl),
32449
+ advancePlanIfStepComplete: (sl) => this.advancePlanIfStepComplete(sl),
32265
32450
  maybeSearchError: (ctx, call) => this.maybeSearchError(ctx, call)
32266
32451
  });
32267
32452
  }
@@ -32330,7 +32515,7 @@ class ExecutionModule {
32330
32515
  }
32331
32516
  return out;
32332
32517
  }
32333
- advancePlanIfStepComplete(contextManager, sessionLog) {
32518
+ advancePlanIfStepComplete(sessionLog) {
32334
32519
  const step = this.tracker?.getCurrentStep();
32335
32520
  if (!step)
32336
32521
  return;
@@ -32352,19 +32537,17 @@ class ExecutionModule {
32352
32537
  ];
32353
32538
  const hasLockFile = lockFiles.some((f) => existsSync51(resolve22(this.baseDir, f)));
32354
32539
  if (!hasLockFile) {
32355
- if (contextManager) {
32356
- const hints = this.state.depsGateHints.get(step.id) || 0;
32357
- this.state.depsGateHints.set(step.id, hints + 1);
32358
- const force = hints >= 1;
32359
- const content = force ? t("exec.step_gate_deps_force", { step: String(step.id) }) : t("exec.step_gate_deps", {
32360
- step: String(step.id),
32361
- description: step.description
32362
- });
32363
- contextManager.addMessage({
32364
- role: "user",
32365
- content: `<system-summary>${content}</system-summary>`
32366
- });
32367
- }
32540
+ const hints = this.state.depsGateHints.get(step.id) || 0;
32541
+ this.state.depsGateHints.set(step.id, hints + 1);
32542
+ const force = hints >= 1;
32543
+ const content = force ? t("exec.step_gate_deps_force", { step: String(step.id) }) : t("exec.step_gate_deps", {
32544
+ step: String(step.id),
32545
+ description: step.description
32546
+ });
32547
+ this.pendingMessages.push({
32548
+ role: "user",
32549
+ content: `<system-summary>${content}</system-summary>`
32550
+ });
32368
32551
  return;
32369
32552
  }
32370
32553
  }
@@ -32388,8 +32571,8 @@ class ExecutionModule {
32388
32571
  }
32389
32572
  } catch {}
32390
32573
  }
32391
- if (emptyFiles.length > 0 && contextManager) {
32392
- contextManager.addMessage({
32574
+ if (emptyFiles.length > 0) {
32575
+ this.pendingMessages.push({
32393
32576
  role: "user",
32394
32577
  content: `<system-summary>${t("exec.step_gate_empty", { step: String(step.id), files: emptyFiles.join(", ") })}</system-summary>`
32395
32578
  });
@@ -32400,25 +32583,25 @@ class ExecutionModule {
32400
32583
  const hadNext = this.tracker?.advance() ?? false;
32401
32584
  if (this.tracker) {
32402
32585
  this.store.saveActive(this.tracker.getPlan());
32586
+ this.flushSessionPlan();
32403
32587
  sessionLog?.plan("auto-advance", `Step ${step.id} auto-completed | ${this.tracker.getProgressString()} | current: step ${this.tracker.getCurrentStepIndex() + 1}`);
32404
32588
  }
32405
- if (contextManager) {
32406
- const nextStep = hadNext ? this.tracker?.getCurrentStep() : null;
32407
- const nextMsg = nextStep ? t("exec.step_gate_ok", {
32408
- step: String(step.id),
32409
- nextStep: String(nextStep.id),
32410
- nextDesc: nextStep.description
32411
- }) : t("exec.step_gate_last", { step: String(step.id) });
32412
- contextManager.addMessage({
32413
- role: "user",
32414
- content: `<system-summary>${nextMsg}</system-summary>`
32415
- });
32416
- }
32589
+ const nextStep = hadNext ? this.tracker?.getCurrentStep() : null;
32590
+ const nextMsg = nextStep ? t("exec.step_gate_ok", {
32591
+ step: String(step.id),
32592
+ nextStep: String(nextStep.id),
32593
+ nextDesc: nextStep.description
32594
+ }) : t("exec.step_gate_last", { step: String(step.id) });
32595
+ this.pendingMessages.push({
32596
+ role: "user",
32597
+ content: `<system-summary>${nextMsg}</system-summary>`
32598
+ });
32417
32599
  if (this.tracker?.isComplete()) {
32418
32600
  const completed = this.tracker.getPlan();
32419
32601
  this.store.archivePlan(completed);
32420
32602
  this.recordCompleted(completed);
32421
32603
  this.tracker = null;
32604
+ this.flushSessionPlan();
32422
32605
  sessionLog?.plan("auto-archive", `Plan ${completed.id} complete — archived`);
32423
32606
  }
32424
32607
  }
@@ -33777,6 +33960,9 @@ async function registerCoreModules(input, moduleRegistry) {
33777
33960
  const { config, logger: logger5, dir, baseDir, hallucinationDetector } = input;
33778
33961
  const execModule = new ExecutionModule(baseDir, config.stuckThreshold, config.errorWebSearch?.threshold ?? 5);
33779
33962
  execModule.restorePlan();
33963
+ try {
33964
+ execModule.switchSession(input.sessionManager.getActive());
33965
+ } catch {}
33780
33966
  moduleRegistry.register(execModule);
33781
33967
  execModule.setHallucinationDetector(hallucinationDetector);
33782
33968
  const sessionModule = new SessionModule(input.sessionManager);
@@ -35914,6 +36100,14 @@ function getConfigValue(config, name) {
35914
36100
  const value = def.get(config);
35915
36101
  return { ok: true, key: def.key, def, value, display: formatConfigValue(value) };
35916
36102
  }
36103
+ function mirrorActiveEntryFields(provider, activeName) {
36104
+ const entry = (provider.entries ?? []).find((e) => e.label === activeName || e.type === activeName);
36105
+ if (!entry)
36106
+ return;
36107
+ provider.type = entry.type;
36108
+ provider.baseUrl = entry.baseUrl;
36109
+ provider.apiKey = entry.apiKey;
36110
+ }
35917
36111
  function applyProviderModelMemory(config, key, value) {
35918
36112
  const provider = config.provider;
35919
36113
  const activeName = provider.active ?? provider.type;
@@ -35927,6 +36121,7 @@ function applyProviderModelMemory(config, key, value) {
35927
36121
  const remembered = provider.models?.[String(value)];
35928
36122
  if (remembered)
35929
36123
  config.model = remembered;
36124
+ mirrorActiveEntryFields(provider, String(value));
35930
36125
  }
35931
36126
  }
35932
36127
  function setConfigValue(config, name, raw) {
@@ -45457,8 +45652,9 @@ function registerProviderCommands(ctx) {
45457
45652
  const list2 = () => {
45458
45653
  const providers = ctx.agent.listProviders();
45459
45654
  if (providers.length === 0) {
45460
- ctx.output.writeLine(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
45461
- ctx.output.writeLine(` ${ctx.config.provider.baseUrl}`);
45655
+ const endpoint = activeProviderEndpoint(ctx.config.provider);
45656
+ ctx.output.writeLine(`${t("repl.provider_current")} ${endpoint.type}`);
45657
+ ctx.output.writeLine(` ${endpoint.baseUrl}`);
45462
45658
  return;
45463
45659
  }
45464
45660
  ctx.output.writeLine(t("repl.provider_current"));
@@ -45720,7 +45916,8 @@ function registerAgentCommands(ctx) {
45720
45916
  ctx.output.writeLine(pc.green(t("repl.reloaded")));
45721
45917
  ctx.output.writeLine(`${t("repl.model")} ${ctx.config.model}`);
45722
45918
  ctx.output.writeLine(`${t("repl.context")} ${ctx.config.contextWindow}`);
45723
- ctx.output.writeLine(`${t("repl.provider")} ${ctx.config.provider.type} @ ${ctx.config.provider.baseUrl}`);
45919
+ const endpoint = activeProviderEndpoint(ctx.config.provider);
45920
+ ctx.output.writeLine(`${t("repl.provider")} ${endpoint.type} @ ${endpoint.baseUrl}`);
45724
45921
  }
45725
45922
  });
45726
45923
  ctx.registerCommand({
@@ -45826,6 +46023,10 @@ function registerSessionCommands(ctx) {
45826
46023
  const name = args.join(" ") || undefined;
45827
46024
  const meta = ctx.sessionManager.create(name);
45828
46025
  ctx.agent.clearContext();
46026
+ const exec = ctx.agent.getModule("execution");
46027
+ try {
46028
+ exec?.switchSession(meta.id);
46029
+ } catch {}
45829
46030
  ctx.output.clearScreen();
45830
46031
  ctx.output.writeLine(`${t("session.created", { name: meta.name })} (${pc.dim(meta.id.slice(0, 12))})`);
45831
46032
  ctx.output.writeLine(pc.dim(` ${t("session.chat_cleared")}
@@ -45860,6 +46061,12 @@ function registerSessionCommands(ctx) {
45860
46061
  ctx.sessionManager.setActive(match.id);
45861
46062
  const history = ctx.sessionManager.loadHistory();
45862
46063
  ctx.agent.setContext(history);
46064
+ const exec = ctx.agent.getModule("execution");
46065
+ let planLine = null;
46066
+ try {
46067
+ exec?.switchSession(match.id);
46068
+ planLine = exec?.getPlanSummary() ?? null;
46069
+ } catch {}
45863
46070
  ctx.output.clearScreen();
45864
46071
  ctx.output.writeLine(pc.bold(pc.green(t("session.resumed", { name: match.name }))) + " " + pc.dim(`(${match.id.slice(0, 12)})`) + " — " + match.messageCount + " " + t("repl.msgs"));
45865
46072
  ctx.output.writeLine(pc.dim("─".repeat(50)));
@@ -45882,6 +46089,7 @@ function registerSessionCommands(ctx) {
45882
46089
  }
45883
46090
  ctx.output.writeLine(pc.dim("─".repeat(50)));
45884
46091
  ctx.output.writeLine(pc.dim(` ${t("session.chat_loaded")}`));
46092
+ ctx.output.writeLine(pc.dim(` ◇ ${planLine ?? t("plan.no_active")}`));
45885
46093
  }
45886
46094
  });
45887
46095
  ctx.registerCommand({
@@ -45921,6 +46129,9 @@ function registerSessionCommands(ctx) {
45921
46129
  return;
45922
46130
  }
45923
46131
  ctx.sessionManager.delete(match.id);
46132
+ try {
46133
+ ctx.agent.getModule("execution")?.forgetSession(match.id);
46134
+ } catch {}
45924
46135
  ctx.output.writeLine(`${t("session.deleted", { id: match.id })}: ${match.name}`);
45925
46136
  }
45926
46137
  });
@@ -46031,6 +46242,7 @@ var init_repl_commands = __esm(() => {
46031
46242
  init_setup_order();
46032
46243
  init_config2();
46033
46244
  init_presets();
46245
+ init_manager();
46034
46246
  init_budget();
46035
46247
  init_registry2();
46036
46248
  init_export();
@@ -47083,10 +47295,12 @@ function buildModelCommands(program2) {
47083
47295
  const { config } = await bootstrap();
47084
47296
  getDefaultChannel().writeLine(`${t("cli.current_model")} ${config.model}`);
47085
47297
  const { createProvider: createProvider2 } = await Promise.resolve().then(() => (init_create(), exports_create));
47086
- const provider = createProvider2(config.provider.type, {
47298
+ const { activeProviderEndpoint: activeProviderEndpoint2 } = await Promise.resolve().then(() => (init_manager(), exports_manager));
47299
+ const endpoint = activeProviderEndpoint2(config.provider);
47300
+ const provider = createProvider2(endpoint.type, {
47087
47301
  model: config.model,
47088
- baseUrl: config.provider.baseUrl,
47089
- apiKey: config.provider.apiKey,
47302
+ baseUrl: endpoint.baseUrl,
47303
+ apiKey: endpoint.apiKey,
47090
47304
  contextWindow: config.contextWindow
47091
47305
  });
47092
47306
  const spinner = (await Promise.resolve().then(() => (init_spinner(), exports_spinner))).Spinner;
@@ -49692,6 +49906,7 @@ function adaptActivePlan(plan) {
49692
49906
  // src/cli/repl.ts
49693
49907
  init_repl_commands();
49694
49908
  init_registry2();
49909
+ init_manager();
49695
49910
 
49696
49911
  // src/modules/lsp/probe.ts
49697
49912
  init_client3();
@@ -50692,7 +50907,8 @@ ${divider()}`);
50692
50907
  const resBudget = Math.floor(ctx * this.config.contextBudget.responseReserve);
50693
50908
  const histBudget = ctx - sysBudget - resBudget;
50694
50909
  row(t("repl.model"), pc.white(this.config.model));
50695
- row(t("repl.provider"), `${this.config.provider.type} → ${pc.dim(this.config.provider.baseUrl)}`);
50910
+ const endpoint = activeProviderEndpoint(this.config.provider);
50911
+ row(t("repl.provider"), `${endpoint.type} → ${pc.dim(endpoint.baseUrl)}`);
50696
50912
  row(t("repl.context"), `${pc.white(String(ctx))} ${pc.dim(`(sys:${sysBudget} res:${resBudget} hist:${histBudget})`)}`);
50697
50913
  const si = this.agent.getSystemPromptInfo();
50698
50914
  row(t("repl.sysprompt_label"), pc.dim(t("repl.sysprompt_size", { used: si.tokenCount, budget: sysBudget })));
@@ -52290,6 +52506,9 @@ function handleSessionCreate(req, res, s) {
52290
52506
  }
52291
52507
  try {
52292
52508
  const meta = create(name);
52509
+ try {
52510
+ s.execModule?.switchSession(meta.id);
52511
+ } catch {}
52293
52512
  sendJson(res, 201, {
52294
52513
  ok: true,
52295
52514
  session: {
@@ -52330,6 +52549,9 @@ function handleSessionActivate(req, res, s) {
52330
52549
  sendJson(res, 404, { error: "not_found" });
52331
52550
  return;
52332
52551
  }
52552
+ try {
52553
+ s.execModule?.switchSession(id);
52554
+ } catch {}
52333
52555
  sendJson(res, 200, { ok: true });
52334
52556
  }).catch((err) => {
52335
52557
  readBodyError(req, res, err);
@@ -52354,6 +52576,9 @@ function handleSessionDelete(res, id, s) {
52354
52576
  sendJson(res, 404, { error: "not_found" });
52355
52577
  return;
52356
52578
  }
52579
+ try {
52580
+ s.execModule?.forgetSession(id);
52581
+ } catch {}
52357
52582
  sendJson(res, 200, { ok: true });
52358
52583
  }
52359
52584
  function handleSessionsApi(req, res, reqUrl, s) {
@@ -53947,6 +54172,7 @@ async function startWebUi(deps) {
53947
54172
  state.setup = buildSetupDisplay();
53948
54173
  state.config = deps.config;
53949
54174
  state.sessionManager = deps.sessionManager;
54175
+ state.execModule = deps.execModule;
53950
54176
  state.memory = deps.memory;
53951
54177
  state.skills = deps.skills;
53952
54178
  state.plugins = deps.plugins;
@@ -1,11 +1,15 @@
1
+ // Бэкапы перед миграцией: config.json.bak и копия всего configDir.
1
2
  import { copyFileSync, cpSync, existsSync, mkdirSync, readdirSync, writeFileSync } from "fs";
2
3
  import { join } from "path";
3
4
  import { t } from "../i18n/index";
5
+ import { defaultOutputBus } from "../output";
6
+ /** Делает бэкапы конфига перед миграцией v1 → v2. */
4
7
  export class BackupManager {
5
8
  configDir;
6
9
  constructor(configDir) {
7
10
  this.configDir = configDir;
8
11
  }
12
+ /** Копия config.json в config.json.bak. Нет файла — ничего не делает. */
9
13
  backupConfig() {
10
14
  const configPath = join(this.configDir, "config.json");
11
15
  if (!existsSync(configPath))
@@ -13,24 +17,31 @@ export class BackupManager {
13
17
  const bakPath = join(this.configDir, "config.json.bak");
14
18
  copyFileSync(configPath, bakPath);
15
19
  }
20
+ /** Рекурсивная копия всего configDir в `<dir>.bak` (один раз, не перезаписывает). */
16
21
  backupAll() {
17
- const bakDir = this.configDir + ".bak";
18
- if (existsSync(bakDir))
22
+ const bakDir = `${this.configDir}.bak`;
23
+ if (existsSync(bakDir)) {
24
+ // Повторная миграция не перезаписывает бэкап — фиксируем в логе, чтобы
25
+ // «нет бэкапа за этот запуск» не выглядело как потеря данных.
26
+ defaultOutputBus.log("debug", "migration", `Backup already exists at ${bakDir}; keeping the previous state (not overwritten).`);
19
27
  return;
28
+ }
20
29
  if (existsSync(this.configDir)) {
21
30
  cpSync(this.configDir, bakDir, { recursive: true });
22
31
  }
23
32
  }
33
+ /** Пишет свежий конфиг v2 в config.json (создаёт каталог при нужде). */
24
34
  writeFreshConfig(config) {
25
35
  if (!existsSync(this.configDir)) {
26
36
  mkdirSync(this.configDir, { recursive: true });
27
37
  }
28
38
  writeFileSync(join(this.configDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
29
39
  }
40
+ /** Человекочитаемая сводка: какие бэкапы есть, или что миграция не нужна. */
30
41
  getBackupSummary() {
31
42
  const lines = [];
32
43
  const bakConfig = join(this.configDir, "config.json.bak");
33
- const bakDir = this.configDir + ".bak";
44
+ const bakDir = `${this.configDir}.bak`;
34
45
  if (existsSync(bakConfig)) {
35
46
  lines.push(t("migration.config_bak"));
36
47
  }