micro-models-agent 0.41.0 → 0.41.2
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 +9 -19
- package/dist/cli/completer.js +36 -37
- package/dist/cli/index.js +2 -2
- package/dist/cli/main.js +48 -23
- package/dist/cli/plugin-commands.js +36 -0
- package/dist/cli/repl-commands.js +40 -12
- package/dist/cli/repl.js +217 -87
- package/dist/cli/run-result.js +22 -0
- package/dist/cli/security-commands.js +5 -7
- package/dist/cli/setup.js +8 -26
- package/dist/config/config.js +52 -5
- package/dist/config/defaults.js +29 -5
- package/dist/config/experts.js +1 -1
- package/dist/config/index.js +3 -3
- package/dist/config/security.js +3 -10
- package/dist/core/agent-moe.js +2 -10
- package/dist/core/agent.js +273 -82
- package/dist/core/bootstrap.js +80 -13
- package/dist/core/index.js +2 -2
- package/dist/core/prompt-builder.js +23 -2
- package/dist/core/session-logger.js +46 -4
- package/dist/core/version.js +24 -0
- package/dist/i18n/en.json +75 -2
- package/dist/i18n/ru.json +74 -1
- package/dist/index.js +1 -1
- package/dist/llm/image-utils.js +4 -5
- package/dist/llm/index.js +4 -4
- package/dist/llm/model-loader.js +6 -6
- package/dist/llm/openai-compat.js +40 -34
- package/dist/llm/orchestrator.js +33 -29
- package/dist/llm/response.js +9 -9
- package/dist/logger/app-logger.js +1 -1
- package/dist/logger/index.js +1 -1
- package/dist/main.js +1111 -954
- package/dist/migration/backup.js +13 -13
- package/dist/migration/detect.js +11 -11
- package/dist/migration/index.js +2 -2
- package/dist/modules/artifacts/store.js +61 -0
- package/dist/modules/browser/actions.js +34 -4
- package/dist/modules/browser/bridge-client.js +199 -0
- package/dist/modules/browser/bridge-path.js +10 -0
- package/dist/modules/browser/bridge-server.mjs +202 -202
- package/dist/modules/browser/cookie-store.js +6 -6
- package/dist/modules/browser/driver.js +136 -0
- package/dist/modules/browser/index.js +7 -5
- package/dist/modules/browser/module.js +8 -7
- package/dist/modules/browser/session.js +87 -84
- package/dist/modules/browser/snapshot.js +92 -58
- package/dist/modules/browser/types.js +4 -1
- package/dist/modules/certification/cli.js +2 -4
- package/dist/modules/certification/fact-checker.js +1 -3
- package/dist/modules/certification/loader.js +3 -9
- package/dist/modules/certification/runner.js +1 -4
- package/dist/modules/context/chunk-query.js +100 -0
- package/dist/modules/context/fact-extractor.js +162 -0
- package/dist/modules/context/history.js +15 -0
- package/dist/modules/context/index.js +1 -1
- package/dist/modules/context/manager.js +160 -86
- package/dist/modules/execution/audit-runners.js +152 -0
- package/dist/modules/execution/auditor.js +177 -25
- package/dist/modules/execution/execution-plugin.js +272 -0
- package/dist/modules/execution/module.js +201 -544
- package/dist/modules/execution/moe-executor.js +25 -0
- package/dist/modules/execution/plan-store.js +1 -3
- package/dist/modules/execution/plan-tool.js +508 -0
- package/dist/modules/execution/plan-validator.js +10 -10
- package/dist/modules/execution/planner.js +6 -1
- package/dist/modules/execution/stuck-detector.js +173 -10
- package/dist/modules/execution/verifier.js +86 -42
- package/dist/modules/execution/windows-commands.js +41 -0
- package/dist/modules/hallucination/confidence.js +8 -1
- package/dist/modules/hallucination/detector.js +2 -5
- package/dist/modules/hallucination/factual.js +3 -64
- package/dist/modules/hallucination/index.js +1 -1
- package/dist/modules/hallucination/js-identifiers.js +190 -0
- package/dist/modules/hallucination/llm-judge.js +1 -3
- package/dist/modules/indexer/cache.js +9 -7
- package/dist/modules/indexer/index.js +3 -3
- package/dist/modules/indexer/module.js +95 -42
- package/dist/modules/indexer/project-profile.js +183 -0
- package/dist/modules/indexer/walker.js +17 -17
- package/dist/modules/lsp/check-tool.js +58 -0
- package/dist/modules/lsp/client.js +74 -31
- package/dist/modules/lsp/command.js +60 -0
- package/dist/modules/lsp/config.js +87 -33
- package/dist/modules/lsp/index.js +3 -3
- package/dist/modules/lsp/module.js +185 -21
- package/dist/modules/lsp/probe.js +76 -0
- package/dist/modules/lsp/project-root.js +32 -0
- package/dist/modules/lsp/startup-check.js +141 -0
- package/dist/modules/mcp/module.js +2 -6
- package/dist/modules/memory/index.js +1 -1
- package/dist/modules/memory/module.js +71 -23
- package/dist/modules/memory/search.js +11 -9
- package/dist/modules/memory/store.js +13 -13
- package/dist/modules/pipelines/engine.js +10 -10
- package/dist/modules/pipelines/index.js +3 -3
- package/dist/modules/pipelines/parser.js +17 -14
- package/dist/modules/pipelines/template.js +1 -1
- package/dist/modules/plugins/builtin/lint-on-write.js +21 -16
- package/dist/modules/plugins/builtin/notify.js +3 -2
- package/dist/modules/plugins/index.js +1 -1
- package/dist/modules/plugins/loader.js +59 -17
- package/dist/modules/plugins/manager.js +73 -17
- package/dist/modules/processes/detect.js +34 -0
- package/dist/modules/processes/index.js +1 -1
- package/dist/modules/processes/registry.js +135 -46
- package/dist/modules/registry.js +4 -2
- package/dist/modules/security/audit-notifier.js +39 -39
- package/dist/modules/security/command-validator.js +2 -8
- package/dist/modules/security/data-sanitizer.js +1 -9
- package/dist/modules/security/encryption.js +58 -56
- package/dist/modules/security/network-validator.js +1 -9
- package/dist/modules/security/path-validator.js +1 -3
- package/dist/modules/security/security-policies.js +3 -19
- package/dist/modules/security/session-encryption.js +1 -1
- package/dist/modules/security/session-isolation.js +8 -8
- package/dist/modules/session/index.js +3 -3
- package/dist/modules/session/module.js +5 -5
- package/dist/modules/session/store.js +3 -9
- package/dist/modules/skills/matcher.js +27 -0
- package/dist/modules/skills/module.js +1 -2
- package/dist/modules/updater/checker.js +70 -6
- package/dist/modules/updater/index.js +2 -1
- package/dist/modules/updater/module.js +116 -0
- package/dist/modules/user-profile/compressor.js +2 -2
- package/dist/modules/user-profile/index.js +1 -1
- package/dist/modules/user-profile/profile.js +9 -9
- package/dist/tools/attach-image.js +1 -1
- package/dist/tools/bash.js +178 -19
- package/dist/tools/browser.js +46 -29
- package/dist/tools/chunk-query.js +99 -0
- package/dist/tools/download-file.js +116 -0
- package/dist/tools/enable-tools.js +58 -0
- package/dist/tools/executor.js +4 -5
- package/dist/tools/file-info.js +13 -12
- package/dist/tools/filter-tools.js +9 -2
- package/dist/tools/glob-tool.js +11 -11
- package/dist/tools/grep-tool.js +1 -3
- package/dist/tools/hidden-tools-block.js +37 -0
- package/dist/tools/index.js +13 -2
- package/dist/tools/list-dir.js +18 -17
- package/dist/tools/load-skill.js +1 -3
- package/dist/tools/path-utils.js +4 -4
- package/dist/tools/pipeline-run.js +25 -25
- package/dist/tools/process-kill.js +11 -11
- package/dist/tools/process-list.js +20 -22
- package/dist/tools/process-log.js +22 -18
- package/dist/tools/question.js +1 -3
- package/dist/tools/read-file.js +10 -2
- package/dist/tools/recall.js +44 -37
- package/dist/tools/registry.js +15 -4
- package/dist/tools/remember.js +29 -29
- package/dist/tools/scope-check.js +9 -9
- package/dist/tools/subagent.js +54 -9
- package/dist/tools/user-input.js +1 -1
- package/dist/tools/web-browse.js +3 -3
- package/dist/tools/web-fetch.js +3 -3
- package/dist/tools/web-search.js +3 -3
- package/dist/tools/write-file.js +1 -3
- package/dist/ui/box.js +1 -5
- package/dist/ui/index.js +6 -6
- package/dist/ui/line-editor.js +703 -0
- package/dist/ui/line-math.js +69 -0
- package/dist/ui/md-formatter.js +33 -33
- package/dist/ui/output.js +5 -5
- package/dist/ui/plan-view.js +103 -0
- package/dist/ui/renderer.js +15 -10
- package/dist/ui/table.js +1 -1
- package/package.json +48 -48
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
|
@@ -7,13 +7,11 @@ import { join, dirname } from "path";
|
|
|
7
7
|
import { homedir } from "os";
|
|
8
8
|
import { existsSync, readFileSync } from "fs";
|
|
9
9
|
import { createSecurityCommand } from "./security-commands";
|
|
10
|
+
import { createPluginCommand } from "./plugin-commands";
|
|
10
11
|
import { fileURLToPath } from "url";
|
|
11
12
|
function readVersion() {
|
|
12
13
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
const candidates = [
|
|
14
|
-
join(here, "..", "..", "package.json"),
|
|
15
|
-
join(here, "..", "package.json"),
|
|
16
|
-
];
|
|
14
|
+
const candidates = [join(here, "..", "..", "package.json"), join(here, "..", "package.json")];
|
|
17
15
|
for (const p of candidates) {
|
|
18
16
|
if (existsSync(p)) {
|
|
19
17
|
try {
|
|
@@ -55,9 +53,7 @@ export function createProgram() {
|
|
|
55
53
|
// Apply security settings from wizard
|
|
56
54
|
if (config.security) {
|
|
57
55
|
config.security.enabled =
|
|
58
|
-
answers.securityBashBlock ||
|
|
59
|
-
answers.securityFlagsBlock ||
|
|
60
|
-
!answers.securityPathsDeny;
|
|
56
|
+
answers.securityBashBlock || answers.securityFlagsBlock || !answers.securityPathsDeny;
|
|
61
57
|
config.security.bash.enabled = config.security.enabled;
|
|
62
58
|
config.security.bash.blockDangerousFlags = answers.securityFlagsBlock;
|
|
63
59
|
if (answers.securityBashBlock) {
|
|
@@ -90,9 +86,7 @@ export function createProgram() {
|
|
|
90
86
|
saveConfig(config, configPath);
|
|
91
87
|
console.log(t("cli.config_saved"));
|
|
92
88
|
});
|
|
93
|
-
const configCmd = program
|
|
94
|
-
.command("config")
|
|
95
|
-
.description(t("cli.manage_config"));
|
|
89
|
+
const configCmd = program.command("config").description(t("cli.manage_config"));
|
|
96
90
|
configCmd
|
|
97
91
|
.command("set")
|
|
98
92
|
.argument("<key>", t("cli.config_key"))
|
|
@@ -199,9 +193,7 @@ export function createProgram() {
|
|
|
199
193
|
name,
|
|
200
194
|
providerUrl: cmdOpts.providerUrl,
|
|
201
195
|
providerKey: cmdOpts.providerKey,
|
|
202
|
-
contextWindow: cmdOpts.contextWindow
|
|
203
|
-
? parseInt(cmdOpts.contextWindow, 10)
|
|
204
|
-
: undefined,
|
|
196
|
+
contextWindow: cmdOpts.contextWindow ? parseInt(cmdOpts.contextWindow, 10) : undefined,
|
|
205
197
|
tags: parseTags(cmdOpts.tags),
|
|
206
198
|
reps: cmdOpts.reps ? parseInt(cmdOpts.reps, 10) : 3,
|
|
207
199
|
force: cmdOpts.force === true,
|
|
@@ -251,9 +243,7 @@ export function createProgram() {
|
|
|
251
243
|
saveConfig(config, configPath);
|
|
252
244
|
console.log(t("cli.context_set", { size: contextWindow }));
|
|
253
245
|
});
|
|
254
|
-
const provider = program
|
|
255
|
-
.command("provider")
|
|
256
|
-
.description(t("cli.manage_providers"));
|
|
246
|
+
const provider = program.command("provider").description(t("cli.manage_providers"));
|
|
257
247
|
provider
|
|
258
248
|
.command("list")
|
|
259
249
|
.description(t("cli.list_providers"))
|
|
@@ -273,9 +263,7 @@ export function createProgram() {
|
|
|
273
263
|
saveConfig(config, configPath);
|
|
274
264
|
console.log(t("cli.provider_set", { name }));
|
|
275
265
|
});
|
|
276
|
-
const session = program
|
|
277
|
-
.command("session")
|
|
278
|
-
.description(t("cli.manage_sessions"));
|
|
266
|
+
const session = program.command("session").description(t("cli.manage_sessions"));
|
|
279
267
|
session
|
|
280
268
|
.command("list")
|
|
281
269
|
.description(t("cli.list_sessions"))
|
|
@@ -323,6 +311,8 @@ export function createProgram() {
|
|
|
323
311
|
});
|
|
324
312
|
// Add security commands
|
|
325
313
|
createSecurityCommand(program);
|
|
314
|
+
// Add plugin commands
|
|
315
|
+
createPluginCommand(program);
|
|
326
316
|
program
|
|
327
317
|
.argument("[prompt...]", "Prompt to execute")
|
|
328
318
|
.description("Run a single prompt")
|
package/dist/cli/completer.js
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
import { readdirSync, statSync } from
|
|
2
|
-
import { join } from
|
|
1
|
+
import { readdirSync, statSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
3
|
export class SlashCommandProvider {
|
|
4
|
-
name =
|
|
4
|
+
name = "slash-commands";
|
|
5
5
|
commands;
|
|
6
6
|
constructor(commands) {
|
|
7
7
|
this.commands = commands;
|
|
8
8
|
}
|
|
9
9
|
match(ctx) {
|
|
10
|
-
return ctx.tokenIndex === 0 && ctx.line.startsWith(
|
|
10
|
+
return ctx.tokenIndex === 0 && ctx.line.startsWith("/");
|
|
11
11
|
}
|
|
12
12
|
complete(ctx) {
|
|
13
|
-
return this.commands
|
|
14
|
-
.filter(c => c.startsWith(ctx.partial.slice(1)))
|
|
15
|
-
.map(c => `/${c}`);
|
|
13
|
+
return this.commands.filter((c) => c.startsWith(ctx.partial.slice(1))).map((c) => `/${c}`);
|
|
16
14
|
}
|
|
17
15
|
}
|
|
18
16
|
export class SubcommandProvider {
|
|
19
|
-
name =
|
|
17
|
+
name = "subcommands";
|
|
20
18
|
command;
|
|
21
19
|
subcommands;
|
|
22
20
|
constructor(command, subcommands) {
|
|
@@ -27,54 +25,54 @@ export class SubcommandProvider {
|
|
|
27
25
|
return ctx.tokenIndex === 1 && ctx.tokens[0] === `/${this.command}`;
|
|
28
26
|
}
|
|
29
27
|
complete(ctx) {
|
|
30
|
-
return this.subcommands.filter(s => s.startsWith(ctx.partial));
|
|
28
|
+
return this.subcommands.filter((s) => s.startsWith(ctx.partial));
|
|
31
29
|
}
|
|
32
30
|
}
|
|
33
31
|
export class ModelArgProvider {
|
|
34
|
-
name =
|
|
32
|
+
name = "model-args";
|
|
35
33
|
models;
|
|
36
34
|
constructor(models) {
|
|
37
35
|
this.models = models;
|
|
38
36
|
}
|
|
39
37
|
match(ctx) {
|
|
40
|
-
return ctx.tokenIndex === 2 && (ctx.tokens[0] ===
|
|
38
|
+
return ctx.tokenIndex === 2 && (ctx.tokens[0] === "/model" || ctx.tokens[0] === "/config");
|
|
41
39
|
}
|
|
42
40
|
complete(ctx) {
|
|
43
|
-
return this.models.filter(m => m.startsWith(ctx.partial));
|
|
41
|
+
return this.models.filter((m) => m.startsWith(ctx.partial));
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
export class ConfigKeyProvider {
|
|
47
|
-
name =
|
|
45
|
+
name = "config-keys";
|
|
48
46
|
keys;
|
|
49
47
|
constructor(keys) {
|
|
50
48
|
this.keys = keys;
|
|
51
49
|
}
|
|
52
50
|
match(ctx) {
|
|
53
|
-
return ctx.tokenIndex >= 1 && ctx.tokens[0] ===
|
|
51
|
+
return ctx.tokenIndex >= 1 && ctx.tokens[0] === "/config" && ctx.tokens[1] === "set";
|
|
54
52
|
}
|
|
55
53
|
complete(ctx) {
|
|
56
|
-
return this.keys.filter(k => k.startsWith(ctx.partial));
|
|
54
|
+
return this.keys.filter((k) => k.startsWith(ctx.partial));
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
57
|
export class FilePathProvider {
|
|
60
|
-
name =
|
|
58
|
+
name = "file-paths";
|
|
61
59
|
match(ctx) {
|
|
62
|
-
return ctx.partial.includes(
|
|
60
|
+
return ctx.partial.includes("/") || ctx.partial.includes("\\");
|
|
63
61
|
}
|
|
64
62
|
complete(ctx) {
|
|
65
63
|
try {
|
|
66
64
|
const cwd = process.cwd();
|
|
67
65
|
const partialPath = ctx.partial;
|
|
68
|
-
const lastSlash = Math.max(partialPath.lastIndexOf(
|
|
69
|
-
const dirPath = lastSlash > 0 ? partialPath.slice(0, lastSlash) :
|
|
70
|
-
const prefix = lastSlash > 0 ? partialPath.slice(0, lastSlash + 1) :
|
|
66
|
+
const lastSlash = Math.max(partialPath.lastIndexOf("/"), partialPath.lastIndexOf("\\"));
|
|
67
|
+
const dirPath = lastSlash > 0 ? partialPath.slice(0, lastSlash) : ".";
|
|
68
|
+
const prefix = lastSlash > 0 ? partialPath.slice(0, lastSlash + 1) : "";
|
|
71
69
|
const fullPath = join(cwd, dirPath);
|
|
72
70
|
const entries = readdirSync(fullPath);
|
|
73
71
|
const matches = [];
|
|
74
72
|
for (const entry of entries) {
|
|
75
73
|
const entryPath = join(fullPath, entry);
|
|
76
74
|
const stat = statSync(entryPath);
|
|
77
|
-
const completion = prefix + entry + (stat.isDirectory() ?
|
|
75
|
+
const completion = prefix + entry + (stat.isDirectory() ? "/" : "");
|
|
78
76
|
if (completion.startsWith(ctx.partial)) {
|
|
79
77
|
matches.push(completion);
|
|
80
78
|
}
|
|
@@ -87,59 +85,60 @@ export class FilePathProvider {
|
|
|
87
85
|
}
|
|
88
86
|
}
|
|
89
87
|
export class ProviderArgProvider {
|
|
90
|
-
name =
|
|
88
|
+
name = "provider-args";
|
|
91
89
|
providers;
|
|
92
90
|
constructor(providers) {
|
|
93
91
|
this.providers = providers;
|
|
94
92
|
}
|
|
95
93
|
match(ctx) {
|
|
96
|
-
return ctx.tokenIndex === 2 && ctx.tokens[0] ===
|
|
94
|
+
return ctx.tokenIndex === 2 && ctx.tokens[0] === "/provider" && ctx.tokens[1] === "use";
|
|
97
95
|
}
|
|
98
96
|
complete(ctx) {
|
|
99
|
-
return this.providers.filter(p => p.startsWith(ctx.partial));
|
|
97
|
+
return this.providers.filter((p) => p.startsWith(ctx.partial));
|
|
100
98
|
}
|
|
101
99
|
}
|
|
102
100
|
export class SessionNameProvider {
|
|
103
|
-
name =
|
|
101
|
+
name = "session-names";
|
|
104
102
|
getNames;
|
|
105
103
|
constructor(getNames) {
|
|
106
104
|
this.getNames = getNames;
|
|
107
105
|
}
|
|
108
106
|
match(ctx) {
|
|
109
|
-
return ctx.tokenIndex >= 1 && ctx.tokens[0] ===
|
|
107
|
+
return ctx.tokenIndex >= 1 && ctx.tokens[0] === "/resume";
|
|
110
108
|
}
|
|
111
109
|
complete(ctx) {
|
|
112
110
|
const names = this.getNames();
|
|
113
111
|
if (!ctx.partial)
|
|
114
112
|
return names;
|
|
115
|
-
return names.filter(n => n.toLowerCase().includes(ctx.partial.toLowerCase()));
|
|
113
|
+
return names.filter((n) => n.toLowerCase().includes(ctx.partial.toLowerCase()));
|
|
116
114
|
}
|
|
117
115
|
}
|
|
118
116
|
export class SkillNameProvider {
|
|
119
|
-
name =
|
|
117
|
+
name = "skill-names";
|
|
120
118
|
skillsModule;
|
|
121
119
|
constructor(skillsModule) {
|
|
122
120
|
this.skillsModule = skillsModule;
|
|
123
121
|
}
|
|
124
122
|
match(ctx) {
|
|
125
|
-
return ctx.tokenIndex >= 2 &&
|
|
126
|
-
|
|
123
|
+
return (ctx.tokenIndex >= 2 &&
|
|
124
|
+
ctx.tokens[0] === "/skill" &&
|
|
125
|
+
(ctx.tokens[1] === "load" || ctx.tokens[1] === "unload"));
|
|
127
126
|
}
|
|
128
127
|
complete(ctx) {
|
|
129
128
|
const subcmd = ctx.tokens[1];
|
|
130
|
-
if (subcmd ===
|
|
129
|
+
if (subcmd === "load") {
|
|
131
130
|
const available = this.skillsModule.getAvailable();
|
|
132
|
-
const names = available.map(s => s.name);
|
|
131
|
+
const names = available.map((s) => s.name);
|
|
133
132
|
if (!ctx.partial)
|
|
134
133
|
return names;
|
|
135
|
-
return names.filter(n => n.toLowerCase().includes(ctx.partial.toLowerCase()));
|
|
134
|
+
return names.filter((n) => n.toLowerCase().includes(ctx.partial.toLowerCase()));
|
|
136
135
|
}
|
|
137
|
-
if (subcmd ===
|
|
136
|
+
if (subcmd === "unload") {
|
|
138
137
|
const loaded = this.skillsModule.getLoaded();
|
|
139
|
-
const names = loaded.map(s => s.name);
|
|
138
|
+
const names = loaded.map((s) => s.name);
|
|
140
139
|
if (!ctx.partial)
|
|
141
140
|
return names;
|
|
142
|
-
return names.filter(n => n.toLowerCase().includes(ctx.partial.toLowerCase()));
|
|
141
|
+
return names.filter((n) => n.toLowerCase().includes(ctx.partial.toLowerCase()));
|
|
143
142
|
}
|
|
144
143
|
return [];
|
|
145
144
|
}
|
|
@@ -152,7 +151,7 @@ export class Completer {
|
|
|
152
151
|
complete(line) {
|
|
153
152
|
const cursor = line.length;
|
|
154
153
|
const tokens = line.split(/\s+/);
|
|
155
|
-
const partial = tokens[tokens.length - 1] ||
|
|
154
|
+
const partial = tokens[tokens.length - 1] || "";
|
|
156
155
|
const tokenIndex = tokens.length - 1;
|
|
157
156
|
const ctx = { line, cursor, tokens, partial, tokenIndex };
|
|
158
157
|
for (const provider of this.providers) {
|
package/dist/cli/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { main } from
|
|
2
|
-
export { createProgram } from
|
|
1
|
+
export { main } from "./main";
|
|
2
|
+
export { createProgram } from "./commands";
|
package/dist/cli/main.js
CHANGED
|
@@ -1,15 +1,50 @@
|
|
|
1
1
|
import { createProgram } from "./commands";
|
|
2
2
|
import { bootstrap } from "../core/bootstrap";
|
|
3
3
|
import { Repl } from "./repl";
|
|
4
|
-
import { formatMarkdown } from "../ui/md-formatter";
|
|
5
4
|
import { Renderer } from "../ui/renderer";
|
|
5
|
+
import { printRunResult } from "./run-result";
|
|
6
6
|
import { runSetup } from "./setup";
|
|
7
7
|
import { saveConfig, loadConfig } from "../config/config";
|
|
8
8
|
import { t } from "../i18n/index";
|
|
9
9
|
import { pc } from "../ui/colors";
|
|
10
|
-
import { existsSync } from "fs";
|
|
11
|
-
import { join } from "path";
|
|
10
|
+
import { existsSync, readFileSync } from "fs";
|
|
11
|
+
import { join, dirname } from "path";
|
|
12
12
|
import { homedir } from "os";
|
|
13
|
+
import { fileURLToPath } from "url";
|
|
14
|
+
import { UpdaterModule } from "../modules/updater/index";
|
|
15
|
+
function readVersion() {
|
|
16
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const candidates = [join(here, "..", "..", "package.json"), join(here, "..", "package.json")];
|
|
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
|
+
// fall through
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return "0.0.0";
|
|
31
|
+
}
|
|
32
|
+
/** Fire-and-forget self-update in the background (never blocks startup). */
|
|
33
|
+
function startAutoUpdate(config) {
|
|
34
|
+
try {
|
|
35
|
+
const module = new UpdaterModule(config.updater, readVersion(), "micro-models-agent", {
|
|
36
|
+
info: (m) => process.stderr.write(pc.dim(m) + "\n"),
|
|
37
|
+
warn: (m) => process.stderr.write(pc.yellow(m) + "\n"),
|
|
38
|
+
error: (m) => process.stderr.write(pc.red(m) + "\n"),
|
|
39
|
+
});
|
|
40
|
+
module.start();
|
|
41
|
+
return module;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Auto-update is best-effort; never let it crash startup.
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
13
48
|
async function main() {
|
|
14
49
|
const program = createProgram();
|
|
15
50
|
program.parse(process.argv);
|
|
@@ -26,6 +61,7 @@ async function main() {
|
|
|
26
61
|
if (program.args.length > 0) {
|
|
27
62
|
const prompt = program.args.join(" ");
|
|
28
63
|
const { agent, config } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
|
|
64
|
+
const updater = exitOnComplete ? undefined : startAutoUpdate(config);
|
|
29
65
|
if (jsonMode) {
|
|
30
66
|
const result = await agent.run(prompt);
|
|
31
67
|
agent.shutdown();
|
|
@@ -41,6 +77,7 @@ async function main() {
|
|
|
41
77
|
totalTokens: result.totalTokens ?? null,
|
|
42
78
|
}, null, 2));
|
|
43
79
|
process.stdout.write("\n");
|
|
80
|
+
await updater?.waitForIdle();
|
|
44
81
|
process.exit(result.success ? 0 : 1);
|
|
45
82
|
}
|
|
46
83
|
const renderer = new Renderer({
|
|
@@ -63,19 +100,10 @@ async function main() {
|
|
|
63
100
|
}
|
|
64
101
|
});
|
|
65
102
|
renderer.flush();
|
|
66
|
-
|
|
67
|
-
if (!result.text) {
|
|
68
|
-
console.log(pc.yellow(t("cli.no_output")));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
console.error(`${t("error.prefix")}${result.error}`);
|
|
73
|
-
if (result.text) {
|
|
74
|
-
console.log(formatMarkdown(result.text));
|
|
75
|
-
}
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
103
|
+
const exitCode = printRunResult(result, () => renderer.flush());
|
|
78
104
|
agent.shutdown();
|
|
105
|
+
await updater?.waitForIdle();
|
|
106
|
+
process.exit(exitCode);
|
|
79
107
|
}
|
|
80
108
|
else {
|
|
81
109
|
const configPath = join(homedir(), ".mma", "config.json");
|
|
@@ -84,9 +112,7 @@ async function main() {
|
|
|
84
112
|
const answers = await runSetup();
|
|
85
113
|
const config = loadConfig({
|
|
86
114
|
configDir: join(homedir(), ".mma"),
|
|
87
|
-
projectConfigPath: projectDir
|
|
88
|
-
? join(projectDir, ".mmrc")
|
|
89
|
-
: join(process.cwd(), ".mmrc"),
|
|
115
|
+
projectConfigPath: projectDir ? join(projectDir, ".mmrc") : join(process.cwd(), ".mmrc"),
|
|
90
116
|
});
|
|
91
117
|
config.provider.type = answers.provider;
|
|
92
118
|
config.provider.baseUrl = answers.apiBase;
|
|
@@ -97,9 +123,7 @@ async function main() {
|
|
|
97
123
|
config.locale = answers.locale;
|
|
98
124
|
if (config.security) {
|
|
99
125
|
config.security.enabled =
|
|
100
|
-
answers.securityBashBlock ||
|
|
101
|
-
answers.securityFlagsBlock ||
|
|
102
|
-
!answers.securityPathsDeny;
|
|
126
|
+
answers.securityBashBlock || answers.securityFlagsBlock || !answers.securityPathsDeny;
|
|
103
127
|
config.security.bash.enabled = config.security.enabled;
|
|
104
128
|
config.security.bash.blockDangerousFlags = answers.securityFlagsBlock;
|
|
105
129
|
if (answers.securityBashBlock) {
|
|
@@ -132,8 +156,9 @@ async function main() {
|
|
|
132
156
|
saveConfig(config, configPath);
|
|
133
157
|
}
|
|
134
158
|
const { agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, logger, } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
|
|
135
|
-
|
|
136
|
-
repl
|
|
159
|
+
startAutoUpdate(config);
|
|
160
|
+
const repl = new Repl(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger, true);
|
|
161
|
+
await repl.start();
|
|
137
162
|
}
|
|
138
163
|
}
|
|
139
164
|
main();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { bootstrap } from "../core/bootstrap";
|
|
2
|
+
import { readMmaVersion } from "../core/version";
|
|
3
|
+
import { t } from "../i18n/index";
|
|
4
|
+
/**
|
|
5
|
+
* Create the `mma plugins` subcommand group.
|
|
6
|
+
*/
|
|
7
|
+
export function createPluginCommand(program) {
|
|
8
|
+
const pluginsCmd = program.command("plugins").description(t("cli.plugins.description"));
|
|
9
|
+
pluginsCmd
|
|
10
|
+
.command("list")
|
|
11
|
+
.description(t("cli.plugins.list"))
|
|
12
|
+
.option("-a, --all", t("cli.plugins.all"))
|
|
13
|
+
.action(async (cmdOpts) => {
|
|
14
|
+
const { pluginManager } = await bootstrap();
|
|
15
|
+
const all = cmdOpts.all === true;
|
|
16
|
+
let infos = pluginManager.getPluginInfos();
|
|
17
|
+
if (!all) {
|
|
18
|
+
infos = infos.filter(({ plugin }) => !plugin.isBuiltin);
|
|
19
|
+
}
|
|
20
|
+
if (infos.length === 0) {
|
|
21
|
+
console.log(t("cli.plugins.none"));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const mmaVersion = readMmaVersion();
|
|
25
|
+
console.log(t("cli.plugins.header", { count: String(infos.length), mma: mmaVersion }));
|
|
26
|
+
for (const { plugin, source } of infos) {
|
|
27
|
+
const version = plugin.version || "-";
|
|
28
|
+
const origin = source || "builtin";
|
|
29
|
+
const builtin = plugin.isBuiltin ? t("cli.plugins.builtin_mark") : " ";
|
|
30
|
+
console.log(` ${builtin} ${plugin.name} v${version} [${origin}]`);
|
|
31
|
+
}
|
|
32
|
+
if (!all) {
|
|
33
|
+
console.log(t("cli.plugins.only_external"));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -10,10 +10,7 @@ import { existsSync, readFileSync } from "fs";
|
|
|
10
10
|
import { fileURLToPath } from "url";
|
|
11
11
|
function readVersion() {
|
|
12
12
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
const candidates = [
|
|
14
|
-
join(here, "..", "..", "package.json"),
|
|
15
|
-
join(here, "..", "package.json"),
|
|
16
|
-
];
|
|
13
|
+
const candidates = [join(here, "..", "..", "package.json"), join(here, "..", "package.json")];
|
|
17
14
|
for (const p of candidates) {
|
|
18
15
|
if (existsSync(p)) {
|
|
19
16
|
try {
|
|
@@ -50,6 +47,7 @@ export const COMMAND_GROUPS = {
|
|
|
50
47
|
rename: "session",
|
|
51
48
|
delete: "session",
|
|
52
49
|
skill: "skill",
|
|
50
|
+
plugins: "agent",
|
|
53
51
|
};
|
|
54
52
|
export function registerAllCommands(ctx) {
|
|
55
53
|
registerBuiltinCommands(ctx);
|
|
@@ -122,8 +120,7 @@ function registerMmaCommands(ctx) {
|
|
|
122
120
|
dataUrl = result.dataUrl;
|
|
123
121
|
label = "clipboard";
|
|
124
122
|
}
|
|
125
|
-
else if (source.startsWith("http://") ||
|
|
126
|
-
source.startsWith("https://")) {
|
|
123
|
+
else if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
127
124
|
const result = await loadUrlAsDataUrl(source);
|
|
128
125
|
dataUrl = result.dataUrl;
|
|
129
126
|
label = source;
|
|
@@ -184,9 +181,7 @@ function registerMmaCommands(ctx) {
|
|
|
184
181
|
usage: t("repl.reasoning_usage"),
|
|
185
182
|
action: () => {
|
|
186
183
|
ctx.config.showReasoning = !ctx.config.showReasoning;
|
|
187
|
-
const status = ctx.config.showReasoning
|
|
188
|
-
? pc.green(t("repl.show"))
|
|
189
|
-
: pc.dim(t("repl.hide"));
|
|
184
|
+
const status = ctx.config.showReasoning ? pc.green(t("repl.show")) : pc.dim(t("repl.hide"));
|
|
190
185
|
console.log(t("repl.reasoning_status", { status }));
|
|
191
186
|
},
|
|
192
187
|
});
|
|
@@ -391,6 +386,41 @@ function registerMmaCommands(ctx) {
|
|
|
391
386
|
console.log(`${t("repl.provider")} ${ctx.config.provider.type} @ ${ctx.config.provider.baseUrl}`);
|
|
392
387
|
},
|
|
393
388
|
});
|
|
389
|
+
ctx.registerCommand({
|
|
390
|
+
name: "plugins",
|
|
391
|
+
description: t("repl.plugins"),
|
|
392
|
+
usage: t("repl.plugins_usage"),
|
|
393
|
+
action: (args) => {
|
|
394
|
+
if (!ctx.pluginManager) {
|
|
395
|
+
console.log(t("cli.plugins.none"));
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const showAll = args.includes("--all");
|
|
399
|
+
const infos = ctx.pluginManager.getPluginInfos();
|
|
400
|
+
const filtered = showAll ? infos : infos.filter(({ plugin }) => !plugin.isBuiltin);
|
|
401
|
+
if (filtered.length === 0) {
|
|
402
|
+
console.log(t("cli.plugins.none"));
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const mmaVersion = version;
|
|
406
|
+
console.log(t("cli.plugins.header", {
|
|
407
|
+
count: String(filtered.length),
|
|
408
|
+
mma: mmaVersion,
|
|
409
|
+
}));
|
|
410
|
+
for (const { plugin, source } of filtered) {
|
|
411
|
+
const v = plugin.version || "-";
|
|
412
|
+
const origin = source || "builtin";
|
|
413
|
+
const mark = plugin.isBuiltin ? t("cli.plugins.builtin_mark") : " ";
|
|
414
|
+
console.log(` ${mark} ${plugin.name} v${v} [${origin}]`);
|
|
415
|
+
}
|
|
416
|
+
if (!showAll) {
|
|
417
|
+
const builtinCount = infos.filter(({ plugin }) => plugin.isBuiltin).length;
|
|
418
|
+
if (builtinCount > 0) {
|
|
419
|
+
console.log(pc.dim(` (${builtinCount} builtin hidden — /plugins --all to show)`));
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
});
|
|
394
424
|
}
|
|
395
425
|
function registerSessionCommands(ctx) {
|
|
396
426
|
if (!ctx.sessionManager)
|
|
@@ -559,9 +589,7 @@ function registerSkillCommands(ctx) {
|
|
|
559
589
|
console.log(pc.bold(t("repl.available_skills")));
|
|
560
590
|
for (const skill of available) {
|
|
561
591
|
const tokens = Math.ceil(skill.content.length / 4);
|
|
562
|
-
const loaded = ctx
|
|
563
|
-
.skillsModule.getLoaded()
|
|
564
|
-
.some((s) => s.name === skill.name);
|
|
592
|
+
const loaded = ctx.skillsModule.getLoaded().some((s) => s.name === skill.name);
|
|
565
593
|
const marker = loaded ? pc.green(" [loaded]") : "";
|
|
566
594
|
console.log(` ${pc.cyan(skill.name)}${marker} ${pc.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
|
|
567
595
|
}
|