micro-models-agent 0.39.1 → 0.40.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mma.mjs +41 -41
- package/dist/cli/commands.js +116 -3
- package/dist/cli/main.js +35 -8
- package/dist/cli/repl-commands.js +633 -0
- package/dist/cli/repl.js +110 -611
- package/dist/cli/setup.js +32 -12
- package/dist/config/config.js +46 -30
- package/dist/config/defaults.js +10 -1
- package/dist/config/security.js +15 -8
- package/dist/core/agent-moe.js +24 -12
- package/dist/core/agent.js +281 -47
- package/dist/core/bootstrap.js +52 -36
- package/dist/core/session-logger.js +35 -2
- package/dist/core/workspace.js +76 -0
- package/dist/i18n/en.json +79 -15
- package/dist/i18n/index.js +12 -9
- package/dist/i18n/ru.json +79 -15
- package/dist/index.js +13 -13
- package/dist/llm/openai-compat.js +39 -10
- package/dist/logger/app-logger.js +83 -16
- package/dist/logger/file-log.js +151 -0
- package/dist/main.js +634 -311
- package/dist/modules/browser/bridge-server.mjs +113 -105
- package/dist/modules/browser/session.js +108 -60
- package/dist/modules/certification/cli.js +176 -0
- package/dist/modules/certification/fact-checker.js +84 -0
- package/dist/modules/certification/loader.js +111 -0
- package/dist/modules/certification/manifest.js +50 -0
- package/dist/modules/certification/runner.js +162 -0
- package/dist/modules/certification/scenarios.js +124 -0
- package/dist/modules/certification/types.js +1 -0
- package/dist/modules/context/manager.js +119 -10
- package/dist/modules/execution/auditor.js +33 -39
- package/dist/modules/execution/index.js +8 -6
- package/dist/modules/execution/module.js +474 -32
- package/dist/modules/execution/moe-executor.js +97 -40
- package/dist/modules/execution/plan-coverage.js +68 -0
- package/dist/modules/execution/plan-persister.js +46 -0
- package/dist/modules/execution/plan-store.js +159 -0
- package/dist/modules/execution/planner.js +63 -13
- package/dist/modules/execution/stuck-detector.js +252 -39
- package/dist/modules/execution/tracker.js +21 -7
- package/dist/modules/execution/verifier.js +46 -17
- package/dist/modules/hallucination/confidence.js +7 -2
- package/dist/modules/hallucination/consistency.js +8 -42
- package/dist/modules/hallucination/detector.js +26 -21
- package/dist/modules/hallucination/factual.js +170 -150
- package/dist/modules/hallucination/index.js +5 -4
- package/dist/modules/hallucination/js-identifiers.js +72 -0
- package/dist/modules/hallucination/llm-judge.js +103 -0
- package/dist/modules/index.js +5 -5
- package/dist/modules/lsp/client.js +235 -0
- package/dist/modules/lsp/config.js +81 -0
- package/dist/modules/lsp/index.js +3 -0
- package/dist/modules/lsp/module.js +68 -0
- package/dist/modules/lsp/types.js +1 -0
- package/dist/modules/mcp/client.js +8 -2
- package/dist/modules/memory/store.js +4 -0
- package/dist/modules/plugins/builtin/lint-on-write.js +143 -38
- package/dist/modules/processes/index.js +1 -2
- package/dist/modules/processes/registry.js +125 -35
- package/dist/modules/processes/runner.js +9 -110
- package/dist/modules/security/audit-log.js +30 -10
- package/dist/modules/security/command-validator.js +42 -16
- package/dist/modules/security/content-scanner.js +9 -8
- package/dist/modules/security/network-validator.js +2 -2
- package/dist/modules/security/path-validator.js +64 -10
- package/dist/modules/security/security-policies.js +221 -67
- package/dist/modules/security/session-encryption.js +42 -25
- package/dist/modules/session/manager.js +15 -10
- package/dist/modules/session/store.js +62 -8
- package/dist/modules/skills/index.js +2 -3
- package/dist/modules/skills/module.js +10 -23
- package/dist/tools/bash.js +287 -90
- package/dist/tools/create-dir.js +0 -1
- package/dist/tools/delete-file.js +0 -1
- package/dist/tools/edit-file.js +10 -8
- package/dist/tools/executor.js +57 -7
- package/dist/tools/grep-tool.js +51 -29
- package/dist/tools/index.js +55 -40
- package/dist/tools/load-skill.js +14 -18
- package/dist/tools/move-file.js +3 -2
- package/dist/tools/pipeline-run.js +1 -1
- package/dist/tools/read-file.js +15 -5
- package/dist/tools/search-history.js +42 -22
- package/dist/tools/subagent.js +21 -12
- package/dist/tools/web-browse.js +54 -25
- package/dist/tools/web-fetch.js +60 -34
- package/dist/tools/web-search.js +39 -20
- package/dist/tools/write-file.js +13 -10
- package/dist/ui/diff.js +9 -16
- package/dist/ui/renderer.js +69 -6
- package/package.json +48 -45
- package/dist/modules/context/history.js +0 -15
- package/dist/modules/processes/detect.js +0 -34
- package/dist/modules/skills/matcher.js +0 -27
package/dist/main.js
CHANGED
|
@@ -2064,12 +2064,7 @@ var init_security = __esm(() => {
|
|
|
2064
2064
|
auditNotifier: {
|
|
2065
2065
|
enabled: false,
|
|
2066
2066
|
minSeverity: "medium",
|
|
2067
|
-
eventTypes: [
|
|
2068
|
-
"security_block",
|
|
2069
|
-
"bash_command",
|
|
2070
|
-
"file_operation",
|
|
2071
|
-
"network_request"
|
|
2072
|
-
],
|
|
2067
|
+
eventTypes: ["security_block", "bash_command", "file_operation", "network_request"],
|
|
2073
2068
|
maxRetries: 3,
|
|
2074
2069
|
webhookTimeout: 5000
|
|
2075
2070
|
}
|
|
@@ -2077,11 +2072,14 @@ var init_security = __esm(() => {
|
|
|
2077
2072
|
});
|
|
2078
2073
|
|
|
2079
2074
|
// src/modules/lsp/config.ts
|
|
2080
|
-
function
|
|
2075
|
+
function getLanguageForFile(filePath) {
|
|
2081
2076
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
2082
2077
|
if (!ext)
|
|
2083
2078
|
return null;
|
|
2084
|
-
|
|
2079
|
+
return LANGUAGE_MAP[ext] ?? null;
|
|
2080
|
+
}
|
|
2081
|
+
function getServerForFile(filePath, config) {
|
|
2082
|
+
const lang = getLanguageForFile(filePath);
|
|
2085
2083
|
if (!lang)
|
|
2086
2084
|
return null;
|
|
2087
2085
|
return config.servers[lang] ?? null;
|
|
@@ -2127,22 +2125,40 @@ var init_config = __esm(() => {
|
|
|
2127
2125
|
},
|
|
2128
2126
|
json: {
|
|
2129
2127
|
command: "npx",
|
|
2130
|
-
args: [
|
|
2131
|
-
|
|
2128
|
+
args: [
|
|
2129
|
+
"--yes",
|
|
2130
|
+
"--package",
|
|
2131
|
+
"vscode-langservers-extracted",
|
|
2132
|
+
"vscode-json-language-server",
|
|
2133
|
+
"--stdio"
|
|
2134
|
+
],
|
|
2135
|
+
timeout: 30000,
|
|
2132
2136
|
autoInstall: true,
|
|
2133
2137
|
workspaceMarkers: ["package.json"]
|
|
2134
2138
|
},
|
|
2135
2139
|
html: {
|
|
2136
2140
|
command: "npx",
|
|
2137
|
-
args: [
|
|
2138
|
-
|
|
2141
|
+
args: [
|
|
2142
|
+
"--yes",
|
|
2143
|
+
"--package",
|
|
2144
|
+
"vscode-langservers-extracted",
|
|
2145
|
+
"vscode-html-language-server",
|
|
2146
|
+
"--stdio"
|
|
2147
|
+
],
|
|
2148
|
+
timeout: 60000,
|
|
2139
2149
|
autoInstall: true,
|
|
2140
2150
|
workspaceMarkers: ["package.json"]
|
|
2141
2151
|
},
|
|
2142
2152
|
css: {
|
|
2143
2153
|
command: "npx",
|
|
2144
|
-
args: [
|
|
2145
|
-
|
|
2154
|
+
args: [
|
|
2155
|
+
"--yes",
|
|
2156
|
+
"--package",
|
|
2157
|
+
"vscode-langservers-extracted",
|
|
2158
|
+
"vscode-css-language-server",
|
|
2159
|
+
"--stdio"
|
|
2160
|
+
],
|
|
2161
|
+
timeout: 60000,
|
|
2146
2162
|
autoInstall: true,
|
|
2147
2163
|
workspaceMarkers: ["package.json"]
|
|
2148
2164
|
}
|
|
@@ -2187,13 +2203,21 @@ var init_defaults = __esm(() => {
|
|
|
2187
2203
|
moe: {
|
|
2188
2204
|
enabled: false
|
|
2189
2205
|
},
|
|
2206
|
+
tools: {
|
|
2207
|
+
defaultTags: ["file", "code"],
|
|
2208
|
+
enableOnDemand: true
|
|
2209
|
+
},
|
|
2190
2210
|
experts: {
|
|
2191
2211
|
code: {
|
|
2192
2212
|
model: "qwen/qwen3.5-9b",
|
|
2193
2213
|
tool_tags: ["file", "code", "shell"],
|
|
2194
2214
|
max_attempts: 3
|
|
2195
2215
|
},
|
|
2196
|
-
research: {
|
|
2216
|
+
research: {
|
|
2217
|
+
model: "qwen/qwen3.5-9b",
|
|
2218
|
+
tool_tags: ["research"],
|
|
2219
|
+
max_attempts: 3
|
|
2220
|
+
},
|
|
2197
2221
|
browser: {
|
|
2198
2222
|
model: "qwen/qwen3.5-9b",
|
|
2199
2223
|
tool_tags: ["browser", "vision"],
|
|
@@ -2513,6 +2537,7 @@ Command: {command}`,
|
|
|
2513
2537
|
"lsp.check_notfound": "Path not found: {path}",
|
|
2514
2538
|
"lsp.check_unsupported": "No LSP server configured for: {path}",
|
|
2515
2539
|
"lsp.check_clean": "No errors or warnings detected ({count} file(s) checked).",
|
|
2540
|
+
"lsp.startup_header": "[Existing project errors (checked at session start) — fix these before continuing]:",
|
|
2516
2541
|
"cli.description": "Micro Models Agent — AI coding agent for small models",
|
|
2517
2542
|
"cli.init": "Run interactive setup wizard",
|
|
2518
2543
|
"cli.config_saved": "Configuration saved to ~/.mma/config.json",
|
|
@@ -2693,6 +2718,10 @@ Available commands:`,
|
|
|
2693
2718
|
"repl.skills_label": "Skills:",
|
|
2694
2719
|
"repl.plugins_label": "Plugins:",
|
|
2695
2720
|
"repl.mcp_label": "MCP:",
|
|
2721
|
+
"repl.lsp_label": "LSP:",
|
|
2722
|
+
"repl.lsp_timeout": "timeout",
|
|
2723
|
+
"repl.lsp_failed": "did not start",
|
|
2724
|
+
"repl.lsp_unknown": "unknown",
|
|
2696
2725
|
"repl.work_dir": "Dir:",
|
|
2697
2726
|
"repl.agents_label": "Instructions:",
|
|
2698
2727
|
"repl.not_found": "not found",
|
|
@@ -2905,7 +2934,13 @@ Use this knowledge to answer the user's question.`,
|
|
|
2905
2934
|
"updater.available": "[updater] Update available: {current} → {latest}. Run `npm install -g micro-models-agent` to upgrade.",
|
|
2906
2935
|
"updater.installing": "[updater] Installing {latest} globally (current: {current})…",
|
|
2907
2936
|
"updater.installed": "[updater] Installed {latest}. Restart MMA to use it (was {current}).",
|
|
2908
|
-
"updater.install_failed": "[updater] Failed to install {latest}: {error}. Update manually with `npm install -g micro-models-agent`."
|
|
2937
|
+
"updater.install_failed": "[updater] Failed to install {latest}: {error}. Update manually with `npm install -g micro-models-agent`.",
|
|
2938
|
+
"tools.enable_no_tags": 'enable_tools requires at least one tag in the "tags" array.',
|
|
2939
|
+
"tools.enable_no_executor": "Tool executor is not available — cannot enumerate enabled tools.",
|
|
2940
|
+
"tools.enable_already_active": "Tool tags already active: {tags}.",
|
|
2941
|
+
"tools.enable_added": "Enabled tool tags: {tags}. Available tools now: {tools}",
|
|
2942
|
+
"tools.hidden_header": "Additional tools (enable on demand via enable_tools or route to subagent tool_tags):",
|
|
2943
|
+
"tool.friendly.enable_tools": "Enable tools"
|
|
2909
2944
|
};
|
|
2910
2945
|
});
|
|
2911
2946
|
|
|
@@ -3132,6 +3167,7 @@ var init_ru = __esm(() => {
|
|
|
3132
3167
|
"lsp.check_notfound": "Путь не найден: {path}",
|
|
3133
3168
|
"lsp.check_unsupported": "Для файла не настроен LSP-сервер: {path}",
|
|
3134
3169
|
"lsp.check_clean": "Ошибок и предупреждений не обнаружено (проверено файлов: {count}).",
|
|
3170
|
+
"lsp.startup_header": "[Существующие ошибки проекта (проверено при старте сессии) — исправьте их перед продолжением]:",
|
|
3135
3171
|
"cli.description": "Micro Models Agent — ИИ-агент для кодинга на малых моделях",
|
|
3136
3172
|
"cli.init": "Запустить мастер настройки",
|
|
3137
3173
|
"cli.config_saved": "Конфигурация сохранена в ~/.mma/config.json",
|
|
@@ -3308,6 +3344,10 @@ var init_ru = __esm(() => {
|
|
|
3308
3344
|
"repl.skills_label": "Скиллы:",
|
|
3309
3345
|
"repl.plugins_label": "Плагины:",
|
|
3310
3346
|
"repl.mcp_label": "MCP:",
|
|
3347
|
+
"repl.lsp_label": "LSP:",
|
|
3348
|
+
"repl.lsp_timeout": "таймаут",
|
|
3349
|
+
"repl.lsp_failed": "не стартовал",
|
|
3350
|
+
"repl.lsp_unknown": "неизвестно",
|
|
3311
3351
|
"repl.work_dir": "Директория:",
|
|
3312
3352
|
"repl.agents_label": "Инструкции:",
|
|
3313
3353
|
"repl.not_found": "не найден",
|
|
@@ -3526,7 +3566,13 @@ var init_ru = __esm(() => {
|
|
|
3526
3566
|
"updater.available": "[updater] Доступно обновление: {current} → {latest}. Выполните `npm install -g micro-models-agent` для обновления.",
|
|
3527
3567
|
"updater.installing": "[updater] Установка {latest} глобально (текущая: {current})…",
|
|
3528
3568
|
"updater.installed": "[updater] Установлена {latest}. Перезапустите MMA для применения (была {current}).",
|
|
3529
|
-
"updater.install_failed": "[updater] Не удалось установить {latest}: {error}. Обновите вручную: `npm install -g micro-models-agent`."
|
|
3569
|
+
"updater.install_failed": "[updater] Не удалось установить {latest}: {error}. Обновите вручную: `npm install -g micro-models-agent`.",
|
|
3570
|
+
"tools.enable_no_tags": 'enable_tools требует хотя бы один тег в массиве "tags".',
|
|
3571
|
+
"tools.enable_no_executor": "Исполнитель тулов недоступен — невозможно перечислить включённые тулы.",
|
|
3572
|
+
"tools.enable_already_active": "Теги тулов уже активны: {tags}.",
|
|
3573
|
+
"tools.enable_added": "Включены теги тулов: {tags}. Теперь доступны тулы: {tools}",
|
|
3574
|
+
"tools.hidden_header": "Дополнительные тулы (включите по требованию через enable_tools или маршрутизируйте через subagent tool_tags):",
|
|
3575
|
+
"tool.friendly.enable_tools": "Включить тулы"
|
|
3530
3576
|
};
|
|
3531
3577
|
});
|
|
3532
3578
|
|
|
@@ -3876,13 +3922,7 @@ __export(exports_config, {
|
|
|
3876
3922
|
saveConfig: () => saveConfig,
|
|
3877
3923
|
loadConfig: () => loadConfig
|
|
3878
3924
|
});
|
|
3879
|
-
import {
|
|
3880
|
-
existsSync as existsSync4,
|
|
3881
|
-
readFileSync as readFileSync3,
|
|
3882
|
-
unlinkSync,
|
|
3883
|
-
writeFileSync as writeFileSync3,
|
|
3884
|
-
mkdirSync as mkdirSync2
|
|
3885
|
-
} from "fs";
|
|
3925
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
3886
3926
|
import { join as join4, dirname } from "path";
|
|
3887
3927
|
function restoreDangerousPatterns(patterns, defaults) {
|
|
3888
3928
|
const fallback = Array.isArray(defaults) ? defaults : [];
|
|
@@ -4019,6 +4059,12 @@ function loadConfig(options) {
|
|
|
4019
4059
|
}
|
|
4020
4060
|
function validateConfig(config, allToolTags) {
|
|
4021
4061
|
const errors = validateExpertConfig(config, allToolTags);
|
|
4062
|
+
const knownTags = new Set(allToolTags);
|
|
4063
|
+
for (const tag of config.tools?.defaultTags ?? []) {
|
|
4064
|
+
if (!knownTags.has(tag)) {
|
|
4065
|
+
errors.push(`tools.defaultTags references unknown tag "${tag}". Known tags: ${Array.from(knownTags).join(", ")}`);
|
|
4066
|
+
}
|
|
4067
|
+
}
|
|
4022
4068
|
if (errors.length > 0) {
|
|
4023
4069
|
throw new Error(`Config validation failed:
|
|
4024
4070
|
${errors.join(`
|
|
@@ -5417,8 +5463,10 @@ class ToolRegistry {
|
|
|
5417
5463
|
});
|
|
5418
5464
|
}
|
|
5419
5465
|
getAllForLLM(tags) {
|
|
5420
|
-
const
|
|
5421
|
-
|
|
5466
|
+
const all = this.getAll();
|
|
5467
|
+
const tagSet = new Set(tags ?? []);
|
|
5468
|
+
const selected = tagSet.size === 0 ? all : all.filter((t2) => t2.alwaysOn || t2.tags && t2.tags.some((tag) => tagSet.has(tag)));
|
|
5469
|
+
return selected.map((t2) => ({
|
|
5422
5470
|
name: t2.name,
|
|
5423
5471
|
description: t2.description,
|
|
5424
5472
|
parameters: t2.parameters,
|
|
@@ -7890,7 +7938,10 @@ var init_process_log = __esm(() => {
|
|
|
7890
7938
|
type: "object",
|
|
7891
7939
|
properties: {
|
|
7892
7940
|
id: { type: "string", description: "Process id from bash output or process_list" },
|
|
7893
|
-
tail: {
|
|
7941
|
+
tail: {
|
|
7942
|
+
type: "number",
|
|
7943
|
+
description: `Number of trailing lines to show (default: ${DEFAULT_TAIL}, max 300)`
|
|
7944
|
+
}
|
|
7894
7945
|
},
|
|
7895
7946
|
required: ["id"]
|
|
7896
7947
|
},
|
|
@@ -9341,6 +9392,8 @@ function filterToolsByTags(tools, toolTags) {
|
|
|
9341
9392
|
return tools;
|
|
9342
9393
|
const tagSet = new Set(toolTags);
|
|
9343
9394
|
return tools.filter((t2) => {
|
|
9395
|
+
if (t2.alwaysOn)
|
|
9396
|
+
return true;
|
|
9344
9397
|
if (!t2.tags || t2.tags.length === 0)
|
|
9345
9398
|
return false;
|
|
9346
9399
|
return t2.tags.some((tag) => tagSet.has(tag));
|
|
@@ -10150,7 +10203,10 @@ class StepVerifier {
|
|
|
10150
10203
|
await this.runAsync(`bun run ${scriptName}`, this.baseDir, 60000);
|
|
10151
10204
|
return { passed: true, message: t("verify.script_passed", { script: scriptName }) };
|
|
10152
10205
|
} catch (e) {
|
|
10153
|
-
return {
|
|
10206
|
+
return {
|
|
10207
|
+
passed: false,
|
|
10208
|
+
message: t("verify.script_failed", { script: scriptName, message: e.message })
|
|
10209
|
+
};
|
|
10154
10210
|
}
|
|
10155
10211
|
}
|
|
10156
10212
|
async runTypeCheck() {
|
|
@@ -10167,10 +10223,7 @@ class StepVerifier {
|
|
|
10167
10223
|
}
|
|
10168
10224
|
}
|
|
10169
10225
|
async runTypeCheckForFile(filePath) {
|
|
10170
|
-
const projectRoot = findProjectRoot(filePath, this.baseDir, [
|
|
10171
|
-
"tsconfig.json",
|
|
10172
|
-
"package.json"
|
|
10173
|
-
]);
|
|
10226
|
+
const projectRoot = findProjectRoot(filePath, this.baseDir, ["tsconfig.json", "package.json"]);
|
|
10174
10227
|
const tsconfigPath = join11(projectRoot, "tsconfig.json");
|
|
10175
10228
|
if (!existsSync20(tsconfigPath)) {
|
|
10176
10229
|
return { passed: true, message: "No tsconfig.json found — skipping type check" };
|
|
@@ -10252,7 +10305,7 @@ class StepVerifier {
|
|
|
10252
10305
|
}
|
|
10253
10306
|
async validateSyntax(filePath) {
|
|
10254
10307
|
const ext = extname2(filePath);
|
|
10255
|
-
if (ext === ".ts" || ext === ".tsx") {
|
|
10308
|
+
if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
|
|
10256
10309
|
try {
|
|
10257
10310
|
await this.runAsync(`npx tsc --noEmit --skipLibCheck ${filePath}`, this.baseDir, 1e4);
|
|
10258
10311
|
return true;
|
|
@@ -10267,7 +10320,7 @@ class StepVerifier {
|
|
|
10267
10320
|
return true;
|
|
10268
10321
|
}
|
|
10269
10322
|
}
|
|
10270
|
-
if (ext === ".js" || ext === ".jsx") {
|
|
10323
|
+
if (ext === ".js" || ext === ".jsx" || ext === ".cjs" || ext === ".mjs") {
|
|
10271
10324
|
try {
|
|
10272
10325
|
await this.runAsync(`node --check ${filePath}`, this.baseDir, 5000);
|
|
10273
10326
|
return true;
|
|
@@ -10374,15 +10427,7 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
|
|
|
10374
10427
|
onMeta?.(`✅ Execution complete: ${planResults.results.filter((r) => r.success).length}/${planResults.results.length} succeeded
|
|
10375
10428
|
`);
|
|
10376
10429
|
const verifier = new StepVerifier(baseDir);
|
|
10377
|
-
const knownTags = [
|
|
10378
|
-
"file",
|
|
10379
|
-
"code",
|
|
10380
|
-
"shell",
|
|
10381
|
-
"research",
|
|
10382
|
-
"browser",
|
|
10383
|
-
"vision",
|
|
10384
|
-
"core"
|
|
10385
|
-
];
|
|
10430
|
+
const knownTags = ["file", "code", "shell", "research", "browser", "vision", "core"];
|
|
10386
10431
|
const verification = await verifier.verifyMoEManifest(plan, config, knownTags);
|
|
10387
10432
|
onPhase?.("thinking");
|
|
10388
10433
|
let verifyResult;
|
|
@@ -10662,13 +10707,17 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
10662
10707
|
let suppressRepetitionRetry = false;
|
|
10663
10708
|
let repeatedToolCount = 0;
|
|
10664
10709
|
const MAX_REPEATED_TOOL_CALLS = 2;
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10710
|
+
let allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
|
|
10711
|
+
let boundedToolNames = new Set(allToolsForBudget.filter((t2) => t2.boundedOutput).map((t2) => t2.name));
|
|
10712
|
+
let toolTokenEstimate = allToolsForBudget.reduce((sum, t2) => sum + Math.ceil((t2.description.length + JSON.stringify(t2.parameters).length) / 4), 0);
|
|
10668
10713
|
contextManager.setToolTokens(toolTokenEstimate);
|
|
10669
10714
|
while (iteration < config.maxToolIterations && !this.shutdownRequested) {
|
|
10670
10715
|
iteration++;
|
|
10671
10716
|
contextManager.noteIteration();
|
|
10717
|
+
allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
|
|
10718
|
+
boundedToolNames = new Set(allToolsForBudget.filter((t2) => t2.boundedOutput).map((t2) => t2.name));
|
|
10719
|
+
toolTokenEstimate = allToolsForBudget.reduce((sum, t2) => sum + Math.ceil((t2.description.length + JSON.stringify(t2.parameters).length) / 4), 0);
|
|
10720
|
+
contextManager.setToolTokens(toolTokenEstimate);
|
|
10672
10721
|
pluginManager.runOnBeforeThink({
|
|
10673
10722
|
iteration,
|
|
10674
10723
|
logger,
|
|
@@ -11256,9 +11305,7 @@ class FactExtractor {
|
|
|
11256
11305
|
new RegExp(`Deleted ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
|
|
11257
11306
|
new RegExp(`(?:Удалён|Файл удалён):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi")
|
|
11258
11307
|
];
|
|
11259
|
-
const readPatterns = [
|
|
11260
|
-
new RegExp(`── (${DRIVE}[\\w./\\\\-]+\\.[a-z]+) \\(`, "gi")
|
|
11261
|
-
];
|
|
11308
|
+
const readPatterns = [new RegExp(`── (${DRIVE}[\\w./\\\\-]+\\.[a-z]+) \\(`, "gi")];
|
|
11262
11309
|
const newFiles = [];
|
|
11263
11310
|
const newDeleted = [];
|
|
11264
11311
|
const newDecisions = [];
|
|
@@ -11621,11 +11668,7 @@ ${lines.join(`
|
|
|
11621
11668
|
const text = getMessageText(m.content);
|
|
11622
11669
|
return !text.startsWith("<system-summary>");
|
|
11623
11670
|
});
|
|
11624
|
-
this.messages = [
|
|
11625
|
-
...firstSystem ? [firstSystem] : [],
|
|
11626
|
-
summary,
|
|
11627
|
-
...freshRecent
|
|
11628
|
-
];
|
|
11671
|
+
this.messages = [...firstSystem ? [firstSystem] : [], summary, ...freshRecent];
|
|
11629
11672
|
this.iterationsSinceCompaction = 0;
|
|
11630
11673
|
if (this.onCompact) {
|
|
11631
11674
|
this.onCompact(summary);
|
|
@@ -12319,7 +12362,11 @@ class Updater {
|
|
|
12319
12362
|
signal: AbortSignal.timeout(5000)
|
|
12320
12363
|
});
|
|
12321
12364
|
if (!response.ok) {
|
|
12322
|
-
return {
|
|
12365
|
+
return {
|
|
12366
|
+
updateAvailable: false,
|
|
12367
|
+
current: this.currentVersion,
|
|
12368
|
+
error: `HTTP ${response.status}`
|
|
12369
|
+
};
|
|
12323
12370
|
}
|
|
12324
12371
|
const data = await response.json();
|
|
12325
12372
|
const latest = data["dist-tags"]?.latest;
|
|
@@ -12643,7 +12690,7 @@ var init_subagent = __esm(() => {
|
|
|
12643
12690
|
};
|
|
12644
12691
|
}
|
|
12645
12692
|
if (toolTags && toolTags.length > 0) {
|
|
12646
|
-
const matched = ctx.toolExecutor.
|
|
12693
|
+
const matched = ctx.toolExecutor.getRegistry().getByTags(toolTags);
|
|
12647
12694
|
if (matched.length === 0) {
|
|
12648
12695
|
return {
|
|
12649
12696
|
success: false,
|
|
@@ -12992,15 +13039,7 @@ function isUrlAllowed(url, securityConfig) {
|
|
|
12992
13039
|
function sanitizeUrl(url) {
|
|
12993
13040
|
try {
|
|
12994
13041
|
const urlObj = new URL(url);
|
|
12995
|
-
const sensitiveKeys = [
|
|
12996
|
-
"api_key",
|
|
12997
|
-
"token",
|
|
12998
|
-
"password",
|
|
12999
|
-
"secret",
|
|
13000
|
-
"access_token",
|
|
13001
|
-
"auth",
|
|
13002
|
-
"key"
|
|
13003
|
-
];
|
|
13042
|
+
const sensitiveKeys = ["api_key", "token", "password", "secret", "access_token", "auth", "key"];
|
|
13004
13043
|
const sanitizedParams = new URLSearchParams(urlObj.search);
|
|
13005
13044
|
for (const key of sensitiveKeys) {
|
|
13006
13045
|
if (sanitizedParams.has(key)) {
|
|
@@ -14575,8 +14614,11 @@ var init_recall = __esm(() => {
|
|
|
14575
14614
|
if (results2.length === 0) {
|
|
14576
14615
|
return { success: true, output: t("tool.recall.empty", { query }) };
|
|
14577
14616
|
}
|
|
14578
|
-
return {
|
|
14579
|
-
|
|
14617
|
+
return {
|
|
14618
|
+
success: true,
|
|
14619
|
+
output: t("tool.recall.search_results", { category, results: results2.join(`
|
|
14620
|
+
`) })
|
|
14621
|
+
};
|
|
14580
14622
|
}
|
|
14581
14623
|
const results = store.search(query);
|
|
14582
14624
|
if (results.length === 0) {
|
|
@@ -14584,7 +14626,10 @@ var init_recall = __esm(() => {
|
|
|
14584
14626
|
}
|
|
14585
14627
|
const formatted = results.map((r) => `[${r.file}] ${r.match}`).join(`
|
|
14586
14628
|
`);
|
|
14587
|
-
return {
|
|
14629
|
+
return {
|
|
14630
|
+
success: true,
|
|
14631
|
+
output: t("tool.recall.search_results", { category: "all", results: formatted })
|
|
14632
|
+
};
|
|
14588
14633
|
} catch (err) {
|
|
14589
14634
|
return { success: true, output: t("tool.memory_error", { error: String(err) }) };
|
|
14590
14635
|
}
|
|
@@ -15006,13 +15051,7 @@ function extractInteractiveElements(html, maxElements = 30) {
|
|
|
15006
15051
|
if (tag === "input" && attrs["type"] === "hidden")
|
|
15007
15052
|
continue;
|
|
15008
15053
|
const role = attrs["role"] || inferRole(tag, attrs["type"]);
|
|
15009
|
-
const isInteractive = [
|
|
15010
|
-
"a",
|
|
15011
|
-
"button",
|
|
15012
|
-
"input",
|
|
15013
|
-
"textarea",
|
|
15014
|
-
"select"
|
|
15015
|
-
].includes(tag) || attrs["role"] !== undefined;
|
|
15054
|
+
const isInteractive = ["a", "button", "input", "textarea", "select"].includes(tag) || attrs["role"] !== undefined;
|
|
15016
15055
|
if (!isInteractive)
|
|
15017
15056
|
continue;
|
|
15018
15057
|
if (tag === "a" && !attrs["href"])
|
|
@@ -15585,7 +15624,18 @@ function createBrowserTool() {
|
|
|
15585
15624
|
properties: {
|
|
15586
15625
|
action: {
|
|
15587
15626
|
type: "string",
|
|
15588
|
-
enum: [
|
|
15627
|
+
enum: [
|
|
15628
|
+
"open",
|
|
15629
|
+
"click",
|
|
15630
|
+
"type",
|
|
15631
|
+
"scroll",
|
|
15632
|
+
"back",
|
|
15633
|
+
"forward",
|
|
15634
|
+
"screenshot",
|
|
15635
|
+
"snapshot",
|
|
15636
|
+
"close",
|
|
15637
|
+
"wait"
|
|
15638
|
+
],
|
|
15589
15639
|
description: "Browser action to perform"
|
|
15590
15640
|
},
|
|
15591
15641
|
url: {
|
|
@@ -15678,7 +15728,9 @@ async function readClipboardFallback() {
|
|
|
15678
15728
|
const tmpPath = join22(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
|
|
15679
15729
|
try {
|
|
15680
15730
|
if (platform5() === "linux") {
|
|
15681
|
-
execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, {
|
|
15731
|
+
execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, {
|
|
15732
|
+
timeout: 5000
|
|
15733
|
+
});
|
|
15682
15734
|
} else {
|
|
15683
15735
|
return null;
|
|
15684
15736
|
}
|
|
@@ -15841,8 +15893,63 @@ var init_attach_image = __esm(() => {
|
|
|
15841
15893
|
};
|
|
15842
15894
|
});
|
|
15843
15895
|
|
|
15896
|
+
// src/tools/enable-tools.ts
|
|
15897
|
+
var enableToolsTool;
|
|
15898
|
+
var init_enable_tools = __esm(() => {
|
|
15899
|
+
init_i18n();
|
|
15900
|
+
enableToolsTool = {
|
|
15901
|
+
name: "enable_tools",
|
|
15902
|
+
description: "Enable hidden tool categories for the current session. Only the essential tools (file/code/shell) are active by default. Call this with the tags you need and they become available from the next turn. Available tags: file, code, shell, research, browser, vision, image, memory, core. Returns the newly available tools. To run a task in a separate context instead, use subagent with tool_tags.",
|
|
15903
|
+
alwaysOn: true,
|
|
15904
|
+
parameters: {
|
|
15905
|
+
type: "object",
|
|
15906
|
+
properties: {
|
|
15907
|
+
tags: {
|
|
15908
|
+
type: "array",
|
|
15909
|
+
items: { type: "string" },
|
|
15910
|
+
description: 'Tool tags to enable (e.g. ["research"] for web_search/web_fetch, ["browser"] for the browser, ["memory"] for remember/recall, ["shell"] for process management).'
|
|
15911
|
+
}
|
|
15912
|
+
},
|
|
15913
|
+
required: ["tags"]
|
|
15914
|
+
},
|
|
15915
|
+
handler: async (ctx, args) => {
|
|
15916
|
+
const requested = Array.isArray(args.tags) ? args.tags.map(String).filter(Boolean) : [];
|
|
15917
|
+
if (requested.length === 0) {
|
|
15918
|
+
return { success: false, output: t("tools.enable_no_tags") };
|
|
15919
|
+
}
|
|
15920
|
+
const active = ctx.activeToolTags ?? [];
|
|
15921
|
+
const added = [];
|
|
15922
|
+
for (const tag of requested) {
|
|
15923
|
+
if (!active.includes(tag)) {
|
|
15924
|
+
active.push(tag);
|
|
15925
|
+
added.push(tag);
|
|
15926
|
+
}
|
|
15927
|
+
}
|
|
15928
|
+
if (!ctx.toolExecutor) {
|
|
15929
|
+
return { success: false, output: t("tools.enable_no_executor") };
|
|
15930
|
+
}
|
|
15931
|
+
const nowVisible = ctx.toolExecutor.getToolDefinitions([...active]).map((t2) => t2.name);
|
|
15932
|
+
if (added.length === 0) {
|
|
15933
|
+
return {
|
|
15934
|
+
success: true,
|
|
15935
|
+
output: t("tools.enable_already_active", {
|
|
15936
|
+
tags: requested.join(", ")
|
|
15937
|
+
})
|
|
15938
|
+
};
|
|
15939
|
+
}
|
|
15940
|
+
return {
|
|
15941
|
+
success: true,
|
|
15942
|
+
output: t("tools.enable_added", {
|
|
15943
|
+
tags: added.join(", "),
|
|
15944
|
+
tools: nowVisible.join(", ")
|
|
15945
|
+
})
|
|
15946
|
+
};
|
|
15947
|
+
}
|
|
15948
|
+
};
|
|
15949
|
+
});
|
|
15950
|
+
|
|
15844
15951
|
// src/tools/index.ts
|
|
15845
|
-
function registerAllTools(registry2, skillsModule) {
|
|
15952
|
+
function registerAllTools(registry2, skillsModule, opts) {
|
|
15846
15953
|
const tools = [
|
|
15847
15954
|
readFileTool,
|
|
15848
15955
|
writeFileTool,
|
|
@@ -15869,6 +15976,9 @@ function registerAllTools(registry2, skillsModule) {
|
|
|
15869
15976
|
searchHistoryTool,
|
|
15870
15977
|
attachImageTool
|
|
15871
15978
|
];
|
|
15979
|
+
if (opts?.enableOnDemand !== false) {
|
|
15980
|
+
tools.push(enableToolsTool);
|
|
15981
|
+
}
|
|
15872
15982
|
if (skillsModule) {
|
|
15873
15983
|
tools.push(createLoadSkillTool(skillsModule));
|
|
15874
15984
|
}
|
|
@@ -15906,6 +16016,42 @@ var init_tools = __esm(() => {
|
|
|
15906
16016
|
init_recall();
|
|
15907
16017
|
init_browser();
|
|
15908
16018
|
init_attach_image();
|
|
16019
|
+
init_enable_tools();
|
|
16020
|
+
});
|
|
16021
|
+
|
|
16022
|
+
// src/tools/hidden-tools-block.ts
|
|
16023
|
+
function buildHiddenToolsBlock(allTools, activeTags) {
|
|
16024
|
+
if (!allTools.length)
|
|
16025
|
+
return "";
|
|
16026
|
+
const activeSet = new Set(activeTags);
|
|
16027
|
+
const visible = new Set;
|
|
16028
|
+
for (const tool of allTools) {
|
|
16029
|
+
if (tool.alwaysOn || tool.tags && tool.tags.some((tag) => activeSet.has(tag))) {
|
|
16030
|
+
visible.add(tool.name);
|
|
16031
|
+
}
|
|
16032
|
+
}
|
|
16033
|
+
const hidden = allTools.filter((tool) => !visible.has(tool.name));
|
|
16034
|
+
if (hidden.length === 0)
|
|
16035
|
+
return "";
|
|
16036
|
+
const byTag = new Map;
|
|
16037
|
+
for (const tool of hidden) {
|
|
16038
|
+
const tags = tool.tags && tool.tags.length > 0 ? tool.tags : ["other"];
|
|
16039
|
+
for (const tag of tags) {
|
|
16040
|
+
if (!byTag.has(tag))
|
|
16041
|
+
byTag.set(tag, []);
|
|
16042
|
+
byTag.get(tag).push(tool);
|
|
16043
|
+
}
|
|
16044
|
+
}
|
|
16045
|
+
const lines = [t("tools.hidden_header")];
|
|
16046
|
+
for (const [tag, tools] of [...byTag.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
16047
|
+
const names = [...new Set(tools.map((tool) => tool.name))].sort().join(", ");
|
|
16048
|
+
lines.push(`- [${tag}] ${names}`);
|
|
16049
|
+
}
|
|
16050
|
+
return lines.join(`
|
|
16051
|
+
`);
|
|
16052
|
+
}
|
|
16053
|
+
var init_hidden_tools_block = __esm(() => {
|
|
16054
|
+
init_i18n();
|
|
15909
16055
|
});
|
|
15910
16056
|
|
|
15911
16057
|
// src/modules/registry.ts
|
|
@@ -16088,7 +16234,7 @@ class LintOnWritePlugin {
|
|
|
16088
16234
|
await this.runProjectTypeCheck(fullPath, ctx.baseDir, result);
|
|
16089
16235
|
}
|
|
16090
16236
|
async checkSyntax(filePath, ext, baseDir) {
|
|
16091
|
-
if (ext === ".ts" || ext === ".tsx") {
|
|
16237
|
+
if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
|
|
16092
16238
|
let content = "";
|
|
16093
16239
|
try {
|
|
16094
16240
|
content = readFileSync15(filePath, "utf-8");
|
|
@@ -16115,7 +16261,7 @@ class LintOnWritePlugin {
|
|
|
16115
16261
|
return firstError.trim();
|
|
16116
16262
|
}
|
|
16117
16263
|
}
|
|
16118
|
-
if (ext === ".js" || ext === ".jsx") {
|
|
16264
|
+
if (ext === ".js" || ext === ".jsx" || ext === ".cjs" || ext === ".mjs") {
|
|
16119
16265
|
try {
|
|
16120
16266
|
await runAsync(`node --check "${filePath}"`, baseDir, 5000);
|
|
16121
16267
|
return null;
|
|
@@ -16150,10 +16296,7 @@ class LintOnWritePlugin {
|
|
|
16150
16296
|
}
|
|
16151
16297
|
}
|
|
16152
16298
|
async runProjectTypeCheck(filePath, baseDir, result) {
|
|
16153
|
-
const projectRoot = findProjectRoot(filePath, baseDir, [
|
|
16154
|
-
"tsconfig.json",
|
|
16155
|
-
"package.json"
|
|
16156
|
-
]);
|
|
16299
|
+
const projectRoot = findProjectRoot(filePath, baseDir, ["tsconfig.json", "package.json"]);
|
|
16157
16300
|
const tsconfigPath = join23(projectRoot, "tsconfig.json");
|
|
16158
16301
|
if (!existsSync29(tsconfigPath)) {
|
|
16159
16302
|
return;
|
|
@@ -16912,6 +17055,7 @@ function createPlanToolDefinitions(deps) {
|
|
|
16912
17055
|
return [
|
|
16913
17056
|
{
|
|
16914
17057
|
name: "plan",
|
|
17058
|
+
alwaysOn: true,
|
|
16915
17059
|
description: `Create, update, show, abort, list, switch, or re-plan multi-step plans.
|
|
16916
17060
|
|
|
16917
17061
|
Actions:
|
|
@@ -16936,15 +17080,7 @@ Write CONCRETE steps with exact file paths and commands:
|
|
|
16936
17080
|
properties: {
|
|
16937
17081
|
action: {
|
|
16938
17082
|
type: "string",
|
|
16939
|
-
enum: [
|
|
16940
|
-
"create",
|
|
16941
|
-
"update",
|
|
16942
|
-
"show",
|
|
16943
|
-
"abort",
|
|
16944
|
-
"list",
|
|
16945
|
-
"switch",
|
|
16946
|
-
"re-plan"
|
|
16947
|
-
]
|
|
17083
|
+
enum: ["create", "update", "show", "abort", "list", "switch", "re-plan"]
|
|
16948
17084
|
},
|
|
16949
17085
|
title: { type: "string" },
|
|
16950
17086
|
steps: { type: "array", items: { type: "string" } },
|
|
@@ -17237,6 +17373,7 @@ ${progress}`,
|
|
|
17237
17373
|
},
|
|
17238
17374
|
{
|
|
17239
17375
|
name: "todo",
|
|
17376
|
+
alwaysOn: true,
|
|
17240
17377
|
description: "Manage sub-tasks within current plan step. Use to break down complex steps into smaller tasks.",
|
|
17241
17378
|
parameters: {
|
|
17242
17379
|
type: "object",
|
|
@@ -17332,6 +17469,7 @@ ${lines.join(`
|
|
|
17332
17469
|
},
|
|
17333
17470
|
{
|
|
17334
17471
|
name: "verify",
|
|
17472
|
+
alwaysOn: true,
|
|
17335
17473
|
description: "Run verification for the current step. Checks files mentioned in the step description.",
|
|
17336
17474
|
parameters: {
|
|
17337
17475
|
type: "object",
|
|
@@ -17943,13 +18081,7 @@ var init_module = __esm(() => {
|
|
|
17943
18081
|
});
|
|
17944
18082
|
|
|
17945
18083
|
// src/modules/security/session-encryption.ts
|
|
17946
|
-
import {
|
|
17947
|
-
readFileSync as readFileSync18,
|
|
17948
|
-
writeFileSync as writeFileSync11,
|
|
17949
|
-
existsSync as existsSync34,
|
|
17950
|
-
readdirSync as readdirSync11,
|
|
17951
|
-
unlinkSync as unlinkSync4
|
|
17952
|
-
} from "fs";
|
|
18084
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync11, existsSync as existsSync34, readdirSync as readdirSync11, unlinkSync as unlinkSync4 } from "fs";
|
|
17953
18085
|
import { join as join27 } from "path";
|
|
17954
18086
|
import { homedir as homedir8 } from "os";
|
|
17955
18087
|
|
|
@@ -18843,24 +18975,7 @@ class LspClient {
|
|
|
18843
18975
|
async checkFile(filePath, baseDir, config, projectRoot = baseDir) {
|
|
18844
18976
|
const timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
18845
18977
|
try {
|
|
18846
|
-
await this.
|
|
18847
|
-
const rootUri = this.pathToUri(projectRoot);
|
|
18848
|
-
const initParams = {
|
|
18849
|
-
processId: process.pid,
|
|
18850
|
-
rootUri,
|
|
18851
|
-
workspaceFolders: [{ uri: rootUri, name: "workspace" }],
|
|
18852
|
-
capabilities: { textDocument: { publishDiagnostics: {} } }
|
|
18853
|
-
};
|
|
18854
|
-
try {
|
|
18855
|
-
await this.sendRequest("initialize", initParams, timeout);
|
|
18856
|
-
} catch (e) {
|
|
18857
|
-
if (!(e instanceof Error) || !e.message.includes("initialize"))
|
|
18858
|
-
throw e;
|
|
18859
|
-
await this.shutdown();
|
|
18860
|
-
await this.startServer(config, projectRoot);
|
|
18861
|
-
await this.sendRequest("initialize", initParams, timeout);
|
|
18862
|
-
}
|
|
18863
|
-
this.initialized = true;
|
|
18978
|
+
await this.initialize(config, projectRoot, timeout);
|
|
18864
18979
|
this.sendNotification("initialized", {});
|
|
18865
18980
|
const uri = this.pathToUri(resolve20(filePath));
|
|
18866
18981
|
const fs2 = await import("fs");
|
|
@@ -18888,6 +19003,33 @@ class LspClient {
|
|
|
18888
19003
|
await this.shutdown();
|
|
18889
19004
|
}
|
|
18890
19005
|
}
|
|
19006
|
+
async probe(config, projectRoot, timeout) {
|
|
19007
|
+
try {
|
|
19008
|
+
await this.initialize(config, projectRoot, timeout);
|
|
19009
|
+
} finally {
|
|
19010
|
+
await this.shutdown();
|
|
19011
|
+
}
|
|
19012
|
+
}
|
|
19013
|
+
async initialize(config, projectRoot, timeout) {
|
|
19014
|
+
await this.startServer(config, projectRoot);
|
|
19015
|
+
const rootUri = this.pathToUri(projectRoot);
|
|
19016
|
+
const initParams = {
|
|
19017
|
+
processId: process.pid,
|
|
19018
|
+
rootUri,
|
|
19019
|
+
workspaceFolders: [{ uri: rootUri, name: "workspace" }],
|
|
19020
|
+
capabilities: { textDocument: { publishDiagnostics: {} } }
|
|
19021
|
+
};
|
|
19022
|
+
try {
|
|
19023
|
+
await this.sendRequest("initialize", initParams, timeout);
|
|
19024
|
+
} catch (e) {
|
|
19025
|
+
if (!(e instanceof Error) || !e.message.includes("initialize"))
|
|
19026
|
+
throw e;
|
|
19027
|
+
await this.shutdown();
|
|
19028
|
+
await this.startServer(config, projectRoot);
|
|
19029
|
+
await this.sendRequest("initialize", initParams, timeout);
|
|
19030
|
+
}
|
|
19031
|
+
this.initialized = true;
|
|
19032
|
+
}
|
|
18891
19033
|
async startServer(config, projectRoot) {
|
|
18892
19034
|
if (config.autoInstall === false) {
|
|
18893
19035
|
try {
|
|
@@ -19051,8 +19193,12 @@ class LspClient {
|
|
|
19051
19193
|
const map = {
|
|
19052
19194
|
ts: "typescript",
|
|
19053
19195
|
tsx: "typescriptreact",
|
|
19196
|
+
mts: "typescript",
|
|
19197
|
+
cts: "typescript",
|
|
19054
19198
|
js: "javascript",
|
|
19055
19199
|
jsx: "javascriptreact",
|
|
19200
|
+
mjs: "javascript",
|
|
19201
|
+
cjs: "javascript",
|
|
19056
19202
|
py: "python",
|
|
19057
19203
|
go: "go",
|
|
19058
19204
|
rs: "rust",
|
|
@@ -19218,6 +19364,7 @@ ${items}`;
|
|
|
19218
19364
|
name: "lsp_check",
|
|
19219
19365
|
description: 'Run static checks (LSP diagnostics) on a file or directory. For "check for errors" tasks: pass a file to check it, or a directory to check its source files (capped at 15). Returns [LSP errors] / [LSP warnings] for files with a configured LSP server.',
|
|
19220
19366
|
tags: ["code", "check"],
|
|
19367
|
+
alwaysOn: true,
|
|
19221
19368
|
boundedOutput: true,
|
|
19222
19369
|
timeoutMs: 90000,
|
|
19223
19370
|
parameters: {
|
|
@@ -19345,9 +19492,133 @@ var init_lsp = __esm(() => {
|
|
|
19345
19492
|
init_config();
|
|
19346
19493
|
});
|
|
19347
19494
|
|
|
19495
|
+
// src/modules/lsp/startup-check.ts
|
|
19496
|
+
import { existsSync as existsSync39 } from "fs";
|
|
19497
|
+
import { join as join31 } from "path";
|
|
19498
|
+
import { spawn as spawn7 } from "child_process";
|
|
19499
|
+
async function runStartupHealthCheck(config, baseDir, deps = {}) {
|
|
19500
|
+
if (!config.enabled)
|
|
19501
|
+
return null;
|
|
19502
|
+
try {
|
|
19503
|
+
const result = await Promise.race([
|
|
19504
|
+
runCheck(config, baseDir, deps),
|
|
19505
|
+
new Promise((resolve23) => setTimeout(() => resolve23(null), STARTUP_CHECK_TIMEOUT_MS))
|
|
19506
|
+
]);
|
|
19507
|
+
if (!result || result.lines.length === 0)
|
|
19508
|
+
return null;
|
|
19509
|
+
const content = `${t("lsp.startup_header")}
|
|
19510
|
+
${result.lines.join(`
|
|
19511
|
+
`)}`;
|
|
19512
|
+
return {
|
|
19513
|
+
content,
|
|
19514
|
+
priority: "high",
|
|
19515
|
+
essential: false,
|
|
19516
|
+
estimatedTokens: Math.ceil(content.length / 4)
|
|
19517
|
+
};
|
|
19518
|
+
} catch {
|
|
19519
|
+
return null;
|
|
19520
|
+
}
|
|
19521
|
+
}
|
|
19522
|
+
async function runCheck(config, baseDir, deps) {
|
|
19523
|
+
const projectRoot = findProjectRoot(baseDir, baseDir, ["tsconfig.json", "package.json"]);
|
|
19524
|
+
if (existsSync39(join31(projectRoot, "tsconfig.json"))) {
|
|
19525
|
+
const runTsc = deps.runTsc ?? runTscDefault;
|
|
19526
|
+
const errors = await runTsc(projectRoot, STARTUP_CHECK_TIMEOUT_MS);
|
|
19527
|
+
if (errors.length === 0)
|
|
19528
|
+
return null;
|
|
19529
|
+
return { lines: errors.slice(0, STARTUP_CHECK_ERROR_CAP) };
|
|
19530
|
+
}
|
|
19531
|
+
const client = deps.client ?? new LspClient;
|
|
19532
|
+
const files = await collectCheckFiles(baseDir, config);
|
|
19533
|
+
const lines = [];
|
|
19534
|
+
let checked = 0;
|
|
19535
|
+
for (const file of files.slice(0, STARTUP_CHECK_FILE_CAP)) {
|
|
19536
|
+
const serverConfig = getServerForFile(file, config);
|
|
19537
|
+
if (!serverConfig)
|
|
19538
|
+
continue;
|
|
19539
|
+
const fileRoot = findProjectRoot(file, baseDir, serverConfig.workspaceMarkers ?? []);
|
|
19540
|
+
try {
|
|
19541
|
+
const diags = await client.checkFile(file, baseDir, serverConfig, fileRoot);
|
|
19542
|
+
checked++;
|
|
19543
|
+
for (const d of diags) {
|
|
19544
|
+
if (d.severity === 1) {
|
|
19545
|
+
lines.push(formatStartupError(file, baseDir, d));
|
|
19546
|
+
}
|
|
19547
|
+
}
|
|
19548
|
+
} catch {}
|
|
19549
|
+
}
|
|
19550
|
+
if (checked === 0 || lines.length === 0)
|
|
19551
|
+
return null;
|
|
19552
|
+
return { lines: lines.slice(0, STARTUP_CHECK_ERROR_CAP) };
|
|
19553
|
+
}
|
|
19554
|
+
async function runTscDefault(projectRoot, timeoutMs) {
|
|
19555
|
+
return new Promise((resolve23) => {
|
|
19556
|
+
const child = spawn7("npx", ["tsc", "--noEmit", "--skipLibCheck"], {
|
|
19557
|
+
cwd: projectRoot,
|
|
19558
|
+
shell: true,
|
|
19559
|
+
windowsHide: true,
|
|
19560
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
19561
|
+
});
|
|
19562
|
+
let out = "";
|
|
19563
|
+
child.stdout?.on("data", (d) => {
|
|
19564
|
+
out += d.toString();
|
|
19565
|
+
});
|
|
19566
|
+
child.stderr?.on("data", (d) => {
|
|
19567
|
+
out += d.toString();
|
|
19568
|
+
});
|
|
19569
|
+
const timer = setTimeout(() => {
|
|
19570
|
+
child.kill();
|
|
19571
|
+
resolve23([]);
|
|
19572
|
+
}, timeoutMs);
|
|
19573
|
+
child.on("error", () => {
|
|
19574
|
+
clearTimeout(timer);
|
|
19575
|
+
resolve23([]);
|
|
19576
|
+
});
|
|
19577
|
+
child.on("close", () => {
|
|
19578
|
+
clearTimeout(timer);
|
|
19579
|
+
resolve23(parseTscErrors(out));
|
|
19580
|
+
});
|
|
19581
|
+
});
|
|
19582
|
+
}
|
|
19583
|
+
function parseTscErrors(output) {
|
|
19584
|
+
const lines = [];
|
|
19585
|
+
for (const raw of output.split(`
|
|
19586
|
+
`)) {
|
|
19587
|
+
const line = raw.replace(/^[a-zA-Z]:/, "").trim();
|
|
19588
|
+
if (line.includes("error TS"))
|
|
19589
|
+
lines.push(line);
|
|
19590
|
+
}
|
|
19591
|
+
return dedupe(lines);
|
|
19592
|
+
}
|
|
19593
|
+
function formatStartupError(file, baseDir, d) {
|
|
19594
|
+
const rel = file.replace(baseDir.replace(/[\\/]$/, ""), "").replace(/^[\\/]/, "");
|
|
19595
|
+
const line = d.range.start.line + 1;
|
|
19596
|
+
const col = d.range.start.character + 1;
|
|
19597
|
+
return ` ${rel || file}(${line},${col}): error: ${d.message}`;
|
|
19598
|
+
}
|
|
19599
|
+
function dedupe(lines) {
|
|
19600
|
+
const seen = new Set;
|
|
19601
|
+
const out = [];
|
|
19602
|
+
for (const line of lines) {
|
|
19603
|
+
if (!seen.has(line)) {
|
|
19604
|
+
seen.add(line);
|
|
19605
|
+
out.push(line);
|
|
19606
|
+
}
|
|
19607
|
+
}
|
|
19608
|
+
return out;
|
|
19609
|
+
}
|
|
19610
|
+
var STARTUP_CHECK_FILE_CAP = 5, STARTUP_CHECK_TIMEOUT_MS = 60000, STARTUP_CHECK_ERROR_CAP = 20;
|
|
19611
|
+
var init_startup_check = __esm(() => {
|
|
19612
|
+
init_i18n();
|
|
19613
|
+
init_client2();
|
|
19614
|
+
init_check_tool();
|
|
19615
|
+
init_config();
|
|
19616
|
+
init_project_root();
|
|
19617
|
+
});
|
|
19618
|
+
|
|
19348
19619
|
// src/modules/indexer/walker.ts
|
|
19349
|
-
import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as
|
|
19350
|
-
import { join as
|
|
19620
|
+
import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync40, watch } from "fs";
|
|
19621
|
+
import { join as join32, relative as relative3, extname as extname5 } from "path";
|
|
19351
19622
|
|
|
19352
19623
|
class Indexer {
|
|
19353
19624
|
baseDir;
|
|
@@ -19374,7 +19645,7 @@ class Indexer {
|
|
|
19374
19645
|
let totalSize = 0;
|
|
19375
19646
|
let count = 0;
|
|
19376
19647
|
const walkDir2 = (dir) => {
|
|
19377
|
-
if (!
|
|
19648
|
+
if (!existsSync40(dir))
|
|
19378
19649
|
return;
|
|
19379
19650
|
let entries;
|
|
19380
19651
|
try {
|
|
@@ -19385,7 +19656,7 @@ class Indexer {
|
|
|
19385
19656
|
for (const entry of entries) {
|
|
19386
19657
|
if (count >= this.MAX_FILES)
|
|
19387
19658
|
return;
|
|
19388
|
-
const fullPath =
|
|
19659
|
+
const fullPath = join32(dir, entry);
|
|
19389
19660
|
const relPath = relative3(this.baseDir, fullPath);
|
|
19390
19661
|
const stat2 = statSync7(fullPath);
|
|
19391
19662
|
if (stat2.isDirectory()) {
|
|
@@ -19448,19 +19719,19 @@ var init_walker = __esm(() => {
|
|
|
19448
19719
|
});
|
|
19449
19720
|
|
|
19450
19721
|
// src/modules/indexer/cache.ts
|
|
19451
|
-
import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as
|
|
19452
|
-
import { join as
|
|
19722
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync41, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
|
|
19723
|
+
import { join as join33 } from "path";
|
|
19453
19724
|
|
|
19454
19725
|
class IndexCache {
|
|
19455
19726
|
cachePath;
|
|
19456
19727
|
cache = null;
|
|
19457
19728
|
constructor(cacheDir) {
|
|
19458
|
-
this.cachePath =
|
|
19729
|
+
this.cachePath = join33(cacheDir, "index-cache.json");
|
|
19459
19730
|
}
|
|
19460
19731
|
load() {
|
|
19461
19732
|
if (this.cache)
|
|
19462
19733
|
return this.cache;
|
|
19463
|
-
if (!
|
|
19734
|
+
if (!existsSync41(this.cachePath))
|
|
19464
19735
|
return null;
|
|
19465
19736
|
try {
|
|
19466
19737
|
this.cache = JSON.parse(readFileSync23(this.cachePath, "utf-8"));
|
|
@@ -19471,14 +19742,14 @@ class IndexCache {
|
|
|
19471
19742
|
}
|
|
19472
19743
|
save(result) {
|
|
19473
19744
|
this.cache = result;
|
|
19474
|
-
const dir =
|
|
19475
|
-
if (!
|
|
19745
|
+
const dir = join33(this.cachePath, "..");
|
|
19746
|
+
if (!existsSync41(dir))
|
|
19476
19747
|
mkdirSync17(dir, { recursive: true });
|
|
19477
19748
|
writeFileSync14(this.cachePath, JSON.stringify(result), "utf-8");
|
|
19478
19749
|
}
|
|
19479
19750
|
invalidate() {
|
|
19480
19751
|
this.cache = null;
|
|
19481
|
-
if (
|
|
19752
|
+
if (existsSync41(this.cachePath)) {
|
|
19482
19753
|
try {
|
|
19483
19754
|
rmSync3(this.cachePath);
|
|
19484
19755
|
} catch {}
|
|
@@ -19488,11 +19759,11 @@ class IndexCache {
|
|
|
19488
19759
|
var init_cache = () => {};
|
|
19489
19760
|
|
|
19490
19761
|
// src/modules/indexer/project-profile.ts
|
|
19491
|
-
import { readFileSync as readFileSync24, existsSync as
|
|
19492
|
-
import { join as
|
|
19762
|
+
import { readFileSync as readFileSync24, existsSync as existsSync42 } from "fs";
|
|
19763
|
+
import { join as join34 } from "path";
|
|
19493
19764
|
function detectManifest(baseDir) {
|
|
19494
19765
|
for (const manifest of MANIFEST_ORDER) {
|
|
19495
|
-
if (
|
|
19766
|
+
if (existsSync42(join34(baseDir, manifest)))
|
|
19496
19767
|
return manifest;
|
|
19497
19768
|
}
|
|
19498
19769
|
return null;
|
|
@@ -19509,7 +19780,7 @@ function cleanDependency(entry) {
|
|
|
19509
19780
|
}
|
|
19510
19781
|
function readPackageJson(baseDir) {
|
|
19511
19782
|
try {
|
|
19512
|
-
const raw = JSON.parse(readFileSync24(
|
|
19783
|
+
const raw = JSON.parse(readFileSync24(join34(baseDir, "package.json"), "utf-8"));
|
|
19513
19784
|
if (!raw || typeof raw !== "object")
|
|
19514
19785
|
return null;
|
|
19515
19786
|
const profile = {
|
|
@@ -19533,7 +19804,7 @@ function readPackageJson(baseDir) {
|
|
|
19533
19804
|
}
|
|
19534
19805
|
function readPyproject(baseDir) {
|
|
19535
19806
|
try {
|
|
19536
|
-
const content = readFileSync24(
|
|
19807
|
+
const content = readFileSync24(join34(baseDir, "pyproject.toml"), "utf-8");
|
|
19537
19808
|
const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
|
|
19538
19809
|
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
19539
19810
|
if (nameMatch)
|
|
@@ -19549,7 +19820,7 @@ function readPyproject(baseDir) {
|
|
|
19549
19820
|
}
|
|
19550
19821
|
function readCargo(baseDir) {
|
|
19551
19822
|
try {
|
|
19552
|
-
const content = readFileSync24(
|
|
19823
|
+
const content = readFileSync24(join34(baseDir, "Cargo.toml"), "utf-8");
|
|
19553
19824
|
const profile = { runtime: "rust", deps: [], devDeps: [], scripts: {} };
|
|
19554
19825
|
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
19555
19826
|
if (nameMatch)
|
|
@@ -19573,7 +19844,7 @@ function readCargo(baseDir) {
|
|
|
19573
19844
|
}
|
|
19574
19845
|
function readGoMod(baseDir) {
|
|
19575
19846
|
try {
|
|
19576
|
-
const content = readFileSync24(
|
|
19847
|
+
const content = readFileSync24(join34(baseDir, "go.mod"), "utf-8");
|
|
19577
19848
|
const profile = { runtime: "go", deps: [], devDeps: [], scripts: {} };
|
|
19578
19849
|
const moduleMatch = content.match(/^module\s+(\S+)/m);
|
|
19579
19850
|
if (moduleMatch)
|
|
@@ -19591,7 +19862,7 @@ function readGoMod(baseDir) {
|
|
|
19591
19862
|
}
|
|
19592
19863
|
function readRequirements(baseDir) {
|
|
19593
19864
|
try {
|
|
19594
|
-
const content = readFileSync24(
|
|
19865
|
+
const content = readFileSync24(join34(baseDir, "requirements.txt"), "utf-8");
|
|
19595
19866
|
const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
|
|
19596
19867
|
for (const line of content.split(`
|
|
19597
19868
|
`)) {
|
|
@@ -19819,6 +20090,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
|
|
|
19819
20090
|
createProjectMapTool() {
|
|
19820
20091
|
return {
|
|
19821
20092
|
name: "project_map",
|
|
20093
|
+
alwaysOn: true,
|
|
19822
20094
|
description: t("indexer.project_map_desc"),
|
|
19823
20095
|
parameters: {
|
|
19824
20096
|
type: "object",
|
|
@@ -19859,7 +20131,10 @@ ${stackLine2}` : summary2;
|
|
|
19859
20131
|
return `- ${path}${exports}`;
|
|
19860
20132
|
}).join(`
|
|
19861
20133
|
`);
|
|
19862
|
-
return this.makeResult(t("indexer.find_results", {
|
|
20134
|
+
return this.makeResult(t("indexer.find_results", {
|
|
20135
|
+
count: matches.length,
|
|
20136
|
+
results: lines
|
|
20137
|
+
}));
|
|
19863
20138
|
}
|
|
19864
20139
|
if (!this.index) {
|
|
19865
20140
|
await this.buildIndex();
|
|
@@ -20045,7 +20320,7 @@ var init_mcp = __esm(() => {
|
|
|
20045
20320
|
|
|
20046
20321
|
// src/modules/memory/module.ts
|
|
20047
20322
|
import { homedir as homedir10 } from "os";
|
|
20048
|
-
import { join as
|
|
20323
|
+
import { join as join35 } from "path";
|
|
20049
20324
|
|
|
20050
20325
|
class MemoryModule {
|
|
20051
20326
|
name = "memory";
|
|
@@ -20054,7 +20329,7 @@ class MemoryModule {
|
|
|
20054
20329
|
if (storeOrDir instanceof MemoryStore) {
|
|
20055
20330
|
this.store = storeOrDir;
|
|
20056
20331
|
} else {
|
|
20057
|
-
const dir = storeOrDir ||
|
|
20332
|
+
const dir = storeOrDir || join35(homedir10(), ".mma", "memory");
|
|
20058
20333
|
this.store = new MemoryStore(dir);
|
|
20059
20334
|
}
|
|
20060
20335
|
}
|
|
@@ -20140,17 +20415,14 @@ var init_module8 = __esm(() => {
|
|
|
20140
20415
|
});
|
|
20141
20416
|
|
|
20142
20417
|
// src/core/version.ts
|
|
20143
|
-
import { existsSync as
|
|
20144
|
-
import { join as
|
|
20418
|
+
import { existsSync as existsSync43, readFileSync as readFileSync25 } from "fs";
|
|
20419
|
+
import { join as join36, dirname as dirname13 } from "path";
|
|
20145
20420
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20146
20421
|
function readMmaVersion() {
|
|
20147
20422
|
const here = dirname13(fileURLToPath2(import.meta.url));
|
|
20148
|
-
const candidates = [
|
|
20149
|
-
join35(here, "..", "..", "package.json"),
|
|
20150
|
-
join35(here, "..", "package.json")
|
|
20151
|
-
];
|
|
20423
|
+
const candidates = [join36(here, "..", "..", "package.json"), join36(here, "..", "package.json")];
|
|
20152
20424
|
for (const p of candidates) {
|
|
20153
|
-
if (
|
|
20425
|
+
if (existsSync43(p)) {
|
|
20154
20426
|
try {
|
|
20155
20427
|
const raw = JSON.parse(readFileSync25(p, "utf8"));
|
|
20156
20428
|
if (raw.version)
|
|
@@ -20169,8 +20441,8 @@ __export(exports_bootstrap, {
|
|
|
20169
20441
|
bootstrap: () => bootstrap
|
|
20170
20442
|
});
|
|
20171
20443
|
import { homedir as homedir11 } from "os";
|
|
20172
|
-
import { join as
|
|
20173
|
-
import { existsSync as
|
|
20444
|
+
import { join as join37, resolve as resolve23 } from "path";
|
|
20445
|
+
import { existsSync as existsSync44, readFileSync as readFileSync26, writeFileSync as writeFileSync15 } from "fs";
|
|
20174
20446
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
20175
20447
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
20176
20448
|
const isWin = profileCompressed.toLowerCase().includes("win32");
|
|
@@ -20183,11 +20455,11 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
20183
20455
|
lines.push(`Windows (PowerShell): use list_dir/read_file/delete_file/create_dir tools instead of dir/type/del/mkdir. No PowerShell cmdlets (Get-Content, Select-Object, Write-Output), no head/tail/grep/cat. Use forward slashes in paths. CWD: ${baseDir}`);
|
|
20184
20456
|
}
|
|
20185
20457
|
lines.push(`Runtime: Bun is available — run TypeScript directly with "bun <file.ts>" and tests with "bun test" (no tsx/ts-node/npm install needed for that).`);
|
|
20186
|
-
lines.push(`Bash: use "workdir" param instead of "cd dir && cmd". One command per call. Long-running processes: pass "background: true" (id immediately), otherwise auto-backgrounded after a few seconds — check with process_log.`, `DEVELOPMENT RULES (strict): 1) install deps BEFORE writing source (npm/pip/cargo, verify lockfile exists; never import uninstalled packages); 2) framework/toolkit init BEFORE app code; 3) follow plan sequentially, after each step verify deliverables exist with real content, then "plan update step=N status=done"; 4) verify work on disk + command output — don't assume success; 5) no premature work (no files/imports for future steps); 6) stuck after 2+ failures: STOP, try a different approach, write files directly, ask the user.`, `PLAN QUALITY: each step = CONCRETE deliverables (exact file paths with extensions, exact packages, exact commands). Vague steps ("Setup the project") forbidden. Cover init → deps → framework → code → verification. 5-8 steps.`, `For "check/fix errors" tasks, each verification step must name the exact command that proves the errors are gone — "bun run build", "bun test", or the "lsp_check" tool — and the step is done only after that check reports clean.`);
|
|
20458
|
+
lines.push(`Bash: use "workdir" param instead of "cd dir && cmd". One command per call. Long-running processes: pass "background: true" (id immediately), otherwise auto-backgrounded after a few seconds — check with process_log.`, `DEVELOPMENT RULES (strict): 1) install deps BEFORE writing source (npm/pip/cargo, verify lockfile exists; never import uninstalled packages); 2) framework/toolkit init BEFORE app code; 3) follow plan sequentially, after each step verify deliverables exist with real content, then "plan update step=N status=done"; 4) verify work on disk + command output — don't assume success; 5) no premature work (no files/imports for future steps); 6) stuck after 2+ failures: STOP, try a different approach, write files directly, ask the user.`, `VERIFY EVERY WRITE: after write_file or edit_file, if the tool result contains NO [LSP errors], [LSP warnings], [Syntax check failed], or [Project typecheck failed] feedback, call the "lsp_check" tool on the file you just wrote BEFORE marking the step done. Never assume a written file is valid — prove it.`, `PLAN QUALITY: each step = CONCRETE deliverables (exact file paths with extensions, exact packages, exact commands). Vague steps ("Setup the project") forbidden. Cover init → deps → framework → code → verification. 5-8 steps.`, `For "check/fix errors" tasks, each verification step must name the exact command that proves the errors are gone — "bun run build", "bun test", or the "lsp_check" tool — and the step is done only after that check reports clean.`);
|
|
20187
20459
|
if (config.autoPlan) {
|
|
20188
20460
|
lines.push(`Plan rule (MANDATORY): any task creating files, installing packages, or requiring multiple actions MUST create a plan with the "plan" tool BEFORE starting. Each step = a concrete deliverable.`);
|
|
20189
20461
|
}
|
|
20190
|
-
lines.push(`Runtime verification: when a bug is described in terms of runtime behavior (what happens when the app runs), reproduce it — run the app / build / browser tool — and confirm the fix against actual runtime output before calling "plan update step=N status=done".`);
|
|
20462
|
+
lines.push(`Runtime verification: when a bug is described in terms of runtime behavior (what happens when the app runs), reproduce it — run the app / build / browser tool — and confirm the fix against actual runtime output before calling "plan update step=N status=done". Check existing servers first with process_list/process_log: a stale dev server started BEFORE your change still runs the old pipeline and keeps failing even after the files on disk are fixed. Restart or kill it (process_kill) and verify the exact endpoint/port the user reported — a fresh server on a new port does NOT prove the user's error is gone.`);
|
|
20191
20463
|
const hasMCP = config.mcpServers && Object.values(config.mcpServers).some((s) => s.enabled !== false);
|
|
20192
20464
|
if (hasMCP) {
|
|
20193
20465
|
lines.push(`MCP servers are available — use the named MCP tools (prefixed mcp__) to query external services.`);
|
|
@@ -20196,8 +20468,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
20196
20468
|
`);
|
|
20197
20469
|
}
|
|
20198
20470
|
async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
20199
|
-
const dir = configDir ||
|
|
20200
|
-
const projectConfigPath = projectDir ?
|
|
20471
|
+
const dir = configDir || join37(homedir11(), ".mma");
|
|
20472
|
+
const projectConfigPath = projectDir ? join37(projectDir, ".mmrc") : join37(process.cwd(), ".mmrc");
|
|
20201
20473
|
const config = loadConfig({ configDir: dir, projectConfigPath });
|
|
20202
20474
|
setLocale(config.locale);
|
|
20203
20475
|
try {
|
|
@@ -20207,7 +20479,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20207
20479
|
}
|
|
20208
20480
|
} catch {}
|
|
20209
20481
|
const logger = new Logger(config.logLevel);
|
|
20210
|
-
logger.setLogDir(
|
|
20482
|
+
logger.setLogDir(join37(dir, "logs"));
|
|
20211
20483
|
logger.debug("MMA bootstrap", {
|
|
20212
20484
|
version: config.version,
|
|
20213
20485
|
model: config.model
|
|
@@ -20229,7 +20501,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20229
20501
|
logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
|
|
20230
20502
|
}
|
|
20231
20503
|
}
|
|
20232
|
-
const profile = new UserProfile(
|
|
20504
|
+
const profile = new UserProfile(join37(dir));
|
|
20233
20505
|
profile.load() || profile.collect();
|
|
20234
20506
|
profile.save();
|
|
20235
20507
|
const llmProvider = new OpenAICompatProvider({
|
|
@@ -20241,7 +20513,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20241
20513
|
rateLimits: config.security?.rateLimits
|
|
20242
20514
|
});
|
|
20243
20515
|
const baseDir = projectDir ? resolve23(projectDir) : process.cwd();
|
|
20244
|
-
const projectMapCacheDir =
|
|
20516
|
+
const projectMapCacheDir = join37(baseDir, ".mma");
|
|
20245
20517
|
const indexerModule = new IndexerModule({
|
|
20246
20518
|
baseDir,
|
|
20247
20519
|
cacheDir: projectMapCacheDir
|
|
@@ -20252,14 +20524,16 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20252
20524
|
logger.warn(`Project indexing failed: ${err.message}`);
|
|
20253
20525
|
}
|
|
20254
20526
|
const skillsLoader = new SkillsLoader;
|
|
20255
|
-
const builtinDir =
|
|
20256
|
-
const globalDir =
|
|
20257
|
-
const projectSkillsDir =
|
|
20527
|
+
const builtinDir = join37(import.meta.dirname, "skills", "builtin");
|
|
20528
|
+
const globalDir = join37(homedir11(), ".agents", "skills");
|
|
20529
|
+
const projectSkillsDir = join37(baseDir, ".mma", "skills");
|
|
20258
20530
|
const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
|
|
20259
20531
|
const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
|
|
20260
20532
|
const skillsModule = new SkillsModule(availableSkills, skillsBudget);
|
|
20261
20533
|
const toolRegistry = new ToolRegistry;
|
|
20262
|
-
registerAllTools(toolRegistry, skillsModule
|
|
20534
|
+
registerAllTools(toolRegistry, skillsModule, {
|
|
20535
|
+
enableOnDemand: config.tools?.enableOnDemand
|
|
20536
|
+
});
|
|
20263
20537
|
const pluginManager = new PluginManager;
|
|
20264
20538
|
const systemInfoContent = buildSystemInfo(config, baseDir, profile.compress());
|
|
20265
20539
|
const systemInfoPrompt = {
|
|
@@ -20268,11 +20542,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20268
20542
|
essential: true,
|
|
20269
20543
|
estimatedTokens: Math.ceil(systemInfoContent.length / 4)
|
|
20270
20544
|
};
|
|
20271
|
-
const agentsMdGlobal =
|
|
20272
|
-
if (!
|
|
20545
|
+
const agentsMdGlobal = join37(dir, "AGENTS.md");
|
|
20546
|
+
if (!existsSync44(agentsMdGlobal)) {
|
|
20273
20547
|
writeFileSync15(agentsMdGlobal, "", "utf-8");
|
|
20274
20548
|
}
|
|
20275
|
-
const sessionDir =
|
|
20549
|
+
const sessionDir = join37(dir, "sessions");
|
|
20276
20550
|
const sessionStore = new SessionStore(sessionDir);
|
|
20277
20551
|
sessionStore.init();
|
|
20278
20552
|
const sessionManager = new SessionManager(sessionStore, {
|
|
@@ -20286,6 +20560,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20286
20560
|
sessionManager.create();
|
|
20287
20561
|
}
|
|
20288
20562
|
const tokenCounter = new TokenCounter(config.model);
|
|
20563
|
+
const enableOnDemand = config.tools?.enableOnDemand !== false;
|
|
20564
|
+
const activeToolTags = enableOnDemand ? config.tools?.defaultTags ? [...config.tools.defaultTags] : [] : [];
|
|
20289
20565
|
const contextManager = new ContextManager(config.contextWindow, config.contextBudget, tokenCounter);
|
|
20290
20566
|
const toolCtx = {
|
|
20291
20567
|
config,
|
|
@@ -20293,6 +20569,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20293
20569
|
logger,
|
|
20294
20570
|
exitOnComplete,
|
|
20295
20571
|
contextManager,
|
|
20572
|
+
activeToolTags,
|
|
20296
20573
|
sessionId: sessionManager.getActiveMeta()?.id,
|
|
20297
20574
|
sessionContext: sessionManager.getSessionContext() ?? undefined,
|
|
20298
20575
|
recursionDepth: 0,
|
|
@@ -20339,7 +20616,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20339
20616
|
const mcpModule = new MCPModule(config);
|
|
20340
20617
|
await mcpModule.initialize();
|
|
20341
20618
|
moduleRegistry.register(mcpModule);
|
|
20342
|
-
const memoryStore = new MemoryStore(
|
|
20619
|
+
const memoryStore = new MemoryStore(join37(dir, "memory"));
|
|
20343
20620
|
const memoryModule = new MemoryModule(memoryStore);
|
|
20344
20621
|
moduleRegistry.register(memoryModule);
|
|
20345
20622
|
if (config.browser.enabled) {
|
|
@@ -20358,6 +20635,10 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20358
20635
|
lspPlugin.isBuiltin = true;
|
|
20359
20636
|
pluginManager.register(lspPlugin);
|
|
20360
20637
|
}
|
|
20638
|
+
let startupCheckBlock = null;
|
|
20639
|
+
if (!exitOnComplete && true) {
|
|
20640
|
+
startupCheckBlock = await runStartupHealthCheck(config.lsp ?? DEFAULT_LSP_CONFIG, baseDir);
|
|
20641
|
+
}
|
|
20361
20642
|
const moduleTools = moduleRegistry.collectToolDefinitions();
|
|
20362
20643
|
for (const tool of moduleTools) {
|
|
20363
20644
|
toolRegistry.register(tool);
|
|
@@ -20390,8 +20671,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20390
20671
|
pluginManager.register(plugin);
|
|
20391
20672
|
pluginManager.register(plugin2);
|
|
20392
20673
|
const pluginLoader = new PluginLoader;
|
|
20393
|
-
const globalPluginsDir =
|
|
20394
|
-
const projectPluginsDir =
|
|
20674
|
+
const globalPluginsDir = join37(homedir11(), ".mma", "plugins");
|
|
20675
|
+
const projectPluginsDir = join37(baseDir, ".mma", "plugins");
|
|
20395
20676
|
const mmaVersion = readMmaVersion();
|
|
20396
20677
|
pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger, {
|
|
20397
20678
|
source: "global",
|
|
@@ -20417,12 +20698,12 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20417
20698
|
const skipAgentsMd = noAgentsMd === true;
|
|
20418
20699
|
if (!skipAgentsMd) {
|
|
20419
20700
|
const agentsMdCandidates = [
|
|
20420
|
-
|
|
20421
|
-
|
|
20422
|
-
|
|
20701
|
+
join37(baseDir, "AGENTS.md"),
|
|
20702
|
+
join37(baseDir, ".mma", "AGENTS.md"),
|
|
20703
|
+
join37(dir, "AGENTS.md")
|
|
20423
20704
|
];
|
|
20424
20705
|
for (const p of agentsMdCandidates) {
|
|
20425
|
-
if (
|
|
20706
|
+
if (existsSync44(p)) {
|
|
20426
20707
|
const content = readFileSync26(p, "utf-8").trim();
|
|
20427
20708
|
if (content) {
|
|
20428
20709
|
agentsMdBlocks.push({
|
|
@@ -20440,6 +20721,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20440
20721
|
...moduleRegistry.collectPromptBlocks(["indexer"]),
|
|
20441
20722
|
...agentsMdBlocks
|
|
20442
20723
|
];
|
|
20724
|
+
if (startupCheckBlock)
|
|
20725
|
+
promptBlocks.push(startupCheckBlock);
|
|
20443
20726
|
const agentDeps = {
|
|
20444
20727
|
config,
|
|
20445
20728
|
llmProvider,
|
|
@@ -20449,6 +20732,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20449
20732
|
hallucinationDetector,
|
|
20450
20733
|
logger,
|
|
20451
20734
|
baseDir,
|
|
20735
|
+
toolTags: activeToolTags,
|
|
20452
20736
|
promptBlocks,
|
|
20453
20737
|
getDynamicPromptBlocks: () => {
|
|
20454
20738
|
const blocks = [];
|
|
@@ -20461,6 +20745,15 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20461
20745
|
const mapBlock = indexerModule.getSystemPromptBlock();
|
|
20462
20746
|
if (mapBlock)
|
|
20463
20747
|
blocks.push(mapBlock);
|
|
20748
|
+
const hiddenToolsBlock = buildHiddenToolsBlock(toolRegistry.getAll(), activeToolTags);
|
|
20749
|
+
if (hiddenToolsBlock) {
|
|
20750
|
+
blocks.push({
|
|
20751
|
+
content: hiddenToolsBlock,
|
|
20752
|
+
priority: "low",
|
|
20753
|
+
essential: false,
|
|
20754
|
+
estimatedTokens: Math.ceil(hiddenToolsBlock.length / 4)
|
|
20755
|
+
});
|
|
20756
|
+
}
|
|
20464
20757
|
return blocks;
|
|
20465
20758
|
},
|
|
20466
20759
|
finalAudit: () => execModule.runFinalAudit(),
|
|
@@ -20486,6 +20779,7 @@ var init_bootstrap = __esm(() => {
|
|
|
20486
20779
|
init_app_logger();
|
|
20487
20780
|
init_openai_compat();
|
|
20488
20781
|
init_tools();
|
|
20782
|
+
init_hidden_tools_block();
|
|
20489
20783
|
init_executor();
|
|
20490
20784
|
init_manager2();
|
|
20491
20785
|
init_loader();
|
|
@@ -20500,6 +20794,7 @@ var init_bootstrap = __esm(() => {
|
|
|
20500
20794
|
init_skills();
|
|
20501
20795
|
init_browser2();
|
|
20502
20796
|
init_lsp();
|
|
20797
|
+
init_startup_check();
|
|
20503
20798
|
init_indexer();
|
|
20504
20799
|
init_mcp();
|
|
20505
20800
|
init_module8();
|
|
@@ -21227,18 +21522,8 @@ async function runSetup(externalRl) {
|
|
|
21227
21522
|
t("setup.summary_value")
|
|
21228
21523
|
], [
|
|
21229
21524
|
[t("setup.provider_type"), provider, t("setup.model_name"), model],
|
|
21230
|
-
[
|
|
21231
|
-
|
|
21232
|
-
apiBase,
|
|
21233
|
-
t("setup.context_window"),
|
|
21234
|
-
String(contextWindow)
|
|
21235
|
-
],
|
|
21236
|
-
[
|
|
21237
|
-
t("setup.api_key"),
|
|
21238
|
-
apiKey || "not-needed",
|
|
21239
|
-
t("setup.max_iters"),
|
|
21240
|
-
String(maxIterations)
|
|
21241
|
-
],
|
|
21525
|
+
["API Base URL", apiBase, t("setup.context_window"), String(contextWindow)],
|
|
21526
|
+
[t("setup.api_key"), apiKey || "not-needed", t("setup.max_iters"), String(maxIterations)],
|
|
21242
21527
|
[t("setup.ui_lang"), locale, "", ""]
|
|
21243
21528
|
], { maxColumns: 4 });
|
|
21244
21529
|
for (const l of summary)
|
|
@@ -21279,12 +21564,12 @@ __export(exports_manifest, {
|
|
|
21279
21564
|
getCertMark: () => getCertMark,
|
|
21280
21565
|
MANIFEST_PATH: () => MANIFEST_PATH
|
|
21281
21566
|
});
|
|
21282
|
-
import { existsSync as
|
|
21567
|
+
import { existsSync as existsSync45, readFileSync as readFileSync27, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
21283
21568
|
import { homedir as homedir13 } from "os";
|
|
21284
|
-
import { join as
|
|
21569
|
+
import { join as join39 } from "path";
|
|
21285
21570
|
function readManifest(path = MANIFEST_PATH) {
|
|
21286
21571
|
try {
|
|
21287
|
-
if (
|
|
21572
|
+
if (existsSync45(path)) {
|
|
21288
21573
|
const raw = JSON.parse(readFileSync27(path, "utf-8"));
|
|
21289
21574
|
return { version: 1, certifications: raw.certifications ?? [] };
|
|
21290
21575
|
}
|
|
@@ -21292,7 +21577,7 @@ function readManifest(path = MANIFEST_PATH) {
|
|
|
21292
21577
|
return { version: 1, certifications: [] };
|
|
21293
21578
|
}
|
|
21294
21579
|
function saveManifest(m, path = MANIFEST_PATH) {
|
|
21295
|
-
mkdirSync18(
|
|
21580
|
+
mkdirSync18(join39(homedir13(), ".mma"), { recursive: true });
|
|
21296
21581
|
writeFileSync16(path, JSON.stringify(m, null, 2), "utf-8");
|
|
21297
21582
|
}
|
|
21298
21583
|
function upsertCertification(entry, path = MANIFEST_PATH) {
|
|
@@ -21327,7 +21612,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
|
|
|
21327
21612
|
}
|
|
21328
21613
|
var MANIFEST_PATH;
|
|
21329
21614
|
var init_manifest = __esm(() => {
|
|
21330
|
-
MANIFEST_PATH =
|
|
21615
|
+
MANIFEST_PATH = join39(homedir13(), ".mma", "certifications.json");
|
|
21331
21616
|
});
|
|
21332
21617
|
|
|
21333
21618
|
// node_modules/yaml/dist/nodes/identity.js
|
|
@@ -28450,8 +28735,8 @@ var init_scenarios = __esm(() => {
|
|
|
28450
28735
|
});
|
|
28451
28736
|
|
|
28452
28737
|
// src/modules/certification/loader.ts
|
|
28453
|
-
import { existsSync as
|
|
28454
|
-
import { join as
|
|
28738
|
+
import { existsSync as existsSync46, readdirSync as readdirSync15, readFileSync as readFileSync28 } from "fs";
|
|
28739
|
+
import { join as join40 } from "path";
|
|
28455
28740
|
function validateScenario(s) {
|
|
28456
28741
|
const errors2 = [];
|
|
28457
28742
|
const isSkip = s.mode === "skip";
|
|
@@ -28500,12 +28785,12 @@ function loadScenarios(userDir) {
|
|
|
28500
28785
|
else
|
|
28501
28786
|
scenarios.push(s);
|
|
28502
28787
|
}
|
|
28503
|
-
if (userDir &&
|
|
28788
|
+
if (userDir && existsSync46(userDir)) {
|
|
28504
28789
|
for (const file of readdirSync15(userDir)) {
|
|
28505
28790
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
|
|
28506
28791
|
continue;
|
|
28507
28792
|
try {
|
|
28508
|
-
const raw = readFileSync28(
|
|
28793
|
+
const raw = readFileSync28(join40(userDir, file), "utf-8");
|
|
28509
28794
|
const data = $parse(raw);
|
|
28510
28795
|
const parsed = normalizeScenario(data, file);
|
|
28511
28796
|
const errs = validateScenario(parsed);
|
|
@@ -28558,31 +28843,31 @@ var init_loader3 = __esm(() => {
|
|
|
28558
28843
|
});
|
|
28559
28844
|
|
|
28560
28845
|
// src/modules/certification/fact-checker.ts
|
|
28561
|
-
import { existsSync as
|
|
28562
|
-
import { join as
|
|
28846
|
+
import { existsSync as existsSync47, readFileSync as readFileSync29, statSync as statSync8 } from "fs";
|
|
28847
|
+
import { join as join41 } from "path";
|
|
28563
28848
|
function checkSandbox(sandboxDir, checks, exitCode, output) {
|
|
28564
28849
|
const failures = [];
|
|
28565
28850
|
for (const check of checks) {
|
|
28566
|
-
if (!
|
|
28851
|
+
if (!runCheck2(sandboxDir, check, exitCode, output)) {
|
|
28567
28852
|
failures.push(describe(check));
|
|
28568
28853
|
}
|
|
28569
28854
|
}
|
|
28570
28855
|
return { pass: failures.length === 0, failures };
|
|
28571
28856
|
}
|
|
28572
|
-
function
|
|
28857
|
+
function runCheck2(sandboxDir, check, exitCode, output) {
|
|
28573
28858
|
switch (check.type) {
|
|
28574
28859
|
case "exitCode":
|
|
28575
28860
|
return exitCode === (check.code ?? 0);
|
|
28576
28861
|
case "outputContains":
|
|
28577
28862
|
return output.includes(check.text);
|
|
28578
28863
|
case "fileExists":
|
|
28579
|
-
return isFile(
|
|
28864
|
+
return isFile(join41(sandboxDir, check.path));
|
|
28580
28865
|
case "fileNotExists":
|
|
28581
|
-
return !
|
|
28866
|
+
return !existsSync47(join41(sandboxDir, check.path));
|
|
28582
28867
|
case "dirExists":
|
|
28583
|
-
return isDir(
|
|
28868
|
+
return isDir(join41(sandboxDir, check.path));
|
|
28584
28869
|
case "fileContent": {
|
|
28585
|
-
const abs =
|
|
28870
|
+
const abs = join41(sandboxDir, check.path);
|
|
28586
28871
|
if (!isFile(abs))
|
|
28587
28872
|
return false;
|
|
28588
28873
|
const content = readFileSync29(abs, "utf-8");
|
|
@@ -28593,7 +28878,7 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
28593
28878
|
return false;
|
|
28594
28879
|
}
|
|
28595
28880
|
case "fileRegex": {
|
|
28596
|
-
const abs =
|
|
28881
|
+
const abs = join41(sandboxDir, check.path);
|
|
28597
28882
|
if (!isFile(abs))
|
|
28598
28883
|
return false;
|
|
28599
28884
|
return new RegExp(check.pattern).test(readFileSync29(abs, "utf-8"));
|
|
@@ -28604,14 +28889,14 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
28604
28889
|
}
|
|
28605
28890
|
function isFile(p) {
|
|
28606
28891
|
try {
|
|
28607
|
-
return
|
|
28892
|
+
return existsSync47(p) && statSync8(p).isFile();
|
|
28608
28893
|
} catch {
|
|
28609
28894
|
return false;
|
|
28610
28895
|
}
|
|
28611
28896
|
}
|
|
28612
28897
|
function isDir(p) {
|
|
28613
28898
|
try {
|
|
28614
|
-
return
|
|
28899
|
+
return existsSync47(p) && statSync8(p).isDirectory();
|
|
28615
28900
|
} catch {
|
|
28616
28901
|
return false;
|
|
28617
28902
|
}
|
|
@@ -28641,10 +28926,10 @@ function describe(check) {
|
|
|
28641
28926
|
var init_fact_checker = () => {};
|
|
28642
28927
|
|
|
28643
28928
|
// src/modules/certification/runner.ts
|
|
28644
|
-
import { spawn as
|
|
28645
|
-
import { existsSync as
|
|
28929
|
+
import { spawn as spawn8 } from "child_process";
|
|
28930
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
|
|
28646
28931
|
import { platform as platform9 } from "os";
|
|
28647
|
-
import { join as
|
|
28932
|
+
import { join as join42, resolve as resolve24, dirname as dirname14 } from "path";
|
|
28648
28933
|
async function runScenario(scenario, opts) {
|
|
28649
28934
|
if (scenario.mode === "skip") {
|
|
28650
28935
|
return {
|
|
@@ -28663,7 +28948,7 @@ async function runScenario(scenario, opts) {
|
|
|
28663
28948
|
let passed = 0;
|
|
28664
28949
|
let firstError;
|
|
28665
28950
|
for (let i = 1;i <= reps; i++) {
|
|
28666
|
-
const sandbox =
|
|
28951
|
+
const sandbox = join42(opts.sandboxBase, `run-${scenario.id}-${i}`);
|
|
28667
28952
|
let failures = [];
|
|
28668
28953
|
let exitCode = -1;
|
|
28669
28954
|
let output = "";
|
|
@@ -28724,28 +29009,25 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
|
|
|
28724
29009
|
rmSync4(sandbox, { recursive: true, force: true });
|
|
28725
29010
|
mkdirSync19(sandbox, { recursive: true });
|
|
28726
29011
|
for (const f of scenario.fixtures ?? []) {
|
|
28727
|
-
const src =
|
|
28728
|
-
if (!
|
|
29012
|
+
const src = join42(mmaRoot, f.source);
|
|
29013
|
+
if (!existsSync48(src)) {
|
|
28729
29014
|
throw new Error(`fixture missing: ${f.source}`);
|
|
28730
29015
|
}
|
|
28731
|
-
const dest =
|
|
29016
|
+
const dest = join42(sandbox, f.dest);
|
|
28732
29017
|
mkdirSync19(dirname14(dest), { recursive: true });
|
|
28733
29018
|
cpSync2(src, dest);
|
|
28734
29019
|
}
|
|
28735
29020
|
}
|
|
28736
29021
|
function resolveMmaEntry(mmaRoot) {
|
|
28737
|
-
const dev =
|
|
28738
|
-
if (
|
|
29022
|
+
const dev = join42(mmaRoot, "src", "cli", "main.ts");
|
|
29023
|
+
if (existsSync48(dev))
|
|
28739
29024
|
return dev;
|
|
28740
|
-
return
|
|
29025
|
+
return join42(mmaRoot, "dist", "main.js");
|
|
28741
29026
|
}
|
|
28742
29027
|
function findMmaRoot(fromDir) {
|
|
28743
|
-
const candidates = [
|
|
28744
|
-
resolve24(fromDir, "..", "..", ".."),
|
|
28745
|
-
resolve24(fromDir, "..")
|
|
28746
|
-
];
|
|
29028
|
+
const candidates = [resolve24(fromDir, "..", "..", ".."), resolve24(fromDir, "..")];
|
|
28747
29029
|
for (const c of candidates) {
|
|
28748
|
-
if (
|
|
29030
|
+
if (existsSync48(join42(c, "package.json")))
|
|
28749
29031
|
return c;
|
|
28750
29032
|
}
|
|
28751
29033
|
return process.cwd();
|
|
@@ -28755,7 +29037,7 @@ function killTree2(child) {
|
|
|
28755
29037
|
if (!pid)
|
|
28756
29038
|
return;
|
|
28757
29039
|
if (platform9() === "win32") {
|
|
28758
|
-
|
|
29040
|
+
spawn8("taskkill", ["/pid", String(pid), "/T", "/F"], {
|
|
28759
29041
|
windowsHide: true,
|
|
28760
29042
|
stdio: "ignore"
|
|
28761
29043
|
});
|
|
@@ -28770,7 +29052,7 @@ function killTree2(child) {
|
|
|
28770
29052
|
}
|
|
28771
29053
|
}
|
|
28772
29054
|
var defaultRunner2 = (env2, cwd, args, timeoutMs) => new Promise((resolvePromise) => {
|
|
28773
|
-
const child =
|
|
29055
|
+
const child = spawn8(process.execPath, args, {
|
|
28774
29056
|
cwd,
|
|
28775
29057
|
env: env2,
|
|
28776
29058
|
windowsHide: true,
|
|
@@ -28813,13 +29095,13 @@ __export(exports_cli, {
|
|
|
28813
29095
|
});
|
|
28814
29096
|
import { rmSync as rmSync5 } from "fs";
|
|
28815
29097
|
import { homedir as homedir14 } from "os";
|
|
28816
|
-
import { join as
|
|
29098
|
+
import { join as join43, dirname as dirname15 } from "path";
|
|
28817
29099
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
28818
|
-
import { existsSync as
|
|
29100
|
+
import { existsSync as existsSync49, readFileSync as readFileSync30 } from "fs";
|
|
28819
29101
|
function readVersion() {
|
|
28820
|
-
const candidates = [
|
|
29102
|
+
const candidates = [join43(MMA_ROOT, "package.json")];
|
|
28821
29103
|
for (const p of candidates) {
|
|
28822
|
-
if (
|
|
29104
|
+
if (existsSync49(p)) {
|
|
28823
29105
|
try {
|
|
28824
29106
|
const raw = JSON.parse(readFileSync30(p, "utf-8"));
|
|
28825
29107
|
if (raw.version)
|
|
@@ -28857,7 +29139,7 @@ async function certify(opts) {
|
|
|
28857
29139
|
return;
|
|
28858
29140
|
}
|
|
28859
29141
|
console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
|
|
28860
|
-
const sandboxBase =
|
|
29142
|
+
const sandboxBase = join43(process.cwd(), ".mma", "certification");
|
|
28861
29143
|
const results = [];
|
|
28862
29144
|
const total = selected.length;
|
|
28863
29145
|
let idx = 0;
|
|
@@ -28971,7 +29253,7 @@ var init_cli = __esm(() => {
|
|
|
28971
29253
|
init_manifest();
|
|
28972
29254
|
HERE = dirname15(fileURLToPath3(import.meta.url));
|
|
28973
29255
|
MMA_ROOT = findMmaRoot(HERE);
|
|
28974
|
-
USER_SCENARIO_DIR =
|
|
29256
|
+
USER_SCENARIO_DIR = join43(homedir14(), ".mma", "certification", "scenarios");
|
|
28975
29257
|
});
|
|
28976
29258
|
|
|
28977
29259
|
// src/cli/repl-commands.ts
|
|
@@ -28980,18 +29262,15 @@ __export(exports_repl_commands, {
|
|
|
28980
29262
|
registerAllCommands: () => registerAllCommands,
|
|
28981
29263
|
COMMAND_GROUPS: () => COMMAND_GROUPS
|
|
28982
29264
|
});
|
|
28983
|
-
import { join as
|
|
29265
|
+
import { join as join45, dirname as dirname17 } from "path";
|
|
28984
29266
|
import { homedir as homedir16 } from "os";
|
|
28985
|
-
import { existsSync as
|
|
29267
|
+
import { existsSync as existsSync51, readFileSync as readFileSync32 } from "fs";
|
|
28986
29268
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
28987
29269
|
function readVersion3() {
|
|
28988
29270
|
const here = dirname17(fileURLToPath5(import.meta.url));
|
|
28989
|
-
const candidates = [
|
|
28990
|
-
join44(here, "..", "..", "package.json"),
|
|
28991
|
-
join44(here, "..", "package.json")
|
|
28992
|
-
];
|
|
29271
|
+
const candidates = [join45(here, "..", "..", "package.json"), join45(here, "..", "package.json")];
|
|
28993
29272
|
for (const p of candidates) {
|
|
28994
|
-
if (
|
|
29273
|
+
if (existsSync51(p)) {
|
|
28995
29274
|
try {
|
|
28996
29275
|
const raw = JSON.parse(readFileSync32(p, "utf8"));
|
|
28997
29276
|
if (raw.version)
|
|
@@ -29057,7 +29336,7 @@ function registerMmaCommands(ctx) {
|
|
|
29057
29336
|
}
|
|
29058
29337
|
try {
|
|
29059
29338
|
const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
|
|
29060
|
-
const { existsSync:
|
|
29339
|
+
const { existsSync: existsSync52 } = await import("fs");
|
|
29061
29340
|
const { resolve: resolve25 } = await import("path");
|
|
29062
29341
|
let dataUrl;
|
|
29063
29342
|
let label;
|
|
@@ -29077,7 +29356,7 @@ function registerMmaCommands(ctx) {
|
|
|
29077
29356
|
label = source;
|
|
29078
29357
|
} else {
|
|
29079
29358
|
const absPath = resolve25(process.cwd(), source);
|
|
29080
|
-
if (!
|
|
29359
|
+
if (!existsSync52(absPath)) {
|
|
29081
29360
|
console.log(pc2.red(t("image.not_found", { path: source })));
|
|
29082
29361
|
return;
|
|
29083
29362
|
}
|
|
@@ -29156,7 +29435,7 @@ function registerMmaCommands(ctx) {
|
|
|
29156
29435
|
console.log(pc2.yellow(t("repl.wizard_running")));
|
|
29157
29436
|
await ctx.withExclusiveInput(async () => {
|
|
29158
29437
|
const answers = await runSetup(ctx.rl);
|
|
29159
|
-
const configPath =
|
|
29438
|
+
const configPath = join45(homedir16(), ".mma", "config.json");
|
|
29160
29439
|
ctx.config.provider.type = answers.provider;
|
|
29161
29440
|
ctx.config.provider.baseUrl = answers.apiBase;
|
|
29162
29441
|
ctx.config.provider.apiKey = answers.apiKey;
|
|
@@ -29210,7 +29489,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
29210
29489
|
return;
|
|
29211
29490
|
}
|
|
29212
29491
|
ctx.config.provider.type = name;
|
|
29213
|
-
const configPath =
|
|
29492
|
+
const configPath = join45(homedir16(), ".mma", "config.json");
|
|
29214
29493
|
saveConfig(ctx.config, configPath);
|
|
29215
29494
|
await ctx.agent.reconfigure(ctx.config);
|
|
29216
29495
|
console.log(pc2.green(t("repl.provider_set", { name })));
|
|
@@ -29266,7 +29545,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
29266
29545
|
return;
|
|
29267
29546
|
}
|
|
29268
29547
|
ctx.config.model = name;
|
|
29269
|
-
const configPath =
|
|
29548
|
+
const configPath = join45(homedir16(), ".mma", "config.json");
|
|
29270
29549
|
saveConfig(ctx.config, configPath);
|
|
29271
29550
|
await ctx.agent.reconfigure(ctx.config);
|
|
29272
29551
|
console.log(pc2.green(t("repl.model_set", { name })));
|
|
@@ -29291,7 +29570,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
29291
29570
|
return;
|
|
29292
29571
|
}
|
|
29293
29572
|
ctx.config.contextWindow = size;
|
|
29294
|
-
const configPath =
|
|
29573
|
+
const configPath = join45(homedir16(), ".mma", "config.json");
|
|
29295
29574
|
saveConfig(ctx.config, configPath);
|
|
29296
29575
|
await ctx.agent.reconfigure(ctx.config);
|
|
29297
29576
|
console.log(pc2.green(t("cli.context_set", { size })));
|
|
@@ -29310,10 +29589,10 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
29310
29589
|
ctx.agent.shutdown();
|
|
29311
29590
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
|
|
29312
29591
|
const { homedir: homedir17 } = await import("os");
|
|
29313
|
-
const { join:
|
|
29592
|
+
const { join: join46 } = await import("path");
|
|
29314
29593
|
const configDir = ctx.configDir;
|
|
29315
29594
|
const baseDir = ctx.baseDir;
|
|
29316
|
-
const projectConfigPath =
|
|
29595
|
+
const projectConfigPath = join46(baseDir, ".mmrc");
|
|
29317
29596
|
const freshConfig = loadConfig2({ configDir, projectConfigPath });
|
|
29318
29597
|
Object.assign(ctx.config, freshConfig);
|
|
29319
29598
|
const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
|
|
@@ -29649,14 +29928,14 @@ init_bootstrap();
|
|
|
29649
29928
|
init_config2();
|
|
29650
29929
|
init_setup();
|
|
29651
29930
|
init_i18n();
|
|
29652
|
-
import { join as
|
|
29931
|
+
import { join as join44, dirname as dirname16 } from "path";
|
|
29653
29932
|
import { homedir as homedir15 } from "os";
|
|
29654
|
-
import { existsSync as
|
|
29933
|
+
import { existsSync as existsSync50, readFileSync as readFileSync31 } from "fs";
|
|
29655
29934
|
|
|
29656
29935
|
// src/cli/security-commands.ts
|
|
29657
29936
|
init_bootstrap();
|
|
29658
29937
|
init_config2();
|
|
29659
|
-
import { join as
|
|
29938
|
+
import { join as join38 } from "path";
|
|
29660
29939
|
import { homedir as homedir12 } from "os";
|
|
29661
29940
|
|
|
29662
29941
|
// src/modules/security/security-policies.ts
|
|
@@ -29728,18 +30007,7 @@ var STRICT_POLICY = {
|
|
|
29728
30007
|
"-R",
|
|
29729
30008
|
"--no-clobber"
|
|
29730
30009
|
],
|
|
29731
|
-
dangerousOperators: [
|
|
29732
|
-
">",
|
|
29733
|
-
">>",
|
|
29734
|
-
"2>",
|
|
29735
|
-
"2>>",
|
|
29736
|
-
"|",
|
|
29737
|
-
"&&",
|
|
29738
|
-
"||",
|
|
29739
|
-
";",
|
|
29740
|
-
"&",
|
|
29741
|
-
"`"
|
|
29742
|
-
],
|
|
30010
|
+
dangerousOperators: [">", ">>", "2>", "2>>", "|", "&&", "||", ";", "&", "`"],
|
|
29743
30011
|
logCommands: true
|
|
29744
30012
|
},
|
|
29745
30013
|
paths: {
|
|
@@ -29953,12 +30221,7 @@ var BALANCED_POLICY = {
|
|
|
29953
30221
|
auditNotifier: {
|
|
29954
30222
|
enabled: false,
|
|
29955
30223
|
minSeverity: "medium",
|
|
29956
|
-
eventTypes: [
|
|
29957
|
-
"security_block",
|
|
29958
|
-
"bash_command",
|
|
29959
|
-
"file_operation",
|
|
29960
|
-
"network_request"
|
|
29961
|
-
],
|
|
30224
|
+
eventTypes: ["security_block", "bash_command", "file_operation", "network_request"],
|
|
29962
30225
|
maxRetries: 3
|
|
29963
30226
|
}
|
|
29964
30227
|
}
|
|
@@ -30186,7 +30449,7 @@ function createSecurityCommand(program2) {
|
|
|
30186
30449
|
}
|
|
30187
30450
|
});
|
|
30188
30451
|
securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
|
|
30189
|
-
const configPath =
|
|
30452
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30190
30453
|
const { config: appConfig } = await bootstrap();
|
|
30191
30454
|
const validPresets = ["strict", "balanced", "permissive"];
|
|
30192
30455
|
if (!validPresets.includes(preset)) {
|
|
@@ -30201,7 +30464,7 @@ function createSecurityCommand(program2) {
|
|
|
30201
30464
|
console.log(t("cli.security.policy_description", { description: policy.description }));
|
|
30202
30465
|
});
|
|
30203
30466
|
securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
|
|
30204
|
-
const configPath =
|
|
30467
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30205
30468
|
const { config: appConfig } = await bootstrap();
|
|
30206
30469
|
appConfig.security = appConfig.security || {};
|
|
30207
30470
|
appConfig.security.sessionEncryption = {
|
|
@@ -30213,7 +30476,7 @@ function createSecurityCommand(program2) {
|
|
|
30213
30476
|
console.log(t("cli.security.encryption_enabled"));
|
|
30214
30477
|
});
|
|
30215
30478
|
securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
|
|
30216
|
-
const configPath =
|
|
30479
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30217
30480
|
const { config: appConfig } = await bootstrap();
|
|
30218
30481
|
appConfig.security = appConfig.security || {};
|
|
30219
30482
|
appConfig.security.sessionEncryption = {
|
|
@@ -30225,7 +30488,7 @@ function createSecurityCommand(program2) {
|
|
|
30225
30488
|
console.log(t("cli.security.encryption_disabled"));
|
|
30226
30489
|
});
|
|
30227
30490
|
securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
|
|
30228
|
-
const configPath =
|
|
30491
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30229
30492
|
const { config: appConfig } = await bootstrap();
|
|
30230
30493
|
appConfig.security = appConfig.security || {};
|
|
30231
30494
|
appConfig.security.auditNotifier = {
|
|
@@ -30239,7 +30502,7 @@ function createSecurityCommand(program2) {
|
|
|
30239
30502
|
console.log(t("cli.security.audit_enabled"));
|
|
30240
30503
|
});
|
|
30241
30504
|
securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
|
|
30242
|
-
const configPath =
|
|
30505
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30243
30506
|
const { config: appConfig } = await bootstrap();
|
|
30244
30507
|
appConfig.security = appConfig.security || {};
|
|
30245
30508
|
appConfig.security.auditNotifier = {
|
|
@@ -30305,12 +30568,9 @@ function createPluginCommand(program2) {
|
|
|
30305
30568
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
30306
30569
|
function readVersion2() {
|
|
30307
30570
|
const here = dirname16(fileURLToPath4(import.meta.url));
|
|
30308
|
-
const candidates = [
|
|
30309
|
-
join43(here, "..", "..", "package.json"),
|
|
30310
|
-
join43(here, "..", "package.json")
|
|
30311
|
-
];
|
|
30571
|
+
const candidates = [join44(here, "..", "..", "package.json"), join44(here, "..", "package.json")];
|
|
30312
30572
|
for (const p of candidates) {
|
|
30313
|
-
if (
|
|
30573
|
+
if (existsSync50(p)) {
|
|
30314
30574
|
try {
|
|
30315
30575
|
const raw = JSON.parse(readFileSync31(p, "utf8"));
|
|
30316
30576
|
if (raw.version)
|
|
@@ -30325,7 +30585,7 @@ function createProgram() {
|
|
|
30325
30585
|
const program2 = new Command().name("mma").description(t("cli.description")).version(version).option("--no-agents-md", t("cli.no_agents_md")).option("-d, --dir <path>", t("cli.dir")).option("-e, --exit-on-complete", t("cli.exit_on_complete")).option("-j, --json", t("cli.json"));
|
|
30326
30586
|
program2.command("init").description(t("cli.init")).action(async () => {
|
|
30327
30587
|
const answers = await runSetup();
|
|
30328
|
-
const configPath =
|
|
30588
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30329
30589
|
const { config } = await bootstrap();
|
|
30330
30590
|
config.provider.type = answers.provider;
|
|
30331
30591
|
config.provider.baseUrl = answers.apiBase;
|
|
@@ -30370,7 +30630,7 @@ function createProgram() {
|
|
|
30370
30630
|
});
|
|
30371
30631
|
const configCmd = program2.command("config").description(t("cli.manage_config"));
|
|
30372
30632
|
configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
|
|
30373
|
-
const configPath =
|
|
30633
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30374
30634
|
const { config } = await bootstrap();
|
|
30375
30635
|
const keys = key.split(".");
|
|
30376
30636
|
let obj = config;
|
|
@@ -30433,7 +30693,7 @@ function createProgram() {
|
|
|
30433
30693
|
console.log(t("cli.model_hint"));
|
|
30434
30694
|
});
|
|
30435
30695
|
model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
|
|
30436
|
-
const configPath =
|
|
30696
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30437
30697
|
const { config } = await bootstrap();
|
|
30438
30698
|
config.model = name;
|
|
30439
30699
|
saveConfig(config, configPath);
|
|
@@ -30469,7 +30729,7 @@ function createProgram() {
|
|
|
30469
30729
|
await uncertify2(name, config);
|
|
30470
30730
|
});
|
|
30471
30731
|
program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
|
|
30472
|
-
const configPath =
|
|
30732
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30473
30733
|
const { config } = await bootstrap();
|
|
30474
30734
|
const contextWindow = parseInt(size, 10);
|
|
30475
30735
|
if (isNaN(contextWindow) || contextWindow < 1024) {
|
|
@@ -30487,7 +30747,7 @@ function createProgram() {
|
|
|
30487
30747
|
console.log(t("cli.base_url"), config.provider.baseUrl);
|
|
30488
30748
|
});
|
|
30489
30749
|
provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
|
|
30490
|
-
const configPath =
|
|
30750
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30491
30751
|
const { config } = await bootstrap();
|
|
30492
30752
|
config.provider.type = name;
|
|
30493
30753
|
saveConfig(config, configPath);
|
|
@@ -31295,8 +31555,8 @@ class LineEditor {
|
|
|
31295
31555
|
}
|
|
31296
31556
|
|
|
31297
31557
|
// src/cli/repl.ts
|
|
31298
|
-
import { existsSync as
|
|
31299
|
-
import { join as
|
|
31558
|
+
import { existsSync as existsSync52, readFileSync as readFileSync33, writeFileSync as writeFileSync17 } from "fs";
|
|
31559
|
+
import { join as join46, dirname as dirname18 } from "path";
|
|
31300
31560
|
import { homedir as homedir17 } from "os";
|
|
31301
31561
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
31302
31562
|
|
|
@@ -31799,14 +32059,63 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
|
|
|
31799
32059
|
init_box();
|
|
31800
32060
|
init_i18n();
|
|
31801
32061
|
init_repl_commands();
|
|
32062
|
+
|
|
32063
|
+
// src/modules/lsp/probe.ts
|
|
32064
|
+
init_client2();
|
|
32065
|
+
init_config();
|
|
32066
|
+
init_check_tool();
|
|
32067
|
+
init_project_root();
|
|
32068
|
+
var DEFAULT_PROBE_TIMEOUT_MS = 20000;
|
|
32069
|
+
async function probeLspServers(config, baseDir, deps = {}) {
|
|
32070
|
+
if (!config.enabled)
|
|
32071
|
+
return { ok: [], failed: [], noneApplicable: true };
|
|
32072
|
+
const client = deps.client ?? new LspClient;
|
|
32073
|
+
const timeoutMs = deps.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
32074
|
+
const collect = deps.collectFiles ?? collectCheckFiles;
|
|
32075
|
+
const files = await collect(baseDir, config);
|
|
32076
|
+
const seen = new Set;
|
|
32077
|
+
const servers = [];
|
|
32078
|
+
for (const file of files) {
|
|
32079
|
+
const language = getLanguageForFile(file);
|
|
32080
|
+
if (!language)
|
|
32081
|
+
continue;
|
|
32082
|
+
const server = config.servers[language];
|
|
32083
|
+
if (!server || seen.has(language))
|
|
32084
|
+
continue;
|
|
32085
|
+
seen.add(language);
|
|
32086
|
+
servers.push({ language, config: server });
|
|
32087
|
+
}
|
|
32088
|
+
if (servers.length === 0)
|
|
32089
|
+
return { ok: [], failed: [], noneApplicable: true };
|
|
32090
|
+
const results = await Promise.all(servers.map(async ({ language, config: server }) => {
|
|
32091
|
+
const projectRoot = findProjectRoot(baseDir, baseDir, server.workspaceMarkers ?? []);
|
|
32092
|
+
const started = Date.now();
|
|
32093
|
+
try {
|
|
32094
|
+
await client.probe(server, projectRoot, timeoutMs);
|
|
32095
|
+
return { language, ok: true, durationMs: Date.now() - started };
|
|
32096
|
+
} catch (e) {
|
|
32097
|
+
return {
|
|
32098
|
+
language,
|
|
32099
|
+
ok: false,
|
|
32100
|
+
error: e instanceof Error ? e.message : String(e),
|
|
32101
|
+
durationMs: Date.now() - started
|
|
32102
|
+
};
|
|
32103
|
+
}
|
|
32104
|
+
}));
|
|
32105
|
+
return {
|
|
32106
|
+
ok: results.filter((r) => r.ok),
|
|
32107
|
+
failed: results.filter((r) => !r.ok),
|
|
32108
|
+
noneApplicable: false
|
|
32109
|
+
};
|
|
32110
|
+
}
|
|
32111
|
+
|
|
32112
|
+
// src/cli/repl.ts
|
|
32113
|
+
init_config();
|
|
31802
32114
|
function readVersion4() {
|
|
31803
32115
|
const here = dirname18(fileURLToPath6(import.meta.url));
|
|
31804
|
-
const candidates = [
|
|
31805
|
-
join45(here, "..", "..", "package.json"),
|
|
31806
|
-
join45(here, "..", "package.json")
|
|
31807
|
-
];
|
|
32116
|
+
const candidates = [join46(here, "..", "..", "package.json"), join46(here, "..", "package.json")];
|
|
31808
32117
|
for (const p of candidates) {
|
|
31809
|
-
if (
|
|
32118
|
+
if (existsSync52(p)) {
|
|
31810
32119
|
try {
|
|
31811
32120
|
const raw = JSON.parse(readFileSync33(p, "utf8"));
|
|
31812
32121
|
if (raw.version)
|
|
@@ -31864,10 +32173,10 @@ class Repl {
|
|
|
31864
32173
|
this.skillsModule = skillsModule;
|
|
31865
32174
|
this.pluginManager = pluginManager;
|
|
31866
32175
|
this.logger = logger;
|
|
31867
|
-
this.configDir = configDir ||
|
|
32176
|
+
this.configDir = configDir || join46(homedir17(), ".mma");
|
|
31868
32177
|
this.baseDir = baseDir || process.cwd();
|
|
31869
32178
|
this.noAgentsMd = noAgentsMd === true;
|
|
31870
|
-
this.historyPath =
|
|
32179
|
+
this.historyPath = join46(homedir17(), ".mma", "repl-history");
|
|
31871
32180
|
this.loadHistory();
|
|
31872
32181
|
this.rl = process.stdin.isTTY ? new LineEditor({
|
|
31873
32182
|
input: process.stdin,
|
|
@@ -31900,7 +32209,7 @@ class Repl {
|
|
|
31900
32209
|
this.setupListeners();
|
|
31901
32210
|
}
|
|
31902
32211
|
loadHistory() {
|
|
31903
|
-
if (
|
|
32212
|
+
if (existsSync52(this.historyPath)) {
|
|
31904
32213
|
try {
|
|
31905
32214
|
const raw = readFileSync33(this.historyPath, "utf-8");
|
|
31906
32215
|
this.history = raw.split(`
|
|
@@ -31922,13 +32231,7 @@ class Repl {
|
|
|
31922
32231
|
this.completer.registerProvider(new SessionNameProvider(() => this.sessionManager.list().map((s) => s.name)));
|
|
31923
32232
|
}
|
|
31924
32233
|
if (this.skillsModule) {
|
|
31925
|
-
this.completer.registerProvider(new SubcommandProvider("skill", [
|
|
31926
|
-
"list",
|
|
31927
|
-
"loaded",
|
|
31928
|
-
"load",
|
|
31929
|
-
"unload",
|
|
31930
|
-
"search"
|
|
31931
|
-
]));
|
|
32234
|
+
this.completer.registerProvider(new SubcommandProvider("skill", ["list", "loaded", "load", "unload", "search"]));
|
|
31932
32235
|
this.completer.registerProvider(new SkillNameProvider(this.skillsModule));
|
|
31933
32236
|
}
|
|
31934
32237
|
}
|
|
@@ -32221,7 +32524,7 @@ ${t("image.clipboard_empty")}`));
|
|
|
32221
32524
|
}
|
|
32222
32525
|
}
|
|
32223
32526
|
}
|
|
32224
|
-
start() {
|
|
32527
|
+
async start() {
|
|
32225
32528
|
this.running = true;
|
|
32226
32529
|
const info = [];
|
|
32227
32530
|
const row = (label, value) => {
|
|
@@ -32257,17 +32560,21 @@ ${t("image.clipboard_empty")}`));
|
|
|
32257
32560
|
const names = enabledServers.map(([name]) => name).join(", ");
|
|
32258
32561
|
row(t("repl.mcp_label"), `${pc2.white(String(enabledServers.length))} ${pc2.dim(`(${names})`)}`);
|
|
32259
32562
|
}
|
|
32563
|
+
const lspSummary = await this.probeLspBanner();
|
|
32564
|
+
if (lspSummary) {
|
|
32565
|
+
row(t("repl.lsp_label"), lspSummary);
|
|
32566
|
+
}
|
|
32260
32567
|
const cwd = process.cwd();
|
|
32261
32568
|
row(t("repl.work_dir"), pc2.dim(cwd));
|
|
32262
32569
|
if (this.noAgentsMd) {
|
|
32263
32570
|
row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
|
|
32264
32571
|
} else {
|
|
32265
32572
|
const agentsMdCandidates = [
|
|
32266
|
-
|
|
32267
|
-
|
|
32268
|
-
|
|
32573
|
+
join46(this.baseDir, "AGENTS.md"),
|
|
32574
|
+
join46(this.baseDir, ".mma", "AGENTS.md"),
|
|
32575
|
+
join46(this.configDir, "AGENTS.md")
|
|
32269
32576
|
];
|
|
32270
|
-
const foundAgents = agentsMdCandidates.filter((p) =>
|
|
32577
|
+
const foundAgents = agentsMdCandidates.filter((p) => existsSync52(p));
|
|
32271
32578
|
if (foundAgents.length > 0) {
|
|
32272
32579
|
for (const p of foundAgents) {
|
|
32273
32580
|
row(t("repl.agents_label"), pc2.dim(p));
|
|
@@ -32278,7 +32585,7 @@ ${t("image.clipboard_empty")}`));
|
|
|
32278
32585
|
}
|
|
32279
32586
|
const meta = this.sessionManager?.getActiveMeta();
|
|
32280
32587
|
if (meta) {
|
|
32281
|
-
const sessionPath =
|
|
32588
|
+
const sessionPath = join46(this.configDir, "sessions", meta.id);
|
|
32282
32589
|
row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
|
|
32283
32590
|
}
|
|
32284
32591
|
const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
|
|
@@ -32291,6 +32598,25 @@ ${t("image.clipboard_empty")}`));
|
|
|
32291
32598
|
console.log();
|
|
32292
32599
|
this.rl.prompt();
|
|
32293
32600
|
}
|
|
32601
|
+
async probeLspBanner() {
|
|
32602
|
+
const config = this.config.lsp ?? DEFAULT_LSP_CONFIG;
|
|
32603
|
+
try {
|
|
32604
|
+
const summary = await probeLspServers(config, this.baseDir);
|
|
32605
|
+
if (summary.noneApplicable)
|
|
32606
|
+
return null;
|
|
32607
|
+
const parts = [];
|
|
32608
|
+
for (const r of summary.ok) {
|
|
32609
|
+
parts.push(pc2.green(`✓ ${r.language}${pc2.dim(` (${(r.durationMs / 1000).toFixed(1)}s)`)}`));
|
|
32610
|
+
}
|
|
32611
|
+
for (const r of summary.failed) {
|
|
32612
|
+
const reason = r.error?.includes("timeout") ? t("repl.lsp_timeout") : t("repl.lsp_failed");
|
|
32613
|
+
parts.push(pc2.red(`✗ ${r.language}${pc2.dim(` — ${reason}`)}`));
|
|
32614
|
+
}
|
|
32615
|
+
return parts.join(" ");
|
|
32616
|
+
} catch {
|
|
32617
|
+
return pc2.yellow(t("repl.lsp_unknown"));
|
|
32618
|
+
}
|
|
32619
|
+
}
|
|
32294
32620
|
stop() {
|
|
32295
32621
|
this.running = false;
|
|
32296
32622
|
this.saveHistory();
|
|
@@ -32319,8 +32645,8 @@ init_setup();
|
|
|
32319
32645
|
init_config2();
|
|
32320
32646
|
init_i18n();
|
|
32321
32647
|
init_colors();
|
|
32322
|
-
import { existsSync as
|
|
32323
|
-
import { join as
|
|
32648
|
+
import { existsSync as existsSync53, readFileSync as readFileSync34 } from "fs";
|
|
32649
|
+
import { join as join47, dirname as dirname19 } from "path";
|
|
32324
32650
|
import { homedir as homedir18 } from "os";
|
|
32325
32651
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
32326
32652
|
|
|
@@ -32424,12 +32750,9 @@ class UpdaterModule {
|
|
|
32424
32750
|
// src/cli/main.ts
|
|
32425
32751
|
function readVersion5() {
|
|
32426
32752
|
const here = dirname19(fileURLToPath7(import.meta.url));
|
|
32427
|
-
const candidates = [
|
|
32428
|
-
join46(here, "..", "..", "package.json"),
|
|
32429
|
-
join46(here, "..", "package.json")
|
|
32430
|
-
];
|
|
32753
|
+
const candidates = [join47(here, "..", "..", "package.json"), join47(here, "..", "package.json")];
|
|
32431
32754
|
for (const p of candidates) {
|
|
32432
|
-
if (
|
|
32755
|
+
if (existsSync53(p)) {
|
|
32433
32756
|
try {
|
|
32434
32757
|
const raw = JSON.parse(readFileSync34(p, "utf8"));
|
|
32435
32758
|
if (raw.version)
|
|
@@ -32514,15 +32837,15 @@ async function main() {
|
|
|
32514
32837
|
await updater?.waitForIdle();
|
|
32515
32838
|
process.exit(exitCode);
|
|
32516
32839
|
} else {
|
|
32517
|
-
const configPath =
|
|
32518
|
-
if (!
|
|
32840
|
+
const configPath = join47(homedir18(), ".mma", "config.json");
|
|
32841
|
+
if (!existsSync53(configPath)) {
|
|
32519
32842
|
console.log(pc2.yellow(`
|
|
32520
32843
|
` + t("cli.first_run") + `
|
|
32521
32844
|
`));
|
|
32522
32845
|
const answers = await runSetup();
|
|
32523
32846
|
const config2 = loadConfig({
|
|
32524
|
-
configDir:
|
|
32525
|
-
projectConfigPath: projectDir ?
|
|
32847
|
+
configDir: join47(homedir18(), ".mma"),
|
|
32848
|
+
projectConfigPath: projectDir ? join47(projectDir, ".mmrc") : join47(process.cwd(), ".mmrc")
|
|
32526
32849
|
});
|
|
32527
32850
|
config2.provider.type = answers.provider;
|
|
32528
32851
|
config2.provider.baseUrl = answers.apiBase;
|
|
@@ -32576,7 +32899,7 @@ async function main() {
|
|
|
32576
32899
|
} = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
|
|
32577
32900
|
startAutoUpdate(config);
|
|
32578
32901
|
const repl = new Repl(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger, true);
|
|
32579
|
-
repl.start();
|
|
32902
|
+
await repl.start();
|
|
32580
32903
|
}
|
|
32581
32904
|
}
|
|
32582
32905
|
main();
|