micro-models-agent 0.39.0 → 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.
- package/bin/mma.mjs +41 -41
- package/dist/cli/commands.js +116 -3
- package/dist/cli/main.js +35 -8
- package/dist/cli/repl-commands.js +633 -0
- package/dist/cli/repl.js +110 -611
- package/dist/cli/setup.js +32 -12
- package/dist/config/config.js +46 -30
- package/dist/config/defaults.js +10 -1
- package/dist/config/security.js +15 -8
- package/dist/core/agent-moe.js +24 -12
- package/dist/core/agent.js +281 -47
- package/dist/core/bootstrap.js +52 -36
- package/dist/core/session-logger.js +35 -2
- package/dist/core/workspace.js +76 -0
- package/dist/i18n/en.json +79 -15
- package/dist/i18n/index.js +12 -9
- package/dist/i18n/ru.json +79 -15
- package/dist/index.js +13 -13
- package/dist/llm/openai-compat.js +39 -10
- package/dist/logger/app-logger.js +83 -16
- package/dist/logger/file-log.js +151 -0
- package/dist/main.js +537 -284
- package/dist/modules/browser/bridge-server.mjs +113 -105
- package/dist/modules/browser/session.js +108 -60
- package/dist/modules/certification/cli.js +176 -0
- package/dist/modules/certification/fact-checker.js +84 -0
- package/dist/modules/certification/loader.js +111 -0
- package/dist/modules/certification/manifest.js +50 -0
- package/dist/modules/certification/runner.js +162 -0
- package/dist/modules/certification/scenarios.js +124 -0
- package/dist/modules/certification/types.js +1 -0
- package/dist/modules/context/manager.js +119 -10
- package/dist/modules/execution/auditor.js +33 -39
- package/dist/modules/execution/index.js +8 -6
- package/dist/modules/execution/module.js +474 -32
- package/dist/modules/execution/moe-executor.js +97 -40
- package/dist/modules/execution/plan-coverage.js +68 -0
- package/dist/modules/execution/plan-persister.js +46 -0
- package/dist/modules/execution/plan-store.js +159 -0
- package/dist/modules/execution/planner.js +63 -13
- package/dist/modules/execution/stuck-detector.js +252 -39
- package/dist/modules/execution/tracker.js +21 -7
- package/dist/modules/execution/verifier.js +46 -17
- package/dist/modules/hallucination/confidence.js +7 -2
- package/dist/modules/hallucination/consistency.js +8 -42
- package/dist/modules/hallucination/detector.js +26 -21
- package/dist/modules/hallucination/factual.js +170 -150
- package/dist/modules/hallucination/index.js +5 -4
- package/dist/modules/hallucination/js-identifiers.js +72 -0
- package/dist/modules/hallucination/llm-judge.js +103 -0
- package/dist/modules/index.js +5 -5
- package/dist/modules/lsp/client.js +235 -0
- package/dist/modules/lsp/config.js +81 -0
- package/dist/modules/lsp/index.js +3 -0
- package/dist/modules/lsp/module.js +68 -0
- package/dist/modules/lsp/types.js +1 -0
- package/dist/modules/mcp/client.js +8 -2
- package/dist/modules/memory/store.js +4 -0
- package/dist/modules/plugins/builtin/lint-on-write.js +143 -38
- package/dist/modules/processes/index.js +1 -2
- package/dist/modules/processes/registry.js +125 -35
- package/dist/modules/processes/runner.js +9 -110
- package/dist/modules/security/audit-log.js +30 -10
- package/dist/modules/security/command-validator.js +42 -16
- package/dist/modules/security/content-scanner.js +9 -8
- package/dist/modules/security/network-validator.js +2 -2
- package/dist/modules/security/path-validator.js +64 -10
- package/dist/modules/security/security-policies.js +221 -67
- package/dist/modules/security/session-encryption.js +42 -25
- package/dist/modules/session/manager.js +15 -10
- package/dist/modules/session/store.js +62 -8
- package/dist/modules/skills/index.js +2 -3
- package/dist/modules/skills/module.js +10 -23
- package/dist/tools/bash.js +287 -90
- package/dist/tools/create-dir.js +0 -1
- package/dist/tools/delete-file.js +0 -1
- package/dist/tools/edit-file.js +10 -8
- package/dist/tools/executor.js +57 -7
- package/dist/tools/grep-tool.js +51 -29
- package/dist/tools/index.js +55 -40
- package/dist/tools/load-skill.js +14 -18
- package/dist/tools/move-file.js +3 -2
- package/dist/tools/pipeline-run.js +1 -1
- package/dist/tools/read-file.js +15 -5
- package/dist/tools/search-history.js +42 -22
- package/dist/tools/subagent.js +21 -12
- package/dist/tools/web-browse.js +54 -25
- package/dist/tools/web-fetch.js +60 -34
- package/dist/tools/web-search.js +39 -20
- package/dist/tools/write-file.js +13 -10
- package/dist/ui/diff.js +9 -16
- package/dist/ui/renderer.js +69 -6
- package/package.json +48 -45
- package/dist/modules/context/history.js +0 -15
- package/dist/modules/processes/detect.js +0 -34
- 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);
|
package/dist/cli/commands.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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({
|
|
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
|
|
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",
|
|
97
|
-
"
|
|
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
|
}
|