micro-models-agent 0.22.0 → 0.23.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/README.md +312 -312
- package/bin/mma.mjs +8 -8
- package/dist/cli/commands.js +220 -0
- package/dist/cli/completer.js +168 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/main.js +113 -0
- package/dist/cli/repl.js +987 -0
- package/dist/cli/security-commands.js +166 -0
- package/dist/cli/setup.js +229 -0
- package/dist/config/config.js +186 -0
- package/dist/config/defaults.js +91 -0
- package/dist/config/experts.js +15 -0
- package/dist/config/index.js +3 -0
- package/dist/config/security.js +193 -0
- package/dist/config/types.js +1 -0
- package/dist/core/agent-moe.js +98 -0
- package/dist/core/agent.js +461 -0
- package/dist/core/bootstrap.js +321 -0
- package/dist/core/index.js +2 -0
- package/dist/core/prompt-builder.js +55 -0
- package/dist/core/session-logger.js +122 -0
- package/dist/core/types.js +1 -0
- package/dist/i18n/en.json +461 -0
- package/dist/i18n/index.js +43 -0
- package/dist/i18n/ru.json +461 -0
- package/dist/index.js +22 -0
- package/dist/llm/image-utils.js +144 -0
- package/dist/llm/index.js +4 -0
- package/dist/llm/model-loader.js +78 -0
- package/dist/llm/openai-compat.js +324 -0
- package/dist/llm/orchestrator.js +194 -0
- package/dist/llm/provider.js +10 -0
- package/dist/llm/response.js +39 -0
- package/dist/llm/token-counter.js +39 -0
- package/dist/llm/types.js +1 -0
- package/dist/logger/app-logger.js +76 -0
- package/dist/logger/index.js +1 -0
- package/dist/main.js +708 -246
- package/dist/migration/backup.js +45 -0
- package/dist/migration/detect.js +50 -0
- package/dist/migration/index.js +2 -0
- package/dist/modules/browser/actions.js +46 -0
- package/dist/modules/browser/cookie-store.js +24 -0
- package/dist/modules/browser/index.js +5 -0
- package/dist/modules/browser/module.js +28 -0
- package/dist/modules/browser/session.js +287 -0
- package/dist/modules/browser/snapshot.js +114 -0
- package/dist/modules/browser/types.js +9 -0
- package/dist/modules/context/history.js +15 -0
- package/dist/modules/context/index.js +1 -0
- package/dist/modules/context/manager.js +240 -0
- package/dist/modules/execution/auditor.js +72 -0
- package/dist/modules/execution/index.js +6 -0
- package/dist/modules/execution/module.js +337 -0
- package/dist/modules/execution/moe-executor.js +209 -0
- package/dist/modules/execution/plan-validator.js +153 -0
- package/dist/modules/execution/planner.js +35 -0
- package/dist/modules/execution/stuck-detector.js +134 -0
- package/dist/modules/execution/tracker.js +53 -0
- package/dist/modules/execution/types.js +1 -0
- package/dist/modules/execution/verifier.js +149 -0
- package/dist/modules/hallucination/confidence.js +54 -0
- package/dist/modules/hallucination/consistency.js +60 -0
- package/dist/modules/hallucination/detector.js +41 -0
- package/dist/modules/hallucination/factual.js +170 -0
- package/dist/modules/hallucination/index.js +4 -0
- package/dist/modules/index.js +5 -0
- package/dist/modules/indexer/cache.js +38 -0
- package/dist/modules/indexer/index.js +3 -0
- package/dist/modules/indexer/module.js +192 -0
- package/dist/modules/indexer/walker.js +101 -0
- package/dist/modules/mcp/client.js +393 -0
- package/dist/modules/mcp/index.js +3 -0
- package/dist/modules/mcp/module.js +146 -0
- package/dist/modules/mcp/registry.js +15 -0
- package/dist/modules/memory/index.js +1 -0
- package/dist/modules/memory/module.js +48 -0
- package/dist/modules/memory/search.js +40 -0
- package/dist/modules/memory/store.js +65 -0
- package/dist/modules/pipelines/engine.js +60 -0
- package/dist/modules/pipelines/index.js +3 -0
- package/dist/modules/pipelines/parser.js +53 -0
- package/dist/modules/pipelines/template.js +14 -0
- package/dist/modules/plugins/builtin/lint-on-write.js +121 -0
- package/dist/modules/plugins/builtin/notify.js +8 -0
- package/dist/modules/plugins/index.js +1 -0
- package/dist/modules/plugins/loader.js +28 -0
- package/dist/modules/plugins/manager.js +161 -0
- package/dist/modules/plugins/types.js +1 -0
- package/dist/modules/processes/detect.js +34 -0
- package/dist/modules/processes/index.js +3 -0
- package/dist/modules/processes/registry.js +148 -0
- package/dist/modules/processes/runner.js +124 -0
- package/dist/modules/registry.js +45 -0
- package/dist/modules/security/audit-log.js +116 -0
- package/dist/modules/security/audit-notifier.js +292 -0
- package/dist/modules/security/command-validator.js +185 -0
- package/dist/modules/security/content-scanner.js +52 -0
- package/dist/modules/security/data-sanitizer.js +97 -0
- package/dist/modules/security/encryption.js +240 -0
- package/dist/modules/security/index.js +14 -0
- package/dist/modules/security/network-validator.js +79 -0
- package/dist/modules/security/path-validator.js +155 -0
- package/dist/modules/security/rate-limiter.js +119 -0
- package/dist/modules/security/security-policies.js +393 -0
- package/dist/modules/security/session-encryption.js +193 -0
- package/dist/modules/security/session-isolation.js +95 -0
- package/dist/modules/session/index.js +3 -0
- package/dist/modules/session/manager.js +167 -0
- package/dist/modules/session/module.js +24 -0
- package/dist/modules/session/store.js +174 -0
- package/dist/modules/session/types.js +1 -0
- package/dist/modules/skills/index.js +3 -0
- package/dist/modules/skills/loader.js +72 -0
- package/dist/modules/skills/matcher.js +27 -0
- package/dist/modules/skills/module.js +143 -0
- package/dist/modules/types.js +1 -0
- package/dist/modules/updater/checker.js +32 -0
- package/dist/modules/updater/index.js +1 -0
- package/dist/modules/user-profile/compressor.js +16 -0
- package/dist/modules/user-profile/index.js +1 -0
- package/dist/modules/user-profile/profile.js +68 -0
- package/dist/tools/approve.js +32 -0
- package/dist/tools/attach-image.js +89 -0
- package/dist/tools/bash.js +140 -0
- package/dist/tools/browser.js +97 -0
- package/dist/tools/create-dir.js +56 -0
- package/dist/tools/delete-file.js +63 -0
- package/dist/tools/edit-file.js +77 -0
- package/dist/tools/executor.js +95 -0
- package/dist/tools/file-info.js +45 -0
- package/dist/tools/filter-tools.js +10 -0
- package/dist/tools/glob-tool.js +26 -0
- package/dist/tools/grep-tool.js +64 -0
- package/dist/tools/index.js +52 -0
- package/dist/tools/list-dir.js +47 -0
- package/dist/tools/load-skill.js +48 -0
- package/dist/tools/mcp-call.js +68 -0
- package/dist/tools/move-file.js +84 -0
- package/dist/tools/path-utils.js +51 -0
- package/dist/tools/pipeline-run.js +144 -0
- package/dist/tools/preview.js +2 -0
- package/dist/tools/process-kill.js +29 -0
- package/dist/tools/process-list.js +38 -0
- package/dist/tools/process-log.js +41 -0
- package/dist/tools/question.js +142 -0
- package/dist/tools/read-file.js +73 -0
- package/dist/tools/recall.js +110 -0
- package/dist/tools/registry.js +36 -0
- package/dist/tools/remember.js +67 -0
- package/dist/tools/scope-check.js +30 -0
- package/dist/tools/search-history.js +64 -0
- package/dist/tools/subagent.js +142 -0
- package/dist/tools/types.js +1 -0
- package/dist/tools/user-input.js +123 -0
- package/dist/tools/web-browse.js +57 -0
- package/dist/tools/web-fetch.js +72 -0
- package/dist/tools/web-search.js +59 -0
- package/dist/tools/write-file.js +80 -0
- package/dist/ui/box.js +81 -0
- package/dist/ui/colors.js +4 -0
- package/dist/ui/diff.js +185 -0
- package/dist/ui/index.js +6 -0
- package/dist/ui/md-formatter.js +212 -0
- package/dist/ui/output.js +13 -0
- package/dist/ui/renderer.js +141 -0
- package/dist/ui/spinner.js +70 -0
- package/dist/ui/table.js +144 -0
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2021,7 +2021,7 @@ var init_security = __esm(() => {
|
|
|
2021
2021
|
maxParallelTasks: 5
|
|
2022
2022
|
},
|
|
2023
2023
|
contentScan: {
|
|
2024
|
-
enabled:
|
|
2024
|
+
enabled: false,
|
|
2025
2025
|
dangerousPatterns: [
|
|
2026
2026
|
/eval\(/,
|
|
2027
2027
|
/new Function\(/,
|
|
@@ -2310,6 +2310,7 @@ Command: {command}`,
|
|
|
2310
2310
|
"tool.friendly.process_kill": "Stopping process",
|
|
2311
2311
|
"plan.no_steps": "No plan steps specified. Provide concrete steps with files and commands.",
|
|
2312
2312
|
"plan.created": "Plan created: {title} ({steps} steps)",
|
|
2313
|
+
"plan.coverage_warning": "Plan may be missing required files from the task: {missing}. Add steps covering them.",
|
|
2313
2314
|
"plan.step_done": "Step {n}/{total}: {description} ✓",
|
|
2314
2315
|
"plan.complete": "Task complete: {summary}",
|
|
2315
2316
|
"plan.title_steps": 'Plan "{title}" created with {count} steps',
|
|
@@ -2570,6 +2571,14 @@ Use this knowledge to answer the user's question.`,
|
|
|
2570
2571
|
"exec.audit_fail": "[✗] Task incomplete: {done}/{total} steps done, {files} files missing",
|
|
2571
2572
|
"exec.audit_fail_typecheck": "[✗] Task incomplete: {done}/{total} steps done, {missing} files missing, typecheck error: {typeError}",
|
|
2572
2573
|
"exec.audit_incomplete": "[⚠ Final audit incomplete: {summary}. Task is NOT finished — continue working. Remaining steps: {steps}]",
|
|
2574
|
+
"exec.mass_edit_warning": "⚠️ Plan affects {count} files — review the full list before proceeding.",
|
|
2575
|
+
"exec.escalation": `
|
|
2576
|
+
|
|
2577
|
+
⚠️ Agent stuck on step {stepId} ({description}). Escalating to user — please provide guidance.`,
|
|
2578
|
+
"exec.hints": `
|
|
2579
|
+
[Hints]
|
|
2580
|
+
{hints}`,
|
|
2581
|
+
"exec.file_rewrite_warning": "⚠️ File {file} has been rewritten {count} times. Consider a different approach — the current fix strategy is not working.",
|
|
2573
2582
|
"hall.max_retries_exhausted": "Model returned empty or insufficient responses after multiple retries",
|
|
2574
2583
|
"hall.short_response": "Response too short or empty",
|
|
2575
2584
|
"hall.repetitive": "Response too repetitive ({pct}% overlap)",
|
|
@@ -2647,7 +2656,12 @@ Use this knowledge to answer the user's question.`,
|
|
|
2647
2656
|
"tool.recall.empty": 'Nothing found for "{query}"',
|
|
2648
2657
|
"tool.recall.no_memory": "Memory is empty",
|
|
2649
2658
|
"tool.recall.search_results": `{category} results:
|
|
2650
|
-
{results}
|
|
2659
|
+
{results}`,
|
|
2660
|
+
"ctx.compactions": "compactions: {count}",
|
|
2661
|
+
"ctx.quality": "quality: {percent}%",
|
|
2662
|
+
"ctx.delta_pos": "ctx +{tokens}",
|
|
2663
|
+
"ctx.delta_neg": "ctx -{tokens} ↓",
|
|
2664
|
+
"ctx.delta_zero": "ctx ±0"
|
|
2651
2665
|
};
|
|
2652
2666
|
});
|
|
2653
2667
|
|
|
@@ -2807,6 +2821,7 @@ var init_ru = __esm(() => {
|
|
|
2807
2821
|
"tool.friendly.process_kill": "Остановка процесса",
|
|
2808
2822
|
"plan.no_steps": "Не указаны шаги плана. Укажите конкретные шаги с файлами и командами.",
|
|
2809
2823
|
"plan.created": "План создан: {title} ({steps} шагов)",
|
|
2824
|
+
"plan.coverage_warning": "План может не покрывать требуемые файлы из постановки: {missing}. Добавьте шаги, покрывающие их.",
|
|
2810
2825
|
"plan.step_done": "Шаг {n}/{total}: {description} ✓",
|
|
2811
2826
|
"plan.complete": "Задача выполнена: {summary}",
|
|
2812
2827
|
"plan.title_steps": 'План "{title}" создан с {count} шагами',
|
|
@@ -3067,6 +3082,14 @@ var init_ru = __esm(() => {
|
|
|
3067
3082
|
"exec.audit_fail": "[✗] Задача не выполнена: {done}/{total} шагов, {files} файлов отсутствует",
|
|
3068
3083
|
"exec.audit_fail_typecheck": "[✗] Задача не выполнена: {done}/{total} шагов, {missing} файлов отсутствует, ошибка typecheck: {typeError}",
|
|
3069
3084
|
"exec.audit_incomplete": "[⚠ Финальная проверка не пройдена: {summary}. Задача НЕ завершена — продолжайте работу. Оставшиеся шаги: {steps}]",
|
|
3085
|
+
"exec.mass_edit_warning": "⚠️ План затрагивает {count} файлов — проверьте полный список перед продолжением.",
|
|
3086
|
+
"exec.escalation": `
|
|
3087
|
+
|
|
3088
|
+
⚠️ Агент застрял на шаге {stepId} ({description}). Эскалация к пользователю — пожалуйста, подскажите как действовать.`,
|
|
3089
|
+
"exec.hints": `
|
|
3090
|
+
[Подсказки]
|
|
3091
|
+
{hints}`,
|
|
3092
|
+
"exec.file_rewrite_warning": "⚠️ Файл {file} был перезаписан {count} раз. Попробуйте другой подход — текущая стратегия исправлений не работает.",
|
|
3070
3093
|
"hall.max_retries_exhausted": "Модель вернула пустой или недостаточный ответ после нескольких попыток",
|
|
3071
3094
|
"hall.short_response": "Слишком короткий или пустой ответ",
|
|
3072
3095
|
"hall.repetitive": "Слишком повторяющийся ответ ({pct}% совпадение)",
|
|
@@ -3144,7 +3167,12 @@ var init_ru = __esm(() => {
|
|
|
3144
3167
|
"tool.recall.empty": 'Ничего не найдено по "{query}"',
|
|
3145
3168
|
"tool.recall.no_memory": "Память пуста",
|
|
3146
3169
|
"tool.recall.search_results": `Результаты {category}:
|
|
3147
|
-
{results}
|
|
3170
|
+
{results}`,
|
|
3171
|
+
"ctx.compactions": "сжатий: {count}",
|
|
3172
|
+
"ctx.quality": "качество: {percent}%",
|
|
3173
|
+
"ctx.delta_pos": "контекст +{tokens}",
|
|
3174
|
+
"ctx.delta_neg": "контекст -{tokens} ↓",
|
|
3175
|
+
"ctx.delta_zero": "контекст ±0"
|
|
3148
3176
|
};
|
|
3149
3177
|
});
|
|
3150
3178
|
|
|
@@ -8797,7 +8825,133 @@ var init_agent_moe = __esm(() => {
|
|
|
8797
8825
|
init_verifier();
|
|
8798
8826
|
});
|
|
8799
8827
|
|
|
8828
|
+
// src/modules/memory/search.ts
|
|
8829
|
+
import { readFileSync as readFileSync9, existsSync as existsSync18 } from "fs";
|
|
8830
|
+
import { join as join8 } from "path";
|
|
8831
|
+
|
|
8832
|
+
class MemorySearch {
|
|
8833
|
+
memoryDir;
|
|
8834
|
+
constructor(memoryDir) {
|
|
8835
|
+
this.memoryDir = memoryDir;
|
|
8836
|
+
}
|
|
8837
|
+
query(query) {
|
|
8838
|
+
const results = [];
|
|
8839
|
+
const lowerQuery = query.toLowerCase();
|
|
8840
|
+
for (const name of MEMORY_FILES) {
|
|
8841
|
+
const path = join8(this.memoryDir, `${name}.md`);
|
|
8842
|
+
if (!existsSync18(path))
|
|
8843
|
+
continue;
|
|
8844
|
+
const content = readFileSync9(path, "utf-8");
|
|
8845
|
+
const lines = content.split(`
|
|
8846
|
+
`);
|
|
8847
|
+
for (const line of lines) {
|
|
8848
|
+
if (line.toLowerCase().includes(lowerQuery)) {
|
|
8849
|
+
results.push({ file: name, match: line.trim() });
|
|
8850
|
+
}
|
|
8851
|
+
}
|
|
8852
|
+
}
|
|
8853
|
+
const prefsPath = join8(this.memoryDir, "preferences.json");
|
|
8854
|
+
if (existsSync18(prefsPath)) {
|
|
8855
|
+
try {
|
|
8856
|
+
const prefs = JSON.parse(readFileSync9(prefsPath, "utf-8"));
|
|
8857
|
+
for (const [key, value] of Object.entries(prefs)) {
|
|
8858
|
+
const searchStr = `${key}=${value}`;
|
|
8859
|
+
if (searchStr.toLowerCase().includes(lowerQuery)) {
|
|
8860
|
+
results.push({ file: "preferences", match: `${key} = ${value}` });
|
|
8861
|
+
}
|
|
8862
|
+
}
|
|
8863
|
+
} catch {}
|
|
8864
|
+
}
|
|
8865
|
+
return results;
|
|
8866
|
+
}
|
|
8867
|
+
}
|
|
8868
|
+
var MEMORY_FILES;
|
|
8869
|
+
var init_search = __esm(() => {
|
|
8870
|
+
MEMORY_FILES = ["conventions", "decisions", "errors", "facts"];
|
|
8871
|
+
});
|
|
8872
|
+
|
|
8873
|
+
// src/modules/memory/store.ts
|
|
8874
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, appendFileSync as appendFileSync4, existsSync as existsSync19, mkdirSync as mkdirSync10 } from "fs";
|
|
8875
|
+
import { join as join9 } from "path";
|
|
8876
|
+
|
|
8877
|
+
class MemoryStore {
|
|
8878
|
+
memoryDir;
|
|
8879
|
+
constructor(memoryDir) {
|
|
8880
|
+
this.memoryDir = memoryDir;
|
|
8881
|
+
this.ensureDir();
|
|
8882
|
+
for (const name of MEMORY_FILES2) {
|
|
8883
|
+
const path = join9(this.memoryDir, `${name}.md`);
|
|
8884
|
+
if (!existsSync19(path)) {
|
|
8885
|
+
writeFileSync8(path, `# ${name.charAt(0).toUpperCase() + name.slice(1)}
|
|
8886
|
+
|
|
8887
|
+
`, "utf-8");
|
|
8888
|
+
}
|
|
8889
|
+
}
|
|
8890
|
+
}
|
|
8891
|
+
ensureDir() {
|
|
8892
|
+
if (!existsSync19(this.memoryDir)) {
|
|
8893
|
+
mkdirSync10(this.memoryDir, { recursive: true });
|
|
8894
|
+
}
|
|
8895
|
+
}
|
|
8896
|
+
read(name) {
|
|
8897
|
+
const path = join9(this.memoryDir, `${name}.md`);
|
|
8898
|
+
if (!existsSync19(path))
|
|
8899
|
+
return "";
|
|
8900
|
+
return readFileSync10(path, "utf-8");
|
|
8901
|
+
}
|
|
8902
|
+
append(name, entry) {
|
|
8903
|
+
const path = join9(this.memoryDir, `${name}.md`);
|
|
8904
|
+
const timestamp = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
8905
|
+
const formatted = `- **${timestamp}** — ${entry}
|
|
8906
|
+
`;
|
|
8907
|
+
appendFileSync4(path, formatted, "utf-8");
|
|
8908
|
+
}
|
|
8909
|
+
search(query) {
|
|
8910
|
+
const searchModule = new MemorySearch(this.memoryDir);
|
|
8911
|
+
return searchModule.query(query);
|
|
8912
|
+
}
|
|
8913
|
+
prefsPath() {
|
|
8914
|
+
return join9(this.memoryDir, "preferences.json");
|
|
8915
|
+
}
|
|
8916
|
+
getPreferences() {
|
|
8917
|
+
const path = this.prefsPath();
|
|
8918
|
+
if (!existsSync19(path))
|
|
8919
|
+
return {};
|
|
8920
|
+
try {
|
|
8921
|
+
return JSON.parse(readFileSync10(path, "utf-8"));
|
|
8922
|
+
} catch {
|
|
8923
|
+
return {};
|
|
8924
|
+
}
|
|
8925
|
+
}
|
|
8926
|
+
setPreference(key, value) {
|
|
8927
|
+
const prefs = this.getPreferences();
|
|
8928
|
+
prefs[key] = value;
|
|
8929
|
+
writeFileSync8(this.prefsPath(), JSON.stringify(prefs, null, 2), "utf-8");
|
|
8930
|
+
}
|
|
8931
|
+
deletePreference(key) {
|
|
8932
|
+
const prefs = this.getPreferences();
|
|
8933
|
+
if (!(key in prefs))
|
|
8934
|
+
return false;
|
|
8935
|
+
delete prefs[key];
|
|
8936
|
+
writeFileSync8(this.prefsPath(), JSON.stringify(prefs, null, 2), "utf-8");
|
|
8937
|
+
return true;
|
|
8938
|
+
}
|
|
8939
|
+
appendRule(category, pattern, cause, solution) {
|
|
8940
|
+
const entry = `**pattern:** ${pattern}
|
|
8941
|
+
**cause:** ${cause}
|
|
8942
|
+
**solution:** ${solution}`;
|
|
8943
|
+
this.append(category, entry);
|
|
8944
|
+
}
|
|
8945
|
+
}
|
|
8946
|
+
var MEMORY_FILES2;
|
|
8947
|
+
var init_store = __esm(() => {
|
|
8948
|
+
init_search();
|
|
8949
|
+
MEMORY_FILES2 = ["conventions", "decisions", "errors", "facts"];
|
|
8950
|
+
});
|
|
8951
|
+
|
|
8800
8952
|
// src/core/agent.ts
|
|
8953
|
+
import { join as join10 } from "path";
|
|
8954
|
+
|
|
8801
8955
|
class Agent {
|
|
8802
8956
|
deps;
|
|
8803
8957
|
systemPromptAdded = false;
|
|
@@ -8865,7 +9019,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
8865
9019
|
pluginManager,
|
|
8866
9020
|
contextManager,
|
|
8867
9021
|
logger,
|
|
8868
|
-
sessionManager
|
|
9022
|
+
sessionManager,
|
|
9023
|
+
baseDir
|
|
8869
9024
|
} = this.deps;
|
|
8870
9025
|
const slog = new SessionLogger(sessionManager);
|
|
8871
9026
|
if (sessionManager && !sessionManager.getActive()) {
|
|
@@ -8907,7 +9062,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
8907
9062
|
contextManager,
|
|
8908
9063
|
hallucinationDetector,
|
|
8909
9064
|
logger,
|
|
8910
|
-
sessionManager
|
|
9065
|
+
sessionManager,
|
|
9066
|
+
baseDir
|
|
8911
9067
|
} = this.deps;
|
|
8912
9068
|
const slog = new SessionLogger(sessionManager);
|
|
8913
9069
|
let iteration = 0;
|
|
@@ -8919,6 +9075,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
8919
9075
|
const MAX_HALLUCINATION_RETRIES = 3;
|
|
8920
9076
|
let consecutiveToolFailures = 0;
|
|
8921
9077
|
const MAX_CONSECUTIVE_TOOL_FAILURES = 5;
|
|
9078
|
+
let auditRetries = 0;
|
|
9079
|
+
const MAX_AUDIT_RETRIES = 3;
|
|
8922
9080
|
while (iteration < config.maxToolIterations && !this.shutdownRequested) {
|
|
8923
9081
|
iteration++;
|
|
8924
9082
|
pluginManager.runOnBeforeThink({
|
|
@@ -9055,6 +9213,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9055
9213
|
pluginManager.runOnToolStart({ iteration, logger }, { id: call.id, name: call.name, arguments: call.arguments });
|
|
9056
9214
|
onTool?.({ type: "start", tool: call.name, args: call.arguments });
|
|
9057
9215
|
slog.logToolCall(call, iteration);
|
|
9216
|
+
const tokensBeforeTool = contextManager.getEstimatedTokens();
|
|
9058
9217
|
const result = await toolExecutor.execute(call);
|
|
9059
9218
|
const duration = Date.now() - startTime;
|
|
9060
9219
|
if (!result.success)
|
|
@@ -9074,12 +9233,14 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9074
9233
|
` + result.diff + `
|
|
9075
9234
|
`);
|
|
9076
9235
|
}
|
|
9236
|
+
const tokensAfterTool = contextManager.getEstimatedTokens();
|
|
9077
9237
|
onTool?.({
|
|
9078
9238
|
type: "end",
|
|
9079
9239
|
tool: call.name,
|
|
9080
9240
|
args: call.arguments,
|
|
9081
9241
|
duration,
|
|
9082
|
-
error: !result.success
|
|
9242
|
+
error: !result.success,
|
|
9243
|
+
ctxDelta: tokensAfterTool - tokensBeforeTool
|
|
9083
9244
|
});
|
|
9084
9245
|
const currentTokens2 = contextManager.getEstimatedTokens();
|
|
9085
9246
|
const budget3 = contextManager.getBudget();
|
|
@@ -9088,7 +9249,9 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9088
9249
|
role: "tool",
|
|
9089
9250
|
content: truncatedOutput,
|
|
9090
9251
|
name: call.name,
|
|
9091
|
-
tool_call_id: call.id
|
|
9252
|
+
tool_call_id: call.id,
|
|
9253
|
+
success: result.success,
|
|
9254
|
+
arguments: call.arguments
|
|
9092
9255
|
});
|
|
9093
9256
|
summaries.push(`[Tool: ${call.name} (${JSON.stringify(call.arguments)}) → ${truncatedOutput.slice(0, 200)}]`);
|
|
9094
9257
|
if (config.session.autoSave) {
|
|
@@ -9116,6 +9279,14 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9116
9279
|
content: `<system-summary>${recoveryMsg}
|
|
9117
9280
|
${taskReminder}</system-summary>`
|
|
9118
9281
|
});
|
|
9282
|
+
if (sessionManager) {
|
|
9283
|
+
const activeSession = sessionManager.getActiveMeta();
|
|
9284
|
+
if (activeSession) {
|
|
9285
|
+
const memDir = join10(baseDir, ".mma", "memory");
|
|
9286
|
+
const memStore = new MemoryStore(memDir);
|
|
9287
|
+
memStore.appendRule("errors", `${consecutiveToolFailures} consecutive tool failures`, "Multiple tools failing suggests environment or configuration issue", "Check dependencies, verify file paths, try write_file directly instead of shell commands");
|
|
9288
|
+
}
|
|
9289
|
+
}
|
|
9119
9290
|
}
|
|
9120
9291
|
contextManager.addMessage({
|
|
9121
9292
|
role: "user",
|
|
@@ -9129,8 +9300,11 @@ ${taskReminder}</system-summary>`
|
|
|
9129
9300
|
const filled = Math.round(ctxPct / 100 * barLen);
|
|
9130
9301
|
const ctxBar = pc.green("█".repeat(filled)) + pc.dim("░".repeat(barLen - filled));
|
|
9131
9302
|
const pctColor = ctxPct >= 75 ? pc.yellow : pc.dim;
|
|
9303
|
+
const compCount = contextManager.getCompactionCount();
|
|
9304
|
+
const quality = contextManager.getQuality();
|
|
9305
|
+
const qualityColor = quality >= 70 ? pc.green : quality >= 40 ? pc.yellow : pc.red;
|
|
9132
9306
|
onMeta?.(`
|
|
9133
|
-
${ctxBar} ${pctColor(`${ctxPct}%`)} ${pc.dim(`ctx: ${ctxTokens}/${ctxBudget.history}`)}
|
|
9307
|
+
${ctxBar} ${pctColor(`${ctxPct}%`)} ${pc.dim(`ctx: ${ctxTokens}/${ctxBudget.history}`)} ${pc.dim(`compactions: ${compCount}`)} ${qualityColor(`quality: ${quality}%`)}
|
|
9134
9308
|
`);
|
|
9135
9309
|
continue;
|
|
9136
9310
|
}
|
|
@@ -9204,7 +9378,9 @@ ${taskReminder}</system-summary>`
|
|
|
9204
9378
|
})}</system-summary>`
|
|
9205
9379
|
});
|
|
9206
9380
|
slog.logAudit(audit.summary, iteration);
|
|
9207
|
-
|
|
9381
|
+
auditRetries++;
|
|
9382
|
+
if (auditRetries >= MAX_AUDIT_RETRIES || iteration >= config.maxToolIterations - 1) {
|
|
9383
|
+
logger.warn(`Final audit still incomplete after ${auditRetries} retries — finishing anyway`);
|
|
9208
9384
|
break;
|
|
9209
9385
|
}
|
|
9210
9386
|
continue;
|
|
@@ -9225,7 +9401,9 @@ ${taskReminder}</system-summary>`
|
|
|
9225
9401
|
contextLimit: budget.history,
|
|
9226
9402
|
promptTokens: apiPromptTokens,
|
|
9227
9403
|
completionTokens: apiCompletionTokens,
|
|
9228
|
-
totalTokens: apiPromptTokens + apiCompletionTokens
|
|
9404
|
+
totalTokens: apiPromptTokens + apiCompletionTokens,
|
|
9405
|
+
compactionCount: contextManager.getCompactionCount(),
|
|
9406
|
+
contextQuality: contextManager.getQuality()
|
|
9229
9407
|
};
|
|
9230
9408
|
}
|
|
9231
9409
|
return {
|
|
@@ -9236,7 +9414,9 @@ ${taskReminder}</system-summary>`
|
|
|
9236
9414
|
contextLimit: budget.history,
|
|
9237
9415
|
promptTokens: apiPromptTokens,
|
|
9238
9416
|
completionTokens: apiCompletionTokens,
|
|
9239
|
-
totalTokens: apiPromptTokens + apiCompletionTokens
|
|
9417
|
+
totalTokens: apiPromptTokens + apiCompletionTokens,
|
|
9418
|
+
compactionCount: contextManager.getCompactionCount(),
|
|
9419
|
+
contextQuality: contextManager.getQuality()
|
|
9240
9420
|
};
|
|
9241
9421
|
}
|
|
9242
9422
|
clearContext() {
|
|
@@ -9280,14 +9460,56 @@ var init_agent = __esm(() => {
|
|
|
9280
9460
|
init_prompt_builder();
|
|
9281
9461
|
init_processes();
|
|
9282
9462
|
init_agent_moe();
|
|
9463
|
+
init_store();
|
|
9283
9464
|
});
|
|
9284
9465
|
|
|
9285
9466
|
// src/modules/context/manager.ts
|
|
9467
|
+
function summarizeArgs(args) {
|
|
9468
|
+
if (!args)
|
|
9469
|
+
return "";
|
|
9470
|
+
if (typeof args === "string")
|
|
9471
|
+
return args.slice(0, 80);
|
|
9472
|
+
try {
|
|
9473
|
+
const keys = Object.keys(args);
|
|
9474
|
+
return keys.slice(0, 3).join(", ");
|
|
9475
|
+
} catch {
|
|
9476
|
+
return String(args).slice(0, 80);
|
|
9477
|
+
}
|
|
9478
|
+
}
|
|
9479
|
+
function truncate(s, max) {
|
|
9480
|
+
if (s.length <= max)
|
|
9481
|
+
return s;
|
|
9482
|
+
return s.slice(0, max - 3) + "...";
|
|
9483
|
+
}
|
|
9484
|
+
function extractTriedAndFailed(messages) {
|
|
9485
|
+
const failures = new Map;
|
|
9486
|
+
for (const msg of messages) {
|
|
9487
|
+
if (msg.role === "tool" && msg.name && msg.success === false) {
|
|
9488
|
+
const key = `${msg.name}:${summarizeArgs(msg.arguments)}`;
|
|
9489
|
+
const existing = failures.get(key);
|
|
9490
|
+
const errorText = truncate(typeof msg.content === "string" ? msg.content : getMessageText(msg.content), 100);
|
|
9491
|
+
if (existing) {
|
|
9492
|
+
existing.count++;
|
|
9493
|
+
} else {
|
|
9494
|
+
failures.set(key, {
|
|
9495
|
+
tool: msg.name,
|
|
9496
|
+
args: summarizeArgs(msg.arguments),
|
|
9497
|
+
error: errorText,
|
|
9498
|
+
count: 1
|
|
9499
|
+
});
|
|
9500
|
+
}
|
|
9501
|
+
}
|
|
9502
|
+
}
|
|
9503
|
+
return Array.from(failures.values()).filter((f) => f.count >= 2);
|
|
9504
|
+
}
|
|
9505
|
+
|
|
9286
9506
|
class ContextManager {
|
|
9287
9507
|
contextWindow;
|
|
9288
9508
|
messages = [];
|
|
9289
9509
|
compactedBlock = null;
|
|
9290
9510
|
iterationsSinceCompaction = 0;
|
|
9511
|
+
compactionCount = 0;
|
|
9512
|
+
peakTokens = 0;
|
|
9291
9513
|
budget;
|
|
9292
9514
|
compactionThreshold;
|
|
9293
9515
|
fileFacts = [];
|
|
@@ -9318,6 +9540,17 @@ class ContextManager {
|
|
|
9318
9540
|
getBudget() {
|
|
9319
9541
|
return { ...this.budget };
|
|
9320
9542
|
}
|
|
9543
|
+
getCompactionCount() {
|
|
9544
|
+
return this.compactionCount;
|
|
9545
|
+
}
|
|
9546
|
+
getIterationsSinceCompaction() {
|
|
9547
|
+
return this.iterationsSinceCompaction;
|
|
9548
|
+
}
|
|
9549
|
+
getQuality() {
|
|
9550
|
+
const freshness = 1 - this.iterationsSinceCompaction / COMPACTION_INTERVAL;
|
|
9551
|
+
const depth = 1 / (1 + this.compactionCount);
|
|
9552
|
+
return Math.round(freshness * depth * 100);
|
|
9553
|
+
}
|
|
9321
9554
|
addMessage(msg) {
|
|
9322
9555
|
if (msg.role === "user" && this.pendingImageParts.length > 0) {
|
|
9323
9556
|
const textPart = {
|
|
@@ -9332,6 +9565,9 @@ class ContextManager {
|
|
|
9332
9565
|
}
|
|
9333
9566
|
this.messages.push(msg);
|
|
9334
9567
|
this.iterationsSinceCompaction++;
|
|
9568
|
+
const tokens = this.getEstimatedTokens();
|
|
9569
|
+
if (tokens > this.peakTokens)
|
|
9570
|
+
this.peakTokens = tokens;
|
|
9335
9571
|
}
|
|
9336
9572
|
addPendingImage(part) {
|
|
9337
9573
|
this.pendingImageParts.push(part);
|
|
@@ -9398,6 +9634,7 @@ class ContextManager {
|
|
|
9398
9634
|
compact() {
|
|
9399
9635
|
if (this.messages.length <= KEEP_LAST_N * 2)
|
|
9400
9636
|
return;
|
|
9637
|
+
this.compactionCount++;
|
|
9401
9638
|
const cutoff = this.messages.length - KEEP_LAST_N * 2;
|
|
9402
9639
|
const oldTurns = this.messages.slice(0, cutoff);
|
|
9403
9640
|
const recentTurns = this.messages.slice(cutoff);
|
|
@@ -9413,6 +9650,13 @@ class ContextManager {
|
|
|
9413
9650
|
if (this.errorFacts.length > 0) {
|
|
9414
9651
|
parts.push(`[Errors: ${this.errorFacts.slice(-3).join("; ")}]`);
|
|
9415
9652
|
}
|
|
9653
|
+
const triedAndFailed = extractTriedAndFailed(this.messages);
|
|
9654
|
+
if (triedAndFailed.length > 0) {
|
|
9655
|
+
const lines = triedAndFailed.map((t2) => `- ${t2.tool}(${t2.args}): ${t2.error} (failed ${t2.count}x)`);
|
|
9656
|
+
parts.push(`[Already tried & failed — do NOT repeat:]
|
|
9657
|
+
${lines.join(`
|
|
9658
|
+
`)}`);
|
|
9659
|
+
}
|
|
9416
9660
|
this.compactedBlock = parts.join(" ");
|
|
9417
9661
|
const summary = {
|
|
9418
9662
|
role: "user",
|
|
@@ -9481,6 +9725,8 @@ class ContextManager {
|
|
|
9481
9725
|
this.messages = [];
|
|
9482
9726
|
this.compactedBlock = null;
|
|
9483
9727
|
this.iterationsSinceCompaction = 0;
|
|
9728
|
+
this.compactionCount = 0;
|
|
9729
|
+
this.peakTokens = 0;
|
|
9484
9730
|
}
|
|
9485
9731
|
getEstimatedTokens() {
|
|
9486
9732
|
return this.messages.reduce((sum, m) => sum + this.estimateMessageTokens(m), 0);
|
|
@@ -10999,7 +11245,7 @@ ${JSON.stringify(result, null, 2)}`
|
|
|
10999
11245
|
|
|
11000
11246
|
// src/tools/search-history.ts
|
|
11001
11247
|
import * as fs from "fs";
|
|
11002
|
-
import { join as
|
|
11248
|
+
import { join as join11 } from "path";
|
|
11003
11249
|
import { homedir as homedir5 } from "os";
|
|
11004
11250
|
function searchFile(filePath, query, maxResults, results) {
|
|
11005
11251
|
if (!fs.existsSync(filePath))
|
|
@@ -11037,7 +11283,7 @@ var init_search_history = __esm(() => {
|
|
|
11037
11283
|
const query = String(args.query || "").toLowerCase();
|
|
11038
11284
|
const maxResults = Number(args.maxResults) || 5;
|
|
11039
11285
|
const sessionId = args.sessionId ? String(args.sessionId) : null;
|
|
11040
|
-
const sessionDir =
|
|
11286
|
+
const sessionDir = join11(homedir5(), ".mma", "sessions");
|
|
11041
11287
|
const results = [];
|
|
11042
11288
|
try {
|
|
11043
11289
|
if (!fs.existsSync(sessionDir)) {
|
|
@@ -11049,7 +11295,7 @@ var init_search_history = __esm(() => {
|
|
|
11049
11295
|
continue;
|
|
11050
11296
|
if (sessionId && entry.name !== sessionId)
|
|
11051
11297
|
continue;
|
|
11052
|
-
const historyFile =
|
|
11298
|
+
const historyFile = join11(sessionDir, entry.name, "history.jsonl");
|
|
11053
11299
|
searchFile(historyFile, query, maxResults, results);
|
|
11054
11300
|
if (results.length >= maxResults)
|
|
11055
11301
|
break;
|
|
@@ -11066,127 +11312,9 @@ var init_search_history = __esm(() => {
|
|
|
11066
11312
|
};
|
|
11067
11313
|
});
|
|
11068
11314
|
|
|
11069
|
-
// src/modules/memory/search.ts
|
|
11070
|
-
import { readFileSync as readFileSync10, existsSync as existsSync19 } from "fs";
|
|
11071
|
-
import { join as join9 } from "path";
|
|
11072
|
-
|
|
11073
|
-
class MemorySearch {
|
|
11074
|
-
memoryDir;
|
|
11075
|
-
constructor(memoryDir) {
|
|
11076
|
-
this.memoryDir = memoryDir;
|
|
11077
|
-
}
|
|
11078
|
-
query(query) {
|
|
11079
|
-
const results = [];
|
|
11080
|
-
const lowerQuery = query.toLowerCase();
|
|
11081
|
-
for (const name of MEMORY_FILES) {
|
|
11082
|
-
const path = join9(this.memoryDir, `${name}.md`);
|
|
11083
|
-
if (!existsSync19(path))
|
|
11084
|
-
continue;
|
|
11085
|
-
const content = readFileSync10(path, "utf-8");
|
|
11086
|
-
const lines = content.split(`
|
|
11087
|
-
`);
|
|
11088
|
-
for (const line of lines) {
|
|
11089
|
-
if (line.toLowerCase().includes(lowerQuery)) {
|
|
11090
|
-
results.push({ file: name, match: line.trim() });
|
|
11091
|
-
}
|
|
11092
|
-
}
|
|
11093
|
-
}
|
|
11094
|
-
const prefsPath = join9(this.memoryDir, "preferences.json");
|
|
11095
|
-
if (existsSync19(prefsPath)) {
|
|
11096
|
-
try {
|
|
11097
|
-
const prefs = JSON.parse(readFileSync10(prefsPath, "utf-8"));
|
|
11098
|
-
for (const [key, value] of Object.entries(prefs)) {
|
|
11099
|
-
const searchStr = `${key}=${value}`;
|
|
11100
|
-
if (searchStr.toLowerCase().includes(lowerQuery)) {
|
|
11101
|
-
results.push({ file: "preferences", match: `${key} = ${value}` });
|
|
11102
|
-
}
|
|
11103
|
-
}
|
|
11104
|
-
} catch {}
|
|
11105
|
-
}
|
|
11106
|
-
return results;
|
|
11107
|
-
}
|
|
11108
|
-
}
|
|
11109
|
-
var MEMORY_FILES;
|
|
11110
|
-
var init_search = __esm(() => {
|
|
11111
|
-
MEMORY_FILES = ["conventions", "decisions", "errors", "facts"];
|
|
11112
|
-
});
|
|
11113
|
-
|
|
11114
|
-
// src/modules/memory/store.ts
|
|
11115
|
-
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, appendFileSync as appendFileSync4, existsSync as existsSync20, mkdirSync as mkdirSync10 } from "fs";
|
|
11116
|
-
import { join as join10 } from "path";
|
|
11117
|
-
|
|
11118
|
-
class MemoryStore {
|
|
11119
|
-
memoryDir;
|
|
11120
|
-
constructor(memoryDir) {
|
|
11121
|
-
this.memoryDir = memoryDir;
|
|
11122
|
-
this.ensureDir();
|
|
11123
|
-
for (const name of MEMORY_FILES2) {
|
|
11124
|
-
const path = join10(this.memoryDir, `${name}.md`);
|
|
11125
|
-
if (!existsSync20(path)) {
|
|
11126
|
-
writeFileSync8(path, `# ${name.charAt(0).toUpperCase() + name.slice(1)}
|
|
11127
|
-
|
|
11128
|
-
`, "utf-8");
|
|
11129
|
-
}
|
|
11130
|
-
}
|
|
11131
|
-
}
|
|
11132
|
-
ensureDir() {
|
|
11133
|
-
if (!existsSync20(this.memoryDir)) {
|
|
11134
|
-
mkdirSync10(this.memoryDir, { recursive: true });
|
|
11135
|
-
}
|
|
11136
|
-
}
|
|
11137
|
-
read(name) {
|
|
11138
|
-
const path = join10(this.memoryDir, `${name}.md`);
|
|
11139
|
-
if (!existsSync20(path))
|
|
11140
|
-
return "";
|
|
11141
|
-
return readFileSync11(path, "utf-8");
|
|
11142
|
-
}
|
|
11143
|
-
append(name, entry) {
|
|
11144
|
-
const path = join10(this.memoryDir, `${name}.md`);
|
|
11145
|
-
const timestamp = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
11146
|
-
const formatted = `- **${timestamp}** — ${entry}
|
|
11147
|
-
`;
|
|
11148
|
-
appendFileSync4(path, formatted, "utf-8");
|
|
11149
|
-
}
|
|
11150
|
-
search(query) {
|
|
11151
|
-
const searchModule = new MemorySearch(this.memoryDir);
|
|
11152
|
-
return searchModule.query(query);
|
|
11153
|
-
}
|
|
11154
|
-
prefsPath() {
|
|
11155
|
-
return join10(this.memoryDir, "preferences.json");
|
|
11156
|
-
}
|
|
11157
|
-
getPreferences() {
|
|
11158
|
-
const path = this.prefsPath();
|
|
11159
|
-
if (!existsSync20(path))
|
|
11160
|
-
return {};
|
|
11161
|
-
try {
|
|
11162
|
-
return JSON.parse(readFileSync11(path, "utf-8"));
|
|
11163
|
-
} catch {
|
|
11164
|
-
return {};
|
|
11165
|
-
}
|
|
11166
|
-
}
|
|
11167
|
-
setPreference(key, value) {
|
|
11168
|
-
const prefs = this.getPreferences();
|
|
11169
|
-
prefs[key] = value;
|
|
11170
|
-
writeFileSync8(this.prefsPath(), JSON.stringify(prefs, null, 2), "utf-8");
|
|
11171
|
-
}
|
|
11172
|
-
deletePreference(key) {
|
|
11173
|
-
const prefs = this.getPreferences();
|
|
11174
|
-
if (!(key in prefs))
|
|
11175
|
-
return false;
|
|
11176
|
-
delete prefs[key];
|
|
11177
|
-
writeFileSync8(this.prefsPath(), JSON.stringify(prefs, null, 2), "utf-8");
|
|
11178
|
-
return true;
|
|
11179
|
-
}
|
|
11180
|
-
}
|
|
11181
|
-
var MEMORY_FILES2;
|
|
11182
|
-
var init_store = __esm(() => {
|
|
11183
|
-
init_search();
|
|
11184
|
-
MEMORY_FILES2 = ["conventions", "decisions", "errors", "facts"];
|
|
11185
|
-
});
|
|
11186
|
-
|
|
11187
11315
|
// src/tools/remember.ts
|
|
11188
11316
|
import { homedir as homedir6 } from "os";
|
|
11189
|
-
import { join as
|
|
11317
|
+
import { join as join12 } from "path";
|
|
11190
11318
|
var CATEGORIES, rememberTool;
|
|
11191
11319
|
var init_remember = __esm(() => {
|
|
11192
11320
|
init_i18n();
|
|
@@ -11224,7 +11352,7 @@ var init_remember = __esm(() => {
|
|
|
11224
11352
|
if (!CATEGORIES.includes(category)) {
|
|
11225
11353
|
return { success: false, output: t("tool.invalid_params") };
|
|
11226
11354
|
}
|
|
11227
|
-
const memoryDir =
|
|
11355
|
+
const memoryDir = join12(homedir6(), ".mma", "memory");
|
|
11228
11356
|
const store = new MemoryStore(memoryDir);
|
|
11229
11357
|
try {
|
|
11230
11358
|
if (category === "preferences") {
|
|
@@ -11257,7 +11385,7 @@ var init_remember = __esm(() => {
|
|
|
11257
11385
|
|
|
11258
11386
|
// src/tools/recall.ts
|
|
11259
11387
|
import { homedir as homedir7 } from "os";
|
|
11260
|
-
import { join as
|
|
11388
|
+
import { join as join13 } from "path";
|
|
11261
11389
|
function formatAll(store) {
|
|
11262
11390
|
const parts = [];
|
|
11263
11391
|
const prefs = store.getPreferences();
|
|
@@ -11340,7 +11468,7 @@ var init_recall = __esm(() => {
|
|
|
11340
11468
|
handler: async (_ctx, args) => {
|
|
11341
11469
|
const query = args.query ? String(args.query) : "";
|
|
11342
11470
|
const category = args.category ? String(args.category) : "";
|
|
11343
|
-
const memoryDir =
|
|
11471
|
+
const memoryDir = join13(homedir7(), ".mma", "memory");
|
|
11344
11472
|
const store = new MemoryStore(memoryDir);
|
|
11345
11473
|
try {
|
|
11346
11474
|
if (!query && !category) {
|
|
@@ -11536,15 +11664,15 @@ function buildIndexInjectionScript() {
|
|
|
11536
11664
|
|
|
11537
11665
|
// src/modules/browser/cookie-store.ts
|
|
11538
11666
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
11539
|
-
import { join as
|
|
11667
|
+
import { join as join14 } from "path";
|
|
11540
11668
|
|
|
11541
11669
|
class CookieStore {
|
|
11542
11670
|
filePath;
|
|
11543
11671
|
constructor(cookieDir) {
|
|
11544
|
-
this.filePath =
|
|
11672
|
+
this.filePath = join14(cookieDir, "cookies.json");
|
|
11545
11673
|
}
|
|
11546
11674
|
async save(cookies) {
|
|
11547
|
-
await mkdir(
|
|
11675
|
+
await mkdir(join14(this.filePath, ".."), { recursive: true });
|
|
11548
11676
|
await writeFile(this.filePath, JSON.stringify(cookies, null, 2), "utf-8");
|
|
11549
11677
|
}
|
|
11550
11678
|
async load() {
|
|
@@ -11864,10 +11992,10 @@ var init_types = __esm(() => {
|
|
|
11864
11992
|
});
|
|
11865
11993
|
|
|
11866
11994
|
// src/tools/browser.ts
|
|
11867
|
-
import { join as
|
|
11995
|
+
import { join as join15 } from "path";
|
|
11868
11996
|
function getSession(ctx) {
|
|
11869
11997
|
if (!session) {
|
|
11870
|
-
const cookieDir =
|
|
11998
|
+
const cookieDir = join15(ctx.baseDir, ".mma", "browser");
|
|
11871
11999
|
session = new BrowserSession({
|
|
11872
12000
|
...DEFAULT_BROWSER_CONFIG,
|
|
11873
12001
|
headless: ctx.config.browser?.headless ?? true,
|
|
@@ -11997,8 +12125,8 @@ async function readClipboardFallback() {
|
|
|
11997
12125
|
const { platform: platform4 } = await import("os");
|
|
11998
12126
|
const { execSync: execSync3 } = await import("child_process");
|
|
11999
12127
|
const { readFileSync: readFileSync13, unlinkSync: unlinkSync3 } = await import("fs");
|
|
12000
|
-
const { join:
|
|
12001
|
-
const tmpPath =
|
|
12128
|
+
const { join: join16 } = await import("path");
|
|
12129
|
+
const tmpPath = join16(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
|
|
12002
12130
|
try {
|
|
12003
12131
|
if (platform4() === "linux") {
|
|
12004
12132
|
execSync3(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, { timeout: 5000 });
|
|
@@ -12276,7 +12404,7 @@ class ModuleRegistry {
|
|
|
12276
12404
|
|
|
12277
12405
|
// src/modules/plugins/loader.ts
|
|
12278
12406
|
import { readdirSync as readdirSync5, existsSync as existsSync22, statSync as statSync4 } from "fs";
|
|
12279
|
-
import { join as
|
|
12407
|
+
import { join as join16 } from "path";
|
|
12280
12408
|
|
|
12281
12409
|
class PluginLoader {
|
|
12282
12410
|
loadFromDir(dirPath, pluginManager, logger) {
|
|
@@ -12284,7 +12412,7 @@ class PluginLoader {
|
|
|
12284
12412
|
return;
|
|
12285
12413
|
const entries = readdirSync5(dirPath);
|
|
12286
12414
|
for (const entry of entries) {
|
|
12287
|
-
const fullPath =
|
|
12415
|
+
const fullPath = join16(dirPath, entry);
|
|
12288
12416
|
if (!statSync4(fullPath).isFile())
|
|
12289
12417
|
continue;
|
|
12290
12418
|
if (!entry.endsWith(".ts") && !entry.endsWith(".js"))
|
|
@@ -12309,7 +12437,7 @@ var init_loader = __esm(() => {
|
|
|
12309
12437
|
// src/modules/plugins/builtin/lint-on-write.ts
|
|
12310
12438
|
import { execSync as execSync3 } from "child_process";
|
|
12311
12439
|
import { existsSync as existsSync23, readFileSync as readFileSync13 } from "fs";
|
|
12312
|
-
import { resolve as resolve12, extname as extname4, join as
|
|
12440
|
+
import { resolve as resolve12, extname as extname4, join as join17 } from "path";
|
|
12313
12441
|
|
|
12314
12442
|
class LintOnWritePlugin {
|
|
12315
12443
|
name = "lint-on-write";
|
|
@@ -12371,7 +12499,7 @@ class LintOnWritePlugin {
|
|
|
12371
12499
|
}
|
|
12372
12500
|
async runProjectLint(ctx, result) {
|
|
12373
12501
|
try {
|
|
12374
|
-
const packageJsonPath =
|
|
12502
|
+
const packageJsonPath = join17(ctx.baseDir, "package.json");
|
|
12375
12503
|
if (!existsSync23(packageJsonPath)) {
|
|
12376
12504
|
return;
|
|
12377
12505
|
}
|
|
@@ -12391,7 +12519,7 @@ class LintOnWritePlugin {
|
|
|
12391
12519
|
}
|
|
12392
12520
|
}
|
|
12393
12521
|
async runProjectTypeCheck(ctx, result) {
|
|
12394
|
-
const tsconfigPath =
|
|
12522
|
+
const tsconfigPath = join17(ctx.baseDir, "tsconfig.json");
|
|
12395
12523
|
if (!existsSync23(tsconfigPath)) {
|
|
12396
12524
|
return;
|
|
12397
12525
|
}
|
|
@@ -12580,6 +12708,11 @@ class StuckDetector {
|
|
|
12580
12708
|
repetitionThreshold = 3;
|
|
12581
12709
|
consecutiveFailures = 0;
|
|
12582
12710
|
lastFailedTool = "";
|
|
12711
|
+
lastErrorOutput = "";
|
|
12712
|
+
escalationCount = 0;
|
|
12713
|
+
escalationThreshold = 3;
|
|
12714
|
+
fileRewriteCount = new Map;
|
|
12715
|
+
fileRewriteThreshold = 3;
|
|
12583
12716
|
constructor(threshold = 8, errorThreshold = 3) {
|
|
12584
12717
|
this.threshold = threshold;
|
|
12585
12718
|
this.errorThreshold = errorThreshold;
|
|
@@ -12599,14 +12732,26 @@ class StuckDetector {
|
|
|
12599
12732
|
this.recentToolCalls.shift();
|
|
12600
12733
|
}
|
|
12601
12734
|
}
|
|
12602
|
-
recordToolError(toolName) {
|
|
12735
|
+
recordToolError(toolName, output) {
|
|
12603
12736
|
this.toolErrors.set(toolName, (this.toolErrors.get(toolName) || 0) + 1);
|
|
12604
12737
|
this.consecutiveFailures++;
|
|
12605
12738
|
this.lastFailedTool = toolName;
|
|
12739
|
+
if (output)
|
|
12740
|
+
this.lastErrorOutput = output;
|
|
12741
|
+
}
|
|
12742
|
+
getLastErrorOutput() {
|
|
12743
|
+
return this.lastErrorOutput;
|
|
12744
|
+
}
|
|
12745
|
+
getLastFailedTool() {
|
|
12746
|
+
return this.lastFailedTool;
|
|
12747
|
+
}
|
|
12748
|
+
getIterationsOnCurrentStep() {
|
|
12749
|
+
return this.iterationsOnCurrentStep;
|
|
12606
12750
|
}
|
|
12607
12751
|
recordToolSuccess() {
|
|
12608
12752
|
this.consecutiveFailures = 0;
|
|
12609
12753
|
this.lastFailedTool = "";
|
|
12754
|
+
this.escalationCount = 0;
|
|
12610
12755
|
}
|
|
12611
12756
|
setCurrentStep(stepId, description) {
|
|
12612
12757
|
if (stepId !== this.currentStepId) {
|
|
@@ -12644,6 +12789,117 @@ class StuckDetector {
|
|
|
12644
12789
|
getConsecutiveFailuresCount() {
|
|
12645
12790
|
return this.consecutiveFailures;
|
|
12646
12791
|
}
|
|
12792
|
+
recordEscalation() {
|
|
12793
|
+
this.escalationCount++;
|
|
12794
|
+
}
|
|
12795
|
+
shouldEscalate() {
|
|
12796
|
+
return this.escalationCount >= this.escalationThreshold;
|
|
12797
|
+
}
|
|
12798
|
+
resetEscalation() {
|
|
12799
|
+
this.escalationCount = 0;
|
|
12800
|
+
}
|
|
12801
|
+
getEscalationCount() {
|
|
12802
|
+
return this.escalationCount;
|
|
12803
|
+
}
|
|
12804
|
+
getHints() {
|
|
12805
|
+
const hints = [];
|
|
12806
|
+
const desc = this.currentStepDescription.toLowerCase();
|
|
12807
|
+
if (desc.includes("install") || desc.includes("npm") || desc.includes("pip")) {
|
|
12808
|
+
hints.push("Check if a lock file exists (package-lock.json, poetry.lock). If missing, run the install command first.");
|
|
12809
|
+
}
|
|
12810
|
+
if (desc.includes("test") || desc.includes("spec")) {
|
|
12811
|
+
hints.push("Make sure the source files exist and have real code before running tests.");
|
|
12812
|
+
}
|
|
12813
|
+
if (desc.includes("build") || desc.includes("compile")) {
|
|
12814
|
+
hints.push("Check that all dependencies are installed and source files are not empty.");
|
|
12815
|
+
}
|
|
12816
|
+
if (desc.includes("deploy") || desc.includes("publish")) {
|
|
12817
|
+
hints.push("Verify credentials and network access before deploying.");
|
|
12818
|
+
}
|
|
12819
|
+
if (this.hasRepetitiveToolCalls()) {
|
|
12820
|
+
hints.push("You are calling the same tool repeatedly with the same arguments. Try a different approach.");
|
|
12821
|
+
}
|
|
12822
|
+
if (this.hasConsecutiveFailures()) {
|
|
12823
|
+
hints.push("Multiple different tools are failing. Check if the environment is set up correctly.");
|
|
12824
|
+
}
|
|
12825
|
+
return hints;
|
|
12826
|
+
}
|
|
12827
|
+
getActionableHints() {
|
|
12828
|
+
const hints = [];
|
|
12829
|
+
const error = this.lastErrorOutput;
|
|
12830
|
+
if (!error)
|
|
12831
|
+
return hints;
|
|
12832
|
+
if (/Cannot read properties of undefined|is not a function|is not a constructor/i.test(error)) {
|
|
12833
|
+
if (/node_modules/.test(error)) {
|
|
12834
|
+
hints.push("A dependency is incompatible with your Node.js version. Check if there is an alternative package or use a different runtime.");
|
|
12835
|
+
}
|
|
12836
|
+
}
|
|
12837
|
+
if (/TS1005|TS1003|TS1109|TS1128|TS1434/i.test(error)) {
|
|
12838
|
+
hints.push("TypeScript syntax error. Read the error message carefully — it tells you the exact line and column. Fix the syntax before retrying.");
|
|
12839
|
+
}
|
|
12840
|
+
if (/TS2322|TS2345|TS2769|TS7006|TS7016/i.test(error)) {
|
|
12841
|
+
hints.push("TypeScript type mismatch. Check the type signature of the function/API you are using. If a package lacks type declarations, install @types/<package> or use skipLibCheck.");
|
|
12842
|
+
}
|
|
12843
|
+
if (/Cannot find module|Module not found|ERR_MODULE_NOT_FOUND/i.test(error)) {
|
|
12844
|
+
hints.push("Module not found. Run npm install or check if the import path is correct.");
|
|
12845
|
+
}
|
|
12846
|
+
if (/EACCES|EPERM|permission denied/i.test(error)) {
|
|
12847
|
+
hints.push("Permission denied. Check file permissions or run with appropriate privileges.");
|
|
12848
|
+
}
|
|
12849
|
+
if (/ECONNREFUSED|ETIMEDOUT|ENOTFOUND|fetch failed/i.test(error)) {
|
|
12850
|
+
hints.push("Network error. Check if the server is running and accessible.");
|
|
12851
|
+
}
|
|
12852
|
+
if (/is not recognized|command not found|not found in path/i.test(error)) {
|
|
12853
|
+
hints.push("Command not found. Check if the tool is installed and in PATH.");
|
|
12854
|
+
}
|
|
12855
|
+
if (this.hasExcessiveRewrites()) {
|
|
12856
|
+
const file = this.getExcessiveRewriteFile();
|
|
12857
|
+
hints.push(`File ${file} has been rewritten ${this.getFileRewriteCount(file)} times without success. Stop rewriting and try a fundamentally different approach.`);
|
|
12858
|
+
}
|
|
12859
|
+
return hints;
|
|
12860
|
+
}
|
|
12861
|
+
getToolAlternative() {
|
|
12862
|
+
const tool = this.lastFailedTool;
|
|
12863
|
+
const error = this.lastErrorOutput;
|
|
12864
|
+
if (!tool)
|
|
12865
|
+
return null;
|
|
12866
|
+
if (/Cannot read properties of undefined|is not a function|TypeError|ReferenceError/i.test(error)) {
|
|
12867
|
+
const alternatives = {
|
|
12868
|
+
"ts-node": "tsx",
|
|
12869
|
+
jest: "vitest",
|
|
12870
|
+
mocha: "vitest",
|
|
12871
|
+
webpack: "vite",
|
|
12872
|
+
rollup: "vite",
|
|
12873
|
+
parcel: "vite",
|
|
12874
|
+
babel: "tsc",
|
|
12875
|
+
eslint: "biome",
|
|
12876
|
+
prettier: "biome"
|
|
12877
|
+
};
|
|
12878
|
+
for (const [failed, alt] of Object.entries(alternatives)) {
|
|
12879
|
+
if (tool.includes(failed) || error.includes(failed)) {
|
|
12880
|
+
return alt;
|
|
12881
|
+
}
|
|
12882
|
+
}
|
|
12883
|
+
}
|
|
12884
|
+
return null;
|
|
12885
|
+
}
|
|
12886
|
+
recordFileRewrite(filePath) {
|
|
12887
|
+
const count = (this.fileRewriteCount.get(filePath) || 0) + 1;
|
|
12888
|
+
this.fileRewriteCount.set(filePath, count);
|
|
12889
|
+
}
|
|
12890
|
+
getFileRewriteCount(filePath) {
|
|
12891
|
+
return this.fileRewriteCount.get(filePath) || 0;
|
|
12892
|
+
}
|
|
12893
|
+
hasExcessiveRewrites() {
|
|
12894
|
+
return Array.from(this.fileRewriteCount.values()).some((c) => c >= this.fileRewriteThreshold);
|
|
12895
|
+
}
|
|
12896
|
+
getExcessiveRewriteFile() {
|
|
12897
|
+
for (const [file, count] of this.fileRewriteCount) {
|
|
12898
|
+
if (count >= this.fileRewriteThreshold)
|
|
12899
|
+
return file;
|
|
12900
|
+
}
|
|
12901
|
+
return null;
|
|
12902
|
+
}
|
|
12647
12903
|
getRepetitiveToolMessage() {
|
|
12648
12904
|
if (!this.hasRepetitiveToolCalls())
|
|
12649
12905
|
return "";
|
|
@@ -12722,7 +12978,7 @@ var init_stuck_detector = __esm(() => {
|
|
|
12722
12978
|
// src/modules/execution/auditor.ts
|
|
12723
12979
|
import { execSync as execSync4 } from "child_process";
|
|
12724
12980
|
import { existsSync as existsSync24 } from "fs";
|
|
12725
|
-
import { resolve as resolve13, join as
|
|
12981
|
+
import { resolve as resolve13, join as join18 } from "path";
|
|
12726
12982
|
|
|
12727
12983
|
class Auditor {
|
|
12728
12984
|
baseDir;
|
|
@@ -12730,7 +12986,7 @@ class Auditor {
|
|
|
12730
12986
|
this.baseDir = baseDir;
|
|
12731
12987
|
}
|
|
12732
12988
|
async audit(plan) {
|
|
12733
|
-
const allStepText = plan.steps.map((s) => s.description).join(" ");
|
|
12989
|
+
const allStepText = plan.steps.map((s) => s.description.replace(/\([^)]*\)/g, " ")).join(" ");
|
|
12734
12990
|
const fileMatches = allStepText.match(/\b[\w./-]+\.[a-z]+/gi) || [];
|
|
12735
12991
|
const uniqueFiles = [...new Set(fileMatches)];
|
|
12736
12992
|
const missingFiles = [];
|
|
@@ -12746,6 +13002,10 @@ class Auditor {
|
|
|
12746
13002
|
const doneSteps = plan.steps.filter((s) => s.status === "done").length;
|
|
12747
13003
|
const totalSteps = plan.steps.length;
|
|
12748
13004
|
const typeCheckError = await this.runProjectTypeCheck();
|
|
13005
|
+
let massEditWarning = null;
|
|
13006
|
+
if (uniqueFiles.length > MASS_EDIT_THRESHOLD) {
|
|
13007
|
+
massEditWarning = t("exec.mass_edit_warning", { count: String(uniqueFiles.length) });
|
|
13008
|
+
}
|
|
12749
13009
|
const passed = missingFiles.length === 0 && !typeCheckError;
|
|
12750
13010
|
let summary;
|
|
12751
13011
|
if (passed) {
|
|
@@ -12764,11 +13024,12 @@ class Auditor {
|
|
|
12764
13024
|
createdFiles: existingFiles,
|
|
12765
13025
|
modifiedFiles: [],
|
|
12766
13026
|
summary,
|
|
12767
|
-
typeCheckError
|
|
13027
|
+
typeCheckError,
|
|
13028
|
+
massEditWarning
|
|
12768
13029
|
};
|
|
12769
13030
|
}
|
|
12770
13031
|
async runProjectTypeCheck() {
|
|
12771
|
-
const tsconfigPath =
|
|
13032
|
+
const tsconfigPath = join18(this.baseDir, "tsconfig.json");
|
|
12772
13033
|
if (!existsSync24(tsconfigPath)) {
|
|
12773
13034
|
return null;
|
|
12774
13035
|
}
|
|
@@ -12789,22 +13050,23 @@ class Auditor {
|
|
|
12789
13050
|
}
|
|
12790
13051
|
}
|
|
12791
13052
|
}
|
|
13053
|
+
var MASS_EDIT_THRESHOLD = 10;
|
|
12792
13054
|
var init_auditor = __esm(() => {
|
|
12793
13055
|
init_i18n();
|
|
12794
13056
|
});
|
|
12795
13057
|
|
|
12796
13058
|
// src/modules/execution/plan-persister.ts
|
|
12797
13059
|
import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11, existsSync as existsSync25 } from "fs";
|
|
12798
|
-
import { join as
|
|
13060
|
+
import { join as join19 } from "path";
|
|
12799
13061
|
|
|
12800
13062
|
class PlanPersister {
|
|
12801
13063
|
filePath;
|
|
12802
13064
|
constructor(baseDir) {
|
|
12803
|
-
const mmaDir =
|
|
13065
|
+
const mmaDir = join19(baseDir, ".mma");
|
|
12804
13066
|
if (!existsSync25(mmaDir)) {
|
|
12805
13067
|
mkdirSync11(mmaDir, { recursive: true });
|
|
12806
13068
|
}
|
|
12807
|
-
this.filePath =
|
|
13069
|
+
this.filePath = join19(mmaDir, "plan.json");
|
|
12808
13070
|
}
|
|
12809
13071
|
save(plan) {
|
|
12810
13072
|
const file = {
|
|
@@ -12842,6 +13104,92 @@ class PlanPersister {
|
|
|
12842
13104
|
}
|
|
12843
13105
|
var init_plan_persister = () => {};
|
|
12844
13106
|
|
|
13107
|
+
// src/modules/execution/plan-coverage.ts
|
|
13108
|
+
function extractFilePaths(text) {
|
|
13109
|
+
if (!text)
|
|
13110
|
+
return [];
|
|
13111
|
+
const seen = new Set;
|
|
13112
|
+
const result = [];
|
|
13113
|
+
for (const m of text.matchAll(FILE_PATH_RE)) {
|
|
13114
|
+
let p = m[0];
|
|
13115
|
+
p = p.replace(/[.,;:)\]>]+$/g, "");
|
|
13116
|
+
const ext = p.split(".").pop()?.toLowerCase() ?? "";
|
|
13117
|
+
if (!p || IGNORED_EXT.has(ext))
|
|
13118
|
+
continue;
|
|
13119
|
+
const key = p.toLowerCase();
|
|
13120
|
+
if (seen.has(key))
|
|
13121
|
+
continue;
|
|
13122
|
+
seen.add(key);
|
|
13123
|
+
result.push(p);
|
|
13124
|
+
}
|
|
13125
|
+
return result;
|
|
13126
|
+
}
|
|
13127
|
+
function basename2(p) {
|
|
13128
|
+
const parts = p.split(/[/\\]/);
|
|
13129
|
+
return parts[parts.length - 1] ?? p;
|
|
13130
|
+
}
|
|
13131
|
+
function checkPlanCoverage(taskText, stepDescriptions) {
|
|
13132
|
+
const taskPaths = extractFilePaths(taskText);
|
|
13133
|
+
if (taskPaths.length === 0)
|
|
13134
|
+
return { missing: [] };
|
|
13135
|
+
const stepText = stepDescriptions.map((s) => s.toLowerCase()).join(`
|
|
13136
|
+
`);
|
|
13137
|
+
const missing = taskPaths.filter((p) => {
|
|
13138
|
+
const lower = p.toLowerCase();
|
|
13139
|
+
const base = basename2(lower);
|
|
13140
|
+
return !stepText.includes(lower) && !stepText.includes(base);
|
|
13141
|
+
});
|
|
13142
|
+
return { missing };
|
|
13143
|
+
}
|
|
13144
|
+
var FILE_PATH_RE, IGNORED_EXT;
|
|
13145
|
+
var init_plan_coverage = __esm(() => {
|
|
13146
|
+
FILE_PATH_RE = /\b[\w./\\-]+\.[a-z]+\b/gi;
|
|
13147
|
+
IGNORED_EXT = new Set([
|
|
13148
|
+
"tsx",
|
|
13149
|
+
"jsx",
|
|
13150
|
+
"json5",
|
|
13151
|
+
"mdx",
|
|
13152
|
+
"yml",
|
|
13153
|
+
"yaml",
|
|
13154
|
+
"toml",
|
|
13155
|
+
"lock",
|
|
13156
|
+
"svg",
|
|
13157
|
+
"png",
|
|
13158
|
+
"jpg",
|
|
13159
|
+
"jpeg",
|
|
13160
|
+
"gif",
|
|
13161
|
+
"webp",
|
|
13162
|
+
"ico",
|
|
13163
|
+
"css",
|
|
13164
|
+
"scss",
|
|
13165
|
+
"less",
|
|
13166
|
+
"html",
|
|
13167
|
+
"jsx"
|
|
13168
|
+
]);
|
|
13169
|
+
});
|
|
13170
|
+
|
|
13171
|
+
// src/modules/skills/error-skill-map.ts
|
|
13172
|
+
function suggestSkill(errorOutput) {
|
|
13173
|
+
for (const { pattern, skill } of ERROR_SKILL_MAP) {
|
|
13174
|
+
if (pattern.test(errorOutput))
|
|
13175
|
+
return skill;
|
|
13176
|
+
}
|
|
13177
|
+
return null;
|
|
13178
|
+
}
|
|
13179
|
+
var ERROR_SKILL_MAP;
|
|
13180
|
+
var init_error_skill_map = __esm(() => {
|
|
13181
|
+
ERROR_SKILL_MAP = [
|
|
13182
|
+
{ pattern: /TS\d{4}:/i, skill: "typescript-expert" },
|
|
13183
|
+
{ pattern: /Cannot find name|No overload matches/i, skill: "typescript-type-expert" },
|
|
13184
|
+
{ pattern: /ts-node|tsx.*error/i, skill: "typescript-expert" },
|
|
13185
|
+
{ pattern: /Module not found|Cannot resolve module/i, skill: "typescript-expert" },
|
|
13186
|
+
{ pattern: /ECONNREFUSED|ETIMEDOUT|fetch failed/i, skill: "devops-expert" },
|
|
13187
|
+
{ pattern: /permission denied|EACCES/i, skill: "linux-server-expert" },
|
|
13188
|
+
{ pattern: /docker|container/i, skill: "docker-expert" },
|
|
13189
|
+
{ pattern: /jest|vitest|test.*fail/i, skill: "vitest-testing-expert" }
|
|
13190
|
+
];
|
|
13191
|
+
});
|
|
13192
|
+
|
|
12845
13193
|
// src/modules/execution/module.ts
|
|
12846
13194
|
import { existsSync as existsSync26, readFileSync as readFileSync15 } from "fs";
|
|
12847
13195
|
import { resolve as resolve14 } from "path";
|
|
@@ -12951,10 +13299,25 @@ Write CONCRETE steps with exact file paths and commands:
|
|
|
12951
13299
|
const plan = PlanCreator.createPlan(title, steps, this.baseDir);
|
|
12952
13300
|
this.setPlan(plan);
|
|
12953
13301
|
const display = PlanCreator.toPromptBlock(plan, 0);
|
|
13302
|
+
let output = t("plan.created", { title, steps: String(steps.length) });
|
|
13303
|
+
let displayOut = display;
|
|
13304
|
+
const taskText = this.getTaskText(_ctx);
|
|
13305
|
+
if (taskText) {
|
|
13306
|
+
const { missing } = checkPlanCoverage(taskText, steps);
|
|
13307
|
+
if (missing.length > 0) {
|
|
13308
|
+
const warn = t("plan.coverage_warning", {
|
|
13309
|
+
missing: missing.join(", ")
|
|
13310
|
+
});
|
|
13311
|
+
output += `
|
|
13312
|
+
⚠️ ${warn}`;
|
|
13313
|
+
displayOut = `${display}
|
|
13314
|
+
⚠️ ${warn}`;
|
|
13315
|
+
}
|
|
13316
|
+
}
|
|
12954
13317
|
return {
|
|
12955
13318
|
success: true,
|
|
12956
|
-
output
|
|
12957
|
-
display
|
|
13319
|
+
output,
|
|
13320
|
+
display: displayOut
|
|
12958
13321
|
};
|
|
12959
13322
|
}
|
|
12960
13323
|
if (action === "show") {
|
|
@@ -13100,12 +13463,47 @@ Sub-tasks: ${note}`
|
|
|
13100
13463
|
if (currentIter - this.lastRecoveryIteration >= STUCK_RECOVERY_COOLDOWN) {
|
|
13101
13464
|
const recovery = this.stuckDetector.getRecoveryMessage();
|
|
13102
13465
|
if (recovery && ctx.contextManager) {
|
|
13466
|
+
const lastError = this.stuckDetector.getLastErrorOutput();
|
|
13467
|
+
const suggestedSkill = suggestSkill(lastError);
|
|
13468
|
+
const skillHint = suggestedSkill ? `
|
|
13469
|
+
Consider loading the "${suggestedSkill}" skill for expert guidance on this error.` : "";
|
|
13470
|
+
const actionableHints = this.stuckDetector.getActionableHints();
|
|
13471
|
+
const actionableHintStr = actionableHints.length > 0 ? `
|
|
13472
|
+
${t("exec.hints", { hints: actionableHints.map((h) => `- ${h}`).join(`
|
|
13473
|
+
`) })}` : "";
|
|
13474
|
+
const alternative = this.stuckDetector.getToolAlternative();
|
|
13475
|
+
const altHint = alternative ? `
|
|
13476
|
+
Tool "${this.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}" instead.` : "";
|
|
13477
|
+
ctx.contextManager.addMessage({
|
|
13478
|
+
role: "user",
|
|
13479
|
+
content: `<system-summary>${recovery}${skillHint}${actionableHintStr}${altHint}</system-summary>`
|
|
13480
|
+
});
|
|
13481
|
+
}
|
|
13482
|
+
const hints = this.stuckDetector.getHints();
|
|
13483
|
+
if (hints.length > 0 && ctx.contextManager) {
|
|
13484
|
+
const hintMsg = t("exec.hints", { hints: hints.map((h) => `- ${h}`).join(`
|
|
13485
|
+
`) });
|
|
13103
13486
|
ctx.contextManager.addMessage({
|
|
13104
13487
|
role: "user",
|
|
13105
|
-
content: `<system-summary>${
|
|
13488
|
+
content: `<system-summary>${hintMsg}</system-summary>`
|
|
13106
13489
|
});
|
|
13107
13490
|
}
|
|
13491
|
+
this.stuckDetector.recordEscalation();
|
|
13108
13492
|
this.lastRecoveryIteration = currentIter;
|
|
13493
|
+
if (this.stuckDetector.shouldEscalate() && ctx.onMeta) {
|
|
13494
|
+
const escalation = t("exec.escalation", {
|
|
13495
|
+
stepId: String(this.tracker?.getCurrentStep()?.id ?? "?"),
|
|
13496
|
+
description: this.tracker?.getCurrentStep()?.description ?? ""
|
|
13497
|
+
});
|
|
13498
|
+
ctx.onMeta(escalation);
|
|
13499
|
+
}
|
|
13500
|
+
if (this.stuckDetector.getIterationsOnCurrentStep() >= FORCE_SKIP_THRESHOLD && ctx.contextManager) {
|
|
13501
|
+
const step2 = this.tracker?.getCurrentStep();
|
|
13502
|
+
ctx.contextManager.addMessage({
|
|
13503
|
+
role: "user",
|
|
13504
|
+
content: `<system-summary>CRITICAL: You have been stuck on step ${step2?.id ?? "?"} ("${step2?.description ?? ""}") for ${this.stuckDetector.getIterationsOnCurrentStep()} iterations. You MUST stop trying the same approach. Options: 1) Skip this step via plan update step=${step2?.id ?? "?"} status=skipped with a note explaining why. 2) Mark the step as done if the code runs correctly, even if there are type errors. 3) Try a completely different approach. Do NOT continue with the current approach.</system-summary>`
|
|
13505
|
+
});
|
|
13506
|
+
}
|
|
13109
13507
|
}
|
|
13110
13508
|
}
|
|
13111
13509
|
},
|
|
@@ -13138,11 +13536,44 @@ Sub-tasks: ${note}`
|
|
|
13138
13536
|
},
|
|
13139
13537
|
onAfterTool: (ctx, call, result) => {
|
|
13140
13538
|
if (!result.success) {
|
|
13141
|
-
this.stuckDetector.recordToolError(call.name);
|
|
13539
|
+
this.stuckDetector.recordToolError(call.name, result.output);
|
|
13540
|
+
const actionableHints = this.stuckDetector.getActionableHints();
|
|
13541
|
+
const alternative = this.stuckDetector.getToolAlternative();
|
|
13542
|
+
if ((actionableHints.length > 0 || alternative) && ctx.contextManager) {
|
|
13543
|
+
const parts = [...actionableHints];
|
|
13544
|
+
if (alternative) {
|
|
13545
|
+
parts.push(`Tool "${call.name}" crashed. Try "${alternative}" instead.`);
|
|
13546
|
+
}
|
|
13547
|
+
ctx.contextManager.addMessage({
|
|
13548
|
+
role: "user",
|
|
13549
|
+
content: `<system-summary>${t("exec.hints", { hints: parts.map((h) => `- ${h}`).join(`
|
|
13550
|
+
`) })}</system-summary>`
|
|
13551
|
+
});
|
|
13552
|
+
}
|
|
13142
13553
|
} else {
|
|
13143
13554
|
this.stuckDetector.recordToolSuccess();
|
|
13555
|
+
if (call.name === "bash" && result.success && ctx.contextManager) {
|
|
13556
|
+
const cmd = String(call.arguments?.command ?? "");
|
|
13557
|
+
if (/node|tsx|ts-node|python|npm\s+(start|test|run)/.test(cmd)) {
|
|
13558
|
+
ctx.contextManager.addMessage({
|
|
13559
|
+
role: "user",
|
|
13560
|
+
content: `<system-summary>The command "${cmd}" completed successfully. If this was testing your code, mark the current step as done via plan update step=N status=done.</system-summary>`
|
|
13561
|
+
});
|
|
13562
|
+
}
|
|
13563
|
+
}
|
|
13144
13564
|
}
|
|
13145
|
-
if (
|
|
13565
|
+
if (result.success && (call.name === "write_file" || call.name === "edit_file")) {
|
|
13566
|
+
const filePath = call.arguments?.path;
|
|
13567
|
+
if (filePath) {
|
|
13568
|
+
this.stuckDetector.recordFileRewrite(filePath);
|
|
13569
|
+
if (this.stuckDetector.hasExcessiveRewrites()) {
|
|
13570
|
+
const file = this.stuckDetector.getExcessiveRewriteFile();
|
|
13571
|
+
const count = this.stuckDetector.getFileRewriteCount(file);
|
|
13572
|
+
if (ctx.onMeta) {
|
|
13573
|
+
ctx.onMeta(t("exec.file_rewrite_warning", { file, count: String(count) }));
|
|
13574
|
+
}
|
|
13575
|
+
}
|
|
13576
|
+
}
|
|
13146
13577
|
this.advancePlanIfStepComplete(ctx.contextManager);
|
|
13147
13578
|
}
|
|
13148
13579
|
}
|
|
@@ -13253,8 +13684,18 @@ Sub-tasks: ${note}`
|
|
|
13253
13684
|
});
|
|
13254
13685
|
}
|
|
13255
13686
|
}
|
|
13687
|
+
getTaskText(ctx) {
|
|
13688
|
+
const manager = ctx?.contextManager;
|
|
13689
|
+
if (!manager)
|
|
13690
|
+
return "";
|
|
13691
|
+
const history = manager.getActiveHistory();
|
|
13692
|
+
const firstUser = history.find((m) => m.role === "user");
|
|
13693
|
+
if (!firstUser)
|
|
13694
|
+
return "";
|
|
13695
|
+
return getMessageText(firstUser.content).trim();
|
|
13696
|
+
}
|
|
13256
13697
|
}
|
|
13257
|
-
var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3;
|
|
13698
|
+
var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3, FORCE_SKIP_THRESHOLD = 15;
|
|
13258
13699
|
var init_module = __esm(() => {
|
|
13259
13700
|
init_i18n();
|
|
13260
13701
|
init_tracker();
|
|
@@ -13262,11 +13703,13 @@ var init_module = __esm(() => {
|
|
|
13262
13703
|
init_stuck_detector();
|
|
13263
13704
|
init_auditor();
|
|
13264
13705
|
init_plan_persister();
|
|
13706
|
+
init_plan_coverage();
|
|
13707
|
+
init_error_skill_map();
|
|
13265
13708
|
});
|
|
13266
13709
|
|
|
13267
13710
|
// src/modules/security/session-encryption.ts
|
|
13268
13711
|
import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, existsSync as existsSync27, readdirSync as readdirSync6, unlinkSync as unlinkSync3 } from "fs";
|
|
13269
|
-
import { join as
|
|
13712
|
+
import { join as join20 } from "path";
|
|
13270
13713
|
import { homedir as homedir8 } from "os";
|
|
13271
13714
|
|
|
13272
13715
|
class SessionFileEncryptor {
|
|
@@ -13275,7 +13718,7 @@ class SessionFileEncryptor {
|
|
|
13275
13718
|
constructor(config) {
|
|
13276
13719
|
this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
|
|
13277
13720
|
this.encryptor = new ConfigEncryptor({
|
|
13278
|
-
keyPath: config?.keyPath ||
|
|
13721
|
+
keyPath: config?.keyPath || join20(homedir8(), ".mma", ".session-encryption-key")
|
|
13279
13722
|
});
|
|
13280
13723
|
}
|
|
13281
13724
|
isEnabled() {
|
|
@@ -13347,7 +13790,7 @@ class SessionFileEncryptor {
|
|
|
13347
13790
|
return;
|
|
13348
13791
|
const files = readdirSync6(sessionDir);
|
|
13349
13792
|
for (const file of files) {
|
|
13350
|
-
const filePath =
|
|
13793
|
+
const filePath = join20(sessionDir, file);
|
|
13351
13794
|
if (existsSync27(filePath) && !file.endsWith(".enc")) {
|
|
13352
13795
|
try {
|
|
13353
13796
|
const content = readFileSync16(filePath, "utf8");
|
|
@@ -13364,7 +13807,7 @@ class SessionFileEncryptor {
|
|
|
13364
13807
|
const files = readdirSync6(sessionDir);
|
|
13365
13808
|
for (const file of files) {
|
|
13366
13809
|
if (file.endsWith(".enc")) {
|
|
13367
|
-
const encFilePath =
|
|
13810
|
+
const encFilePath = join20(sessionDir, file);
|
|
13368
13811
|
const decFilePath = encFilePath.slice(0, -4);
|
|
13369
13812
|
try {
|
|
13370
13813
|
const content = readFileSync16(encFilePath, "utf8");
|
|
@@ -13397,7 +13840,7 @@ import {
|
|
|
13397
13840
|
writeFileSync as writeFileSync11,
|
|
13398
13841
|
appendFileSync as appendFileSync5
|
|
13399
13842
|
} from "fs";
|
|
13400
|
-
import { join as
|
|
13843
|
+
import { join as join21 } from "path";
|
|
13401
13844
|
import { gzipSync } from "zlib";
|
|
13402
13845
|
|
|
13403
13846
|
class SessionStore {
|
|
@@ -13423,16 +13866,16 @@ class SessionStore {
|
|
|
13423
13866
|
mkdirSync12(this.baseDir, { recursive: true });
|
|
13424
13867
|
}
|
|
13425
13868
|
sessionDir(id) {
|
|
13426
|
-
return
|
|
13869
|
+
return join21(this.baseDir, id);
|
|
13427
13870
|
}
|
|
13428
13871
|
metaPath(id) {
|
|
13429
|
-
return
|
|
13872
|
+
return join21(this.sessionDir(id), "meta.json");
|
|
13430
13873
|
}
|
|
13431
13874
|
historyPath(id) {
|
|
13432
|
-
return
|
|
13875
|
+
return join21(this.sessionDir(id), "history.jsonl");
|
|
13433
13876
|
}
|
|
13434
13877
|
sessionLogPath(id) {
|
|
13435
|
-
return
|
|
13878
|
+
return join21(this.sessionDir(id), "session.jsonl");
|
|
13436
13879
|
}
|
|
13437
13880
|
sessionExists(id) {
|
|
13438
13881
|
return existsSync28(this.metaPath(id));
|
|
@@ -13555,7 +13998,7 @@ class SessionStore {
|
|
|
13555
13998
|
if (existsSync28(historyPath)) {
|
|
13556
13999
|
const content = readFileSync17(historyPath, "utf-8");
|
|
13557
14000
|
const compressed = gzipSync(content);
|
|
13558
|
-
const gzPath =
|
|
14001
|
+
const gzPath = join21(this.baseDir, `${session2.id}.jsonl.gz`);
|
|
13559
14002
|
writeFileSync11(gzPath, compressed);
|
|
13560
14003
|
rmSync(historyPath);
|
|
13561
14004
|
}
|
|
@@ -13763,7 +14206,7 @@ class ProfileCompressor {
|
|
|
13763
14206
|
|
|
13764
14207
|
// src/modules/user-profile/profile.ts
|
|
13765
14208
|
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync29, mkdirSync as mkdirSync13 } from "fs";
|
|
13766
|
-
import { join as
|
|
14209
|
+
import { join as join22 } from "path";
|
|
13767
14210
|
import { homedir as homedir9, hostname, platform as platform4, type } from "os";
|
|
13768
14211
|
import { env } from "process";
|
|
13769
14212
|
|
|
@@ -13790,10 +14233,10 @@ class UserProfile {
|
|
|
13790
14233
|
if (!existsSync29(this.profileDir)) {
|
|
13791
14234
|
mkdirSync13(this.profileDir, { recursive: true });
|
|
13792
14235
|
}
|
|
13793
|
-
writeFileSync12(
|
|
14236
|
+
writeFileSync12(join22(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
|
|
13794
14237
|
}
|
|
13795
14238
|
load() {
|
|
13796
|
-
const path =
|
|
14239
|
+
const path = join22(this.profileDir, "profile.json");
|
|
13797
14240
|
if (!existsSync29(path))
|
|
13798
14241
|
return null;
|
|
13799
14242
|
try {
|
|
@@ -13833,7 +14276,7 @@ var init_profile = () => {};
|
|
|
13833
14276
|
|
|
13834
14277
|
// src/modules/skills/loader.ts
|
|
13835
14278
|
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync30, statSync as statSync5 } from "fs";
|
|
13836
|
-
import { join as
|
|
14279
|
+
import { join as join23 } from "path";
|
|
13837
14280
|
|
|
13838
14281
|
class SkillsLoader {
|
|
13839
14282
|
loadFromDir(dirPath) {
|
|
@@ -13846,7 +14289,7 @@ class SkillsLoader {
|
|
|
13846
14289
|
scanDir(dirPath, skills) {
|
|
13847
14290
|
const entries = readdirSync8(dirPath);
|
|
13848
14291
|
for (const entry of entries) {
|
|
13849
|
-
const fullPath =
|
|
14292
|
+
const fullPath = join23(dirPath, entry);
|
|
13850
14293
|
const stat = statSync5(fullPath);
|
|
13851
14294
|
if (stat.isDirectory()) {
|
|
13852
14295
|
this.scanDir(fullPath, skills);
|
|
@@ -14127,7 +14570,7 @@ var init_browser2 = __esm(() => {
|
|
|
14127
14570
|
|
|
14128
14571
|
// src/modules/indexer/walker.ts
|
|
14129
14572
|
import { readdirSync as readdirSync9, readFileSync as readFileSync20, statSync as statSync6, existsSync as existsSync31, watch } from "fs";
|
|
14130
|
-
import { join as
|
|
14573
|
+
import { join as join24, relative, extname as extname5 } from "path";
|
|
14131
14574
|
|
|
14132
14575
|
class Indexer {
|
|
14133
14576
|
baseDir;
|
|
@@ -14165,7 +14608,7 @@ class Indexer {
|
|
|
14165
14608
|
for (const entry of entries) {
|
|
14166
14609
|
if (count >= this.MAX_FILES)
|
|
14167
14610
|
return;
|
|
14168
|
-
const fullPath =
|
|
14611
|
+
const fullPath = join24(dir, entry);
|
|
14169
14612
|
const relPath = relative(this.baseDir, fullPath);
|
|
14170
14613
|
const stat = statSync6(fullPath);
|
|
14171
14614
|
if (stat.isDirectory()) {
|
|
@@ -14229,13 +14672,13 @@ var init_walker = __esm(() => {
|
|
|
14229
14672
|
|
|
14230
14673
|
// src/modules/indexer/cache.ts
|
|
14231
14674
|
import { readFileSync as readFileSync21, writeFileSync as writeFileSync13, existsSync as existsSync32, mkdirSync as mkdirSync14, rmSync as rmSync2 } from "fs";
|
|
14232
|
-
import { join as
|
|
14675
|
+
import { join as join25 } from "path";
|
|
14233
14676
|
|
|
14234
14677
|
class IndexCache {
|
|
14235
14678
|
cachePath;
|
|
14236
14679
|
cache = null;
|
|
14237
14680
|
constructor(cacheDir) {
|
|
14238
|
-
this.cachePath =
|
|
14681
|
+
this.cachePath = join25(cacheDir, "index-cache.json");
|
|
14239
14682
|
}
|
|
14240
14683
|
load() {
|
|
14241
14684
|
if (this.cache)
|
|
@@ -14251,7 +14694,7 @@ class IndexCache {
|
|
|
14251
14694
|
}
|
|
14252
14695
|
save(result) {
|
|
14253
14696
|
this.cache = result;
|
|
14254
|
-
const dir =
|
|
14697
|
+
const dir = join25(this.cachePath, "..");
|
|
14255
14698
|
if (!existsSync32(dir))
|
|
14256
14699
|
mkdirSync14(dir, { recursive: true });
|
|
14257
14700
|
writeFileSync13(this.cachePath, JSON.stringify(result), "utf-8");
|
|
@@ -14616,13 +15059,13 @@ var init_mcp = __esm(() => {
|
|
|
14616
15059
|
|
|
14617
15060
|
// src/modules/memory/module.ts
|
|
14618
15061
|
import { homedir as homedir10 } from "os";
|
|
14619
|
-
import { join as
|
|
15062
|
+
import { join as join26 } from "path";
|
|
14620
15063
|
|
|
14621
15064
|
class MemoryModule {
|
|
14622
15065
|
name = "memory";
|
|
14623
15066
|
store;
|
|
14624
15067
|
constructor(memoryDir) {
|
|
14625
|
-
const dir = memoryDir ||
|
|
15068
|
+
const dir = memoryDir || join26(homedir10(), ".mma", "memory");
|
|
14626
15069
|
this.store = new MemoryStore(dir);
|
|
14627
15070
|
}
|
|
14628
15071
|
getSystemPromptBlock() {
|
|
@@ -14669,7 +15112,7 @@ __export(exports_bootstrap, {
|
|
|
14669
15112
|
bootstrap: () => bootstrap
|
|
14670
15113
|
});
|
|
14671
15114
|
import { homedir as homedir11 } from "os";
|
|
14672
|
-
import { join as
|
|
15115
|
+
import { join as join27, resolve as resolve15 } from "path";
|
|
14673
15116
|
import { existsSync as existsSync33, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "fs";
|
|
14674
15117
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
14675
15118
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
@@ -14704,8 +15147,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
14704
15147
|
`);
|
|
14705
15148
|
}
|
|
14706
15149
|
async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
14707
|
-
const dir = configDir ||
|
|
14708
|
-
const projectConfigPath = projectDir ?
|
|
15150
|
+
const dir = configDir || join27(homedir11(), ".mma");
|
|
15151
|
+
const projectConfigPath = projectDir ? join27(projectDir, ".mmrc") : join27(process.cwd(), ".mmrc");
|
|
14709
15152
|
const config = loadConfig({ configDir: dir, projectConfigPath });
|
|
14710
15153
|
setLocale(config.locale);
|
|
14711
15154
|
try {
|
|
@@ -14715,7 +15158,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14715
15158
|
}
|
|
14716
15159
|
} catch {}
|
|
14717
15160
|
const logger = new Logger(config.logLevel);
|
|
14718
|
-
logger.setLogDir(
|
|
15161
|
+
logger.setLogDir(join27(dir, "logs"));
|
|
14719
15162
|
logger.debug("MMA bootstrap", {
|
|
14720
15163
|
version: config.version,
|
|
14721
15164
|
model: config.model
|
|
@@ -14737,7 +15180,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14737
15180
|
logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
|
|
14738
15181
|
}
|
|
14739
15182
|
}
|
|
14740
|
-
const profile = new UserProfile(
|
|
15183
|
+
const profile = new UserProfile(join27(dir));
|
|
14741
15184
|
profile.load() || profile.collect();
|
|
14742
15185
|
profile.save();
|
|
14743
15186
|
const llmProvider = new OpenAICompatProvider({
|
|
@@ -14749,7 +15192,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14749
15192
|
rateLimits: config.security?.rateLimits
|
|
14750
15193
|
});
|
|
14751
15194
|
const baseDir = projectDir ? resolve15(projectDir) : process.cwd();
|
|
14752
|
-
const projectMapCacheDir =
|
|
15195
|
+
const projectMapCacheDir = join27(baseDir, ".mma");
|
|
14753
15196
|
const indexerModule = new IndexerModule({
|
|
14754
15197
|
baseDir,
|
|
14755
15198
|
cacheDir: projectMapCacheDir
|
|
@@ -14760,9 +15203,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14760
15203
|
logger.warn(`Project indexing failed: ${err.message}`);
|
|
14761
15204
|
}
|
|
14762
15205
|
const skillsLoader = new SkillsLoader;
|
|
14763
|
-
const builtinDir =
|
|
14764
|
-
const globalDir =
|
|
14765
|
-
const projectSkillsDir =
|
|
15206
|
+
const builtinDir = join27(import.meta.dirname, "skills", "builtin");
|
|
15207
|
+
const globalDir = join27(homedir11(), ".agents", "skills");
|
|
15208
|
+
const projectSkillsDir = join27(baseDir, ".mma", "skills");
|
|
14766
15209
|
const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
|
|
14767
15210
|
const skillsMatcher = new SkillsMatcher;
|
|
14768
15211
|
const skillsBudget = Math.floor(config.contextWindow * 0.1);
|
|
@@ -14776,11 +15219,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14776
15219
|
essential: true,
|
|
14777
15220
|
estimatedTokens: 250
|
|
14778
15221
|
};
|
|
14779
|
-
const agentsMdGlobal =
|
|
15222
|
+
const agentsMdGlobal = join27(dir, "AGENTS.md");
|
|
14780
15223
|
if (!existsSync33(agentsMdGlobal)) {
|
|
14781
15224
|
writeFileSync14(agentsMdGlobal, "", "utf-8");
|
|
14782
15225
|
}
|
|
14783
|
-
const sessionDir =
|
|
15226
|
+
const sessionDir = join27(dir, "sessions");
|
|
14784
15227
|
const sessionStore = new SessionStore(sessionDir);
|
|
14785
15228
|
sessionStore.init();
|
|
14786
15229
|
const sessionManager = new SessionManager(sessionStore, {
|
|
@@ -14834,7 +15277,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14834
15277
|
const mcpModule = new MCPModule(config);
|
|
14835
15278
|
await mcpModule.initialize();
|
|
14836
15279
|
moduleRegistry.register(mcpModule);
|
|
14837
|
-
const memoryModule = new MemoryModule(
|
|
15280
|
+
const memoryModule = new MemoryModule(join27(dir, "memory"));
|
|
14838
15281
|
moduleRegistry.register(memoryModule);
|
|
14839
15282
|
if (config.browser.enabled) {
|
|
14840
15283
|
const browserModule = new BrowserModule;
|
|
@@ -14877,8 +15320,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14877
15320
|
pluginManager.register(plugin);
|
|
14878
15321
|
pluginManager.register(plugin2);
|
|
14879
15322
|
const pluginLoader = new PluginLoader;
|
|
14880
|
-
const globalPluginsDir =
|
|
14881
|
-
const projectPluginsDir =
|
|
15323
|
+
const globalPluginsDir = join27(homedir11(), ".mma", "plugins");
|
|
15324
|
+
const projectPluginsDir = join27(dir, ".mma", "plugins");
|
|
14882
15325
|
pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
|
|
14883
15326
|
pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
|
|
14884
15327
|
contextManager.onCompact = (summary) => {
|
|
@@ -14896,9 +15339,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14896
15339
|
const skipAgentsMd = noAgentsMd === true;
|
|
14897
15340
|
if (!skipAgentsMd) {
|
|
14898
15341
|
const agentsMdCandidates = [
|
|
14899
|
-
|
|
14900
|
-
|
|
14901
|
-
|
|
15342
|
+
join27(baseDir, "AGENTS.md"),
|
|
15343
|
+
join27(baseDir, ".mma", "AGENTS.md"),
|
|
15344
|
+
join27(dir, "AGENTS.md")
|
|
14902
15345
|
];
|
|
14903
15346
|
for (const p of agentsMdCandidates) {
|
|
14904
15347
|
if (existsSync33(p)) {
|
|
@@ -15225,7 +15668,7 @@ function pad(text, width, align) {
|
|
|
15225
15668
|
}
|
|
15226
15669
|
return text + " ".repeat(gap);
|
|
15227
15670
|
}
|
|
15228
|
-
function
|
|
15671
|
+
function truncate2(text, width) {
|
|
15229
15672
|
if (stringWidth(text) <= width)
|
|
15230
15673
|
return text;
|
|
15231
15674
|
let acc = "";
|
|
@@ -15311,7 +15754,7 @@ function formatTable(tableLines, opts = {}) {
|
|
|
15311
15754
|
const cells = [];
|
|
15312
15755
|
for (let c = 0;c < columnCount; c++) {
|
|
15313
15756
|
const raw = row[c] ?? "";
|
|
15314
|
-
const cell =
|
|
15757
|
+
const cell = truncate2(raw, widths[c]);
|
|
15315
15758
|
const a = isHeader && align[c] === undefined ? "center" : align[c] ?? "left";
|
|
15316
15759
|
cells.push(pad(cell, widths[c], a));
|
|
15317
15760
|
}
|
|
@@ -15735,14 +16178,14 @@ async function runSetup() {
|
|
|
15735
16178
|
|
|
15736
16179
|
// src/cli/commands.ts
|
|
15737
16180
|
init_i18n();
|
|
15738
|
-
import { join as
|
|
16181
|
+
import { join as join29, dirname as dirname9 } from "path";
|
|
15739
16182
|
import { homedir as homedir13 } from "os";
|
|
15740
16183
|
import { existsSync as existsSync34, readFileSync as readFileSync23 } from "fs";
|
|
15741
16184
|
|
|
15742
16185
|
// src/cli/security-commands.ts
|
|
15743
16186
|
init_bootstrap();
|
|
15744
16187
|
init_config();
|
|
15745
|
-
import { join as
|
|
16188
|
+
import { join as join28 } from "path";
|
|
15746
16189
|
import { homedir as homedir12 } from "os";
|
|
15747
16190
|
|
|
15748
16191
|
// src/modules/security/security-policies.ts
|
|
@@ -16272,7 +16715,7 @@ function createSecurityCommand(program2) {
|
|
|
16272
16715
|
}
|
|
16273
16716
|
});
|
|
16274
16717
|
securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
|
|
16275
|
-
const configPath =
|
|
16718
|
+
const configPath = join28(homedir12(), ".mma", "config.json");
|
|
16276
16719
|
const { config: appConfig } = await bootstrap();
|
|
16277
16720
|
const validPresets = ["strict", "balanced", "permissive"];
|
|
16278
16721
|
if (!validPresets.includes(preset)) {
|
|
@@ -16287,7 +16730,7 @@ function createSecurityCommand(program2) {
|
|
|
16287
16730
|
console.log(t("cli.security.policy_description", { description: policy.description }));
|
|
16288
16731
|
});
|
|
16289
16732
|
securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
|
|
16290
|
-
const configPath =
|
|
16733
|
+
const configPath = join28(homedir12(), ".mma", "config.json");
|
|
16291
16734
|
const { config: appConfig } = await bootstrap();
|
|
16292
16735
|
appConfig.security = appConfig.security || {};
|
|
16293
16736
|
appConfig.security.sessionEncryption = {
|
|
@@ -16299,7 +16742,7 @@ function createSecurityCommand(program2) {
|
|
|
16299
16742
|
console.log(t("cli.security.encryption_enabled"));
|
|
16300
16743
|
});
|
|
16301
16744
|
securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
|
|
16302
|
-
const configPath =
|
|
16745
|
+
const configPath = join28(homedir12(), ".mma", "config.json");
|
|
16303
16746
|
const { config: appConfig } = await bootstrap();
|
|
16304
16747
|
appConfig.security = appConfig.security || {};
|
|
16305
16748
|
appConfig.security.sessionEncryption = {
|
|
@@ -16311,7 +16754,7 @@ function createSecurityCommand(program2) {
|
|
|
16311
16754
|
console.log(t("cli.security.encryption_disabled"));
|
|
16312
16755
|
});
|
|
16313
16756
|
securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
|
|
16314
|
-
const configPath =
|
|
16757
|
+
const configPath = join28(homedir12(), ".mma", "config.json");
|
|
16315
16758
|
const { config: appConfig } = await bootstrap();
|
|
16316
16759
|
appConfig.security = appConfig.security || {};
|
|
16317
16760
|
appConfig.security.auditNotifier = {
|
|
@@ -16325,7 +16768,7 @@ function createSecurityCommand(program2) {
|
|
|
16325
16768
|
console.log(t("cli.security.audit_enabled"));
|
|
16326
16769
|
});
|
|
16327
16770
|
securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
|
|
16328
|
-
const configPath =
|
|
16771
|
+
const configPath = join28(homedir12(), ".mma", "config.json");
|
|
16329
16772
|
const { config: appConfig } = await bootstrap();
|
|
16330
16773
|
appConfig.security = appConfig.security || {};
|
|
16331
16774
|
appConfig.security.auditNotifier = {
|
|
@@ -16361,8 +16804,8 @@ import { fileURLToPath } from "url";
|
|
|
16361
16804
|
function readVersion() {
|
|
16362
16805
|
const here = dirname9(fileURLToPath(import.meta.url));
|
|
16363
16806
|
const candidates = [
|
|
16364
|
-
|
|
16365
|
-
|
|
16807
|
+
join29(here, "..", "..", "package.json"),
|
|
16808
|
+
join29(here, "..", "package.json")
|
|
16366
16809
|
];
|
|
16367
16810
|
for (const p of candidates) {
|
|
16368
16811
|
if (existsSync34(p)) {
|
|
@@ -16378,7 +16821,7 @@ function createProgram() {
|
|
|
16378
16821
|
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"));
|
|
16379
16822
|
program2.command("init").description(t("cli.init")).action(async () => {
|
|
16380
16823
|
const answers = await runSetup();
|
|
16381
|
-
const configPath =
|
|
16824
|
+
const configPath = join29(homedir13(), ".mma", "config.json");
|
|
16382
16825
|
const { config } = await bootstrap();
|
|
16383
16826
|
config.provider.type = answers.provider;
|
|
16384
16827
|
config.provider.baseUrl = answers.apiBase;
|
|
@@ -16423,7 +16866,7 @@ function createProgram() {
|
|
|
16423
16866
|
});
|
|
16424
16867
|
const configCmd = program2.command("config").description(t("cli.manage_config"));
|
|
16425
16868
|
configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
|
|
16426
|
-
const configPath =
|
|
16869
|
+
const configPath = join29(homedir13(), ".mma", "config.json");
|
|
16427
16870
|
const { config } = await bootstrap();
|
|
16428
16871
|
const keys = key.split(".");
|
|
16429
16872
|
let obj = config;
|
|
@@ -16483,14 +16926,14 @@ function createProgram() {
|
|
|
16483
16926
|
console.log(t("cli.model_hint"));
|
|
16484
16927
|
});
|
|
16485
16928
|
model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
|
|
16486
|
-
const configPath =
|
|
16929
|
+
const configPath = join29(homedir13(), ".mma", "config.json");
|
|
16487
16930
|
const { config } = await bootstrap();
|
|
16488
16931
|
config.model = name;
|
|
16489
16932
|
saveConfig(config, configPath);
|
|
16490
16933
|
console.log(t("cli.model_set", { name }));
|
|
16491
16934
|
});
|
|
16492
16935
|
program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
|
|
16493
|
-
const configPath =
|
|
16936
|
+
const configPath = join29(homedir13(), ".mma", "config.json");
|
|
16494
16937
|
const { config } = await bootstrap();
|
|
16495
16938
|
const contextWindow = parseInt(size, 10);
|
|
16496
16939
|
if (isNaN(contextWindow) || contextWindow < 1024) {
|
|
@@ -16508,7 +16951,7 @@ function createProgram() {
|
|
|
16508
16951
|
console.log(t("cli.base_url"), config.provider.baseUrl);
|
|
16509
16952
|
});
|
|
16510
16953
|
provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
|
|
16511
|
-
const configPath =
|
|
16954
|
+
const configPath = join29(homedir13(), ".mma", "config.json");
|
|
16512
16955
|
const { config } = await bootstrap();
|
|
16513
16956
|
config.provider.type = name;
|
|
16514
16957
|
saveConfig(config, configPath);
|
|
@@ -16561,7 +17004,7 @@ init_bootstrap();
|
|
|
16561
17004
|
init_colors();
|
|
16562
17005
|
import * as readline2 from "readline";
|
|
16563
17006
|
import { existsSync as existsSync35, readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "fs";
|
|
16564
|
-
import { join as
|
|
17007
|
+
import { join as join30, dirname as dirname10 } from "path";
|
|
16565
17008
|
import { homedir as homedir14 } from "os";
|
|
16566
17009
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16567
17010
|
|
|
@@ -16877,7 +17320,7 @@ init_i18n();
|
|
|
16877
17320
|
function isRichTerminal() {
|
|
16878
17321
|
return Boolean(process.stdout.isTTY) && !process.env.CI;
|
|
16879
17322
|
}
|
|
16880
|
-
function
|
|
17323
|
+
function summarizeArgs2(args) {
|
|
16881
17324
|
const preferred = ["path", "file", "query", "url", "command", "name"];
|
|
16882
17325
|
for (const key of preferred) {
|
|
16883
17326
|
const value = args[key];
|
|
@@ -16943,7 +17386,7 @@ class Renderer {
|
|
|
16943
17386
|
toolStart(tool, args) {
|
|
16944
17387
|
this.endCard();
|
|
16945
17388
|
this.spinner.stop();
|
|
16946
|
-
const summary =
|
|
17389
|
+
const summary = summarizeArgs2(args);
|
|
16947
17390
|
if (!this.rich) {
|
|
16948
17391
|
this.out.write(`
|
|
16949
17392
|
${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
|
|
@@ -16953,15 +17396,21 @@ ${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
|
|
|
16953
17396
|
this.card = { tool, args, body: [], start: Date.now() };
|
|
16954
17397
|
this.spinner.start(`${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}`);
|
|
16955
17398
|
}
|
|
16956
|
-
toolEnd(_tool, duration, error) {
|
|
17399
|
+
toolEnd(_tool, duration, error, ctxDelta) {
|
|
16957
17400
|
this.spinner.stop();
|
|
16958
|
-
if (!this.rich)
|
|
17401
|
+
if (!this.rich) {
|
|
17402
|
+
if (ctxDelta !== undefined && ctxDelta !== 0) {
|
|
17403
|
+
const deltaStr = ctxDelta > 0 ? pc.green(`+${ctxDelta}`) : pc.yellow(`${ctxDelta} ↓`);
|
|
17404
|
+
this.out.write(`${pc.dim("ctx")} ${deltaStr}
|
|
17405
|
+
`);
|
|
17406
|
+
}
|
|
16959
17407
|
return;
|
|
17408
|
+
}
|
|
16960
17409
|
if (!this.card)
|
|
16961
17410
|
return;
|
|
16962
17411
|
const { tool, args, body } = this.card;
|
|
16963
17412
|
const lines = [];
|
|
16964
|
-
const summary =
|
|
17413
|
+
const summary = summarizeArgs2(args);
|
|
16965
17414
|
if (summary)
|
|
16966
17415
|
lines.push(pc.dim(summary));
|
|
16967
17416
|
for (const chunk of body) {
|
|
@@ -16972,7 +17421,12 @@ ${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
|
|
|
16972
17421
|
}
|
|
16973
17422
|
}
|
|
16974
17423
|
const marker = error ? pc.red("✗") : pc.green("✓");
|
|
16975
|
-
|
|
17424
|
+
let footer = `${marker} ${pc.dim(`${duration}ms`)}`;
|
|
17425
|
+
if (ctxDelta !== undefined && ctxDelta !== 0) {
|
|
17426
|
+
const deltaStr = ctxDelta > 0 ? pc.green(`+${ctxDelta}`) : pc.yellow(`${ctxDelta} ↓`);
|
|
17427
|
+
footer += ` ${pc.dim("ctx")} ${deltaStr}`;
|
|
17428
|
+
}
|
|
17429
|
+
lines.push(footer);
|
|
16976
17430
|
const title = `${marker} ${friendlyTool(tool)}`;
|
|
16977
17431
|
for (const line of box(lines, { title, width: this.width })) {
|
|
16978
17432
|
this.out.write(`${line}
|
|
@@ -17011,8 +17465,8 @@ init_config();
|
|
|
17011
17465
|
function readVersion2() {
|
|
17012
17466
|
const here = dirname10(fileURLToPath2(import.meta.url));
|
|
17013
17467
|
const candidates = [
|
|
17014
|
-
|
|
17015
|
-
|
|
17468
|
+
join30(here, "..", "..", "package.json"),
|
|
17469
|
+
join30(here, "..", "package.json")
|
|
17016
17470
|
];
|
|
17017
17471
|
for (const p of candidates) {
|
|
17018
17472
|
if (existsSync35(p)) {
|
|
@@ -17045,13 +17499,21 @@ var COMMAND_GROUPS = {
|
|
|
17045
17499
|
delete: "session",
|
|
17046
17500
|
skill: "skill"
|
|
17047
17501
|
};
|
|
17048
|
-
function formatContextBar(used, limit) {
|
|
17502
|
+
function formatContextBar(used, limit, compactions, quality) {
|
|
17049
17503
|
const pct = Math.min(100, Math.round(used / limit * 100));
|
|
17050
17504
|
const barLen = 20;
|
|
17051
17505
|
const filled = Math.round(pct / 100 * barLen);
|
|
17052
17506
|
const bar = pc.green("█".repeat(filled)) + pc.dim("░".repeat(barLen - filled));
|
|
17053
17507
|
const pctStr = pct >= 75 ? pc.yellow(`${pct}%`) : pc.dim(`${pct}%`);
|
|
17054
|
-
|
|
17508
|
+
let line = ` ${bar} ${pctStr} ${pc.dim(`(${used} / ${limit} tokens)`)}`;
|
|
17509
|
+
if (compactions !== undefined) {
|
|
17510
|
+
line += pc.dim(` compactions: ${compactions}`);
|
|
17511
|
+
}
|
|
17512
|
+
if (quality !== undefined) {
|
|
17513
|
+
const qColor = quality >= 70 ? pc.green : quality >= 40 ? pc.yellow : pc.red;
|
|
17514
|
+
line += ` ${qColor(`quality: ${quality}%`)}`;
|
|
17515
|
+
}
|
|
17516
|
+
return line;
|
|
17055
17517
|
}
|
|
17056
17518
|
|
|
17057
17519
|
class Repl {
|
|
@@ -17080,10 +17542,10 @@ class Repl {
|
|
|
17080
17542
|
this.sessionManager = sessionManager;
|
|
17081
17543
|
this.skillsModule = skillsModule;
|
|
17082
17544
|
this.pluginManager = pluginManager;
|
|
17083
|
-
this.configDir = configDir ||
|
|
17545
|
+
this.configDir = configDir || join30(homedir14(), ".mma");
|
|
17084
17546
|
this.baseDir = baseDir || process.cwd();
|
|
17085
17547
|
this.noAgentsMd = noAgentsMd === true;
|
|
17086
|
-
this.historyPath =
|
|
17548
|
+
this.historyPath = join30(homedir14(), ".mma", "repl-history");
|
|
17087
17549
|
this.loadHistory();
|
|
17088
17550
|
this.registerBuiltinCommands();
|
|
17089
17551
|
this.registerMmaCommands();
|
|
@@ -17269,7 +17731,7 @@ class Repl {
|
|
|
17269
17731
|
action: async () => {
|
|
17270
17732
|
console.log(pc.yellow(t("repl.wizard_running")));
|
|
17271
17733
|
const answers = await runSetup();
|
|
17272
|
-
const configPath =
|
|
17734
|
+
const configPath = join30(homedir14(), ".mma", "config.json");
|
|
17273
17735
|
this.config.provider.type = answers.provider;
|
|
17274
17736
|
this.config.provider.baseUrl = answers.apiBase;
|
|
17275
17737
|
this.config.provider.apiKey = answers.apiKey;
|
|
@@ -17299,7 +17761,7 @@ class Repl {
|
|
|
17299
17761
|
return;
|
|
17300
17762
|
}
|
|
17301
17763
|
this.config.provider.type = name;
|
|
17302
|
-
const configPath =
|
|
17764
|
+
const configPath = join30(homedir14(), ".mma", "config.json");
|
|
17303
17765
|
saveConfig(this.config, configPath);
|
|
17304
17766
|
console.log(pc.green(t("repl.provider_set", { name })));
|
|
17305
17767
|
return;
|
|
@@ -17351,7 +17813,7 @@ class Repl {
|
|
|
17351
17813
|
return;
|
|
17352
17814
|
}
|
|
17353
17815
|
this.config.model = name;
|
|
17354
|
-
const configPath =
|
|
17816
|
+
const configPath = join30(homedir14(), ".mma", "config.json");
|
|
17355
17817
|
saveConfig(this.config, configPath);
|
|
17356
17818
|
console.log(pc.green(t("repl.model_set", { name })));
|
|
17357
17819
|
return;
|
|
@@ -17375,7 +17837,7 @@ class Repl {
|
|
|
17375
17837
|
return;
|
|
17376
17838
|
}
|
|
17377
17839
|
this.config.contextWindow = size;
|
|
17378
|
-
const configPath =
|
|
17840
|
+
const configPath = join30(homedir14(), ".mma", "config.json");
|
|
17379
17841
|
saveConfig(this.config, configPath);
|
|
17380
17842
|
console.log(pc.green(t("cli.context_set", { size })));
|
|
17381
17843
|
}
|
|
@@ -17393,9 +17855,9 @@ class Repl {
|
|
|
17393
17855
|
this.agent.shutdown();
|
|
17394
17856
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
17395
17857
|
const { homedir: homedir15 } = await import("os");
|
|
17396
|
-
const { join:
|
|
17397
|
-
const configDir =
|
|
17398
|
-
const projectConfigPath =
|
|
17858
|
+
const { join: join31 } = await import("path");
|
|
17859
|
+
const configDir = join31(homedir15(), ".mma");
|
|
17860
|
+
const projectConfigPath = join31(process.cwd(), ".mmrc");
|
|
17399
17861
|
const freshConfig = loadConfig2({ configDir, projectConfigPath });
|
|
17400
17862
|
Object.assign(this.config, freshConfig);
|
|
17401
17863
|
const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
|
|
@@ -17805,7 +18267,7 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
|
17805
18267
|
if (ev.type === "start") {
|
|
17806
18268
|
renderer.toolStart(ev.tool, ev.args);
|
|
17807
18269
|
} else {
|
|
17808
|
-
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error);
|
|
18270
|
+
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
|
|
17809
18271
|
}
|
|
17810
18272
|
}, (phase) => {
|
|
17811
18273
|
if (phase === "thinking") {
|
|
@@ -17885,7 +18347,7 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
|
17885
18347
|
showContextBar(result) {
|
|
17886
18348
|
if (result.contextUsed !== undefined && result.contextLimit !== undefined && result.contextLimit > 0) {
|
|
17887
18349
|
console.log();
|
|
17888
|
-
const ctxLine = formatContextBar(result.contextUsed, result.contextLimit);
|
|
18350
|
+
const ctxLine = formatContextBar(result.contextUsed, result.contextLimit, result.compactionCount, result.contextQuality);
|
|
17889
18351
|
console.log(ctxLine);
|
|
17890
18352
|
if (result.totalTokens !== undefined && result.totalTokens > 0) {
|
|
17891
18353
|
const apiLine = pc.dim(` API: ${result.promptTokens} prompt + ${result.completionTokens} completion = ${result.totalTokens} total`);
|
|
@@ -17929,9 +18391,9 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
|
17929
18391
|
row(t("repl.agents_label"), pc.red(t("repl.disabled")));
|
|
17930
18392
|
} else {
|
|
17931
18393
|
const agentsMdCandidates = [
|
|
17932
|
-
|
|
17933
|
-
|
|
17934
|
-
|
|
18394
|
+
join30(this.baseDir, "AGENTS.md"),
|
|
18395
|
+
join30(this.baseDir, ".mma", "AGENTS.md"),
|
|
18396
|
+
join30(this.configDir, "AGENTS.md")
|
|
17935
18397
|
];
|
|
17936
18398
|
const foundAgents = agentsMdCandidates.filter((p) => existsSync35(p));
|
|
17937
18399
|
if (foundAgents.length > 0) {
|
|
@@ -17944,7 +18406,7 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
|
17944
18406
|
}
|
|
17945
18407
|
const meta = this.sessionManager?.getActiveMeta();
|
|
17946
18408
|
if (meta) {
|
|
17947
|
-
const sessionPath =
|
|
18409
|
+
const sessionPath = join30(this.configDir, "sessions", meta.id);
|
|
17948
18410
|
row(t("repl.session_label"), `${pc.cyan(meta.name)} ${pc.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc.dim(sessionPath)}`);
|
|
17949
18411
|
}
|
|
17950
18412
|
const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
|
|
@@ -17970,7 +18432,7 @@ init_config();
|
|
|
17970
18432
|
init_i18n();
|
|
17971
18433
|
init_colors();
|
|
17972
18434
|
import { existsSync as existsSync36 } from "fs";
|
|
17973
|
-
import { join as
|
|
18435
|
+
import { join as join31 } from "path";
|
|
17974
18436
|
import { homedir as homedir15 } from "os";
|
|
17975
18437
|
async function main() {
|
|
17976
18438
|
const program2 = createProgram();
|
|
@@ -18011,7 +18473,7 @@ async function main() {
|
|
|
18011
18473
|
if (ev.type === "start") {
|
|
18012
18474
|
renderer.toolStart(ev.tool, ev.args);
|
|
18013
18475
|
} else {
|
|
18014
|
-
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error);
|
|
18476
|
+
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
|
|
18015
18477
|
}
|
|
18016
18478
|
}, (phase) => {
|
|
18017
18479
|
if (phase === "thinking") {
|
|
@@ -18034,7 +18496,7 @@ async function main() {
|
|
|
18034
18496
|
}
|
|
18035
18497
|
agent.shutdown();
|
|
18036
18498
|
} else {
|
|
18037
|
-
const configPath =
|
|
18499
|
+
const configPath = join31(homedir15(), ".mma", "config.json");
|
|
18038
18500
|
if (!existsSync36(configPath)) {
|
|
18039
18501
|
console.log(pc.yellow(`
|
|
18040
18502
|
` + t("cli.first_run") + `
|