micro-models-agent 0.41.2 → 0.43.0

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