micro-models-agent 0.39.1 → 0.40.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 (96) hide show
  1. package/bin/mma.mjs +41 -41
  2. package/dist/cli/commands.js +116 -3
  3. package/dist/cli/main.js +35 -8
  4. package/dist/cli/repl-commands.js +633 -0
  5. package/dist/cli/repl.js +110 -611
  6. package/dist/cli/setup.js +32 -12
  7. package/dist/config/config.js +46 -30
  8. package/dist/config/defaults.js +10 -1
  9. package/dist/config/security.js +15 -8
  10. package/dist/core/agent-moe.js +24 -12
  11. package/dist/core/agent.js +281 -47
  12. package/dist/core/bootstrap.js +52 -36
  13. package/dist/core/session-logger.js +35 -2
  14. package/dist/core/workspace.js +76 -0
  15. package/dist/i18n/en.json +79 -15
  16. package/dist/i18n/index.js +12 -9
  17. package/dist/i18n/ru.json +79 -15
  18. package/dist/index.js +13 -13
  19. package/dist/llm/openai-compat.js +39 -10
  20. package/dist/logger/app-logger.js +83 -16
  21. package/dist/logger/file-log.js +151 -0
  22. package/dist/main.js +492 -283
  23. package/dist/modules/browser/bridge-server.mjs +113 -105
  24. package/dist/modules/browser/session.js +108 -60
  25. package/dist/modules/certification/cli.js +176 -0
  26. package/dist/modules/certification/fact-checker.js +84 -0
  27. package/dist/modules/certification/loader.js +111 -0
  28. package/dist/modules/certification/manifest.js +50 -0
  29. package/dist/modules/certification/runner.js +162 -0
  30. package/dist/modules/certification/scenarios.js +124 -0
  31. package/dist/modules/certification/types.js +1 -0
  32. package/dist/modules/context/manager.js +119 -10
  33. package/dist/modules/execution/auditor.js +33 -39
  34. package/dist/modules/execution/index.js +8 -6
  35. package/dist/modules/execution/module.js +474 -32
  36. package/dist/modules/execution/moe-executor.js +97 -40
  37. package/dist/modules/execution/plan-coverage.js +68 -0
  38. package/dist/modules/execution/plan-persister.js +46 -0
  39. package/dist/modules/execution/plan-store.js +159 -0
  40. package/dist/modules/execution/planner.js +63 -13
  41. package/dist/modules/execution/stuck-detector.js +252 -39
  42. package/dist/modules/execution/tracker.js +21 -7
  43. package/dist/modules/execution/verifier.js +46 -17
  44. package/dist/modules/hallucination/confidence.js +7 -2
  45. package/dist/modules/hallucination/consistency.js +8 -42
  46. package/dist/modules/hallucination/detector.js +26 -21
  47. package/dist/modules/hallucination/factual.js +170 -150
  48. package/dist/modules/hallucination/index.js +5 -4
  49. package/dist/modules/hallucination/js-identifiers.js +72 -0
  50. package/dist/modules/hallucination/llm-judge.js +103 -0
  51. package/dist/modules/index.js +5 -5
  52. package/dist/modules/lsp/client.js +235 -0
  53. package/dist/modules/lsp/config.js +81 -0
  54. package/dist/modules/lsp/index.js +3 -0
  55. package/dist/modules/lsp/module.js +68 -0
  56. package/dist/modules/lsp/types.js +1 -0
  57. package/dist/modules/mcp/client.js +8 -2
  58. package/dist/modules/memory/store.js +4 -0
  59. package/dist/modules/plugins/builtin/lint-on-write.js +143 -38
  60. package/dist/modules/processes/index.js +1 -2
  61. package/dist/modules/processes/registry.js +125 -35
  62. package/dist/modules/processes/runner.js +9 -110
  63. package/dist/modules/security/audit-log.js +30 -10
  64. package/dist/modules/security/command-validator.js +42 -16
  65. package/dist/modules/security/content-scanner.js +9 -8
  66. package/dist/modules/security/network-validator.js +2 -2
  67. package/dist/modules/security/path-validator.js +64 -10
  68. package/dist/modules/security/security-policies.js +221 -67
  69. package/dist/modules/security/session-encryption.js +42 -25
  70. package/dist/modules/session/manager.js +15 -10
  71. package/dist/modules/session/store.js +62 -8
  72. package/dist/modules/skills/index.js +2 -3
  73. package/dist/modules/skills/module.js +10 -23
  74. package/dist/tools/bash.js +287 -90
  75. package/dist/tools/create-dir.js +0 -1
  76. package/dist/tools/delete-file.js +0 -1
  77. package/dist/tools/edit-file.js +10 -8
  78. package/dist/tools/executor.js +57 -7
  79. package/dist/tools/grep-tool.js +51 -29
  80. package/dist/tools/index.js +55 -40
  81. package/dist/tools/load-skill.js +14 -18
  82. package/dist/tools/move-file.js +3 -2
  83. package/dist/tools/pipeline-run.js +1 -1
  84. package/dist/tools/read-file.js +15 -5
  85. package/dist/tools/search-history.js +42 -22
  86. package/dist/tools/subagent.js +21 -12
  87. package/dist/tools/web-browse.js +54 -25
  88. package/dist/tools/web-fetch.js +60 -34
  89. package/dist/tools/web-search.js +39 -20
  90. package/dist/tools/write-file.js +13 -10
  91. package/dist/ui/diff.js +9 -16
  92. package/dist/ui/renderer.js +69 -6
  93. package/package.json +48 -45
  94. package/dist/modules/context/history.js +0 -15
  95. package/dist/modules/processes/detect.js +0 -34
  96. package/dist/modules/skills/matcher.js +0 -27
package/bin/mma.mjs CHANGED
@@ -1,41 +1,41 @@
1
- #!/usr/bin/env node
2
- import { spawnSync } from "node:child_process";
3
- import { fileURLToPath, pathToFileURL } from "node:url";
4
- import { dirname, join } from "node:path";
5
-
6
- // MMA is designed to run under Bun: clipboard image paste relies on
7
- // `Bun.Image.fromClipboard()` (Node has no clipboard API), and on Windows a
8
- // bare `npx.cmd` shim can only be spawned reliably through Bun's child_process
9
- // (under Node it throws `spawn EINVAL`). The global npm shim (`mma` /
10
- // `mma.cmd`) launches this file under Node, so re-execute ourselves under Bun
11
- // when it is available. The `bun run mma` path already runs under Bun and
12
- // skips the respawn.
13
- const runningUnderBun =
14
- typeof globalThis.Bun !== "undefined" &&
15
- typeof globalThis.Bun?.version !== "undefined";
16
-
17
- if (process.env.MMA_DEBUG_RUNTIME) {
18
- console.error(
19
- "[mma] runtime=" +
20
- (runningUnderBun ? "bun " + globalThis.Bun.version : "node " + process.version),
21
- );
22
- }
23
-
24
- if (!runningUnderBun) {
25
- try {
26
- const res = spawnSync("bun", [process.argv[1], ...process.argv.slice(2)], {
27
- stdio: "inherit",
28
- windowsHide: true,
29
- });
30
- if (res.error) throw res.error;
31
- process.exit(res.status ?? 0);
32
- } catch {
33
- // `bun` is not on PATH — fall back to the Node import path (clipboard
34
- // paste and LSP will degrade, but the agent still works).
35
- }
36
- }
37
-
38
- const __dirname = dirname(fileURLToPath(import.meta.url));
39
- const main = join(__dirname, "..", "dist", "main.js");
40
-
41
- await import(pathToFileURL(main).href);
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import { fileURLToPath, pathToFileURL } from "node:url";
4
+ import { dirname, join } from "node:path";
5
+
6
+ // MMA is designed to run under Bun: clipboard image paste relies on
7
+ // `Bun.Image.fromClipboard()` (Node has no clipboard API), and on Windows a
8
+ // bare `npx.cmd` shim can only be spawned reliably through Bun's child_process
9
+ // (under Node it throws `spawn EINVAL`). The global npm shim (`mma` /
10
+ // `mma.cmd`) launches this file under Node, so re-execute ourselves under Bun
11
+ // when it is available. The `bun run mma` path already runs under Bun and
12
+ // skips the respawn.
13
+ const runningUnderBun =
14
+ typeof globalThis.Bun !== "undefined" &&
15
+ typeof globalThis.Bun?.version !== "undefined";
16
+
17
+ if (process.env.MMA_DEBUG_RUNTIME) {
18
+ console.error(
19
+ "[mma] runtime=" +
20
+ (runningUnderBun ? "bun " + globalThis.Bun.version : "node " + process.version),
21
+ );
22
+ }
23
+
24
+ if (!runningUnderBun) {
25
+ try {
26
+ const res = spawnSync("bun", [process.argv[1], ...process.argv.slice(2)], {
27
+ stdio: "inherit",
28
+ windowsHide: true,
29
+ });
30
+ if (res.error) throw res.error;
31
+ process.exit(res.status ?? 0);
32
+ } catch {
33
+ // `bun` is not on PATH — fall back to the Node import path (clipboard
34
+ // paste and LSP will degrade, but the agent still works).
35
+ }
36
+ }
37
+
38
+ const __dirname = dirname(fileURLToPath(import.meta.url));
39
+ const main = join(__dirname, "..", "dist", "main.js");
40
+
41
+ await import(pathToFileURL(main).href);
@@ -3,10 +3,32 @@ import { bootstrap } from "../core/bootstrap";
3
3
  import { saveConfig } from "../config/config";
4
4
  import { runSetup } from "./setup";
5
5
  import { t } from "../i18n/index";
6
- import { join } from "path";
6
+ import { join, dirname } from "path";
7
7
  import { homedir } from "os";
8
+ import { existsSync, readFileSync } from "fs";
8
9
  import { createSecurityCommand } from "./security-commands";
9
- import { version } from "../../package.json";
10
+ import { fileURLToPath } from "url";
11
+ function readVersion() {
12
+ const here = dirname(fileURLToPath(import.meta.url));
13
+ const candidates = [
14
+ join(here, "..", "..", "package.json"),
15
+ join(here, "..", "package.json"),
16
+ ];
17
+ for (const p of candidates) {
18
+ if (existsSync(p)) {
19
+ try {
20
+ const raw = JSON.parse(readFileSync(p, "utf8"));
21
+ if (raw.version)
22
+ return raw.version;
23
+ }
24
+ catch {
25
+ // Broken package.json — fall through to the next candidate
26
+ }
27
+ }
28
+ }
29
+ return "0.0.0";
30
+ }
31
+ const version = readVersion();
10
32
  export function createProgram() {
11
33
  const program = new Command()
12
34
  .name("mma")
@@ -30,6 +52,41 @@ export function createProgram() {
30
52
  config.contextWindow = answers.contextWindow;
31
53
  config.maxToolIterations = answers.maxToolIterations;
32
54
  config.locale = answers.locale;
55
+ // Apply security settings from wizard
56
+ if (config.security) {
57
+ config.security.enabled =
58
+ answers.securityBashBlock ||
59
+ answers.securityFlagsBlock ||
60
+ !answers.securityPathsDeny;
61
+ config.security.bash.enabled = config.security.enabled;
62
+ config.security.bash.blockDangerousFlags = answers.securityFlagsBlock;
63
+ if (answers.securityBashBlock) {
64
+ config.security.bash.blacklist = [
65
+ ...new Set([
66
+ ...config.security.bash.blacklist,
67
+ "rm",
68
+ "dd",
69
+ "chmod",
70
+ "wget",
71
+ "curl",
72
+ "scp",
73
+ "ssh",
74
+ "nc",
75
+ "netcat",
76
+ "sudo",
77
+ "su",
78
+ "kill",
79
+ "pkill",
80
+ "killall",
81
+ "shutdown",
82
+ "reboot",
83
+ ]),
84
+ ];
85
+ }
86
+ if (!answers.securityPathsDeny) {
87
+ config.security.paths.denied = [];
88
+ }
89
+ }
33
90
  saveConfig(config, configPath);
34
91
  console.log(t("cli.config_saved"));
35
92
  });
@@ -95,9 +152,12 @@ export function createProgram() {
95
152
  s.stop();
96
153
  if (models.length > 0) {
97
154
  console.log(t("cli.available_models"));
155
+ const { getCertMark } = await import("../modules/certification/manifest");
98
156
  for (const m of models) {
99
157
  const marker = m === config.model ? "* " : " ";
100
- console.log(` ${marker}${m}`);
158
+ const mark = getCertMark(m, config.provider.baseUrl, version);
159
+ const cert = mark === "certified" ? "✔" : mark === "stale" ? "○" : "·";
160
+ console.log(` ${marker}${cert} ${m}`);
101
161
  }
102
162
  }
103
163
  else {
@@ -121,6 +181,59 @@ export function createProgram() {
121
181
  saveConfig(config, configPath);
122
182
  console.log(t("cli.model_set", { name }));
123
183
  });
184
+ model
185
+ .command("certify")
186
+ .argument("<name>", "Model name")
187
+ .option("--provider-url <url>", t("cli.cert_provider_url"))
188
+ .option("--provider-key <key>", t("cli.cert_provider_key"))
189
+ .option("--context-window <n>", t("cli.cert_context_window"))
190
+ .option("--tags <tags>", t("cli.cert_tags"), "core")
191
+ .option("--reps <n>", t("cli.cert_reps"))
192
+ .option("--force", t("cli.cert_force"))
193
+ .option("--clean", t("cli.cert_clean"))
194
+ .description(t("cli.certify"))
195
+ .action(async (name, cmdOpts) => {
196
+ const { config } = await bootstrap();
197
+ const { certify, parseTags } = await import("../modules/certification/cli");
198
+ await certify({
199
+ name,
200
+ providerUrl: cmdOpts.providerUrl,
201
+ providerKey: cmdOpts.providerKey,
202
+ contextWindow: cmdOpts.contextWindow
203
+ ? parseInt(cmdOpts.contextWindow, 10)
204
+ : undefined,
205
+ tags: parseTags(cmdOpts.tags),
206
+ reps: cmdOpts.reps ? parseInt(cmdOpts.reps, 10) : 3,
207
+ force: cmdOpts.force === true,
208
+ clean: cmdOpts.clean === true,
209
+ config,
210
+ });
211
+ });
212
+ model
213
+ .command("cert-status")
214
+ .argument("<name>", "Model name")
215
+ .description(t("cli.cert_status"))
216
+ .action(async (name) => {
217
+ const { config } = await bootstrap();
218
+ const { certStatus } = await import("../modules/certification/cli");
219
+ await certStatus(name, config);
220
+ });
221
+ model
222
+ .command("cert-list")
223
+ .description(t("cli.cert_list"))
224
+ .action(async () => {
225
+ const { certList } = await import("../modules/certification/cli");
226
+ await certList();
227
+ });
228
+ model
229
+ .command("uncertify")
230
+ .argument("<name>", "Model name")
231
+ .description(t("cli.cert_uncertify"))
232
+ .action(async (name) => {
233
+ const { config } = await bootstrap();
234
+ const { uncertify } = await import("../modules/certification/cli");
235
+ await uncertify(name, config);
236
+ });
124
237
  // Context window command
125
238
  program
126
239
  .command("context")
package/dist/cli/main.js CHANGED
@@ -4,7 +4,7 @@ import { Repl } from "./repl";
4
4
  import { formatMarkdown } from "../ui/md-formatter";
5
5
  import { Renderer } from "../ui/renderer";
6
6
  import { runSetup } from "./setup";
7
- import { saveConfig } from "../config/config";
7
+ import { saveConfig, loadConfig } from "../config/config";
8
8
  import { t } from "../i18n/index";
9
9
  import { pc } from "../ui/colors";
10
10
  import { existsSync } from "fs";
@@ -43,13 +43,16 @@ async function main() {
43
43
  process.stdout.write("\n");
44
44
  process.exit(result.success ? 0 : 1);
45
45
  }
46
- const renderer = new Renderer({ spinner: config.ui?.spinner ?? true });
46
+ const renderer = new Renderer({
47
+ spinner: config.ui?.spinner ?? true,
48
+ toolStyle: config.ui?.toolStyle ?? "inline",
49
+ });
47
50
  const result = await agent.run(prompt, (chunk) => renderer.text(chunk), (meta) => renderer.meta(meta), (ev) => {
48
51
  if (ev.type === "start") {
49
52
  renderer.toolStart(ev.tool, ev.args);
50
53
  }
51
54
  else {
52
- renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error);
55
+ renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
53
56
  }
54
57
  }, (phase) => {
55
58
  if (phase === "thinking") {
@@ -79,7 +82,12 @@ async function main() {
79
82
  if (!existsSync(configPath)) {
80
83
  console.log(pc.yellow("\n " + t("cli.first_run") + "\n"));
81
84
  const answers = await runSetup();
82
- const { config } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
85
+ const config = loadConfig({
86
+ configDir: join(homedir(), ".mma"),
87
+ projectConfigPath: projectDir
88
+ ? join(projectDir, ".mmrc")
89
+ : join(process.cwd(), ".mmrc"),
90
+ });
83
91
  config.provider.type = answers.provider;
84
92
  config.provider.baseUrl = answers.apiBase;
85
93
  config.provider.apiKey = answers.apiKey;
@@ -88,13 +96,32 @@ async function main() {
88
96
  config.maxToolIterations = answers.maxToolIterations;
89
97
  config.locale = answers.locale;
90
98
  if (config.security) {
99
+ config.security.enabled =
100
+ answers.securityBashBlock ||
101
+ answers.securityFlagsBlock ||
102
+ !answers.securityPathsDeny;
103
+ config.security.bash.enabled = config.security.enabled;
91
104
  config.security.bash.blockDangerousFlags = answers.securityFlagsBlock;
92
105
  if (answers.securityBashBlock) {
93
106
  config.security.bash.blacklist = [
94
107
  ...new Set([
95
108
  ...config.security.bash.blacklist,
96
- "rm", "dd", "chmod", "wget", "curl", "scp", "ssh", "nc", "netcat",
97
- "sudo", "su", "kill", "pkill", "killall", "shutdown", "reboot",
109
+ "rm",
110
+ "dd",
111
+ "chmod",
112
+ "wget",
113
+ "curl",
114
+ "scp",
115
+ "ssh",
116
+ "nc",
117
+ "netcat",
118
+ "sudo",
119
+ "su",
120
+ "kill",
121
+ "pkill",
122
+ "killall",
123
+ "shutdown",
124
+ "reboot",
98
125
  ]),
99
126
  ];
100
127
  }
@@ -104,8 +131,8 @@ async function main() {
104
131
  }
105
132
  saveConfig(config, configPath);
106
133
  }
107
- const { agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
108
- const repl = new Repl(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd);
134
+ const { agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, logger, } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
135
+ const repl = new Repl(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger);
109
136
  repl.start();
110
137
  }
111
138
  }