micro-models-agent 0.43.3 → 0.45.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 (188) hide show
  1. package/README.md +312 -312
  2. package/bin/mma.mjs +41 -41
  3. package/dist/main.js +333 -66
  4. package/dist/skills/builtin/git.md +36 -36
  5. package/dist/skills/builtin/typescript.md +35 -35
  6. package/package.json +1 -1
  7. package/dist/cli/commands.js +0 -333
  8. package/dist/cli/completer.js +0 -168
  9. package/dist/cli/index.js +0 -2
  10. package/dist/cli/main.js +0 -140
  11. package/dist/cli/repl-commands.js +0 -633
  12. package/dist/cli/repl.js +0 -486
  13. package/dist/cli/security-commands.js +0 -166
  14. package/dist/cli/setup.js +0 -249
  15. package/dist/config/config.js +0 -202
  16. package/dist/config/defaults.js +0 -100
  17. package/dist/config/experts.js +0 -15
  18. package/dist/config/index.js +0 -3
  19. package/dist/config/security.js +0 -200
  20. package/dist/config/types.js +0 -1
  21. package/dist/core/agent-moe.js +0 -110
  22. package/dist/core/agent.js +0 -695
  23. package/dist/core/bootstrap.js +0 -337
  24. package/dist/core/index.js +0 -2
  25. package/dist/core/prompt-builder.js +0 -55
  26. package/dist/core/session-logger.js +0 -155
  27. package/dist/core/types.js +0 -1
  28. package/dist/core/workspace.js +0 -76
  29. package/dist/i18n/en.json +0 -525
  30. package/dist/i18n/index.js +0 -46
  31. package/dist/i18n/ru.json +0 -525
  32. package/dist/index.js +0 -22
  33. package/dist/llm/image-utils.js +0 -144
  34. package/dist/llm/index.js +0 -4
  35. package/dist/llm/model-loader.js +0 -78
  36. package/dist/llm/openai-compat.js +0 -353
  37. package/dist/llm/orchestrator.js +0 -194
  38. package/dist/llm/provider.js +0 -10
  39. package/dist/llm/response.js +0 -39
  40. package/dist/llm/token-counter.js +0 -39
  41. package/dist/llm/types.js +0 -1
  42. package/dist/logger/app-logger.js +0 -143
  43. package/dist/logger/file-log.js +0 -151
  44. package/dist/logger/index.js +0 -1
  45. package/dist/migration/backup.js +0 -45
  46. package/dist/migration/detect.js +0 -50
  47. package/dist/migration/index.js +0 -2
  48. package/dist/modules/browser/actions.js +0 -46
  49. package/dist/modules/browser/cookie-store.js +0 -24
  50. package/dist/modules/browser/index.js +0 -5
  51. package/dist/modules/browser/module.js +0 -28
  52. package/dist/modules/browser/session.js +0 -335
  53. package/dist/modules/browser/snapshot.js +0 -114
  54. package/dist/modules/browser/types.js +0 -9
  55. package/dist/modules/certification/cli.js +0 -176
  56. package/dist/modules/certification/fact-checker.js +0 -84
  57. package/dist/modules/certification/loader.js +0 -111
  58. package/dist/modules/certification/manifest.js +0 -50
  59. package/dist/modules/certification/runner.js +0 -162
  60. package/dist/modules/certification/scenarios.js +0 -124
  61. package/dist/modules/certification/types.js +0 -1
  62. package/dist/modules/context/index.js +0 -1
  63. package/dist/modules/context/manager.js +0 -349
  64. package/dist/modules/execution/auditor.js +0 -66
  65. package/dist/modules/execution/index.js +0 -8
  66. package/dist/modules/execution/module.js +0 -779
  67. package/dist/modules/execution/moe-executor.js +0 -266
  68. package/dist/modules/execution/plan-coverage.js +0 -68
  69. package/dist/modules/execution/plan-persister.js +0 -46
  70. package/dist/modules/execution/plan-store.js +0 -159
  71. package/dist/modules/execution/plan-validator.js +0 -153
  72. package/dist/modules/execution/planner.js +0 -85
  73. package/dist/modules/execution/stuck-detector.js +0 -347
  74. package/dist/modules/execution/tracker.js +0 -67
  75. package/dist/modules/execution/types.js +0 -1
  76. package/dist/modules/execution/verifier.js +0 -178
  77. package/dist/modules/hallucination/confidence.js +0 -59
  78. package/dist/modules/hallucination/consistency.js +0 -26
  79. package/dist/modules/hallucination/detector.js +0 -46
  80. package/dist/modules/hallucination/factual.js +0 -190
  81. package/dist/modules/hallucination/index.js +0 -5
  82. package/dist/modules/hallucination/js-identifiers.js +0 -72
  83. package/dist/modules/hallucination/llm-judge.js +0 -103
  84. package/dist/modules/index.js +0 -5
  85. package/dist/modules/indexer/cache.js +0 -38
  86. package/dist/modules/indexer/index.js +0 -3
  87. package/dist/modules/indexer/module.js +0 -192
  88. package/dist/modules/indexer/walker.js +0 -101
  89. package/dist/modules/lsp/client.js +0 -235
  90. package/dist/modules/lsp/config.js +0 -81
  91. package/dist/modules/lsp/index.js +0 -3
  92. package/dist/modules/lsp/module.js +0 -68
  93. package/dist/modules/lsp/types.js +0 -1
  94. package/dist/modules/mcp/client.js +0 -399
  95. package/dist/modules/mcp/index.js +0 -3
  96. package/dist/modules/mcp/module.js +0 -146
  97. package/dist/modules/mcp/registry.js +0 -15
  98. package/dist/modules/memory/index.js +0 -1
  99. package/dist/modules/memory/module.js +0 -48
  100. package/dist/modules/memory/search.js +0 -40
  101. package/dist/modules/memory/store.js +0 -69
  102. package/dist/modules/pipelines/engine.js +0 -60
  103. package/dist/modules/pipelines/index.js +0 -3
  104. package/dist/modules/pipelines/parser.js +0 -53
  105. package/dist/modules/pipelines/template.js +0 -14
  106. package/dist/modules/plugins/builtin/lint-on-write.js +0 -226
  107. package/dist/modules/plugins/builtin/notify.js +0 -8
  108. package/dist/modules/plugins/index.js +0 -1
  109. package/dist/modules/plugins/loader.js +0 -28
  110. package/dist/modules/plugins/manager.js +0 -161
  111. package/dist/modules/plugins/types.js +0 -1
  112. package/dist/modules/processes/index.js +0 -2
  113. package/dist/modules/processes/registry.js +0 -238
  114. package/dist/modules/processes/runner.js +0 -23
  115. package/dist/modules/registry.js +0 -45
  116. package/dist/modules/security/audit-log.js +0 -136
  117. package/dist/modules/security/audit-notifier.js +0 -292
  118. package/dist/modules/security/command-validator.js +0 -211
  119. package/dist/modules/security/content-scanner.js +0 -53
  120. package/dist/modules/security/data-sanitizer.js +0 -97
  121. package/dist/modules/security/encryption.js +0 -240
  122. package/dist/modules/security/index.js +0 -14
  123. package/dist/modules/security/network-validator.js +0 -79
  124. package/dist/modules/security/path-validator.js +0 -209
  125. package/dist/modules/security/rate-limiter.js +0 -119
  126. package/dist/modules/security/security-policies.js +0 -547
  127. package/dist/modules/security/session-encryption.js +0 -210
  128. package/dist/modules/security/session-isolation.js +0 -95
  129. package/dist/modules/session/index.js +0 -3
  130. package/dist/modules/session/manager.js +0 -172
  131. package/dist/modules/session/module.js +0 -24
  132. package/dist/modules/session/store.js +0 -228
  133. package/dist/modules/session/types.js +0 -1
  134. package/dist/modules/skills/index.js +0 -2
  135. package/dist/modules/skills/loader.js +0 -72
  136. package/dist/modules/skills/module.js +0 -130
  137. package/dist/modules/types.js +0 -1
  138. package/dist/modules/updater/checker.js +0 -32
  139. package/dist/modules/updater/index.js +0 -1
  140. package/dist/modules/user-profile/compressor.js +0 -16
  141. package/dist/modules/user-profile/index.js +0 -1
  142. package/dist/modules/user-profile/profile.js +0 -68
  143. package/dist/tools/approve.js +0 -32
  144. package/dist/tools/attach-image.js +0 -89
  145. package/dist/tools/bash.js +0 -337
  146. package/dist/tools/browser.js +0 -97
  147. package/dist/tools/create-dir.js +0 -55
  148. package/dist/tools/delete-file.js +0 -62
  149. package/dist/tools/edit-file.js +0 -79
  150. package/dist/tools/executor.js +0 -145
  151. package/dist/tools/file-info.js +0 -45
  152. package/dist/tools/filter-tools.js +0 -10
  153. package/dist/tools/glob-tool.js +0 -26
  154. package/dist/tools/grep-tool.js +0 -86
  155. package/dist/tools/index.js +0 -67
  156. package/dist/tools/list-dir.js +0 -47
  157. package/dist/tools/load-skill.js +0 -44
  158. package/dist/tools/mcp-call.js +0 -68
  159. package/dist/tools/move-file.js +0 -85
  160. package/dist/tools/path-utils.js +0 -51
  161. package/dist/tools/pipeline-run.js +0 -144
  162. package/dist/tools/preview.js +0 -2
  163. package/dist/tools/process-kill.js +0 -29
  164. package/dist/tools/process-list.js +0 -38
  165. package/dist/tools/process-log.js +0 -41
  166. package/dist/tools/question.js +0 -142
  167. package/dist/tools/read-file.js +0 -83
  168. package/dist/tools/recall.js +0 -110
  169. package/dist/tools/registry.js +0 -36
  170. package/dist/tools/remember.js +0 -67
  171. package/dist/tools/scope-check.js +0 -30
  172. package/dist/tools/search-history.js +0 -84
  173. package/dist/tools/subagent.js +0 -151
  174. package/dist/tools/types.js +0 -1
  175. package/dist/tools/user-input.js +0 -123
  176. package/dist/tools/web-browse.js +0 -86
  177. package/dist/tools/web-fetch.js +0 -98
  178. package/dist/tools/web-search.js +0 -78
  179. package/dist/tools/write-file.js +0 -83
  180. package/dist/ui/box.js +0 -81
  181. package/dist/ui/colors.js +0 -4
  182. package/dist/ui/diff.js +0 -178
  183. package/dist/ui/index.js +0 -6
  184. package/dist/ui/md-formatter.js +0 -212
  185. package/dist/ui/output.js +0 -13
  186. package/dist/ui/renderer.js +0 -204
  187. package/dist/ui/spinner.js +0 -70
  188. package/dist/ui/table.js +0 -144
package/dist/cli/repl.js DELETED
@@ -1,486 +0,0 @@
1
- import * as readline from "readline";
2
- import { pc } from "../ui/colors";
3
- import { existsSync, readFileSync, writeFileSync } from "fs";
4
- import { join, dirname } from "path";
5
- import { homedir } from "os";
6
- import { fileURLToPath } from "url";
7
- import { Completer, SlashCommandProvider, SessionNameProvider, SubcommandProvider, SkillNameProvider, } from "./completer";
8
- import { Renderer } from "../ui/renderer";
9
- import { box } from "../ui/box";
10
- import { t } from "../i18n/index";
11
- import { registerAllCommands } from "./repl-commands";
12
- function readVersion() {
13
- const here = dirname(fileURLToPath(import.meta.url));
14
- const candidates = [
15
- join(here, "..", "..", "package.json"),
16
- join(here, "..", "package.json"),
17
- ];
18
- for (const p of candidates) {
19
- if (existsSync(p)) {
20
- try {
21
- const raw = JSON.parse(readFileSync(p, "utf8"));
22
- if (raw.version)
23
- return raw.version;
24
- }
25
- catch {
26
- // Broken package.json — fall through to the next candidate
27
- }
28
- }
29
- }
30
- return "0.0.0";
31
- }
32
- const version = readVersion();
33
- function formatContextBar(used, limit, compactions, quality) {
34
- const pct = Math.min(100, Math.round((used / limit) * 100));
35
- const barLen = 20;
36
- const filled = Math.round((pct / 100) * barLen);
37
- const bar = pc.green("█".repeat(filled)) + pc.dim("░".repeat(barLen - filled));
38
- const pctStr = pct >= 75 ? pc.yellow(`${pct}%`) : pc.dim(`${pct}%`);
39
- let line = ` ${bar} ${pctStr} ${pc.dim(`(${used} / ${limit} tokens)`)}`;
40
- if (compactions !== undefined) {
41
- line += pc.dim(` compactions: ${compactions}`);
42
- }
43
- if (quality !== undefined) {
44
- const qColor = quality >= 70 ? pc.green : quality >= 40 ? pc.yellow : pc.red;
45
- line += ` ${qColor(`quality: ${quality}%`)}`;
46
- }
47
- return line;
48
- }
49
- export class Repl {
50
- completer = new Completer();
51
- running = false;
52
- agentRunning = false;
53
- inputLocked = false;
54
- historyPath;
55
- history = [];
56
- maxHistory = 1000;
57
- lastEscTime = 0;
58
- doubleEscDelay = 500;
59
- configDir;
60
- baseDir;
61
- noAgentsMd;
62
- pendingClipboardImage = null;
63
- rl;
64
- agent;
65
- config;
66
- sessionManager;
67
- skillsModule;
68
- pluginManager;
69
- logger;
70
- constructor(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger) {
71
- this.agent = agent;
72
- this.config = config;
73
- this.sessionManager = sessionManager;
74
- this.skillsModule = skillsModule;
75
- this.pluginManager = pluginManager;
76
- this.logger = logger;
77
- this.configDir = configDir || join(homedir(), ".mma");
78
- this.baseDir = baseDir || process.cwd();
79
- this.noAgentsMd = noAgentsMd === true;
80
- this.historyPath = join(homedir(), ".mma", "repl-history");
81
- this.loadHistory();
82
- this.rl = readline.createInterface({
83
- input: process.stdin,
84
- output: process.stdout,
85
- prompt: pc.cyan("> "),
86
- history: this.history,
87
- historySize: this.maxHistory,
88
- tabSize: 2,
89
- completer: (line) => {
90
- const [matches, partial] = this.completer.complete(line);
91
- if (matches.length > 0)
92
- return [matches, partial];
93
- return [[], line];
94
- },
95
- });
96
- registerAllCommands(this);
97
- this.setupCompleter();
98
- this.setupListeners();
99
- }
100
- loadHistory() {
101
- if (existsSync(this.historyPath)) {
102
- try {
103
- const raw = readFileSync(this.historyPath, "utf-8");
104
- this.history = raw.split("\n").filter(Boolean).slice(-this.maxHistory);
105
- }
106
- catch {
107
- this.history = [];
108
- }
109
- }
110
- }
111
- saveHistory() {
112
- const allHistory = this.history.slice(-this.maxHistory);
113
- writeFileSync(this.historyPath, allHistory.join("\n"), "utf-8");
114
- }
115
- setupCompleter() {
116
- const slashCommands = Array.from(this.commands.keys());
117
- this.completer.registerProvider(new SlashCommandProvider(slashCommands));
118
- if (this.sessionManager) {
119
- this.completer.registerProvider(new SessionNameProvider(() => this.sessionManager.list().map((s) => s.name)));
120
- }
121
- if (this.skillsModule) {
122
- this.completer.registerProvider(new SubcommandProvider("skill", [
123
- "list",
124
- "loaded",
125
- "load",
126
- "unload",
127
- "search",
128
- ]));
129
- this.completer.registerProvider(new SkillNameProvider(this.skillsModule));
130
- }
131
- }
132
- setupListeners() {
133
- let multiLineBuffer = "";
134
- let inMultiLine = false;
135
- this.rl.on("line", async (line) => {
136
- const trimmed = line.trim();
137
- if (this.agentRunning || this.inputLocked) {
138
- if (trimmed) {
139
- this.history.push(trimmed);
140
- if (this.history.length > this.maxHistory) {
141
- this.history = this.history.slice(-this.maxHistory);
142
- }
143
- }
144
- return;
145
- }
146
- if (trimmed) {
147
- this.history.push(trimmed);
148
- if (this.history.length > this.maxHistory) {
149
- this.history = this.history.slice(-this.maxHistory);
150
- }
151
- }
152
- if (inMultiLine) {
153
- multiLineBuffer += "\n" + line;
154
- if (!this.isMultiLineInput(multiLineBuffer)) {
155
- inMultiLine = false;
156
- const fullInput = multiLineBuffer.trim();
157
- multiLineBuffer = "";
158
- if (fullInput) {
159
- if (fullInput.startsWith("/")) {
160
- await this.executeCommand(fullInput);
161
- }
162
- else {
163
- await this.runAgent(fullInput);
164
- }
165
- }
166
- if (this.running) {
167
- this.rl.setPrompt(pc.cyan("> "));
168
- this.rl.prompt();
169
- }
170
- }
171
- else {
172
- this.rl.setPrompt(pc.cyan("... "));
173
- this.rl.prompt();
174
- }
175
- return;
176
- }
177
- if (this.isMultiLineInput(trimmed)) {
178
- inMultiLine = true;
179
- multiLineBuffer = trimmed;
180
- this.rl.setPrompt(pc.cyan("... "));
181
- this.rl.prompt();
182
- return;
183
- }
184
- if (!trimmed) {
185
- this.rl.prompt();
186
- return;
187
- }
188
- if (trimmed.startsWith("/")) {
189
- await this.executeCommand(trimmed);
190
- }
191
- else {
192
- await this.runAgent(trimmed);
193
- }
194
- if (this.running) {
195
- this.rl.prompt();
196
- }
197
- });
198
- this.rl.on("close", () => {
199
- this.running = false;
200
- });
201
- if (process.stdin.isTTY) {
202
- readline.emitKeypressEvents(process.stdin);
203
- process.stdin.on("keypress", async (str, key) => {
204
- if (key.name === "escape") {
205
- // Bun/Node's readline collapses a fast double-Esc into a single
206
- // keypress whose `sequence` contains two ESC bytes ("\x1b\x1b").
207
- // Counting bytes (not events) catches both the collapsed case and
208
- // the case where two separate escape keypresses land in the window.
209
- const escBytes = key.sequence
210
- ? (key.sequence.match(/\x1b/g) || []).length
211
- : 1;
212
- const now = Date.now();
213
- const withinWindow = now - this.lastEscTime < this.doubleEscDelay;
214
- this.lastEscTime = now;
215
- if (escBytes >= 2 || withinWindow) {
216
- this.lastEscTime = 0;
217
- if (this.agentRunning) {
218
- process.stdout.write(pc.yellow(`\n${t("repl.interrupt")}\n`));
219
- this.agent.shutdown();
220
- }
221
- }
222
- return;
223
- }
224
- if (key.ctrl && key.name === "v" && !this.agentRunning) {
225
- try {
226
- const { readClipboardImage, bufferToDataUrl } = await import("../llm/image-utils");
227
- const clipBuf = await readClipboardImage();
228
- if (clipBuf) {
229
- const { dataUrl } = await bufferToDataUrl(clipBuf);
230
- this.pendingClipboardImage = dataUrl;
231
- const sizeKb = Math.round((dataUrl.length * 3) / 4 / 1024);
232
- console.log(pc.green(`\n${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
233
- this.rl.prompt();
234
- }
235
- else {
236
- console.log(pc.yellow(`\n${t("image.clipboard_empty")}`));
237
- this.rl.prompt();
238
- }
239
- }
240
- catch {
241
- // clipboard read failed — ignore, let terminal paste text normally
242
- }
243
- }
244
- });
245
- }
246
- let forceExitTimer = null;
247
- process.on("SIGINT", () => {
248
- if (this.agentRunning) {
249
- console.log(pc.yellow("\n[Ctrl+C] Остановка агента... (ещё раз — принудительно)"));
250
- this.agent.shutdown();
251
- this.agentRunning = false;
252
- if (forceExitTimer)
253
- clearTimeout(forceExitTimer);
254
- forceExitTimer = setTimeout(() => process.exit(1), 2000).unref();
255
- }
256
- else {
257
- process.exit(0);
258
- }
259
- });
260
- }
261
- isMultiLineInput(line) {
262
- if (line.endsWith("\\"))
263
- return true;
264
- const openBraces = (line.match(/\{/g) || []).length;
265
- const closeBraces = (line.match(/\}/g) || []).length;
266
- if (openBraces > closeBraces)
267
- return true;
268
- return false;
269
- }
270
- async runAgent(input) {
271
- if (this.agentRunning)
272
- return;
273
- this.agentRunning = true;
274
- try {
275
- if (this.pendingClipboardImage) {
276
- const contextManager = this.agent.contextManager;
277
- if (contextManager) {
278
- contextManager.addPendingImage({
279
- type: "image_url",
280
- image_url: { url: this.pendingClipboardImage },
281
- });
282
- }
283
- this.pendingClipboardImage = null;
284
- }
285
- this.logger?.logREPL("user", input);
286
- process.stdout.write("\n" + pc.green(t("repl.agent")));
287
- const renderer = new Renderer({
288
- spinner: this.config.ui?.spinner ?? true,
289
- toolStyle: this.config.ui?.toolStyle ?? "inline",
290
- });
291
- const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
292
- if (ev.type === "start") {
293
- renderer.toolStart(ev.tool, ev.args);
294
- }
295
- else {
296
- renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
297
- }
298
- }, (phase) => {
299
- if (phase === "thinking") {
300
- renderer.thinkingStart();
301
- }
302
- else {
303
- renderer.thinkingEnd();
304
- }
305
- });
306
- renderer.flush();
307
- process.stdout.write("\n");
308
- this.logger?.logREPL(result.success ? "assistant" : "system", result.text?.slice(0, 400) || result.error || "");
309
- if (!result.success) {
310
- console.error(pc.red(`${t("error.prefix")}${result.error}`));
311
- }
312
- this.showContextBar(result);
313
- }
314
- finally {
315
- this.agentRunning = false;
316
- }
317
- }
318
- commands = new Map();
319
- registerCommand(cmd) {
320
- this.commands.set(cmd.name, cmd);
321
- if (cmd.aliases) {
322
- for (const alias of cmd.aliases) {
323
- this.commands.set(alias, cmd);
324
- }
325
- }
326
- }
327
- async withExclusiveInput(fn) {
328
- this.inputLocked = true;
329
- try {
330
- await fn();
331
- }
332
- finally {
333
- this.inputLocked = false;
334
- }
335
- }
336
- async executeCommand(input) {
337
- const parts = input.split(/\s+/);
338
- const name = parts[0].slice(1);
339
- const args = parts.slice(1);
340
- const cmd = this.commands.get(name);
341
- if (!cmd) {
342
- console.log(pc.red(t("cli.unknown_cmd", { name })), t("cli.help_hint"));
343
- return;
344
- }
345
- try {
346
- await cmd.action(args);
347
- }
348
- catch (err) {
349
- console.error(pc.red(t("error.command_error", {
350
- message: err instanceof Error ? err.message : String(err),
351
- })));
352
- }
353
- }
354
- showHelp() {
355
- const { COMMAND_GROUPS } = require("./repl-commands");
356
- const order = ["general", "agent", "session", "skill"];
357
- const seen = new Set();
358
- for (const groupKey of order) {
359
- const cmds = [];
360
- for (const [name, cmd] of this.commands) {
361
- if (cmd.aliases?.includes(name))
362
- continue;
363
- if (seen.has(cmd.name))
364
- continue;
365
- const group = COMMAND_GROUPS[cmd.name] ?? "general";
366
- if (group !== groupKey)
367
- continue;
368
- seen.add(cmd.name);
369
- cmds.push(cmd);
370
- }
371
- if (cmds.length === 0)
372
- continue;
373
- console.log(pc.bold(t(`repl.group.${groupKey}`)));
374
- for (const cmd of cmds) {
375
- const aliases = cmd.aliases?.length
376
- ? ` (${pc.dim(cmd.aliases.join(", "))})`
377
- : "";
378
- console.log(` ${pc.cyan("/" + cmd.name)}${aliases} ${pc.dim(cmd.description)}`);
379
- if (cmd.usage) {
380
- console.log(` ${pc.dim(cmd.usage)}`);
381
- }
382
- }
383
- console.log();
384
- }
385
- }
386
- lastCompactionShown = 0;
387
- showContextBar(result) {
388
- if (result.contextUsed === undefined ||
389
- result.contextLimit === undefined ||
390
- result.contextLimit <= 0) {
391
- return;
392
- }
393
- const ui = this.config.ui;
394
- if (ui?.showContextStats) {
395
- console.log();
396
- const ctxLine = formatContextBar(result.contextUsed, result.contextLimit, result.compactionCount, result.contextQuality);
397
- console.log(ctxLine);
398
- if (result.totalTokens !== undefined && result.totalTokens > 0) {
399
- const apiLine = pc.dim(` API: ${result.promptTokens} prompt + ${result.completionTokens} completion = ${result.totalTokens} total`);
400
- console.log(apiLine);
401
- }
402
- }
403
- else if (ui?.showCompaction && result.compactionCount !== undefined) {
404
- if (result.compactionCount > this.lastCompactionShown) {
405
- this.lastCompactionShown = result.compactionCount;
406
- console.log(pc.dim(`\n ⟳ Context compacted (${result.compactionCount})`));
407
- }
408
- }
409
- }
410
- start() {
411
- this.running = true;
412
- const info = [];
413
- const row = (label, value) => {
414
- info.push(` ${pc.yellow(label)} ${value}`);
415
- };
416
- const ctx = this.config.contextWindow;
417
- const sysBudget = Math.floor(ctx * this.config.contextBudget.systemPrompt);
418
- const resBudget = Math.floor(ctx * this.config.contextBudget.responseReserve);
419
- const histBudget = ctx - sysBudget - resBudget;
420
- row(t("repl.model"), pc.white(this.config.model));
421
- row(t("repl.provider"), `${this.config.provider.type} → ${pc.dim(this.config.provider.baseUrl)}`);
422
- row(t("repl.context"), `${pc.white(String(ctx))} ${pc.dim(`(sys:${sysBudget} res:${resBudget} hist:${histBudget})`)}`);
423
- const si = this.agent.getSystemPromptInfo();
424
- row(t("repl.sysprompt_label"), pc.dim(t("repl.sysprompt_size", { used: si.tokenCount, budget: sysBudget })));
425
- if (this.skillsModule) {
426
- const budget = this.skillsModule.getBudget();
427
- row(t("repl.skills_label"), `${pc.white(String(this.skillsModule.getAvailable().length))} available, ${pc.dim(`budget: ${budget.total} tokens`)}`);
428
- }
429
- if (this.pluginManager) {
430
- const plugins = this.pluginManager
431
- .getAllPlugins()
432
- .filter((p) => !p.isBuiltin);
433
- if (plugins.length > 0) {
434
- const pluginNames = plugins.map((p) => p.name).join(", ");
435
- row(t("repl.plugins_label"), `${pc.white(String(plugins.length))} active ${pc.dim(`(${pluginNames})`)}`);
436
- }
437
- }
438
- const mcpServers = this.config.mcpServers || {};
439
- const enabledServers = Object.entries(mcpServers).filter(([, s]) => s.enabled !== false);
440
- if (enabledServers.length > 0) {
441
- const names = enabledServers.map(([name]) => name).join(", ");
442
- row(t("repl.mcp_label"), `${pc.white(String(enabledServers.length))} ${pc.dim(`(${names})`)}`);
443
- }
444
- const cwd = process.cwd();
445
- row(t("repl.work_dir"), pc.dim(cwd));
446
- if (this.noAgentsMd) {
447
- row(t("repl.agents_label"), pc.red(t("repl.disabled")));
448
- }
449
- else {
450
- const agentsMdCandidates = [
451
- join(this.baseDir, "AGENTS.md"),
452
- join(this.baseDir, ".mma", "AGENTS.md"),
453
- join(this.configDir, "AGENTS.md"),
454
- ];
455
- const foundAgents = agentsMdCandidates.filter((p) => existsSync(p));
456
- if (foundAgents.length > 0) {
457
- for (const p of foundAgents) {
458
- row(t("repl.agents_label"), pc.dim(p));
459
- }
460
- }
461
- else {
462
- row(t("repl.agents_label"), pc.dim(t("repl.not_found")));
463
- }
464
- }
465
- const meta = this.sessionManager?.getActiveMeta();
466
- if (meta) {
467
- const sessionPath = join(this.configDir, "sessions", meta.id);
468
- row(t("repl.session_label"), `${pc.cyan(meta.name)} ${pc.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc.dim(sessionPath)}`);
469
- }
470
- const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
471
- for (const line of box(info, {
472
- title: t("repl.title", { version }),
473
- width: headerWidth,
474
- })) {
475
- console.log(line);
476
- }
477
- console.log();
478
- this.rl.prompt();
479
- }
480
- stop() {
481
- this.running = false;
482
- this.saveHistory();
483
- this.agent.shutdown();
484
- this.rl.close();
485
- }
486
- }
@@ -1,166 +0,0 @@
1
- import { bootstrap } from "../core/bootstrap";
2
- import { saveConfig } from "../config/config";
3
- import { join } from "path";
4
- import { homedir } from "os";
5
- import { SECURITY_POLICIES, applySecurityPolicy, getSecurityPolicy, } from "../modules/security/security-policies";
6
- import { globalAuditNotifier } from "../modules/security/audit-notifier";
7
- import { t } from "../i18n/index";
8
- /**
9
- * Create security subcommand
10
- */
11
- export function createSecurityCommand(program) {
12
- const securityCmd = program
13
- .command("security")
14
- .description(t("cli.security.description"));
15
- // security status - show current security configuration
16
- securityCmd
17
- .command("status")
18
- .description(t("cli.security.status"))
19
- .action(async () => {
20
- const { config } = await bootstrap();
21
- const security = config.security || {};
22
- const bash = security.bash || {};
23
- const paths = security.paths || {};
24
- const network = security.network || {};
25
- const contentScan = security.contentScan || {};
26
- const rateLimits = security.rateLimits || {};
27
- const sessionEncryption = security.sessionEncryption || {};
28
- const auditNotifier = security.auditNotifier || {};
29
- console.log(t("cli.security.current_policy"));
30
- console.log(` ${t("cli.security.bash_enabled")}: ${bash.blacklist?.length > 0 ? t("cli.yes") : t("cli.no")}`);
31
- console.log(` ${t("cli.security.path_validation")}: ${paths.denied?.length > 0 ? t("cli.yes") : t("cli.no")}`);
32
- console.log(` ${t("cli.security.network_validation")}: ${network.deniedDomains?.length > 0 || network.allowedDomains?.length > 0 ? t("cli.yes") : t("cli.no")}`);
33
- console.log(` ${t("cli.security.content_scanning")}: ${contentScan.enabled ? t("cli.yes") : t("cli.no")}`);
34
- console.log(` ${t("cli.security.max_recursion")}: ${security.maxRecursionDepth ?? 3}`);
35
- console.log(` ${t("cli.security.max_file_ops")}: ${security.maxFileOperations ?? 100}`);
36
- console.log(` ${t("cli.security.rate_limit")}: ${rateLimits.maxRequestsPerMinute ?? 60}/min`);
37
- console.log(` ${t("cli.security.session_encryption")}: ${sessionEncryption.enabled ? t("cli.yes") : t("cli.no")}`);
38
- console.log(` ${t("cli.security.audit_notifier")}: ${auditNotifier.enabled ? t("cli.yes") : t("cli.no")}`);
39
- });
40
- // security policies - manage security policies
41
- securityCmd
42
- .command("policies")
43
- .description(t("cli.security.policies"))
44
- .action(async () => {
45
- console.log(t("cli.security.available_policies"));
46
- console.log("");
47
- for (const [preset, policy] of Object.entries(SECURITY_POLICIES)) {
48
- if (preset === 'custom')
49
- continue;
50
- const marker = " ";
51
- console.log(` ${marker}${preset.padEnd(12)} ${policy.name}`);
52
- console.log(` ${policy.description}`);
53
- console.log(` ${t("cli.security.recommended_for")}: ${policy.recommendedFor.join(", ")}`);
54
- console.log("");
55
- }
56
- });
57
- // security set-policy - apply a security policy
58
- securityCmd
59
- .command("set-policy")
60
- .argument("<preset>", t("cli.security.preset"))
61
- .description(t("cli.security.set_policy"))
62
- .action(async (preset) => {
63
- const configPath = join(homedir(), ".mma", "config.json");
64
- const { config: appConfig } = await bootstrap();
65
- const validPresets = ['strict', 'balanced', 'permissive'];
66
- if (!validPresets.includes(preset)) {
67
- console.log(t("cli.security.invalid_preset", { presets: validPresets.join(", ") }));
68
- return;
69
- }
70
- const policy = getSecurityPolicy(preset);
71
- const newSecurityConfig = applySecurityPolicy(preset);
72
- // Merge with existing config
73
- appConfig.security = newSecurityConfig;
74
- saveConfig(appConfig, configPath);
75
- console.log(t("cli.security.policy_applied", { name: policy.name }));
76
- console.log(t("cli.security.policy_description", { description: policy.description }));
77
- });
78
- // security enable-encryption - enable session file encryption
79
- securityCmd
80
- .command("enable-encryption")
81
- .description(t("cli.security.enable_encryption"))
82
- .action(async () => {
83
- const configPath = join(homedir(), ".mma", "config.json");
84
- const { config: appConfig } = await bootstrap();
85
- appConfig.security = appConfig.security || {};
86
- appConfig.security.sessionEncryption = {
87
- enabled: true,
88
- encryptHistory: true,
89
- encryptSessionLog: true,
90
- };
91
- saveConfig(appConfig, configPath);
92
- console.log(t("cli.security.encryption_enabled"));
93
- });
94
- // security disable-encryption - disable session file encryption
95
- securityCmd
96
- .command("disable-encryption")
97
- .description(t("cli.security.disable_encryption"))
98
- .action(async () => {
99
- const configPath = join(homedir(), ".mma", "config.json");
100
- const { config: appConfig } = await bootstrap();
101
- appConfig.security = appConfig.security || {};
102
- appConfig.security.sessionEncryption = {
103
- enabled: false,
104
- encryptHistory: false,
105
- encryptSessionLog: false,
106
- };
107
- saveConfig(appConfig, configPath);
108
- console.log(t("cli.security.encryption_disabled"));
109
- });
110
- // security enable-audit - enable audit notifications
111
- securityCmd
112
- .command("enable-audit")
113
- .description(t("cli.security.enable_audit"))
114
- .action(async () => {
115
- const configPath = join(homedir(), ".mma", "config.json");
116
- const { config: appConfig } = await bootstrap();
117
- appConfig.security = appConfig.security || {};
118
- appConfig.security.auditNotifier = {
119
- enabled: true,
120
- minSeverity: 'medium',
121
- eventTypes: ['security_block', 'bash_command', 'file_operation', 'network_request'],
122
- maxRetries: 3,
123
- webhookTimeout: 5000,
124
- };
125
- saveConfig(appConfig, configPath);
126
- console.log(t("cli.security.audit_enabled"));
127
- });
128
- // security disable-audit - disable audit notifications
129
- securityCmd
130
- .command("disable-audit")
131
- .description(t("cli.security.disable_audit"))
132
- .action(async () => {
133
- const configPath = join(homedir(), ".mma", "config.json");
134
- const { config: appConfig } = await bootstrap();
135
- appConfig.security = appConfig.security || {};
136
- appConfig.security.auditNotifier = {
137
- enabled: false,
138
- maxRetries: 3,
139
- webhookTimeout: 5000,
140
- };
141
- saveConfig(appConfig, configPath);
142
- console.log(t("cli.security.audit_disabled"));
143
- });
144
- // security audit-stats - show audit notification statistics
145
- securityCmd
146
- .command("audit-stats")
147
- .description(t("cli.security.audit_stats"))
148
- .action(async () => {
149
- const stats = globalAuditNotifier.getStats();
150
- console.log(t("cli.security.audit_stats_title"));
151
- console.log(` ${t("cli.security.total_notifications")}: ${stats.total}`);
152
- console.log("");
153
- console.log(t("cli.security.by_severity"));
154
- console.log(` ${t("cli.security.low")}: ${stats.bySeverity.low}`);
155
- console.log(` ${t("cli.security.medium")}: ${stats.bySeverity.medium}`);
156
- console.log(` ${t("cli.security.high")}: ${stats.bySeverity.high}`);
157
- console.log(` ${t("cli.security.critical")}: ${stats.bySeverity.critical}`);
158
- console.log("");
159
- console.log(t("cli.security.by_type"));
160
- for (const [type, count] of Object.entries(stats.byType)) {
161
- if (count > 0) {
162
- console.log(` ${type}: ${count}`);
163
- }
164
- }
165
- });
166
- }