micro-models-agent 0.20.0 → 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
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
|
}
|
|
@@ -12994,7 +13024,7 @@ class PlanPersister {
|
|
|
12994
13024
|
var init_plan_persister = () => {};
|
|
12995
13025
|
|
|
12996
13026
|
// src/modules/execution/module.ts
|
|
12997
|
-
import { existsSync as existsSync26 } from "fs";
|
|
13027
|
+
import { existsSync as existsSync26, readFileSync as readFileSync15 } from "fs";
|
|
12998
13028
|
import { resolve as resolve14 } from "path";
|
|
12999
13029
|
|
|
13000
13030
|
class ExecutionModule {
|
|
@@ -13006,6 +13036,8 @@ class ExecutionModule {
|
|
|
13006
13036
|
persister;
|
|
13007
13037
|
baseDir;
|
|
13008
13038
|
lastRecoveryIteration = -STUCK_RECOVERY_COOLDOWN;
|
|
13039
|
+
consecutivePlanWarnings = 0;
|
|
13040
|
+
lastStepId = -1;
|
|
13009
13041
|
constructor(baseDir, stuckThreshold = 8) {
|
|
13010
13042
|
this.baseDir = baseDir;
|
|
13011
13043
|
this.verifier = new StepVerifier(baseDir);
|
|
@@ -13221,10 +13253,16 @@ Sub-tasks: ${note}`
|
|
|
13221
13253
|
onBeforeThink: (ctx) => {
|
|
13222
13254
|
const step = this.tracker?.getCurrentStep();
|
|
13223
13255
|
if (this.tracker && step) {
|
|
13256
|
+
if (step.id !== this.lastStepId) {
|
|
13257
|
+
this.consecutivePlanWarnings = 0;
|
|
13258
|
+
this.lastStepId = step.id;
|
|
13259
|
+
}
|
|
13224
13260
|
this.stuckDetector.setCurrentStep(step.id, step.description);
|
|
13225
13261
|
this.stuckDetector.recordIteration(step.id);
|
|
13226
13262
|
} else {
|
|
13227
13263
|
this.stuckDetector.reset();
|
|
13264
|
+
this.consecutivePlanWarnings = 0;
|
|
13265
|
+
this.lastStepId = -1;
|
|
13228
13266
|
}
|
|
13229
13267
|
const stuckReason = this.stuckDetector.getStuckReason();
|
|
13230
13268
|
if (stuckReason) {
|
|
@@ -13251,6 +13289,16 @@ Sub-tasks: ${note}`
|
|
|
13251
13289
|
role: "user",
|
|
13252
13290
|
content: `<system-summary>${warning}</system-summary>`
|
|
13253
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;
|
|
13254
13302
|
}
|
|
13255
13303
|
return true;
|
|
13256
13304
|
},
|
|
@@ -13268,7 +13316,7 @@ Sub-tasks: ${note}`
|
|
|
13268
13316
|
this.stuckDetector.recordToolSuccess();
|
|
13269
13317
|
}
|
|
13270
13318
|
if (this.tracker && result.success && (call.name === "write_file" || call.name === "edit_file")) {
|
|
13271
|
-
this.advancePlanIfStepComplete();
|
|
13319
|
+
this.advancePlanIfStepComplete(ctx.contextManager);
|
|
13272
13320
|
}
|
|
13273
13321
|
}
|
|
13274
13322
|
};
|
|
@@ -13310,24 +13358,78 @@ Sub-tasks: ${note}`
|
|
|
13310
13358
|
tool: call.name
|
|
13311
13359
|
});
|
|
13312
13360
|
}
|
|
13313
|
-
advancePlanIfStepComplete() {
|
|
13361
|
+
advancePlanIfStepComplete(contextManager) {
|
|
13314
13362
|
const step = this.tracker?.getCurrentStep();
|
|
13315
13363
|
if (!step)
|
|
13316
13364
|
return;
|
|
13365
|
+
const stepText = step.description.toLowerCase();
|
|
13317
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
|
+
}
|
|
13318
13392
|
if (stepPaths.length === 0)
|
|
13319
13393
|
return;
|
|
13320
13394
|
const allExist = stepPaths.every((p) => existsSync26(resolve14(this.baseDir, p)));
|
|
13321
|
-
if (allExist)
|
|
13322
|
-
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
|
|
13326
|
-
|
|
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
|
+
});
|
|
13327
13429
|
}
|
|
13328
13430
|
}
|
|
13329
13431
|
}
|
|
13330
|
-
var STUCK_RECOVERY_COOLDOWN = 5;
|
|
13432
|
+
var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3;
|
|
13331
13433
|
var init_module = __esm(() => {
|
|
13332
13434
|
init_i18n();
|
|
13333
13435
|
init_tracker();
|
|
@@ -13338,7 +13440,7 @@ var init_module = __esm(() => {
|
|
|
13338
13440
|
});
|
|
13339
13441
|
|
|
13340
13442
|
// src/modules/security/session-encryption.ts
|
|
13341
|
-
import { readFileSync as
|
|
13443
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, existsSync as existsSync27, readdirSync as readdirSync6, unlinkSync as unlinkSync3 } from "fs";
|
|
13342
13444
|
import { join as join19 } from "path";
|
|
13343
13445
|
import { homedir as homedir8 } from "os";
|
|
13344
13446
|
|
|
@@ -13388,7 +13490,7 @@ class SessionFileEncryptor {
|
|
|
13388
13490
|
return lines.map((line) => this.decryptFileContent(line));
|
|
13389
13491
|
}
|
|
13390
13492
|
readSessionFile(filePath) {
|
|
13391
|
-
const content =
|
|
13493
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13392
13494
|
return this.decryptFileContent(content);
|
|
13393
13495
|
}
|
|
13394
13496
|
writeSessionFile(filePath, content) {
|
|
@@ -13396,7 +13498,7 @@ class SessionFileEncryptor {
|
|
|
13396
13498
|
writeFileSync10(filePath, encrypted, "utf8");
|
|
13397
13499
|
}
|
|
13398
13500
|
readSessionJSON(filePath) {
|
|
13399
|
-
const content =
|
|
13501
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13400
13502
|
return this.decryptJSON(content);
|
|
13401
13503
|
}
|
|
13402
13504
|
writeSessionJSON(filePath, obj) {
|
|
@@ -13404,7 +13506,7 @@ class SessionFileEncryptor {
|
|
|
13404
13506
|
writeFileSync10(filePath, content, "utf8");
|
|
13405
13507
|
}
|
|
13406
13508
|
readSessionJSONL(filePath) {
|
|
13407
|
-
const content =
|
|
13509
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13408
13510
|
const lines = content.split(`
|
|
13409
13511
|
`).filter((line) => line.trim());
|
|
13410
13512
|
const decryptedLines = this.decryptJSONL(lines);
|
|
@@ -13423,7 +13525,7 @@ class SessionFileEncryptor {
|
|
|
13423
13525
|
const filePath = join19(sessionDir, file);
|
|
13424
13526
|
if (existsSync27(filePath) && !file.endsWith(".enc")) {
|
|
13425
13527
|
try {
|
|
13426
|
-
const content =
|
|
13528
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13427
13529
|
const encrypted = this.encryptFileContent(content);
|
|
13428
13530
|
writeFileSync10(filePath + ".enc", encrypted, "utf8");
|
|
13429
13531
|
unlinkSync3(filePath);
|
|
@@ -13440,7 +13542,7 @@ class SessionFileEncryptor {
|
|
|
13440
13542
|
const encFilePath = join19(sessionDir, file);
|
|
13441
13543
|
const decFilePath = encFilePath.slice(0, -4);
|
|
13442
13544
|
try {
|
|
13443
|
-
const content =
|
|
13545
|
+
const content = readFileSync16(encFilePath, "utf8");
|
|
13444
13546
|
const decrypted = this.decryptFileContent(content);
|
|
13445
13547
|
writeFileSync10(decFilePath, decrypted, "utf8");
|
|
13446
13548
|
unlinkSync3(encFilePath);
|
|
@@ -13465,7 +13567,7 @@ import {
|
|
|
13465
13567
|
existsSync as existsSync28,
|
|
13466
13568
|
mkdirSync as mkdirSync12,
|
|
13467
13569
|
readdirSync as readdirSync7,
|
|
13468
|
-
readFileSync as
|
|
13570
|
+
readFileSync as readFileSync17,
|
|
13469
13571
|
rmSync,
|
|
13470
13572
|
writeFileSync as writeFileSync11,
|
|
13471
13573
|
appendFileSync as appendFileSync5
|
|
@@ -13525,7 +13627,7 @@ class SessionStore {
|
|
|
13525
13627
|
if (!existsSync28(path))
|
|
13526
13628
|
return null;
|
|
13527
13629
|
try {
|
|
13528
|
-
const raw =
|
|
13630
|
+
const raw = readFileSync17(path, "utf-8");
|
|
13529
13631
|
const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
|
|
13530
13632
|
return JSON.parse(content);
|
|
13531
13633
|
} catch {
|
|
@@ -13555,7 +13657,7 @@ class SessionStore {
|
|
|
13555
13657
|
if (!existsSync28(path))
|
|
13556
13658
|
return [];
|
|
13557
13659
|
try {
|
|
13558
|
-
const raw =
|
|
13660
|
+
const raw = readFileSync17(path, "utf-8");
|
|
13559
13661
|
const lines = raw.split(`
|
|
13560
13662
|
`).filter(Boolean);
|
|
13561
13663
|
if (this.encryptor?.isEnabled()) {
|
|
@@ -13584,7 +13686,7 @@ class SessionStore {
|
|
|
13584
13686
|
if (!existsSync28(path))
|
|
13585
13687
|
return [];
|
|
13586
13688
|
try {
|
|
13587
|
-
const raw =
|
|
13689
|
+
const raw = readFileSync17(path, "utf-8");
|
|
13588
13690
|
const lines = raw.split(`
|
|
13589
13691
|
`).filter(Boolean);
|
|
13590
13692
|
if (this.encryptor?.isEnabled()) {
|
|
@@ -13626,7 +13728,7 @@ class SessionStore {
|
|
|
13626
13728
|
if (updatedAt < thirtyDaysAgo) {
|
|
13627
13729
|
const historyPath = this.historyPath(session2.id);
|
|
13628
13730
|
if (existsSync28(historyPath)) {
|
|
13629
|
-
const content =
|
|
13731
|
+
const content = readFileSync17(historyPath, "utf-8");
|
|
13630
13732
|
const compressed = gzipSync(content);
|
|
13631
13733
|
const gzPath = join20(this.baseDir, `${session2.id}.jsonl.gz`);
|
|
13632
13734
|
writeFileSync11(gzPath, compressed);
|
|
@@ -13835,7 +13937,7 @@ class ProfileCompressor {
|
|
|
13835
13937
|
}
|
|
13836
13938
|
|
|
13837
13939
|
// src/modules/user-profile/profile.ts
|
|
13838
|
-
import { readFileSync as
|
|
13940
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync29, mkdirSync as mkdirSync13 } from "fs";
|
|
13839
13941
|
import { join as join21 } from "path";
|
|
13840
13942
|
import { homedir as homedir9, hostname, platform as platform4, type } from "os";
|
|
13841
13943
|
import { env } from "process";
|
|
@@ -13870,7 +13972,7 @@ class UserProfile {
|
|
|
13870
13972
|
if (!existsSync29(path))
|
|
13871
13973
|
return null;
|
|
13872
13974
|
try {
|
|
13873
|
-
const data = JSON.parse(
|
|
13975
|
+
const data = JSON.parse(readFileSync18(path, "utf-8"));
|
|
13874
13976
|
this.info = {
|
|
13875
13977
|
platform: data.platform,
|
|
13876
13978
|
os: data.os,
|
|
@@ -13905,7 +14007,7 @@ class UserProfile {
|
|
|
13905
14007
|
var init_profile = () => {};
|
|
13906
14008
|
|
|
13907
14009
|
// src/modules/skills/loader.ts
|
|
13908
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
14010
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync30, statSync as statSync5 } from "fs";
|
|
13909
14011
|
import { join as join22 } from "path";
|
|
13910
14012
|
|
|
13911
14013
|
class SkillsLoader {
|
|
@@ -13927,7 +14029,7 @@ class SkillsLoader {
|
|
|
13927
14029
|
}
|
|
13928
14030
|
if (!entry.endsWith(".md") && !entry.endsWith(".skill.md"))
|
|
13929
14031
|
continue;
|
|
13930
|
-
const content =
|
|
14032
|
+
const content = readFileSync19(fullPath, "utf-8");
|
|
13931
14033
|
const parsed = this.parseSkillFile(content, fullPath);
|
|
13932
14034
|
if (parsed)
|
|
13933
14035
|
skills.push(parsed);
|
|
@@ -14199,7 +14301,7 @@ var init_browser2 = __esm(() => {
|
|
|
14199
14301
|
});
|
|
14200
14302
|
|
|
14201
14303
|
// src/modules/indexer/walker.ts
|
|
14202
|
-
import { readdirSync as readdirSync9, readFileSync as
|
|
14304
|
+
import { readdirSync as readdirSync9, readFileSync as readFileSync20, statSync as statSync6, existsSync as existsSync31, watch } from "fs";
|
|
14203
14305
|
import { join as join23, relative, extname as extname5 } from "path";
|
|
14204
14306
|
|
|
14205
14307
|
class Indexer {
|
|
@@ -14249,7 +14351,7 @@ class Indexer {
|
|
|
14249
14351
|
const ext = extname5(entry).toLowerCase();
|
|
14250
14352
|
const language = LANGUAGES[ext];
|
|
14251
14353
|
if (language) {
|
|
14252
|
-
const content =
|
|
14354
|
+
const content = readFileSync20(fullPath, "utf-8");
|
|
14253
14355
|
const exports = this.extractExports(content, language);
|
|
14254
14356
|
files.push({ path: relPath, language, exports, size: stat.size });
|
|
14255
14357
|
totalSize += stat.size;
|
|
@@ -14301,7 +14403,7 @@ var init_walker = __esm(() => {
|
|
|
14301
14403
|
});
|
|
14302
14404
|
|
|
14303
14405
|
// src/modules/indexer/cache.ts
|
|
14304
|
-
import { readFileSync as
|
|
14406
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync13, existsSync as existsSync32, mkdirSync as mkdirSync14, rmSync as rmSync2 } from "fs";
|
|
14305
14407
|
import { join as join24 } from "path";
|
|
14306
14408
|
|
|
14307
14409
|
class IndexCache {
|
|
@@ -14316,7 +14418,7 @@ class IndexCache {
|
|
|
14316
14418
|
if (!existsSync32(this.cachePath))
|
|
14317
14419
|
return null;
|
|
14318
14420
|
try {
|
|
14319
|
-
this.cache = JSON.parse(
|
|
14421
|
+
this.cache = JSON.parse(readFileSync21(this.cachePath, "utf-8"));
|
|
14320
14422
|
return this.cache;
|
|
14321
14423
|
} catch {
|
|
14322
14424
|
return null;
|
|
@@ -14743,7 +14845,7 @@ __export(exports_bootstrap, {
|
|
|
14743
14845
|
});
|
|
14744
14846
|
import { homedir as homedir11 } from "os";
|
|
14745
14847
|
import { join as join26, resolve as resolve15 } from "path";
|
|
14746
|
-
import { existsSync as existsSync33, readFileSync as
|
|
14848
|
+
import { existsSync as existsSync33, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "fs";
|
|
14747
14849
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
14748
14850
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
14749
14851
|
const isWin = profileCompressed.toLowerCase().includes("win32");
|
|
@@ -14765,9 +14867,10 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
14765
14867
|
if (isWin) {
|
|
14766
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}`);
|
|
14767
14869
|
}
|
|
14768
|
-
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.`);
|
|
14769
14872
|
if (config.autoPlan) {
|
|
14770
|
-
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.`);
|
|
14771
14874
|
}
|
|
14772
14875
|
const hasMCP = config.mcpServers && Object.values(config.mcpServers).some((s) => s.enabled !== false);
|
|
14773
14876
|
if (hasMCP) {
|
|
@@ -14975,7 +15078,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14975
15078
|
];
|
|
14976
15079
|
for (const p of agentsMdCandidates) {
|
|
14977
15080
|
if (existsSync33(p)) {
|
|
14978
|
-
const content =
|
|
15081
|
+
const content = readFileSync22(p, "utf-8").trim();
|
|
14979
15082
|
if (content) {
|
|
14980
15083
|
agentsMdBlocks.push({
|
|
14981
15084
|
content,
|
|
@@ -15810,7 +15913,7 @@ async function runSetup() {
|
|
|
15810
15913
|
init_i18n();
|
|
15811
15914
|
import { join as join28, dirname as dirname9 } from "path";
|
|
15812
15915
|
import { homedir as homedir13 } from "os";
|
|
15813
|
-
import { existsSync as existsSync34, readFileSync as
|
|
15916
|
+
import { existsSync as existsSync34, readFileSync as readFileSync23 } from "fs";
|
|
15814
15917
|
|
|
15815
15918
|
// src/cli/security-commands.ts
|
|
15816
15919
|
init_bootstrap();
|
|
@@ -16411,7 +16514,7 @@ function readVersion() {
|
|
|
16411
16514
|
];
|
|
16412
16515
|
for (const p of candidates) {
|
|
16413
16516
|
if (existsSync34(p)) {
|
|
16414
|
-
const raw = JSON.parse(
|
|
16517
|
+
const raw = JSON.parse(readFileSync23(p, "utf8"));
|
|
16415
16518
|
if (raw.version)
|
|
16416
16519
|
return raw.version;
|
|
16417
16520
|
}
|
|
@@ -16574,7 +16677,7 @@ init_bootstrap();
|
|
|
16574
16677
|
// src/cli/repl.ts
|
|
16575
16678
|
init_colors();
|
|
16576
16679
|
import * as readline3 from "readline";
|
|
16577
|
-
import { existsSync as existsSync35, readFileSync as
|
|
16680
|
+
import { existsSync as existsSync35, readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "fs";
|
|
16578
16681
|
import { join as join29, dirname as dirname10 } from "path";
|
|
16579
16682
|
import { homedir as homedir14 } from "os";
|
|
16580
16683
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -17030,7 +17133,7 @@ function readVersion2() {
|
|
|
17030
17133
|
];
|
|
17031
17134
|
for (const p of candidates) {
|
|
17032
17135
|
if (existsSync35(p)) {
|
|
17033
|
-
const raw = JSON.parse(
|
|
17136
|
+
const raw = JSON.parse(readFileSync24(p, "utf8"));
|
|
17034
17137
|
if (raw.version)
|
|
17035
17138
|
return raw.version;
|
|
17036
17139
|
}
|
|
@@ -17123,7 +17226,7 @@ class Repl {
|
|
|
17123
17226
|
loadHistory() {
|
|
17124
17227
|
if (existsSync35(this.historyPath)) {
|
|
17125
17228
|
try {
|
|
17126
|
-
const raw =
|
|
17229
|
+
const raw = readFileSync24(this.historyPath, "utf-8");
|
|
17127
17230
|
this.history = raw.split(`
|
|
17128
17231
|
`).filter(Boolean).slice(-this.maxHistory);
|
|
17129
17232
|
} catch {
|
|
@@ -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
|