micro-models-agent 0.41.2 → 0.43.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 (171) hide show
  1. package/bin/mma.mjs +41 -41
  2. package/dist/cli/commands.js +19 -9
  3. package/dist/cli/completer.js +37 -36
  4. package/dist/cli/index.js +2 -2
  5. package/dist/cli/main.js +23 -48
  6. package/dist/cli/repl-commands.js +12 -40
  7. package/dist/cli/repl.js +87 -217
  8. package/dist/cli/security-commands.js +7 -5
  9. package/dist/cli/setup.js +26 -8
  10. package/dist/config/config.js +5 -52
  11. package/dist/config/defaults.js +5 -29
  12. package/dist/config/experts.js +1 -1
  13. package/dist/config/index.js +3 -3
  14. package/dist/config/security.js +10 -3
  15. package/dist/core/agent-moe.js +10 -2
  16. package/dist/core/agent.js +82 -273
  17. package/dist/core/bootstrap.js +13 -80
  18. package/dist/core/index.js +2 -2
  19. package/dist/core/prompt-builder.js +2 -23
  20. package/dist/core/session-logger.js +4 -46
  21. package/dist/i18n/en.json +2 -75
  22. package/dist/i18n/ru.json +1 -74
  23. package/dist/index.js +1 -1
  24. package/dist/llm/image-utils.js +5 -4
  25. package/dist/llm/index.js +4 -4
  26. package/dist/llm/model-loader.js +6 -6
  27. package/dist/llm/openai-compat.js +34 -40
  28. package/dist/llm/orchestrator.js +29 -33
  29. package/dist/llm/response.js +9 -9
  30. package/dist/logger/app-logger.js +1 -1
  31. package/dist/logger/index.js +1 -1
  32. package/dist/main.js +648 -183
  33. package/dist/migration/backup.js +13 -13
  34. package/dist/migration/detect.js +11 -11
  35. package/dist/migration/index.js +2 -2
  36. package/dist/modules/browser/actions.js +4 -34
  37. package/dist/modules/browser/bridge-server.mjs +202 -202
  38. package/dist/modules/browser/cookie-store.js +6 -6
  39. package/dist/modules/browser/index.js +5 -7
  40. package/dist/modules/browser/module.js +7 -8
  41. package/dist/modules/browser/session.js +84 -87
  42. package/dist/modules/browser/snapshot.js +58 -92
  43. package/dist/modules/browser/types.js +1 -4
  44. package/dist/modules/certification/cli.js +4 -2
  45. package/dist/modules/certification/fact-checker.js +3 -1
  46. package/dist/modules/certification/loader.js +9 -3
  47. package/dist/modules/certification/runner.js +4 -1
  48. package/dist/modules/context/index.js +1 -1
  49. package/dist/modules/context/manager.js +86 -160
  50. package/dist/modules/execution/auditor.js +25 -177
  51. package/dist/modules/execution/module.js +544 -201
  52. package/dist/modules/execution/moe-executor.js +0 -25
  53. package/dist/modules/execution/plan-store.js +3 -1
  54. package/dist/modules/execution/plan-validator.js +10 -10
  55. package/dist/modules/execution/planner.js +1 -6
  56. package/dist/modules/execution/stuck-detector.js +10 -173
  57. package/dist/modules/execution/verifier.js +42 -86
  58. package/dist/modules/hallucination/confidence.js +1 -8
  59. package/dist/modules/hallucination/detector.js +5 -2
  60. package/dist/modules/hallucination/factual.js +64 -3
  61. package/dist/modules/hallucination/index.js +1 -1
  62. package/dist/modules/hallucination/js-identifiers.js +0 -190
  63. package/dist/modules/hallucination/llm-judge.js +3 -1
  64. package/dist/modules/indexer/cache.js +7 -9
  65. package/dist/modules/indexer/index.js +3 -3
  66. package/dist/modules/indexer/module.js +42 -95
  67. package/dist/modules/indexer/walker.js +17 -17
  68. package/dist/modules/lsp/client.js +31 -74
  69. package/dist/modules/lsp/config.js +33 -87
  70. package/dist/modules/lsp/index.js +3 -3
  71. package/dist/modules/lsp/module.js +21 -185
  72. package/dist/modules/mcp/module.js +6 -2
  73. package/dist/modules/memory/index.js +1 -1
  74. package/dist/modules/memory/module.js +23 -71
  75. package/dist/modules/memory/search.js +9 -11
  76. package/dist/modules/memory/store.js +13 -13
  77. package/dist/modules/pipelines/engine.js +10 -10
  78. package/dist/modules/pipelines/index.js +3 -3
  79. package/dist/modules/pipelines/parser.js +14 -17
  80. package/dist/modules/pipelines/template.js +1 -1
  81. package/dist/modules/plugins/builtin/lint-on-write.js +16 -21
  82. package/dist/modules/plugins/builtin/notify.js +2 -3
  83. package/dist/modules/plugins/index.js +1 -1
  84. package/dist/modules/plugins/loader.js +17 -59
  85. package/dist/modules/plugins/manager.js +17 -73
  86. package/dist/modules/processes/index.js +1 -1
  87. package/dist/modules/processes/registry.js +46 -135
  88. package/dist/modules/registry.js +2 -4
  89. package/dist/modules/security/audit-notifier.js +39 -39
  90. package/dist/modules/security/command-validator.js +8 -2
  91. package/dist/modules/security/data-sanitizer.js +9 -1
  92. package/dist/modules/security/encryption.js +56 -58
  93. package/dist/modules/security/network-validator.js +9 -1
  94. package/dist/modules/security/path-validator.js +3 -1
  95. package/dist/modules/security/security-policies.js +19 -3
  96. package/dist/modules/security/session-encryption.js +1 -1
  97. package/dist/modules/security/session-isolation.js +8 -8
  98. package/dist/modules/session/index.js +3 -3
  99. package/dist/modules/session/module.js +5 -5
  100. package/dist/modules/session/store.js +9 -3
  101. package/dist/modules/skills/module.js +2 -1
  102. package/dist/modules/updater/checker.js +6 -70
  103. package/dist/modules/updater/index.js +1 -2
  104. package/dist/modules/user-profile/compressor.js +2 -2
  105. package/dist/modules/user-profile/index.js +1 -1
  106. package/dist/modules/user-profile/profile.js +9 -9
  107. package/dist/tools/attach-image.js +1 -1
  108. package/dist/tools/bash.js +19 -178
  109. package/dist/tools/browser.js +29 -46
  110. package/dist/tools/executor.js +5 -4
  111. package/dist/tools/file-info.js +12 -13
  112. package/dist/tools/filter-tools.js +2 -9
  113. package/dist/tools/glob-tool.js +11 -11
  114. package/dist/tools/grep-tool.js +3 -1
  115. package/dist/tools/index.js +2 -13
  116. package/dist/tools/list-dir.js +17 -18
  117. package/dist/tools/load-skill.js +3 -1
  118. package/dist/tools/path-utils.js +4 -4
  119. package/dist/tools/pipeline-run.js +25 -25
  120. package/dist/tools/process-kill.js +11 -11
  121. package/dist/tools/process-list.js +22 -20
  122. package/dist/tools/process-log.js +18 -22
  123. package/dist/tools/question.js +3 -1
  124. package/dist/tools/read-file.js +2 -10
  125. package/dist/tools/recall.js +37 -44
  126. package/dist/tools/registry.js +4 -15
  127. package/dist/tools/remember.js +29 -29
  128. package/dist/tools/scope-check.js +9 -9
  129. package/dist/tools/subagent.js +9 -54
  130. package/dist/tools/user-input.js +1 -1
  131. package/dist/tools/web-browse.js +3 -3
  132. package/dist/tools/web-fetch.js +3 -3
  133. package/dist/tools/web-search.js +3 -3
  134. package/dist/tools/write-file.js +3 -1
  135. package/dist/ui/box.js +5 -1
  136. package/dist/ui/index.js +6 -6
  137. package/dist/ui/md-formatter.js +33 -33
  138. package/dist/ui/output.js +5 -5
  139. package/dist/ui/renderer.js +10 -15
  140. package/dist/ui/table.js +1 -1
  141. package/package.json +48 -48
  142. package/dist/cli/plugin-commands.js +0 -36
  143. package/dist/cli/run-result.js +0 -22
  144. package/dist/core/version.js +0 -24
  145. package/dist/modules/artifacts/store.js +0 -61
  146. package/dist/modules/browser/bridge-client.js +0 -199
  147. package/dist/modules/browser/bridge-path.js +0 -10
  148. package/dist/modules/browser/driver.js +0 -136
  149. package/dist/modules/context/chunk-query.js +0 -100
  150. package/dist/modules/context/fact-extractor.js +0 -162
  151. package/dist/modules/context/history.js +0 -15
  152. package/dist/modules/execution/audit-runners.js +0 -152
  153. package/dist/modules/execution/execution-plugin.js +0 -272
  154. package/dist/modules/execution/plan-tool.js +0 -508
  155. package/dist/modules/execution/windows-commands.js +0 -41
  156. package/dist/modules/indexer/project-profile.js +0 -183
  157. package/dist/modules/lsp/check-tool.js +0 -58
  158. package/dist/modules/lsp/command.js +0 -60
  159. package/dist/modules/lsp/probe.js +0 -76
  160. package/dist/modules/lsp/project-root.js +0 -32
  161. package/dist/modules/lsp/startup-check.js +0 -141
  162. package/dist/modules/processes/detect.js +0 -34
  163. package/dist/modules/skills/matcher.js +0 -27
  164. package/dist/modules/updater/module.js +0 -116
  165. package/dist/tools/chunk-query.js +0 -99
  166. package/dist/tools/download-file.js +0 -116
  167. package/dist/tools/enable-tools.js +0 -58
  168. package/dist/tools/hidden-tools-block.js +0 -37
  169. package/dist/ui/line-editor.js +0 -703
  170. package/dist/ui/line-math.js +0 -69
  171. package/dist/ui/plan-view.js +0 -103
@@ -1,44 +1,14 @@
1
- import { semverGt } from "../updater/checker";
2
1
  export class PluginManager {
3
2
  plugins = [];
4
- /**
5
- * Register a plugin. Plugins with the same `name` are deduplicated — the
6
- * higher `version` wins (unversioned plugins count as "0.0.0"). The loser is
7
- * discarded; `skipped_older` lets the caller warn about the dropped copy.
8
- */
9
- register(plugin, source) {
10
- if (source)
11
- plugin.source = source;
12
- const existing = this.plugins.find((p) => p.name === plugin.name);
13
- if (existing) {
14
- if (semverGt(plugin.version || "0.0.0", existing.version || "0.0.0")) {
15
- this.plugins = this.plugins.filter((p) => p.name !== plugin.name);
16
- this.plugins.push(plugin);
17
- this.sort();
18
- return { status: "registered" };
19
- }
20
- return { status: "skipped_older", existing };
21
- }
3
+ register(plugin) {
22
4
  this.plugins.push(plugin);
23
- this.sort();
24
- return { status: "registered" };
25
- }
26
- sort() {
27
5
  this.plugins.sort((a, b) => (b.priority || 0) - (a.priority || 0));
28
6
  }
29
7
  getAllPlugins() {
30
8
  return [...this.plugins];
31
9
  }
32
- /** Detailed plugin list (name, version, source) for REPL / CLI display. */
33
- getPluginInfos() {
34
- return [...this.plugins].map((plugin) => ({ plugin, source: plugin.source }));
35
- }
36
- /** Find a registered plugin by name, or null. */
37
- getPlugin(name) {
38
- return this.plugins.find((p) => p.name === name) ?? null;
39
- }
40
10
  runOnBuildPrompt() {
41
- return this.plugins.map((p) => {
11
+ return this.plugins.map(p => {
42
12
  try {
43
13
  return p.onBuildPrompt?.() ?? null;
44
14
  }
@@ -55,9 +25,7 @@ export class PluginManager {
55
25
  if (result === false)
56
26
  return false;
57
27
  }
58
- catch {
59
- /* error isolation */
60
- }
28
+ catch { /* error isolation */ }
61
29
  }
62
30
  }
63
31
  return true;
@@ -68,9 +36,7 @@ export class PluginManager {
68
36
  try {
69
37
  await plugin.onAfterTool(ctx, call, result);
70
38
  }
71
- catch {
72
- /* error isolation */
73
- }
39
+ catch { /* error isolation */ }
74
40
  }
75
41
  }
76
42
  }
@@ -80,9 +46,7 @@ export class PluginManager {
80
46
  try {
81
47
  await plugin.onError(ctx, error);
82
48
  }
83
- catch {
84
- /* error isolation */
85
- }
49
+ catch { /* error isolation */ }
86
50
  }
87
51
  }
88
52
  }
@@ -92,9 +56,7 @@ export class PluginManager {
92
56
  try {
93
57
  plugin.onSessionStart(ctx);
94
58
  }
95
- catch {
96
- /* error isolation */
97
- }
59
+ catch { /* error isolation */ }
98
60
  }
99
61
  }
100
62
  }
@@ -104,9 +66,7 @@ export class PluginManager {
104
66
  try {
105
67
  plugin.onBeforeThink(ctx);
106
68
  }
107
- catch {
108
- /* error isolation */
109
- }
69
+ catch { /* error isolation */ }
110
70
  }
111
71
  }
112
72
  }
@@ -116,9 +76,7 @@ export class PluginManager {
116
76
  try {
117
77
  plugin.onAfterThink(ctx, response);
118
78
  }
119
- catch {
120
- /* error isolation */
121
- }
79
+ catch { /* error isolation */ }
122
80
  }
123
81
  }
124
82
  }
@@ -128,9 +86,7 @@ export class PluginManager {
128
86
  try {
129
87
  plugin.onSessionEnd(ctx);
130
88
  }
131
- catch {
132
- /* error isolation */
133
- }
89
+ catch { /* error isolation */ }
134
90
  }
135
91
  }
136
92
  }
@@ -140,9 +96,7 @@ export class PluginManager {
140
96
  try {
141
97
  plugin.onToolCall(ctx);
142
98
  }
143
- catch {
144
- /* error isolation */
145
- }
99
+ catch { /* error isolation */ }
146
100
  }
147
101
  }
148
102
  }
@@ -152,9 +106,7 @@ export class PluginManager {
152
106
  try {
153
107
  plugin.onPhase(ctx, phase);
154
108
  }
155
- catch {
156
- /* error isolation */
157
- }
109
+ catch { /* error isolation */ }
158
110
  }
159
111
  }
160
112
  }
@@ -164,9 +116,7 @@ export class PluginManager {
164
116
  try {
165
117
  plugin.onToolStart(ctx, call);
166
118
  }
167
- catch {
168
- /* error isolation */
169
- }
119
+ catch { /* error isolation */ }
170
120
  }
171
121
  }
172
122
  }
@@ -176,9 +126,7 @@ export class PluginManager {
176
126
  try {
177
127
  plugin.onToolEnd(ctx, call, result, durationMs);
178
128
  }
179
- catch {
180
- /* error isolation */
181
- }
129
+ catch { /* error isolation */ }
182
130
  }
183
131
  }
184
132
  }
@@ -188,12 +136,10 @@ export class PluginManager {
188
136
  if (plugin.onText) {
189
137
  try {
190
138
  const out = plugin.onText(ctx, chunk);
191
- if (typeof out === "string")
139
+ if (typeof out === 'string')
192
140
  chunk = out;
193
141
  }
194
- catch {
195
- /* error isolation */
196
- }
142
+ catch { /* error isolation */ }
197
143
  }
198
144
  }
199
145
  return chunk;
@@ -204,12 +150,10 @@ export class PluginManager {
204
150
  if (plugin.onMeta) {
205
151
  try {
206
152
  const out = plugin.onMeta(ctx, chunk);
207
- if (typeof out === "string")
153
+ if (typeof out === 'string')
208
154
  chunk = out;
209
155
  }
210
- catch {
211
- /* error isolation */
212
- }
156
+ catch { /* error isolation */ }
213
157
  }
214
158
  }
215
159
  return chunk;
@@ -1,2 +1,2 @@
1
- export { registerKillable, unregisterKillable, killByCallId } from "./runner";
1
+ export { registerKillable, unregisterKillable, killByCallId, } from "./runner";
2
2
  export { processRegistry } from "./registry";
@@ -3,107 +3,21 @@ import { platform } from "os";
3
3
  const MAX_LOG_LINES = 2000;
4
4
  const MAX_KEPT_PROCESSES = 20;
5
5
  let seq = 0;
6
- /** OEM decoder (Russian CP866 / active code page) — cached after first use. */
7
- let oemDecoder;
8
- function getOemDecoder() {
9
- if (oemDecoder !== undefined)
10
- return oemDecoder;
11
- oemDecoder = null;
12
- try {
13
- const cpOut = spawnSync("chcp.com", {
14
- encoding: "buffer",
15
- timeout: 2000,
16
- windowsHide: true,
17
- }).stdout;
18
- const m = cpOut ? cpOut.toString("latin1").match(/(\d+)/) : null;
19
- if (m) {
20
- try {
21
- oemDecoder = new TextDecoder("ibm" + m[1]);
22
- }
23
- catch {
24
- oemDecoder = null;
25
- }
26
- }
27
- }
28
- catch {
29
- /* ignore */
30
- }
31
- if (!oemDecoder) {
32
- try {
33
- oemDecoder = new TextDecoder("ibm866");
34
- }
35
- catch {
36
- oemDecoder = null;
37
- }
38
- }
39
- return oemDecoder;
40
- }
41
- /**
42
- * Decode one complete line of output to UTF-8.
43
- *
44
- * Modern tools (Bun, Node, npm, git) write UTF-8 into the pipe regardless of
45
- * the console code page, while built-in cmd.exe commands (echo, type, dir)
46
- * emit the OEM code page (CP866 on Russian Windows). Try strict UTF-8 first;
47
- * fall back to the OEM decoder when the bytes are not valid UTF-8.
48
- */
49
- function decodeLineToUtf8(buf) {
50
- try {
51
- return new TextDecoder("utf-8", { fatal: true }).decode(buf);
52
- }
53
- catch {
54
- /* not valid UTF-8 → OEM code page output */
55
- }
56
- const oem = getOemDecoder();
57
- if (oem) {
58
- try {
59
- return oem.decode(buf);
60
- }
61
- catch {
62
- /* unknown encoding — latin1 fallback */
63
- }
64
- }
65
- return buf.toString("latin1");
66
- }
67
- /** Synchronous pause without blocking the event loop (via Atomics.wait). */
68
- function sleepSync(ms) {
69
- try {
70
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
71
- }
72
- catch {
73
- /* ignore */
74
- }
75
- }
76
- function taskkillPid(pid) {
77
- try {
78
- spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], {
79
- windowsHide: true,
80
- stdio: "ignore",
81
- timeout: 5000,
82
- });
83
- }
84
- catch {
85
- /* already dead */
86
- }
87
- }
88
- /**
89
- * Kill a spawned tree on Windows.
90
- *
91
- * `taskkill /T` has a race: when cmd.exe is killed, a child (node) that is
92
- * still starting up can survive as an orphan because it was never attached to
93
- * the tree at kill time. A single pass misses it. Running taskkill twice with
94
- * a settle gap catches those late starters on the second pass — the second
95
- * tree walk sees the child that was still being created during the first one.
96
- * This is much cheaper than enumerating processes (wmic/PowerShell), which
97
- * slows every kill down to seconds under parallel load.
98
- */
99
- export function killTree(child) {
6
+ function killTree(child) {
100
7
  const pid = child.pid;
101
8
  if (!pid)
102
9
  return;
103
10
  if (platform() === "win32") {
104
- taskkillPid(pid);
105
- sleepSync(150);
106
- taskkillPid(pid);
11
+ try {
12
+ spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], {
13
+ windowsHide: true,
14
+ stdio: "ignore",
15
+ timeout: 3000,
16
+ });
17
+ }
18
+ catch {
19
+ /* already dead */
20
+ }
107
21
  return;
108
22
  }
109
23
  try {
@@ -159,10 +73,31 @@ class ProcessRegistry {
159
73
  }
160
74
  this.children.set(id, child);
161
75
  entry.pid = child.pid ?? 0;
76
+ // On Windows, children spawned via cmd.exe output in the OEM code page,
77
+ // NOT UTF-8. Detect the active code page via chcp.com; fall back to
78
+ // ibm866 (Russian CP866) when detection fails — still correct for the
79
+ // majority of users, and always better than the UTF-8 default.
80
+ const decoder = platform() === "win32"
81
+ ? (() => {
82
+ try {
83
+ const cpOut = require("child_process")
84
+ .execSync("chcp.com", {
85
+ encoding: "buffer",
86
+ timeout: 2000,
87
+ windowsHide: true,
88
+ })
89
+ .toString("latin1");
90
+ const m = cpOut.match(/(\d+)/);
91
+ if (m)
92
+ return new TextDecoder("ibm" + m[1]);
93
+ }
94
+ catch {
95
+ /* ignore */
96
+ }
97
+ return new TextDecoder("ibm866");
98
+ })()
99
+ : new TextDecoder("utf-8");
162
100
  let buf = "";
163
- let byteBuf = Buffer.alloc(0);
164
- const isWin = platform() === "win32";
165
- const unixDecoder = new TextDecoder("utf-8");
166
101
  const pushLine = (line) => {
167
102
  if (entry.log.length >= MAX_LOG_LINES) {
168
103
  entry.log.shift();
@@ -170,40 +105,19 @@ class ProcessRegistry {
170
105
  entry.log.push(line);
171
106
  };
172
107
  const append = (chunk) => {
173
- if (!isWin) {
174
- const decoded = unixDecoder.decode(chunk, { stream: true });
175
- buf += decoded;
176
- const lines = buf.split(/\r?\n/);
177
- buf = lines.pop() ?? "";
178
- for (const line of lines) {
179
- pushLine(line);
180
- }
181
- return;
182
- }
183
- // Windows: buffer raw bytes and decode per line. Modern tools (Bun, Node,
184
- // npm, git) write UTF-8 into the pipe regardless of the console code
185
- // page; cmd.exe builtins (echo, type, dir) emit the OEM code page. Pick
186
- // the right decoding per line so Russian text survives either way.
187
- byteBuf = byteBuf.length ? Buffer.concat([byteBuf, chunk]) : Buffer.from(chunk);
188
- let nl;
189
- while ((nl = byteBuf.indexOf(0x0a)) !== -1) {
190
- const raw = byteBuf.subarray(0, nl);
191
- byteBuf = byteBuf.subarray(nl + 1);
192
- pushLine(decodeLineToUtf8(raw).replace(/\r$/, ""));
108
+ const decoded = decoder.decode(chunk, { stream: true });
109
+ buf += decoded;
110
+ const lines = buf.split(/\r?\n/);
111
+ buf = lines.pop() ?? "";
112
+ for (const line of lines) {
113
+ pushLine(line);
193
114
  }
194
115
  };
195
116
  const flush = () => {
196
- if (!isWin) {
197
- buf += unixDecoder.decode();
198
- if (buf) {
199
- pushLine(buf);
200
- buf = "";
201
- }
202
- return;
203
- }
204
- if (byteBuf.length) {
205
- pushLine(decodeLineToUtf8(byteBuf));
206
- byteBuf = Buffer.alloc(0);
117
+ buf += decoder.decode();
118
+ if (buf) {
119
+ pushLine(buf);
120
+ buf = "";
207
121
  }
208
122
  };
209
123
  const resolveExit = () => {
@@ -216,10 +130,7 @@ class ProcessRegistry {
216
130
  entry.status = "killed";
217
131
  }
218
132
  entry.spawnError = err.message;
219
- // Write directly to the log, not through `append`: a failed spawn often
220
- // never emits `close`, so the buffered line would never be flushed and
221
- // the log would be empty (observed: "records a spawn error" test).
222
- pushLine(`[process error] ${err.message}`);
133
+ append(Buffer.from(`[process error] ${err.message}`));
223
134
  resolveExit();
224
135
  });
225
136
  child.on("close", (code) => {
@@ -9,11 +9,9 @@ export class ModuleRegistry {
9
9
  listModules() {
10
10
  return Array.from(this.modules.keys()).sort();
11
11
  }
12
- collectPromptBlocks(exclude = []) {
12
+ collectPromptBlocks() {
13
13
  const blocks = [];
14
- for (const [name, mod] of this.modules) {
15
- if (exclude.includes(name))
16
- continue;
14
+ for (const mod of this.modules.values()) {
17
15
  if (mod.getSystemPromptBlock) {
18
16
  const block = mod.getSystemPromptBlock();
19
17
  if (block)
@@ -1,6 +1,6 @@
1
- import { writeFileSync, appendFileSync, existsSync, mkdirSync } from "fs";
2
- import { join, dirname } from "path";
3
- import { homedir } from "os";
1
+ import { writeFileSync, appendFileSync, existsSync, mkdirSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { homedir } from 'os';
4
4
  /**
5
5
  * Severity weights for comparison
6
6
  */
@@ -15,16 +15,16 @@ const SEVERITY_WEIGHTS = {
15
15
  */
16
16
  export const DEFAULT_AUDIT_NOTIFIER_CONFIG = {
17
17
  enabled: false,
18
- filePath: join(homedir(), ".mma", "logs", "audit-notifications.jsonl"),
18
+ filePath: join(homedir(), '.mma', 'logs', 'audit-notifications.jsonl'),
19
19
  webhookTimeout: 5000,
20
- minSeverity: "medium",
20
+ minSeverity: 'medium',
21
21
  eventTypes: [
22
- "security_block",
23
- "bash_command",
24
- "file_operation",
25
- "network_request",
26
- "authentication",
27
- "configuration_change",
22
+ 'security_block',
23
+ 'bash_command',
24
+ 'file_operation',
25
+ 'network_request',
26
+ 'authentication',
27
+ 'configuration_change',
28
28
  ],
29
29
  maxRetries: 3,
30
30
  };
@@ -85,7 +85,7 @@ export class AuditNotifier {
85
85
  * Check if a severity level should be notified
86
86
  */
87
87
  shouldNotifySeverity(severity) {
88
- const minSeverity = this.config.minSeverity ?? "medium";
88
+ const minSeverity = this.config.minSeverity ?? 'medium';
89
89
  const minWeight = SEVERITY_WEIGHTS[minSeverity];
90
90
  const eventWeight = SEVERITY_WEIGHTS[severity];
91
91
  return eventWeight >= minWeight;
@@ -123,12 +123,12 @@ export class AuditNotifier {
123
123
  */
124
124
  mapEventType(action) {
125
125
  const typeMap = {
126
- tool_call: "tool_call",
127
- bash_command: "bash_command",
128
- file_write: "file_operation",
129
- file_delete: "file_operation",
130
- network_request: "network_request",
131
- security_block: "security_block",
126
+ 'tool_call': 'tool_call',
127
+ 'bash_command': 'bash_command',
128
+ 'file_write': 'file_operation',
129
+ 'file_delete': 'file_operation',
130
+ 'network_request': 'network_request',
131
+ 'security_block': 'security_block',
132
132
  };
133
133
  return typeMap[action] || null;
134
134
  }
@@ -138,16 +138,16 @@ export class AuditNotifier {
138
138
  determineSeverity(entry) {
139
139
  // Default severity based on action type
140
140
  const typeSeverity = {
141
- security_block: "high",
142
- bash_command: "high",
143
- file_delete: "medium",
144
- file_write: "medium",
145
- network_request: "medium",
146
- tool_call: "low",
147
- session_start: "low",
148
- session_end: "low",
141
+ 'security_block': 'high',
142
+ 'bash_command': 'high',
143
+ 'file_delete': 'medium',
144
+ 'file_write': 'medium',
145
+ 'network_request': 'medium',
146
+ 'tool_call': 'low',
147
+ 'session_start': 'low',
148
+ 'session_end': 'low',
149
149
  };
150
- return typeSeverity[entry.action] || "low";
150
+ return typeSeverity[entry.action] || 'low';
151
151
  }
152
152
  /**
153
153
  * Write notification to file
@@ -157,10 +157,10 @@ export class AuditNotifier {
157
157
  return;
158
158
  try {
159
159
  const line = JSON.stringify(notification);
160
- appendFileSync(this.config.filePath, line + "\n", "utf8");
160
+ appendFileSync(this.config.filePath, line + '\n', 'utf8');
161
161
  }
162
162
  catch (error) {
163
- console.error("[AuditNotifier] Failed to write to file:", error);
163
+ console.error('[AuditNotifier] Failed to write to file:', error);
164
164
  }
165
165
  }
166
166
  /**
@@ -173,8 +173,8 @@ export class AuditNotifier {
173
173
  const controller = new AbortController();
174
174
  const timeoutId = setTimeout(() => controller.abort(), this.config.webhookTimeout);
175
175
  const response = await fetch(this.config.webhookUrl, {
176
- method: "POST",
177
- headers: { "Content-Type": "application/json" },
176
+ method: 'POST',
177
+ headers: { 'Content-Type': 'application/json' },
178
178
  body: JSON.stringify(notification),
179
179
  signal: controller.signal,
180
180
  });
@@ -184,7 +184,7 @@ export class AuditNotifier {
184
184
  }
185
185
  }
186
186
  catch (error) {
187
- console.error("[AuditNotifier] Webhook failed, adding to retry queue:", error);
187
+ console.error('[AuditNotifier] Webhook failed, adding to retry queue:', error);
188
188
  this.addToRetryQueue(notification);
189
189
  }
190
190
  }
@@ -207,7 +207,7 @@ export class AuditNotifier {
207
207
  while (this.retryQueue.length > 0) {
208
208
  const item = this.retryQueue[0];
209
209
  if (item.retries >= (this.config.maxRetries ?? 3)) {
210
- console.error("[AuditNotifier] Max retries exceeded for notification:", item.entry);
210
+ console.error('[AuditNotifier] Max retries exceeded for notification:', item.entry);
211
211
  this.retryQueue.shift();
212
212
  continue;
213
213
  }
@@ -219,7 +219,7 @@ export class AuditNotifier {
219
219
  item.retries++;
220
220
  // Exponential backoff
221
221
  const delay = Math.pow(2, item.retries) * 1000;
222
- await new Promise((resolve) => setTimeout(resolve, delay));
222
+ await new Promise(resolve => setTimeout(resolve, delay));
223
223
  }
224
224
  }
225
225
  this.isProcessing = false;
@@ -232,9 +232,9 @@ export class AuditNotifier {
232
232
  return [];
233
233
  }
234
234
  try {
235
- const content = readFileSync(this.config.filePath, "utf8");
236
- const lines = content.split("\n").filter(Boolean);
237
- return lines.slice(-limit).map((line) => JSON.parse(line));
235
+ const content = readFileSync(this.config.filePath, 'utf8');
236
+ const lines = content.split('\n').filter(Boolean);
237
+ return lines.slice(-limit).map(line => JSON.parse(line));
238
238
  }
239
239
  catch {
240
240
  return [];
@@ -245,7 +245,7 @@ export class AuditNotifier {
245
245
  */
246
246
  clearNotifications() {
247
247
  if (this.config.filePath) {
248
- writeFileSync(this.config.filePath, "", "utf8");
248
+ writeFileSync(this.config.filePath, '', 'utf8');
249
249
  }
250
250
  this.retryQueue = [];
251
251
  }
@@ -289,4 +289,4 @@ export function createAuditNotifier(config) {
289
289
  return new AuditNotifier(config);
290
290
  }
291
291
  // Import readFileSync for readNotifications
292
- import { readFileSync } from "fs";
292
+ import { readFileSync } from 'fs';
@@ -46,7 +46,11 @@ function extractBaseCommand(trimmed) {
46
46
  i++;
47
47
  continue;
48
48
  }
49
- if (tok === "sudo" || tok === "env" || tok === "command" || tok === "exec" || tok === "nohup") {
49
+ if (tok === "sudo" ||
50
+ tok === "env" ||
51
+ tok === "command" ||
52
+ tok === "exec" ||
53
+ tok === "nohup") {
50
54
  i++;
51
55
  continue;
52
56
  }
@@ -146,7 +150,9 @@ export function isCommandAllowed(command, securityConfig) {
146
150
  };
147
151
  }
148
152
  // Also check the raw first token in case it's a simple name
149
- const rawFirst = trimmedCommand.split(/\s+/)[0].replace(/\.(exe|cmd|bat)$/i, "");
153
+ const rawFirst = trimmedCommand
154
+ .split(/\s+/)[0]
155
+ .replace(/\.(exe|cmd|bat)$/i, "");
150
156
  if (rawFirst !== baseCommand && config.blacklist.includes(rawFirst)) {
151
157
  return {
152
158
  allowed: false,
@@ -73,7 +73,15 @@ export function sanitizeCommand(command) {
73
73
  export function sanitizeUrl(url) {
74
74
  try {
75
75
  const urlObj = new URL(url);
76
- const sensitiveKeys = ["api_key", "token", "password", "secret", "access_token", "auth", "key"];
76
+ const sensitiveKeys = [
77
+ "api_key",
78
+ "token",
79
+ "password",
80
+ "secret",
81
+ "access_token",
82
+ "auth",
83
+ "key",
84
+ ];
77
85
  const sanitizedParams = new URLSearchParams(urlObj.search);
78
86
  for (const key of sensitiveKeys) {
79
87
  if (sanitizedParams.has(key)) {