micro-models-agent 0.44.0 → 0.45.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 (188) hide show
  1. package/README.md +312 -312
  2. package/bin/mma.mjs +41 -41
  3. package/dist/main.js +241 -56
  4. package/dist/skills/builtin/git.md +36 -36
  5. package/dist/skills/builtin/typescript.md +35 -35
  6. package/package.json +1 -1
  7. package/dist/cli/commands.js +0 -333
  8. package/dist/cli/completer.js +0 -168
  9. package/dist/cli/index.js +0 -2
  10. package/dist/cli/main.js +0 -140
  11. package/dist/cli/repl-commands.js +0 -633
  12. package/dist/cli/repl.js +0 -486
  13. package/dist/cli/security-commands.js +0 -166
  14. package/dist/cli/setup.js +0 -249
  15. package/dist/config/config.js +0 -202
  16. package/dist/config/defaults.js +0 -100
  17. package/dist/config/experts.js +0 -15
  18. package/dist/config/index.js +0 -3
  19. package/dist/config/security.js +0 -200
  20. package/dist/config/types.js +0 -1
  21. package/dist/core/agent-moe.js +0 -110
  22. package/dist/core/agent.js +0 -695
  23. package/dist/core/bootstrap.js +0 -337
  24. package/dist/core/index.js +0 -2
  25. package/dist/core/prompt-builder.js +0 -55
  26. package/dist/core/session-logger.js +0 -155
  27. package/dist/core/types.js +0 -1
  28. package/dist/core/workspace.js +0 -76
  29. package/dist/i18n/en.json +0 -525
  30. package/dist/i18n/index.js +0 -46
  31. package/dist/i18n/ru.json +0 -525
  32. package/dist/index.js +0 -22
  33. package/dist/llm/image-utils.js +0 -144
  34. package/dist/llm/index.js +0 -4
  35. package/dist/llm/model-loader.js +0 -78
  36. package/dist/llm/openai-compat.js +0 -353
  37. package/dist/llm/orchestrator.js +0 -194
  38. package/dist/llm/provider.js +0 -10
  39. package/dist/llm/response.js +0 -39
  40. package/dist/llm/token-counter.js +0 -39
  41. package/dist/llm/types.js +0 -1
  42. package/dist/logger/app-logger.js +0 -143
  43. package/dist/logger/file-log.js +0 -151
  44. package/dist/logger/index.js +0 -1
  45. package/dist/migration/backup.js +0 -45
  46. package/dist/migration/detect.js +0 -50
  47. package/dist/migration/index.js +0 -2
  48. package/dist/modules/browser/actions.js +0 -46
  49. package/dist/modules/browser/cookie-store.js +0 -24
  50. package/dist/modules/browser/index.js +0 -5
  51. package/dist/modules/browser/module.js +0 -28
  52. package/dist/modules/browser/session.js +0 -335
  53. package/dist/modules/browser/snapshot.js +0 -114
  54. package/dist/modules/browser/types.js +0 -9
  55. package/dist/modules/certification/cli.js +0 -176
  56. package/dist/modules/certification/fact-checker.js +0 -84
  57. package/dist/modules/certification/loader.js +0 -111
  58. package/dist/modules/certification/manifest.js +0 -50
  59. package/dist/modules/certification/runner.js +0 -162
  60. package/dist/modules/certification/scenarios.js +0 -124
  61. package/dist/modules/certification/types.js +0 -1
  62. package/dist/modules/context/index.js +0 -1
  63. package/dist/modules/context/manager.js +0 -349
  64. package/dist/modules/execution/auditor.js +0 -66
  65. package/dist/modules/execution/index.js +0 -8
  66. package/dist/modules/execution/module.js +0 -779
  67. package/dist/modules/execution/moe-executor.js +0 -266
  68. package/dist/modules/execution/plan-coverage.js +0 -68
  69. package/dist/modules/execution/plan-persister.js +0 -46
  70. package/dist/modules/execution/plan-store.js +0 -159
  71. package/dist/modules/execution/plan-validator.js +0 -153
  72. package/dist/modules/execution/planner.js +0 -85
  73. package/dist/modules/execution/stuck-detector.js +0 -347
  74. package/dist/modules/execution/tracker.js +0 -67
  75. package/dist/modules/execution/types.js +0 -1
  76. package/dist/modules/execution/verifier.js +0 -178
  77. package/dist/modules/hallucination/confidence.js +0 -59
  78. package/dist/modules/hallucination/consistency.js +0 -26
  79. package/dist/modules/hallucination/detector.js +0 -46
  80. package/dist/modules/hallucination/factual.js +0 -190
  81. package/dist/modules/hallucination/index.js +0 -5
  82. package/dist/modules/hallucination/js-identifiers.js +0 -72
  83. package/dist/modules/hallucination/llm-judge.js +0 -103
  84. package/dist/modules/index.js +0 -5
  85. package/dist/modules/indexer/cache.js +0 -38
  86. package/dist/modules/indexer/index.js +0 -3
  87. package/dist/modules/indexer/module.js +0 -192
  88. package/dist/modules/indexer/walker.js +0 -101
  89. package/dist/modules/lsp/client.js +0 -235
  90. package/dist/modules/lsp/config.js +0 -81
  91. package/dist/modules/lsp/index.js +0 -3
  92. package/dist/modules/lsp/module.js +0 -68
  93. package/dist/modules/lsp/types.js +0 -1
  94. package/dist/modules/mcp/client.js +0 -399
  95. package/dist/modules/mcp/index.js +0 -3
  96. package/dist/modules/mcp/module.js +0 -146
  97. package/dist/modules/mcp/registry.js +0 -15
  98. package/dist/modules/memory/index.js +0 -1
  99. package/dist/modules/memory/module.js +0 -48
  100. package/dist/modules/memory/search.js +0 -40
  101. package/dist/modules/memory/store.js +0 -69
  102. package/dist/modules/pipelines/engine.js +0 -60
  103. package/dist/modules/pipelines/index.js +0 -3
  104. package/dist/modules/pipelines/parser.js +0 -53
  105. package/dist/modules/pipelines/template.js +0 -14
  106. package/dist/modules/plugins/builtin/lint-on-write.js +0 -226
  107. package/dist/modules/plugins/builtin/notify.js +0 -8
  108. package/dist/modules/plugins/index.js +0 -1
  109. package/dist/modules/plugins/loader.js +0 -28
  110. package/dist/modules/plugins/manager.js +0 -161
  111. package/dist/modules/plugins/types.js +0 -1
  112. package/dist/modules/processes/index.js +0 -2
  113. package/dist/modules/processes/registry.js +0 -238
  114. package/dist/modules/processes/runner.js +0 -23
  115. package/dist/modules/registry.js +0 -45
  116. package/dist/modules/security/audit-log.js +0 -136
  117. package/dist/modules/security/audit-notifier.js +0 -292
  118. package/dist/modules/security/command-validator.js +0 -211
  119. package/dist/modules/security/content-scanner.js +0 -53
  120. package/dist/modules/security/data-sanitizer.js +0 -97
  121. package/dist/modules/security/encryption.js +0 -240
  122. package/dist/modules/security/index.js +0 -14
  123. package/dist/modules/security/network-validator.js +0 -79
  124. package/dist/modules/security/path-validator.js +0 -209
  125. package/dist/modules/security/rate-limiter.js +0 -119
  126. package/dist/modules/security/security-policies.js +0 -547
  127. package/dist/modules/security/session-encryption.js +0 -210
  128. package/dist/modules/security/session-isolation.js +0 -95
  129. package/dist/modules/session/index.js +0 -3
  130. package/dist/modules/session/manager.js +0 -172
  131. package/dist/modules/session/module.js +0 -24
  132. package/dist/modules/session/store.js +0 -228
  133. package/dist/modules/session/types.js +0 -1
  134. package/dist/modules/skills/index.js +0 -2
  135. package/dist/modules/skills/loader.js +0 -72
  136. package/dist/modules/skills/module.js +0 -130
  137. package/dist/modules/types.js +0 -1
  138. package/dist/modules/updater/checker.js +0 -32
  139. package/dist/modules/updater/index.js +0 -1
  140. package/dist/modules/user-profile/compressor.js +0 -16
  141. package/dist/modules/user-profile/index.js +0 -1
  142. package/dist/modules/user-profile/profile.js +0 -68
  143. package/dist/tools/approve.js +0 -32
  144. package/dist/tools/attach-image.js +0 -89
  145. package/dist/tools/bash.js +0 -337
  146. package/dist/tools/browser.js +0 -97
  147. package/dist/tools/create-dir.js +0 -55
  148. package/dist/tools/delete-file.js +0 -62
  149. package/dist/tools/edit-file.js +0 -79
  150. package/dist/tools/executor.js +0 -145
  151. package/dist/tools/file-info.js +0 -45
  152. package/dist/tools/filter-tools.js +0 -10
  153. package/dist/tools/glob-tool.js +0 -26
  154. package/dist/tools/grep-tool.js +0 -86
  155. package/dist/tools/index.js +0 -67
  156. package/dist/tools/list-dir.js +0 -47
  157. package/dist/tools/load-skill.js +0 -44
  158. package/dist/tools/mcp-call.js +0 -68
  159. package/dist/tools/move-file.js +0 -85
  160. package/dist/tools/path-utils.js +0 -51
  161. package/dist/tools/pipeline-run.js +0 -144
  162. package/dist/tools/preview.js +0 -2
  163. package/dist/tools/process-kill.js +0 -29
  164. package/dist/tools/process-list.js +0 -38
  165. package/dist/tools/process-log.js +0 -41
  166. package/dist/tools/question.js +0 -142
  167. package/dist/tools/read-file.js +0 -83
  168. package/dist/tools/recall.js +0 -110
  169. package/dist/tools/registry.js +0 -36
  170. package/dist/tools/remember.js +0 -67
  171. package/dist/tools/scope-check.js +0 -30
  172. package/dist/tools/search-history.js +0 -84
  173. package/dist/tools/subagent.js +0 -151
  174. package/dist/tools/types.js +0 -1
  175. package/dist/tools/user-input.js +0 -123
  176. package/dist/tools/web-browse.js +0 -86
  177. package/dist/tools/web-fetch.js +0 -98
  178. package/dist/tools/web-search.js +0 -78
  179. package/dist/tools/write-file.js +0 -83
  180. package/dist/ui/box.js +0 -81
  181. package/dist/ui/colors.js +0 -4
  182. package/dist/ui/diff.js +0 -178
  183. package/dist/ui/index.js +0 -6
  184. package/dist/ui/md-formatter.js +0 -212
  185. package/dist/ui/output.js +0 -13
  186. package/dist/ui/renderer.js +0 -204
  187. package/dist/ui/spinner.js +0 -70
  188. package/dist/ui/table.js +0 -144
package/dist/cli/setup.js DELETED
@@ -1,249 +0,0 @@
1
- import * as readline from "readline";
2
- import { pc } from "../ui/colors";
3
- import { t, setLocale } from "../i18n/index";
4
- import { Spinner } from "../ui/spinner";
5
- import { box } from "../ui/box";
6
- import { renderTable } from "../ui/table";
7
- async function withSpinner(message, fn) {
8
- const spinner = new Spinner();
9
- spinner.start(message);
10
- try {
11
- return await fn();
12
- }
13
- finally {
14
- spinner.stop();
15
- }
16
- }
17
- /** Render a numbered list inside a box. */
18
- function menuList(items) {
19
- const lines = items.map((it, i) => ` ${pc.cyan(`[${i + 1}]`)} ${it.label}${it.url ? ` ${pc.dim(it.url)}` : ""}`);
20
- for (const l of box(lines, { width: 72 }))
21
- console.log(l);
22
- }
23
- function ask(rl, question, defaultValue) {
24
- return new Promise((resolve) => {
25
- const prompt = defaultValue
26
- ? `${question} [${defaultValue}]: `
27
- : `${question}: `;
28
- rl.question(prompt, (answer) => {
29
- resolve(answer.trim() || defaultValue || "");
30
- });
31
- });
32
- }
33
- const PROVIDER_TYPES = [
34
- {
35
- value: "openai-compat",
36
- label: "OpenAI-compatible (LM Studio, Ollama, vLLM, etc.)",
37
- },
38
- { value: "openai", label: "OpenAI API" },
39
- { value: "anthropic", label: "Anthropic Claude" },
40
- ];
41
- const KNOWN_PORTS = [
42
- { port: 1234, label: "LM Studio" },
43
- { port: 11434, label: "Ollama" },
44
- { port: 8080, label: "vLLM / custom" },
45
- { port: 4891, label: "GPT4All" },
46
- ];
47
- async function scanPorts() {
48
- const found = [];
49
- for (const { port, label } of KNOWN_PORTS) {
50
- try {
51
- const controller = new AbortController();
52
- const timeout = setTimeout(() => controller.abort(), 2000);
53
- const resp = await fetch(`http://localhost:${port}/v1/models`, {
54
- signal: controller.signal,
55
- });
56
- clearTimeout(timeout);
57
- if (resp.ok) {
58
- found.push({ label, url: `http://localhost:${port}/v1` });
59
- }
60
- }
61
- catch {
62
- /* port not available */
63
- }
64
- }
65
- return found;
66
- }
67
- async function fetchModels(apiBase, apiKey) {
68
- try {
69
- const url = `${apiBase.replace(/\/+$/, "")}/models`;
70
- const controller = new AbortController();
71
- const timeout = setTimeout(() => controller.abort(), 5000);
72
- const resp = await fetch(url, {
73
- headers: {
74
- Authorization: `Bearer ${apiKey}`,
75
- "Content-Type": "application/json",
76
- },
77
- signal: controller.signal,
78
- });
79
- clearTimeout(timeout);
80
- if (!resp.ok)
81
- return [];
82
- const data = (await resp.json());
83
- const models = (data.data || data || [])
84
- .map((m) => m.id || m.name || m.model || "")
85
- .filter(Boolean);
86
- return models;
87
- }
88
- catch {
89
- return [];
90
- }
91
- }
92
- async function testChat(apiBase, apiKey, model) {
93
- try {
94
- const url = `${apiBase.replace(/\/+$/, "")}/chat/completions`;
95
- const controller = new AbortController();
96
- const timeout = setTimeout(() => controller.abort(), 10000);
97
- const resp = await fetch(url, {
98
- method: "POST",
99
- headers: {
100
- Authorization: `Bearer ${apiKey}`,
101
- "Content-Type": "application/json",
102
- },
103
- body: JSON.stringify({
104
- model,
105
- messages: [{ role: "user", content: 'Say "ok"' }],
106
- max_tokens: 20,
107
- }),
108
- signal: controller.signal,
109
- });
110
- clearTimeout(timeout);
111
- if (!resp.ok)
112
- return false;
113
- const data = (await resp.json());
114
- const msg = data.choices?.[0]?.message;
115
- const text = msg?.content || msg?.reasoning_content || "";
116
- return text.length > 0;
117
- }
118
- catch {
119
- return false;
120
- }
121
- }
122
- export async function runSetup(externalRl) {
123
- console.log(t("setup.title"));
124
- const rl = externalRl ||
125
- readline.createInterface({
126
- input: process.stdin,
127
- output: process.stdout,
128
- });
129
- const ownRl = !externalRl;
130
- console.log(t("setup.language"));
131
- const locale = await ask(rl, t("setup.ui_lang"), "en");
132
- setLocale(locale);
133
- console.log(t("setup.select_provider"));
134
- menuList(PROVIDER_TYPES);
135
- const providerChoice = await ask(rl, t("setup.select_provider_num", { max: PROVIDER_TYPES.length }), "1");
136
- const providerIdx = Math.max(0, Math.min(PROVIDER_TYPES.length - 1, (parseInt(providerChoice) || 1) - 1));
137
- const provider = PROVIDER_TYPES[providerIdx].value;
138
- let apiBase = "";
139
- if (provider === "openai-compat") {
140
- const found = await withSpinner(t("setup.scanning_spinner"), async () => scanPorts());
141
- if (found.length > 0) {
142
- console.log(t("setup.found_servers", { count: found.length }));
143
- menuList([
144
- ...found.map((f) => ({ label: f.label, url: f.url })),
145
- { label: t("setup.custom_url") },
146
- ]);
147
- const choice = await ask(rl, t("setup.select_server", { max: found.length + 1 }), "1");
148
- const idx = (parseInt(choice) || 1) - 1;
149
- if (idx >= found.length) {
150
- apiBase = await ask(rl, t("setup.api_base"), "http://localhost:1234/v1");
151
- }
152
- else {
153
- apiBase = found[Math.max(0, Math.min(found.length - 1, idx))].url;
154
- }
155
- }
156
- else {
157
- console.log(t("setup.no_servers"));
158
- apiBase = await ask(rl, t("setup.api_base"), "http://localhost:1234/v1");
159
- }
160
- }
161
- else if (provider === "openai") {
162
- apiBase = "https://api.openai.com/v1";
163
- }
164
- else if (provider === "anthropic") {
165
- apiBase = "https://api.anthropic.com";
166
- }
167
- const defaultKey = provider === "openai-compat" ? "not-needed" : "";
168
- const apiKey = await ask(rl, t("setup.api_key"), defaultKey);
169
- const models = await withSpinner(t("setup.fetching_spinner"), () => fetchModels(apiBase, apiKey));
170
- let model = "";
171
- if (models.length > 0) {
172
- console.log(t("setup.available_models"));
173
- menuList(models.slice(0, 10).map((m) => ({ label: m })));
174
- const choice = await ask(rl, t("setup.select_model", { max: Math.min(models.length, 10) }), "1");
175
- const idx = Math.max(0, Math.min(models.length - 1, (parseInt(choice) || 1) - 1));
176
- model = models[idx];
177
- }
178
- else {
179
- model = await ask(rl, t("setup.model_name"), "qwen3.5-9b");
180
- }
181
- const connected = await withSpinner(t("setup.testing_spinner", { model }), () => testChat(apiBase, apiKey, model));
182
- if (connected) {
183
- console.log(pc.green(t("setup.ok")));
184
- }
185
- else {
186
- console.log(pc.yellow(t("setup.warning")));
187
- }
188
- console.log(t("setup.agent_settings"));
189
- const contextWindow = parseInt(await ask(rl, t("setup.context_window"), "32768"));
190
- const maxIterations = parseInt(await ask(rl, t("setup.max_iters"), "1000"));
191
- // Security settings
192
- console.log(t("setup.security_header"));
193
- console.log(pc.dim(t("setup.security_status_off")));
194
- const configureSecurity = await ask(rl, t("setup.security_configure"), "n");
195
- let securityBashBlock = false;
196
- let securityFlagsBlock = false;
197
- let securityPathsDeny = true;
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";
209
- }
210
- if (ownRl)
211
- rl.close();
212
- const answers = {
213
- provider,
214
- apiBase,
215
- apiKey: apiKey || "not-needed",
216
- model,
217
- contextWindow,
218
- maxToolIterations: maxIterations,
219
- locale,
220
- securityBashBlock,
221
- securityFlagsBlock,
222
- securityPathsDeny,
223
- };
224
- console.log(pc.green(pc.bold(t("setup.complete"))));
225
- const summary = renderTable([
226
- t("setup.summary_setting"),
227
- t("setup.summary_value"),
228
- t("setup.summary_setting"),
229
- t("setup.summary_value"),
230
- ], [
231
- [t("setup.provider_type"), provider, t("setup.model_name"), model],
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
- ],
244
- [t("setup.ui_lang"), locale, "", ""],
245
- ], { maxColumns: 4 });
246
- for (const l of summary)
247
- console.log(l);
248
- return answers;
249
- }
@@ -1,202 +0,0 @@
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
- /**
11
- * Restore RegExp instances in dangerousPatterns that were serialized as {}
12
- * (pre-0.8.0 configs) or as {__regex, source, flags} (new format).
13
- * Falls back to default patterns for any entry that is not a real RegExp.
14
- */
15
- function restoreDangerousPatterns(patterns, defaults) {
16
- const fallback = (Array.isArray(defaults) ? defaults : []);
17
- if (!Array.isArray(patterns) || patterns.length === 0) {
18
- return fallback;
19
- }
20
- return patterns.map((p, i) => {
21
- if (p instanceof RegExp)
22
- return p;
23
- // If the pattern was serialized as {__regex, source, flags}, revive it
24
- if (p && typeof p === "object") {
25
- const { source, flags } = p;
26
- if (source && typeof source === "string") {
27
- try {
28
- return new RegExp(source, flags || "");
29
- }
30
- catch {
31
- // fall through
32
- }
33
- }
34
- }
35
- // Corrupted entry (e.g. serialized as {} pre-0.8.0): use default by index
36
- return fallback[i] || fallback[0] || p;
37
- });
38
- }
39
- function deepMerge(target, source) {
40
- const result = { ...target };
41
- for (const key of Object.keys(source)) {
42
- const srcVal = source[key];
43
- const tgtVal = target[key];
44
- if (srcVal !== null &&
45
- srcVal !== undefined &&
46
- typeof srcVal === "object" &&
47
- !Array.isArray(srcVal) &&
48
- typeof tgtVal === "object" &&
49
- !Array.isArray(tgtVal)) {
50
- result[key] = deepMerge(tgtVal, srcVal);
51
- }
52
- else if (srcVal !== undefined) {
53
- result[key] = srcVal;
54
- }
55
- }
56
- return result;
57
- }
58
- /**
59
- * JSON replacer that serializes RegExp objects as {__regex, source, flags}
60
- * so they survive JSON.stringify/parse round-trips.
61
- */
62
- function regexReplacer(_key, value) {
63
- if (value instanceof RegExp) {
64
- return { __regex: true, source: value.source, flags: value.flags };
65
- }
66
- return value;
67
- }
68
- /**
69
- * JSON reviver that restores RegExp objects serialized by regexReplacer.
70
- */
71
- function regexReviver(_key, value) {
72
- if (value &&
73
- typeof value === "object" &&
74
- value.__regex === true) {
75
- const { source, flags } = value;
76
- try {
77
- return new RegExp(source, flags);
78
- }
79
- catch {
80
- return value;
81
- }
82
- }
83
- return value;
84
- }
85
- function loadJSON(path) {
86
- try {
87
- if (existsSync(path)) {
88
- return JSON.parse(readFileSync(path, "utf-8"), regexReviver);
89
- }
90
- }
91
- catch {
92
- /* ignore malformed files */
93
- }
94
- return null;
95
- }
96
- function applyEnvVars(config) {
97
- const env = process.env;
98
- const result = { ...config };
99
- if (env.MMA_MODEL)
100
- result.model = env.MMA_MODEL;
101
- if (env.MMA_PROVIDER_TYPE)
102
- result.provider = { ...result.provider, type: env.MMA_PROVIDER_TYPE };
103
- if (env.MMA_PROVIDER_BASEURL)
104
- result.provider = { ...result.provider, baseUrl: env.MMA_PROVIDER_BASEURL };
105
- if (env.MMA_PROVIDER_APIKEY)
106
- result.provider = { ...result.provider, apiKey: env.MMA_PROVIDER_APIKEY };
107
- if (env.MMA_LOG_LEVEL)
108
- result.logLevel = env.MMA_LOG_LEVEL;
109
- if (env.MMA_LOCALE)
110
- result.locale = env.MMA_LOCALE;
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
- }
126
- if (env.MMA_AUTO_PLAN)
127
- result.autoPlan = env.MMA_AUTO_PLAN === "true";
128
- if (env.MMA_MOE_ENABLED)
129
- result.moe = { ...result.moe, enabled: env.MMA_MOE_ENABLED === "true" };
130
- return result;
131
- }
132
- export function loadConfig(options) {
133
- const globalPath = join(options.configDir, "config.json");
134
- mkdirSync(options.configDir, { recursive: true });
135
- const detector = new MigrationDetector(options.configDir);
136
- if (detector.needsMigration()) {
137
- const backup = new BackupManager(options.configDir);
138
- backup.backupConfig();
139
- const summary = backup.getBackupSummary();
140
- console.log(t("migration.detected", { summary }));
141
- try {
142
- unlinkSync(globalPath);
143
- }
144
- catch { }
145
- }
146
- let config = { ...DEFAULTS };
147
- const globalData = loadJSON(globalPath);
148
- if (globalData) {
149
- config = deepMerge(config, globalData);
150
- }
151
- if (!existsSync(globalPath)) {
152
- saveConfig(config, globalPath);
153
- }
154
- const projectData = loadJSON(options.projectConfigPath);
155
- if (projectData) {
156
- config = deepMerge(config, projectData);
157
- }
158
- // Restore RegExp patterns in contentScan that may have been serialized
159
- // as {} in pre-0.8.0 config files, or merged from user config.
160
- if (config.security?.contentScan?.dangerousPatterns) {
161
- config.security.contentScan.dangerousPatterns = restoreDangerousPatterns(config.security.contentScan.dangerousPatterns, DEFAULT_SECURITY_CONFIG.contentScan.dangerousPatterns);
162
- }
163
- config = applyEnvVars(config);
164
- // Decrypt sensitive fields in the loaded config
165
- try {
166
- const encryptor = new ConfigEncryptor();
167
- const decrypted = encryptor.decrypt(config);
168
- // Merge decrypted sensitive fields back into config
169
- for (const key of Object.keys(decrypted)) {
170
- config[key] = decrypted[key];
171
- }
172
- }
173
- catch (e) {
174
- // If decryption fails, log a warning but continue with the config
175
- console.warn(t("config.decryption_warning", { error: e.message }));
176
- }
177
- // Update global audit notifier with config (done in bootstrap.ts)
178
- return config;
179
- }
180
- export function validateConfig(config, allToolTags) {
181
- const errors = validateExpertConfig(config, allToolTags);
182
- if (errors.length > 0) {
183
- throw new Error(`Config validation failed:\n${errors.join("\n")}`);
184
- }
185
- }
186
- export function saveConfig(config, configPath) {
187
- const dir = dirname(configPath);
188
- mkdirSync(dir, { recursive: true });
189
- // Encrypt sensitive fields before saving
190
- try {
191
- const encryptor = new ConfigEncryptor();
192
- const encryptedConfig = encryptor.encrypt({
193
- ...config,
194
- });
195
- writeFileSync(configPath, JSON.stringify(encryptedConfig, regexReplacer, 2), "utf-8");
196
- }
197
- catch (e) {
198
- // If encryption fails, save without encryption
199
- console.warn(t("config.encryption_warning", { error: e.message }));
200
- writeFileSync(configPath, JSON.stringify(config, regexReplacer, 2), "utf-8");
201
- }
202
- }
@@ -1,100 +0,0 @@
1
- import { DEFAULT_SECURITY_CONFIG } from "./security";
2
- import { DEFAULT_LSP_CONFIG } from "../modules/lsp/config";
3
- export const DEFAULTS = {
4
- version: "2.0.0",
5
- model: "qwen3.5-9b",
6
- provider: {
7
- type: "openai-compat",
8
- baseUrl: "http://localhost:1234/v1",
9
- apiKey: "not-needed",
10
- },
11
- orchestrator: {
12
- model: undefined,
13
- provider: undefined,
14
- },
15
- moe: {
16
- enabled: false,
17
- },
18
- experts: {
19
- code: {
20
- model: "qwen3.5-9b",
21
- tool_tags: ["file", "code", "shell"],
22
- max_attempts: 3,
23
- },
24
- research: { model: "qwen3.5-9b", tool_tags: ["research"], max_attempts: 3 },
25
- browser: {
26
- model: "qwen3.5-9b",
27
- tool_tags: ["browser", "vision"],
28
- max_attempts: 3,
29
- },
30
- vision: {
31
- model: "qwen3.5-9b",
32
- tool_tags: ["browser", "vision", "file"],
33
- max_attempts: 2,
34
- },
35
- },
36
- contextWindow: 32768,
37
- contextBudget: {
38
- systemPrompt: 0.1,
39
- responseReserve: 0.15,
40
- compactionThreshold: 0.75,
41
- },
42
- modelLoad: {
43
- autoLoad: false,
44
- flashAttention: true,
45
- offloadKvCacheToGpu: true,
46
- },
47
- retry: {
48
- maxRetries: 3,
49
- baseDelay: 1000,
50
- maxDelay: 30000,
51
- },
52
- maxToolIterations: 1000,
53
- stuckThreshold: 6,
54
- autoPlan: true,
55
- showReasoning: false,
56
- logLevel: "info",
57
- locale: "en",
58
- session: {
59
- autoSave: true,
60
- maxSessions: 50,
61
- isolateMemory: false,
62
- },
63
- browser: {
64
- enabled: true,
65
- headless: true,
66
- maxElements: 30,
67
- viewportWidth: 1280,
68
- viewportHeight: 720,
69
- navigationTimeout: 15000,
70
- },
71
- ui: {
72
- spinner: true,
73
- toolStyle: "inline",
74
- toolComments: true,
75
- showContextStats: false,
76
- showCompaction: true,
77
- },
78
- mcpServers: {
79
- context7: {
80
- name: "context7",
81
- transport: "http",
82
- url: "https://mcp.context7.com/mcp",
83
- headers: {
84
- CONTEXT7_API_KEY: process.env.CONTEXT7_API_KEY || "",
85
- },
86
- enabled: true,
87
- timeout: 30000,
88
- },
89
- },
90
- security: DEFAULT_SECURITY_CONFIG,
91
- sessionIsolation: {
92
- enabled: false,
93
- isolatePlugins: true,
94
- isolateTempFiles: true,
95
- },
96
- skills: {
97
- budget: 0.15,
98
- },
99
- lsp: DEFAULT_LSP_CONFIG,
100
- };
@@ -1,15 +0,0 @@
1
- export function getExpertConfig(config, tag) {
2
- return config.experts?.[tag];
3
- }
4
- export function validateExpertConfig(config, allToolTags) {
5
- const errors = [];
6
- const knownTags = new Set(allToolTags);
7
- for (const [name, expert] of Object.entries(config.experts || {})) {
8
- for (const tag of expert.tool_tags) {
9
- if (!knownTags.has(tag)) {
10
- errors.push(`Expert "${name}" references unknown tool_tag "${tag}". Known tags: ${Array.from(knownTags).join(', ')}`);
11
- }
12
- }
13
- }
14
- return errors;
15
- }
@@ -1,3 +0,0 @@
1
- export { DEFAULTS } from './defaults';
2
- export { loadConfig, saveConfig, validateConfig } from './config';
3
- export { getExpertConfig, validateExpertConfig } from './experts';