micro-models-agent 0.20.0 → 0.20.2
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 +167 -349
- 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}",
|
|
@@ -10105,285 +10115,6 @@ var init_web_browse = __esm(() => {
|
|
|
10105
10115
|
};
|
|
10106
10116
|
});
|
|
10107
10117
|
|
|
10108
|
-
// src/tools/user-input.ts
|
|
10109
|
-
import * as readline from "readline";
|
|
10110
|
-
function parseSelection(input, optionCount, multiple) {
|
|
10111
|
-
const trimmed = input.trim();
|
|
10112
|
-
if (!trimmed)
|
|
10113
|
-
return null;
|
|
10114
|
-
const parts = trimmed.split(",").map((p) => p.trim());
|
|
10115
|
-
if (!multiple && parts.length > 1)
|
|
10116
|
-
return null;
|
|
10117
|
-
const indexes = [];
|
|
10118
|
-
for (const part of parts) {
|
|
10119
|
-
if (!/^\d+$/.test(part))
|
|
10120
|
-
return null;
|
|
10121
|
-
const idx = Number(part) - 1;
|
|
10122
|
-
if (idx < 0 || idx >= optionCount)
|
|
10123
|
-
return null;
|
|
10124
|
-
if (indexes.includes(idx))
|
|
10125
|
-
return null;
|
|
10126
|
-
indexes.push(idx);
|
|
10127
|
-
}
|
|
10128
|
-
return indexes.length ? indexes : null;
|
|
10129
|
-
}
|
|
10130
|
-
function formatMenu(question, options, opts = {}) {
|
|
10131
|
-
const lines = [question];
|
|
10132
|
-
options.forEach((opt, i) => {
|
|
10133
|
-
lines.push(` [${i + 1}] ${opt.label} — ${opt.description}`);
|
|
10134
|
-
});
|
|
10135
|
-
if (opts.allowCustom) {
|
|
10136
|
-
lines.push(` [${options.length + 1}] ${t("tool.user_input.custom_option")}`);
|
|
10137
|
-
}
|
|
10138
|
-
return lines.join(`
|
|
10139
|
-
`);
|
|
10140
|
-
}
|
|
10141
|
-
function choicePrompt(optionCount, multiple) {
|
|
10142
|
-
return multiple ? t("tool.user_input.choice_multiple") : t("tool.user_input.choice_single", { max: optionCount });
|
|
10143
|
-
}
|
|
10144
|
-
function createRl() {
|
|
10145
|
-
return readline.createInterface({
|
|
10146
|
-
input: process.stdin,
|
|
10147
|
-
output: process.stdout
|
|
10148
|
-
});
|
|
10149
|
-
}
|
|
10150
|
-
function promptLine(rl, prompt) {
|
|
10151
|
-
return new Promise((resolve11) => {
|
|
10152
|
-
rl.question(prompt, (answer) => resolve11(answer));
|
|
10153
|
-
});
|
|
10154
|
-
}
|
|
10155
|
-
async function askText(question) {
|
|
10156
|
-
const rl = createRl();
|
|
10157
|
-
try {
|
|
10158
|
-
const answer = await promptLine(rl, `${question} `);
|
|
10159
|
-
return answer.trim();
|
|
10160
|
-
} finally {
|
|
10161
|
-
rl.close();
|
|
10162
|
-
}
|
|
10163
|
-
}
|
|
10164
|
-
async function askChoice(question, options, opts = {}) {
|
|
10165
|
-
const multiple = opts.multiple ?? false;
|
|
10166
|
-
const entryCount = options.length + (opts.allowCustom ? 1 : 0);
|
|
10167
|
-
const customEntry = options.length;
|
|
10168
|
-
const rl = createRl();
|
|
10169
|
-
try {
|
|
10170
|
-
console.log(formatMenu(question, options, opts));
|
|
10171
|
-
for (;; ) {
|
|
10172
|
-
const answer = await promptLine(rl, choicePrompt(entryCount, multiple));
|
|
10173
|
-
const parsed = parseSelection(answer, entryCount, multiple);
|
|
10174
|
-
if (parsed) {
|
|
10175
|
-
return parsed.map((i) => opts.allowCustom && i === customEntry ? CUSTOM_INDEX : i);
|
|
10176
|
-
}
|
|
10177
|
-
console.log(t("tool.user_input.invalid"));
|
|
10178
|
-
}
|
|
10179
|
-
} finally {
|
|
10180
|
-
rl.close();
|
|
10181
|
-
}
|
|
10182
|
-
}
|
|
10183
|
-
async function askUser(question, opts = {}) {
|
|
10184
|
-
const header = [opts.progress, opts.header].filter(Boolean).join(" — ");
|
|
10185
|
-
const text = header ? `${header}
|
|
10186
|
-
${question}` : question;
|
|
10187
|
-
if (!opts.options || opts.options.length === 0) {
|
|
10188
|
-
const answer = await askText(text);
|
|
10189
|
-
return answer ? [answer] : [];
|
|
10190
|
-
}
|
|
10191
|
-
const allowCustom = opts.custom ?? true;
|
|
10192
|
-
const indexes = await askChoice(text, opts.options, {
|
|
10193
|
-
multiple: opts.multiple,
|
|
10194
|
-
allowCustom
|
|
10195
|
-
});
|
|
10196
|
-
const labels = [];
|
|
10197
|
-
for (const idx of indexes) {
|
|
10198
|
-
if (idx === CUSTOM_INDEX) {
|
|
10199
|
-
const custom = await askText(t("tool.user_input.custom_prompt"));
|
|
10200
|
-
if (custom)
|
|
10201
|
-
labels.push(custom);
|
|
10202
|
-
} else {
|
|
10203
|
-
labels.push(opts.options[idx].label);
|
|
10204
|
-
}
|
|
10205
|
-
}
|
|
10206
|
-
return labels;
|
|
10207
|
-
}
|
|
10208
|
-
var CUSTOM_INDEX = -1;
|
|
10209
|
-
var init_user_input = __esm(() => {
|
|
10210
|
-
init_i18n();
|
|
10211
|
-
});
|
|
10212
|
-
|
|
10213
|
-
// src/tools/question.ts
|
|
10214
|
-
function isOption(val) {
|
|
10215
|
-
if (!val || typeof val !== "object")
|
|
10216
|
-
return false;
|
|
10217
|
-
const opt = val;
|
|
10218
|
-
return typeof opt.label === "string" && typeof opt.description === "string";
|
|
10219
|
-
}
|
|
10220
|
-
function normalizeQuestions(args) {
|
|
10221
|
-
const raw = args.questions;
|
|
10222
|
-
if (Array.isArray(raw)) {
|
|
10223
|
-
const specs = [];
|
|
10224
|
-
for (const item of raw) {
|
|
10225
|
-
if (!item || typeof item !== "object")
|
|
10226
|
-
continue;
|
|
10227
|
-
const q = item;
|
|
10228
|
-
if (typeof q.question !== "string" || !q.question.trim())
|
|
10229
|
-
continue;
|
|
10230
|
-
const options = Array.isArray(q.options) ? q.options.filter(isOption) : undefined;
|
|
10231
|
-
if (Array.isArray(q.options) && options.length === 0)
|
|
10232
|
-
continue;
|
|
10233
|
-
specs.push({
|
|
10234
|
-
question: q.question,
|
|
10235
|
-
header: typeof q.header === "string" ? q.header : undefined,
|
|
10236
|
-
options,
|
|
10237
|
-
multiple: q.multiple === true,
|
|
10238
|
-
custom: q.custom === false ? false : undefined
|
|
10239
|
-
});
|
|
10240
|
-
}
|
|
10241
|
-
return specs;
|
|
10242
|
-
}
|
|
10243
|
-
if (typeof args.question === "string" && args.question.trim()) {
|
|
10244
|
-
return [{ question: args.question }];
|
|
10245
|
-
}
|
|
10246
|
-
return [];
|
|
10247
|
-
}
|
|
10248
|
-
var DESCRIPTION = `Use this tool when you need to ask the user questions during execution. This allows you to:
|
|
10249
|
-
1. Gather user preferences or requirements
|
|
10250
|
-
2. Clarify ambiguous instructions
|
|
10251
|
-
3. Get decisions on implementation choices as you work
|
|
10252
|
-
4. Offer choices to the user about what direction to take.
|
|
10253
|
-
|
|
10254
|
-
Usage notes:
|
|
10255
|
-
- When "custom" is enabled (default), a "Type your own answer" option is added automatically; don't include "Other" or catch-all options
|
|
10256
|
-
- Answers are returned as arrays of labels; set "multiple": true to allow selecting more than one
|
|
10257
|
-
- If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
|
|
10258
|
-
- Execution blocks until the user answers every question
|
|
10259
|
-
- Omit "options" for a free-text question`, questionTool;
|
|
10260
|
-
var init_question = __esm(() => {
|
|
10261
|
-
init_i18n();
|
|
10262
|
-
init_user_input();
|
|
10263
|
-
questionTool = {
|
|
10264
|
-
name: "question",
|
|
10265
|
-
description: DESCRIPTION,
|
|
10266
|
-
tags: ["core"],
|
|
10267
|
-
interactive: true,
|
|
10268
|
-
parameters: {
|
|
10269
|
-
type: "object",
|
|
10270
|
-
properties: {
|
|
10271
|
-
questions: {
|
|
10272
|
-
type: "array",
|
|
10273
|
-
description: "Questions to ask",
|
|
10274
|
-
items: {
|
|
10275
|
-
type: "object",
|
|
10276
|
-
properties: {
|
|
10277
|
-
question: { type: "string", description: "Complete question" },
|
|
10278
|
-
header: {
|
|
10279
|
-
type: "string",
|
|
10280
|
-
description: "Very short label (max 30 chars)"
|
|
10281
|
-
},
|
|
10282
|
-
options: {
|
|
10283
|
-
type: "array",
|
|
10284
|
-
description: "Available choices; omit for a free-text question",
|
|
10285
|
-
items: {
|
|
10286
|
-
type: "object",
|
|
10287
|
-
properties: {
|
|
10288
|
-
label: {
|
|
10289
|
-
type: "string",
|
|
10290
|
-
description: "Display text (1-5 words, concise)"
|
|
10291
|
-
},
|
|
10292
|
-
description: {
|
|
10293
|
-
type: "string",
|
|
10294
|
-
description: "Explanation of choice"
|
|
10295
|
-
}
|
|
10296
|
-
},
|
|
10297
|
-
required: ["label", "description"]
|
|
10298
|
-
}
|
|
10299
|
-
},
|
|
10300
|
-
multiple: {
|
|
10301
|
-
type: "boolean",
|
|
10302
|
-
description: "Allow selecting multiple choices"
|
|
10303
|
-
},
|
|
10304
|
-
custom: {
|
|
10305
|
-
type: "boolean",
|
|
10306
|
-
description: "Allow typing a custom answer (default: true)"
|
|
10307
|
-
}
|
|
10308
|
-
},
|
|
10309
|
-
required: ["question"]
|
|
10310
|
-
}
|
|
10311
|
-
},
|
|
10312
|
-
question: {
|
|
10313
|
-
type: "string",
|
|
10314
|
-
description: "Legacy single free-text question"
|
|
10315
|
-
}
|
|
10316
|
-
}
|
|
10317
|
-
},
|
|
10318
|
-
handler: async (ctx, args) => {
|
|
10319
|
-
if (ctx.exitOnComplete) {
|
|
10320
|
-
return { success: false, output: t("tool.interactive_disabled") };
|
|
10321
|
-
}
|
|
10322
|
-
const questions = normalizeQuestions(args);
|
|
10323
|
-
if (questions.length === 0) {
|
|
10324
|
-
return { success: false, output: t("tool.question.no_questions") };
|
|
10325
|
-
}
|
|
10326
|
-
const answers = [];
|
|
10327
|
-
for (let i = 0;i < questions.length; i++) {
|
|
10328
|
-
const q = questions[i];
|
|
10329
|
-
const progress = questions.length > 1 ? t("tool.question.progress", {
|
|
10330
|
-
current: i + 1,
|
|
10331
|
-
total: questions.length
|
|
10332
|
-
}) : undefined;
|
|
10333
|
-
answers.push(await askUser(q.question, {
|
|
10334
|
-
header: q.header,
|
|
10335
|
-
options: q.options,
|
|
10336
|
-
multiple: q.multiple,
|
|
10337
|
-
custom: q.custom,
|
|
10338
|
-
progress
|
|
10339
|
-
}));
|
|
10340
|
-
}
|
|
10341
|
-
const formatted = questions.map((q, i) => `"${q.question}"="${answers[i].length ? answers[i].join(", ") : t("tool.question.unanswered")}"`).join(", ");
|
|
10342
|
-
return {
|
|
10343
|
-
success: true,
|
|
10344
|
-
output: t("tool.question.answered", { formatted })
|
|
10345
|
-
};
|
|
10346
|
-
}
|
|
10347
|
-
};
|
|
10348
|
-
});
|
|
10349
|
-
|
|
10350
|
-
// src/tools/approve.ts
|
|
10351
|
-
var approveTool;
|
|
10352
|
-
var init_approve = __esm(() => {
|
|
10353
|
-
init_i18n();
|
|
10354
|
-
init_user_input();
|
|
10355
|
-
approveTool = {
|
|
10356
|
-
name: "approve",
|
|
10357
|
-
description: "Request user approval for an action. The user picks Yes or No from a menu.",
|
|
10358
|
-
tags: ["core"],
|
|
10359
|
-
interactive: true,
|
|
10360
|
-
parameters: {
|
|
10361
|
-
type: "object",
|
|
10362
|
-
properties: {
|
|
10363
|
-
action: {
|
|
10364
|
-
type: "string",
|
|
10365
|
-
description: "Description of the action requiring approval"
|
|
10366
|
-
}
|
|
10367
|
-
},
|
|
10368
|
-
required: ["action"]
|
|
10369
|
-
},
|
|
10370
|
-
handler: async (ctx, args) => {
|
|
10371
|
-
if (ctx.exitOnComplete) {
|
|
10372
|
-
return { success: false, output: t("tool.interactive_disabled") };
|
|
10373
|
-
}
|
|
10374
|
-
const action = String(args.action || "");
|
|
10375
|
-
const indexes = await askChoice(t("tool.approve_prompt", { action }), [
|
|
10376
|
-
{ label: t("tool.approve_yes"), description: t("tool.approve_yes_desc") },
|
|
10377
|
-
{ label: t("tool.approve_no"), description: t("tool.approve_no_desc") }
|
|
10378
|
-
]);
|
|
10379
|
-
if (indexes[0] === 0) {
|
|
10380
|
-
return { success: true, output: t("tool.approved") };
|
|
10381
|
-
}
|
|
10382
|
-
return { success: false, output: t("tool.rejected") };
|
|
10383
|
-
}
|
|
10384
|
-
};
|
|
10385
|
-
});
|
|
10386
|
-
|
|
10387
10118
|
// src/tools/load-skill.ts
|
|
10388
10119
|
function createLoadSkillTool(skillsModule) {
|
|
10389
10120
|
return {
|
|
@@ -12384,8 +12115,6 @@ function registerAllTools(registry2, skillsModule) {
|
|
|
12384
12115
|
webSearchTool,
|
|
12385
12116
|
webFetchTool,
|
|
12386
12117
|
webBrowseTool,
|
|
12387
|
-
questionTool,
|
|
12388
|
-
approveTool,
|
|
12389
12118
|
pipelineRunTool,
|
|
12390
12119
|
mcpCallTool,
|
|
12391
12120
|
searchHistoryTool,
|
|
@@ -12418,8 +12147,6 @@ var init_tools = __esm(() => {
|
|
|
12418
12147
|
init_web_search();
|
|
12419
12148
|
init_web_fetch();
|
|
12420
12149
|
init_web_browse();
|
|
12421
|
-
init_question();
|
|
12422
|
-
init_approve();
|
|
12423
12150
|
init_load_skill();
|
|
12424
12151
|
init_pipeline_run();
|
|
12425
12152
|
init_mcp_call();
|
|
@@ -12823,11 +12550,18 @@ class StuckDetector {
|
|
|
12823
12550
|
if (!this.hasRepetitiveToolCalls())
|
|
12824
12551
|
return "";
|
|
12825
12552
|
const last = this.recentToolCalls[this.recentToolCalls.length - 1];
|
|
12826
|
-
return t("exec.repetitive_tool", {
|
|
12553
|
+
return t("exec.repetitive_tool", {
|
|
12554
|
+
tool: last.name,
|
|
12555
|
+
count: this.repetitionThreshold
|
|
12556
|
+
});
|
|
12827
12557
|
}
|
|
12828
12558
|
getStuckReason() {
|
|
12829
12559
|
if (this.isStuck()) {
|
|
12830
|
-
return t("exec.stuck", {
|
|
12560
|
+
return t("exec.stuck", {
|
|
12561
|
+
stepId: String(this.currentStepId ?? "?"),
|
|
12562
|
+
description: this.currentStepDescription,
|
|
12563
|
+
iterations: this.iterationsOnCurrentStep
|
|
12564
|
+
});
|
|
12831
12565
|
}
|
|
12832
12566
|
const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
|
|
12833
12567
|
if (errorTool) {
|
|
@@ -12837,14 +12571,23 @@ class StuckDetector {
|
|
|
12837
12571
|
}
|
|
12838
12572
|
getRecoveryMessage() {
|
|
12839
12573
|
if (this.isStuck()) {
|
|
12840
|
-
return t("exec.stuck_recovery", {
|
|
12574
|
+
return t("exec.stuck_recovery", {
|
|
12575
|
+
iterations: this.iterationsOnCurrentStep,
|
|
12576
|
+
stepId: String(this.currentStepId ?? "?"),
|
|
12577
|
+
description: this.currentStepDescription
|
|
12578
|
+
});
|
|
12841
12579
|
}
|
|
12842
12580
|
const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
|
|
12843
12581
|
if (errorTool) {
|
|
12844
|
-
return t("exec.tool_errors_recovery", {
|
|
12582
|
+
return t("exec.tool_errors_recovery", {
|
|
12583
|
+
tool: errorTool[0],
|
|
12584
|
+
count: errorTool[1]
|
|
12585
|
+
});
|
|
12845
12586
|
}
|
|
12846
12587
|
if (this.hasConsecutiveFailures()) {
|
|
12847
|
-
return t("exec.consecutive_failures_recovery", {
|
|
12588
|
+
return t("exec.consecutive_failures_recovery", {
|
|
12589
|
+
count: this.consecutiveFailures
|
|
12590
|
+
});
|
|
12848
12591
|
}
|
|
12849
12592
|
if (this.hasRepetitiveToolCalls()) {
|
|
12850
12593
|
return this.getRepetitiveToolMessage();
|
|
@@ -12859,7 +12602,11 @@ class StuckDetector {
|
|
|
12859
12602
|
const pathInCall = (toolArgStr.match(/\b[\w./-]+\.[a-z]+/gi) || []).map((p) => p.toLowerCase());
|
|
12860
12603
|
const overlaps = pathInCall.some((p) => pathInStep.some((s) => p.includes(s) || s.includes(p)));
|
|
12861
12604
|
if (!overlaps && pathInStep.length > 0 && pathInCall.length > 0) {
|
|
12862
|
-
return t("exec.off_track", {
|
|
12605
|
+
return t("exec.off_track", {
|
|
12606
|
+
stepId: String(this.currentStepId),
|
|
12607
|
+
description: this.currentStepDescription,
|
|
12608
|
+
tool: toolName
|
|
12609
|
+
});
|
|
12863
12610
|
}
|
|
12864
12611
|
return null;
|
|
12865
12612
|
}
|
|
@@ -12994,7 +12741,7 @@ class PlanPersister {
|
|
|
12994
12741
|
var init_plan_persister = () => {};
|
|
12995
12742
|
|
|
12996
12743
|
// src/modules/execution/module.ts
|
|
12997
|
-
import { existsSync as existsSync26 } from "fs";
|
|
12744
|
+
import { existsSync as existsSync26, readFileSync as readFileSync15 } from "fs";
|
|
12998
12745
|
import { resolve as resolve14 } from "path";
|
|
12999
12746
|
|
|
13000
12747
|
class ExecutionModule {
|
|
@@ -13006,6 +12753,8 @@ class ExecutionModule {
|
|
|
13006
12753
|
persister;
|
|
13007
12754
|
baseDir;
|
|
13008
12755
|
lastRecoveryIteration = -STUCK_RECOVERY_COOLDOWN;
|
|
12756
|
+
consecutivePlanWarnings = 0;
|
|
12757
|
+
lastStepId = -1;
|
|
13009
12758
|
constructor(baseDir, stuckThreshold = 8) {
|
|
13010
12759
|
this.baseDir = baseDir;
|
|
13011
12760
|
this.verifier = new StepVerifier(baseDir);
|
|
@@ -13221,10 +12970,16 @@ Sub-tasks: ${note}`
|
|
|
13221
12970
|
onBeforeThink: (ctx) => {
|
|
13222
12971
|
const step = this.tracker?.getCurrentStep();
|
|
13223
12972
|
if (this.tracker && step) {
|
|
12973
|
+
if (step.id !== this.lastStepId) {
|
|
12974
|
+
this.consecutivePlanWarnings = 0;
|
|
12975
|
+
this.lastStepId = step.id;
|
|
12976
|
+
}
|
|
13224
12977
|
this.stuckDetector.setCurrentStep(step.id, step.description);
|
|
13225
12978
|
this.stuckDetector.recordIteration(step.id);
|
|
13226
12979
|
} else {
|
|
13227
12980
|
this.stuckDetector.reset();
|
|
12981
|
+
this.consecutivePlanWarnings = 0;
|
|
12982
|
+
this.lastStepId = -1;
|
|
13228
12983
|
}
|
|
13229
12984
|
const stuckReason = this.stuckDetector.getStuckReason();
|
|
13230
12985
|
if (stuckReason) {
|
|
@@ -13251,6 +13006,16 @@ Sub-tasks: ${note}`
|
|
|
13251
13006
|
role: "user",
|
|
13252
13007
|
content: `<system-summary>${warning}</system-summary>`
|
|
13253
13008
|
});
|
|
13009
|
+
this.consecutivePlanWarnings++;
|
|
13010
|
+
if (this.consecutivePlanWarnings >= MAX_PLAN_WARNINGS_BEFORE_BLOCK) {
|
|
13011
|
+
ctx.contextManager.addMessage({
|
|
13012
|
+
role: "user",
|
|
13013
|
+
content: `<system-summary>${t("exec.plan_blocked", { step: String(this.tracker?.getCurrentStep()?.id ?? "?"), max: MAX_PLAN_WARNINGS_BEFORE_BLOCK })}</system-summary>`
|
|
13014
|
+
});
|
|
13015
|
+
return false;
|
|
13016
|
+
}
|
|
13017
|
+
} else {
|
|
13018
|
+
this.consecutivePlanWarnings = 0;
|
|
13254
13019
|
}
|
|
13255
13020
|
return true;
|
|
13256
13021
|
},
|
|
@@ -13268,7 +13033,7 @@ Sub-tasks: ${note}`
|
|
|
13268
13033
|
this.stuckDetector.recordToolSuccess();
|
|
13269
13034
|
}
|
|
13270
13035
|
if (this.tracker && result.success && (call.name === "write_file" || call.name === "edit_file")) {
|
|
13271
|
-
this.advancePlanIfStepComplete();
|
|
13036
|
+
this.advancePlanIfStepComplete(ctx.contextManager);
|
|
13272
13037
|
}
|
|
13273
13038
|
}
|
|
13274
13039
|
};
|
|
@@ -13288,9 +13053,7 @@ Sub-tasks: ${note}`
|
|
|
13288
13053
|
"glob",
|
|
13289
13054
|
"grep",
|
|
13290
13055
|
"file_info",
|
|
13291
|
-
"load_skill"
|
|
13292
|
-
"question",
|
|
13293
|
-
"approve"
|
|
13056
|
+
"load_skill"
|
|
13294
13057
|
];
|
|
13295
13058
|
if (allowedAlways.includes(call.name))
|
|
13296
13059
|
return null;
|
|
@@ -13310,24 +13073,78 @@ Sub-tasks: ${note}`
|
|
|
13310
13073
|
tool: call.name
|
|
13311
13074
|
});
|
|
13312
13075
|
}
|
|
13313
|
-
advancePlanIfStepComplete() {
|
|
13076
|
+
advancePlanIfStepComplete(contextManager) {
|
|
13314
13077
|
const step = this.tracker?.getCurrentStep();
|
|
13315
13078
|
if (!step)
|
|
13316
13079
|
return;
|
|
13080
|
+
const stepText = step.description.toLowerCase();
|
|
13317
13081
|
const stepPaths = step.description.match(/\b[\w./\\-]+\.[a-z]+/gi) || [];
|
|
13082
|
+
const isDepsStep = stepText.includes("install") || stepText.includes("зависим") || stepText.includes("init") || stepText.includes("инициализац");
|
|
13083
|
+
if (isDepsStep) {
|
|
13084
|
+
const lockFiles = [
|
|
13085
|
+
"package-lock.json",
|
|
13086
|
+
"bun.lockb",
|
|
13087
|
+
"yarn.lock",
|
|
13088
|
+
"pnpm-lock.yaml",
|
|
13089
|
+
"node_modules",
|
|
13090
|
+
"go.sum",
|
|
13091
|
+
"Cargo.lock",
|
|
13092
|
+
"Pipfile.lock",
|
|
13093
|
+
"poetry.lock",
|
|
13094
|
+
"requirements.txt"
|
|
13095
|
+
];
|
|
13096
|
+
const hasLockFile = lockFiles.some((f) => existsSync26(resolve14(this.baseDir, f)));
|
|
13097
|
+
if (!hasLockFile) {
|
|
13098
|
+
if (contextManager) {
|
|
13099
|
+
contextManager.addMessage({
|
|
13100
|
+
role: "user",
|
|
13101
|
+
content: `<system-summary>${t("exec.step_gate_deps", { step: String(step.id), description: step.description })}</system-summary>`
|
|
13102
|
+
});
|
|
13103
|
+
}
|
|
13104
|
+
return;
|
|
13105
|
+
}
|
|
13106
|
+
}
|
|
13318
13107
|
if (stepPaths.length === 0)
|
|
13319
13108
|
return;
|
|
13320
13109
|
const allExist = stepPaths.every((p) => existsSync26(resolve14(this.baseDir, p)));
|
|
13321
|
-
if (allExist)
|
|
13322
|
-
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
|
|
13326
|
-
|
|
13110
|
+
if (!allExist)
|
|
13111
|
+
return;
|
|
13112
|
+
const emptyFiles = [];
|
|
13113
|
+
for (const p of stepPaths) {
|
|
13114
|
+
try {
|
|
13115
|
+
const content = readFileSync15(resolve14(this.baseDir, p), "utf-8");
|
|
13116
|
+
if (content.trim().length < 10) {
|
|
13117
|
+
emptyFiles.push(p);
|
|
13118
|
+
}
|
|
13119
|
+
} catch {}
|
|
13120
|
+
}
|
|
13121
|
+
if (emptyFiles.length > 0 && contextManager) {
|
|
13122
|
+
contextManager.addMessage({
|
|
13123
|
+
role: "user",
|
|
13124
|
+
content: `<system-summary>${t("exec.step_gate_empty", { step: String(step.id), files: emptyFiles.join(", ") })}</system-summary>`
|
|
13125
|
+
});
|
|
13126
|
+
return;
|
|
13127
|
+
}
|
|
13128
|
+
this.tracker?.updateStepStatus(step.id, "done");
|
|
13129
|
+
const hadNext = this.tracker?.advance() ?? false;
|
|
13130
|
+
if (this.tracker) {
|
|
13131
|
+
this.persister.save(this.tracker.getPlan());
|
|
13132
|
+
}
|
|
13133
|
+
if (contextManager) {
|
|
13134
|
+
const nextStep = hadNext ? this.tracker?.getCurrentStep() : null;
|
|
13135
|
+
const nextMsg = nextStep ? t("exec.step_gate_ok", {
|
|
13136
|
+
step: String(step.id),
|
|
13137
|
+
nextStep: String(nextStep.id),
|
|
13138
|
+
nextDesc: nextStep.description
|
|
13139
|
+
}) : t("exec.step_gate_last", { step: String(step.id) });
|
|
13140
|
+
contextManager.addMessage({
|
|
13141
|
+
role: "user",
|
|
13142
|
+
content: `<system-summary>${nextMsg}</system-summary>`
|
|
13143
|
+
});
|
|
13327
13144
|
}
|
|
13328
13145
|
}
|
|
13329
13146
|
}
|
|
13330
|
-
var STUCK_RECOVERY_COOLDOWN = 5;
|
|
13147
|
+
var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3;
|
|
13331
13148
|
var init_module = __esm(() => {
|
|
13332
13149
|
init_i18n();
|
|
13333
13150
|
init_tracker();
|
|
@@ -13338,7 +13155,7 @@ var init_module = __esm(() => {
|
|
|
13338
13155
|
});
|
|
13339
13156
|
|
|
13340
13157
|
// src/modules/security/session-encryption.ts
|
|
13341
|
-
import { readFileSync as
|
|
13158
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, existsSync as existsSync27, readdirSync as readdirSync6, unlinkSync as unlinkSync3 } from "fs";
|
|
13342
13159
|
import { join as join19 } from "path";
|
|
13343
13160
|
import { homedir as homedir8 } from "os";
|
|
13344
13161
|
|
|
@@ -13388,7 +13205,7 @@ class SessionFileEncryptor {
|
|
|
13388
13205
|
return lines.map((line) => this.decryptFileContent(line));
|
|
13389
13206
|
}
|
|
13390
13207
|
readSessionFile(filePath) {
|
|
13391
|
-
const content =
|
|
13208
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13392
13209
|
return this.decryptFileContent(content);
|
|
13393
13210
|
}
|
|
13394
13211
|
writeSessionFile(filePath, content) {
|
|
@@ -13396,7 +13213,7 @@ class SessionFileEncryptor {
|
|
|
13396
13213
|
writeFileSync10(filePath, encrypted, "utf8");
|
|
13397
13214
|
}
|
|
13398
13215
|
readSessionJSON(filePath) {
|
|
13399
|
-
const content =
|
|
13216
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13400
13217
|
return this.decryptJSON(content);
|
|
13401
13218
|
}
|
|
13402
13219
|
writeSessionJSON(filePath, obj) {
|
|
@@ -13404,7 +13221,7 @@ class SessionFileEncryptor {
|
|
|
13404
13221
|
writeFileSync10(filePath, content, "utf8");
|
|
13405
13222
|
}
|
|
13406
13223
|
readSessionJSONL(filePath) {
|
|
13407
|
-
const content =
|
|
13224
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13408
13225
|
const lines = content.split(`
|
|
13409
13226
|
`).filter((line) => line.trim());
|
|
13410
13227
|
const decryptedLines = this.decryptJSONL(lines);
|
|
@@ -13423,7 +13240,7 @@ class SessionFileEncryptor {
|
|
|
13423
13240
|
const filePath = join19(sessionDir, file);
|
|
13424
13241
|
if (existsSync27(filePath) && !file.endsWith(".enc")) {
|
|
13425
13242
|
try {
|
|
13426
|
-
const content =
|
|
13243
|
+
const content = readFileSync16(filePath, "utf8");
|
|
13427
13244
|
const encrypted = this.encryptFileContent(content);
|
|
13428
13245
|
writeFileSync10(filePath + ".enc", encrypted, "utf8");
|
|
13429
13246
|
unlinkSync3(filePath);
|
|
@@ -13440,7 +13257,7 @@ class SessionFileEncryptor {
|
|
|
13440
13257
|
const encFilePath = join19(sessionDir, file);
|
|
13441
13258
|
const decFilePath = encFilePath.slice(0, -4);
|
|
13442
13259
|
try {
|
|
13443
|
-
const content =
|
|
13260
|
+
const content = readFileSync16(encFilePath, "utf8");
|
|
13444
13261
|
const decrypted = this.decryptFileContent(content);
|
|
13445
13262
|
writeFileSync10(decFilePath, decrypted, "utf8");
|
|
13446
13263
|
unlinkSync3(encFilePath);
|
|
@@ -13465,7 +13282,7 @@ import {
|
|
|
13465
13282
|
existsSync as existsSync28,
|
|
13466
13283
|
mkdirSync as mkdirSync12,
|
|
13467
13284
|
readdirSync as readdirSync7,
|
|
13468
|
-
readFileSync as
|
|
13285
|
+
readFileSync as readFileSync17,
|
|
13469
13286
|
rmSync,
|
|
13470
13287
|
writeFileSync as writeFileSync11,
|
|
13471
13288
|
appendFileSync as appendFileSync5
|
|
@@ -13525,7 +13342,7 @@ class SessionStore {
|
|
|
13525
13342
|
if (!existsSync28(path))
|
|
13526
13343
|
return null;
|
|
13527
13344
|
try {
|
|
13528
|
-
const raw =
|
|
13345
|
+
const raw = readFileSync17(path, "utf-8");
|
|
13529
13346
|
const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
|
|
13530
13347
|
return JSON.parse(content);
|
|
13531
13348
|
} catch {
|
|
@@ -13555,7 +13372,7 @@ class SessionStore {
|
|
|
13555
13372
|
if (!existsSync28(path))
|
|
13556
13373
|
return [];
|
|
13557
13374
|
try {
|
|
13558
|
-
const raw =
|
|
13375
|
+
const raw = readFileSync17(path, "utf-8");
|
|
13559
13376
|
const lines = raw.split(`
|
|
13560
13377
|
`).filter(Boolean);
|
|
13561
13378
|
if (this.encryptor?.isEnabled()) {
|
|
@@ -13584,7 +13401,7 @@ class SessionStore {
|
|
|
13584
13401
|
if (!existsSync28(path))
|
|
13585
13402
|
return [];
|
|
13586
13403
|
try {
|
|
13587
|
-
const raw =
|
|
13404
|
+
const raw = readFileSync17(path, "utf-8");
|
|
13588
13405
|
const lines = raw.split(`
|
|
13589
13406
|
`).filter(Boolean);
|
|
13590
13407
|
if (this.encryptor?.isEnabled()) {
|
|
@@ -13626,7 +13443,7 @@ class SessionStore {
|
|
|
13626
13443
|
if (updatedAt < thirtyDaysAgo) {
|
|
13627
13444
|
const historyPath = this.historyPath(session2.id);
|
|
13628
13445
|
if (existsSync28(historyPath)) {
|
|
13629
|
-
const content =
|
|
13446
|
+
const content = readFileSync17(historyPath, "utf-8");
|
|
13630
13447
|
const compressed = gzipSync(content);
|
|
13631
13448
|
const gzPath = join20(this.baseDir, `${session2.id}.jsonl.gz`);
|
|
13632
13449
|
writeFileSync11(gzPath, compressed);
|
|
@@ -13835,7 +13652,7 @@ class ProfileCompressor {
|
|
|
13835
13652
|
}
|
|
13836
13653
|
|
|
13837
13654
|
// src/modules/user-profile/profile.ts
|
|
13838
|
-
import { readFileSync as
|
|
13655
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync29, mkdirSync as mkdirSync13 } from "fs";
|
|
13839
13656
|
import { join as join21 } from "path";
|
|
13840
13657
|
import { homedir as homedir9, hostname, platform as platform4, type } from "os";
|
|
13841
13658
|
import { env } from "process";
|
|
@@ -13870,7 +13687,7 @@ class UserProfile {
|
|
|
13870
13687
|
if (!existsSync29(path))
|
|
13871
13688
|
return null;
|
|
13872
13689
|
try {
|
|
13873
|
-
const data = JSON.parse(
|
|
13690
|
+
const data = JSON.parse(readFileSync18(path, "utf-8"));
|
|
13874
13691
|
this.info = {
|
|
13875
13692
|
platform: data.platform,
|
|
13876
13693
|
os: data.os,
|
|
@@ -13905,7 +13722,7 @@ class UserProfile {
|
|
|
13905
13722
|
var init_profile = () => {};
|
|
13906
13723
|
|
|
13907
13724
|
// src/modules/skills/loader.ts
|
|
13908
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
13725
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync30, statSync as statSync5 } from "fs";
|
|
13909
13726
|
import { join as join22 } from "path";
|
|
13910
13727
|
|
|
13911
13728
|
class SkillsLoader {
|
|
@@ -13927,7 +13744,7 @@ class SkillsLoader {
|
|
|
13927
13744
|
}
|
|
13928
13745
|
if (!entry.endsWith(".md") && !entry.endsWith(".skill.md"))
|
|
13929
13746
|
continue;
|
|
13930
|
-
const content =
|
|
13747
|
+
const content = readFileSync19(fullPath, "utf-8");
|
|
13931
13748
|
const parsed = this.parseSkillFile(content, fullPath);
|
|
13932
13749
|
if (parsed)
|
|
13933
13750
|
skills.push(parsed);
|
|
@@ -14199,7 +14016,7 @@ var init_browser2 = __esm(() => {
|
|
|
14199
14016
|
});
|
|
14200
14017
|
|
|
14201
14018
|
// src/modules/indexer/walker.ts
|
|
14202
|
-
import { readdirSync as readdirSync9, readFileSync as
|
|
14019
|
+
import { readdirSync as readdirSync9, readFileSync as readFileSync20, statSync as statSync6, existsSync as existsSync31, watch } from "fs";
|
|
14203
14020
|
import { join as join23, relative, extname as extname5 } from "path";
|
|
14204
14021
|
|
|
14205
14022
|
class Indexer {
|
|
@@ -14249,7 +14066,7 @@ class Indexer {
|
|
|
14249
14066
|
const ext = extname5(entry).toLowerCase();
|
|
14250
14067
|
const language = LANGUAGES[ext];
|
|
14251
14068
|
if (language) {
|
|
14252
|
-
const content =
|
|
14069
|
+
const content = readFileSync20(fullPath, "utf-8");
|
|
14253
14070
|
const exports = this.extractExports(content, language);
|
|
14254
14071
|
files.push({ path: relPath, language, exports, size: stat.size });
|
|
14255
14072
|
totalSize += stat.size;
|
|
@@ -14301,7 +14118,7 @@ var init_walker = __esm(() => {
|
|
|
14301
14118
|
});
|
|
14302
14119
|
|
|
14303
14120
|
// src/modules/indexer/cache.ts
|
|
14304
|
-
import { readFileSync as
|
|
14121
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync13, existsSync as existsSync32, mkdirSync as mkdirSync14, rmSync as rmSync2 } from "fs";
|
|
14305
14122
|
import { join as join24 } from "path";
|
|
14306
14123
|
|
|
14307
14124
|
class IndexCache {
|
|
@@ -14316,7 +14133,7 @@ class IndexCache {
|
|
|
14316
14133
|
if (!existsSync32(this.cachePath))
|
|
14317
14134
|
return null;
|
|
14318
14135
|
try {
|
|
14319
|
-
this.cache = JSON.parse(
|
|
14136
|
+
this.cache = JSON.parse(readFileSync21(this.cachePath, "utf-8"));
|
|
14320
14137
|
return this.cache;
|
|
14321
14138
|
} catch {
|
|
14322
14139
|
return null;
|
|
@@ -14743,7 +14560,7 @@ __export(exports_bootstrap, {
|
|
|
14743
14560
|
});
|
|
14744
14561
|
import { homedir as homedir11 } from "os";
|
|
14745
14562
|
import { join as join26, resolve as resolve15 } from "path";
|
|
14746
|
-
import { existsSync as existsSync33, readFileSync as
|
|
14563
|
+
import { existsSync as existsSync33, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "fs";
|
|
14747
14564
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
14748
14565
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
14749
14566
|
const isWin = profileCompressed.toLowerCase().includes("win32");
|
|
@@ -14765,9 +14582,10 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
14765
14582
|
if (isWin) {
|
|
14766
14583
|
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
14584
|
}
|
|
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.`);
|
|
14585
|
+
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.`);
|
|
14586
|
+
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
14587
|
if (config.autoPlan) {
|
|
14770
|
-
lines.push(``, `Plan rule: For
|
|
14588
|
+
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
14589
|
}
|
|
14772
14590
|
const hasMCP = config.mcpServers && Object.values(config.mcpServers).some((s) => s.enabled !== false);
|
|
14773
14591
|
if (hasMCP) {
|
|
@@ -14975,7 +14793,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
14975
14793
|
];
|
|
14976
14794
|
for (const p of agentsMdCandidates) {
|
|
14977
14795
|
if (existsSync33(p)) {
|
|
14978
|
-
const content =
|
|
14796
|
+
const content = readFileSync22(p, "utf-8").trim();
|
|
14979
14797
|
if (content) {
|
|
14980
14798
|
agentsMdBlocks.push({
|
|
14981
14799
|
content,
|
|
@@ -15526,7 +15344,7 @@ init_config();
|
|
|
15526
15344
|
init_colors();
|
|
15527
15345
|
init_i18n();
|
|
15528
15346
|
init_spinner();
|
|
15529
|
-
import * as
|
|
15347
|
+
import * as readline from "readline";
|
|
15530
15348
|
|
|
15531
15349
|
// src/ui/box.ts
|
|
15532
15350
|
init_string_width();
|
|
@@ -15706,7 +15524,7 @@ async function testChat(apiBase, apiKey, model) {
|
|
|
15706
15524
|
}
|
|
15707
15525
|
async function runSetup() {
|
|
15708
15526
|
console.log(t("setup.title"));
|
|
15709
|
-
const rl =
|
|
15527
|
+
const rl = readline.createInterface({
|
|
15710
15528
|
input: process.stdin,
|
|
15711
15529
|
output: process.stdout
|
|
15712
15530
|
});
|
|
@@ -15810,7 +15628,7 @@ async function runSetup() {
|
|
|
15810
15628
|
init_i18n();
|
|
15811
15629
|
import { join as join28, dirname as dirname9 } from "path";
|
|
15812
15630
|
import { homedir as homedir13 } from "os";
|
|
15813
|
-
import { existsSync as existsSync34, readFileSync as
|
|
15631
|
+
import { existsSync as existsSync34, readFileSync as readFileSync23 } from "fs";
|
|
15814
15632
|
|
|
15815
15633
|
// src/cli/security-commands.ts
|
|
15816
15634
|
init_bootstrap();
|
|
@@ -16411,7 +16229,7 @@ function readVersion() {
|
|
|
16411
16229
|
];
|
|
16412
16230
|
for (const p of candidates) {
|
|
16413
16231
|
if (existsSync34(p)) {
|
|
16414
|
-
const raw = JSON.parse(
|
|
16232
|
+
const raw = JSON.parse(readFileSync23(p, "utf8"));
|
|
16415
16233
|
if (raw.version)
|
|
16416
16234
|
return raw.version;
|
|
16417
16235
|
}
|
|
@@ -16573,8 +16391,8 @@ init_bootstrap();
|
|
|
16573
16391
|
|
|
16574
16392
|
// src/cli/repl.ts
|
|
16575
16393
|
init_colors();
|
|
16576
|
-
import * as
|
|
16577
|
-
import { existsSync as existsSync35, readFileSync as
|
|
16394
|
+
import * as readline2 from "readline";
|
|
16395
|
+
import { existsSync as existsSync35, readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "fs";
|
|
16578
16396
|
import { join as join29, dirname as dirname10 } from "path";
|
|
16579
16397
|
import { homedir as homedir14 } from "os";
|
|
16580
16398
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -17030,7 +16848,7 @@ function readVersion2() {
|
|
|
17030
16848
|
];
|
|
17031
16849
|
for (const p of candidates) {
|
|
17032
16850
|
if (existsSync35(p)) {
|
|
17033
|
-
const raw = JSON.parse(
|
|
16851
|
+
const raw = JSON.parse(readFileSync24(p, "utf8"));
|
|
17034
16852
|
if (raw.version)
|
|
17035
16853
|
return raw.version;
|
|
17036
16854
|
}
|
|
@@ -17104,7 +16922,7 @@ class Repl {
|
|
|
17104
16922
|
this.registerSessionCommands();
|
|
17105
16923
|
this.registerSkillCommands();
|
|
17106
16924
|
this.setupCompleter();
|
|
17107
|
-
this.rl =
|
|
16925
|
+
this.rl = readline2.createInterface({
|
|
17108
16926
|
input: process.stdin,
|
|
17109
16927
|
output: process.stdout,
|
|
17110
16928
|
prompt: pc.cyan("> "),
|
|
@@ -17123,7 +16941,7 @@ class Repl {
|
|
|
17123
16941
|
loadHistory() {
|
|
17124
16942
|
if (existsSync35(this.historyPath)) {
|
|
17125
16943
|
try {
|
|
17126
|
-
const raw =
|
|
16944
|
+
const raw = readFileSync24(this.historyPath, "utf-8");
|
|
17127
16945
|
this.history = raw.split(`
|
|
17128
16946
|
`).filter(Boolean).slice(-this.maxHistory);
|
|
17129
16947
|
} catch {
|
|
@@ -17741,7 +17559,7 @@ class Repl {
|
|
|
17741
17559
|
this.running = false;
|
|
17742
17560
|
});
|
|
17743
17561
|
if (process.stdin.isTTY) {
|
|
17744
|
-
|
|
17562
|
+
readline2.emitKeypressEvents(process.stdin);
|
|
17745
17563
|
process.stdin.on("keypress", async (str, key) => {
|
|
17746
17564
|
if (key.name === "escape") {
|
|
17747
17565
|
const now = Date.now();
|
|
@@ -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
|