micro-models-agent 0.19.2 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +345 -176
- package/dist/skills/builtin/builtin/git.md +36 -0
- package/dist/skills/builtin/builtin/typescript.md +35 -0
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2548,14 +2548,19 @@ Available commands:`,
|
|
|
2548
2548
|
|
|
2549
2549
|
Use this knowledge to answer the user's question.`,
|
|
2550
2550
|
"exec.stuck": "Stuck on step {stepId}. Current: {description}. No progress for {iterations} iterations.",
|
|
2551
|
-
"exec.stuck_recovery":
|
|
2551
|
+
"exec.stuck_recovery": '[STUCK: {iterations} iterations on step {stepId} — "{description}". You MUST change approach NOW. Concrete actions: (1) Check what this step needs — are dependencies installed? (2) Use plan show to see the plan. (3) If commands fail — create files directly via write_file. (4) After completing the step, call plan update step={stepId} status=done. Do NOT work on other steps until this one is finished.]',
|
|
2552
2552
|
"exec.tool_errors": "Tool {tool} failed {count} times. Suggest alternative approach.",
|
|
2553
|
-
"exec.tool_errors_recovery": "[Tool {tool} failed {count} times.
|
|
2554
|
-
"exec.repetitive_tool": "[
|
|
2555
|
-
"exec.consecutive_failures_recovery": "[{count}
|
|
2556
|
-
"exec.task_reminder": "[
|
|
2557
|
-
"exec.plan_warning": '[⚠
|
|
2558
|
-
"exec.
|
|
2553
|
+
"exec.tool_errors_recovery": "[Tool {tool} failed {count} consecutive times. DO NOT use it again. Try a different approach: (1) create files directly via write_file, (2) use a different tool for the same task, (3) if nothing works — explain the problem and skip this step via plan update step=N status=skipped with a note why.]",
|
|
2554
|
+
"exec.repetitive_tool": "[REPETITION: you called {tool} {count} times with identical arguments and result. This is pointless. IMMEDIATELY change approach: create files directly, change arguments, or if it's a process — check its status via process_log.]",
|
|
2555
|
+
"exec.consecutive_failures_recovery": "[{count} CONSECUTIVE TOOLS FAILED. Stop running commands. Here is what to do: (1) Create files directly via write_file instead of terminal commands. (2) Check if dependencies are installed (npm install). (3) Use list_dir to see what's in the project. (4) Do not attempt build/tests until all files are created.]",
|
|
2556
|
+
"exec.task_reminder": "[ORIGINAL TASK: {task}. You MUST work on this task only. Do not create files for other tasks. If you cannot complete it — explain why and request help.]",
|
|
2557
|
+
"exec.plan_warning": '[⚠ PLAN: you are on step {step} — "{description}", but calling {tool} with files outside this step. This is FORBIDDEN — work STRICTLY on the current step. First complete it and call plan update step={step} status=done, only then move to the next.]',
|
|
2558
|
+
"exec.plan_blocked": "[⛔ BLOCKED: {max} consecutive calls outside the current step. You are violating the plan. Return to step {step} and complete it. Other steps are blocked until this one is done.]",
|
|
2559
|
+
"exec.off_track": `[⚠ OFF PLAN: step {stepId} is "{description}", but you're using {tool} on a different path. Return to the current step immediately.]`,
|
|
2560
|
+
"exec.step_gate_deps": '[⚠ Step {step} "{description}": dependencies are not installed. First run the install command (npm install, pip install, etc.). Verify the lock file or dependency directory exists.]',
|
|
2561
|
+
"exec.step_gate_empty": "[⚠ Step {step}: files exist but appear empty: {files}. Add real code to these files before advancing to the next step.]",
|
|
2562
|
+
"exec.step_gate_ok": '[✓] Step {step} completed and verified. MOVING to step {nextStep}: "{nextDesc}". Work ONLY on this step.',
|
|
2563
|
+
"exec.step_gate_last": "[✓] Step {step} completed — that was the final step. Verify everything together and provide the final answer.]",
|
|
2559
2564
|
"exec.audit_pass": "[✓] Task complete: {done}/{total} steps done, {files} files verified",
|
|
2560
2565
|
"exec.audit_fail": "[✗] Task incomplete: {done}/{total} steps done, {files} files missing",
|
|
2561
2566
|
"exec.audit_fail_typecheck": "[✗] Task incomplete: {done}/{total} steps done, {missing} files missing, typecheck error: {typeError}",
|
|
@@ -3040,14 +3045,19 @@ var init_ru = __esm(() => {
|
|
|
3040
3045
|
|
|
3041
3046
|
Используйте эти знания для ответа на вопрос пользователя.`,
|
|
3042
3047
|
"exec.stuck": "Застряли на шаге {stepId}. Текущий: {description}. Нет прогресса {iterations} итераций.",
|
|
3043
|
-
"exec.stuck_recovery":
|
|
3048
|
+
"exec.stuck_recovery": '[ЗАСТРЕВАНИЕ: {iterations} итераций на шаге {stepId} — "{description}". ВЫ ДОЛЖНЫ сменить подход прямо сейчас. Конкретные действия: (1) Проверьте что нужно для этого шага — установлены ли зависимости? (2) Используйте plan show чтобы увидеть план. (3) Если команды не работают — создайте файлы напрямую через write_file. (4) После завершения шага вызовите plan update step={stepId} status=done. НЕ переходите к другим шагам пока этот не завершён.]',
|
|
3044
3049
|
"exec.tool_errors": "Инструмент {tool} сбоил {count} раз. Предложите другой подход.",
|
|
3045
|
-
"exec.tool_errors_recovery": "[Инструмент {tool} сбоил {count}
|
|
3046
|
-
"exec.repetitive_tool": "[
|
|
3047
|
-
"exec.consecutive_failures_recovery": "[{count}
|
|
3048
|
-
"exec.task_reminder": "[
|
|
3049
|
-
"exec.plan_warning": '[⚠
|
|
3050
|
-
"exec.
|
|
3050
|
+
"exec.tool_errors_recovery": "[Инструмент {tool} сбоил {count} раз подряд. НЕ ИСПОЛЬЗУЙТЕ его снова. Используйте другой подход: (1) создайте нужные файлы напрямую через write_file, (2) используйте другой инструмент для той же задачи, (3) если ничего не работает — объясните проблему и переходите к следующему шагу плана через plan update step=N status=skipped с пометкой почему.]",
|
|
3051
|
+
"exec.repetitive_tool": "[ПОВТОРЕНИЕ: вы вызвали {tool} {count} раз с одинаковыми аргументами и результатом. Это бессмысленно. НЕМЕДЛЕННО смените подход: создайте файлы напрямую, измените аргументы или, если это процесс — проверьте его статус через process_log.]",
|
|
3052
|
+
"exec.consecutive_failures_recovery": "[{count} ИНСТРУМЕНТОВ ПОДРЯД УПАЛИ. Хватит пытаться запускать команды. Вот что делать: (1) Создавайте файлы напрямую через write_file вместо команд терминала. (2) Проверьте, установлены ли зависимости (npm install). (3) Используйте list_dir чтобы увидеть что есть в проекте. (4) Не пытайтесь запустить сборку/тесты пока не созданы все файлы.]",
|
|
3053
|
+
"exec.task_reminder": "[ИСХОДНАЯ ЗАДАЧА: {task}. ВЫ ДОЛЖНЫ работать только над этой задачей. Не создавайте файлы для других задач. Если не можете выполнить — объясните почему и запросите помощь.]",
|
|
3054
|
+
"exec.plan_warning": '[⚠ ПЛАН: вы на шаге {step} — "{description}", но вызываете {tool} для файлов вне этого шага. Это ЗАПРЕЩЕНО — работайте СТРОГО над текущим шагом. Сначала завершите его и вызовите plan update step={step} status=done, только потом переходите к следующему.]',
|
|
3055
|
+
"exec.plan_blocked": "[⛔ ЗАБЛОКИРОВАНО: {max} вызова подряд вне текущего шага. Вы нарушаете план. Вернитесь к шагу {step} и завершите его. Другие шаги будут заблокированы пока текущий не выполнен.]",
|
|
3056
|
+
"exec.off_track": '[⚠ ВНЕ ПЛАНА: шаг {stepId} — "{description}", но вы используете {tool} для другого пути. Вернитесь к текущему шагу немедленно.]',
|
|
3057
|
+
"exec.step_gate_deps": '[⚠ Шаг {step} "{description}": зависимости не установлены. Сначала выполните команду установки (npm install, pip install и т.д.). Проверьте что lock-файл или директория зависимостей существует.]',
|
|
3058
|
+
"exec.step_gate_empty": "[⚠ Шаг {step}: файлы существуют, но выглядят пустыми: {files}. Добавьте реальный код в эти файлы перед тем как переходить к следующему шагу.]",
|
|
3059
|
+
"exec.step_gate_ok": '[✓] Шаг {step} завершён и проверен. ПЕРЕХОДИМ к шагу {nextStep}: "{nextDesc}". Работайте ТОЛЬКО над этим шагом.',
|
|
3060
|
+
"exec.step_gate_last": "[✓] Шаг {step} завершён — это был последний шаг. Проверьте всё вместе и предоставьте финальный ответ.]",
|
|
3051
3061
|
"exec.audit_pass": "[✓] Задача выполнена: {done}/{total} шагов, {files} файлов проверено",
|
|
3052
3062
|
"exec.audit_fail": "[✗] Задача не выполнена: {done}/{total} шагов, {files} файлов отсутствует",
|
|
3053
3063
|
"exec.audit_fail_typecheck": "[✗] Задача не выполнена: {done}/{total} шагов, {missing} файлов отсутствует, ошибка typecheck: {typeError}",
|
|
@@ -12823,11 +12833,18 @@ class StuckDetector {
|
|
|
12823
12833
|
if (!this.hasRepetitiveToolCalls())
|
|
12824
12834
|
return "";
|
|
12825
12835
|
const last = this.recentToolCalls[this.recentToolCalls.length - 1];
|
|
12826
|
-
return t("exec.repetitive_tool", {
|
|
12836
|
+
return t("exec.repetitive_tool", {
|
|
12837
|
+
tool: last.name,
|
|
12838
|
+
count: this.repetitionThreshold
|
|
12839
|
+
});
|
|
12827
12840
|
}
|
|
12828
12841
|
getStuckReason() {
|
|
12829
12842
|
if (this.isStuck()) {
|
|
12830
|
-
return t("exec.stuck", {
|
|
12843
|
+
return t("exec.stuck", {
|
|
12844
|
+
stepId: String(this.currentStepId ?? "?"),
|
|
12845
|
+
description: this.currentStepDescription,
|
|
12846
|
+
iterations: this.iterationsOnCurrentStep
|
|
12847
|
+
});
|
|
12831
12848
|
}
|
|
12832
12849
|
const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
|
|
12833
12850
|
if (errorTool) {
|
|
@@ -12837,14 +12854,23 @@ class StuckDetector {
|
|
|
12837
12854
|
}
|
|
12838
12855
|
getRecoveryMessage() {
|
|
12839
12856
|
if (this.isStuck()) {
|
|
12840
|
-
return t("exec.stuck_recovery", {
|
|
12857
|
+
return t("exec.stuck_recovery", {
|
|
12858
|
+
iterations: this.iterationsOnCurrentStep,
|
|
12859
|
+
stepId: String(this.currentStepId ?? "?"),
|
|
12860
|
+
description: this.currentStepDescription
|
|
12861
|
+
});
|
|
12841
12862
|
}
|
|
12842
12863
|
const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
|
|
12843
12864
|
if (errorTool) {
|
|
12844
|
-
return t("exec.tool_errors_recovery", {
|
|
12865
|
+
return t("exec.tool_errors_recovery", {
|
|
12866
|
+
tool: errorTool[0],
|
|
12867
|
+
count: errorTool[1]
|
|
12868
|
+
});
|
|
12845
12869
|
}
|
|
12846
12870
|
if (this.hasConsecutiveFailures()) {
|
|
12847
|
-
return t("exec.consecutive_failures_recovery", {
|
|
12871
|
+
return t("exec.consecutive_failures_recovery", {
|
|
12872
|
+
count: this.consecutiveFailures
|
|
12873
|
+
});
|
|
12848
12874
|
}
|
|
12849
12875
|
if (this.hasRepetitiveToolCalls()) {
|
|
12850
12876
|
return this.getRepetitiveToolMessage();
|
|
@@ -12859,7 +12885,11 @@ class StuckDetector {
|
|
|
12859
12885
|
const pathInCall = (toolArgStr.match(/\b[\w./-]+\.[a-z]+/gi) || []).map((p) => p.toLowerCase());
|
|
12860
12886
|
const overlaps = pathInCall.some((p) => pathInStep.some((s) => p.includes(s) || s.includes(p)));
|
|
12861
12887
|
if (!overlaps && pathInStep.length > 0 && pathInCall.length > 0) {
|
|
12862
|
-
return t("exec.off_track", {
|
|
12888
|
+
return t("exec.off_track", {
|
|
12889
|
+
stepId: String(this.currentStepId),
|
|
12890
|
+
description: this.currentStepDescription,
|
|
12891
|
+
tool: toolName
|
|
12892
|
+
});
|
|
12863
12893
|
}
|
|
12864
12894
|
return null;
|
|
12865
12895
|
}
|
|
@@ -12948,8 +12978,53 @@ var init_auditor = __esm(() => {
|
|
|
12948
12978
|
init_i18n();
|
|
12949
12979
|
});
|
|
12950
12980
|
|
|
12981
|
+
// src/modules/execution/plan-persister.ts
|
|
12982
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11, existsSync as existsSync25 } from "fs";
|
|
12983
|
+
import { join as join18 } from "path";
|
|
12984
|
+
|
|
12985
|
+
class PlanPersister {
|
|
12986
|
+
filePath;
|
|
12987
|
+
constructor(baseDir) {
|
|
12988
|
+
const mmaDir = join18(baseDir, ".mma");
|
|
12989
|
+
if (!existsSync25(mmaDir)) {
|
|
12990
|
+
mkdirSync11(mmaDir, { recursive: true });
|
|
12991
|
+
}
|
|
12992
|
+
this.filePath = join18(mmaDir, "plan.json");
|
|
12993
|
+
}
|
|
12994
|
+
save(plan) {
|
|
12995
|
+
const file = {
|
|
12996
|
+
title: plan.title,
|
|
12997
|
+
steps: plan.steps,
|
|
12998
|
+
createdAt: plan.createdAt,
|
|
12999
|
+
updatedAt: new Date().toISOString()
|
|
13000
|
+
};
|
|
13001
|
+
writeFileSync9(this.filePath, JSON.stringify(file, null, 2), "utf-8");
|
|
13002
|
+
}
|
|
13003
|
+
load() {
|
|
13004
|
+
if (!existsSync25(this.filePath))
|
|
13005
|
+
return null;
|
|
13006
|
+
try {
|
|
13007
|
+
const raw = readFileSync14(this.filePath, "utf-8");
|
|
13008
|
+
const file = JSON.parse(raw);
|
|
13009
|
+
return {
|
|
13010
|
+
title: file.title,
|
|
13011
|
+
steps: file.steps,
|
|
13012
|
+
createdAt: file.createdAt
|
|
13013
|
+
};
|
|
13014
|
+
} catch {
|
|
13015
|
+
return null;
|
|
13016
|
+
}
|
|
13017
|
+
}
|
|
13018
|
+
clear() {
|
|
13019
|
+
if (existsSync25(this.filePath)) {
|
|
13020
|
+
writeFileSync9(this.filePath, "", "utf-8");
|
|
13021
|
+
}
|
|
13022
|
+
}
|
|
13023
|
+
}
|
|
13024
|
+
var init_plan_persister = () => {};
|
|
13025
|
+
|
|
12951
13026
|
// src/modules/execution/module.ts
|
|
12952
|
-
import { existsSync as
|
|
13027
|
+
import { existsSync as existsSync26, readFileSync as readFileSync15 } from "fs";
|
|
12953
13028
|
import { resolve as resolve14 } from "path";
|
|
12954
13029
|
|
|
12955
13030
|
class ExecutionModule {
|
|
@@ -12958,16 +13033,32 @@ class ExecutionModule {
|
|
|
12958
13033
|
verifier;
|
|
12959
13034
|
stuckDetector;
|
|
12960
13035
|
auditor;
|
|
13036
|
+
persister;
|
|
12961
13037
|
baseDir;
|
|
12962
13038
|
lastRecoveryIteration = -STUCK_RECOVERY_COOLDOWN;
|
|
13039
|
+
consecutivePlanWarnings = 0;
|
|
13040
|
+
lastStepId = -1;
|
|
12963
13041
|
constructor(baseDir, stuckThreshold = 8) {
|
|
12964
13042
|
this.baseDir = baseDir;
|
|
12965
13043
|
this.verifier = new StepVerifier(baseDir);
|
|
12966
13044
|
this.stuckDetector = new StuckDetector(stuckThreshold);
|
|
12967
13045
|
this.auditor = new Auditor(baseDir);
|
|
13046
|
+
this.persister = new PlanPersister(baseDir);
|
|
12968
13047
|
}
|
|
12969
13048
|
setPlan(plan) {
|
|
12970
13049
|
this.tracker = new PlanTracker(plan);
|
|
13050
|
+
this.persister.save(plan);
|
|
13051
|
+
}
|
|
13052
|
+
restorePlan() {
|
|
13053
|
+
const plan = this.persister.load();
|
|
13054
|
+
if (!plan)
|
|
13055
|
+
return false;
|
|
13056
|
+
this.tracker = new PlanTracker(plan);
|
|
13057
|
+
while (this.tracker.getCurrentStep()?.status === "done" || this.tracker.getCurrentStep()?.status === "skipped") {
|
|
13058
|
+
if (!this.tracker.advance())
|
|
13059
|
+
break;
|
|
13060
|
+
}
|
|
13061
|
+
return true;
|
|
12971
13062
|
}
|
|
12972
13063
|
getTracker() {
|
|
12973
13064
|
return this.tracker;
|
|
@@ -13055,6 +13146,7 @@ ${display}`,
|
|
|
13055
13146
|
this.tracker.updateStepStatus(Number(args.step), args.status || "done");
|
|
13056
13147
|
if (args.note)
|
|
13057
13148
|
this.tracker.addNote(Number(args.step), String(args.note));
|
|
13149
|
+
this.persister.save(this.tracker.getPlan());
|
|
13058
13150
|
const progress = this.tracker.getProgressString();
|
|
13059
13151
|
const display = this.tracker.toPromptBlock();
|
|
13060
13152
|
return {
|
|
@@ -13066,6 +13158,7 @@ ${progress}`,
|
|
|
13066
13158
|
}
|
|
13067
13159
|
if (action === "abort") {
|
|
13068
13160
|
this.tracker = null;
|
|
13161
|
+
this.persister.clear();
|
|
13069
13162
|
return { success: true, output: t("plan.aborted") };
|
|
13070
13163
|
}
|
|
13071
13164
|
if (!this.tracker) {
|
|
@@ -13160,10 +13253,16 @@ Sub-tasks: ${note}`
|
|
|
13160
13253
|
onBeforeThink: (ctx) => {
|
|
13161
13254
|
const step = this.tracker?.getCurrentStep();
|
|
13162
13255
|
if (this.tracker && step) {
|
|
13256
|
+
if (step.id !== this.lastStepId) {
|
|
13257
|
+
this.consecutivePlanWarnings = 0;
|
|
13258
|
+
this.lastStepId = step.id;
|
|
13259
|
+
}
|
|
13163
13260
|
this.stuckDetector.setCurrentStep(step.id, step.description);
|
|
13164
13261
|
this.stuckDetector.recordIteration(step.id);
|
|
13165
13262
|
} else {
|
|
13166
13263
|
this.stuckDetector.reset();
|
|
13264
|
+
this.consecutivePlanWarnings = 0;
|
|
13265
|
+
this.lastStepId = -1;
|
|
13167
13266
|
}
|
|
13168
13267
|
const stuckReason = this.stuckDetector.getStuckReason();
|
|
13169
13268
|
if (stuckReason) {
|
|
@@ -13190,6 +13289,16 @@ Sub-tasks: ${note}`
|
|
|
13190
13289
|
role: "user",
|
|
13191
13290
|
content: `<system-summary>${warning}</system-summary>`
|
|
13192
13291
|
});
|
|
13292
|
+
this.consecutivePlanWarnings++;
|
|
13293
|
+
if (this.consecutivePlanWarnings >= MAX_PLAN_WARNINGS_BEFORE_BLOCK) {
|
|
13294
|
+
ctx.contextManager.addMessage({
|
|
13295
|
+
role: "user",
|
|
13296
|
+
content: `<system-summary>${t("exec.plan_blocked", { step: String(this.tracker?.getCurrentStep()?.id ?? "?"), max: MAX_PLAN_WARNINGS_BEFORE_BLOCK })}</system-summary>`
|
|
13297
|
+
});
|
|
13298
|
+
return false;
|
|
13299
|
+
}
|
|
13300
|
+
} else {
|
|
13301
|
+
this.consecutivePlanWarnings = 0;
|
|
13193
13302
|
}
|
|
13194
13303
|
return true;
|
|
13195
13304
|
},
|
|
@@ -13207,7 +13316,7 @@ Sub-tasks: ${note}`
|
|
|
13207
13316
|
this.stuckDetector.recordToolSuccess();
|
|
13208
13317
|
}
|
|
13209
13318
|
if (this.tracker && result.success && (call.name === "write_file" || call.name === "edit_file")) {
|
|
13210
|
-
this.advancePlanIfStepComplete();
|
|
13319
|
+
this.advancePlanIfStepComplete(ctx.contextManager);
|
|
13211
13320
|
}
|
|
13212
13321
|
}
|
|
13213
13322
|
};
|
|
@@ -13249,32 +13358,90 @@ Sub-tasks: ${note}`
|
|
|
13249
13358
|
tool: call.name
|
|
13250
13359
|
});
|
|
13251
13360
|
}
|
|
13252
|
-
advancePlanIfStepComplete() {
|
|
13361
|
+
advancePlanIfStepComplete(contextManager) {
|
|
13253
13362
|
const step = this.tracker?.getCurrentStep();
|
|
13254
13363
|
if (!step)
|
|
13255
13364
|
return;
|
|
13365
|
+
const stepText = step.description.toLowerCase();
|
|
13256
13366
|
const stepPaths = step.description.match(/\b[\w./\\-]+\.[a-z]+/gi) || [];
|
|
13367
|
+
const isDepsStep = stepText.includes("install") || stepText.includes("зависим") || stepText.includes("init") || stepText.includes("инициализац");
|
|
13368
|
+
if (isDepsStep) {
|
|
13369
|
+
const lockFiles = [
|
|
13370
|
+
"package-lock.json",
|
|
13371
|
+
"bun.lockb",
|
|
13372
|
+
"yarn.lock",
|
|
13373
|
+
"pnpm-lock.yaml",
|
|
13374
|
+
"node_modules",
|
|
13375
|
+
"go.sum",
|
|
13376
|
+
"Cargo.lock",
|
|
13377
|
+
"Pipfile.lock",
|
|
13378
|
+
"poetry.lock",
|
|
13379
|
+
"requirements.txt"
|
|
13380
|
+
];
|
|
13381
|
+
const hasLockFile = lockFiles.some((f) => existsSync26(resolve14(this.baseDir, f)));
|
|
13382
|
+
if (!hasLockFile) {
|
|
13383
|
+
if (contextManager) {
|
|
13384
|
+
contextManager.addMessage({
|
|
13385
|
+
role: "user",
|
|
13386
|
+
content: `<system-summary>${t("exec.step_gate_deps", { step: String(step.id), description: step.description })}</system-summary>`
|
|
13387
|
+
});
|
|
13388
|
+
}
|
|
13389
|
+
return;
|
|
13390
|
+
}
|
|
13391
|
+
}
|
|
13257
13392
|
if (stepPaths.length === 0)
|
|
13258
13393
|
return;
|
|
13259
|
-
const allExist = stepPaths.every((p) =>
|
|
13260
|
-
if (allExist)
|
|
13261
|
-
|
|
13262
|
-
|
|
13394
|
+
const allExist = stepPaths.every((p) => existsSync26(resolve14(this.baseDir, p)));
|
|
13395
|
+
if (!allExist)
|
|
13396
|
+
return;
|
|
13397
|
+
const emptyFiles = [];
|
|
13398
|
+
for (const p of stepPaths) {
|
|
13399
|
+
try {
|
|
13400
|
+
const content = readFileSync15(resolve14(this.baseDir, p), "utf-8");
|
|
13401
|
+
if (content.trim().length < 10) {
|
|
13402
|
+
emptyFiles.push(p);
|
|
13403
|
+
}
|
|
13404
|
+
} catch {}
|
|
13405
|
+
}
|
|
13406
|
+
if (emptyFiles.length > 0 && contextManager) {
|
|
13407
|
+
contextManager.addMessage({
|
|
13408
|
+
role: "user",
|
|
13409
|
+
content: `<system-summary>${t("exec.step_gate_empty", { step: String(step.id), files: emptyFiles.join(", ") })}</system-summary>`
|
|
13410
|
+
});
|
|
13411
|
+
return;
|
|
13412
|
+
}
|
|
13413
|
+
this.tracker?.updateStepStatus(step.id, "done");
|
|
13414
|
+
const hadNext = this.tracker?.advance() ?? false;
|
|
13415
|
+
if (this.tracker) {
|
|
13416
|
+
this.persister.save(this.tracker.getPlan());
|
|
13417
|
+
}
|
|
13418
|
+
if (contextManager) {
|
|
13419
|
+
const nextStep = hadNext ? this.tracker?.getCurrentStep() : null;
|
|
13420
|
+
const nextMsg = nextStep ? t("exec.step_gate_ok", {
|
|
13421
|
+
step: String(step.id),
|
|
13422
|
+
nextStep: String(nextStep.id),
|
|
13423
|
+
nextDesc: nextStep.description
|
|
13424
|
+
}) : t("exec.step_gate_last", { step: String(step.id) });
|
|
13425
|
+
contextManager.addMessage({
|
|
13426
|
+
role: "user",
|
|
13427
|
+
content: `<system-summary>${nextMsg}</system-summary>`
|
|
13428
|
+
});
|
|
13263
13429
|
}
|
|
13264
13430
|
}
|
|
13265
13431
|
}
|
|
13266
|
-
var STUCK_RECOVERY_COOLDOWN = 5;
|
|
13432
|
+
var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3;
|
|
13267
13433
|
var init_module = __esm(() => {
|
|
13268
13434
|
init_i18n();
|
|
13269
13435
|
init_tracker();
|
|
13270
13436
|
init_verifier();
|
|
13271
13437
|
init_stuck_detector();
|
|
13272
13438
|
init_auditor();
|
|
13439
|
+
init_plan_persister();
|
|
13273
13440
|
});
|
|
13274
13441
|
|
|
13275
13442
|
// src/modules/security/session-encryption.ts
|
|
13276
|
-
import { readFileSync as
|
|
13277
|
-
import { join as
|
|
13443
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, existsSync as existsSync27, readdirSync as readdirSync6, unlinkSync as unlinkSync3 } from "fs";
|
|
13444
|
+
import { join as join19 } from "path";
|
|
13278
13445
|
import { homedir as homedir8 } from "os";
|
|
13279
13446
|
|
|
13280
13447
|
class SessionFileEncryptor {
|
|
@@ -13283,7 +13450,7 @@ class SessionFileEncryptor {
|
|
|
13283
13450
|
constructor(config) {
|
|
13284
13451
|
this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
|
|
13285
13452
|
this.encryptor = new ConfigEncryptor({
|
|
13286
|
-
keyPath: config?.keyPath ||
|
|
13453
|
+
keyPath: config?.keyPath || join19(homedir8(), ".mma", ".session-encryption-key")
|
|
13287
13454
|
});
|
|
13288
13455
|
}
|
|
13289
13456
|
isEnabled() {
|
|
@@ -13323,23 +13490,23 @@ class SessionFileEncryptor {
|
|
|
13323
13490
|
return lines.map((line) => this.decryptFileContent(line));
|
|
13324
13491
|
}
|
|
13325
13492
|
readSessionFile(filePath) {
|
|
13326
|
-
const content =
|
|
13493
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13327
13494
|
return this.decryptFileContent(content);
|
|
13328
13495
|
}
|
|
13329
13496
|
writeSessionFile(filePath, content) {
|
|
13330
13497
|
const encrypted = this.encryptFileContent(content);
|
|
13331
|
-
|
|
13498
|
+
writeFileSync10(filePath, encrypted, "utf8");
|
|
13332
13499
|
}
|
|
13333
13500
|
readSessionJSON(filePath) {
|
|
13334
|
-
const content =
|
|
13501
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13335
13502
|
return this.decryptJSON(content);
|
|
13336
13503
|
}
|
|
13337
13504
|
writeSessionJSON(filePath, obj) {
|
|
13338
13505
|
const content = this.encryptJSON(obj);
|
|
13339
|
-
|
|
13506
|
+
writeFileSync10(filePath, content, "utf8");
|
|
13340
13507
|
}
|
|
13341
13508
|
readSessionJSONL(filePath) {
|
|
13342
|
-
const content =
|
|
13509
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13343
13510
|
const lines = content.split(`
|
|
13344
13511
|
`).filter((line) => line.trim());
|
|
13345
13512
|
const decryptedLines = this.decryptJSONL(lines);
|
|
@@ -13347,7 +13514,7 @@ class SessionFileEncryptor {
|
|
|
13347
13514
|
}
|
|
13348
13515
|
appendToSessionJSONL(filePath, obj) {
|
|
13349
13516
|
const encryptedLine = this.encryptFileContent(JSON.stringify(obj));
|
|
13350
|
-
|
|
13517
|
+
writeFileSync10(filePath, encryptedLine + `
|
|
13351
13518
|
`, { flag: "a", encoding: "utf8" });
|
|
13352
13519
|
}
|
|
13353
13520
|
encryptSessionDirectory(sessionDir) {
|
|
@@ -13355,12 +13522,12 @@ class SessionFileEncryptor {
|
|
|
13355
13522
|
return;
|
|
13356
13523
|
const files = readdirSync6(sessionDir);
|
|
13357
13524
|
for (const file of files) {
|
|
13358
|
-
const filePath =
|
|
13359
|
-
if (
|
|
13525
|
+
const filePath = join19(sessionDir, file);
|
|
13526
|
+
if (existsSync27(filePath) && !file.endsWith(".enc")) {
|
|
13360
13527
|
try {
|
|
13361
|
-
const content =
|
|
13528
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13362
13529
|
const encrypted = this.encryptFileContent(content);
|
|
13363
|
-
|
|
13530
|
+
writeFileSync10(filePath + ".enc", encrypted, "utf8");
|
|
13364
13531
|
unlinkSync3(filePath);
|
|
13365
13532
|
} catch {}
|
|
13366
13533
|
}
|
|
@@ -13372,12 +13539,12 @@ class SessionFileEncryptor {
|
|
|
13372
13539
|
const files = readdirSync6(sessionDir);
|
|
13373
13540
|
for (const file of files) {
|
|
13374
13541
|
if (file.endsWith(".enc")) {
|
|
13375
|
-
const encFilePath =
|
|
13542
|
+
const encFilePath = join19(sessionDir, file);
|
|
13376
13543
|
const decFilePath = encFilePath.slice(0, -4);
|
|
13377
13544
|
try {
|
|
13378
|
-
const content =
|
|
13545
|
+
const content = readFileSync16(encFilePath, "utf8");
|
|
13379
13546
|
const decrypted = this.decryptFileContent(content);
|
|
13380
|
-
|
|
13547
|
+
writeFileSync10(decFilePath, decrypted, "utf8");
|
|
13381
13548
|
unlinkSync3(encFilePath);
|
|
13382
13549
|
} catch {}
|
|
13383
13550
|
}
|
|
@@ -13397,15 +13564,15 @@ var init_session_encryption = __esm(() => {
|
|
|
13397
13564
|
|
|
13398
13565
|
// src/modules/session/store.ts
|
|
13399
13566
|
import {
|
|
13400
|
-
existsSync as
|
|
13401
|
-
mkdirSync as
|
|
13567
|
+
existsSync as existsSync28,
|
|
13568
|
+
mkdirSync as mkdirSync12,
|
|
13402
13569
|
readdirSync as readdirSync7,
|
|
13403
|
-
readFileSync as
|
|
13570
|
+
readFileSync as readFileSync17,
|
|
13404
13571
|
rmSync,
|
|
13405
|
-
writeFileSync as
|
|
13572
|
+
writeFileSync as writeFileSync11,
|
|
13406
13573
|
appendFileSync as appendFileSync5
|
|
13407
13574
|
} from "fs";
|
|
13408
|
-
import { join as
|
|
13575
|
+
import { join as join20 } from "path";
|
|
13409
13576
|
import { gzipSync } from "zlib";
|
|
13410
13577
|
|
|
13411
13578
|
class SessionStore {
|
|
@@ -13428,39 +13595,39 @@ class SessionStore {
|
|
|
13428
13595
|
return this.encryptor?.isEnabled() ?? false;
|
|
13429
13596
|
}
|
|
13430
13597
|
init() {
|
|
13431
|
-
|
|
13598
|
+
mkdirSync12(this.baseDir, { recursive: true });
|
|
13432
13599
|
}
|
|
13433
13600
|
sessionDir(id) {
|
|
13434
|
-
return
|
|
13601
|
+
return join20(this.baseDir, id);
|
|
13435
13602
|
}
|
|
13436
13603
|
metaPath(id) {
|
|
13437
|
-
return
|
|
13604
|
+
return join20(this.sessionDir(id), "meta.json");
|
|
13438
13605
|
}
|
|
13439
13606
|
historyPath(id) {
|
|
13440
|
-
return
|
|
13607
|
+
return join20(this.sessionDir(id), "history.jsonl");
|
|
13441
13608
|
}
|
|
13442
13609
|
sessionLogPath(id) {
|
|
13443
|
-
return
|
|
13610
|
+
return join20(this.sessionDir(id), "session.jsonl");
|
|
13444
13611
|
}
|
|
13445
13612
|
sessionExists(id) {
|
|
13446
|
-
return
|
|
13613
|
+
return existsSync28(this.metaPath(id));
|
|
13447
13614
|
}
|
|
13448
13615
|
saveMeta(id, meta) {
|
|
13449
13616
|
const dir = this.sessionDir(id);
|
|
13450
|
-
|
|
13617
|
+
mkdirSync12(dir, { recursive: true });
|
|
13451
13618
|
const content = JSON.stringify(meta, null, 2);
|
|
13452
13619
|
if (this.encryptor) {
|
|
13453
|
-
|
|
13620
|
+
writeFileSync11(this.metaPath(id), this.encryptor.encryptFileContent(content), "utf-8");
|
|
13454
13621
|
} else {
|
|
13455
|
-
|
|
13622
|
+
writeFileSync11(this.metaPath(id), content, "utf-8");
|
|
13456
13623
|
}
|
|
13457
13624
|
}
|
|
13458
13625
|
loadMeta(id) {
|
|
13459
13626
|
const path = this.metaPath(id);
|
|
13460
|
-
if (!
|
|
13627
|
+
if (!existsSync28(path))
|
|
13461
13628
|
return null;
|
|
13462
13629
|
try {
|
|
13463
|
-
const raw =
|
|
13630
|
+
const raw = readFileSync17(path, "utf-8");
|
|
13464
13631
|
const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
|
|
13465
13632
|
return JSON.parse(content);
|
|
13466
13633
|
} catch {
|
|
@@ -13469,7 +13636,7 @@ class SessionStore {
|
|
|
13469
13636
|
}
|
|
13470
13637
|
appendMessage(id, msg) {
|
|
13471
13638
|
const dir = this.sessionDir(id);
|
|
13472
|
-
|
|
13639
|
+
mkdirSync12(dir, { recursive: true });
|
|
13473
13640
|
const line = JSON.stringify(msg);
|
|
13474
13641
|
if (this.encryptor?.isEnabled()) {
|
|
13475
13642
|
appendFileSync5(this.historyPath(id), this.encryptor.encryptFileContent(line) + `
|
|
@@ -13487,10 +13654,10 @@ class SessionStore {
|
|
|
13487
13654
|
}
|
|
13488
13655
|
loadHistory(id) {
|
|
13489
13656
|
const path = this.historyPath(id);
|
|
13490
|
-
if (!
|
|
13657
|
+
if (!existsSync28(path))
|
|
13491
13658
|
return [];
|
|
13492
13659
|
try {
|
|
13493
|
-
const raw =
|
|
13660
|
+
const raw = readFileSync17(path, "utf-8");
|
|
13494
13661
|
const lines = raw.split(`
|
|
13495
13662
|
`).filter(Boolean);
|
|
13496
13663
|
if (this.encryptor?.isEnabled()) {
|
|
@@ -13504,7 +13671,7 @@ class SessionStore {
|
|
|
13504
13671
|
}
|
|
13505
13672
|
appendSessionLog(id, entry) {
|
|
13506
13673
|
const dir = this.sessionDir(id);
|
|
13507
|
-
|
|
13674
|
+
mkdirSync12(dir, { recursive: true });
|
|
13508
13675
|
const line = JSON.stringify(entry);
|
|
13509
13676
|
if (this.encryptor?.isEnabled()) {
|
|
13510
13677
|
appendFileSync5(this.sessionLogPath(id), this.encryptor.encryptFileContent(line) + `
|
|
@@ -13516,10 +13683,10 @@ class SessionStore {
|
|
|
13516
13683
|
}
|
|
13517
13684
|
loadSessionLog(id) {
|
|
13518
13685
|
const path = this.sessionLogPath(id);
|
|
13519
|
-
if (!
|
|
13686
|
+
if (!existsSync28(path))
|
|
13520
13687
|
return [];
|
|
13521
13688
|
try {
|
|
13522
|
-
const raw =
|
|
13689
|
+
const raw = readFileSync17(path, "utf-8");
|
|
13523
13690
|
const lines = raw.split(`
|
|
13524
13691
|
`).filter(Boolean);
|
|
13525
13692
|
if (this.encryptor?.isEnabled()) {
|
|
@@ -13532,7 +13699,7 @@ class SessionStore {
|
|
|
13532
13699
|
}
|
|
13533
13700
|
}
|
|
13534
13701
|
listSessions() {
|
|
13535
|
-
if (!
|
|
13702
|
+
if (!existsSync28(this.baseDir))
|
|
13536
13703
|
return [];
|
|
13537
13704
|
const entries = readdirSync7(this.baseDir, { withFileTypes: true });
|
|
13538
13705
|
const sessions = [];
|
|
@@ -13548,7 +13715,7 @@ class SessionStore {
|
|
|
13548
13715
|
}
|
|
13549
13716
|
deleteSession(id) {
|
|
13550
13717
|
const dir = this.sessionDir(id);
|
|
13551
|
-
if (
|
|
13718
|
+
if (existsSync28(dir)) {
|
|
13552
13719
|
rmSync(dir, { recursive: true, force: true });
|
|
13553
13720
|
}
|
|
13554
13721
|
}
|
|
@@ -13560,11 +13727,11 @@ class SessionStore {
|
|
|
13560
13727
|
const updatedAt = new Date(session2.updatedAt);
|
|
13561
13728
|
if (updatedAt < thirtyDaysAgo) {
|
|
13562
13729
|
const historyPath = this.historyPath(session2.id);
|
|
13563
|
-
if (
|
|
13564
|
-
const content =
|
|
13730
|
+
if (existsSync28(historyPath)) {
|
|
13731
|
+
const content = readFileSync17(historyPath, "utf-8");
|
|
13565
13732
|
const compressed = gzipSync(content);
|
|
13566
|
-
const gzPath =
|
|
13567
|
-
|
|
13733
|
+
const gzPath = join20(this.baseDir, `${session2.id}.jsonl.gz`);
|
|
13734
|
+
writeFileSync11(gzPath, compressed);
|
|
13568
13735
|
rmSync(historyPath);
|
|
13569
13736
|
}
|
|
13570
13737
|
}
|
|
@@ -13770,8 +13937,8 @@ class ProfileCompressor {
|
|
|
13770
13937
|
}
|
|
13771
13938
|
|
|
13772
13939
|
// src/modules/user-profile/profile.ts
|
|
13773
|
-
import { readFileSync as
|
|
13774
|
-
import { join as
|
|
13940
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync29, mkdirSync as mkdirSync13 } from "fs";
|
|
13941
|
+
import { join as join21 } from "path";
|
|
13775
13942
|
import { homedir as homedir9, hostname, platform as platform4, type } from "os";
|
|
13776
13943
|
import { env } from "process";
|
|
13777
13944
|
|
|
@@ -13795,17 +13962,17 @@ class UserProfile {
|
|
|
13795
13962
|
return this.info;
|
|
13796
13963
|
}
|
|
13797
13964
|
save() {
|
|
13798
|
-
if (!
|
|
13799
|
-
|
|
13965
|
+
if (!existsSync29(this.profileDir)) {
|
|
13966
|
+
mkdirSync13(this.profileDir, { recursive: true });
|
|
13800
13967
|
}
|
|
13801
|
-
|
|
13968
|
+
writeFileSync12(join21(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
|
|
13802
13969
|
}
|
|
13803
13970
|
load() {
|
|
13804
|
-
const path =
|
|
13805
|
-
if (!
|
|
13971
|
+
const path = join21(this.profileDir, "profile.json");
|
|
13972
|
+
if (!existsSync29(path))
|
|
13806
13973
|
return null;
|
|
13807
13974
|
try {
|
|
13808
|
-
const data = JSON.parse(
|
|
13975
|
+
const data = JSON.parse(readFileSync18(path, "utf-8"));
|
|
13809
13976
|
this.info = {
|
|
13810
13977
|
platform: data.platform,
|
|
13811
13978
|
os: data.os,
|
|
@@ -13840,12 +14007,12 @@ class UserProfile {
|
|
|
13840
14007
|
var init_profile = () => {};
|
|
13841
14008
|
|
|
13842
14009
|
// src/modules/skills/loader.ts
|
|
13843
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
13844
|
-
import { join as
|
|
14010
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync30, statSync as statSync5 } from "fs";
|
|
14011
|
+
import { join as join22 } from "path";
|
|
13845
14012
|
|
|
13846
14013
|
class SkillsLoader {
|
|
13847
14014
|
loadFromDir(dirPath) {
|
|
13848
|
-
if (!
|
|
14015
|
+
if (!existsSync30(dirPath))
|
|
13849
14016
|
return [];
|
|
13850
14017
|
const skills = [];
|
|
13851
14018
|
this.scanDir(dirPath, skills);
|
|
@@ -13854,7 +14021,7 @@ class SkillsLoader {
|
|
|
13854
14021
|
scanDir(dirPath, skills) {
|
|
13855
14022
|
const entries = readdirSync8(dirPath);
|
|
13856
14023
|
for (const entry of entries) {
|
|
13857
|
-
const fullPath =
|
|
14024
|
+
const fullPath = join22(dirPath, entry);
|
|
13858
14025
|
const stat = statSync5(fullPath);
|
|
13859
14026
|
if (stat.isDirectory()) {
|
|
13860
14027
|
this.scanDir(fullPath, skills);
|
|
@@ -13862,7 +14029,7 @@ class SkillsLoader {
|
|
|
13862
14029
|
}
|
|
13863
14030
|
if (!entry.endsWith(".md") && !entry.endsWith(".skill.md"))
|
|
13864
14031
|
continue;
|
|
13865
|
-
const content =
|
|
14032
|
+
const content = readFileSync19(fullPath, "utf-8");
|
|
13866
14033
|
const parsed = this.parseSkillFile(content, fullPath);
|
|
13867
14034
|
if (parsed)
|
|
13868
14035
|
skills.push(parsed);
|
|
@@ -14134,8 +14301,8 @@ var init_browser2 = __esm(() => {
|
|
|
14134
14301
|
});
|
|
14135
14302
|
|
|
14136
14303
|
// src/modules/indexer/walker.ts
|
|
14137
|
-
import { readdirSync as readdirSync9, readFileSync as
|
|
14138
|
-
import { join as
|
|
14304
|
+
import { readdirSync as readdirSync9, readFileSync as readFileSync20, statSync as statSync6, existsSync as existsSync31, watch } from "fs";
|
|
14305
|
+
import { join as join23, relative, extname as extname5 } from "path";
|
|
14139
14306
|
|
|
14140
14307
|
class Indexer {
|
|
14141
14308
|
baseDir;
|
|
@@ -14162,7 +14329,7 @@ class Indexer {
|
|
|
14162
14329
|
let totalSize = 0;
|
|
14163
14330
|
let count = 0;
|
|
14164
14331
|
const walkDir = (dir) => {
|
|
14165
|
-
if (!
|
|
14332
|
+
if (!existsSync31(dir))
|
|
14166
14333
|
return;
|
|
14167
14334
|
let entries;
|
|
14168
14335
|
try {
|
|
@@ -14173,7 +14340,7 @@ class Indexer {
|
|
|
14173
14340
|
for (const entry of entries) {
|
|
14174
14341
|
if (count >= this.MAX_FILES)
|
|
14175
14342
|
return;
|
|
14176
|
-
const fullPath =
|
|
14343
|
+
const fullPath = join23(dir, entry);
|
|
14177
14344
|
const relPath = relative(this.baseDir, fullPath);
|
|
14178
14345
|
const stat = statSync6(fullPath);
|
|
14179
14346
|
if (stat.isDirectory()) {
|
|
@@ -14184,7 +14351,7 @@ class Indexer {
|
|
|
14184
14351
|
const ext = extname5(entry).toLowerCase();
|
|
14185
14352
|
const language = LANGUAGES[ext];
|
|
14186
14353
|
if (language) {
|
|
14187
|
-
const content =
|
|
14354
|
+
const content = readFileSync20(fullPath, "utf-8");
|
|
14188
14355
|
const exports = this.extractExports(content, language);
|
|
14189
14356
|
files.push({ path: relPath, language, exports, size: stat.size });
|
|
14190
14357
|
totalSize += stat.size;
|
|
@@ -14236,22 +14403,22 @@ var init_walker = __esm(() => {
|
|
|
14236
14403
|
});
|
|
14237
14404
|
|
|
14238
14405
|
// src/modules/indexer/cache.ts
|
|
14239
|
-
import { readFileSync as
|
|
14240
|
-
import { join as
|
|
14406
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync13, existsSync as existsSync32, mkdirSync as mkdirSync14, rmSync as rmSync2 } from "fs";
|
|
14407
|
+
import { join as join24 } from "path";
|
|
14241
14408
|
|
|
14242
14409
|
class IndexCache {
|
|
14243
14410
|
cachePath;
|
|
14244
14411
|
cache = null;
|
|
14245
14412
|
constructor(cacheDir) {
|
|
14246
|
-
this.cachePath =
|
|
14413
|
+
this.cachePath = join24(cacheDir, "index-cache.json");
|
|
14247
14414
|
}
|
|
14248
14415
|
load() {
|
|
14249
14416
|
if (this.cache)
|
|
14250
14417
|
return this.cache;
|
|
14251
|
-
if (!
|
|
14418
|
+
if (!existsSync32(this.cachePath))
|
|
14252
14419
|
return null;
|
|
14253
14420
|
try {
|
|
14254
|
-
this.cache = JSON.parse(
|
|
14421
|
+
this.cache = JSON.parse(readFileSync21(this.cachePath, "utf-8"));
|
|
14255
14422
|
return this.cache;
|
|
14256
14423
|
} catch {
|
|
14257
14424
|
return null;
|
|
@@ -14259,14 +14426,14 @@ class IndexCache {
|
|
|
14259
14426
|
}
|
|
14260
14427
|
save(result) {
|
|
14261
14428
|
this.cache = result;
|
|
14262
|
-
const dir =
|
|
14263
|
-
if (!
|
|
14264
|
-
|
|
14265
|
-
|
|
14429
|
+
const dir = join24(this.cachePath, "..");
|
|
14430
|
+
if (!existsSync32(dir))
|
|
14431
|
+
mkdirSync14(dir, { recursive: true });
|
|
14432
|
+
writeFileSync13(this.cachePath, JSON.stringify(result), "utf-8");
|
|
14266
14433
|
}
|
|
14267
14434
|
invalidate() {
|
|
14268
14435
|
this.cache = null;
|
|
14269
|
-
if (
|
|
14436
|
+
if (existsSync32(this.cachePath)) {
|
|
14270
14437
|
try {
|
|
14271
14438
|
rmSync2(this.cachePath);
|
|
14272
14439
|
} catch {}
|
|
@@ -14276,7 +14443,7 @@ class IndexCache {
|
|
|
14276
14443
|
var init_cache = () => {};
|
|
14277
14444
|
|
|
14278
14445
|
// src/modules/indexer/module.ts
|
|
14279
|
-
import { dirname as
|
|
14446
|
+
import { dirname as dirname8 } from "path";
|
|
14280
14447
|
|
|
14281
14448
|
class IndexerModule {
|
|
14282
14449
|
name = "indexer";
|
|
@@ -14393,7 +14560,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
|
|
|
14393
14560
|
const counts = {};
|
|
14394
14561
|
for (const f of result.files) {
|
|
14395
14562
|
const normalized = f.path.replace(/\\/g, "/");
|
|
14396
|
-
const dir =
|
|
14563
|
+
const dir = dirname8(normalized);
|
|
14397
14564
|
const key = dir === "." ? "(root)" : dir;
|
|
14398
14565
|
counts[key] = (counts[key] || 0) + 1;
|
|
14399
14566
|
}
|
|
@@ -14624,13 +14791,13 @@ var init_mcp = __esm(() => {
|
|
|
14624
14791
|
|
|
14625
14792
|
// src/modules/memory/module.ts
|
|
14626
14793
|
import { homedir as homedir10 } from "os";
|
|
14627
|
-
import { join as
|
|
14794
|
+
import { join as join25 } from "path";
|
|
14628
14795
|
|
|
14629
14796
|
class MemoryModule {
|
|
14630
14797
|
name = "memory";
|
|
14631
14798
|
store;
|
|
14632
14799
|
constructor(memoryDir) {
|
|
14633
|
-
const dir = memoryDir ||
|
|
14800
|
+
const dir = memoryDir || join25(homedir10(), ".mma", "memory");
|
|
14634
14801
|
this.store = new MemoryStore(dir);
|
|
14635
14802
|
}
|
|
14636
14803
|
getSystemPromptBlock() {
|
|
@@ -14677,8 +14844,8 @@ __export(exports_bootstrap, {
|
|
|
14677
14844
|
bootstrap: () => bootstrap
|
|
14678
14845
|
});
|
|
14679
14846
|
import { homedir as homedir11 } from "os";
|
|
14680
|
-
import { join as
|
|
14681
|
-
import { existsSync as
|
|
14847
|
+
import { join as join26, resolve as resolve15 } from "path";
|
|
14848
|
+
import { existsSync as existsSync33, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "fs";
|
|
14682
14849
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
14683
14850
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
14684
14851
|
const isWin = profileCompressed.toLowerCase().includes("win32");
|
|
@@ -14700,9 +14867,10 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
14700
14867
|
if (isWin) {
|
|
14701
14868
|
lines.push(``, `Windows environment — use Windows-compatible commands:`, `- Use "dir" instead of "ls". Use "dir /b" for bare listing.`, `- Use "type" or "Get-Content" instead of "cat".`, `- Use "cd" instead of "pwd". Use "echo %cd%" to print working directory.`, `- Use "copy" instead of "cp", "move" instead of "mv", "del" instead of "rm".`, `- Do not use "mkdir -p" — Windows mkdir creates intermediate dirs by default. Use the create_dir tool instead.`, `- Use forward slashes (/) or escaped backslashes (\\\\) in file paths.`, `- Your working directory is: ${baseDir}`);
|
|
14702
14869
|
}
|
|
14703
|
-
lines.push(``, `Bash tool rules:`, `- Use the "workdir" parameter to run commands in a specific directory. Do NOT chain "cd dir && cmd" — the security module blocks the "&&" operator.`, `- Run one command per tool call. Split multi-step shell operations into separate bash calls.`);
|
|
14870
|
+
lines.push(``, `Bash tool rules:`, `- Use the "workdir" parameter to run commands in a specific directory. Do NOT chain "cd dir && cmd" — the security module blocks the "&&" operator.`, `- Run one command per tool call. Split multi-step shell operations into separate bash calls.`, `- Background processes (dev servers, watchers, long-running npm install): use the "background: true" parameter or the tool will auto-detect and background them. Check output with process_log.`);
|
|
14871
|
+
lines.push(``, `=== DEVELOPMENT RULES — follow these strictly ===`, ``, `1. DEPENDENCIES FIRST: Before writing any source code, ALWAYS install project dependencies (e.g., "npm install", "pip install -r requirements.txt", "cargo build", "go mod tidy"). Verify the package manager's lock file or dependency directory exists. Never write code that imports/uses packages that aren't installed yet.`, `2. TOOLKIT/FWK FIRST: If the task specifies a framework or UI library, initialize and configure it BEFORE writing application code. Run its project init command first, then add components/modules. Never write your own version of what the framework already provides.`, `3. ONE STEP AT A TIME: Follow the plan sequentially. Complete step N before starting step N+1. When a step is done: verify the deliverables exist and have real content (not empty), then call "plan update step=N status=done". Do not redo completed work.`, `4. VERIFY YOUR WORK: After creating/modifying files, verify they exist on disk. After installing dependencies, verify the package manager completed successfully. After any command, check its output for errors. Don't assume operations succeeded.`, `5. NO PREMATURE WORK: Do not create files for future steps. Do not add imports/references to packages or modules that haven't been installed yet. Do not reference files or components that don't exist yet. Build incrementally — one layer at a time.`, `6. WHEN STUCK: If a command fails 2+ times, STOP and try a different approach. Write files directly instead of using commands. Ask the user for help. Never repeat the same failing command more than twice.`);
|
|
14704
14872
|
if (config.autoPlan) {
|
|
14705
|
-
lines.push(``, `Plan rule: For
|
|
14873
|
+
lines.push(``, `Plan rule (MANDATORY): For ANY task that requires creating files, installing packages, or multiple actions — you MUST create a plan using the "plan" tool BEFORE starting work. Each step must describe a concrete deliverable (specific files to create, packages to install, commands to run). Do not combine unrelated work into one step.`);
|
|
14706
14874
|
}
|
|
14707
14875
|
const hasMCP = config.mcpServers && Object.values(config.mcpServers).some((s) => s.enabled !== false);
|
|
14708
14876
|
if (hasMCP) {
|
|
@@ -14712,8 +14880,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
14712
14880
|
`);
|
|
14713
14881
|
}
|
|
14714
14882
|
async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
14715
|
-
const dir = configDir ||
|
|
14716
|
-
const projectConfigPath = projectDir ?
|
|
14883
|
+
const dir = configDir || join26(homedir11(), ".mma");
|
|
14884
|
+
const projectConfigPath = projectDir ? join26(projectDir, ".mmrc") : join26(process.cwd(), ".mmrc");
|
|
14717
14885
|
const config = loadConfig({ configDir: dir, projectConfigPath });
|
|
14718
14886
|
setLocale(config.locale);
|
|
14719
14887
|
try {
|
|
@@ -14723,7 +14891,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14723
14891
|
}
|
|
14724
14892
|
} catch {}
|
|
14725
14893
|
const logger = new Logger(config.logLevel);
|
|
14726
|
-
logger.setLogDir(
|
|
14894
|
+
logger.setLogDir(join26(dir, "logs"));
|
|
14727
14895
|
logger.debug("MMA bootstrap", {
|
|
14728
14896
|
version: config.version,
|
|
14729
14897
|
model: config.model
|
|
@@ -14745,7 +14913,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14745
14913
|
logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
|
|
14746
14914
|
}
|
|
14747
14915
|
}
|
|
14748
|
-
const profile = new UserProfile(
|
|
14916
|
+
const profile = new UserProfile(join26(dir));
|
|
14749
14917
|
profile.load() || profile.collect();
|
|
14750
14918
|
profile.save();
|
|
14751
14919
|
const llmProvider = new OpenAICompatProvider({
|
|
@@ -14757,7 +14925,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14757
14925
|
rateLimits: config.security?.rateLimits
|
|
14758
14926
|
});
|
|
14759
14927
|
const baseDir = projectDir ? resolve15(projectDir) : process.cwd();
|
|
14760
|
-
const projectMapCacheDir =
|
|
14928
|
+
const projectMapCacheDir = join26(baseDir, ".mma");
|
|
14761
14929
|
const indexerModule = new IndexerModule({
|
|
14762
14930
|
baseDir,
|
|
14763
14931
|
cacheDir: projectMapCacheDir
|
|
@@ -14768,9 +14936,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14768
14936
|
logger.warn(`Project indexing failed: ${err.message}`);
|
|
14769
14937
|
}
|
|
14770
14938
|
const skillsLoader = new SkillsLoader;
|
|
14771
|
-
const builtinDir =
|
|
14772
|
-
const globalDir =
|
|
14773
|
-
const projectSkillsDir =
|
|
14939
|
+
const builtinDir = join26(import.meta.dirname, "skills", "builtin");
|
|
14940
|
+
const globalDir = join26(homedir11(), ".agents", "skills");
|
|
14941
|
+
const projectSkillsDir = join26(baseDir, ".mma", "skills");
|
|
14774
14942
|
const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
|
|
14775
14943
|
const skillsMatcher = new SkillsMatcher;
|
|
14776
14944
|
const skillsBudget = Math.floor(config.contextWindow * 0.1);
|
|
@@ -14784,11 +14952,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14784
14952
|
essential: true,
|
|
14785
14953
|
estimatedTokens: 250
|
|
14786
14954
|
};
|
|
14787
|
-
const agentsMdGlobal =
|
|
14788
|
-
if (!
|
|
14789
|
-
|
|
14955
|
+
const agentsMdGlobal = join26(dir, "AGENTS.md");
|
|
14956
|
+
if (!existsSync33(agentsMdGlobal)) {
|
|
14957
|
+
writeFileSync14(agentsMdGlobal, "", "utf-8");
|
|
14790
14958
|
}
|
|
14791
|
-
const sessionDir =
|
|
14959
|
+
const sessionDir = join26(dir, "sessions");
|
|
14792
14960
|
const sessionStore = new SessionStore(sessionDir);
|
|
14793
14961
|
sessionStore.init();
|
|
14794
14962
|
const sessionManager = new SessionManager(sessionStore, {
|
|
@@ -14833,6 +15001,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14833
15001
|
const hallucinationDetector = new HallucinationDetector;
|
|
14834
15002
|
const moduleRegistry = new ModuleRegistry;
|
|
14835
15003
|
const execModule = new ExecutionModule(baseDir, config.stuckThreshold);
|
|
15004
|
+
execModule.restorePlan();
|
|
14836
15005
|
moduleRegistry.register(execModule);
|
|
14837
15006
|
const sessionModule = new SessionModule(sessionManager);
|
|
14838
15007
|
moduleRegistry.register(sessionModule);
|
|
@@ -14841,7 +15010,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14841
15010
|
const mcpModule = new MCPModule(config);
|
|
14842
15011
|
await mcpModule.initialize();
|
|
14843
15012
|
moduleRegistry.register(mcpModule);
|
|
14844
|
-
const memoryModule = new MemoryModule(
|
|
15013
|
+
const memoryModule = new MemoryModule(join26(dir, "memory"));
|
|
14845
15014
|
moduleRegistry.register(memoryModule);
|
|
14846
15015
|
if (config.browser.enabled) {
|
|
14847
15016
|
const browserModule = new BrowserModule;
|
|
@@ -14884,8 +15053,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14884
15053
|
pluginManager.register(plugin);
|
|
14885
15054
|
pluginManager.register(plugin2);
|
|
14886
15055
|
const pluginLoader = new PluginLoader;
|
|
14887
|
-
const globalPluginsDir =
|
|
14888
|
-
const projectPluginsDir =
|
|
15056
|
+
const globalPluginsDir = join26(homedir11(), ".mma", "plugins");
|
|
15057
|
+
const projectPluginsDir = join26(dir, ".mma", "plugins");
|
|
14889
15058
|
pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
|
|
14890
15059
|
pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
|
|
14891
15060
|
contextManager.onCompact = (summary) => {
|
|
@@ -14903,13 +15072,13 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14903
15072
|
const skipAgentsMd = noAgentsMd === true;
|
|
14904
15073
|
if (!skipAgentsMd) {
|
|
14905
15074
|
const agentsMdCandidates = [
|
|
14906
|
-
|
|
14907
|
-
|
|
14908
|
-
|
|
15075
|
+
join26(baseDir, "AGENTS.md"),
|
|
15076
|
+
join26(baseDir, ".mma", "AGENTS.md"),
|
|
15077
|
+
join26(dir, "AGENTS.md")
|
|
14909
15078
|
];
|
|
14910
15079
|
for (const p of agentsMdCandidates) {
|
|
14911
|
-
if (
|
|
14912
|
-
const content =
|
|
15080
|
+
if (existsSync33(p)) {
|
|
15081
|
+
const content = readFileSync22(p, "utf-8").trim();
|
|
14913
15082
|
if (content) {
|
|
14914
15083
|
agentsMdBlocks.push({
|
|
14915
15084
|
content,
|
|
@@ -15742,14 +15911,14 @@ async function runSetup() {
|
|
|
15742
15911
|
|
|
15743
15912
|
// src/cli/commands.ts
|
|
15744
15913
|
init_i18n();
|
|
15745
|
-
import { join as
|
|
15914
|
+
import { join as join28, dirname as dirname9 } from "path";
|
|
15746
15915
|
import { homedir as homedir13 } from "os";
|
|
15747
|
-
import { existsSync as
|
|
15916
|
+
import { existsSync as existsSync34, readFileSync as readFileSync23 } from "fs";
|
|
15748
15917
|
|
|
15749
15918
|
// src/cli/security-commands.ts
|
|
15750
15919
|
init_bootstrap();
|
|
15751
15920
|
init_config();
|
|
15752
|
-
import { join as
|
|
15921
|
+
import { join as join27 } from "path";
|
|
15753
15922
|
import { homedir as homedir12 } from "os";
|
|
15754
15923
|
|
|
15755
15924
|
// src/modules/security/security-policies.ts
|
|
@@ -16251,7 +16420,7 @@ function createSecurityCommand(program2) {
|
|
|
16251
16420
|
}
|
|
16252
16421
|
});
|
|
16253
16422
|
securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
|
|
16254
|
-
const configPath =
|
|
16423
|
+
const configPath = join27(homedir12(), ".mma", "config.json");
|
|
16255
16424
|
const { config: appConfig } = await bootstrap();
|
|
16256
16425
|
const validPresets = ["strict", "balanced", "permissive"];
|
|
16257
16426
|
if (!validPresets.includes(preset)) {
|
|
@@ -16266,7 +16435,7 @@ function createSecurityCommand(program2) {
|
|
|
16266
16435
|
console.log(t("cli.security.policy_description", { description: policy.description }));
|
|
16267
16436
|
});
|
|
16268
16437
|
securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
|
|
16269
|
-
const configPath =
|
|
16438
|
+
const configPath = join27(homedir12(), ".mma", "config.json");
|
|
16270
16439
|
const { config: appConfig } = await bootstrap();
|
|
16271
16440
|
appConfig.security = appConfig.security || {};
|
|
16272
16441
|
appConfig.security.sessionEncryption = {
|
|
@@ -16278,7 +16447,7 @@ function createSecurityCommand(program2) {
|
|
|
16278
16447
|
console.log(t("cli.security.encryption_enabled"));
|
|
16279
16448
|
});
|
|
16280
16449
|
securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
|
|
16281
|
-
const configPath =
|
|
16450
|
+
const configPath = join27(homedir12(), ".mma", "config.json");
|
|
16282
16451
|
const { config: appConfig } = await bootstrap();
|
|
16283
16452
|
appConfig.security = appConfig.security || {};
|
|
16284
16453
|
appConfig.security.sessionEncryption = {
|
|
@@ -16290,7 +16459,7 @@ function createSecurityCommand(program2) {
|
|
|
16290
16459
|
console.log(t("cli.security.encryption_disabled"));
|
|
16291
16460
|
});
|
|
16292
16461
|
securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
|
|
16293
|
-
const configPath =
|
|
16462
|
+
const configPath = join27(homedir12(), ".mma", "config.json");
|
|
16294
16463
|
const { config: appConfig } = await bootstrap();
|
|
16295
16464
|
appConfig.security = appConfig.security || {};
|
|
16296
16465
|
appConfig.security.auditNotifier = {
|
|
@@ -16304,7 +16473,7 @@ function createSecurityCommand(program2) {
|
|
|
16304
16473
|
console.log(t("cli.security.audit_enabled"));
|
|
16305
16474
|
});
|
|
16306
16475
|
securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
|
|
16307
|
-
const configPath =
|
|
16476
|
+
const configPath = join27(homedir12(), ".mma", "config.json");
|
|
16308
16477
|
const { config: appConfig } = await bootstrap();
|
|
16309
16478
|
appConfig.security = appConfig.security || {};
|
|
16310
16479
|
appConfig.security.auditNotifier = {
|
|
@@ -16338,14 +16507,14 @@ function createSecurityCommand(program2) {
|
|
|
16338
16507
|
// src/cli/commands.ts
|
|
16339
16508
|
import { fileURLToPath } from "url";
|
|
16340
16509
|
function readVersion() {
|
|
16341
|
-
const here =
|
|
16510
|
+
const here = dirname9(fileURLToPath(import.meta.url));
|
|
16342
16511
|
const candidates = [
|
|
16343
|
-
|
|
16344
|
-
|
|
16512
|
+
join28(here, "..", "..", "package.json"),
|
|
16513
|
+
join28(here, "..", "package.json")
|
|
16345
16514
|
];
|
|
16346
16515
|
for (const p of candidates) {
|
|
16347
|
-
if (
|
|
16348
|
-
const raw = JSON.parse(
|
|
16516
|
+
if (existsSync34(p)) {
|
|
16517
|
+
const raw = JSON.parse(readFileSync23(p, "utf8"));
|
|
16349
16518
|
if (raw.version)
|
|
16350
16519
|
return raw.version;
|
|
16351
16520
|
}
|
|
@@ -16357,7 +16526,7 @@ function createProgram() {
|
|
|
16357
16526
|
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"));
|
|
16358
16527
|
program2.command("init").description(t("cli.init")).action(async () => {
|
|
16359
16528
|
const answers = await runSetup();
|
|
16360
|
-
const configPath =
|
|
16529
|
+
const configPath = join28(homedir13(), ".mma", "config.json");
|
|
16361
16530
|
const { config } = await bootstrap();
|
|
16362
16531
|
config.provider.type = answers.provider;
|
|
16363
16532
|
config.provider.baseUrl = answers.apiBase;
|
|
@@ -16371,7 +16540,7 @@ function createProgram() {
|
|
|
16371
16540
|
});
|
|
16372
16541
|
const configCmd = program2.command("config").description(t("cli.manage_config"));
|
|
16373
16542
|
configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
|
|
16374
|
-
const configPath =
|
|
16543
|
+
const configPath = join28(homedir13(), ".mma", "config.json");
|
|
16375
16544
|
const { config } = await bootstrap();
|
|
16376
16545
|
const keys = key.split(".");
|
|
16377
16546
|
let obj = config;
|
|
@@ -16431,14 +16600,14 @@ function createProgram() {
|
|
|
16431
16600
|
console.log(t("cli.model_hint"));
|
|
16432
16601
|
});
|
|
16433
16602
|
model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
|
|
16434
|
-
const configPath =
|
|
16603
|
+
const configPath = join28(homedir13(), ".mma", "config.json");
|
|
16435
16604
|
const { config } = await bootstrap();
|
|
16436
16605
|
config.model = name;
|
|
16437
16606
|
saveConfig(config, configPath);
|
|
16438
16607
|
console.log(t("cli.model_set", { name }));
|
|
16439
16608
|
});
|
|
16440
16609
|
program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
|
|
16441
|
-
const configPath =
|
|
16610
|
+
const configPath = join28(homedir13(), ".mma", "config.json");
|
|
16442
16611
|
const { config } = await bootstrap();
|
|
16443
16612
|
const contextWindow = parseInt(size, 10);
|
|
16444
16613
|
if (isNaN(contextWindow) || contextWindow < 1024) {
|
|
@@ -16456,7 +16625,7 @@ function createProgram() {
|
|
|
16456
16625
|
console.log(t("cli.base_url"), config.provider.baseUrl);
|
|
16457
16626
|
});
|
|
16458
16627
|
provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
|
|
16459
|
-
const configPath =
|
|
16628
|
+
const configPath = join28(homedir13(), ".mma", "config.json");
|
|
16460
16629
|
const { config } = await bootstrap();
|
|
16461
16630
|
config.provider.type = name;
|
|
16462
16631
|
saveConfig(config, configPath);
|
|
@@ -16508,8 +16677,8 @@ init_bootstrap();
|
|
|
16508
16677
|
// src/cli/repl.ts
|
|
16509
16678
|
init_colors();
|
|
16510
16679
|
import * as readline3 from "readline";
|
|
16511
|
-
import { existsSync as
|
|
16512
|
-
import { join as
|
|
16680
|
+
import { existsSync as existsSync35, readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "fs";
|
|
16681
|
+
import { join as join29, dirname as dirname10 } from "path";
|
|
16513
16682
|
import { homedir as homedir14 } from "os";
|
|
16514
16683
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16515
16684
|
|
|
@@ -16957,14 +17126,14 @@ init_table();
|
|
|
16957
17126
|
init_i18n();
|
|
16958
17127
|
init_config();
|
|
16959
17128
|
function readVersion2() {
|
|
16960
|
-
const here =
|
|
17129
|
+
const here = dirname10(fileURLToPath2(import.meta.url));
|
|
16961
17130
|
const candidates = [
|
|
16962
|
-
|
|
16963
|
-
|
|
17131
|
+
join29(here, "..", "..", "package.json"),
|
|
17132
|
+
join29(here, "..", "package.json")
|
|
16964
17133
|
];
|
|
16965
17134
|
for (const p of candidates) {
|
|
16966
|
-
if (
|
|
16967
|
-
const raw = JSON.parse(
|
|
17135
|
+
if (existsSync35(p)) {
|
|
17136
|
+
const raw = JSON.parse(readFileSync24(p, "utf8"));
|
|
16968
17137
|
if (raw.version)
|
|
16969
17138
|
return raw.version;
|
|
16970
17139
|
}
|
|
@@ -17028,10 +17197,10 @@ class Repl {
|
|
|
17028
17197
|
this.sessionManager = sessionManager;
|
|
17029
17198
|
this.skillsModule = skillsModule;
|
|
17030
17199
|
this.pluginManager = pluginManager;
|
|
17031
|
-
this.configDir = configDir ||
|
|
17200
|
+
this.configDir = configDir || join29(homedir14(), ".mma");
|
|
17032
17201
|
this.baseDir = baseDir || process.cwd();
|
|
17033
17202
|
this.noAgentsMd = noAgentsMd === true;
|
|
17034
|
-
this.historyPath =
|
|
17203
|
+
this.historyPath = join29(homedir14(), ".mma", "repl-history");
|
|
17035
17204
|
this.loadHistory();
|
|
17036
17205
|
this.registerBuiltinCommands();
|
|
17037
17206
|
this.registerMmaCommands();
|
|
@@ -17055,9 +17224,9 @@ class Repl {
|
|
|
17055
17224
|
this.setupListeners();
|
|
17056
17225
|
}
|
|
17057
17226
|
loadHistory() {
|
|
17058
|
-
if (
|
|
17227
|
+
if (existsSync35(this.historyPath)) {
|
|
17059
17228
|
try {
|
|
17060
|
-
const raw =
|
|
17229
|
+
const raw = readFileSync24(this.historyPath, "utf-8");
|
|
17061
17230
|
this.history = raw.split(`
|
|
17062
17231
|
`).filter(Boolean).slice(-this.maxHistory);
|
|
17063
17232
|
} catch {
|
|
@@ -17067,7 +17236,7 @@ class Repl {
|
|
|
17067
17236
|
}
|
|
17068
17237
|
saveHistory() {
|
|
17069
17238
|
const allHistory = this.history.slice(-this.maxHistory);
|
|
17070
|
-
|
|
17239
|
+
writeFileSync15(this.historyPath, allHistory.join(`
|
|
17071
17240
|
`), "utf-8");
|
|
17072
17241
|
}
|
|
17073
17242
|
registerBuiltinCommands() {
|
|
@@ -17120,7 +17289,7 @@ class Repl {
|
|
|
17120
17289
|
}
|
|
17121
17290
|
try {
|
|
17122
17291
|
const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
|
|
17123
|
-
const { existsSync:
|
|
17292
|
+
const { existsSync: existsSync36 } = await import("fs");
|
|
17124
17293
|
const { resolve: resolve16 } = await import("path");
|
|
17125
17294
|
let dataUrl;
|
|
17126
17295
|
let label;
|
|
@@ -17140,7 +17309,7 @@ class Repl {
|
|
|
17140
17309
|
label = source;
|
|
17141
17310
|
} else {
|
|
17142
17311
|
const absPath = resolve16(process.cwd(), source);
|
|
17143
|
-
if (!
|
|
17312
|
+
if (!existsSync36(absPath)) {
|
|
17144
17313
|
console.log(pc.red(t("image.not_found", { path: source })));
|
|
17145
17314
|
return;
|
|
17146
17315
|
}
|
|
@@ -17217,7 +17386,7 @@ class Repl {
|
|
|
17217
17386
|
action: async () => {
|
|
17218
17387
|
console.log(pc.yellow(t("repl.wizard_running")));
|
|
17219
17388
|
const answers = await runSetup();
|
|
17220
|
-
const configPath =
|
|
17389
|
+
const configPath = join29(homedir14(), ".mma", "config.json");
|
|
17221
17390
|
this.config.provider.type = answers.provider;
|
|
17222
17391
|
this.config.provider.baseUrl = answers.apiBase;
|
|
17223
17392
|
this.config.provider.apiKey = answers.apiKey;
|
|
@@ -17247,7 +17416,7 @@ class Repl {
|
|
|
17247
17416
|
return;
|
|
17248
17417
|
}
|
|
17249
17418
|
this.config.provider.type = name;
|
|
17250
|
-
const configPath =
|
|
17419
|
+
const configPath = join29(homedir14(), ".mma", "config.json");
|
|
17251
17420
|
saveConfig(this.config, configPath);
|
|
17252
17421
|
console.log(pc.green(t("repl.provider_set", { name })));
|
|
17253
17422
|
return;
|
|
@@ -17299,7 +17468,7 @@ class Repl {
|
|
|
17299
17468
|
return;
|
|
17300
17469
|
}
|
|
17301
17470
|
this.config.model = name;
|
|
17302
|
-
const configPath =
|
|
17471
|
+
const configPath = join29(homedir14(), ".mma", "config.json");
|
|
17303
17472
|
saveConfig(this.config, configPath);
|
|
17304
17473
|
console.log(pc.green(t("repl.model_set", { name })));
|
|
17305
17474
|
return;
|
|
@@ -17323,7 +17492,7 @@ class Repl {
|
|
|
17323
17492
|
return;
|
|
17324
17493
|
}
|
|
17325
17494
|
this.config.contextWindow = size;
|
|
17326
|
-
const configPath =
|
|
17495
|
+
const configPath = join29(homedir14(), ".mma", "config.json");
|
|
17327
17496
|
saveConfig(this.config, configPath);
|
|
17328
17497
|
console.log(pc.green(t("cli.context_set", { size })));
|
|
17329
17498
|
}
|
|
@@ -17341,9 +17510,9 @@ class Repl {
|
|
|
17341
17510
|
this.agent.shutdown();
|
|
17342
17511
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
17343
17512
|
const { homedir: homedir15 } = await import("os");
|
|
17344
|
-
const { join:
|
|
17345
|
-
const configDir =
|
|
17346
|
-
const projectConfigPath =
|
|
17513
|
+
const { join: join30 } = await import("path");
|
|
17514
|
+
const configDir = join30(homedir15(), ".mma");
|
|
17515
|
+
const projectConfigPath = join30(process.cwd(), ".mmrc");
|
|
17347
17516
|
const freshConfig = loadConfig2({ configDir, projectConfigPath });
|
|
17348
17517
|
Object.assign(this.config, freshConfig);
|
|
17349
17518
|
const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
|
|
@@ -17877,11 +18046,11 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
|
17877
18046
|
row(t("repl.agents_label"), pc.red(t("repl.disabled")));
|
|
17878
18047
|
} else {
|
|
17879
18048
|
const agentsMdCandidates = [
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
|
|
18049
|
+
join29(this.baseDir, "AGENTS.md"),
|
|
18050
|
+
join29(this.baseDir, ".mma", "AGENTS.md"),
|
|
18051
|
+
join29(this.configDir, "AGENTS.md")
|
|
17883
18052
|
];
|
|
17884
|
-
const foundAgents = agentsMdCandidates.filter((p) =>
|
|
18053
|
+
const foundAgents = agentsMdCandidates.filter((p) => existsSync35(p));
|
|
17885
18054
|
if (foundAgents.length > 0) {
|
|
17886
18055
|
for (const p of foundAgents) {
|
|
17887
18056
|
row(t("repl.agents_label"), pc.dim(p));
|
|
@@ -17892,7 +18061,7 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
|
17892
18061
|
}
|
|
17893
18062
|
const meta = this.sessionManager?.getActiveMeta();
|
|
17894
18063
|
if (meta) {
|
|
17895
|
-
const sessionPath =
|
|
18064
|
+
const sessionPath = join29(this.configDir, "sessions", meta.id);
|
|
17896
18065
|
row(t("repl.session_label"), `${pc.cyan(meta.name)} ${pc.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc.dim(sessionPath)}`);
|
|
17897
18066
|
}
|
|
17898
18067
|
const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
|
|
@@ -17917,8 +18086,8 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
|
17917
18086
|
init_config();
|
|
17918
18087
|
init_i18n();
|
|
17919
18088
|
init_colors();
|
|
17920
|
-
import { existsSync as
|
|
17921
|
-
import { join as
|
|
18089
|
+
import { existsSync as existsSync36 } from "fs";
|
|
18090
|
+
import { join as join30 } from "path";
|
|
17922
18091
|
import { homedir as homedir15 } from "os";
|
|
17923
18092
|
async function main() {
|
|
17924
18093
|
const program2 = createProgram();
|
|
@@ -17982,8 +18151,8 @@ async function main() {
|
|
|
17982
18151
|
}
|
|
17983
18152
|
agent.shutdown();
|
|
17984
18153
|
} else {
|
|
17985
|
-
const configPath =
|
|
17986
|
-
if (!
|
|
18154
|
+
const configPath = join30(homedir15(), ".mma", "config.json");
|
|
18155
|
+
if (!existsSync36(configPath)) {
|
|
17987
18156
|
console.log(pc.yellow(`
|
|
17988
18157
|
` + t("cli.first_run") + `
|
|
17989
18158
|
`));
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-expert
|
|
3
|
+
description: Git branching, merge conflicts, rebasing, workflow strategies
|
|
4
|
+
keywords: [git, branch, merge, rebase, commit, conflict, workflow]
|
|
5
|
+
mma_version: 2
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Git Expert
|
|
9
|
+
|
|
10
|
+
## Branching Strategies
|
|
11
|
+
|
|
12
|
+
- **Feature branches**: `feature/xxx` from `main`, merge via PR
|
|
13
|
+
- **Hotfix**: `hotfix/xxx` from `main`, merge to both `main` and `develop`
|
|
14
|
+
- **Release**: `release/xxx` from `develop`, merge to `main` + `develop`
|
|
15
|
+
|
|
16
|
+
## Conflict Resolution
|
|
17
|
+
|
|
18
|
+
1. `git fetch origin` — get latest
|
|
19
|
+
2. `git checkout your-branch`
|
|
20
|
+
3. `git rebase origin/main` — apply your commits on top
|
|
21
|
+
4. Resolve conflicts file by file
|
|
22
|
+
5. `git add <files>` then `git rebase --continue`
|
|
23
|
+
|
|
24
|
+
## Useful Commands
|
|
25
|
+
|
|
26
|
+
- `git log --oneline --graph --all` — visualize history
|
|
27
|
+
- `git diff --stat` — summary of changes
|
|
28
|
+
- `git stash pop` — restore stashed changes
|
|
29
|
+
- `git cherry-pick <commit>` — apply specific commit
|
|
30
|
+
|
|
31
|
+
## Best Practices
|
|
32
|
+
|
|
33
|
+
- Commit often with clear messages
|
|
34
|
+
- Keep commits atomic (one logical change)
|
|
35
|
+
- Never force push to shared branches
|
|
36
|
+
- Use `git rebase -i` to clean up before PR
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: typescript-expert
|
|
3
|
+
description: TypeScript type system, generics, advanced patterns, compiler API
|
|
4
|
+
keywords: [typescript, types, generics, tsconfig, compiler, interface, type]
|
|
5
|
+
mma_version: 2
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# TypeScript Expert
|
|
9
|
+
|
|
10
|
+
## Key Patterns
|
|
11
|
+
|
|
12
|
+
- Use `readonly` for immutable properties
|
|
13
|
+
- Prefer `interface` over `type` for object shapes
|
|
14
|
+
- Use `as const` for literal types
|
|
15
|
+
- Prefer `unknown` over `any` for type safety
|
|
16
|
+
|
|
17
|
+
## Common Pitfalls
|
|
18
|
+
|
|
19
|
+
- Avoid `any` — use `unknown` + type guards
|
|
20
|
+
- Don't use `enum` — use `const` objects or union types
|
|
21
|
+
- Avoid `namespace` — use ES modules
|
|
22
|
+
|
|
23
|
+
## Type Guards
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
function isString(val: unknown): val is string {
|
|
27
|
+
return typeof val === 'string'
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Generics
|
|
32
|
+
|
|
33
|
+
- Use `extends` for constraints
|
|
34
|
+
- Use `infer` for conditional type extraction
|
|
35
|
+
- Prefer explicit over implicit for complex cases
|