micro-models-agent 2.16.1 → 2.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (427) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/assets/app.js +1 -314
  3. package/dist/assets/hljs.js +5 -1244
  4. package/dist/assets/index.html +11 -0
  5. package/dist/assets/js/api.js +1 -28
  6. package/dist/assets/js/core/menus.js +1 -0
  7. package/dist/assets/js/core/store/feed.js +1 -0
  8. package/dist/assets/js/core/store/index.js +1 -0
  9. package/dist/assets/js/core/store/session.js +1 -0
  10. package/dist/assets/js/core/store/settings.js +1 -0
  11. package/dist/assets/js/core/store/tabs.js +1 -0
  12. package/dist/assets/js/dialog.js +1 -105
  13. package/dist/assets/js/dom.js +1 -178
  14. package/dist/assets/js/feed/core.js +1 -0
  15. package/dist/assets/js/feed/history.js +1 -0
  16. package/dist/assets/js/feed/plan.js +1 -0
  17. package/dist/assets/js/feed/question.js +3 -0
  18. package/dist/assets/js/feed/sidebar.js +1 -0
  19. package/dist/assets/js/feed/stream.js +1 -0
  20. package/dist/assets/js/feed/turn.js +5 -0
  21. package/dist/assets/js/feed.js +1 -1250
  22. package/dist/assets/js/format.js +2 -122
  23. package/dist/assets/js/i18n.js +1 -46
  24. package/dist/assets/js/rail.js +1 -114
  25. package/dist/assets/js/session/cmdk.js +1 -0
  26. package/dist/assets/js/session/composer.js +1 -0
  27. package/dist/assets/js/session/sessions-menu.js +1 -0
  28. package/dist/assets/js/session/tabs.js +1 -0
  29. package/dist/assets/js/settings/controls.js +1 -0
  30. package/dist/assets/js/settings/editors.js +1 -0
  31. package/dist/assets/js/settings/form.js +1 -0
  32. package/dist/assets/js/settings/modal.js +1 -0
  33. package/dist/assets/js/settings/panels.js +1 -0
  34. package/dist/assets/js/settings/providers.js +1 -0
  35. package/dist/assets/js/settings/search.js +1 -0
  36. package/dist/assets/js/settings/subdialog.js +1 -0
  37. package/dist/assets/js/settings/write.js +1 -0
  38. package/dist/assets/js/settings.js +1 -1914
  39. package/dist/assets/js/sidebar/core.js +1 -0
  40. package/dist/assets/js/sidebar/lsp.js +2 -0
  41. package/dist/assets/js/sidebar/map.js +1 -0
  42. package/dist/assets/js/sidebar/state.js +1 -0
  43. package/dist/assets/js/sidebar/trace.js +5 -0
  44. package/dist/assets/js/sidebar.js +1 -705
  45. package/dist/assets/js/store.js +1 -82
  46. package/dist/assets/js/subdialog.js +1 -0
  47. package/dist/assets/md.js +1 -291
  48. package/dist/assets/setup.js +3 -816
  49. package/dist/assets/smd.js +29 -1665
  50. package/dist/assets/styles.css +1 -1598
  51. package/dist/certification/certifications.json +1 -494
  52. package/dist/i18n/en.json +1 -1851
  53. package/dist/i18n/ru.json +1 -1854
  54. package/dist/main.js +815 -55797
  55. package/dist/modules/browser/bridge-server.mjs +2 -252
  56. package/package.json +10 -5
  57. package/dist/assets/js/settings-controls.js +0 -452
  58. package/dist/assets/js/tabs.js +0 -867
  59. package/dist/cli/cache-line.js +0 -31
  60. package/dist/cli/command-suggest.js +0 -39
  61. package/dist/cli/commands.js +0 -781
  62. package/dist/cli/completer.js +0 -268
  63. package/dist/cli/index.js +0 -3
  64. package/dist/cli/json-payload.js +0 -32
  65. package/dist/cli/main.js +0 -346
  66. package/dist/cli/onboarding-commands.js +0 -126
  67. package/dist/cli/plugin-commands.js +0 -38
  68. package/dist/cli/relaunch.js +0 -40
  69. package/dist/cli/repl-commands-lsp.js +0 -75
  70. package/dist/cli/repl-commands-skills.js +0 -105
  71. package/dist/cli/repl-commands.js +0 -1218
  72. package/dist/cli/repl.js +0 -1238
  73. package/dist/cli/run-result.js +0 -38
  74. package/dist/cli/security-commands.js +0 -177
  75. package/dist/cli/setup-order.js +0 -6
  76. package/dist/cli/setup-prompt.js +0 -50
  77. package/dist/cli/setup.js +0 -161
  78. package/dist/cli/web-command.js +0 -98
  79. package/dist/config/budget.js +0 -48
  80. package/dist/config/config.js +0 -345
  81. package/dist/config/defaults.js +0 -197
  82. package/dist/config/domains.js +0 -135
  83. package/dist/config/env.js +0 -46
  84. package/dist/config/experts.js +0 -17
  85. package/dist/config/index.js +0 -5
  86. package/dist/config/paths.js +0 -56
  87. package/dist/config/redact.js +0 -44
  88. package/dist/config/registry-extra.js +0 -334
  89. package/dist/config/registry.js +0 -584
  90. package/dist/config/security.js +0 -212
  91. package/dist/config/timeouts.js +0 -74
  92. package/dist/config/types.js +0 -1
  93. package/dist/config/utils.js +0 -57
  94. package/dist/core/agent/artifact-progress.js +0 -59
  95. package/dist/core/agent/artifact-resolve.js +0 -79
  96. package/dist/core/agent/audit-gate.js +0 -53
  97. package/dist/core/agent/compaction.js +0 -89
  98. package/dist/core/agent/constants.js +0 -90
  99. package/dist/core/agent/context-log.js +0 -454
  100. package/dist/core/agent/context-renderer.js +0 -45
  101. package/dist/core/agent/critic-gate.js +0 -132
  102. package/dist/core/agent/hallucination-gate.js +0 -197
  103. package/dist/core/agent/loop-state.js +0 -68
  104. package/dist/core/agent/prefix-monitor.js +0 -101
  105. package/dist/core/agent/reasoning-resolver.js +0 -65
  106. package/dist/core/agent/token-tracker.js +0 -99
  107. package/dist/core/agent/tool-batch.js +0 -312
  108. package/dist/core/agent/tool-images.js +0 -18
  109. package/dist/core/agent/tool-output.js +0 -116
  110. package/dist/core/agent/tool-pairing.js +0 -60
  111. package/dist/core/agent-moe.js +0 -248
  112. package/dist/core/agent.js +0 -1299
  113. package/dist/core/bootstrap/agent-phase.js +0 -66
  114. package/dist/core/bootstrap/config-phase.js +0 -86
  115. package/dist/core/bootstrap/modules-phase.js +0 -269
  116. package/dist/core/bootstrap/provider-phase.js +0 -183
  117. package/dist/core/bootstrap/session-phase.js +0 -204
  118. package/dist/core/bootstrap/state.js +0 -94
  119. package/dist/core/bootstrap/workspace-phase.js +0 -115
  120. package/dist/core/bootstrap.js +0 -112
  121. package/dist/core/crash-handler.js +0 -62
  122. package/dist/core/environment.js +0 -224
  123. package/dist/core/host-plan.js +0 -43
  124. package/dist/core/host.js +0 -23
  125. package/dist/core/index.js +0 -3
  126. package/dist/core/prompt-builder.js +0 -95
  127. package/dist/core/prompt-overflow.js +0 -306
  128. package/dist/core/session-logger.js +0 -375
  129. package/dist/core/system-prompt.js +0 -117
  130. package/dist/core/types.js +0 -1
  131. package/dist/core/version.js +0 -28
  132. package/dist/core/web-host.js +0 -34
  133. package/dist/core/workspace.js +0 -80
  134. package/dist/i18n/index.js +0 -80
  135. package/dist/index.js +0 -30
  136. package/dist/llm/cache-usage.js +0 -76
  137. package/dist/llm/image-utils.js +0 -138
  138. package/dist/llm/index.js +0 -4
  139. package/dist/llm/llm-errors.js +0 -50
  140. package/dist/llm/model-loader.js +0 -86
  141. package/dist/llm/models-dev.js +0 -121
  142. package/dist/llm/openai-compat.js +0 -756
  143. package/dist/llm/orchestrator.js +0 -294
  144. package/dist/llm/provider-budget.js +0 -68
  145. package/dist/llm/provider-context.js +0 -233
  146. package/dist/llm/provider.js +0 -9
  147. package/dist/llm/response.js +0 -44
  148. package/dist/llm/stream-state.js +0 -26
  149. package/dist/llm/token-counter.js +0 -83
  150. package/dist/llm/types.js +0 -1
  151. package/dist/logger/app-logger.js +0 -212
  152. package/dist/logger/file-log.js +0 -160
  153. package/dist/logger/index.js +0 -2
  154. package/dist/migration/backup.js +0 -56
  155. package/dist/migration/detect.js +0 -61
  156. package/dist/migration/index.js +0 -3
  157. package/dist/modules/artifacts/store.js +0 -62
  158. package/dist/modules/browser/actions.js +0 -79
  159. package/dist/modules/browser/bridge-client.js +0 -203
  160. package/dist/modules/browser/bridge-path.js +0 -10
  161. package/dist/modules/browser/console-buffer.js +0 -37
  162. package/dist/modules/browser/cookie-store.js +0 -29
  163. package/dist/modules/browser/driver-types.js +0 -1
  164. package/dist/modules/browser/driver.js +0 -186
  165. package/dist/modules/browser/index.js +0 -9
  166. package/dist/modules/browser/module.js +0 -30
  167. package/dist/modules/browser/session.js +0 -322
  168. package/dist/modules/browser/snapshot.js +0 -154
  169. package/dist/modules/browser/types.js +0 -13
  170. package/dist/modules/certification/cli.js +0 -264
  171. package/dist/modules/certification/fact-checker.js +0 -90
  172. package/dist/modules/certification/loader.js +0 -127
  173. package/dist/modules/certification/manifest.js +0 -231
  174. package/dist/modules/certification/runner.js +0 -233
  175. package/dist/modules/certification/scenarios.js +0 -586
  176. package/dist/modules/certification/syntax-scenarios.js +0 -50
  177. package/dist/modules/certification/types.js +0 -1
  178. package/dist/modules/context/chunk-query.js +0 -122
  179. package/dist/modules/context/fact-extractor.js +0 -170
  180. package/dist/modules/context/history.js +0 -15
  181. package/dist/modules/context/index.js +0 -2
  182. package/dist/modules/context/manager.js +0 -482
  183. package/dist/modules/critic/client.js +0 -176
  184. package/dist/modules/critic/evidence.js +0 -81
  185. package/dist/modules/critic/provider.js +0 -45
  186. package/dist/modules/critic/tools.js +0 -78
  187. package/dist/modules/critic/types.js +0 -1
  188. package/dist/modules/execution/audit-runners.js +0 -206
  189. package/dist/modules/execution/auditor.js +0 -222
  190. package/dist/modules/execution/execution-plugin.js +0 -478
  191. package/dist/modules/execution/index.js +0 -8
  192. package/dist/modules/execution/input-from.js +0 -70
  193. package/dist/modules/execution/module.js +0 -891
  194. package/dist/modules/execution/moe-executor.js +0 -443
  195. package/dist/modules/execution/plan-actions.js +0 -642
  196. package/dist/modules/execution/plan-checks.js +0 -35
  197. package/dist/modules/execution/plan-coverage.js +0 -71
  198. package/dist/modules/execution/plan-persister.js +0 -46
  199. package/dist/modules/execution/plan-steps.js +0 -31
  200. package/dist/modules/execution/plan-store.js +0 -274
  201. package/dist/modules/execution/plan-tool.js +0 -249
  202. package/dist/modules/execution/plan-validator.js +0 -197
  203. package/dist/modules/execution/planner.js +0 -103
  204. package/dist/modules/execution/stuck-detector.js +0 -834
  205. package/dist/modules/execution/tracker.js +0 -92
  206. package/dist/modules/execution/transient-error.js +0 -30
  207. package/dist/modules/execution/types.js +0 -1
  208. package/dist/modules/execution/verifier.js +0 -343
  209. package/dist/modules/execution/windows-commands.js +0 -52
  210. package/dist/modules/hallucination/artifact-claim.js +0 -93
  211. package/dist/modules/hallucination/confidence.js +0 -81
  212. package/dist/modules/hallucination/consistency.js +0 -37
  213. package/dist/modules/hallucination/detector.js +0 -57
  214. package/dist/modules/hallucination/factual.js +0 -205
  215. package/dist/modules/hallucination/index.js +0 -6
  216. package/dist/modules/hallucination/js-identifiers.js +0 -261
  217. package/dist/modules/hallucination/llm-judge.js +0 -116
  218. package/dist/modules/hallucination/success-claim.js +0 -59
  219. package/dist/modules/index.js +0 -5
  220. package/dist/modules/indexer/cache.js +0 -88
  221. package/dist/modules/indexer/index.js +0 -4
  222. package/dist/modules/indexer/map-command.js +0 -33
  223. package/dist/modules/indexer/map-select.js +0 -87
  224. package/dist/modules/indexer/module.js +0 -293
  225. package/dist/modules/indexer/project-profile.js +0 -184
  226. package/dist/modules/indexer/symbols.js +0 -189
  227. package/dist/modules/indexer/walker.js +0 -285
  228. package/dist/modules/lsp/check-tool.js +0 -61
  229. package/dist/modules/lsp/client.js +0 -406
  230. package/dist/modules/lsp/command.js +0 -53
  231. package/dist/modules/lsp/config.js +0 -189
  232. package/dist/modules/lsp/index.js +0 -4
  233. package/dist/modules/lsp/module.js +0 -295
  234. package/dist/modules/lsp/probe.js +0 -86
  235. package/dist/modules/lsp/project-root.js +0 -69
  236. package/dist/modules/lsp/startup-check.js +0 -154
  237. package/dist/modules/lsp/types.js +0 -1
  238. package/dist/modules/mcp/client.js +0 -445
  239. package/dist/modules/mcp/index.js +0 -4
  240. package/dist/modules/mcp/module.js +0 -295
  241. package/dist/modules/mcp/registry.js +0 -20
  242. package/dist/modules/memory/index.js +0 -2
  243. package/dist/modules/memory/module.js +0 -101
  244. package/dist/modules/memory/search.js +0 -45
  245. package/dist/modules/memory/store.js +0 -107
  246. package/dist/modules/onboarding/init.js +0 -47
  247. package/dist/modules/onboarding/meet.js +0 -30
  248. package/dist/modules/onboarding/mode.js +0 -30
  249. package/dist/modules/onboarding/prompts.js +0 -43
  250. package/dist/modules/pipelines/engine.js +0 -70
  251. package/dist/modules/pipelines/index.js +0 -4
  252. package/dist/modules/pipelines/parser.js +0 -59
  253. package/dist/modules/pipelines/template.js +0 -18
  254. package/dist/modules/plugins/builtin/lint-on-write.js +0 -377
  255. package/dist/modules/plugins/builtin/notify.js +0 -11
  256. package/dist/modules/plugins/index.js +0 -2
  257. package/dist/modules/plugins/loader.js +0 -85
  258. package/dist/modules/plugins/manager.js +0 -244
  259. package/dist/modules/plugins/types.js +0 -1
  260. package/dist/modules/pricing/index.js +0 -70
  261. package/dist/modules/pricing/prices.js +0 -147
  262. package/dist/modules/processes/detect.js +0 -34
  263. package/dist/modules/processes/index.js +0 -4
  264. package/dist/modules/processes/kill-tree.js +0 -52
  265. package/dist/modules/processes/registry.js +0 -294
  266. package/dist/modules/processes/runner.js +0 -23
  267. package/dist/modules/providers/cache.js +0 -23
  268. package/dist/modules/providers/capabilities.js +0 -28
  269. package/dist/modules/providers/create.js +0 -21
  270. package/dist/modules/providers/factory.js +0 -28
  271. package/dist/modules/providers/fallback.js +0 -81
  272. package/dist/modules/providers/health.js +0 -47
  273. package/dist/modules/providers/index.js +0 -6
  274. package/dist/modules/providers/manager.js +0 -207
  275. package/dist/modules/providers/naming.js +0 -15
  276. package/dist/modules/providers/preflight.js +0 -71
  277. package/dist/modules/providers/presets.js +0 -232
  278. package/dist/modules/providers/registry.js +0 -27
  279. package/dist/modules/providers/types.js +0 -1
  280. package/dist/modules/reasoning/policy.js +0 -42
  281. package/dist/modules/reasoning/probe.js +0 -116
  282. package/dist/modules/registry.js +0 -48
  283. package/dist/modules/security/audit-log.js +0 -119
  284. package/dist/modules/security/audit-notifier.js +0 -267
  285. package/dist/modules/security/command-validator.js +0 -272
  286. package/dist/modules/security/content-scanner.js +0 -53
  287. package/dist/modules/security/data-sanitizer.js +0 -82
  288. package/dist/modules/security/encryption.js +0 -216
  289. package/dist/modules/security/index.js +0 -15
  290. package/dist/modules/security/network-validator.js +0 -236
  291. package/dist/modules/security/path-validator.js +0 -261
  292. package/dist/modules/security/protected-paths.js +0 -73
  293. package/dist/modules/security/rate-limiter.js +0 -98
  294. package/dist/modules/security/security-policies.js +0 -499
  295. package/dist/modules/security/session-encryption.js +0 -182
  296. package/dist/modules/security/session-isolation.js +0 -75
  297. package/dist/modules/session/auto-name.js +0 -63
  298. package/dist/modules/session/export.js +0 -98
  299. package/dist/modules/session/index.js +0 -4
  300. package/dist/modules/session/manager.js +0 -234
  301. package/dist/modules/session/module.js +0 -33
  302. package/dist/modules/session/store.js +0 -295
  303. package/dist/modules/session/types.js +0 -1
  304. package/dist/modules/setup/answers.js +0 -35
  305. package/dist/modules/setup/apply.js +0 -79
  306. package/dist/modules/setup/discovery.js +0 -72
  307. package/dist/modules/skills/index.js +0 -3
  308. package/dist/modules/skills/loader.js +0 -86
  309. package/dist/modules/skills/matcher.js +0 -27
  310. package/dist/modules/skills/module.js +0 -141
  311. package/dist/modules/types.js +0 -1
  312. package/dist/modules/updater/changelog-reader.js +0 -93
  313. package/dist/modules/updater/checker.js +0 -101
  314. package/dist/modules/updater/dev-detect.js +0 -18
  315. package/dist/modules/updater/index.js +0 -4
  316. package/dist/modules/updater/module.js +0 -129
  317. package/dist/modules/user-profile/compressor.js +0 -18
  318. package/dist/modules/user-profile/index.js +0 -2
  319. package/dist/modules/user-profile/profile.js +0 -77
  320. package/dist/modules/webui/answer-api.js +0 -29
  321. package/dist/modules/webui/assets.js +0 -50
  322. package/dist/modules/webui/body.js +0 -21
  323. package/dist/modules/webui/commands-settings.js +0 -209
  324. package/dist/modules/webui/commands-shared.js +0 -60
  325. package/dist/modules/webui/commands.js +0 -174
  326. package/dist/modules/webui/config-api.js +0 -134
  327. package/dist/modules/webui/file-api.js +0 -202
  328. package/dist/modules/webui/forward.js +0 -159
  329. package/dist/modules/webui/history-api.js +0 -112
  330. package/dist/modules/webui/host-state.js +0 -60
  331. package/dist/modules/webui/i18n-api.js +0 -9
  332. package/dist/modules/webui/limits.js +0 -6
  333. package/dist/modules/webui/log-forward.js +0 -20
  334. package/dist/modules/webui/memory-commands.js +0 -64
  335. package/dist/modules/webui/model-cache.js +0 -18
  336. package/dist/modules/webui/module.js +0 -148
  337. package/dist/modules/webui/persist.js +0 -24
  338. package/dist/modules/webui/prompt-io.js +0 -97
  339. package/dist/modules/webui/providers-api.js +0 -337
  340. package/dist/modules/webui/providers-view.js +0 -56
  341. package/dist/modules/webui/reasoning-view.js +0 -15
  342. package/dist/modules/webui/run-agent.js +0 -81
  343. package/dist/modules/webui/server.js +0 -284
  344. package/dist/modules/webui/sessions-api.js +0 -178
  345. package/dist/modules/webui/settings-api.js +0 -561
  346. package/dist/modules/webui/setup-api.js +0 -201
  347. package/dist/modules/webui/state.js +0 -74
  348. package/dist/modules/webui/util.js +0 -261
  349. package/dist/output/bus.js +0 -37
  350. package/dist/output/channel.js +0 -285
  351. package/dist/output/format.js +0 -15
  352. package/dist/output/index.js +0 -8
  353. package/dist/output/json-sink.js +0 -24
  354. package/dist/output/machine.js +0 -9
  355. package/dist/output/session-sink.js +0 -27
  356. package/dist/output/types.js +0 -1
  357. package/dist/tools/approve.js +0 -41
  358. package/dist/tools/attach-image.js +0 -102
  359. package/dist/tools/auto-fixer.js +0 -180
  360. package/dist/tools/auto-tags.js +0 -83
  361. package/dist/tools/bash.js +0 -649
  362. package/dist/tools/browser.js +0 -160
  363. package/dist/tools/chunk-query.js +0 -112
  364. package/dist/tools/create-dir.js +0 -60
  365. package/dist/tools/delete-file.js +0 -67
  366. package/dist/tools/download-file.js +0 -142
  367. package/dist/tools/edit-file.js +0 -136
  368. package/dist/tools/enable-tools.js +0 -59
  369. package/dist/tools/executor.js +0 -304
  370. package/dist/tools/file-info.js +0 -49
  371. package/dist/tools/filter-tools.js +0 -17
  372. package/dist/tools/glob-tool.js +0 -37
  373. package/dist/tools/grep-tool.js +0 -142
  374. package/dist/tools/hidden-tools-block.js +0 -37
  375. package/dist/tools/index.js +0 -88
  376. package/dist/tools/list-dir.js +0 -53
  377. package/dist/tools/load-skill.js +0 -51
  378. package/dist/tools/mcp-call.js +0 -80
  379. package/dist/tools/meet-done.js +0 -14
  380. package/dist/tools/move-file.js +0 -94
  381. package/dist/tools/path-utils.js +0 -108
  382. package/dist/tools/pipeline-run.js +0 -167
  383. package/dist/tools/preview.js +0 -2
  384. package/dist/tools/process-ids.js +0 -31
  385. package/dist/tools/process-kill.js +0 -33
  386. package/dist/tools/process-list.js +0 -38
  387. package/dist/tools/process-log.js +0 -49
  388. package/dist/tools/process-wait.js +0 -63
  389. package/dist/tools/prompt-io.js +0 -29
  390. package/dist/tools/question.js +0 -288
  391. package/dist/tools/read-file.js +0 -200
  392. package/dist/tools/recall.js +0 -124
  393. package/dist/tools/registry.js +0 -48
  394. package/dist/tools/remember.js +0 -72
  395. package/dist/tools/scope-check.js +0 -32
  396. package/dist/tools/scope-request.js +0 -96
  397. package/dist/tools/search-history.js +0 -88
  398. package/dist/tools/session-info.js +0 -46
  399. package/dist/tools/set-thinking.js +0 -75
  400. package/dist/tools/subagent.js +0 -257
  401. package/dist/tools/syntax-validator.js +0 -379
  402. package/dist/tools/types.js +0 -1
  403. package/dist/tools/user-input.js +0 -134
  404. package/dist/tools/web-browse.js +0 -93
  405. package/dist/tools/web-fetch.js +0 -108
  406. package/dist/tools/web-search.js +0 -107
  407. package/dist/tools/write-file.js +0 -128
  408. package/dist/ui/action-log.js +0 -13
  409. package/dist/ui/box.js +0 -78
  410. package/dist/ui/colors.js +0 -6
  411. package/dist/ui/diff.js +0 -189
  412. package/dist/ui/index.js +0 -7
  413. package/dist/ui/line-editor.js +0 -1083
  414. package/dist/ui/line-math.js +0 -98
  415. package/dist/ui/md-formatter.js +0 -322
  416. package/dist/ui/output.js +0 -19
  417. package/dist/ui/plan-view.js +0 -109
  418. package/dist/ui/renderer.js +0 -589
  419. package/dist/ui/spinner.js +0 -91
  420. package/dist/ui/table.js +0 -142
  421. package/dist/ui/theme.js +0 -143
  422. package/dist/utils/child-run.js +0 -20
  423. package/dist/utils/error.js +0 -4
  424. package/dist/utils/index.js +0 -6
  425. package/dist/utils/retry.js +0 -17
  426. package/dist/utils/sleep.js +0 -23
  427. package/dist/utils/truncate.js +0 -9
@@ -1,142 +0,0 @@
1
- /** Тул поиска по содержимому (rg с fallback на grep -r). */
2
- import { spawn, } from "child_process";
3
- import { resolve } from "path";
4
- import { t } from "../i18n/index";
5
- import { logBashCommand, logSecurityBlock } from "../modules/security/audit-log";
6
- import { isPathInScope } from "../modules/security/path-validator";
7
- import { DEFAULT_SECURITY_CONFIG } from "../config/security";
8
- import { MAX_PREVIEW_LINES } from "./preview";
9
- /** Обрезает вывод до MAX_PREVIEW_LINES строк. */
10
- function truncateLines(output) {
11
- const lines = output.split("\n");
12
- if (lines.length <= MAX_PREVIEW_LINES)
13
- return output;
14
- return (lines.slice(0, MAX_PREVIEW_LINES).join("\n") +
15
- `\n... (${lines.length - MAX_PREVIEW_LINES} more lines)`);
16
- }
17
- /**
18
- * Поисковая команда асинхронно, с kill по таймауту. Exit code 1 (нет совпадений)
19
- * резолвится в пустую строку. Возврат: stdout поиска.
20
- */
21
- export function runSearch(bin, args, cwd, timeoutMs = 30000) {
22
- return new Promise((resolvePromise, reject) => {
23
- const child = spawn(bin, args, { cwd, windowsHide: true });
24
- let out = "";
25
- let err = "";
26
- let timedOut = false;
27
- const timer = setTimeout(() => {
28
- timedOut = true;
29
- child.kill();
30
- }, timeoutMs);
31
- child.stdout?.on("data", (d) => {
32
- out += d;
33
- });
34
- child.stderr?.on("data", (d) => {
35
- err += d;
36
- });
37
- child.on("error", (e) => {
38
- clearTimeout(timer);
39
- reject(e);
40
- });
41
- child.on("close", (code) => {
42
- clearTimeout(timer);
43
- if (timedOut) {
44
- reject(new Error(`search timed out after ${timeoutMs}ms`));
45
- }
46
- else if (code === 1) {
47
- resolvePromise("");
48
- }
49
- else if (code === 0) {
50
- resolvePromise(out);
51
- }
52
- else {
53
- reject(new Error(err || `exit ${code}`));
54
- }
55
- });
56
- });
57
- }
58
- /** Ищет по содержимому через regex (rg, иначе grep -r); кешируемый. */
59
- export const grepTool = {
60
- name: "grep",
61
- icon: "🔍",
62
- description: `Search file contents using a regular expression. Shows up to ${MAX_PREVIEW_LINES} matching lines by default. Uses ripgrep (rg) if available, otherwise falls back to grep -r.`,
63
- tags: ["file", "code", "research"],
64
- cacheable: true,
65
- parameters: {
66
- type: "object",
67
- properties: {
68
- pattern: { type: "string", description: "Regex pattern to search" },
69
- include: {
70
- type: "string",
71
- description: "File pattern to filter (e.g. *.ts)",
72
- },
73
- path: {
74
- type: "string",
75
- description: "Directory to search (defaults to baseDir)",
76
- },
77
- },
78
- required: ["pattern"],
79
- },
80
- handler: async (ctx, args) => {
81
- const pattern = String(args.pattern);
82
- const searchPath = args.path ? resolve(ctx.baseDir, String(args.path)) : ctx.baseDir;
83
- // Каталог поиска обязан оставаться внутри baseDir/скоупа: `path: "../../.."`
84
- // не должен читать вне песочницы.
85
- const scopeCheck = isPathInScope(ctx.baseDir, searchPath, ctx.scope, ctx.config?.security?.paths || DEFAULT_SECURITY_CONFIG.paths);
86
- if (!scopeCheck.allowed) {
87
- logSecurityBlock(ctx.sessionId || undefined, "file_read", scopeCheck.reason || "grep path not allowed", String(args.path ?? ctx.baseDir));
88
- return {
89
- success: false,
90
- output: t("file.path_not_allowed", {
91
- path: `${args.path ?? "."} — ${scopeCheck.reason}`,
92
- }),
93
- };
94
- }
95
- // Аргументы rg массивом, чтобы шелл не трактовал метасимволы regex
96
- // (|, (, )) как операторы — это паттерны, не команды шелла.
97
- const rgArgs = ["-n", "--with-filename", pattern, searchPath];
98
- if (args.include) {
99
- rgArgs.push("-g", String(args.include));
100
- }
101
- logBashCommand(ctx.sessionId, `rg ${rgArgs.join(" ")}`, false, "grep-tool");
102
- try {
103
- const output = await runSearch("rg", rgArgs, ctx.baseDir);
104
- return {
105
- success: true,
106
- output: truncateLines(output || t("file.no_matches")),
107
- };
108
- }
109
- catch (e) {
110
- if (e.code === "ENOENT") {
111
- // fall through to grep fallback
112
- }
113
- else if (/timed out/.test(e.message)) {
114
- return { success: false, output: t("error.grep_failed", { message: e.message }) };
115
- }
116
- else if (e.status === 1) {
117
- return { success: true, output: t("file.no_matches") };
118
- }
119
- // Fallback на plain grep -r, когда rg нет или упал. Массив аргументов —
120
- // защита от shell injection.
121
- try {
122
- const grepArgs = ["-rn", pattern, searchPath];
123
- if (args.include) {
124
- grepArgs.push("--include", String(args.include));
125
- }
126
- const output = await runSearch("grep", grepArgs, ctx.baseDir);
127
- return {
128
- success: true,
129
- output: truncateLines(output || t("file.no_matches")),
130
- };
131
- }
132
- catch (e2) {
133
- if (e2.status === 1)
134
- return { success: true, output: t("file.no_matches") };
135
- return {
136
- success: false,
137
- output: t("error.grep_failed", { message: e2.message }),
138
- };
139
- }
140
- }
141
- },
142
- };
@@ -1,37 +0,0 @@
1
- /** Блок системного промпта о скрытых tag-фильтром тулах. */
2
- import { t } from "../i18n/index";
3
- /**
4
- * Компактный блок системного промпта со скрытыми тулами. Модель должна знать
5
- * об их существовании (и пути доступа), хотя их нет в tool-схеме LLM.
6
- * Группировка по тегам, размер ограничен.
7
- */
8
- export function buildHiddenToolsBlock(allTools, activeTags) {
9
- if (!allTools.length)
10
- return "";
11
- const activeSet = new Set(activeTags);
12
- const visible = new Set();
13
- for (const tool of allTools) {
14
- if (tool.alwaysOn || (tool.tags?.some((tag) => activeSet.has(tag)))) {
15
- visible.add(tool.name);
16
- }
17
- }
18
- const hidden = allTools.filter((tool) => !visible.has(tool.name));
19
- if (hidden.length === 0)
20
- return "";
21
- // Группировка по тегам, внутри тега — по имени тула.
22
- const byTag = new Map();
23
- for (const tool of hidden) {
24
- const tags = tool.tags && tool.tags.length > 0 ? tool.tags : ["other"];
25
- for (const tag of tags) {
26
- if (!byTag.has(tag))
27
- byTag.set(tag, []);
28
- byTag.get(tag).push(tool);
29
- }
30
- }
31
- const lines = [t("tools.hidden_header")];
32
- for (const [tag, tools] of [...byTag.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
33
- const names = [...new Set(tools.map((tool) => tool.name))].sort().join(", ");
34
- lines.push(`- [${tag}] ${names}`);
35
- }
36
- return lines.join("\n");
37
- }
@@ -1,88 +0,0 @@
1
- /** Точка сборки каталога тулов: импорты, реэкспорты, регистрация. */
2
- import { ToolRegistry } from "./registry";
3
- import { ToolExecutor } from "./executor";
4
- import { readFileTool } from "./read-file";
5
- import { writeFileTool } from "./write-file";
6
- import { editFileTool } from "./edit-file";
7
- import { globTool } from "./glob-tool";
8
- import { grepTool } from "./grep-tool";
9
- import { listDirTool } from "./list-dir";
10
- import { createDirTool } from "./create-dir";
11
- import { deleteFileTool } from "./delete-file";
12
- import { moveFileTool } from "./move-file";
13
- import { fileInfoTool } from "./file-info";
14
- import { bashTool } from "./bash";
15
- import { processListTool } from "./process-list";
16
- import { processLogTool } from "./process-log";
17
- import { processKillTool } from "./process-kill";
18
- import { processWaitTool } from "./process-wait";
19
- import { subagentTool } from "./subagent";
20
- import { chunkQueryTool } from "./chunk-query";
21
- import { webSearchTool } from "./web-search";
22
- import { webFetchTool } from "./web-fetch";
23
- import { webBrowseTool } from "./web-browse";
24
- import { downloadFileTool } from "./download-file";
25
- // question/approve — основной набор: question покрывает выбор + свободный
26
- // текст (с pre-check памяти), approve — явное Yes/No (reject даёт success:false,
27
- // и цикл трактует это как сигнал сбоя, а не текст ответа).
28
- import { questionTool } from "./question";
29
- import { approveTool } from "./approve";
30
- import { createLoadSkillTool } from "./load-skill";
31
- import { pipelineRunTool } from "./pipeline-run";
32
- import { mcpCallTool } from "./mcp-call";
33
- import { searchHistoryTool } from "./search-history";
34
- import { rememberTool } from "./remember";
35
- import { recallTool } from "./recall";
36
- import { meetDoneTool } from "./meet-done";
37
- import { createBrowserTool } from "./browser";
38
- import { attachImageTool } from "./attach-image";
39
- import { enableToolsTool } from "./enable-tools";
40
- import { sessionInfoTool } from "./session-info";
41
- export { ToolRegistry, ToolExecutor };
42
- export { filterToolsByTags } from "./filter-tools";
43
- export { readFileTool, writeFileTool, editFileTool, globTool, grepTool, listDirTool, createDirTool, deleteFileTool, moveFileTool, fileInfoTool, bashTool, subagentTool, chunkQueryTool, processListTool, processLogTool, processKillTool, processWaitTool, webSearchTool, webFetchTool, webBrowseTool, downloadFileTool, createLoadSkillTool, pipelineRunTool, mcpCallTool, searchHistoryTool, rememberTool, recallTool, meetDoneTool, createBrowserTool, attachImageTool, enableToolsTool, sessionInfoTool, questionTool, approveTool, };
44
- /** Регистрирует все тулы; опционально — on-demand тул и скиллы. */
45
- export function registerAllTools(registry, skillsModule, opts) {
46
- const tools = [
47
- readFileTool,
48
- writeFileTool,
49
- editFileTool,
50
- globTool,
51
- grepTool,
52
- listDirTool,
53
- createDirTool,
54
- deleteFileTool,
55
- moveFileTool,
56
- fileInfoTool,
57
- bashTool,
58
- subagentTool,
59
- chunkQueryTool,
60
- processListTool,
61
- processLogTool,
62
- processKillTool,
63
- processWaitTool,
64
- webSearchTool,
65
- webFetchTool,
66
- webBrowseTool,
67
- downloadFileTool,
68
- pipelineRunTool,
69
- mcpCallTool,
70
- searchHistoryTool,
71
- attachImageTool,
72
- sessionInfoTool,
73
- meetDoneTool,
74
- questionTool,
75
- approveTool,
76
- ];
77
- // On-demand активация — дефолт. При явном enableOnDemand:false тул не
78
- // регистрируется вовсе — с пустым defaultTags это legacy-режим «все тулы».
79
- if (opts?.enableOnDemand !== false) {
80
- tools.push(enableToolsTool);
81
- }
82
- if (skillsModule) {
83
- tools.push(createLoadSkillTool(skillsModule));
84
- }
85
- for (const tool of tools) {
86
- registry.register(tool);
87
- }
88
- }
@@ -1,53 +0,0 @@
1
- /** Тул листинга каталога (игнор мусора, cap вывода, кешируемый). */
2
- import { readdirSync, statSync, existsSync } from "fs";
3
- import { resolve } from "path";
4
- import { t } from "../i18n/index";
5
- import { isPathInScope } from "../modules/security/path-validator";
6
- import { safeResolvePath } from "./path-utils";
7
- import { MAX_PREVIEW_LINES } from "./preview";
8
- /** Каталоги вне выдачи list_dir (едино с walker'ом индексёра). */
9
- const IGNORED_DIRS = new Set(["node_modules", ".git", "dist", "build", "coverage", ".mma"]);
10
- /** Показывает файлы/подкаталоги (каталоги с `/`); мусор скрыт. */
11
- export const listDirTool = {
12
- name: "list_dir",
13
- icon: "📂",
14
- description: `List files and directories in a given path. Shows up to ${MAX_PREVIEW_LINES} entries by default.`,
15
- tags: ["file"],
16
- boundedOutput: true,
17
- cacheable: true,
18
- parameters: {
19
- type: "object",
20
- properties: {
21
- path: { type: "string", description: "Directory path" },
22
- },
23
- required: ["path"],
24
- },
25
- handler: async (ctx, args) => {
26
- const path = String(args.path);
27
- const resolved = safeResolvePath(ctx.baseDir, path);
28
- const scopeCheck = isPathInScope(ctx.baseDir, resolved, ctx.scope, ctx.config.security?.paths);
29
- if (!scopeCheck.allowed) {
30
- return {
31
- success: false,
32
- output: t("file.path_not_allowed", {
33
- path: `${path} — ${scopeCheck.reason}`,
34
- }),
35
- };
36
- }
37
- if (!existsSync(resolved)) {
38
- return { success: false, output: t("file.dir_notfound", { path }) };
39
- }
40
- const entries = readdirSync(resolved).filter((e) => !IGNORED_DIRS.has(e));
41
- const lines = entries.map((e) => {
42
- const full = resolve(resolved, e);
43
- return statSync(full).isDirectory() ? `${e}/` : e;
44
- });
45
- if (lines.length === 0) {
46
- return { success: true, output: t("file.empty") };
47
- }
48
- const truncated = lines.length > MAX_PREVIEW_LINES
49
- ? `\n... (${lines.length - MAX_PREVIEW_LINES} more entries)`
50
- : "";
51
- return { success: true, output: lines.slice(0, MAX_PREVIEW_LINES).join("\n") + truncated };
52
- },
53
- };
@@ -1,51 +0,0 @@
1
- /** Фабрика тула загрузки скилла (инжект в системный промпт). */
2
- import { t } from "../i18n/index";
3
- import { estimateTokens } from "../llm/token-counter";
4
- /**
5
- * Фабрика тула load_skill. Контент скилла инжектится в системный промпт
6
- * (не в историю) — переживает компакцию. Возврат: определение тула.
7
- */
8
- export function createLoadSkillTool(skillsModule) {
9
- return {
10
- name: "load_skill",
11
- icon: "🎯",
12
- tags: ["core"],
13
- // Роутинг скиллов — вне сужения (P5): модель использует только видимый скилл.
14
- alwaysOn: true,
15
- description: "Load a skill by name. Skills provide specialized instructions and workflows. When loaded, the skill content is injected into the system prompt (not conversation history) so it persists through context compaction. Only use when the task clearly requires domain-specific knowledge.",
16
- parameters: {
17
- type: "object",
18
- properties: {
19
- name: {
20
- type: "string",
21
- description: "Exact skill name to load (see [Available Skills] for names)",
22
- },
23
- },
24
- required: ["name"],
25
- },
26
- handler: async (_ctx, args) => {
27
- const name = args.name ? String(args.name) : undefined;
28
- if (!name) {
29
- return { success: false, output: t("tool.invalid_params") };
30
- }
31
- const result = skillsModule.loadByName(name);
32
- if (!result.success) {
33
- const available = skillsModule.getAvailable();
34
- const hint = available.length > 0
35
- ? `\n\n${t("tool.skill_available_hint")}: ${available.map((s) => s.name).join(", ")}`
36
- : "";
37
- return { success: false, output: result.message + hint };
38
- }
39
- const budget = skillsModule.getBudget();
40
- const tokens = result.skill ? estimateTokens(result.skill.content) : 0;
41
- return {
42
- success: true,
43
- output: t("tool.skill_budget", {
44
- name,
45
- tokens,
46
- remaining: budget.remaining,
47
- }),
48
- };
49
- },
50
- };
51
- }
@@ -1,80 +0,0 @@
1
- /** Тул вызова тула на MCP-сервере (ленивая регистрация из конфига). */
2
- import { t } from "../i18n/index";
3
- import { MCPClient } from "../modules/mcp/client";
4
- import { MCPRegistry } from "../modules/mcp/registry";
5
- const registry = new MCPRegistry();
6
- let initialized = false;
7
- /** Ленивая регистрация MCP-серверов из конфига (один раз на процесс). */
8
- function ensureInitialized(ctx) {
9
- if (initialized)
10
- return;
11
- initialized = true;
12
- const servers = ctx.config.mcpServers || {};
13
- for (const [name, cfg] of Object.entries(servers)) {
14
- if (cfg.enabled !== false) {
15
- registry.register({
16
- name: cfg.name || name,
17
- command: cfg.command,
18
- args: cfg.args,
19
- env: cfg.env,
20
- transport: cfg.transport,
21
- url: cfg.url,
22
- headers: cfg.headers,
23
- timeout: cfg.timeout,
24
- });
25
- }
26
- }
27
- }
28
- /** Вызывает тул на MCP-сервере. Параметры: server, tool, args. */
29
- export const mcpCallTool = {
30
- name: "mcp_call",
31
- icon: "🔗",
32
- description: "Call a tool on an MCP (Model Context Protocol) server. MCP servers provide external capabilities like databases, APIs, or specialized tools.",
33
- tags: ["research"],
34
- parameters: {
35
- type: "object",
36
- properties: {
37
- server: { type: "string", description: "MCP server name" },
38
- tool: { type: "string", description: "Tool name on the server" },
39
- args: { type: "object", description: "Arguments to pass to the tool" },
40
- },
41
- required: ["server", "tool"],
42
- },
43
- handler: async (ctx, args) => {
44
- const serverName = String(args.server || "");
45
- const toolName = String(args.tool || "");
46
- const toolArgs = (args.args || {});
47
- if (!serverName || !toolName) {
48
- return { success: false, output: "Server and tool names are required" };
49
- }
50
- ensureInitialized(ctx);
51
- const serverConfig = registry.get(serverName);
52
- if (!serverConfig) {
53
- const available = registry.list();
54
- return {
55
- success: false,
56
- output: t("tool.mcp_server_not_found", {
57
- server: serverName,
58
- available: available.join(", ") || "(none)",
59
- }),
60
- };
61
- }
62
- const client = new MCPClient(serverConfig);
63
- try {
64
- await client.connect();
65
- const result = await client.callTool(toolName, toolArgs);
66
- return {
67
- success: true,
68
- output: `MCP call result:\n${JSON.stringify(result, null, 2)}`,
69
- };
70
- }
71
- catch (e) {
72
- return { success: false, output: t("tool.mcp_call_failed", { error: e.message }) };
73
- }
74
- finally {
75
- // Клиент закрывать всегда: раньше ошибка/таймаут в callTool пропускала
76
- // disconnect и сиротила stdio-дочерний процесс на сессию.
77
- await client.disconnect().catch(() => { });
78
- }
79
- },
80
- };
@@ -1,14 +0,0 @@
1
- /** Сентинел завершения meet-интервью: ставит флаг, REPL выходит из режима. */
2
- import { t } from "../i18n/index";
3
- /** Модель зовёт по финальному саммари; вне онбординга — no-op по флагу. */
4
- export const meetDoneTool = {
5
- name: "meet_done",
6
- description: "Signal that the get-acquainted interview is complete. Call only after the final summary.",
7
- tags: ["memory"],
8
- parameters: { type: "object", properties: {} },
9
- handler: async (ctx) => {
10
- if (ctx.onboarding)
11
- ctx.onboarding.done = true;
12
- return { success: true, output: t("tool.meet_done") };
13
- },
14
- };
@@ -1,94 +0,0 @@
1
- /** Тул перемещения/переименования файла или каталога. */
2
- import { renameSync, existsSync, mkdirSync } from "fs";
3
- import { resolve, normalize, dirname } from "path";
4
- import { t } from "../i18n/index";
5
- import { isPathWritable } from "../modules/security/path-validator";
6
- import { logFileWrite, logSecurityBlock } from "../modules/security/audit-log";
7
- import { getSessionSecurityConfig } from "../modules/security/session-isolation";
8
- import { generateMoveDiff } from "../ui/diff";
9
- import { safeResolvePath } from "./path-utils";
10
- import { protectedPathBlock } from "../modules/security/protected-paths";
11
- /** Перемещает/переименовывает; обе стороны проверяются по скоупу. */
12
- export const moveFileTool = {
13
- name: "move_file",
14
- icon: "📦",
15
- description: "Move or rename a file or directory.",
16
- tags: ["file"],
17
- parameters: {
18
- type: "object",
19
- properties: {
20
- from: { type: "string", description: "Source path" },
21
- to: { type: "string", description: "Destination path" },
22
- },
23
- required: ["from", "to"],
24
- },
25
- handler: async (ctx, args) => {
26
- const fromPath = String(args.from);
27
- const toPath = String(args.to);
28
- const baseDir = resolve(ctx.baseDir);
29
- const fromResolved = safeResolvePath(baseDir, normalize(fromPath));
30
- const toResolved = safeResolvePath(baseDir, normalize(toPath));
31
- const securityConfig = ctx.sessionContext
32
- ? getSessionSecurityConfig(ctx.config, ctx.sessionContext)
33
- : ctx.config.security;
34
- // Лимит файловых операций.
35
- const maxFileOps = securityConfig?.maxFileOperations ?? 100;
36
- const currentCount = ctx.fileOperationsCount ?? 0;
37
- if (currentCount >= maxFileOps) {
38
- logSecurityBlock(ctx.sessionId, "file_write", `Maximum file operations (${maxFileOps}) exceeded`, `${fromPath} -> ${toPath}`);
39
- return {
40
- success: false,
41
- output: `[SECURITY BLOCKED] Maximum file operations (${maxFileOps}) exceeded`,
42
- };
43
- }
44
- // Права источника — по РЕЗОЛВЛЕННОМУ пути (по нему же работает renameSync),
45
- // никогда по сырому аргументу.
46
- const fromCheck = isPathWritable(ctx.baseDir, fromResolved, ctx.scope, ctx.config.security?.paths);
47
- if (!fromCheck.allowed) {
48
- logSecurityBlock(ctx.sessionId, "file_write", fromCheck.reason || "Source path not allowed", fromPath);
49
- return {
50
- success: false,
51
- output: t("file.path_not_allowed", {
52
- path: `${fromPath} — ${fromCheck.reason}`,
53
- }),
54
- };
55
- }
56
- // Права приёмника — тоже по резолвленному.
57
- const toCheck = isPathWritable(ctx.baseDir, toResolved, ctx.scope, ctx.config.security?.paths);
58
- if (!toCheck.allowed) {
59
- logSecurityBlock(ctx.sessionId, "file_write", toCheck.reason || "Destination path not allowed", toPath);
60
- return {
61
- success: false,
62
- output: t("file.path_not_allowed", {
63
- path: `${toPath} — ${toCheck.reason}`,
64
- }),
65
- };
66
- }
67
- // Защищённые пути с любой стороны (.git/, .env, ключи) — спросить юзера.
68
- const fromProtected = protectedPathBlock(ctx, fromResolved, fromPath);
69
- if (fromProtected)
70
- return fromProtected;
71
- const toProtected = protectedPathBlock(ctx, toResolved, toPath);
72
- if (toProtected)
73
- return toProtected;
74
- if (!existsSync(fromResolved)) {
75
- return {
76
- success: false,
77
- output: t("file.not_found_short", { path: fromPath }),
78
- };
79
- }
80
- const toDir = dirname(toResolved);
81
- if (!existsSync(toDir)) {
82
- mkdirSync(toDir, { recursive: true });
83
- }
84
- renameSync(fromResolved, toResolved);
85
- const diff = generateMoveDiff(fromPath, toPath);
86
- ctx.fileOperationsCount = currentCount + 1;
87
- logFileWrite(ctx.sessionId, `${fromPath} -> ${toPath}`, true, "File moved");
88
- return {
89
- success: true,
90
- output: t("file.moved", { from: fromPath, to: toPath }),
91
- diff,
92
- };
93
- },
94
- };
@@ -1,108 +0,0 @@
1
- /** Утилиты путей: нормализация, jail-проверки, резолв от baseDir. */
2
- import { resolve, normalize, dirname, basename, sep, relative, isAbsolute } from "path";
3
- import { existsSync } from "fs";
4
- /**
5
- * Бэкслэши → прямые слэши для показа и сравнения.
6
- * На POSIX no-op; на Windows `src\foo\bar.ts` → `src/foo/bar.ts`.
7
- */
8
- export function toForwardSlash(p) {
9
- return p.replace(/\\/g, "/");
10
- }
11
- /**
12
- * True, если targetPath равен dirPath или внутри него.
13
- *
14
- * Кроссплатформенно:
15
- * - через path.relative(), а не raw startsWith: сосед с общим префиксом
16
- * ("src" vs "src-other") не пройдёт;
17
- * - на Windows ФС регистронезависима: обе стороны lowercased до сравнения.
18
- */
19
- export function isInsideDir(targetPath, dirPath) {
20
- const norm = (p) => (process.platform === "win32" ? p.toLowerCase() : p);
21
- const t = norm(resolve(targetPath));
22
- const d = norm(resolve(dirPath));
23
- if (t === d)
24
- return true;
25
- const rel = relative(d, t);
26
- // Побег наверх — только реальный `..`/`../…`. Файл буквально `..foo`
27
- // даёт rel === "..foo" и легально внутри.
28
- return rel.length > 0 && !isAbsolute(rel) && rel !== ".." && !rel.startsWith(`..${sep}`);
29
- }
30
- /**
31
- * True, если targetPath — сам scope-entry или внутри него. Проверка
32
- * сепараторов и регистра — как в isInsideDir.
33
- */
34
- export function matchesScopeEntry(targetResolved, entryResolved) {
35
- if (targetResolved === entryResolved)
36
- return true;
37
- return isInsideDir(targetResolved, entryResolved);
38
- }
39
- /**
40
- * Резолв пользовательского пути от baseDir.
41
- *
42
- * Чинит типовые ошибки модели:
43
- * 1. Ведущий слэш: "/testing/cat3" → относительно baseDir.
44
- * 2. Пропущенный сепаратор: "E:\agent_test" при baseDir "E:\agent\_test"
45
- * → вставка недостающего бэкслэша.
46
- *
47
- * Для новых файлов обязан существовать родитель — проверяется он, а не
48
- * полный путь, иначе write_file не сработает.
49
- */
50
- export function safeResolvePath(baseDir, userPath) {
51
- // Существующий абсолютный путь — как есть.
52
- const asIs = resolve(normalize(userPath));
53
- if (userPath.startsWith("/") || userPath.startsWith("\\")) {
54
- if (existsSync(asIs) || existsSync(dirname(asIs)))
55
- return asIs;
56
- }
57
- const norm = normalize(userPath);
58
- // Абсолютные пути — дословно, БЕЗ сдирания ведущего слэша и перерезолва
59
- // от baseDir (иначе /var/folders/... станет baseDir/var/folders/... на POSIX).
60
- // Эвристика ведущего слэша ниже — только fallback, когда путь не на диске.
61
- if (isAbsolute(norm)) {
62
- if (existsSync(norm) || existsSync(dirname(norm)))
63
- return norm;
64
- // Абсолютный, но ещё не на диске (новый файл без существующих dirs).
65
- // Восстановление ошибки модели: ведущий слэш мог значить "от baseDir".
66
- const stripped = norm.replace(/^[/\\]/, "");
67
- const relativeCandidate = resolve(baseDir, stripped);
68
- if (existsSync(relativeCandidate) || existsSync(dirname(relativeCandidate))) {
69
- return relativeCandidate;
70
- }
71
- return norm;
72
- }
73
- const stripped = norm.replace(/^[/\\]/, "");
74
- const resolved = resolve(baseDir, stripped);
75
- // Быстрый путь: существует сам (или родитель для новых файлов).
76
- if (existsSync(resolved) || existsSync(dirname(resolved)))
77
- return resolved;
78
- const baseNorm = normalize(baseDir);
79
- // Подъём по предкам в поиске пропущенных сепараторов.
80
- let cur = baseNorm;
81
- while (cur && cur !== dirname(cur)) {
82
- const name = basename(cur);
83
- if (!name) {
84
- cur = dirname(cur);
85
- continue;
86
- }
87
- let idx = stripped.toLowerCase().indexOf(name.toLowerCase());
88
- while (idx >= 0) {
89
- const afterIdx = idx + name.length;
90
- const afterChar = stripped[afterIdx];
91
- if (afterChar && afterChar !== "\\" && afterChar !== "/") {
92
- const fixed = stripped.slice(0, afterIdx) + sep + stripped.slice(afterIdx);
93
- const fixedResolved = resolve(baseDir, normalize(fixed));
94
- if (existsSync(fixedResolved) || existsSync(dirname(fixedResolved))) {
95
- return fixedResolved;
96
- }
97
- // Проба от родителя предка.
98
- const fromParent = resolve(dirname(cur), normalize(fixed));
99
- if (existsSync(fromParent) || existsSync(dirname(fromParent))) {
100
- return fromParent;
101
- }
102
- }
103
- idx = stripped.toLowerCase().indexOf(name.toLowerCase(), idx + 1);
104
- }
105
- cur = dirname(cur);
106
- }
107
- return resolved;
108
- }