micro-models-agent 0.39.1 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +492 -283
- 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
|
}
|
|
@@ -2187,13 +2182,21 @@ var init_defaults = __esm(() => {
|
|
|
2187
2182
|
moe: {
|
|
2188
2183
|
enabled: false
|
|
2189
2184
|
},
|
|
2185
|
+
tools: {
|
|
2186
|
+
defaultTags: ["file", "code"],
|
|
2187
|
+
enableOnDemand: true
|
|
2188
|
+
},
|
|
2190
2189
|
experts: {
|
|
2191
2190
|
code: {
|
|
2192
2191
|
model: "qwen/qwen3.5-9b",
|
|
2193
2192
|
tool_tags: ["file", "code", "shell"],
|
|
2194
2193
|
max_attempts: 3
|
|
2195
2194
|
},
|
|
2196
|
-
research: {
|
|
2195
|
+
research: {
|
|
2196
|
+
model: "qwen/qwen3.5-9b",
|
|
2197
|
+
tool_tags: ["research"],
|
|
2198
|
+
max_attempts: 3
|
|
2199
|
+
},
|
|
2197
2200
|
browser: {
|
|
2198
2201
|
model: "qwen/qwen3.5-9b",
|
|
2199
2202
|
tool_tags: ["browser", "vision"],
|
|
@@ -2513,6 +2516,7 @@ Command: {command}`,
|
|
|
2513
2516
|
"lsp.check_notfound": "Path not found: {path}",
|
|
2514
2517
|
"lsp.check_unsupported": "No LSP server configured for: {path}",
|
|
2515
2518
|
"lsp.check_clean": "No errors or warnings detected ({count} file(s) checked).",
|
|
2519
|
+
"lsp.startup_header": "[Existing project errors (checked at session start) — fix these before continuing]:",
|
|
2516
2520
|
"cli.description": "Micro Models Agent — AI coding agent for small models",
|
|
2517
2521
|
"cli.init": "Run interactive setup wizard",
|
|
2518
2522
|
"cli.config_saved": "Configuration saved to ~/.mma/config.json",
|
|
@@ -2905,7 +2909,13 @@ Use this knowledge to answer the user's question.`,
|
|
|
2905
2909
|
"updater.available": "[updater] Update available: {current} → {latest}. Run `npm install -g micro-models-agent` to upgrade.",
|
|
2906
2910
|
"updater.installing": "[updater] Installing {latest} globally (current: {current})…",
|
|
2907
2911
|
"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`."
|
|
2912
|
+
"updater.install_failed": "[updater] Failed to install {latest}: {error}. Update manually with `npm install -g micro-models-agent`.",
|
|
2913
|
+
"tools.enable_no_tags": 'enable_tools requires at least one tag in the "tags" array.',
|
|
2914
|
+
"tools.enable_no_executor": "Tool executor is not available — cannot enumerate enabled tools.",
|
|
2915
|
+
"tools.enable_already_active": "Tool tags already active: {tags}.",
|
|
2916
|
+
"tools.enable_added": "Enabled tool tags: {tags}. Available tools now: {tools}",
|
|
2917
|
+
"tools.hidden_header": "Additional tools (enable on demand via enable_tools or route to subagent tool_tags):",
|
|
2918
|
+
"tool.friendly.enable_tools": "Enable tools"
|
|
2909
2919
|
};
|
|
2910
2920
|
});
|
|
2911
2921
|
|
|
@@ -3132,6 +3142,7 @@ var init_ru = __esm(() => {
|
|
|
3132
3142
|
"lsp.check_notfound": "Путь не найден: {path}",
|
|
3133
3143
|
"lsp.check_unsupported": "Для файла не настроен LSP-сервер: {path}",
|
|
3134
3144
|
"lsp.check_clean": "Ошибок и предупреждений не обнаружено (проверено файлов: {count}).",
|
|
3145
|
+
"lsp.startup_header": "[Существующие ошибки проекта (проверено при старте сессии) — исправьте их перед продолжением]:",
|
|
3135
3146
|
"cli.description": "Micro Models Agent — ИИ-агент для кодинга на малых моделях",
|
|
3136
3147
|
"cli.init": "Запустить мастер настройки",
|
|
3137
3148
|
"cli.config_saved": "Конфигурация сохранена в ~/.mma/config.json",
|
|
@@ -3526,7 +3537,13 @@ var init_ru = __esm(() => {
|
|
|
3526
3537
|
"updater.available": "[updater] Доступно обновление: {current} → {latest}. Выполните `npm install -g micro-models-agent` для обновления.",
|
|
3527
3538
|
"updater.installing": "[updater] Установка {latest} глобально (текущая: {current})…",
|
|
3528
3539
|
"updater.installed": "[updater] Установлена {latest}. Перезапустите MMA для применения (была {current}).",
|
|
3529
|
-
"updater.install_failed": "[updater] Не удалось установить {latest}: {error}. Обновите вручную: `npm install -g micro-models-agent`."
|
|
3540
|
+
"updater.install_failed": "[updater] Не удалось установить {latest}: {error}. Обновите вручную: `npm install -g micro-models-agent`.",
|
|
3541
|
+
"tools.enable_no_tags": 'enable_tools требует хотя бы один тег в массиве "tags".',
|
|
3542
|
+
"tools.enable_no_executor": "Исполнитель тулов недоступен — невозможно перечислить включённые тулы.",
|
|
3543
|
+
"tools.enable_already_active": "Теги тулов уже активны: {tags}.",
|
|
3544
|
+
"tools.enable_added": "Включены теги тулов: {tags}. Теперь доступны тулы: {tools}",
|
|
3545
|
+
"tools.hidden_header": "Дополнительные тулы (включите по требованию через enable_tools или маршрутизируйте через subagent tool_tags):",
|
|
3546
|
+
"tool.friendly.enable_tools": "Включить тулы"
|
|
3530
3547
|
};
|
|
3531
3548
|
});
|
|
3532
3549
|
|
|
@@ -3876,13 +3893,7 @@ __export(exports_config, {
|
|
|
3876
3893
|
saveConfig: () => saveConfig,
|
|
3877
3894
|
loadConfig: () => loadConfig
|
|
3878
3895
|
});
|
|
3879
|
-
import {
|
|
3880
|
-
existsSync as existsSync4,
|
|
3881
|
-
readFileSync as readFileSync3,
|
|
3882
|
-
unlinkSync,
|
|
3883
|
-
writeFileSync as writeFileSync3,
|
|
3884
|
-
mkdirSync as mkdirSync2
|
|
3885
|
-
} from "fs";
|
|
3896
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
3886
3897
|
import { join as join4, dirname } from "path";
|
|
3887
3898
|
function restoreDangerousPatterns(patterns, defaults) {
|
|
3888
3899
|
const fallback = Array.isArray(defaults) ? defaults : [];
|
|
@@ -4019,6 +4030,12 @@ function loadConfig(options) {
|
|
|
4019
4030
|
}
|
|
4020
4031
|
function validateConfig(config, allToolTags) {
|
|
4021
4032
|
const errors = validateExpertConfig(config, allToolTags);
|
|
4033
|
+
const knownTags = new Set(allToolTags);
|
|
4034
|
+
for (const tag of config.tools?.defaultTags ?? []) {
|
|
4035
|
+
if (!knownTags.has(tag)) {
|
|
4036
|
+
errors.push(`tools.defaultTags references unknown tag "${tag}". Known tags: ${Array.from(knownTags).join(", ")}`);
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4022
4039
|
if (errors.length > 0) {
|
|
4023
4040
|
throw new Error(`Config validation failed:
|
|
4024
4041
|
${errors.join(`
|
|
@@ -5417,8 +5434,10 @@ class ToolRegistry {
|
|
|
5417
5434
|
});
|
|
5418
5435
|
}
|
|
5419
5436
|
getAllForLLM(tags) {
|
|
5420
|
-
const
|
|
5421
|
-
|
|
5437
|
+
const all = this.getAll();
|
|
5438
|
+
const tagSet = new Set(tags ?? []);
|
|
5439
|
+
const selected = tagSet.size === 0 ? all : all.filter((t2) => t2.alwaysOn || t2.tags && t2.tags.some((tag) => tagSet.has(tag)));
|
|
5440
|
+
return selected.map((t2) => ({
|
|
5422
5441
|
name: t2.name,
|
|
5423
5442
|
description: t2.description,
|
|
5424
5443
|
parameters: t2.parameters,
|
|
@@ -7890,7 +7909,10 @@ var init_process_log = __esm(() => {
|
|
|
7890
7909
|
type: "object",
|
|
7891
7910
|
properties: {
|
|
7892
7911
|
id: { type: "string", description: "Process id from bash output or process_list" },
|
|
7893
|
-
tail: {
|
|
7912
|
+
tail: {
|
|
7913
|
+
type: "number",
|
|
7914
|
+
description: `Number of trailing lines to show (default: ${DEFAULT_TAIL}, max 300)`
|
|
7915
|
+
}
|
|
7894
7916
|
},
|
|
7895
7917
|
required: ["id"]
|
|
7896
7918
|
},
|
|
@@ -9341,6 +9363,8 @@ function filterToolsByTags(tools, toolTags) {
|
|
|
9341
9363
|
return tools;
|
|
9342
9364
|
const tagSet = new Set(toolTags);
|
|
9343
9365
|
return tools.filter((t2) => {
|
|
9366
|
+
if (t2.alwaysOn)
|
|
9367
|
+
return true;
|
|
9344
9368
|
if (!t2.tags || t2.tags.length === 0)
|
|
9345
9369
|
return false;
|
|
9346
9370
|
return t2.tags.some((tag) => tagSet.has(tag));
|
|
@@ -10150,7 +10174,10 @@ class StepVerifier {
|
|
|
10150
10174
|
await this.runAsync(`bun run ${scriptName}`, this.baseDir, 60000);
|
|
10151
10175
|
return { passed: true, message: t("verify.script_passed", { script: scriptName }) };
|
|
10152
10176
|
} catch (e) {
|
|
10153
|
-
return {
|
|
10177
|
+
return {
|
|
10178
|
+
passed: false,
|
|
10179
|
+
message: t("verify.script_failed", { script: scriptName, message: e.message })
|
|
10180
|
+
};
|
|
10154
10181
|
}
|
|
10155
10182
|
}
|
|
10156
10183
|
async runTypeCheck() {
|
|
@@ -10167,10 +10194,7 @@ class StepVerifier {
|
|
|
10167
10194
|
}
|
|
10168
10195
|
}
|
|
10169
10196
|
async runTypeCheckForFile(filePath) {
|
|
10170
|
-
const projectRoot = findProjectRoot(filePath, this.baseDir, [
|
|
10171
|
-
"tsconfig.json",
|
|
10172
|
-
"package.json"
|
|
10173
|
-
]);
|
|
10197
|
+
const projectRoot = findProjectRoot(filePath, this.baseDir, ["tsconfig.json", "package.json"]);
|
|
10174
10198
|
const tsconfigPath = join11(projectRoot, "tsconfig.json");
|
|
10175
10199
|
if (!existsSync20(tsconfigPath)) {
|
|
10176
10200
|
return { passed: true, message: "No tsconfig.json found — skipping type check" };
|
|
@@ -10252,7 +10276,7 @@ class StepVerifier {
|
|
|
10252
10276
|
}
|
|
10253
10277
|
async validateSyntax(filePath) {
|
|
10254
10278
|
const ext = extname2(filePath);
|
|
10255
|
-
if (ext === ".ts" || ext === ".tsx") {
|
|
10279
|
+
if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
|
|
10256
10280
|
try {
|
|
10257
10281
|
await this.runAsync(`npx tsc --noEmit --skipLibCheck ${filePath}`, this.baseDir, 1e4);
|
|
10258
10282
|
return true;
|
|
@@ -10267,7 +10291,7 @@ class StepVerifier {
|
|
|
10267
10291
|
return true;
|
|
10268
10292
|
}
|
|
10269
10293
|
}
|
|
10270
|
-
if (ext === ".js" || ext === ".jsx") {
|
|
10294
|
+
if (ext === ".js" || ext === ".jsx" || ext === ".cjs" || ext === ".mjs") {
|
|
10271
10295
|
try {
|
|
10272
10296
|
await this.runAsync(`node --check ${filePath}`, this.baseDir, 5000);
|
|
10273
10297
|
return true;
|
|
@@ -10374,15 +10398,7 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
|
|
|
10374
10398
|
onMeta?.(`✅ Execution complete: ${planResults.results.filter((r) => r.success).length}/${planResults.results.length} succeeded
|
|
10375
10399
|
`);
|
|
10376
10400
|
const verifier = new StepVerifier(baseDir);
|
|
10377
|
-
const knownTags = [
|
|
10378
|
-
"file",
|
|
10379
|
-
"code",
|
|
10380
|
-
"shell",
|
|
10381
|
-
"research",
|
|
10382
|
-
"browser",
|
|
10383
|
-
"vision",
|
|
10384
|
-
"core"
|
|
10385
|
-
];
|
|
10401
|
+
const knownTags = ["file", "code", "shell", "research", "browser", "vision", "core"];
|
|
10386
10402
|
const verification = await verifier.verifyMoEManifest(plan, config, knownTags);
|
|
10387
10403
|
onPhase?.("thinking");
|
|
10388
10404
|
let verifyResult;
|
|
@@ -10662,13 +10678,17 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
10662
10678
|
let suppressRepetitionRetry = false;
|
|
10663
10679
|
let repeatedToolCount = 0;
|
|
10664
10680
|
const MAX_REPEATED_TOOL_CALLS = 2;
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10681
|
+
let allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
|
|
10682
|
+
let boundedToolNames = new Set(allToolsForBudget.filter((t2) => t2.boundedOutput).map((t2) => t2.name));
|
|
10683
|
+
let toolTokenEstimate = allToolsForBudget.reduce((sum, t2) => sum + Math.ceil((t2.description.length + JSON.stringify(t2.parameters).length) / 4), 0);
|
|
10668
10684
|
contextManager.setToolTokens(toolTokenEstimate);
|
|
10669
10685
|
while (iteration < config.maxToolIterations && !this.shutdownRequested) {
|
|
10670
10686
|
iteration++;
|
|
10671
10687
|
contextManager.noteIteration();
|
|
10688
|
+
allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
|
|
10689
|
+
boundedToolNames = new Set(allToolsForBudget.filter((t2) => t2.boundedOutput).map((t2) => t2.name));
|
|
10690
|
+
toolTokenEstimate = allToolsForBudget.reduce((sum, t2) => sum + Math.ceil((t2.description.length + JSON.stringify(t2.parameters).length) / 4), 0);
|
|
10691
|
+
contextManager.setToolTokens(toolTokenEstimate);
|
|
10672
10692
|
pluginManager.runOnBeforeThink({
|
|
10673
10693
|
iteration,
|
|
10674
10694
|
logger,
|
|
@@ -11256,9 +11276,7 @@ class FactExtractor {
|
|
|
11256
11276
|
new RegExp(`Deleted ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
|
|
11257
11277
|
new RegExp(`(?:Удалён|Файл удалён):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi")
|
|
11258
11278
|
];
|
|
11259
|
-
const readPatterns = [
|
|
11260
|
-
new RegExp(`── (${DRIVE}[\\w./\\\\-]+\\.[a-z]+) \\(`, "gi")
|
|
11261
|
-
];
|
|
11279
|
+
const readPatterns = [new RegExp(`── (${DRIVE}[\\w./\\\\-]+\\.[a-z]+) \\(`, "gi")];
|
|
11262
11280
|
const newFiles = [];
|
|
11263
11281
|
const newDeleted = [];
|
|
11264
11282
|
const newDecisions = [];
|
|
@@ -11621,11 +11639,7 @@ ${lines.join(`
|
|
|
11621
11639
|
const text = getMessageText(m.content);
|
|
11622
11640
|
return !text.startsWith("<system-summary>");
|
|
11623
11641
|
});
|
|
11624
|
-
this.messages = [
|
|
11625
|
-
...firstSystem ? [firstSystem] : [],
|
|
11626
|
-
summary,
|
|
11627
|
-
...freshRecent
|
|
11628
|
-
];
|
|
11642
|
+
this.messages = [...firstSystem ? [firstSystem] : [], summary, ...freshRecent];
|
|
11629
11643
|
this.iterationsSinceCompaction = 0;
|
|
11630
11644
|
if (this.onCompact) {
|
|
11631
11645
|
this.onCompact(summary);
|
|
@@ -12319,7 +12333,11 @@ class Updater {
|
|
|
12319
12333
|
signal: AbortSignal.timeout(5000)
|
|
12320
12334
|
});
|
|
12321
12335
|
if (!response.ok) {
|
|
12322
|
-
return {
|
|
12336
|
+
return {
|
|
12337
|
+
updateAvailable: false,
|
|
12338
|
+
current: this.currentVersion,
|
|
12339
|
+
error: `HTTP ${response.status}`
|
|
12340
|
+
};
|
|
12323
12341
|
}
|
|
12324
12342
|
const data = await response.json();
|
|
12325
12343
|
const latest = data["dist-tags"]?.latest;
|
|
@@ -12643,7 +12661,7 @@ var init_subagent = __esm(() => {
|
|
|
12643
12661
|
};
|
|
12644
12662
|
}
|
|
12645
12663
|
if (toolTags && toolTags.length > 0) {
|
|
12646
|
-
const matched = ctx.toolExecutor.
|
|
12664
|
+
const matched = ctx.toolExecutor.getRegistry().getByTags(toolTags);
|
|
12647
12665
|
if (matched.length === 0) {
|
|
12648
12666
|
return {
|
|
12649
12667
|
success: false,
|
|
@@ -12992,15 +13010,7 @@ function isUrlAllowed(url, securityConfig) {
|
|
|
12992
13010
|
function sanitizeUrl(url) {
|
|
12993
13011
|
try {
|
|
12994
13012
|
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
|
-
];
|
|
13013
|
+
const sensitiveKeys = ["api_key", "token", "password", "secret", "access_token", "auth", "key"];
|
|
13004
13014
|
const sanitizedParams = new URLSearchParams(urlObj.search);
|
|
13005
13015
|
for (const key of sensitiveKeys) {
|
|
13006
13016
|
if (sanitizedParams.has(key)) {
|
|
@@ -14575,8 +14585,11 @@ var init_recall = __esm(() => {
|
|
|
14575
14585
|
if (results2.length === 0) {
|
|
14576
14586
|
return { success: true, output: t("tool.recall.empty", { query }) };
|
|
14577
14587
|
}
|
|
14578
|
-
return {
|
|
14579
|
-
|
|
14588
|
+
return {
|
|
14589
|
+
success: true,
|
|
14590
|
+
output: t("tool.recall.search_results", { category, results: results2.join(`
|
|
14591
|
+
`) })
|
|
14592
|
+
};
|
|
14580
14593
|
}
|
|
14581
14594
|
const results = store.search(query);
|
|
14582
14595
|
if (results.length === 0) {
|
|
@@ -14584,7 +14597,10 @@ var init_recall = __esm(() => {
|
|
|
14584
14597
|
}
|
|
14585
14598
|
const formatted = results.map((r) => `[${r.file}] ${r.match}`).join(`
|
|
14586
14599
|
`);
|
|
14587
|
-
return {
|
|
14600
|
+
return {
|
|
14601
|
+
success: true,
|
|
14602
|
+
output: t("tool.recall.search_results", { category: "all", results: formatted })
|
|
14603
|
+
};
|
|
14588
14604
|
} catch (err) {
|
|
14589
14605
|
return { success: true, output: t("tool.memory_error", { error: String(err) }) };
|
|
14590
14606
|
}
|
|
@@ -15006,13 +15022,7 @@ function extractInteractiveElements(html, maxElements = 30) {
|
|
|
15006
15022
|
if (tag === "input" && attrs["type"] === "hidden")
|
|
15007
15023
|
continue;
|
|
15008
15024
|
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;
|
|
15025
|
+
const isInteractive = ["a", "button", "input", "textarea", "select"].includes(tag) || attrs["role"] !== undefined;
|
|
15016
15026
|
if (!isInteractive)
|
|
15017
15027
|
continue;
|
|
15018
15028
|
if (tag === "a" && !attrs["href"])
|
|
@@ -15585,7 +15595,18 @@ function createBrowserTool() {
|
|
|
15585
15595
|
properties: {
|
|
15586
15596
|
action: {
|
|
15587
15597
|
type: "string",
|
|
15588
|
-
enum: [
|
|
15598
|
+
enum: [
|
|
15599
|
+
"open",
|
|
15600
|
+
"click",
|
|
15601
|
+
"type",
|
|
15602
|
+
"scroll",
|
|
15603
|
+
"back",
|
|
15604
|
+
"forward",
|
|
15605
|
+
"screenshot",
|
|
15606
|
+
"snapshot",
|
|
15607
|
+
"close",
|
|
15608
|
+
"wait"
|
|
15609
|
+
],
|
|
15589
15610
|
description: "Browser action to perform"
|
|
15590
15611
|
},
|
|
15591
15612
|
url: {
|
|
@@ -15678,7 +15699,9 @@ async function readClipboardFallback() {
|
|
|
15678
15699
|
const tmpPath = join22(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
|
|
15679
15700
|
try {
|
|
15680
15701
|
if (platform5() === "linux") {
|
|
15681
|
-
execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, {
|
|
15702
|
+
execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, {
|
|
15703
|
+
timeout: 5000
|
|
15704
|
+
});
|
|
15682
15705
|
} else {
|
|
15683
15706
|
return null;
|
|
15684
15707
|
}
|
|
@@ -15841,8 +15864,63 @@ var init_attach_image = __esm(() => {
|
|
|
15841
15864
|
};
|
|
15842
15865
|
});
|
|
15843
15866
|
|
|
15867
|
+
// src/tools/enable-tools.ts
|
|
15868
|
+
var enableToolsTool;
|
|
15869
|
+
var init_enable_tools = __esm(() => {
|
|
15870
|
+
init_i18n();
|
|
15871
|
+
enableToolsTool = {
|
|
15872
|
+
name: "enable_tools",
|
|
15873
|
+
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.",
|
|
15874
|
+
alwaysOn: true,
|
|
15875
|
+
parameters: {
|
|
15876
|
+
type: "object",
|
|
15877
|
+
properties: {
|
|
15878
|
+
tags: {
|
|
15879
|
+
type: "array",
|
|
15880
|
+
items: { type: "string" },
|
|
15881
|
+
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).'
|
|
15882
|
+
}
|
|
15883
|
+
},
|
|
15884
|
+
required: ["tags"]
|
|
15885
|
+
},
|
|
15886
|
+
handler: async (ctx, args) => {
|
|
15887
|
+
const requested = Array.isArray(args.tags) ? args.tags.map(String).filter(Boolean) : [];
|
|
15888
|
+
if (requested.length === 0) {
|
|
15889
|
+
return { success: false, output: t("tools.enable_no_tags") };
|
|
15890
|
+
}
|
|
15891
|
+
const active = ctx.activeToolTags ?? [];
|
|
15892
|
+
const added = [];
|
|
15893
|
+
for (const tag of requested) {
|
|
15894
|
+
if (!active.includes(tag)) {
|
|
15895
|
+
active.push(tag);
|
|
15896
|
+
added.push(tag);
|
|
15897
|
+
}
|
|
15898
|
+
}
|
|
15899
|
+
if (!ctx.toolExecutor) {
|
|
15900
|
+
return { success: false, output: t("tools.enable_no_executor") };
|
|
15901
|
+
}
|
|
15902
|
+
const nowVisible = ctx.toolExecutor.getToolDefinitions([...active]).map((t2) => t2.name);
|
|
15903
|
+
if (added.length === 0) {
|
|
15904
|
+
return {
|
|
15905
|
+
success: true,
|
|
15906
|
+
output: t("tools.enable_already_active", {
|
|
15907
|
+
tags: requested.join(", ")
|
|
15908
|
+
})
|
|
15909
|
+
};
|
|
15910
|
+
}
|
|
15911
|
+
return {
|
|
15912
|
+
success: true,
|
|
15913
|
+
output: t("tools.enable_added", {
|
|
15914
|
+
tags: added.join(", "),
|
|
15915
|
+
tools: nowVisible.join(", ")
|
|
15916
|
+
})
|
|
15917
|
+
};
|
|
15918
|
+
}
|
|
15919
|
+
};
|
|
15920
|
+
});
|
|
15921
|
+
|
|
15844
15922
|
// src/tools/index.ts
|
|
15845
|
-
function registerAllTools(registry2, skillsModule) {
|
|
15923
|
+
function registerAllTools(registry2, skillsModule, opts) {
|
|
15846
15924
|
const tools = [
|
|
15847
15925
|
readFileTool,
|
|
15848
15926
|
writeFileTool,
|
|
@@ -15869,6 +15947,9 @@ function registerAllTools(registry2, skillsModule) {
|
|
|
15869
15947
|
searchHistoryTool,
|
|
15870
15948
|
attachImageTool
|
|
15871
15949
|
];
|
|
15950
|
+
if (opts?.enableOnDemand !== false) {
|
|
15951
|
+
tools.push(enableToolsTool);
|
|
15952
|
+
}
|
|
15872
15953
|
if (skillsModule) {
|
|
15873
15954
|
tools.push(createLoadSkillTool(skillsModule));
|
|
15874
15955
|
}
|
|
@@ -15906,6 +15987,42 @@ var init_tools = __esm(() => {
|
|
|
15906
15987
|
init_recall();
|
|
15907
15988
|
init_browser();
|
|
15908
15989
|
init_attach_image();
|
|
15990
|
+
init_enable_tools();
|
|
15991
|
+
});
|
|
15992
|
+
|
|
15993
|
+
// src/tools/hidden-tools-block.ts
|
|
15994
|
+
function buildHiddenToolsBlock(allTools, activeTags) {
|
|
15995
|
+
if (!allTools.length)
|
|
15996
|
+
return "";
|
|
15997
|
+
const activeSet = new Set(activeTags);
|
|
15998
|
+
const visible = new Set;
|
|
15999
|
+
for (const tool of allTools) {
|
|
16000
|
+
if (tool.alwaysOn || tool.tags && tool.tags.some((tag) => activeSet.has(tag))) {
|
|
16001
|
+
visible.add(tool.name);
|
|
16002
|
+
}
|
|
16003
|
+
}
|
|
16004
|
+
const hidden = allTools.filter((tool) => !visible.has(tool.name));
|
|
16005
|
+
if (hidden.length === 0)
|
|
16006
|
+
return "";
|
|
16007
|
+
const byTag = new Map;
|
|
16008
|
+
for (const tool of hidden) {
|
|
16009
|
+
const tags = tool.tags && tool.tags.length > 0 ? tool.tags : ["other"];
|
|
16010
|
+
for (const tag of tags) {
|
|
16011
|
+
if (!byTag.has(tag))
|
|
16012
|
+
byTag.set(tag, []);
|
|
16013
|
+
byTag.get(tag).push(tool);
|
|
16014
|
+
}
|
|
16015
|
+
}
|
|
16016
|
+
const lines = [t("tools.hidden_header")];
|
|
16017
|
+
for (const [tag, tools] of [...byTag.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
16018
|
+
const names = [...new Set(tools.map((tool) => tool.name))].sort().join(", ");
|
|
16019
|
+
lines.push(`- [${tag}] ${names}`);
|
|
16020
|
+
}
|
|
16021
|
+
return lines.join(`
|
|
16022
|
+
`);
|
|
16023
|
+
}
|
|
16024
|
+
var init_hidden_tools_block = __esm(() => {
|
|
16025
|
+
init_i18n();
|
|
15909
16026
|
});
|
|
15910
16027
|
|
|
15911
16028
|
// src/modules/registry.ts
|
|
@@ -16088,7 +16205,7 @@ class LintOnWritePlugin {
|
|
|
16088
16205
|
await this.runProjectTypeCheck(fullPath, ctx.baseDir, result);
|
|
16089
16206
|
}
|
|
16090
16207
|
async checkSyntax(filePath, ext, baseDir) {
|
|
16091
|
-
if (ext === ".ts" || ext === ".tsx") {
|
|
16208
|
+
if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
|
|
16092
16209
|
let content = "";
|
|
16093
16210
|
try {
|
|
16094
16211
|
content = readFileSync15(filePath, "utf-8");
|
|
@@ -16115,7 +16232,7 @@ class LintOnWritePlugin {
|
|
|
16115
16232
|
return firstError.trim();
|
|
16116
16233
|
}
|
|
16117
16234
|
}
|
|
16118
|
-
if (ext === ".js" || ext === ".jsx") {
|
|
16235
|
+
if (ext === ".js" || ext === ".jsx" || ext === ".cjs" || ext === ".mjs") {
|
|
16119
16236
|
try {
|
|
16120
16237
|
await runAsync(`node --check "${filePath}"`, baseDir, 5000);
|
|
16121
16238
|
return null;
|
|
@@ -16150,10 +16267,7 @@ class LintOnWritePlugin {
|
|
|
16150
16267
|
}
|
|
16151
16268
|
}
|
|
16152
16269
|
async runProjectTypeCheck(filePath, baseDir, result) {
|
|
16153
|
-
const projectRoot = findProjectRoot(filePath, baseDir, [
|
|
16154
|
-
"tsconfig.json",
|
|
16155
|
-
"package.json"
|
|
16156
|
-
]);
|
|
16270
|
+
const projectRoot = findProjectRoot(filePath, baseDir, ["tsconfig.json", "package.json"]);
|
|
16157
16271
|
const tsconfigPath = join23(projectRoot, "tsconfig.json");
|
|
16158
16272
|
if (!existsSync29(tsconfigPath)) {
|
|
16159
16273
|
return;
|
|
@@ -16912,6 +17026,7 @@ function createPlanToolDefinitions(deps) {
|
|
|
16912
17026
|
return [
|
|
16913
17027
|
{
|
|
16914
17028
|
name: "plan",
|
|
17029
|
+
alwaysOn: true,
|
|
16915
17030
|
description: `Create, update, show, abort, list, switch, or re-plan multi-step plans.
|
|
16916
17031
|
|
|
16917
17032
|
Actions:
|
|
@@ -16936,15 +17051,7 @@ Write CONCRETE steps with exact file paths and commands:
|
|
|
16936
17051
|
properties: {
|
|
16937
17052
|
action: {
|
|
16938
17053
|
type: "string",
|
|
16939
|
-
enum: [
|
|
16940
|
-
"create",
|
|
16941
|
-
"update",
|
|
16942
|
-
"show",
|
|
16943
|
-
"abort",
|
|
16944
|
-
"list",
|
|
16945
|
-
"switch",
|
|
16946
|
-
"re-plan"
|
|
16947
|
-
]
|
|
17054
|
+
enum: ["create", "update", "show", "abort", "list", "switch", "re-plan"]
|
|
16948
17055
|
},
|
|
16949
17056
|
title: { type: "string" },
|
|
16950
17057
|
steps: { type: "array", items: { type: "string" } },
|
|
@@ -17237,6 +17344,7 @@ ${progress}`,
|
|
|
17237
17344
|
},
|
|
17238
17345
|
{
|
|
17239
17346
|
name: "todo",
|
|
17347
|
+
alwaysOn: true,
|
|
17240
17348
|
description: "Manage sub-tasks within current plan step. Use to break down complex steps into smaller tasks.",
|
|
17241
17349
|
parameters: {
|
|
17242
17350
|
type: "object",
|
|
@@ -17332,6 +17440,7 @@ ${lines.join(`
|
|
|
17332
17440
|
},
|
|
17333
17441
|
{
|
|
17334
17442
|
name: "verify",
|
|
17443
|
+
alwaysOn: true,
|
|
17335
17444
|
description: "Run verification for the current step. Checks files mentioned in the step description.",
|
|
17336
17445
|
parameters: {
|
|
17337
17446
|
type: "object",
|
|
@@ -17943,13 +18052,7 @@ var init_module = __esm(() => {
|
|
|
17943
18052
|
});
|
|
17944
18053
|
|
|
17945
18054
|
// 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";
|
|
18055
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync11, existsSync as existsSync34, readdirSync as readdirSync11, unlinkSync as unlinkSync4 } from "fs";
|
|
17953
18056
|
import { join as join27 } from "path";
|
|
17954
18057
|
import { homedir as homedir8 } from "os";
|
|
17955
18058
|
|
|
@@ -19051,8 +19154,12 @@ class LspClient {
|
|
|
19051
19154
|
const map = {
|
|
19052
19155
|
ts: "typescript",
|
|
19053
19156
|
tsx: "typescriptreact",
|
|
19157
|
+
mts: "typescript",
|
|
19158
|
+
cts: "typescript",
|
|
19054
19159
|
js: "javascript",
|
|
19055
19160
|
jsx: "javascriptreact",
|
|
19161
|
+
mjs: "javascript",
|
|
19162
|
+
cjs: "javascript",
|
|
19056
19163
|
py: "python",
|
|
19057
19164
|
go: "go",
|
|
19058
19165
|
rs: "rust",
|
|
@@ -19218,6 +19325,7 @@ ${items}`;
|
|
|
19218
19325
|
name: "lsp_check",
|
|
19219
19326
|
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
19327
|
tags: ["code", "check"],
|
|
19328
|
+
alwaysOn: true,
|
|
19221
19329
|
boundedOutput: true,
|
|
19222
19330
|
timeoutMs: 90000,
|
|
19223
19331
|
parameters: {
|
|
@@ -19345,9 +19453,133 @@ var init_lsp = __esm(() => {
|
|
|
19345
19453
|
init_config();
|
|
19346
19454
|
});
|
|
19347
19455
|
|
|
19456
|
+
// src/modules/lsp/startup-check.ts
|
|
19457
|
+
import { existsSync as existsSync39 } from "fs";
|
|
19458
|
+
import { join as join31 } from "path";
|
|
19459
|
+
import { spawn as spawn7 } from "child_process";
|
|
19460
|
+
async function runStartupHealthCheck(config, baseDir, deps = {}) {
|
|
19461
|
+
if (!config.enabled)
|
|
19462
|
+
return null;
|
|
19463
|
+
try {
|
|
19464
|
+
const result = await Promise.race([
|
|
19465
|
+
runCheck(config, baseDir, deps),
|
|
19466
|
+
new Promise((resolve23) => setTimeout(() => resolve23(null), STARTUP_CHECK_TIMEOUT_MS))
|
|
19467
|
+
]);
|
|
19468
|
+
if (!result || result.lines.length === 0)
|
|
19469
|
+
return null;
|
|
19470
|
+
const content = `${t("lsp.startup_header")}
|
|
19471
|
+
${result.lines.join(`
|
|
19472
|
+
`)}`;
|
|
19473
|
+
return {
|
|
19474
|
+
content,
|
|
19475
|
+
priority: "high",
|
|
19476
|
+
essential: false,
|
|
19477
|
+
estimatedTokens: Math.ceil(content.length / 4)
|
|
19478
|
+
};
|
|
19479
|
+
} catch {
|
|
19480
|
+
return null;
|
|
19481
|
+
}
|
|
19482
|
+
}
|
|
19483
|
+
async function runCheck(config, baseDir, deps) {
|
|
19484
|
+
const projectRoot = findProjectRoot(baseDir, baseDir, ["tsconfig.json", "package.json"]);
|
|
19485
|
+
if (existsSync39(join31(projectRoot, "tsconfig.json"))) {
|
|
19486
|
+
const runTsc = deps.runTsc ?? runTscDefault;
|
|
19487
|
+
const errors = await runTsc(projectRoot, STARTUP_CHECK_TIMEOUT_MS);
|
|
19488
|
+
if (errors.length === 0)
|
|
19489
|
+
return null;
|
|
19490
|
+
return { lines: errors.slice(0, STARTUP_CHECK_ERROR_CAP) };
|
|
19491
|
+
}
|
|
19492
|
+
const client = deps.client ?? new LspClient;
|
|
19493
|
+
const files = await collectCheckFiles(baseDir, config);
|
|
19494
|
+
const lines = [];
|
|
19495
|
+
let checked = 0;
|
|
19496
|
+
for (const file of files.slice(0, STARTUP_CHECK_FILE_CAP)) {
|
|
19497
|
+
const serverConfig = getServerForFile(file, config);
|
|
19498
|
+
if (!serverConfig)
|
|
19499
|
+
continue;
|
|
19500
|
+
const fileRoot = findProjectRoot(file, baseDir, serverConfig.workspaceMarkers ?? []);
|
|
19501
|
+
try {
|
|
19502
|
+
const diags = await client.checkFile(file, baseDir, serverConfig, fileRoot);
|
|
19503
|
+
checked++;
|
|
19504
|
+
for (const d of diags) {
|
|
19505
|
+
if (d.severity === 1) {
|
|
19506
|
+
lines.push(formatStartupError(file, baseDir, d));
|
|
19507
|
+
}
|
|
19508
|
+
}
|
|
19509
|
+
} catch {}
|
|
19510
|
+
}
|
|
19511
|
+
if (checked === 0 || lines.length === 0)
|
|
19512
|
+
return null;
|
|
19513
|
+
return { lines: lines.slice(0, STARTUP_CHECK_ERROR_CAP) };
|
|
19514
|
+
}
|
|
19515
|
+
async function runTscDefault(projectRoot, timeoutMs) {
|
|
19516
|
+
return new Promise((resolve23) => {
|
|
19517
|
+
const child = spawn7("npx", ["tsc", "--noEmit", "--skipLibCheck"], {
|
|
19518
|
+
cwd: projectRoot,
|
|
19519
|
+
shell: true,
|
|
19520
|
+
windowsHide: true,
|
|
19521
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
19522
|
+
});
|
|
19523
|
+
let out = "";
|
|
19524
|
+
child.stdout?.on("data", (d) => {
|
|
19525
|
+
out += d.toString();
|
|
19526
|
+
});
|
|
19527
|
+
child.stderr?.on("data", (d) => {
|
|
19528
|
+
out += d.toString();
|
|
19529
|
+
});
|
|
19530
|
+
const timer = setTimeout(() => {
|
|
19531
|
+
child.kill();
|
|
19532
|
+
resolve23([]);
|
|
19533
|
+
}, timeoutMs);
|
|
19534
|
+
child.on("error", () => {
|
|
19535
|
+
clearTimeout(timer);
|
|
19536
|
+
resolve23([]);
|
|
19537
|
+
});
|
|
19538
|
+
child.on("close", () => {
|
|
19539
|
+
clearTimeout(timer);
|
|
19540
|
+
resolve23(parseTscErrors(out));
|
|
19541
|
+
});
|
|
19542
|
+
});
|
|
19543
|
+
}
|
|
19544
|
+
function parseTscErrors(output) {
|
|
19545
|
+
const lines = [];
|
|
19546
|
+
for (const raw of output.split(`
|
|
19547
|
+
`)) {
|
|
19548
|
+
const line = raw.replace(/^[a-zA-Z]:/, "").trim();
|
|
19549
|
+
if (line.includes("error TS"))
|
|
19550
|
+
lines.push(line);
|
|
19551
|
+
}
|
|
19552
|
+
return dedupe(lines);
|
|
19553
|
+
}
|
|
19554
|
+
function formatStartupError(file, baseDir, d) {
|
|
19555
|
+
const rel = file.replace(baseDir.replace(/[\\/]$/, ""), "").replace(/^[\\/]/, "");
|
|
19556
|
+
const line = d.range.start.line + 1;
|
|
19557
|
+
const col = d.range.start.character + 1;
|
|
19558
|
+
return ` ${rel || file}(${line},${col}): error: ${d.message}`;
|
|
19559
|
+
}
|
|
19560
|
+
function dedupe(lines) {
|
|
19561
|
+
const seen = new Set;
|
|
19562
|
+
const out = [];
|
|
19563
|
+
for (const line of lines) {
|
|
19564
|
+
if (!seen.has(line)) {
|
|
19565
|
+
seen.add(line);
|
|
19566
|
+
out.push(line);
|
|
19567
|
+
}
|
|
19568
|
+
}
|
|
19569
|
+
return out;
|
|
19570
|
+
}
|
|
19571
|
+
var STARTUP_CHECK_FILE_CAP = 5, STARTUP_CHECK_TIMEOUT_MS = 60000, STARTUP_CHECK_ERROR_CAP = 20;
|
|
19572
|
+
var init_startup_check = __esm(() => {
|
|
19573
|
+
init_i18n();
|
|
19574
|
+
init_client2();
|
|
19575
|
+
init_check_tool();
|
|
19576
|
+
init_config();
|
|
19577
|
+
init_project_root();
|
|
19578
|
+
});
|
|
19579
|
+
|
|
19348
19580
|
// src/modules/indexer/walker.ts
|
|
19349
|
-
import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as
|
|
19350
|
-
import { join as
|
|
19581
|
+
import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync40, watch } from "fs";
|
|
19582
|
+
import { join as join32, relative as relative3, extname as extname5 } from "path";
|
|
19351
19583
|
|
|
19352
19584
|
class Indexer {
|
|
19353
19585
|
baseDir;
|
|
@@ -19374,7 +19606,7 @@ class Indexer {
|
|
|
19374
19606
|
let totalSize = 0;
|
|
19375
19607
|
let count = 0;
|
|
19376
19608
|
const walkDir2 = (dir) => {
|
|
19377
|
-
if (!
|
|
19609
|
+
if (!existsSync40(dir))
|
|
19378
19610
|
return;
|
|
19379
19611
|
let entries;
|
|
19380
19612
|
try {
|
|
@@ -19385,7 +19617,7 @@ class Indexer {
|
|
|
19385
19617
|
for (const entry of entries) {
|
|
19386
19618
|
if (count >= this.MAX_FILES)
|
|
19387
19619
|
return;
|
|
19388
|
-
const fullPath =
|
|
19620
|
+
const fullPath = join32(dir, entry);
|
|
19389
19621
|
const relPath = relative3(this.baseDir, fullPath);
|
|
19390
19622
|
const stat2 = statSync7(fullPath);
|
|
19391
19623
|
if (stat2.isDirectory()) {
|
|
@@ -19448,19 +19680,19 @@ var init_walker = __esm(() => {
|
|
|
19448
19680
|
});
|
|
19449
19681
|
|
|
19450
19682
|
// src/modules/indexer/cache.ts
|
|
19451
|
-
import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as
|
|
19452
|
-
import { join as
|
|
19683
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync41, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
|
|
19684
|
+
import { join as join33 } from "path";
|
|
19453
19685
|
|
|
19454
19686
|
class IndexCache {
|
|
19455
19687
|
cachePath;
|
|
19456
19688
|
cache = null;
|
|
19457
19689
|
constructor(cacheDir) {
|
|
19458
|
-
this.cachePath =
|
|
19690
|
+
this.cachePath = join33(cacheDir, "index-cache.json");
|
|
19459
19691
|
}
|
|
19460
19692
|
load() {
|
|
19461
19693
|
if (this.cache)
|
|
19462
19694
|
return this.cache;
|
|
19463
|
-
if (!
|
|
19695
|
+
if (!existsSync41(this.cachePath))
|
|
19464
19696
|
return null;
|
|
19465
19697
|
try {
|
|
19466
19698
|
this.cache = JSON.parse(readFileSync23(this.cachePath, "utf-8"));
|
|
@@ -19471,14 +19703,14 @@ class IndexCache {
|
|
|
19471
19703
|
}
|
|
19472
19704
|
save(result) {
|
|
19473
19705
|
this.cache = result;
|
|
19474
|
-
const dir =
|
|
19475
|
-
if (!
|
|
19706
|
+
const dir = join33(this.cachePath, "..");
|
|
19707
|
+
if (!existsSync41(dir))
|
|
19476
19708
|
mkdirSync17(dir, { recursive: true });
|
|
19477
19709
|
writeFileSync14(this.cachePath, JSON.stringify(result), "utf-8");
|
|
19478
19710
|
}
|
|
19479
19711
|
invalidate() {
|
|
19480
19712
|
this.cache = null;
|
|
19481
|
-
if (
|
|
19713
|
+
if (existsSync41(this.cachePath)) {
|
|
19482
19714
|
try {
|
|
19483
19715
|
rmSync3(this.cachePath);
|
|
19484
19716
|
} catch {}
|
|
@@ -19488,11 +19720,11 @@ class IndexCache {
|
|
|
19488
19720
|
var init_cache = () => {};
|
|
19489
19721
|
|
|
19490
19722
|
// src/modules/indexer/project-profile.ts
|
|
19491
|
-
import { readFileSync as readFileSync24, existsSync as
|
|
19492
|
-
import { join as
|
|
19723
|
+
import { readFileSync as readFileSync24, existsSync as existsSync42 } from "fs";
|
|
19724
|
+
import { join as join34 } from "path";
|
|
19493
19725
|
function detectManifest(baseDir) {
|
|
19494
19726
|
for (const manifest of MANIFEST_ORDER) {
|
|
19495
|
-
if (
|
|
19727
|
+
if (existsSync42(join34(baseDir, manifest)))
|
|
19496
19728
|
return manifest;
|
|
19497
19729
|
}
|
|
19498
19730
|
return null;
|
|
@@ -19509,7 +19741,7 @@ function cleanDependency(entry) {
|
|
|
19509
19741
|
}
|
|
19510
19742
|
function readPackageJson(baseDir) {
|
|
19511
19743
|
try {
|
|
19512
|
-
const raw = JSON.parse(readFileSync24(
|
|
19744
|
+
const raw = JSON.parse(readFileSync24(join34(baseDir, "package.json"), "utf-8"));
|
|
19513
19745
|
if (!raw || typeof raw !== "object")
|
|
19514
19746
|
return null;
|
|
19515
19747
|
const profile = {
|
|
@@ -19533,7 +19765,7 @@ function readPackageJson(baseDir) {
|
|
|
19533
19765
|
}
|
|
19534
19766
|
function readPyproject(baseDir) {
|
|
19535
19767
|
try {
|
|
19536
|
-
const content = readFileSync24(
|
|
19768
|
+
const content = readFileSync24(join34(baseDir, "pyproject.toml"), "utf-8");
|
|
19537
19769
|
const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
|
|
19538
19770
|
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
19539
19771
|
if (nameMatch)
|
|
@@ -19549,7 +19781,7 @@ function readPyproject(baseDir) {
|
|
|
19549
19781
|
}
|
|
19550
19782
|
function readCargo(baseDir) {
|
|
19551
19783
|
try {
|
|
19552
|
-
const content = readFileSync24(
|
|
19784
|
+
const content = readFileSync24(join34(baseDir, "Cargo.toml"), "utf-8");
|
|
19553
19785
|
const profile = { runtime: "rust", deps: [], devDeps: [], scripts: {} };
|
|
19554
19786
|
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
19555
19787
|
if (nameMatch)
|
|
@@ -19573,7 +19805,7 @@ function readCargo(baseDir) {
|
|
|
19573
19805
|
}
|
|
19574
19806
|
function readGoMod(baseDir) {
|
|
19575
19807
|
try {
|
|
19576
|
-
const content = readFileSync24(
|
|
19808
|
+
const content = readFileSync24(join34(baseDir, "go.mod"), "utf-8");
|
|
19577
19809
|
const profile = { runtime: "go", deps: [], devDeps: [], scripts: {} };
|
|
19578
19810
|
const moduleMatch = content.match(/^module\s+(\S+)/m);
|
|
19579
19811
|
if (moduleMatch)
|
|
@@ -19591,7 +19823,7 @@ function readGoMod(baseDir) {
|
|
|
19591
19823
|
}
|
|
19592
19824
|
function readRequirements(baseDir) {
|
|
19593
19825
|
try {
|
|
19594
|
-
const content = readFileSync24(
|
|
19826
|
+
const content = readFileSync24(join34(baseDir, "requirements.txt"), "utf-8");
|
|
19595
19827
|
const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
|
|
19596
19828
|
for (const line of content.split(`
|
|
19597
19829
|
`)) {
|
|
@@ -19819,6 +20051,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
|
|
|
19819
20051
|
createProjectMapTool() {
|
|
19820
20052
|
return {
|
|
19821
20053
|
name: "project_map",
|
|
20054
|
+
alwaysOn: true,
|
|
19822
20055
|
description: t("indexer.project_map_desc"),
|
|
19823
20056
|
parameters: {
|
|
19824
20057
|
type: "object",
|
|
@@ -19859,7 +20092,10 @@ ${stackLine2}` : summary2;
|
|
|
19859
20092
|
return `- ${path}${exports}`;
|
|
19860
20093
|
}).join(`
|
|
19861
20094
|
`);
|
|
19862
|
-
return this.makeResult(t("indexer.find_results", {
|
|
20095
|
+
return this.makeResult(t("indexer.find_results", {
|
|
20096
|
+
count: matches.length,
|
|
20097
|
+
results: lines
|
|
20098
|
+
}));
|
|
19863
20099
|
}
|
|
19864
20100
|
if (!this.index) {
|
|
19865
20101
|
await this.buildIndex();
|
|
@@ -20045,7 +20281,7 @@ var init_mcp = __esm(() => {
|
|
|
20045
20281
|
|
|
20046
20282
|
// src/modules/memory/module.ts
|
|
20047
20283
|
import { homedir as homedir10 } from "os";
|
|
20048
|
-
import { join as
|
|
20284
|
+
import { join as join35 } from "path";
|
|
20049
20285
|
|
|
20050
20286
|
class MemoryModule {
|
|
20051
20287
|
name = "memory";
|
|
@@ -20054,7 +20290,7 @@ class MemoryModule {
|
|
|
20054
20290
|
if (storeOrDir instanceof MemoryStore) {
|
|
20055
20291
|
this.store = storeOrDir;
|
|
20056
20292
|
} else {
|
|
20057
|
-
const dir = storeOrDir ||
|
|
20293
|
+
const dir = storeOrDir || join35(homedir10(), ".mma", "memory");
|
|
20058
20294
|
this.store = new MemoryStore(dir);
|
|
20059
20295
|
}
|
|
20060
20296
|
}
|
|
@@ -20140,17 +20376,14 @@ var init_module8 = __esm(() => {
|
|
|
20140
20376
|
});
|
|
20141
20377
|
|
|
20142
20378
|
// src/core/version.ts
|
|
20143
|
-
import { existsSync as
|
|
20144
|
-
import { join as
|
|
20379
|
+
import { existsSync as existsSync43, readFileSync as readFileSync25 } from "fs";
|
|
20380
|
+
import { join as join36, dirname as dirname13 } from "path";
|
|
20145
20381
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20146
20382
|
function readMmaVersion() {
|
|
20147
20383
|
const here = dirname13(fileURLToPath2(import.meta.url));
|
|
20148
|
-
const candidates = [
|
|
20149
|
-
join35(here, "..", "..", "package.json"),
|
|
20150
|
-
join35(here, "..", "package.json")
|
|
20151
|
-
];
|
|
20384
|
+
const candidates = [join36(here, "..", "..", "package.json"), join36(here, "..", "package.json")];
|
|
20152
20385
|
for (const p of candidates) {
|
|
20153
|
-
if (
|
|
20386
|
+
if (existsSync43(p)) {
|
|
20154
20387
|
try {
|
|
20155
20388
|
const raw = JSON.parse(readFileSync25(p, "utf8"));
|
|
20156
20389
|
if (raw.version)
|
|
@@ -20169,8 +20402,8 @@ __export(exports_bootstrap, {
|
|
|
20169
20402
|
bootstrap: () => bootstrap
|
|
20170
20403
|
});
|
|
20171
20404
|
import { homedir as homedir11 } from "os";
|
|
20172
|
-
import { join as
|
|
20173
|
-
import { existsSync as
|
|
20405
|
+
import { join as join37, resolve as resolve23 } from "path";
|
|
20406
|
+
import { existsSync as existsSync44, readFileSync as readFileSync26, writeFileSync as writeFileSync15 } from "fs";
|
|
20174
20407
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
20175
20408
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
20176
20409
|
const isWin = profileCompressed.toLowerCase().includes("win32");
|
|
@@ -20183,11 +20416,11 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
20183
20416
|
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
20417
|
}
|
|
20185
20418
|
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.`);
|
|
20419
|
+
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
20420
|
if (config.autoPlan) {
|
|
20188
20421
|
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
20422
|
}
|
|
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".`);
|
|
20423
|
+
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
20424
|
const hasMCP = config.mcpServers && Object.values(config.mcpServers).some((s) => s.enabled !== false);
|
|
20192
20425
|
if (hasMCP) {
|
|
20193
20426
|
lines.push(`MCP servers are available — use the named MCP tools (prefixed mcp__) to query external services.`);
|
|
@@ -20196,8 +20429,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
20196
20429
|
`);
|
|
20197
20430
|
}
|
|
20198
20431
|
async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
20199
|
-
const dir = configDir ||
|
|
20200
|
-
const projectConfigPath = projectDir ?
|
|
20432
|
+
const dir = configDir || join37(homedir11(), ".mma");
|
|
20433
|
+
const projectConfigPath = projectDir ? join37(projectDir, ".mmrc") : join37(process.cwd(), ".mmrc");
|
|
20201
20434
|
const config = loadConfig({ configDir: dir, projectConfigPath });
|
|
20202
20435
|
setLocale(config.locale);
|
|
20203
20436
|
try {
|
|
@@ -20207,7 +20440,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20207
20440
|
}
|
|
20208
20441
|
} catch {}
|
|
20209
20442
|
const logger = new Logger(config.logLevel);
|
|
20210
|
-
logger.setLogDir(
|
|
20443
|
+
logger.setLogDir(join37(dir, "logs"));
|
|
20211
20444
|
logger.debug("MMA bootstrap", {
|
|
20212
20445
|
version: config.version,
|
|
20213
20446
|
model: config.model
|
|
@@ -20229,7 +20462,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20229
20462
|
logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
|
|
20230
20463
|
}
|
|
20231
20464
|
}
|
|
20232
|
-
const profile = new UserProfile(
|
|
20465
|
+
const profile = new UserProfile(join37(dir));
|
|
20233
20466
|
profile.load() || profile.collect();
|
|
20234
20467
|
profile.save();
|
|
20235
20468
|
const llmProvider = new OpenAICompatProvider({
|
|
@@ -20241,7 +20474,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20241
20474
|
rateLimits: config.security?.rateLimits
|
|
20242
20475
|
});
|
|
20243
20476
|
const baseDir = projectDir ? resolve23(projectDir) : process.cwd();
|
|
20244
|
-
const projectMapCacheDir =
|
|
20477
|
+
const projectMapCacheDir = join37(baseDir, ".mma");
|
|
20245
20478
|
const indexerModule = new IndexerModule({
|
|
20246
20479
|
baseDir,
|
|
20247
20480
|
cacheDir: projectMapCacheDir
|
|
@@ -20252,14 +20485,16 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20252
20485
|
logger.warn(`Project indexing failed: ${err.message}`);
|
|
20253
20486
|
}
|
|
20254
20487
|
const skillsLoader = new SkillsLoader;
|
|
20255
|
-
const builtinDir =
|
|
20256
|
-
const globalDir =
|
|
20257
|
-
const projectSkillsDir =
|
|
20488
|
+
const builtinDir = join37(import.meta.dirname, "skills", "builtin");
|
|
20489
|
+
const globalDir = join37(homedir11(), ".agents", "skills");
|
|
20490
|
+
const projectSkillsDir = join37(baseDir, ".mma", "skills");
|
|
20258
20491
|
const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
|
|
20259
20492
|
const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
|
|
20260
20493
|
const skillsModule = new SkillsModule(availableSkills, skillsBudget);
|
|
20261
20494
|
const toolRegistry = new ToolRegistry;
|
|
20262
|
-
registerAllTools(toolRegistry, skillsModule
|
|
20495
|
+
registerAllTools(toolRegistry, skillsModule, {
|
|
20496
|
+
enableOnDemand: config.tools?.enableOnDemand
|
|
20497
|
+
});
|
|
20263
20498
|
const pluginManager = new PluginManager;
|
|
20264
20499
|
const systemInfoContent = buildSystemInfo(config, baseDir, profile.compress());
|
|
20265
20500
|
const systemInfoPrompt = {
|
|
@@ -20268,11 +20503,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20268
20503
|
essential: true,
|
|
20269
20504
|
estimatedTokens: Math.ceil(systemInfoContent.length / 4)
|
|
20270
20505
|
};
|
|
20271
|
-
const agentsMdGlobal =
|
|
20272
|
-
if (!
|
|
20506
|
+
const agentsMdGlobal = join37(dir, "AGENTS.md");
|
|
20507
|
+
if (!existsSync44(agentsMdGlobal)) {
|
|
20273
20508
|
writeFileSync15(agentsMdGlobal, "", "utf-8");
|
|
20274
20509
|
}
|
|
20275
|
-
const sessionDir =
|
|
20510
|
+
const sessionDir = join37(dir, "sessions");
|
|
20276
20511
|
const sessionStore = new SessionStore(sessionDir);
|
|
20277
20512
|
sessionStore.init();
|
|
20278
20513
|
const sessionManager = new SessionManager(sessionStore, {
|
|
@@ -20286,6 +20521,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20286
20521
|
sessionManager.create();
|
|
20287
20522
|
}
|
|
20288
20523
|
const tokenCounter = new TokenCounter(config.model);
|
|
20524
|
+
const enableOnDemand = config.tools?.enableOnDemand !== false;
|
|
20525
|
+
const activeToolTags = enableOnDemand ? config.tools?.defaultTags ? [...config.tools.defaultTags] : [] : [];
|
|
20289
20526
|
const contextManager = new ContextManager(config.contextWindow, config.contextBudget, tokenCounter);
|
|
20290
20527
|
const toolCtx = {
|
|
20291
20528
|
config,
|
|
@@ -20293,6 +20530,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20293
20530
|
logger,
|
|
20294
20531
|
exitOnComplete,
|
|
20295
20532
|
contextManager,
|
|
20533
|
+
activeToolTags,
|
|
20296
20534
|
sessionId: sessionManager.getActiveMeta()?.id,
|
|
20297
20535
|
sessionContext: sessionManager.getSessionContext() ?? undefined,
|
|
20298
20536
|
recursionDepth: 0,
|
|
@@ -20339,7 +20577,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20339
20577
|
const mcpModule = new MCPModule(config);
|
|
20340
20578
|
await mcpModule.initialize();
|
|
20341
20579
|
moduleRegistry.register(mcpModule);
|
|
20342
|
-
const memoryStore = new MemoryStore(
|
|
20580
|
+
const memoryStore = new MemoryStore(join37(dir, "memory"));
|
|
20343
20581
|
const memoryModule = new MemoryModule(memoryStore);
|
|
20344
20582
|
moduleRegistry.register(memoryModule);
|
|
20345
20583
|
if (config.browser.enabled) {
|
|
@@ -20358,6 +20596,10 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20358
20596
|
lspPlugin.isBuiltin = true;
|
|
20359
20597
|
pluginManager.register(lspPlugin);
|
|
20360
20598
|
}
|
|
20599
|
+
let startupCheckBlock = null;
|
|
20600
|
+
if (!exitOnComplete && true) {
|
|
20601
|
+
startupCheckBlock = await runStartupHealthCheck(config.lsp ?? DEFAULT_LSP_CONFIG, baseDir);
|
|
20602
|
+
}
|
|
20361
20603
|
const moduleTools = moduleRegistry.collectToolDefinitions();
|
|
20362
20604
|
for (const tool of moduleTools) {
|
|
20363
20605
|
toolRegistry.register(tool);
|
|
@@ -20390,8 +20632,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20390
20632
|
pluginManager.register(plugin);
|
|
20391
20633
|
pluginManager.register(plugin2);
|
|
20392
20634
|
const pluginLoader = new PluginLoader;
|
|
20393
|
-
const globalPluginsDir =
|
|
20394
|
-
const projectPluginsDir =
|
|
20635
|
+
const globalPluginsDir = join37(homedir11(), ".mma", "plugins");
|
|
20636
|
+
const projectPluginsDir = join37(baseDir, ".mma", "plugins");
|
|
20395
20637
|
const mmaVersion = readMmaVersion();
|
|
20396
20638
|
pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger, {
|
|
20397
20639
|
source: "global",
|
|
@@ -20417,12 +20659,12 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20417
20659
|
const skipAgentsMd = noAgentsMd === true;
|
|
20418
20660
|
if (!skipAgentsMd) {
|
|
20419
20661
|
const agentsMdCandidates = [
|
|
20420
|
-
|
|
20421
|
-
|
|
20422
|
-
|
|
20662
|
+
join37(baseDir, "AGENTS.md"),
|
|
20663
|
+
join37(baseDir, ".mma", "AGENTS.md"),
|
|
20664
|
+
join37(dir, "AGENTS.md")
|
|
20423
20665
|
];
|
|
20424
20666
|
for (const p of agentsMdCandidates) {
|
|
20425
|
-
if (
|
|
20667
|
+
if (existsSync44(p)) {
|
|
20426
20668
|
const content = readFileSync26(p, "utf-8").trim();
|
|
20427
20669
|
if (content) {
|
|
20428
20670
|
agentsMdBlocks.push({
|
|
@@ -20440,6 +20682,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20440
20682
|
...moduleRegistry.collectPromptBlocks(["indexer"]),
|
|
20441
20683
|
...agentsMdBlocks
|
|
20442
20684
|
];
|
|
20685
|
+
if (startupCheckBlock)
|
|
20686
|
+
promptBlocks.push(startupCheckBlock);
|
|
20443
20687
|
const agentDeps = {
|
|
20444
20688
|
config,
|
|
20445
20689
|
llmProvider,
|
|
@@ -20449,6 +20693,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20449
20693
|
hallucinationDetector,
|
|
20450
20694
|
logger,
|
|
20451
20695
|
baseDir,
|
|
20696
|
+
toolTags: activeToolTags,
|
|
20452
20697
|
promptBlocks,
|
|
20453
20698
|
getDynamicPromptBlocks: () => {
|
|
20454
20699
|
const blocks = [];
|
|
@@ -20461,6 +20706,15 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20461
20706
|
const mapBlock = indexerModule.getSystemPromptBlock();
|
|
20462
20707
|
if (mapBlock)
|
|
20463
20708
|
blocks.push(mapBlock);
|
|
20709
|
+
const hiddenToolsBlock = buildHiddenToolsBlock(toolRegistry.getAll(), activeToolTags);
|
|
20710
|
+
if (hiddenToolsBlock) {
|
|
20711
|
+
blocks.push({
|
|
20712
|
+
content: hiddenToolsBlock,
|
|
20713
|
+
priority: "low",
|
|
20714
|
+
essential: false,
|
|
20715
|
+
estimatedTokens: Math.ceil(hiddenToolsBlock.length / 4)
|
|
20716
|
+
});
|
|
20717
|
+
}
|
|
20464
20718
|
return blocks;
|
|
20465
20719
|
},
|
|
20466
20720
|
finalAudit: () => execModule.runFinalAudit(),
|
|
@@ -20486,6 +20740,7 @@ var init_bootstrap = __esm(() => {
|
|
|
20486
20740
|
init_app_logger();
|
|
20487
20741
|
init_openai_compat();
|
|
20488
20742
|
init_tools();
|
|
20743
|
+
init_hidden_tools_block();
|
|
20489
20744
|
init_executor();
|
|
20490
20745
|
init_manager2();
|
|
20491
20746
|
init_loader();
|
|
@@ -20500,6 +20755,7 @@ var init_bootstrap = __esm(() => {
|
|
|
20500
20755
|
init_skills();
|
|
20501
20756
|
init_browser2();
|
|
20502
20757
|
init_lsp();
|
|
20758
|
+
init_startup_check();
|
|
20503
20759
|
init_indexer();
|
|
20504
20760
|
init_mcp();
|
|
20505
20761
|
init_module8();
|
|
@@ -21227,18 +21483,8 @@ async function runSetup(externalRl) {
|
|
|
21227
21483
|
t("setup.summary_value")
|
|
21228
21484
|
], [
|
|
21229
21485
|
[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
|
-
],
|
|
21486
|
+
["API Base URL", apiBase, t("setup.context_window"), String(contextWindow)],
|
|
21487
|
+
[t("setup.api_key"), apiKey || "not-needed", t("setup.max_iters"), String(maxIterations)],
|
|
21242
21488
|
[t("setup.ui_lang"), locale, "", ""]
|
|
21243
21489
|
], { maxColumns: 4 });
|
|
21244
21490
|
for (const l of summary)
|
|
@@ -21279,12 +21525,12 @@ __export(exports_manifest, {
|
|
|
21279
21525
|
getCertMark: () => getCertMark,
|
|
21280
21526
|
MANIFEST_PATH: () => MANIFEST_PATH
|
|
21281
21527
|
});
|
|
21282
|
-
import { existsSync as
|
|
21528
|
+
import { existsSync as existsSync45, readFileSync as readFileSync27, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
21283
21529
|
import { homedir as homedir13 } from "os";
|
|
21284
|
-
import { join as
|
|
21530
|
+
import { join as join39 } from "path";
|
|
21285
21531
|
function readManifest(path = MANIFEST_PATH) {
|
|
21286
21532
|
try {
|
|
21287
|
-
if (
|
|
21533
|
+
if (existsSync45(path)) {
|
|
21288
21534
|
const raw = JSON.parse(readFileSync27(path, "utf-8"));
|
|
21289
21535
|
return { version: 1, certifications: raw.certifications ?? [] };
|
|
21290
21536
|
}
|
|
@@ -21292,7 +21538,7 @@ function readManifest(path = MANIFEST_PATH) {
|
|
|
21292
21538
|
return { version: 1, certifications: [] };
|
|
21293
21539
|
}
|
|
21294
21540
|
function saveManifest(m, path = MANIFEST_PATH) {
|
|
21295
|
-
mkdirSync18(
|
|
21541
|
+
mkdirSync18(join39(homedir13(), ".mma"), { recursive: true });
|
|
21296
21542
|
writeFileSync16(path, JSON.stringify(m, null, 2), "utf-8");
|
|
21297
21543
|
}
|
|
21298
21544
|
function upsertCertification(entry, path = MANIFEST_PATH) {
|
|
@@ -21327,7 +21573,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
|
|
|
21327
21573
|
}
|
|
21328
21574
|
var MANIFEST_PATH;
|
|
21329
21575
|
var init_manifest = __esm(() => {
|
|
21330
|
-
MANIFEST_PATH =
|
|
21576
|
+
MANIFEST_PATH = join39(homedir13(), ".mma", "certifications.json");
|
|
21331
21577
|
});
|
|
21332
21578
|
|
|
21333
21579
|
// node_modules/yaml/dist/nodes/identity.js
|
|
@@ -28450,8 +28696,8 @@ var init_scenarios = __esm(() => {
|
|
|
28450
28696
|
});
|
|
28451
28697
|
|
|
28452
28698
|
// src/modules/certification/loader.ts
|
|
28453
|
-
import { existsSync as
|
|
28454
|
-
import { join as
|
|
28699
|
+
import { existsSync as existsSync46, readdirSync as readdirSync15, readFileSync as readFileSync28 } from "fs";
|
|
28700
|
+
import { join as join40 } from "path";
|
|
28455
28701
|
function validateScenario(s) {
|
|
28456
28702
|
const errors2 = [];
|
|
28457
28703
|
const isSkip = s.mode === "skip";
|
|
@@ -28500,12 +28746,12 @@ function loadScenarios(userDir) {
|
|
|
28500
28746
|
else
|
|
28501
28747
|
scenarios.push(s);
|
|
28502
28748
|
}
|
|
28503
|
-
if (userDir &&
|
|
28749
|
+
if (userDir && existsSync46(userDir)) {
|
|
28504
28750
|
for (const file of readdirSync15(userDir)) {
|
|
28505
28751
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
|
|
28506
28752
|
continue;
|
|
28507
28753
|
try {
|
|
28508
|
-
const raw = readFileSync28(
|
|
28754
|
+
const raw = readFileSync28(join40(userDir, file), "utf-8");
|
|
28509
28755
|
const data = $parse(raw);
|
|
28510
28756
|
const parsed = normalizeScenario(data, file);
|
|
28511
28757
|
const errs = validateScenario(parsed);
|
|
@@ -28558,31 +28804,31 @@ var init_loader3 = __esm(() => {
|
|
|
28558
28804
|
});
|
|
28559
28805
|
|
|
28560
28806
|
// src/modules/certification/fact-checker.ts
|
|
28561
|
-
import { existsSync as
|
|
28562
|
-
import { join as
|
|
28807
|
+
import { existsSync as existsSync47, readFileSync as readFileSync29, statSync as statSync8 } from "fs";
|
|
28808
|
+
import { join as join41 } from "path";
|
|
28563
28809
|
function checkSandbox(sandboxDir, checks, exitCode, output) {
|
|
28564
28810
|
const failures = [];
|
|
28565
28811
|
for (const check of checks) {
|
|
28566
|
-
if (!
|
|
28812
|
+
if (!runCheck2(sandboxDir, check, exitCode, output)) {
|
|
28567
28813
|
failures.push(describe(check));
|
|
28568
28814
|
}
|
|
28569
28815
|
}
|
|
28570
28816
|
return { pass: failures.length === 0, failures };
|
|
28571
28817
|
}
|
|
28572
|
-
function
|
|
28818
|
+
function runCheck2(sandboxDir, check, exitCode, output) {
|
|
28573
28819
|
switch (check.type) {
|
|
28574
28820
|
case "exitCode":
|
|
28575
28821
|
return exitCode === (check.code ?? 0);
|
|
28576
28822
|
case "outputContains":
|
|
28577
28823
|
return output.includes(check.text);
|
|
28578
28824
|
case "fileExists":
|
|
28579
|
-
return isFile(
|
|
28825
|
+
return isFile(join41(sandboxDir, check.path));
|
|
28580
28826
|
case "fileNotExists":
|
|
28581
|
-
return !
|
|
28827
|
+
return !existsSync47(join41(sandboxDir, check.path));
|
|
28582
28828
|
case "dirExists":
|
|
28583
|
-
return isDir(
|
|
28829
|
+
return isDir(join41(sandboxDir, check.path));
|
|
28584
28830
|
case "fileContent": {
|
|
28585
|
-
const abs =
|
|
28831
|
+
const abs = join41(sandboxDir, check.path);
|
|
28586
28832
|
if (!isFile(abs))
|
|
28587
28833
|
return false;
|
|
28588
28834
|
const content = readFileSync29(abs, "utf-8");
|
|
@@ -28593,7 +28839,7 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
28593
28839
|
return false;
|
|
28594
28840
|
}
|
|
28595
28841
|
case "fileRegex": {
|
|
28596
|
-
const abs =
|
|
28842
|
+
const abs = join41(sandboxDir, check.path);
|
|
28597
28843
|
if (!isFile(abs))
|
|
28598
28844
|
return false;
|
|
28599
28845
|
return new RegExp(check.pattern).test(readFileSync29(abs, "utf-8"));
|
|
@@ -28604,14 +28850,14 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
28604
28850
|
}
|
|
28605
28851
|
function isFile(p) {
|
|
28606
28852
|
try {
|
|
28607
|
-
return
|
|
28853
|
+
return existsSync47(p) && statSync8(p).isFile();
|
|
28608
28854
|
} catch {
|
|
28609
28855
|
return false;
|
|
28610
28856
|
}
|
|
28611
28857
|
}
|
|
28612
28858
|
function isDir(p) {
|
|
28613
28859
|
try {
|
|
28614
|
-
return
|
|
28860
|
+
return existsSync47(p) && statSync8(p).isDirectory();
|
|
28615
28861
|
} catch {
|
|
28616
28862
|
return false;
|
|
28617
28863
|
}
|
|
@@ -28641,10 +28887,10 @@ function describe(check) {
|
|
|
28641
28887
|
var init_fact_checker = () => {};
|
|
28642
28888
|
|
|
28643
28889
|
// src/modules/certification/runner.ts
|
|
28644
|
-
import { spawn as
|
|
28645
|
-
import { existsSync as
|
|
28890
|
+
import { spawn as spawn8 } from "child_process";
|
|
28891
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
|
|
28646
28892
|
import { platform as platform9 } from "os";
|
|
28647
|
-
import { join as
|
|
28893
|
+
import { join as join42, resolve as resolve24, dirname as dirname14 } from "path";
|
|
28648
28894
|
async function runScenario(scenario, opts) {
|
|
28649
28895
|
if (scenario.mode === "skip") {
|
|
28650
28896
|
return {
|
|
@@ -28663,7 +28909,7 @@ async function runScenario(scenario, opts) {
|
|
|
28663
28909
|
let passed = 0;
|
|
28664
28910
|
let firstError;
|
|
28665
28911
|
for (let i = 1;i <= reps; i++) {
|
|
28666
|
-
const sandbox =
|
|
28912
|
+
const sandbox = join42(opts.sandboxBase, `run-${scenario.id}-${i}`);
|
|
28667
28913
|
let failures = [];
|
|
28668
28914
|
let exitCode = -1;
|
|
28669
28915
|
let output = "";
|
|
@@ -28724,28 +28970,25 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
|
|
|
28724
28970
|
rmSync4(sandbox, { recursive: true, force: true });
|
|
28725
28971
|
mkdirSync19(sandbox, { recursive: true });
|
|
28726
28972
|
for (const f of scenario.fixtures ?? []) {
|
|
28727
|
-
const src =
|
|
28728
|
-
if (!
|
|
28973
|
+
const src = join42(mmaRoot, f.source);
|
|
28974
|
+
if (!existsSync48(src)) {
|
|
28729
28975
|
throw new Error(`fixture missing: ${f.source}`);
|
|
28730
28976
|
}
|
|
28731
|
-
const dest =
|
|
28977
|
+
const dest = join42(sandbox, f.dest);
|
|
28732
28978
|
mkdirSync19(dirname14(dest), { recursive: true });
|
|
28733
28979
|
cpSync2(src, dest);
|
|
28734
28980
|
}
|
|
28735
28981
|
}
|
|
28736
28982
|
function resolveMmaEntry(mmaRoot) {
|
|
28737
|
-
const dev =
|
|
28738
|
-
if (
|
|
28983
|
+
const dev = join42(mmaRoot, "src", "cli", "main.ts");
|
|
28984
|
+
if (existsSync48(dev))
|
|
28739
28985
|
return dev;
|
|
28740
|
-
return
|
|
28986
|
+
return join42(mmaRoot, "dist", "main.js");
|
|
28741
28987
|
}
|
|
28742
28988
|
function findMmaRoot(fromDir) {
|
|
28743
|
-
const candidates = [
|
|
28744
|
-
resolve24(fromDir, "..", "..", ".."),
|
|
28745
|
-
resolve24(fromDir, "..")
|
|
28746
|
-
];
|
|
28989
|
+
const candidates = [resolve24(fromDir, "..", "..", ".."), resolve24(fromDir, "..")];
|
|
28747
28990
|
for (const c of candidates) {
|
|
28748
|
-
if (
|
|
28991
|
+
if (existsSync48(join42(c, "package.json")))
|
|
28749
28992
|
return c;
|
|
28750
28993
|
}
|
|
28751
28994
|
return process.cwd();
|
|
@@ -28755,7 +28998,7 @@ function killTree2(child) {
|
|
|
28755
28998
|
if (!pid)
|
|
28756
28999
|
return;
|
|
28757
29000
|
if (platform9() === "win32") {
|
|
28758
|
-
|
|
29001
|
+
spawn8("taskkill", ["/pid", String(pid), "/T", "/F"], {
|
|
28759
29002
|
windowsHide: true,
|
|
28760
29003
|
stdio: "ignore"
|
|
28761
29004
|
});
|
|
@@ -28770,7 +29013,7 @@ function killTree2(child) {
|
|
|
28770
29013
|
}
|
|
28771
29014
|
}
|
|
28772
29015
|
var defaultRunner2 = (env2, cwd, args, timeoutMs) => new Promise((resolvePromise) => {
|
|
28773
|
-
const child =
|
|
29016
|
+
const child = spawn8(process.execPath, args, {
|
|
28774
29017
|
cwd,
|
|
28775
29018
|
env: env2,
|
|
28776
29019
|
windowsHide: true,
|
|
@@ -28813,13 +29056,13 @@ __export(exports_cli, {
|
|
|
28813
29056
|
});
|
|
28814
29057
|
import { rmSync as rmSync5 } from "fs";
|
|
28815
29058
|
import { homedir as homedir14 } from "os";
|
|
28816
|
-
import { join as
|
|
29059
|
+
import { join as join43, dirname as dirname15 } from "path";
|
|
28817
29060
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
28818
|
-
import { existsSync as
|
|
29061
|
+
import { existsSync as existsSync49, readFileSync as readFileSync30 } from "fs";
|
|
28819
29062
|
function readVersion() {
|
|
28820
|
-
const candidates = [
|
|
29063
|
+
const candidates = [join43(MMA_ROOT, "package.json")];
|
|
28821
29064
|
for (const p of candidates) {
|
|
28822
|
-
if (
|
|
29065
|
+
if (existsSync49(p)) {
|
|
28823
29066
|
try {
|
|
28824
29067
|
const raw = JSON.parse(readFileSync30(p, "utf-8"));
|
|
28825
29068
|
if (raw.version)
|
|
@@ -28857,7 +29100,7 @@ async function certify(opts) {
|
|
|
28857
29100
|
return;
|
|
28858
29101
|
}
|
|
28859
29102
|
console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
|
|
28860
|
-
const sandboxBase =
|
|
29103
|
+
const sandboxBase = join43(process.cwd(), ".mma", "certification");
|
|
28861
29104
|
const results = [];
|
|
28862
29105
|
const total = selected.length;
|
|
28863
29106
|
let idx = 0;
|
|
@@ -28971,7 +29214,7 @@ var init_cli = __esm(() => {
|
|
|
28971
29214
|
init_manifest();
|
|
28972
29215
|
HERE = dirname15(fileURLToPath3(import.meta.url));
|
|
28973
29216
|
MMA_ROOT = findMmaRoot(HERE);
|
|
28974
|
-
USER_SCENARIO_DIR =
|
|
29217
|
+
USER_SCENARIO_DIR = join43(homedir14(), ".mma", "certification", "scenarios");
|
|
28975
29218
|
});
|
|
28976
29219
|
|
|
28977
29220
|
// src/cli/repl-commands.ts
|
|
@@ -28980,18 +29223,15 @@ __export(exports_repl_commands, {
|
|
|
28980
29223
|
registerAllCommands: () => registerAllCommands,
|
|
28981
29224
|
COMMAND_GROUPS: () => COMMAND_GROUPS
|
|
28982
29225
|
});
|
|
28983
|
-
import { join as
|
|
29226
|
+
import { join as join45, dirname as dirname17 } from "path";
|
|
28984
29227
|
import { homedir as homedir16 } from "os";
|
|
28985
|
-
import { existsSync as
|
|
29228
|
+
import { existsSync as existsSync51, readFileSync as readFileSync32 } from "fs";
|
|
28986
29229
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
28987
29230
|
function readVersion3() {
|
|
28988
29231
|
const here = dirname17(fileURLToPath5(import.meta.url));
|
|
28989
|
-
const candidates = [
|
|
28990
|
-
join44(here, "..", "..", "package.json"),
|
|
28991
|
-
join44(here, "..", "package.json")
|
|
28992
|
-
];
|
|
29232
|
+
const candidates = [join45(here, "..", "..", "package.json"), join45(here, "..", "package.json")];
|
|
28993
29233
|
for (const p of candidates) {
|
|
28994
|
-
if (
|
|
29234
|
+
if (existsSync51(p)) {
|
|
28995
29235
|
try {
|
|
28996
29236
|
const raw = JSON.parse(readFileSync32(p, "utf8"));
|
|
28997
29237
|
if (raw.version)
|
|
@@ -29057,7 +29297,7 @@ function registerMmaCommands(ctx) {
|
|
|
29057
29297
|
}
|
|
29058
29298
|
try {
|
|
29059
29299
|
const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
|
|
29060
|
-
const { existsSync:
|
|
29300
|
+
const { existsSync: existsSync52 } = await import("fs");
|
|
29061
29301
|
const { resolve: resolve25 } = await import("path");
|
|
29062
29302
|
let dataUrl;
|
|
29063
29303
|
let label;
|
|
@@ -29077,7 +29317,7 @@ function registerMmaCommands(ctx) {
|
|
|
29077
29317
|
label = source;
|
|
29078
29318
|
} else {
|
|
29079
29319
|
const absPath = resolve25(process.cwd(), source);
|
|
29080
|
-
if (!
|
|
29320
|
+
if (!existsSync52(absPath)) {
|
|
29081
29321
|
console.log(pc2.red(t("image.not_found", { path: source })));
|
|
29082
29322
|
return;
|
|
29083
29323
|
}
|
|
@@ -29156,7 +29396,7 @@ function registerMmaCommands(ctx) {
|
|
|
29156
29396
|
console.log(pc2.yellow(t("repl.wizard_running")));
|
|
29157
29397
|
await ctx.withExclusiveInput(async () => {
|
|
29158
29398
|
const answers = await runSetup(ctx.rl);
|
|
29159
|
-
const configPath =
|
|
29399
|
+
const configPath = join45(homedir16(), ".mma", "config.json");
|
|
29160
29400
|
ctx.config.provider.type = answers.provider;
|
|
29161
29401
|
ctx.config.provider.baseUrl = answers.apiBase;
|
|
29162
29402
|
ctx.config.provider.apiKey = answers.apiKey;
|
|
@@ -29210,7 +29450,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
29210
29450
|
return;
|
|
29211
29451
|
}
|
|
29212
29452
|
ctx.config.provider.type = name;
|
|
29213
|
-
const configPath =
|
|
29453
|
+
const configPath = join45(homedir16(), ".mma", "config.json");
|
|
29214
29454
|
saveConfig(ctx.config, configPath);
|
|
29215
29455
|
await ctx.agent.reconfigure(ctx.config);
|
|
29216
29456
|
console.log(pc2.green(t("repl.provider_set", { name })));
|
|
@@ -29266,7 +29506,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
29266
29506
|
return;
|
|
29267
29507
|
}
|
|
29268
29508
|
ctx.config.model = name;
|
|
29269
|
-
const configPath =
|
|
29509
|
+
const configPath = join45(homedir16(), ".mma", "config.json");
|
|
29270
29510
|
saveConfig(ctx.config, configPath);
|
|
29271
29511
|
await ctx.agent.reconfigure(ctx.config);
|
|
29272
29512
|
console.log(pc2.green(t("repl.model_set", { name })));
|
|
@@ -29291,7 +29531,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
29291
29531
|
return;
|
|
29292
29532
|
}
|
|
29293
29533
|
ctx.config.contextWindow = size;
|
|
29294
|
-
const configPath =
|
|
29534
|
+
const configPath = join45(homedir16(), ".mma", "config.json");
|
|
29295
29535
|
saveConfig(ctx.config, configPath);
|
|
29296
29536
|
await ctx.agent.reconfigure(ctx.config);
|
|
29297
29537
|
console.log(pc2.green(t("cli.context_set", { size })));
|
|
@@ -29310,10 +29550,10 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
29310
29550
|
ctx.agent.shutdown();
|
|
29311
29551
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
|
|
29312
29552
|
const { homedir: homedir17 } = await import("os");
|
|
29313
|
-
const { join:
|
|
29553
|
+
const { join: join46 } = await import("path");
|
|
29314
29554
|
const configDir = ctx.configDir;
|
|
29315
29555
|
const baseDir = ctx.baseDir;
|
|
29316
|
-
const projectConfigPath =
|
|
29556
|
+
const projectConfigPath = join46(baseDir, ".mmrc");
|
|
29317
29557
|
const freshConfig = loadConfig2({ configDir, projectConfigPath });
|
|
29318
29558
|
Object.assign(ctx.config, freshConfig);
|
|
29319
29559
|
const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
|
|
@@ -29649,14 +29889,14 @@ init_bootstrap();
|
|
|
29649
29889
|
init_config2();
|
|
29650
29890
|
init_setup();
|
|
29651
29891
|
init_i18n();
|
|
29652
|
-
import { join as
|
|
29892
|
+
import { join as join44, dirname as dirname16 } from "path";
|
|
29653
29893
|
import { homedir as homedir15 } from "os";
|
|
29654
|
-
import { existsSync as
|
|
29894
|
+
import { existsSync as existsSync50, readFileSync as readFileSync31 } from "fs";
|
|
29655
29895
|
|
|
29656
29896
|
// src/cli/security-commands.ts
|
|
29657
29897
|
init_bootstrap();
|
|
29658
29898
|
init_config2();
|
|
29659
|
-
import { join as
|
|
29899
|
+
import { join as join38 } from "path";
|
|
29660
29900
|
import { homedir as homedir12 } from "os";
|
|
29661
29901
|
|
|
29662
29902
|
// src/modules/security/security-policies.ts
|
|
@@ -29728,18 +29968,7 @@ var STRICT_POLICY = {
|
|
|
29728
29968
|
"-R",
|
|
29729
29969
|
"--no-clobber"
|
|
29730
29970
|
],
|
|
29731
|
-
dangerousOperators: [
|
|
29732
|
-
">",
|
|
29733
|
-
">>",
|
|
29734
|
-
"2>",
|
|
29735
|
-
"2>>",
|
|
29736
|
-
"|",
|
|
29737
|
-
"&&",
|
|
29738
|
-
"||",
|
|
29739
|
-
";",
|
|
29740
|
-
"&",
|
|
29741
|
-
"`"
|
|
29742
|
-
],
|
|
29971
|
+
dangerousOperators: [">", ">>", "2>", "2>>", "|", "&&", "||", ";", "&", "`"],
|
|
29743
29972
|
logCommands: true
|
|
29744
29973
|
},
|
|
29745
29974
|
paths: {
|
|
@@ -29953,12 +30182,7 @@ var BALANCED_POLICY = {
|
|
|
29953
30182
|
auditNotifier: {
|
|
29954
30183
|
enabled: false,
|
|
29955
30184
|
minSeverity: "medium",
|
|
29956
|
-
eventTypes: [
|
|
29957
|
-
"security_block",
|
|
29958
|
-
"bash_command",
|
|
29959
|
-
"file_operation",
|
|
29960
|
-
"network_request"
|
|
29961
|
-
],
|
|
30185
|
+
eventTypes: ["security_block", "bash_command", "file_operation", "network_request"],
|
|
29962
30186
|
maxRetries: 3
|
|
29963
30187
|
}
|
|
29964
30188
|
}
|
|
@@ -30186,7 +30410,7 @@ function createSecurityCommand(program2) {
|
|
|
30186
30410
|
}
|
|
30187
30411
|
});
|
|
30188
30412
|
securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
|
|
30189
|
-
const configPath =
|
|
30413
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30190
30414
|
const { config: appConfig } = await bootstrap();
|
|
30191
30415
|
const validPresets = ["strict", "balanced", "permissive"];
|
|
30192
30416
|
if (!validPresets.includes(preset)) {
|
|
@@ -30201,7 +30425,7 @@ function createSecurityCommand(program2) {
|
|
|
30201
30425
|
console.log(t("cli.security.policy_description", { description: policy.description }));
|
|
30202
30426
|
});
|
|
30203
30427
|
securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
|
|
30204
|
-
const configPath =
|
|
30428
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30205
30429
|
const { config: appConfig } = await bootstrap();
|
|
30206
30430
|
appConfig.security = appConfig.security || {};
|
|
30207
30431
|
appConfig.security.sessionEncryption = {
|
|
@@ -30213,7 +30437,7 @@ function createSecurityCommand(program2) {
|
|
|
30213
30437
|
console.log(t("cli.security.encryption_enabled"));
|
|
30214
30438
|
});
|
|
30215
30439
|
securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
|
|
30216
|
-
const configPath =
|
|
30440
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30217
30441
|
const { config: appConfig } = await bootstrap();
|
|
30218
30442
|
appConfig.security = appConfig.security || {};
|
|
30219
30443
|
appConfig.security.sessionEncryption = {
|
|
@@ -30225,7 +30449,7 @@ function createSecurityCommand(program2) {
|
|
|
30225
30449
|
console.log(t("cli.security.encryption_disabled"));
|
|
30226
30450
|
});
|
|
30227
30451
|
securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
|
|
30228
|
-
const configPath =
|
|
30452
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30229
30453
|
const { config: appConfig } = await bootstrap();
|
|
30230
30454
|
appConfig.security = appConfig.security || {};
|
|
30231
30455
|
appConfig.security.auditNotifier = {
|
|
@@ -30239,7 +30463,7 @@ function createSecurityCommand(program2) {
|
|
|
30239
30463
|
console.log(t("cli.security.audit_enabled"));
|
|
30240
30464
|
});
|
|
30241
30465
|
securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
|
|
30242
|
-
const configPath =
|
|
30466
|
+
const configPath = join38(homedir12(), ".mma", "config.json");
|
|
30243
30467
|
const { config: appConfig } = await bootstrap();
|
|
30244
30468
|
appConfig.security = appConfig.security || {};
|
|
30245
30469
|
appConfig.security.auditNotifier = {
|
|
@@ -30305,12 +30529,9 @@ function createPluginCommand(program2) {
|
|
|
30305
30529
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
30306
30530
|
function readVersion2() {
|
|
30307
30531
|
const here = dirname16(fileURLToPath4(import.meta.url));
|
|
30308
|
-
const candidates = [
|
|
30309
|
-
join43(here, "..", "..", "package.json"),
|
|
30310
|
-
join43(here, "..", "package.json")
|
|
30311
|
-
];
|
|
30532
|
+
const candidates = [join44(here, "..", "..", "package.json"), join44(here, "..", "package.json")];
|
|
30312
30533
|
for (const p of candidates) {
|
|
30313
|
-
if (
|
|
30534
|
+
if (existsSync50(p)) {
|
|
30314
30535
|
try {
|
|
30315
30536
|
const raw = JSON.parse(readFileSync31(p, "utf8"));
|
|
30316
30537
|
if (raw.version)
|
|
@@ -30325,7 +30546,7 @@ function createProgram() {
|
|
|
30325
30546
|
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
30547
|
program2.command("init").description(t("cli.init")).action(async () => {
|
|
30327
30548
|
const answers = await runSetup();
|
|
30328
|
-
const configPath =
|
|
30549
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30329
30550
|
const { config } = await bootstrap();
|
|
30330
30551
|
config.provider.type = answers.provider;
|
|
30331
30552
|
config.provider.baseUrl = answers.apiBase;
|
|
@@ -30370,7 +30591,7 @@ function createProgram() {
|
|
|
30370
30591
|
});
|
|
30371
30592
|
const configCmd = program2.command("config").description(t("cli.manage_config"));
|
|
30372
30593
|
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 =
|
|
30594
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30374
30595
|
const { config } = await bootstrap();
|
|
30375
30596
|
const keys = key.split(".");
|
|
30376
30597
|
let obj = config;
|
|
@@ -30433,7 +30654,7 @@ function createProgram() {
|
|
|
30433
30654
|
console.log(t("cli.model_hint"));
|
|
30434
30655
|
});
|
|
30435
30656
|
model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
|
|
30436
|
-
const configPath =
|
|
30657
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30437
30658
|
const { config } = await bootstrap();
|
|
30438
30659
|
config.model = name;
|
|
30439
30660
|
saveConfig(config, configPath);
|
|
@@ -30469,7 +30690,7 @@ function createProgram() {
|
|
|
30469
30690
|
await uncertify2(name, config);
|
|
30470
30691
|
});
|
|
30471
30692
|
program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
|
|
30472
|
-
const configPath =
|
|
30693
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30473
30694
|
const { config } = await bootstrap();
|
|
30474
30695
|
const contextWindow = parseInt(size, 10);
|
|
30475
30696
|
if (isNaN(contextWindow) || contextWindow < 1024) {
|
|
@@ -30487,7 +30708,7 @@ function createProgram() {
|
|
|
30487
30708
|
console.log(t("cli.base_url"), config.provider.baseUrl);
|
|
30488
30709
|
});
|
|
30489
30710
|
provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
|
|
30490
|
-
const configPath =
|
|
30711
|
+
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
30491
30712
|
const { config } = await bootstrap();
|
|
30492
30713
|
config.provider.type = name;
|
|
30493
30714
|
saveConfig(config, configPath);
|
|
@@ -31295,8 +31516,8 @@ class LineEditor {
|
|
|
31295
31516
|
}
|
|
31296
31517
|
|
|
31297
31518
|
// src/cli/repl.ts
|
|
31298
|
-
import { existsSync as
|
|
31299
|
-
import { join as
|
|
31519
|
+
import { existsSync as existsSync52, readFileSync as readFileSync33, writeFileSync as writeFileSync17 } from "fs";
|
|
31520
|
+
import { join as join46, dirname as dirname18 } from "path";
|
|
31300
31521
|
import { homedir as homedir17 } from "os";
|
|
31301
31522
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
31302
31523
|
|
|
@@ -31801,12 +32022,9 @@ init_i18n();
|
|
|
31801
32022
|
init_repl_commands();
|
|
31802
32023
|
function readVersion4() {
|
|
31803
32024
|
const here = dirname18(fileURLToPath6(import.meta.url));
|
|
31804
|
-
const candidates = [
|
|
31805
|
-
join45(here, "..", "..", "package.json"),
|
|
31806
|
-
join45(here, "..", "package.json")
|
|
31807
|
-
];
|
|
32025
|
+
const candidates = [join46(here, "..", "..", "package.json"), join46(here, "..", "package.json")];
|
|
31808
32026
|
for (const p of candidates) {
|
|
31809
|
-
if (
|
|
32027
|
+
if (existsSync52(p)) {
|
|
31810
32028
|
try {
|
|
31811
32029
|
const raw = JSON.parse(readFileSync33(p, "utf8"));
|
|
31812
32030
|
if (raw.version)
|
|
@@ -31864,10 +32082,10 @@ class Repl {
|
|
|
31864
32082
|
this.skillsModule = skillsModule;
|
|
31865
32083
|
this.pluginManager = pluginManager;
|
|
31866
32084
|
this.logger = logger;
|
|
31867
|
-
this.configDir = configDir ||
|
|
32085
|
+
this.configDir = configDir || join46(homedir17(), ".mma");
|
|
31868
32086
|
this.baseDir = baseDir || process.cwd();
|
|
31869
32087
|
this.noAgentsMd = noAgentsMd === true;
|
|
31870
|
-
this.historyPath =
|
|
32088
|
+
this.historyPath = join46(homedir17(), ".mma", "repl-history");
|
|
31871
32089
|
this.loadHistory();
|
|
31872
32090
|
this.rl = process.stdin.isTTY ? new LineEditor({
|
|
31873
32091
|
input: process.stdin,
|
|
@@ -31900,7 +32118,7 @@ class Repl {
|
|
|
31900
32118
|
this.setupListeners();
|
|
31901
32119
|
}
|
|
31902
32120
|
loadHistory() {
|
|
31903
|
-
if (
|
|
32121
|
+
if (existsSync52(this.historyPath)) {
|
|
31904
32122
|
try {
|
|
31905
32123
|
const raw = readFileSync33(this.historyPath, "utf-8");
|
|
31906
32124
|
this.history = raw.split(`
|
|
@@ -31922,13 +32140,7 @@ class Repl {
|
|
|
31922
32140
|
this.completer.registerProvider(new SessionNameProvider(() => this.sessionManager.list().map((s) => s.name)));
|
|
31923
32141
|
}
|
|
31924
32142
|
if (this.skillsModule) {
|
|
31925
|
-
this.completer.registerProvider(new SubcommandProvider("skill", [
|
|
31926
|
-
"list",
|
|
31927
|
-
"loaded",
|
|
31928
|
-
"load",
|
|
31929
|
-
"unload",
|
|
31930
|
-
"search"
|
|
31931
|
-
]));
|
|
32143
|
+
this.completer.registerProvider(new SubcommandProvider("skill", ["list", "loaded", "load", "unload", "search"]));
|
|
31932
32144
|
this.completer.registerProvider(new SkillNameProvider(this.skillsModule));
|
|
31933
32145
|
}
|
|
31934
32146
|
}
|
|
@@ -32263,11 +32475,11 @@ ${t("image.clipboard_empty")}`));
|
|
|
32263
32475
|
row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
|
|
32264
32476
|
} else {
|
|
32265
32477
|
const agentsMdCandidates = [
|
|
32266
|
-
|
|
32267
|
-
|
|
32268
|
-
|
|
32478
|
+
join46(this.baseDir, "AGENTS.md"),
|
|
32479
|
+
join46(this.baseDir, ".mma", "AGENTS.md"),
|
|
32480
|
+
join46(this.configDir, "AGENTS.md")
|
|
32269
32481
|
];
|
|
32270
|
-
const foundAgents = agentsMdCandidates.filter((p) =>
|
|
32482
|
+
const foundAgents = agentsMdCandidates.filter((p) => existsSync52(p));
|
|
32271
32483
|
if (foundAgents.length > 0) {
|
|
32272
32484
|
for (const p of foundAgents) {
|
|
32273
32485
|
row(t("repl.agents_label"), pc2.dim(p));
|
|
@@ -32278,7 +32490,7 @@ ${t("image.clipboard_empty")}`));
|
|
|
32278
32490
|
}
|
|
32279
32491
|
const meta = this.sessionManager?.getActiveMeta();
|
|
32280
32492
|
if (meta) {
|
|
32281
|
-
const sessionPath =
|
|
32493
|
+
const sessionPath = join46(this.configDir, "sessions", meta.id);
|
|
32282
32494
|
row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
|
|
32283
32495
|
}
|
|
32284
32496
|
const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
|
|
@@ -32319,8 +32531,8 @@ init_setup();
|
|
|
32319
32531
|
init_config2();
|
|
32320
32532
|
init_i18n();
|
|
32321
32533
|
init_colors();
|
|
32322
|
-
import { existsSync as
|
|
32323
|
-
import { join as
|
|
32534
|
+
import { existsSync as existsSync53, readFileSync as readFileSync34 } from "fs";
|
|
32535
|
+
import { join as join47, dirname as dirname19 } from "path";
|
|
32324
32536
|
import { homedir as homedir18 } from "os";
|
|
32325
32537
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
32326
32538
|
|
|
@@ -32424,12 +32636,9 @@ class UpdaterModule {
|
|
|
32424
32636
|
// src/cli/main.ts
|
|
32425
32637
|
function readVersion5() {
|
|
32426
32638
|
const here = dirname19(fileURLToPath7(import.meta.url));
|
|
32427
|
-
const candidates = [
|
|
32428
|
-
join46(here, "..", "..", "package.json"),
|
|
32429
|
-
join46(here, "..", "package.json")
|
|
32430
|
-
];
|
|
32639
|
+
const candidates = [join47(here, "..", "..", "package.json"), join47(here, "..", "package.json")];
|
|
32431
32640
|
for (const p of candidates) {
|
|
32432
|
-
if (
|
|
32641
|
+
if (existsSync53(p)) {
|
|
32433
32642
|
try {
|
|
32434
32643
|
const raw = JSON.parse(readFileSync34(p, "utf8"));
|
|
32435
32644
|
if (raw.version)
|
|
@@ -32514,15 +32723,15 @@ async function main() {
|
|
|
32514
32723
|
await updater?.waitForIdle();
|
|
32515
32724
|
process.exit(exitCode);
|
|
32516
32725
|
} else {
|
|
32517
|
-
const configPath =
|
|
32518
|
-
if (!
|
|
32726
|
+
const configPath = join47(homedir18(), ".mma", "config.json");
|
|
32727
|
+
if (!existsSync53(configPath)) {
|
|
32519
32728
|
console.log(pc2.yellow(`
|
|
32520
32729
|
` + t("cli.first_run") + `
|
|
32521
32730
|
`));
|
|
32522
32731
|
const answers = await runSetup();
|
|
32523
32732
|
const config2 = loadConfig({
|
|
32524
|
-
configDir:
|
|
32525
|
-
projectConfigPath: projectDir ?
|
|
32733
|
+
configDir: join47(homedir18(), ".mma"),
|
|
32734
|
+
projectConfigPath: projectDir ? join47(projectDir, ".mmrc") : join47(process.cwd(), ".mmrc")
|
|
32526
32735
|
});
|
|
32527
32736
|
config2.provider.type = answers.provider;
|
|
32528
32737
|
config2.provider.baseUrl = answers.apiBase;
|