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/dist/cli/setup.js CHANGED
@@ -119,12 +119,14 @@ async function testChat(apiBase, apiKey, model) {
119
119
  return false;
120
120
  }
121
121
  }
122
- export async function runSetup() {
122
+ export async function runSetup(externalRl) {
123
123
  console.log(t("setup.title"));
124
- const rl = readline.createInterface({
125
- input: process.stdin,
126
- output: process.stdout,
127
- });
124
+ const rl = externalRl ||
125
+ readline.createInterface({
126
+ input: process.stdin,
127
+ output: process.stdout,
128
+ });
129
+ const ownRl = !externalRl;
128
130
  console.log(t("setup.language"));
129
131
  const locale = await ask(rl, t("setup.ui_lang"), "en");
130
132
  setLocale(locale);
@@ -193,12 +195,20 @@ export async function runSetup() {
193
195
  let securityBashBlock = false;
194
196
  let securityFlagsBlock = false;
195
197
  let securityPathsDeny = true;
196
- if (configureSecurity.toLowerCase() === "y" || configureSecurity.toLowerCase() === "yes") {
197
- securityBashBlock = (await ask(rl, t("setup.security_bash_block"), "n")).toLowerCase() === "y";
198
- securityFlagsBlock = (await ask(rl, t("setup.security_flags_block"), "n")).toLowerCase() === "y";
199
- securityPathsDeny = (await ask(rl, t("setup.security_paths_deny"), "Y")).toLowerCase() !== "n";
198
+ if (configureSecurity.toLowerCase() === "y" ||
199
+ configureSecurity.toLowerCase() === "yes") {
200
+ securityBashBlock =
201
+ (await ask(rl, t("setup.security_bash_block"), "n")).toLowerCase() ===
202
+ "y";
203
+ securityFlagsBlock =
204
+ (await ask(rl, t("setup.security_flags_block"), "n")).toLowerCase() ===
205
+ "y";
206
+ securityPathsDeny =
207
+ (await ask(rl, t("setup.security_paths_deny"), "Y")).toLowerCase() !==
208
+ "n";
200
209
  }
201
- rl.close();
210
+ if (ownRl)
211
+ rl.close();
202
212
  const answers = {
203
213
  provider,
204
214
  apiBase,
@@ -219,8 +229,18 @@ export async function runSetup() {
219
229
  t("setup.summary_value"),
220
230
  ], [
221
231
  [t("setup.provider_type"), provider, t("setup.model_name"), model],
222
- ["API Base URL", apiBase, t("setup.context_window"), String(contextWindow)],
223
- [t("setup.api_key"), apiKey || "not-needed", t("setup.max_iters"), String(maxIterations)],
232
+ [
233
+ "API Base URL",
234
+ apiBase,
235
+ t("setup.context_window"),
236
+ String(contextWindow),
237
+ ],
238
+ [
239
+ t("setup.api_key"),
240
+ apiKey || "not-needed",
241
+ t("setup.max_iters"),
242
+ String(maxIterations),
243
+ ],
224
244
  [t("setup.ui_lang"), locale, "", ""],
225
245
  ], { maxColumns: 4 });
226
246
  for (const l of summary)
@@ -1,12 +1,12 @@
1
- import { existsSync, readFileSync, unlinkSync, writeFileSync, mkdirSync } from 'fs';
2
- import { join, dirname } from 'path';
3
- import { DEFAULTS } from './defaults';
4
- import { DEFAULT_SECURITY_CONFIG } from './security';
5
- import { t } from '../i18n/index';
6
- import { MigrationDetector } from '../migration/detect';
7
- import { BackupManager } from '../migration/backup';
8
- import { validateExpertConfig } from './experts';
9
- import { ConfigEncryptor } from '../modules/security/encryption';
1
+ import { existsSync, readFileSync, unlinkSync, writeFileSync, mkdirSync, } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { DEFAULTS } from "./defaults";
4
+ import { DEFAULT_SECURITY_CONFIG } from "./security";
5
+ import { t } from "../i18n/index";
6
+ import { MigrationDetector } from "../migration/detect";
7
+ import { BackupManager } from "../migration/backup";
8
+ import { validateExpertConfig } from "./experts";
9
+ import { ConfigEncryptor, } from "../modules/security/encryption";
10
10
  /**
11
11
  * Restore RegExp instances in dangerousPatterns that were serialized as {}
12
12
  * (pre-0.8.0 configs) or as {__regex, source, flags} (new format).
@@ -41,9 +41,12 @@ function deepMerge(target, source) {
41
41
  for (const key of Object.keys(source)) {
42
42
  const srcVal = source[key];
43
43
  const tgtVal = target[key];
44
- if (srcVal !== null && srcVal !== undefined &&
45
- typeof srcVal === 'object' && !Array.isArray(srcVal) &&
46
- typeof tgtVal === 'object' && !Array.isArray(tgtVal)) {
44
+ if (srcVal !== null &&
45
+ srcVal !== undefined &&
46
+ typeof srcVal === "object" &&
47
+ !Array.isArray(srcVal) &&
48
+ typeof tgtVal === "object" &&
49
+ !Array.isArray(tgtVal)) {
47
50
  result[key] = deepMerge(tgtVal, srcVal);
48
51
  }
49
52
  else if (srcVal !== undefined) {
@@ -82,10 +85,12 @@ function regexReviver(_key, value) {
82
85
  function loadJSON(path) {
83
86
  try {
84
87
  if (existsSync(path)) {
85
- return JSON.parse(readFileSync(path, 'utf-8'), regexReviver);
88
+ return JSON.parse(readFileSync(path, "utf-8"), regexReviver);
86
89
  }
87
90
  }
88
- catch { /* ignore malformed files */ }
91
+ catch {
92
+ /* ignore malformed files */
93
+ }
89
94
  return null;
90
95
  }
91
96
  function applyEnvVars(config) {
@@ -103,27 +108,36 @@ function applyEnvVars(config) {
103
108
  result.logLevel = env.MMA_LOG_LEVEL;
104
109
  if (env.MMA_LOCALE)
105
110
  result.locale = env.MMA_LOCALE;
106
- if (env.MMA_CONTEXT_WINDOW)
107
- result.contextWindow = parseInt(env.MMA_CONTEXT_WINDOW, 10);
108
- if (env.MMA_MAX_TOOL_ITERATIONS)
109
- result.maxToolIterations = parseInt(env.MMA_MAX_TOOL_ITERATIONS, 10);
110
- if (env.MMA_STUCK_THRESHOLD)
111
- result.stuckThreshold = parseInt(env.MMA_STUCK_THRESHOLD, 10);
111
+ if (env.MMA_CONTEXT_WINDOW) {
112
+ const v = parseInt(env.MMA_CONTEXT_WINDOW, 10);
113
+ if (!isNaN(v))
114
+ result.contextWindow = v;
115
+ }
116
+ if (env.MMA_MAX_TOOL_ITERATIONS) {
117
+ const v = parseInt(env.MMA_MAX_TOOL_ITERATIONS, 10);
118
+ if (!isNaN(v))
119
+ result.maxToolIterations = v;
120
+ }
121
+ if (env.MMA_STUCK_THRESHOLD) {
122
+ const v = parseInt(env.MMA_STUCK_THRESHOLD, 10);
123
+ if (!isNaN(v))
124
+ result.stuckThreshold = v;
125
+ }
112
126
  if (env.MMA_AUTO_PLAN)
113
- result.autoPlan = env.MMA_AUTO_PLAN === 'true';
127
+ result.autoPlan = env.MMA_AUTO_PLAN === "true";
114
128
  if (env.MMA_MOE_ENABLED)
115
- result.moe = { ...result.moe, enabled: env.MMA_MOE_ENABLED === 'true' };
129
+ result.moe = { ...result.moe, enabled: env.MMA_MOE_ENABLED === "true" };
116
130
  return result;
117
131
  }
118
132
  export function loadConfig(options) {
119
- const globalPath = join(options.configDir, 'config.json');
133
+ const globalPath = join(options.configDir, "config.json");
120
134
  mkdirSync(options.configDir, { recursive: true });
121
135
  const detector = new MigrationDetector(options.configDir);
122
136
  if (detector.needsMigration()) {
123
137
  const backup = new BackupManager(options.configDir);
124
138
  backup.backupConfig();
125
139
  const summary = backup.getBackupSummary();
126
- console.log(t('migration.detected', { summary }));
140
+ console.log(t("migration.detected", { summary }));
127
141
  try {
128
142
  unlinkSync(globalPath);
129
143
  }
@@ -158,7 +172,7 @@ export function loadConfig(options) {
158
172
  }
159
173
  catch (e) {
160
174
  // If decryption fails, log a warning but continue with the config
161
- console.warn(t('config.decryption_warning', { error: e.message }));
175
+ console.warn(t("config.decryption_warning", { error: e.message }));
162
176
  }
163
177
  // Update global audit notifier with config (done in bootstrap.ts)
164
178
  return config;
@@ -166,7 +180,7 @@ export function loadConfig(options) {
166
180
  export function validateConfig(config, allToolTags) {
167
181
  const errors = validateExpertConfig(config, allToolTags);
168
182
  if (errors.length > 0) {
169
- throw new Error(`Config validation failed:\n${errors.join('\n')}`);
183
+ throw new Error(`Config validation failed:\n${errors.join("\n")}`);
170
184
  }
171
185
  }
172
186
  export function saveConfig(config, configPath) {
@@ -175,12 +189,14 @@ export function saveConfig(config, configPath) {
175
189
  // Encrypt sensitive fields before saving
176
190
  try {
177
191
  const encryptor = new ConfigEncryptor();
178
- const encryptedConfig = encryptor.encrypt({ ...config });
179
- writeFileSync(configPath, JSON.stringify(encryptedConfig, regexReplacer, 2), 'utf-8');
192
+ const encryptedConfig = encryptor.encrypt({
193
+ ...config,
194
+ });
195
+ writeFileSync(configPath, JSON.stringify(encryptedConfig, regexReplacer, 2), "utf-8");
180
196
  }
181
197
  catch (e) {
182
198
  // If encryption fails, save without encryption
183
- console.warn(t('config.encryption_warning', { error: e.message }));
184
- writeFileSync(configPath, JSON.stringify(config, regexReplacer, 2), 'utf-8');
199
+ console.warn(t("config.encryption_warning", { error: e.message }));
200
+ writeFileSync(configPath, JSON.stringify(config, regexReplacer, 2), "utf-8");
185
201
  }
186
202
  }
@@ -1,4 +1,5 @@
1
1
  import { DEFAULT_SECURITY_CONFIG } from "./security";
2
+ import { DEFAULT_LSP_CONFIG } from "../modules/lsp/config";
2
3
  export const DEFAULTS = {
3
4
  version: "2.0.0",
4
5
  model: "qwen3.5-9b",
@@ -49,7 +50,7 @@ export const DEFAULTS = {
49
50
  maxDelay: 30000,
50
51
  },
51
52
  maxToolIterations: 1000,
52
- stuckThreshold: 8,
53
+ stuckThreshold: 6,
53
54
  autoPlan: true,
54
55
  showReasoning: false,
55
56
  logLevel: "info",
@@ -69,6 +70,10 @@ export const DEFAULTS = {
69
70
  },
70
71
  ui: {
71
72
  spinner: true,
73
+ toolStyle: "inline",
74
+ toolComments: true,
75
+ showContextStats: false,
76
+ showCompaction: true,
72
77
  },
73
78
  mcpServers: {
74
79
  context7: {
@@ -88,4 +93,8 @@ export const DEFAULTS = {
88
93
  isolatePlugins: true,
89
94
  isolateTempFiles: true,
90
95
  },
96
+ skills: {
97
+ budget: 0.15,
98
+ },
99
+ lsp: DEFAULT_LSP_CONFIG,
91
100
  };
@@ -3,7 +3,9 @@
3
3
  * These settings provide a balance between security and usability.
4
4
  */
5
5
  export const DEFAULT_SECURITY_CONFIG = {
6
+ enabled: false,
6
7
  bash: {
8
+ enabled: false,
7
9
  // Commands that are always blocked (dangerous)
8
10
  blacklist: [
9
11
  "rm",
@@ -74,6 +76,7 @@ export const DEFAULT_SECURITY_CONFIG = {
74
76
  dangerousOperators: [">", ">>", "2>", "2>>", "`"],
75
77
  },
76
78
  paths: {
79
+ enabled: false,
77
80
  // Glob patterns for paths that are always denied
78
81
  denied: [
79
82
  ".git/",
@@ -95,6 +98,7 @@ export const DEFAULT_SECURITY_CONFIG = {
95
98
  allowed: [],
96
99
  },
97
100
  network: {
101
+ enabled: false,
98
102
  // Domains that are always denied
99
103
  deniedDomains: ["localhost", "127.0.0.1", "::1"],
100
104
  // If allowedDomains is non-empty, only these domains are allowed
@@ -115,7 +119,7 @@ export const DEFAULT_SECURITY_CONFIG = {
115
119
  },
116
120
  // Content scanning settings
117
121
  contentScan: {
118
- enabled: true,
122
+ enabled: false,
119
123
  // Patterns that are considered dangerous in file content
120
124
  dangerousPatterns: [
121
125
  /eval\(/,
@@ -142,12 +146,12 @@ export const DEFAULT_SECURITY_CONFIG = {
142
146
  // Audit notification settings
143
147
  auditNotifier: {
144
148
  enabled: false,
145
- minSeverity: 'medium',
149
+ minSeverity: "medium",
146
150
  eventTypes: [
147
- 'security_block',
148
- 'bash_command',
149
- 'file_operation',
150
- 'network_request',
151
+ "security_block",
152
+ "bash_command",
153
+ "file_operation",
154
+ "network_request",
151
155
  ],
152
156
  maxRetries: 3,
153
157
  webhookTimeout: 5000,
@@ -159,6 +163,7 @@ export const DEFAULT_SECURITY_CONFIG = {
159
163
  */
160
164
  export function mergeSecurityConfig(userConfig) {
161
165
  return {
166
+ enabled: userConfig?.enabled ?? DEFAULT_SECURITY_CONFIG.enabled,
162
167
  bash: {
163
168
  ...DEFAULT_SECURITY_CONFIG.bash,
164
169
  ...userConfig?.bash,
@@ -171,8 +176,10 @@ export function mergeSecurityConfig(userConfig) {
171
176
  ...DEFAULT_SECURITY_CONFIG.network,
172
177
  ...userConfig?.network,
173
178
  },
174
- maxRecursionDepth: userConfig?.maxRecursionDepth ?? DEFAULT_SECURITY_CONFIG.maxRecursionDepth,
175
- maxFileOperations: userConfig?.maxFileOperations ?? DEFAULT_SECURITY_CONFIG.maxFileOperations,
179
+ maxRecursionDepth: userConfig?.maxRecursionDepth ??
180
+ DEFAULT_SECURITY_CONFIG.maxRecursionDepth,
181
+ maxFileOperations: userConfig?.maxFileOperations ??
182
+ DEFAULT_SECURITY_CONFIG.maxFileOperations,
176
183
  rateLimits: {
177
184
  ...DEFAULT_SECURITY_CONFIG.rateLimits,
178
185
  ...userConfig?.rateLimits,
@@ -64,18 +64,30 @@ export async function runWithMoE(deps, input, fallback, opts = {}) {
64
64
  ];
65
65
  const verification = await verifier.verifyMoEManifest(plan, config, knownTags);
66
66
  onPhase?.("thinking");
67
- const verifyResult = await orchestrator.verifyAndMerge({
68
- plan,
69
- results: planResults.results.map((r) => ({
70
- subtaskId: r.subtaskId,
71
- success: r.success,
72
- summary: r.summary,
73
- result: r.result,
74
- error: r.error,
75
- })),
76
- verifierErrors: verification.errors,
77
- verifierWarnings: verification.warnings,
78
- });
67
+ let verifyResult;
68
+ try {
69
+ verifyResult = await orchestrator.verifyAndMerge({
70
+ plan,
71
+ results: planResults.results.map((r) => ({
72
+ subtaskId: r.subtaskId,
73
+ success: r.success,
74
+ summary: r.summary,
75
+ result: r.result,
76
+ error: r.error,
77
+ })),
78
+ verifierErrors: verification.errors,
79
+ verifierWarnings: verification.warnings,
80
+ });
81
+ }
82
+ catch (err) {
83
+ onPhase?.("done");
84
+ return {
85
+ success: false,
86
+ text: `MoE verifyAndMerge crashed: ${err.message}`,
87
+ error: err.message,
88
+ iterationCount: 0,
89
+ };
90
+ }
79
91
  onPhase?.("done");
80
92
  const outputLines = [`## MoE Execution Results\n`];
81
93
  for (const r of planResults.results) {