micro-models-agent 0.35.4 → 0.35.5
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 +1247 -913
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2472,6 +2472,10 @@ Command: {command}`,
|
|
|
2472
2472
|
"plan.step_already_done": "Step {step} is already done — nothing to do. Plan progress:",
|
|
2473
2473
|
"plan.order_blocked": 'Cannot mark step {step} done: step {first} ("{desc}") is not finished yet. Complete earlier steps first, or mark step {first} status=skipped if it is not needed.',
|
|
2474
2474
|
"plan.deliverables_missing": "Cannot mark step {step} done: the files it names do not exist yet: {files}. Create these files first (or mark the step status=skipped if they are not actually needed).",
|
|
2475
|
+
"plan.kinds_mismatch": "kinds array length must match steps",
|
|
2476
|
+
"plan.kinds_invalid": 'Invalid step kind(s): {kinds}. Use "create" or "delete".',
|
|
2477
|
+
"plan.kinds_not_array": 'kinds must be an array of "create" or "delete"',
|
|
2478
|
+
"plan.deliverables_remain": "Cannot mark step {step} done: the files it names still exist: {files}. This step is kind=delete — delete these files first (or set status=skipped if they should stay).",
|
|
2475
2479
|
"plan.show_header": "Plan status:",
|
|
2476
2480
|
"plan.show_empty": "(plan has no steps)",
|
|
2477
2481
|
"plan.list_header": "Plans:",
|
|
@@ -2768,6 +2772,7 @@ Use this knowledge to answer the user's question.`,
|
|
|
2768
2772
|
"exec.audit_pass": "[✓] Task complete: {done}/{total} steps done, {files} files verified",
|
|
2769
2773
|
"exec.audit_pending": "[✗] Task incomplete: {done}/{total} steps done — remaining steps are not marked done",
|
|
2770
2774
|
"exec.audit_fail": "[✗] Task incomplete: {done}/{total} steps done, {files} files missing",
|
|
2775
|
+
"exec.audit_leftovers": "[✗] Task incomplete: {done}/{total} steps done, {files} files from delete-steps still exist",
|
|
2771
2776
|
"exec.audit_fail_tests": "[✗] Task incomplete: {done}/{total} steps done, tests FAILING: {failed} failed / {passed} passed — {detail}",
|
|
2772
2777
|
"exec.audit_fail_typecheck": "[✗] Task incomplete: {done}/{total} steps done, {missing} files missing, typecheck error: {typeError}",
|
|
2773
2778
|
"exec.audit_incomplete": "[⚠ Final audit incomplete: {summary}. Task is NOT finished — continue working. Remaining steps: {steps}]",
|
|
@@ -2779,6 +2784,7 @@ Use this knowledge to answer the user's question.`,
|
|
|
2779
2784
|
[Hints]
|
|
2780
2785
|
{hints}`,
|
|
2781
2786
|
"exec.file_rewrite_warning": "⚠️ File {file} has been rewritten {count} times. Consider a different approach — the current fix strategy is not working.",
|
|
2787
|
+
"exec.forbidden_cmd": 'STOP using "{cmd}" via the bash tool — it is not a native Windows cmd.exe command and has failed repeatedly this session. Use the dedicated tool instead: grep → the grep tool, ls/dir → list_dir, find → glob, rm → delete_file, sed → edit_file, touch → write_file, which → `where`, cp/mv → move_file, diff → read_file. Do NOT call bash for this purpose again.',
|
|
2782
2788
|
"hall.max_retries_exhausted": "Model returned empty or insufficient responses after multiple retries",
|
|
2783
2789
|
"hall.short_response": "Response too short or empty",
|
|
2784
2790
|
"hall.repetitive": "Response too repetitive ({pct}% overlap)",
|
|
@@ -3064,6 +3070,10 @@ var init_ru = __esm(() => {
|
|
|
3064
3070
|
"plan.step_already_done": "Шаг {step} уже выполнен — ничего делать не нужно. Прогресс плана:",
|
|
3065
3071
|
"plan.order_blocked": "Нельзя отметить шаг {step} выполненным: шаг {first} («{desc}») ещё не завершён. Сначала завершите предыдущие шаги или отметьте шаг {first} status=skipped, если он не нужен.",
|
|
3066
3072
|
"plan.deliverables_missing": "Нельзя отметить шаг {step} выполненным: указанные в нём файлы ещё не существуют: {files}. Сначала создайте эти файлы (или отметьте шаг status=skipped, если они на самом деле не нужны).",
|
|
3073
|
+
"plan.kinds_mismatch": "Длина kinds должна совпадать с числом шагов",
|
|
3074
|
+
"plan.kinds_invalid": 'Недопустимый kind шага: {kinds}. Используй "create" или "delete".',
|
|
3075
|
+
"plan.kinds_not_array": 'kinds должен быть массивом значений "create" или "delete"',
|
|
3076
|
+
"plan.deliverables_remain": "Нельзя пометить шаг {step} как выполненный: указанные файлы всё ещё существуют: {files}. Шаг имеет kind=delete — сначала удали их (или поставь status=skipped, если они должны остаться).",
|
|
3067
3077
|
"plan.show_header": "Статус плана:",
|
|
3068
3078
|
"plan.show_empty": "(в плане нет шагов)",
|
|
3069
3079
|
"plan.list_header": "Планы:",
|
|
@@ -3360,6 +3370,7 @@ var init_ru = __esm(() => {
|
|
|
3360
3370
|
"exec.audit_pass": "[✓] Задача выполнена: {done}/{total} шагов, {files} файлов проверено",
|
|
3361
3371
|
"exec.audit_pending": "[✗] Задача не выполнена: {done}/{total} шагов — оставшиеся шаги не отмечены выполненными",
|
|
3362
3372
|
"exec.audit_fail": "[✗] Задача не выполнена: {done}/{total} шагов, {files} файлов отсутствует",
|
|
3373
|
+
"exec.audit_leftovers": "[✗] Задача не выполнена: {done}/{total} шагов, {files} файлов из delete-шагов всё ещё существуют",
|
|
3363
3374
|
"exec.audit_fail_tests": "[✗] Задача не выполнена: {done}/{total} шагов, тесты ПАДАЮТ: {failed} failed / {passed} passed — {detail}",
|
|
3364
3375
|
"exec.audit_fail_typecheck": "[✗] Задача не выполнена: {done}/{total} шагов, {missing} файлов отсутствует, ошибка typecheck: {typeError}",
|
|
3365
3376
|
"exec.audit_incomplete": "[⚠ Финальная проверка не пройдена: {summary}. Задача НЕ завершена — продолжайте работу. Оставшиеся шаги: {steps}]",
|
|
@@ -3371,6 +3382,7 @@ var init_ru = __esm(() => {
|
|
|
3371
3382
|
[Подсказки]
|
|
3372
3383
|
{hints}`,
|
|
3373
3384
|
"exec.file_rewrite_warning": "⚠️ Файл {file} был перезаписан {count} раз. Попробуйте другой подход — текущая стратегия исправлений не работает.",
|
|
3385
|
+
"exec.forbidden_cmd": 'ПРЕКРАТИ использовать "{cmd}" через bash — это не команда Windows cmd.exe, и она уже неоднократно падала в этой сессии. Используй предназначенный тул: grep → тул grep, ls/dir → list_dir, find → glob, rm → delete_file, sed → edit_file, touch → write_file, which → `where`, cp/mv → move_file, diff → read_file. Больше не вызывай bash для этого.',
|
|
3374
3386
|
"hall.max_retries_exhausted": "Модель вернула пустой или недостаточный ответ после нескольких попыток",
|
|
3375
3387
|
"hall.short_response": "Слишком короткий или пустой ответ",
|
|
3376
3388
|
"hall.repetitive": "Слишком повторяющийся ответ ({pct}% совпадение)",
|
|
@@ -4902,6 +4914,30 @@ var exports_openai_compat = {};
|
|
|
4902
4914
|
__export(exports_openai_compat, {
|
|
4903
4915
|
OpenAICompatProvider: () => OpenAICompatProvider
|
|
4904
4916
|
});
|
|
4917
|
+
function buildRequestBody(opts) {
|
|
4918
|
+
const body = {
|
|
4919
|
+
model: opts.model,
|
|
4920
|
+
messages: opts.messages,
|
|
4921
|
+
stream: opts.stream
|
|
4922
|
+
};
|
|
4923
|
+
if (opts.maxTokens !== undefined)
|
|
4924
|
+
body.max_tokens = opts.maxTokens;
|
|
4925
|
+
if (opts.reasoningEffort) {
|
|
4926
|
+
body.reasoning_effort = opts.reasoningEffort;
|
|
4927
|
+
}
|
|
4928
|
+
if (opts.tools && opts.tools.length > 0) {
|
|
4929
|
+
body.tools = opts.tools.map((t2) => ({
|
|
4930
|
+
type: "function",
|
|
4931
|
+
function: {
|
|
4932
|
+
name: t2.name,
|
|
4933
|
+
description: t2.description,
|
|
4934
|
+
parameters: t2.parameters
|
|
4935
|
+
}
|
|
4936
|
+
}));
|
|
4937
|
+
body.tool_choice = "auto";
|
|
4938
|
+
}
|
|
4939
|
+
return body;
|
|
4940
|
+
}
|
|
4905
4941
|
|
|
4906
4942
|
class OpenAICompatProvider {
|
|
4907
4943
|
model;
|
|
@@ -4949,26 +4985,14 @@ class OpenAICompatProvider {
|
|
|
4949
4985
|
}
|
|
4950
4986
|
}
|
|
4951
4987
|
async* doStream(messages, tools, signal, options) {
|
|
4952
|
-
const body = {
|
|
4988
|
+
const body = buildRequestBody({
|
|
4953
4989
|
model: this.model,
|
|
4954
4990
|
messages,
|
|
4991
|
+
tools,
|
|
4955
4992
|
stream: true,
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
body.reasoning_effort = options.reasoningEffort;
|
|
4960
|
-
}
|
|
4961
|
-
if (tools && tools.length > 0) {
|
|
4962
|
-
body.tools = tools.map((t2) => ({
|
|
4963
|
-
type: "function",
|
|
4964
|
-
function: {
|
|
4965
|
-
name: t2.name,
|
|
4966
|
-
description: t2.description,
|
|
4967
|
-
parameters: t2.parameters
|
|
4968
|
-
}
|
|
4969
|
-
}));
|
|
4970
|
-
body.tool_choice = "auto";
|
|
4971
|
-
}
|
|
4993
|
+
maxTokens: options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096,
|
|
4994
|
+
reasoningEffort: options?.reasoningEffort
|
|
4995
|
+
});
|
|
4972
4996
|
const headers = {
|
|
4973
4997
|
"Content-Type": "application/json"
|
|
4974
4998
|
};
|
|
@@ -5094,26 +5118,14 @@ class OpenAICompatProvider {
|
|
|
5094
5118
|
}
|
|
5095
5119
|
}
|
|
5096
5120
|
async doNonStreaming(messages, tools, signal, options) {
|
|
5097
|
-
const body = {
|
|
5121
|
+
const body = buildRequestBody({
|
|
5098
5122
|
model: this.model,
|
|
5099
5123
|
messages,
|
|
5124
|
+
tools,
|
|
5100
5125
|
stream: false,
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
body.reasoning_effort = options.reasoningEffort;
|
|
5105
|
-
}
|
|
5106
|
-
if (tools && tools.length > 0) {
|
|
5107
|
-
body.tools = tools.map((t2) => ({
|
|
5108
|
-
type: "function",
|
|
5109
|
-
function: {
|
|
5110
|
-
name: t2.name,
|
|
5111
|
-
description: t2.description,
|
|
5112
|
-
parameters: t2.parameters
|
|
5113
|
-
}
|
|
5114
|
-
}));
|
|
5115
|
-
body.tool_choice = "auto";
|
|
5116
|
-
}
|
|
5126
|
+
maxTokens: options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096,
|
|
5127
|
+
reasoningEffort: options?.reasoningEffort
|
|
5128
|
+
});
|
|
5117
5129
|
const headers = {
|
|
5118
5130
|
"Content-Type": "application/json"
|
|
5119
5131
|
};
|
|
@@ -9374,13 +9386,14 @@ class StuckDetector {
|
|
|
9374
9386
|
if (desc.includes("deploy") || desc.includes("publish")) {
|
|
9375
9387
|
hints.push("Verify credentials and network access before deploying.");
|
|
9376
9388
|
}
|
|
9377
|
-
|
|
9389
|
+
const primary = this.getPrimaryReason();
|
|
9390
|
+
if (this.hasRepetitiveToolCalls() && primary !== "repetitive") {
|
|
9378
9391
|
hints.push("You are calling the same tool repeatedly with the same arguments. Try a different approach.");
|
|
9379
9392
|
}
|
|
9380
|
-
if (this.hasConsecutiveFailures()) {
|
|
9393
|
+
if (this.hasConsecutiveFailures() && primary !== "consecutive") {
|
|
9381
9394
|
hints.push("Multiple different tools are failing. Check if the environment is set up correctly.");
|
|
9382
9395
|
}
|
|
9383
|
-
if (this.hasReadOnlyLoop()) {
|
|
9396
|
+
if (this.hasReadOnlyLoop() && primary !== "read-only") {
|
|
9384
9397
|
hints.push("You have made many read-only tool calls (read_file/glob/grep/browser) without writing anything. Stop exploring — make the edit/write the task needs, or use the plan tool to decide next steps.");
|
|
9385
9398
|
}
|
|
9386
9399
|
return hints;
|
|
@@ -9506,35 +9519,50 @@ class StuckDetector {
|
|
|
9506
9519
|
return "";
|
|
9507
9520
|
}
|
|
9508
9521
|
getRecoveryMessage() {
|
|
9509
|
-
|
|
9522
|
+
const reason = this.getPrimaryReason();
|
|
9523
|
+
if (reason === "stuck") {
|
|
9510
9524
|
return t("exec.stuck_recovery", {
|
|
9511
9525
|
iterations: this.iterationsOnCurrentStep,
|
|
9512
9526
|
stepId: String(this.currentStepId ?? "?"),
|
|
9513
9527
|
description: this.currentStepDescription
|
|
9514
9528
|
});
|
|
9515
9529
|
}
|
|
9516
|
-
|
|
9517
|
-
|
|
9530
|
+
if (reason === "tool-errors") {
|
|
9531
|
+
const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
|
|
9518
9532
|
return t("exec.tool_errors_recovery", {
|
|
9519
9533
|
tool: errorTool[0],
|
|
9520
9534
|
count: errorTool[1]
|
|
9521
9535
|
});
|
|
9522
9536
|
}
|
|
9523
|
-
if (
|
|
9537
|
+
if (reason === "consecutive") {
|
|
9524
9538
|
return t("exec.consecutive_failures_recovery", {
|
|
9525
9539
|
count: this.consecutiveFailures
|
|
9526
9540
|
});
|
|
9527
9541
|
}
|
|
9528
|
-
if (
|
|
9542
|
+
if (reason === "repetitive") {
|
|
9529
9543
|
return this.getRepetitiveToolMessage();
|
|
9530
9544
|
}
|
|
9531
|
-
if (
|
|
9545
|
+
if (reason === "read-only") {
|
|
9532
9546
|
return t("exec.read_only_loop_recovery", {
|
|
9533
9547
|
count: String(this.readOnlyStreak)
|
|
9534
9548
|
});
|
|
9535
9549
|
}
|
|
9536
9550
|
return "";
|
|
9537
9551
|
}
|
|
9552
|
+
getPrimaryReason() {
|
|
9553
|
+
if (this.isStuck())
|
|
9554
|
+
return "stuck";
|
|
9555
|
+
const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
|
|
9556
|
+
if (errorTool)
|
|
9557
|
+
return "tool-errors";
|
|
9558
|
+
if (this.hasConsecutiveFailures())
|
|
9559
|
+
return "consecutive";
|
|
9560
|
+
if (this.hasRepetitiveToolCalls())
|
|
9561
|
+
return "repetitive";
|
|
9562
|
+
if (this.hasReadOnlyLoop())
|
|
9563
|
+
return "read-only";
|
|
9564
|
+
return null;
|
|
9565
|
+
}
|
|
9538
9566
|
reset() {
|
|
9539
9567
|
this.currentStepId = null;
|
|
9540
9568
|
this.iterationsOnCurrentStep = 0;
|
|
@@ -11009,6 +11037,105 @@ var init_agent = __esm(() => {
|
|
|
11009
11037
|
init_verifier();
|
|
11010
11038
|
});
|
|
11011
11039
|
|
|
11040
|
+
// src/modules/context/fact-extractor.ts
|
|
11041
|
+
class FactExtractor {
|
|
11042
|
+
fileFacts = [];
|
|
11043
|
+
deletedFacts = [];
|
|
11044
|
+
decisionFacts = [];
|
|
11045
|
+
errorFacts = [];
|
|
11046
|
+
static MAX_FACTS = 20;
|
|
11047
|
+
get errorCount() {
|
|
11048
|
+
return this.errorFacts.length;
|
|
11049
|
+
}
|
|
11050
|
+
extract(turns) {
|
|
11051
|
+
const DRIVE = "(?:[a-zA-Z]:[\\\\/])?";
|
|
11052
|
+
const createdPatterns = [
|
|
11053
|
+
new RegExp(`(?:Created|Updated|Written|Moved|Replaced in) ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
|
|
11054
|
+
new RegExp(`Файл (?:создан|обновлён|записан|перемещён):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
|
|
11055
|
+
new RegExp(`file (?:created|updated|written|moved):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi")
|
|
11056
|
+
];
|
|
11057
|
+
const deletedPatterns = [
|
|
11058
|
+
new RegExp(`Deleted ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
|
|
11059
|
+
new RegExp(`(?:Удалён|Файл удалён):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi")
|
|
11060
|
+
];
|
|
11061
|
+
const newFiles = [];
|
|
11062
|
+
const newDeleted = [];
|
|
11063
|
+
const newDecisions = [];
|
|
11064
|
+
const newErrors = [];
|
|
11065
|
+
const lastEvent = new Map;
|
|
11066
|
+
for (const msg of turns) {
|
|
11067
|
+
const content = getMessageText(msg.content);
|
|
11068
|
+
if (msg.role === "user" && (content.startsWith("<system-summary>") || content.includes("[Compressed:"))) {
|
|
11069
|
+
continue;
|
|
11070
|
+
}
|
|
11071
|
+
if (msg.role === "tool") {
|
|
11072
|
+
for (const pattern of createdPatterns) {
|
|
11073
|
+
for (const match of content.matchAll(pattern)) {
|
|
11074
|
+
newFiles.push(match[1]);
|
|
11075
|
+
lastEvent.set(match[1], "file");
|
|
11076
|
+
}
|
|
11077
|
+
}
|
|
11078
|
+
for (const pattern of deletedPatterns) {
|
|
11079
|
+
for (const match of content.matchAll(pattern)) {
|
|
11080
|
+
newDeleted.push(match[1]);
|
|
11081
|
+
lastEvent.set(match[1], "deleted");
|
|
11082
|
+
}
|
|
11083
|
+
}
|
|
11084
|
+
if (content.includes("Plan:") && content.includes("[")) {
|
|
11085
|
+
const planLine = content.split(`
|
|
11086
|
+
`).find((line) => line.includes("Plan:"));
|
|
11087
|
+
if (planLine)
|
|
11088
|
+
newDecisions.push(planLine.trim());
|
|
11089
|
+
}
|
|
11090
|
+
}
|
|
11091
|
+
if (msg.role === "assistant") {
|
|
11092
|
+
if (content.includes("decided:") || content.includes("decision:")) {
|
|
11093
|
+
const line = content.split(`
|
|
11094
|
+
`).find((l) => l.includes("decided:") || l.includes("decision:"));
|
|
11095
|
+
if (line)
|
|
11096
|
+
newDecisions.push(line.trim().slice(0, 200));
|
|
11097
|
+
}
|
|
11098
|
+
}
|
|
11099
|
+
if (content.includes("Error:") || content.includes("failed") || content.includes("Ошибка:") || content.includes("не удалось")) {
|
|
11100
|
+
const line = content.split(`
|
|
11101
|
+
`).find((l) => l.includes("Error:") || l.includes("failed") || l.includes("Ошибка:") || l.includes("не удалось"));
|
|
11102
|
+
if (line)
|
|
11103
|
+
newErrors.push(line.trim().slice(0, 250));
|
|
11104
|
+
}
|
|
11105
|
+
}
|
|
11106
|
+
const dedup = (arr) => [...new Set(arr)];
|
|
11107
|
+
const finalFiles = dedup(newFiles.filter((p) => lastEvent.get(p) === "file"));
|
|
11108
|
+
const finalDeleted = dedup(newDeleted.filter((p) => lastEvent.get(p) === "deleted"));
|
|
11109
|
+
this.fileFacts = dedup([...this.fileFacts, ...finalFiles].filter((p) => !finalDeleted.includes(p))).slice(-FactExtractor.MAX_FACTS);
|
|
11110
|
+
this.deletedFacts = dedup([...this.deletedFacts, ...finalDeleted].filter((p) => !finalFiles.includes(p))).slice(-FactExtractor.MAX_FACTS);
|
|
11111
|
+
this.decisionFacts = dedup([...this.decisionFacts, ...newDecisions]).slice(-FactExtractor.MAX_FACTS);
|
|
11112
|
+
this.errorFacts = dedup([...this.errorFacts, ...newErrors]).slice(-FactExtractor.MAX_FACTS);
|
|
11113
|
+
}
|
|
11114
|
+
filesLine() {
|
|
11115
|
+
const deletedSet = new Set(this.deletedFacts);
|
|
11116
|
+
const liveFiles = this.fileFacts.filter((p) => !deletedSet.has(p));
|
|
11117
|
+
if (liveFiles.length === 0)
|
|
11118
|
+
return null;
|
|
11119
|
+
return `[Files: ${liveFiles.slice(-15).join("; ")}]`;
|
|
11120
|
+
}
|
|
11121
|
+
deletedLine() {
|
|
11122
|
+
if (this.deletedFacts.length === 0)
|
|
11123
|
+
return null;
|
|
11124
|
+
return `[Deleted: ${this.deletedFacts.slice(-10).join("; ")}]`;
|
|
11125
|
+
}
|
|
11126
|
+
decisionsLine() {
|
|
11127
|
+
if (this.decisionFacts.length === 0)
|
|
11128
|
+
return null;
|
|
11129
|
+
return `[Decisions: ${this.decisionFacts.slice(-5).join("; ")}]`;
|
|
11130
|
+
}
|
|
11131
|
+
errorsLine() {
|
|
11132
|
+
if (this.errorFacts.length === 0)
|
|
11133
|
+
return null;
|
|
11134
|
+
return `[Errors: ${this.errorFacts.slice(-3).join("; ")}]`;
|
|
11135
|
+
}
|
|
11136
|
+
}
|
|
11137
|
+
var init_fact_extractor = () => {};
|
|
11138
|
+
|
|
11012
11139
|
// src/modules/context/manager.ts
|
|
11013
11140
|
function summarizeArgs(args) {
|
|
11014
11141
|
if (!args)
|
|
@@ -11027,6 +11154,18 @@ function truncate(s, max) {
|
|
|
11027
11154
|
return s;
|
|
11028
11155
|
return s.slice(0, max - 3) + "...";
|
|
11029
11156
|
}
|
|
11157
|
+
function looksLikeErrorPaste(text) {
|
|
11158
|
+
if (/(?:^|\s)ERROR|Error:|error TS\d+|Transform failed|\[plugin:|SyntaxError|Cannot find|Uncaught|exception/i.test(text)) {
|
|
11159
|
+
return true;
|
|
11160
|
+
}
|
|
11161
|
+
if (/(?:^|\n)\s*\d+\s*\|/.test(text))
|
|
11162
|
+
return true;
|
|
11163
|
+
if (/[\w./\\-]+\.[a-z]{1,6}:\d+:\d+/.test(text))
|
|
11164
|
+
return true;
|
|
11165
|
+
if (/(?:^|\n)\s*at\s+\S+/.test(text))
|
|
11166
|
+
return true;
|
|
11167
|
+
return false;
|
|
11168
|
+
}
|
|
11030
11169
|
function extractTriedAndFailed(messages) {
|
|
11031
11170
|
const failures = new Map;
|
|
11032
11171
|
for (const msg of messages) {
|
|
@@ -11058,11 +11197,10 @@ class ContextManager {
|
|
|
11058
11197
|
peakTokens = 0;
|
|
11059
11198
|
budget;
|
|
11060
11199
|
compactionThreshold;
|
|
11061
|
-
|
|
11062
|
-
decisionFacts = [];
|
|
11063
|
-
errorFacts = [];
|
|
11200
|
+
facts = new FactExtractor;
|
|
11064
11201
|
lastUserTask = "";
|
|
11065
|
-
|
|
11202
|
+
sessionMission = "";
|
|
11203
|
+
lastUserFeedback = "";
|
|
11066
11204
|
tokenCounter;
|
|
11067
11205
|
pendingImageParts = [];
|
|
11068
11206
|
toolTokens = 0;
|
|
@@ -11101,6 +11239,7 @@ class ContextManager {
|
|
|
11101
11239
|
resetUserTurn() {
|
|
11102
11240
|
this.iterationsSinceCompaction = 0;
|
|
11103
11241
|
this.lastUserTask = "";
|
|
11242
|
+
this.lastUserFeedback = "";
|
|
11104
11243
|
}
|
|
11105
11244
|
getQuality() {
|
|
11106
11245
|
const usedTokens = this.getEstimatedTokens();
|
|
@@ -11108,16 +11247,22 @@ class ContextManager {
|
|
|
11108
11247
|
const COMPACTION_PENALTY_FLOOR = 0.5;
|
|
11109
11248
|
const compactionLoss = Math.max(COMPACTION_PENALTY_FLOOR, 1 - this.compactionCount * 0.15);
|
|
11110
11249
|
const msgCount = this.messages.length || 1;
|
|
11111
|
-
const errorDensity = Math.max(0, 1 - Math.min(1, this.
|
|
11250
|
+
const errorDensity = Math.max(0, 1 - Math.min(1, this.facts.errorCount / msgCount));
|
|
11112
11251
|
const freshness = Math.max(0, 1 - this.iterationsSinceCompaction / COMPACTION_INTERVAL);
|
|
11113
11252
|
const score = tokenLoad * 0.4 + compactionLoss * 0.25 + errorDensity * 0.2 + freshness * 0.15;
|
|
11114
11253
|
return Math.round(Math.min(100, Math.max(0, score * 100)));
|
|
11115
11254
|
}
|
|
11116
11255
|
addMessage(msg) {
|
|
11117
|
-
if (msg.role === "user"
|
|
11256
|
+
if (msg.role === "user") {
|
|
11118
11257
|
const text = typeof msg.content === "string" ? msg.content : getMessageText(msg.content);
|
|
11119
11258
|
if (text.trim() && !text.startsWith("<system-summary>") && !text.includes("[Compressed:")) {
|
|
11120
|
-
this.lastUserTask
|
|
11259
|
+
if (looksLikeErrorPaste(text) && (this.lastUserTask || this.sessionMission)) {
|
|
11260
|
+
this.lastUserFeedback = text.trim().slice(0, 400);
|
|
11261
|
+
} else if (!this.lastUserTask && !this.lastUserFeedback) {
|
|
11262
|
+
this.lastUserTask = text.trim();
|
|
11263
|
+
if (!this.sessionMission)
|
|
11264
|
+
this.sessionMission = text.trim();
|
|
11265
|
+
}
|
|
11121
11266
|
}
|
|
11122
11267
|
}
|
|
11123
11268
|
if (msg.role === "user" && this.pendingImageParts.length > 0) {
|
|
@@ -11206,22 +11351,27 @@ class ContextManager {
|
|
|
11206
11351
|
const cutoff = this.messages.length - KEEP_LAST_N * 2;
|
|
11207
11352
|
const oldTurns = this.messages.slice(0, cutoff);
|
|
11208
11353
|
const recentTurns = this.messages.slice(cutoff);
|
|
11209
|
-
this.
|
|
11354
|
+
this.facts.extract(oldTurns);
|
|
11210
11355
|
const parts = [];
|
|
11211
11356
|
parts.push(`[Compressed: ${oldTurns.length} old turns removed]`);
|
|
11212
|
-
|
|
11213
|
-
|
|
11357
|
+
const task = (this.lastUserTask || this.sessionMission).slice(0, 400);
|
|
11358
|
+
if (task)
|
|
11214
11359
|
parts.push(`[Task: ${task}]`);
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
if (
|
|
11220
|
-
parts.push(
|
|
11221
|
-
|
|
11222
|
-
if (
|
|
11223
|
-
parts.push(
|
|
11224
|
-
|
|
11360
|
+
if (this.lastUserFeedback && !task.startsWith(this.lastUserFeedback)) {
|
|
11361
|
+
parts.push(`[User feedback: ${this.lastUserFeedback}]`);
|
|
11362
|
+
}
|
|
11363
|
+
const filesLine = this.facts.filesLine();
|
|
11364
|
+
if (filesLine)
|
|
11365
|
+
parts.push(filesLine);
|
|
11366
|
+
const deletedLine = this.facts.deletedLine();
|
|
11367
|
+
if (deletedLine)
|
|
11368
|
+
parts.push(deletedLine);
|
|
11369
|
+
const decisionsLine = this.facts.decisionsLine();
|
|
11370
|
+
if (decisionsLine)
|
|
11371
|
+
parts.push(decisionsLine);
|
|
11372
|
+
const errorsLine = this.facts.errorsLine();
|
|
11373
|
+
if (errorsLine)
|
|
11374
|
+
parts.push(errorsLine);
|
|
11225
11375
|
const triedAndFailed = extractTriedAndFailed(oldTurns);
|
|
11226
11376
|
if (triedAndFailed.length > 0) {
|
|
11227
11377
|
const lines = triedAndFailed.map((t2) => `- ${t2.tool}(${t2.args}): ${t2.error} (failed ${t2.count}x)`);
|
|
@@ -11251,55 +11401,6 @@ ${lines.join(`
|
|
|
11251
11401
|
this.onCompact(summary);
|
|
11252
11402
|
}
|
|
11253
11403
|
}
|
|
11254
|
-
extractFacts(turns) {
|
|
11255
|
-
const DRIVE = "(?:[a-zA-Z]:[\\\\/])?";
|
|
11256
|
-
const filePatterns = [
|
|
11257
|
-
new RegExp(`(?:Created|Updated|Written|Deleted|Moved) ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
|
|
11258
|
-
new RegExp(`Replaced in ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
|
|
11259
|
-
new RegExp(`Файл (?:создан|обновлён|записан|удалён|перемещён):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
|
|
11260
|
-
new RegExp(`file (?:created|updated|written|deleted|moved):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi")
|
|
11261
|
-
];
|
|
11262
|
-
const newFiles = [];
|
|
11263
|
-
const newDecisions = [];
|
|
11264
|
-
const newErrors = [];
|
|
11265
|
-
for (const msg of turns) {
|
|
11266
|
-
const content = getMessageText(msg.content);
|
|
11267
|
-
if (msg.role === "user" && (content.startsWith("<system-summary>") || content.includes("[Compressed:"))) {
|
|
11268
|
-
continue;
|
|
11269
|
-
}
|
|
11270
|
-
if (msg.role === "tool") {
|
|
11271
|
-
for (const pattern of filePatterns) {
|
|
11272
|
-
for (const match of content.matchAll(pattern)) {
|
|
11273
|
-
newFiles.push(match[1]);
|
|
11274
|
-
}
|
|
11275
|
-
}
|
|
11276
|
-
if (content.includes("Plan:") && content.includes("[")) {
|
|
11277
|
-
const planLine = content.split(`
|
|
11278
|
-
`).find((line) => line.includes("Plan:"));
|
|
11279
|
-
if (planLine)
|
|
11280
|
-
newDecisions.push(planLine.trim());
|
|
11281
|
-
}
|
|
11282
|
-
}
|
|
11283
|
-
if (msg.role === "assistant") {
|
|
11284
|
-
if (content.includes("decided:") || content.includes("decision:")) {
|
|
11285
|
-
const line = content.split(`
|
|
11286
|
-
`).find((l) => l.includes("decided:") || l.includes("decision:"));
|
|
11287
|
-
if (line)
|
|
11288
|
-
newDecisions.push(line.trim().slice(0, 200));
|
|
11289
|
-
}
|
|
11290
|
-
}
|
|
11291
|
-
if (content.includes("Error:") || content.includes("failed") || content.includes("Ошибка:") || content.includes("не удалось")) {
|
|
11292
|
-
const line = content.split(`
|
|
11293
|
-
`).find((l) => l.includes("Error:") || l.includes("failed") || l.includes("Ошибка:") || l.includes("не удалось"));
|
|
11294
|
-
if (line)
|
|
11295
|
-
newErrors.push(line.trim().slice(0, 250));
|
|
11296
|
-
}
|
|
11297
|
-
}
|
|
11298
|
-
const dedup = (arr) => [...new Set(arr)];
|
|
11299
|
-
this.fileFacts = dedup([...this.fileFacts, ...newFiles]).slice(-ContextManager.MAX_FACTS);
|
|
11300
|
-
this.decisionFacts = dedup([...this.decisionFacts, ...newDecisions]).slice(-ContextManager.MAX_FACTS);
|
|
11301
|
-
this.errorFacts = dedup([...this.errorFacts, ...newErrors]).slice(-ContextManager.MAX_FACTS);
|
|
11302
|
-
}
|
|
11303
11404
|
updateSystemPrompt(content) {
|
|
11304
11405
|
const idx = this.messages.findIndex((m) => m.role === "system");
|
|
11305
11406
|
if (idx >= 0) {
|
|
@@ -11318,6 +11419,8 @@ ${lines.join(`
|
|
|
11318
11419
|
this.compactionCount = 0;
|
|
11319
11420
|
this.peakTokens = 0;
|
|
11320
11421
|
this.lastUserTask = "";
|
|
11422
|
+
this.lastUserFeedback = "";
|
|
11423
|
+
this.sessionMission = "";
|
|
11321
11424
|
}
|
|
11322
11425
|
getEstimatedTokens() {
|
|
11323
11426
|
return this.messages.reduce((sum, m) => sum + this.estimateMessageTokens(m), 0) + this.toolTokens;
|
|
@@ -11334,7 +11437,9 @@ ${lines.join(`
|
|
|
11334
11437
|
}
|
|
11335
11438
|
}
|
|
11336
11439
|
var COMPACTION_INTERVAL = 15, KEEP_LAST_N = 6;
|
|
11337
|
-
var init_manager = () => {
|
|
11440
|
+
var init_manager = __esm(() => {
|
|
11441
|
+
init_fact_extractor();
|
|
11442
|
+
});
|
|
11338
11443
|
|
|
11339
11444
|
// src/modules/hallucination/consistency.ts
|
|
11340
11445
|
class ConsistencyCheck {
|
|
@@ -11445,6 +11550,10 @@ function isFilePathLike(s) {
|
|
|
11445
11550
|
return false;
|
|
11446
11551
|
return FILE_EXTENSIONS.has(ext);
|
|
11447
11552
|
}
|
|
11553
|
+
const last = s.split(/[\\/]/).pop() ?? "";
|
|
11554
|
+
const lastDot = last.lastIndexOf(".");
|
|
11555
|
+
if (lastDot <= 0)
|
|
11556
|
+
return false;
|
|
11448
11557
|
return true;
|
|
11449
11558
|
}
|
|
11450
11559
|
function extractFileLikeTokens(text) {
|
|
@@ -15708,7 +15817,7 @@ class PlanCreator {
|
|
|
15708
15817
|
const hasActionWord = actionWords.some((w) => task.toLowerCase().includes(w));
|
|
15709
15818
|
return hasActionWord && words.length > 8;
|
|
15710
15819
|
}
|
|
15711
|
-
static createPlan(title, stepDescriptions, baseDir) {
|
|
15820
|
+
static createPlan(title, stepDescriptions, baseDir, kinds) {
|
|
15712
15821
|
const stepCount = stepDescriptions.length;
|
|
15713
15822
|
return {
|
|
15714
15823
|
id: generatePlanId(),
|
|
@@ -15716,7 +15825,8 @@ class PlanCreator {
|
|
|
15716
15825
|
steps: stepDescriptions.map((desc, i) => ({
|
|
15717
15826
|
id: i + 1,
|
|
15718
15827
|
description: desc,
|
|
15719
|
-
status: "pending"
|
|
15828
|
+
status: "pending",
|
|
15829
|
+
kind: kinds?.[i] ?? "create"
|
|
15720
15830
|
})),
|
|
15721
15831
|
createdAt: new Date().toISOString(),
|
|
15722
15832
|
baseDir
|
|
@@ -15730,7 +15840,8 @@ class PlanCreator {
|
|
|
15730
15840
|
const added = newSteps.map((desc, i) => ({
|
|
15731
15841
|
id: kept.length + i + 1,
|
|
15732
15842
|
description: desc,
|
|
15733
|
-
status: "pending"
|
|
15843
|
+
status: "pending",
|
|
15844
|
+
kind: "create"
|
|
15734
15845
|
}));
|
|
15735
15846
|
return {
|
|
15736
15847
|
id: plan.id,
|
|
@@ -15822,42 +15933,9 @@ class PlanTracker {
|
|
|
15822
15933
|
}
|
|
15823
15934
|
var init_tracker = () => {};
|
|
15824
15935
|
|
|
15825
|
-
// src/modules/execution/
|
|
15826
|
-
import {
|
|
15827
|
-
import {
|
|
15828
|
-
function findExistingFile(baseDir, filePath) {
|
|
15829
|
-
const direct = resolve17(baseDir, filePath);
|
|
15830
|
-
if (existsSync28(direct))
|
|
15831
|
-
return direct;
|
|
15832
|
-
const name = basename2(filePath).toLowerCase();
|
|
15833
|
-
const suffix = filePath.replace(/\\/g, "/").toLowerCase();
|
|
15834
|
-
let found = null;
|
|
15835
|
-
const walk = (dir, depth) => {
|
|
15836
|
-
if (found || depth > RESOLVE_MAX_DEPTH)
|
|
15837
|
-
return;
|
|
15838
|
-
let entries;
|
|
15839
|
-
try {
|
|
15840
|
-
entries = readdirSync8(dir, { withFileTypes: true });
|
|
15841
|
-
} catch {
|
|
15842
|
-
return;
|
|
15843
|
-
}
|
|
15844
|
-
for (const e of entries) {
|
|
15845
|
-
if (found)
|
|
15846
|
-
return;
|
|
15847
|
-
const full = join23(dir, e.name);
|
|
15848
|
-
if (e.isDirectory()) {
|
|
15849
|
-
if (SKIP_DIRS.has(e.name))
|
|
15850
|
-
continue;
|
|
15851
|
-
walk(full, depth + 1);
|
|
15852
|
-
} else if (e.name.toLowerCase() === name || full.replace(/\\/g, "/").toLowerCase().endsWith("/" + suffix)) {
|
|
15853
|
-
found = full;
|
|
15854
|
-
return;
|
|
15855
|
-
}
|
|
15856
|
-
}
|
|
15857
|
-
};
|
|
15858
|
-
walk(baseDir, 0);
|
|
15859
|
-
return found;
|
|
15860
|
-
}
|
|
15936
|
+
// src/modules/execution/audit-runners.ts
|
|
15937
|
+
import { readdirSync as readdirSync8 } from "fs";
|
|
15938
|
+
import { join as join23 } from "path";
|
|
15861
15939
|
function findTestFile(dir, depth = 0) {
|
|
15862
15940
|
if (depth > 5)
|
|
15863
15941
|
return null;
|
|
@@ -15932,6 +16010,76 @@ async function runTests(baseDir) {
|
|
|
15932
16010
|
command: "bun test"
|
|
15933
16011
|
};
|
|
15934
16012
|
}
|
|
16013
|
+
function parseTypecheckErrors(output) {
|
|
16014
|
+
const line = output.split(`
|
|
16015
|
+
`).find((l) => /error TS\d+/.test(l));
|
|
16016
|
+
return line ? line.trim().slice(0, 300) : null;
|
|
16017
|
+
}
|
|
16018
|
+
async function runTypecheck(baseDir) {
|
|
16019
|
+
const entry = processRegistry.start("npx --no-install tsc --noEmit --skipLibCheck", baseDir);
|
|
16020
|
+
const exited = await processRegistry.waitForExit(entry.id, 90000);
|
|
16021
|
+
const output = entry.log.join(`
|
|
16022
|
+
`);
|
|
16023
|
+
processRegistry.remove(entry.id);
|
|
16024
|
+
if (!exited)
|
|
16025
|
+
return null;
|
|
16026
|
+
return parseTypecheckErrors(output);
|
|
16027
|
+
}
|
|
16028
|
+
var SKIP_DIRS, TEST_EXT_RE, TEST_STEP_RE;
|
|
16029
|
+
var init_audit_runners = __esm(() => {
|
|
16030
|
+
init_bash();
|
|
16031
|
+
init_processes();
|
|
16032
|
+
SKIP_DIRS = new Set([
|
|
16033
|
+
"node_modules",
|
|
16034
|
+
".git",
|
|
16035
|
+
".mma",
|
|
16036
|
+
"dist",
|
|
16037
|
+
"build",
|
|
16038
|
+
"coverage",
|
|
16039
|
+
".next",
|
|
16040
|
+
".nuxt",
|
|
16041
|
+
"vendor"
|
|
16042
|
+
]);
|
|
16043
|
+
TEST_EXT_RE = /\.(test|spec)\.[jt]sx?$/i;
|
|
16044
|
+
TEST_STEP_RE = /\b(test(ing|s)?|тест(ы|ирование|ировать)?|провер\w*\s+тест|запустить\s+тест)\b|bun test|npm test|vitest|pytest|go test|jest|mocha/i;
|
|
16045
|
+
});
|
|
16046
|
+
|
|
16047
|
+
// src/modules/execution/auditor.ts
|
|
16048
|
+
import { existsSync as existsSync28, readdirSync as readdirSync9 } from "fs";
|
|
16049
|
+
import { resolve as resolve17, join as join24, basename as basename2 } from "path";
|
|
16050
|
+
function findExistingFile(baseDir, filePath) {
|
|
16051
|
+
const direct = resolve17(baseDir, filePath);
|
|
16052
|
+
if (existsSync28(direct))
|
|
16053
|
+
return direct;
|
|
16054
|
+
const name = basename2(filePath).toLowerCase();
|
|
16055
|
+
const suffix = filePath.replace(/\\/g, "/").toLowerCase();
|
|
16056
|
+
let found = null;
|
|
16057
|
+
const walk = (dir, depth) => {
|
|
16058
|
+
if (found || depth > RESOLVE_MAX_DEPTH)
|
|
16059
|
+
return;
|
|
16060
|
+
let entries;
|
|
16061
|
+
try {
|
|
16062
|
+
entries = readdirSync9(dir, { withFileTypes: true });
|
|
16063
|
+
} catch {
|
|
16064
|
+
return;
|
|
16065
|
+
}
|
|
16066
|
+
for (const e of entries) {
|
|
16067
|
+
if (found)
|
|
16068
|
+
return;
|
|
16069
|
+
const full = join24(dir, e.name);
|
|
16070
|
+
if (e.isDirectory()) {
|
|
16071
|
+
if (SKIP_DIRS.has(e.name))
|
|
16072
|
+
continue;
|
|
16073
|
+
walk(full, depth + 1);
|
|
16074
|
+
} else if (e.name.toLowerCase() === name || full.replace(/\\/g, "/").toLowerCase().endsWith("/" + suffix)) {
|
|
16075
|
+
found = full;
|
|
16076
|
+
return;
|
|
16077
|
+
}
|
|
16078
|
+
}
|
|
16079
|
+
};
|
|
16080
|
+
walk(baseDir, 0);
|
|
16081
|
+
return found;
|
|
16082
|
+
}
|
|
15935
16083
|
|
|
15936
16084
|
class Auditor {
|
|
15937
16085
|
baseDir;
|
|
@@ -15939,18 +16087,27 @@ class Auditor {
|
|
|
15939
16087
|
this.baseDir = baseDir;
|
|
15940
16088
|
}
|
|
15941
16089
|
async audit(plan) {
|
|
15942
|
-
const
|
|
15943
|
-
const
|
|
16090
|
+
const doneCreate = plan.steps.filter((s) => s.status === "done" && s.kind !== "delete");
|
|
16091
|
+
const doneDelete = plan.steps.filter((s) => s.status === "done" && s.kind === "delete");
|
|
16092
|
+
const createText = doneCreate.map((s) => s.description.replace(/\([^)]*\)/g, " ")).join(" ");
|
|
16093
|
+
const deleteText = doneDelete.map((s) => s.description.replace(/\([^)]*\)/g, " ")).join(" ");
|
|
16094
|
+
const createFiles = extractFileLikeTokens(stripUrls(createText));
|
|
16095
|
+
const deleteFiles = extractFileLikeTokens(stripUrls(deleteText));
|
|
15944
16096
|
const missingFiles = [];
|
|
15945
16097
|
const existingFiles = [];
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
if (
|
|
16098
|
+
const leftoverFiles = [];
|
|
16099
|
+
for (const filePath of createFiles) {
|
|
16100
|
+
if (findExistingFile(this.baseDir, filePath)) {
|
|
15949
16101
|
existingFiles.push(filePath);
|
|
15950
16102
|
} else {
|
|
15951
16103
|
missingFiles.push(filePath);
|
|
15952
16104
|
}
|
|
15953
16105
|
}
|
|
16106
|
+
for (const filePath of deleteFiles) {
|
|
16107
|
+
if (findExistingFile(this.baseDir, filePath)) {
|
|
16108
|
+
leftoverFiles.push(filePath);
|
|
16109
|
+
}
|
|
16110
|
+
}
|
|
15954
16111
|
let testRun = null;
|
|
15955
16112
|
if (hasTestStep(plan) && findTestFile(this.baseDir)) {
|
|
15956
16113
|
try {
|
|
@@ -15959,17 +16116,27 @@ class Auditor {
|
|
|
15959
16116
|
testRun = null;
|
|
15960
16117
|
}
|
|
15961
16118
|
}
|
|
16119
|
+
let typecheckError = null;
|
|
16120
|
+
if (missingFiles.length === 0 && leftoverFiles.length === 0 && existsSync28(join24(this.baseDir, "tsconfig.json"))) {
|
|
16121
|
+
try {
|
|
16122
|
+
typecheckError = await runTypecheck(this.baseDir);
|
|
16123
|
+
} catch {
|
|
16124
|
+
typecheckError = null;
|
|
16125
|
+
}
|
|
16126
|
+
}
|
|
15962
16127
|
const doneSteps = plan.steps.filter((s) => s.status === "done").length;
|
|
15963
16128
|
const terminalSteps = plan.steps.filter((s) => s.status === "done" || s.status === "skipped").length;
|
|
15964
16129
|
const totalSteps = plan.steps.length;
|
|
16130
|
+
const auditedFiles = [...new Set([...createFiles, ...deleteFiles])];
|
|
15965
16131
|
let massEditWarning = null;
|
|
15966
|
-
if (
|
|
16132
|
+
if (auditedFiles.length > MASS_EDIT_THRESHOLD) {
|
|
15967
16133
|
massEditWarning = t("exec.mass_edit_warning", {
|
|
15968
|
-
count: String(
|
|
16134
|
+
count: String(auditedFiles.length)
|
|
15969
16135
|
});
|
|
15970
16136
|
}
|
|
15971
16137
|
const testsFailing = testRun !== null && testRun.failed > 0;
|
|
15972
|
-
const
|
|
16138
|
+
const typecheckFailing = typecheckError !== null;
|
|
16139
|
+
const passed = missingFiles.length === 0 && leftoverFiles.length === 0 && !testsFailing && !typecheckFailing;
|
|
15973
16140
|
const stepsPending = terminalSteps < totalSteps;
|
|
15974
16141
|
let summary;
|
|
15975
16142
|
if (missingFiles.length > 0) {
|
|
@@ -15978,6 +16145,12 @@ class Auditor {
|
|
|
15978
16145
|
total: totalSteps,
|
|
15979
16146
|
files: missingFiles.length
|
|
15980
16147
|
});
|
|
16148
|
+
} else if (leftoverFiles.length > 0) {
|
|
16149
|
+
summary = t("exec.audit_leftovers", {
|
|
16150
|
+
done: doneSteps,
|
|
16151
|
+
total: totalSteps,
|
|
16152
|
+
files: leftoverFiles.length
|
|
16153
|
+
});
|
|
15981
16154
|
} else if (testsFailing) {
|
|
15982
16155
|
summary = t("exec.audit_fail_tests", {
|
|
15983
16156
|
done: doneSteps,
|
|
@@ -15986,6 +16159,13 @@ class Auditor {
|
|
|
15986
16159
|
passed: String(testRun.passedCount),
|
|
15987
16160
|
detail: testRun.detail
|
|
15988
16161
|
});
|
|
16162
|
+
} else if (typecheckFailing) {
|
|
16163
|
+
summary = t("exec.audit_fail_typecheck", {
|
|
16164
|
+
done: doneSteps,
|
|
16165
|
+
total: totalSteps,
|
|
16166
|
+
missing: String(missingFiles.length),
|
|
16167
|
+
typeError: typecheckError
|
|
16168
|
+
});
|
|
15989
16169
|
} else if (stepsPending) {
|
|
15990
16170
|
summary = t("exec.audit_pending", {
|
|
15991
16171
|
done: doneSteps,
|
|
@@ -16001,38 +16181,27 @@ class Auditor {
|
|
|
16001
16181
|
return {
|
|
16002
16182
|
passed,
|
|
16003
16183
|
missingFiles,
|
|
16184
|
+
leftoverFiles,
|
|
16004
16185
|
createdFiles: existingFiles,
|
|
16005
16186
|
modifiedFiles: [],
|
|
16006
16187
|
summary,
|
|
16007
16188
|
massEditWarning,
|
|
16008
|
-
testRun
|
|
16189
|
+
testRun,
|
|
16190
|
+
typecheckError
|
|
16009
16191
|
};
|
|
16010
16192
|
}
|
|
16011
16193
|
}
|
|
16012
|
-
var MASS_EDIT_THRESHOLD = 10,
|
|
16194
|
+
var MASS_EDIT_THRESHOLD = 10, RESOLVE_MAX_DEPTH = 8;
|
|
16013
16195
|
var init_auditor = __esm(() => {
|
|
16014
16196
|
init_i18n();
|
|
16015
16197
|
init_js_identifiers();
|
|
16016
|
-
|
|
16017
|
-
|
|
16018
|
-
SKIP_DIRS = new Set([
|
|
16019
|
-
"node_modules",
|
|
16020
|
-
".git",
|
|
16021
|
-
".mma",
|
|
16022
|
-
"dist",
|
|
16023
|
-
"build",
|
|
16024
|
-
"coverage",
|
|
16025
|
-
".next",
|
|
16026
|
-
".nuxt",
|
|
16027
|
-
"vendor"
|
|
16028
|
-
]);
|
|
16029
|
-
TEST_EXT_RE = /\.(test|spec)\.[jt]sx?$/i;
|
|
16030
|
-
TEST_STEP_RE = /\b(test(ing|s)?|тест(ы|ирование|ировать)?|провер\w*\s+тест|запустить\s+тест)\b|bun test|npm test|vitest|pytest|go test|jest|mocha/i;
|
|
16198
|
+
init_audit_runners();
|
|
16199
|
+
init_audit_runners();
|
|
16031
16200
|
});
|
|
16032
16201
|
|
|
16033
16202
|
// src/modules/execution/plan-store.ts
|
|
16034
|
-
import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync29, readdirSync as
|
|
16035
|
-
import { join as
|
|
16203
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync29, readdirSync as readdirSync10, rmSync } from "fs";
|
|
16204
|
+
import { join as join25 } from "path";
|
|
16036
16205
|
function readPlanFile(path, fallbackBaseDir) {
|
|
16037
16206
|
try {
|
|
16038
16207
|
const raw = readFileSync16(path, "utf-8");
|
|
@@ -16059,8 +16228,8 @@ function writePlanFile(path, plan) {
|
|
|
16059
16228
|
function listDir(dir, baseDir) {
|
|
16060
16229
|
if (!existsSync29(dir))
|
|
16061
16230
|
return [];
|
|
16062
|
-
const files =
|
|
16063
|
-
return files.map((f) => readPlanFile(
|
|
16231
|
+
const files = readdirSync10(dir).filter((f) => f.endsWith(".json"));
|
|
16232
|
+
return files.map((f) => readPlanFile(join25(dir, f), baseDir)).filter((p) => p !== null);
|
|
16064
16233
|
}
|
|
16065
16234
|
function toMeta(plan, status) {
|
|
16066
16235
|
return {
|
|
@@ -16081,21 +16250,21 @@ class PlanStore {
|
|
|
16081
16250
|
archiveDir;
|
|
16082
16251
|
legacyPath;
|
|
16083
16252
|
constructor(baseDir) {
|
|
16084
|
-
const mmaDir =
|
|
16253
|
+
const mmaDir = join25(baseDir, ".mma");
|
|
16085
16254
|
if (!existsSync29(mmaDir))
|
|
16086
16255
|
mkdirSync14(mmaDir, { recursive: true });
|
|
16087
16256
|
this.baseDir = baseDir;
|
|
16088
|
-
this.plansDir =
|
|
16089
|
-
this.draftsDir =
|
|
16090
|
-
this.archiveDir =
|
|
16091
|
-
this.legacyPath =
|
|
16257
|
+
this.plansDir = join25(mmaDir, "plans");
|
|
16258
|
+
this.draftsDir = join25(this.plansDir, "drafts");
|
|
16259
|
+
this.archiveDir = join25(this.plansDir, "archive");
|
|
16260
|
+
this.legacyPath = join25(mmaDir, LEGACY_FILE);
|
|
16092
16261
|
for (const dir of [this.plansDir, this.draftsDir, this.archiveDir]) {
|
|
16093
16262
|
if (!existsSync29(dir))
|
|
16094
16263
|
mkdirSync14(dir, { recursive: true });
|
|
16095
16264
|
}
|
|
16096
16265
|
}
|
|
16097
16266
|
activePath() {
|
|
16098
|
-
return
|
|
16267
|
+
return join25(this.plansDir, "active.json");
|
|
16099
16268
|
}
|
|
16100
16269
|
saveActive(plan) {
|
|
16101
16270
|
writePlanFile(this.activePath(), plan);
|
|
@@ -16125,14 +16294,14 @@ class PlanStore {
|
|
|
16125
16294
|
rmSync(p, { force: true });
|
|
16126
16295
|
}
|
|
16127
16296
|
saveDraft(plan) {
|
|
16128
|
-
writePlanFile(
|
|
16297
|
+
writePlanFile(join25(this.draftsDir, `${plan.id}.json`), plan);
|
|
16129
16298
|
}
|
|
16130
16299
|
loadDraft(id) {
|
|
16131
|
-
const p =
|
|
16300
|
+
const p = join25(this.draftsDir, `${id}.json`);
|
|
16132
16301
|
return existsSync29(p) ? readPlanFile(p, this.baseDir) : null;
|
|
16133
16302
|
}
|
|
16134
16303
|
removeDraft(id) {
|
|
16135
|
-
const p =
|
|
16304
|
+
const p = join25(this.draftsDir, `${id}.json`);
|
|
16136
16305
|
if (existsSync29(p))
|
|
16137
16306
|
rmSync(p, { force: true });
|
|
16138
16307
|
}
|
|
@@ -16140,7 +16309,7 @@ class PlanStore {
|
|
|
16140
16309
|
return listDir(this.draftsDir, this.baseDir);
|
|
16141
16310
|
}
|
|
16142
16311
|
archivePlan(plan) {
|
|
16143
|
-
writePlanFile(
|
|
16312
|
+
writePlanFile(join25(this.archiveDir, `${plan.id}.json`), plan);
|
|
16144
16313
|
this.removeDraft(plan.id);
|
|
16145
16314
|
const active = this.loadActive();
|
|
16146
16315
|
if (active && active.id === plan.id) {
|
|
@@ -16151,7 +16320,7 @@ class PlanStore {
|
|
|
16151
16320
|
return listDir(this.archiveDir, this.baseDir);
|
|
16152
16321
|
}
|
|
16153
16322
|
removeArchived(id) {
|
|
16154
|
-
const p =
|
|
16323
|
+
const p = join25(this.archiveDir, `${id}.json`);
|
|
16155
16324
|
if (existsSync29(p))
|
|
16156
16325
|
rmSync(p, { force: true });
|
|
16157
16326
|
}
|
|
@@ -16245,91 +16414,12 @@ var init_plan_coverage = __esm(() => {
|
|
|
16245
16414
|
]);
|
|
16246
16415
|
});
|
|
16247
16416
|
|
|
16248
|
-
// src/modules/execution/
|
|
16249
|
-
|
|
16250
|
-
|
|
16251
|
-
|
|
16252
|
-
|
|
16253
|
-
|
|
16254
|
-
tracker = null;
|
|
16255
|
-
verifier;
|
|
16256
|
-
stuckDetector;
|
|
16257
|
-
auditor;
|
|
16258
|
-
store;
|
|
16259
|
-
baseDir;
|
|
16260
|
-
lastRecoveryIteration = -STUCK_RECOVERY_COOLDOWN;
|
|
16261
|
-
consecutivePlanWarnings = 0;
|
|
16262
|
-
lastStepId = -1;
|
|
16263
|
-
depsGateHints = new Map;
|
|
16264
|
-
_auditSkipsRemaining = 0;
|
|
16265
|
-
stuckNotified = false;
|
|
16266
|
-
pendingMessages = [];
|
|
16267
|
-
constructor(baseDir, stuckThreshold = 6) {
|
|
16268
|
-
this.baseDir = baseDir;
|
|
16269
|
-
this.verifier = new StepVerifier(baseDir);
|
|
16270
|
-
this.stuckDetector = new StuckDetector(stuckThreshold);
|
|
16271
|
-
this.auditor = new Auditor(baseDir);
|
|
16272
|
-
this.store = new PlanStore(baseDir);
|
|
16273
|
-
}
|
|
16274
|
-
setPlan(plan) {
|
|
16275
|
-
this.tracker = new PlanTracker(plan);
|
|
16276
|
-
this.store.saveActive(plan);
|
|
16277
|
-
this._auditSkipsRemaining = 0;
|
|
16278
|
-
}
|
|
16279
|
-
restorePlan() {
|
|
16280
|
-
const plan = this.store.loadActive();
|
|
16281
|
-
if (!plan)
|
|
16282
|
-
return false;
|
|
16283
|
-
this.tracker = new PlanTracker(plan);
|
|
16284
|
-
this.tracker.syncCurrentStep();
|
|
16285
|
-
this._auditSkipsRemaining = 1;
|
|
16286
|
-
return true;
|
|
16287
|
-
}
|
|
16288
|
-
getTracker() {
|
|
16289
|
-
return this.tracker;
|
|
16290
|
-
}
|
|
16291
|
-
getStore() {
|
|
16292
|
-
return this.store;
|
|
16293
|
-
}
|
|
16294
|
-
getStuckDetector() {
|
|
16295
|
-
return this.stuckDetector;
|
|
16296
|
-
}
|
|
16297
|
-
async runFinalAudit() {
|
|
16298
|
-
if (!this.tracker)
|
|
16299
|
-
return null;
|
|
16300
|
-
if (this._auditSkipsRemaining > 0) {
|
|
16301
|
-
this._auditSkipsRemaining--;
|
|
16302
|
-
return null;
|
|
16303
|
-
}
|
|
16304
|
-
const plan = this.tracker.getPlan();
|
|
16305
|
-
const audit = await this.auditor.audit(plan);
|
|
16306
|
-
const pendingSteps = plan.steps.flatMap((s) => s.status !== "done" && s.status !== "skipped" ? [`${s.id}. ${s.description}`] : []);
|
|
16307
|
-
const done = plan.steps.filter((s) => s.status === "done").length;
|
|
16308
|
-
const passed = audit.passed && pendingSteps.length === 0;
|
|
16309
|
-
return {
|
|
16310
|
-
passed,
|
|
16311
|
-
done,
|
|
16312
|
-
total: plan.steps.length,
|
|
16313
|
-
pendingSteps,
|
|
16314
|
-
missingFiles: audit.missingFiles,
|
|
16315
|
-
summary: audit.summary
|
|
16316
|
-
};
|
|
16317
|
-
}
|
|
16318
|
-
getSystemPromptBlock() {
|
|
16319
|
-
if (!this.tracker)
|
|
16320
|
-
return null;
|
|
16321
|
-
return {
|
|
16322
|
-
content: this.tracker.toPromptBlock(),
|
|
16323
|
-
priority: "critical",
|
|
16324
|
-
essential: true,
|
|
16325
|
-
estimatedTokens: 200
|
|
16326
|
-
};
|
|
16327
|
-
}
|
|
16328
|
-
getToolDefinitions() {
|
|
16329
|
-
return [
|
|
16330
|
-
{
|
|
16331
|
-
name: "plan",
|
|
16332
|
-
description: `Create, update, show, abort, list, switch, or re-plan multi-step plans.
|
|
16417
|
+
// src/modules/execution/plan-tool.ts
|
|
16418
|
+
function createPlanToolDefinitions(deps) {
|
|
16419
|
+
return [
|
|
16420
|
+
{
|
|
16421
|
+
name: "plan",
|
|
16422
|
+
description: `Create, update, show, abort, list, switch, or re-plan multi-step plans.
|
|
16333
16423
|
|
|
16334
16424
|
Actions:
|
|
16335
16425
|
- create: Start a new plan. Previous active plan is auto-preserved: incomplete → draft, complete → archive.
|
|
@@ -16346,198 +16436,222 @@ Write CONCRETE steps with exact file paths and commands:
|
|
|
16346
16436
|
- Specify WHICH CLI commands to run with exact arguments
|
|
16347
16437
|
- Each step should include at least one file extension (.ts, .tsx, .json, etc.) or a command verb (install, create, build, run, add, init)
|
|
16348
16438
|
- Good: "Создать src/components/Header.tsx с навигацией и логотипом"
|
|
16349
|
-
- Bad: "Настройка проекта" (too vague — what exactly needs to be configured?)
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
|
|
16355
|
-
|
|
16356
|
-
|
|
16357
|
-
|
|
16358
|
-
|
|
16359
|
-
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
|
|
16370
|
-
|
|
16439
|
+
- Bad: "Настройка проекта" (too vague — what exactly needs to be configured?)
|
|
16440
|
+
- For steps that REMOVE files, pass kinds: ["delete"] aligned with steps (the done-gate verifies those files are gone instead of demanding they exist).`,
|
|
16441
|
+
parameters: {
|
|
16442
|
+
type: "object",
|
|
16443
|
+
properties: {
|
|
16444
|
+
action: {
|
|
16445
|
+
type: "string",
|
|
16446
|
+
enum: [
|
|
16447
|
+
"create",
|
|
16448
|
+
"update",
|
|
16449
|
+
"show",
|
|
16450
|
+
"abort",
|
|
16451
|
+
"list",
|
|
16452
|
+
"switch",
|
|
16453
|
+
"re-plan"
|
|
16454
|
+
]
|
|
16455
|
+
},
|
|
16456
|
+
title: { type: "string" },
|
|
16457
|
+
steps: { type: "array", items: { type: "string" } },
|
|
16458
|
+
kinds: {
|
|
16459
|
+
type: "array",
|
|
16460
|
+
items: { type: "string", enum: ["create", "delete"] },
|
|
16461
|
+
description: 'Optional per-step intent, aligned 1:1 with steps. Pass "delete" for steps whose purpose is REMOVING files — the done-gate then requires those files to be GONE (not present). Defaults to "create".'
|
|
16371
16462
|
},
|
|
16372
|
-
|
|
16463
|
+
step: { type: "number" },
|
|
16464
|
+
status: { type: "string", enum: ["done", "failed", "skipped"] },
|
|
16465
|
+
note: { type: "string" },
|
|
16466
|
+
id: { type: "string", description: "Plan id (for switch action)" }
|
|
16373
16467
|
},
|
|
16374
|
-
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
|
|
16385
|
-
});
|
|
16386
|
-
return {
|
|
16387
|
-
|
|
16388
|
-
|
|
16468
|
+
required: ["action"]
|
|
16469
|
+
},
|
|
16470
|
+
handler: async (_ctx, args) => {
|
|
16471
|
+
const action = String(args.action);
|
|
16472
|
+
if (action === "list") {
|
|
16473
|
+
const metas = deps.store.listAll();
|
|
16474
|
+
if (metas.length === 0) {
|
|
16475
|
+
return { success: true, output: t("plan.list_empty") };
|
|
16476
|
+
}
|
|
16477
|
+
const lines = metas.map((m) => {
|
|
16478
|
+
const icon = m.status === "active" ? "[*]" : m.status === "draft" ? "[ ]" : "[-]";
|
|
16479
|
+
const namePart = m.name ? ` (${m.name})` : "";
|
|
16480
|
+
return `${icon} ${m.id}${namePart} — ${m.title} ${m.doneCount}/${m.stepCount}`;
|
|
16481
|
+
});
|
|
16482
|
+
return {
|
|
16483
|
+
success: true,
|
|
16484
|
+
output: `${t("plan.list_header")}
|
|
16389
16485
|
${lines.join(`
|
|
16390
16486
|
`)}`
|
|
16487
|
+
};
|
|
16488
|
+
}
|
|
16489
|
+
if (action === "switch") {
|
|
16490
|
+
const planId = String(args.id || "");
|
|
16491
|
+
if (!planId) {
|
|
16492
|
+
return { success: false, output: t("plan.switch_no_id") };
|
|
16493
|
+
}
|
|
16494
|
+
const found = deps.store.find(planId);
|
|
16495
|
+
if (!found) {
|
|
16496
|
+
return {
|
|
16497
|
+
success: false,
|
|
16498
|
+
output: t("plan.not_found", { id: planId })
|
|
16391
16499
|
};
|
|
16392
16500
|
}
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16501
|
+
deps.preserveActive();
|
|
16502
|
+
if (found.status === "draft") {
|
|
16503
|
+
deps.store.removeDraft(found.plan.id);
|
|
16504
|
+
} else if (found.status === "archived") {
|
|
16505
|
+
deps.store.removeArchived(found.plan.id);
|
|
16506
|
+
}
|
|
16507
|
+
deps.setPlan(found.plan);
|
|
16508
|
+
const display = PlanCreator.toPromptBlock(found.plan, 0);
|
|
16509
|
+
return {
|
|
16510
|
+
success: true,
|
|
16511
|
+
output: t("plan.switched", {
|
|
16512
|
+
id: found.plan.id,
|
|
16513
|
+
title: found.plan.title
|
|
16514
|
+
}),
|
|
16515
|
+
display
|
|
16516
|
+
};
|
|
16517
|
+
}
|
|
16518
|
+
if (action === "re-plan") {
|
|
16519
|
+
if (!deps.trackerRef.current) {
|
|
16520
|
+
return { success: false, output: t("plan.no_active") };
|
|
16521
|
+
}
|
|
16522
|
+
const newSteps = Array.isArray(args.steps) ? args.steps.map(String) : [];
|
|
16523
|
+
if (newSteps.length === 0) {
|
|
16524
|
+
return { success: false, output: t("plan.replan_no_steps") };
|
|
16525
|
+
}
|
|
16526
|
+
const tracker = deps.trackerRef.current;
|
|
16527
|
+
const oldPlan = tracker.getPlan();
|
|
16528
|
+
const replanned = PlanCreator.replan(oldPlan, newSteps, args.title ? String(args.title) : undefined);
|
|
16529
|
+
const keptCount = replanned.steps.length - newSteps.length;
|
|
16530
|
+
deps.setPlan(replanned);
|
|
16531
|
+
const display = PlanCreator.toPromptBlock(replanned, keptCount);
|
|
16532
|
+
return {
|
|
16533
|
+
success: true,
|
|
16534
|
+
output: t("plan.replanned", {
|
|
16535
|
+
kept: String(keptCount),
|
|
16536
|
+
steps: String(newSteps.length)
|
|
16537
|
+
}),
|
|
16538
|
+
display
|
|
16539
|
+
};
|
|
16540
|
+
}
|
|
16541
|
+
if (action === "create") {
|
|
16542
|
+
const title = String(args.title || "Task Plan");
|
|
16543
|
+
const steps = Array.isArray(args.steps) ? args.steps.map(String) : [];
|
|
16544
|
+
if (steps.length === 0) {
|
|
16545
|
+
return { success: false, output: t("plan.no_steps") };
|
|
16546
|
+
}
|
|
16547
|
+
const parsed = deps.parseKinds(args, steps);
|
|
16548
|
+
if (parsed.error) {
|
|
16549
|
+
return { success: false, output: parsed.error };
|
|
16550
|
+
}
|
|
16551
|
+
deps.preserveActive();
|
|
16552
|
+
const plan = PlanCreator.createPlan(title, steps, deps.baseDir, parsed.kinds ?? []);
|
|
16553
|
+
deps.setPlan(plan);
|
|
16554
|
+
const display = PlanCreator.toPromptBlock(plan, 0);
|
|
16555
|
+
let output = t("plan.created", {
|
|
16556
|
+
title,
|
|
16557
|
+
steps: String(steps.length)
|
|
16558
|
+
});
|
|
16559
|
+
let displayOut = display;
|
|
16560
|
+
const taskText = deps.getTaskText(_ctx);
|
|
16561
|
+
if (taskText) {
|
|
16562
|
+
const { missing } = checkPlanCoverage(taskText, steps);
|
|
16563
|
+
if (missing.length > 0) {
|
|
16564
|
+
const warn = t("plan.coverage_warning", {
|
|
16565
|
+
missing: missing.join(", ")
|
|
16566
|
+
});
|
|
16567
|
+
output += `
|
|
16568
|
+
⚠️ ${warn}`;
|
|
16569
|
+
displayOut = `${display}
|
|
16570
|
+
⚠️ ${warn}`;
|
|
16397
16571
|
}
|
|
16398
|
-
|
|
16572
|
+
}
|
|
16573
|
+
return {
|
|
16574
|
+
success: true,
|
|
16575
|
+
output,
|
|
16576
|
+
display: displayOut
|
|
16577
|
+
};
|
|
16578
|
+
}
|
|
16579
|
+
if (action === "show") {
|
|
16580
|
+
const planId = args.id ? String(args.id) : "";
|
|
16581
|
+
if (planId && planId !== deps.trackerRef.current?.getPlan()?.id) {
|
|
16582
|
+
const found = deps.store.find(planId);
|
|
16399
16583
|
if (!found) {
|
|
16400
16584
|
return {
|
|
16401
16585
|
success: false,
|
|
16402
16586
|
output: t("plan.not_found", { id: planId })
|
|
16403
16587
|
};
|
|
16404
16588
|
}
|
|
16405
|
-
|
|
16406
|
-
if (found.status === "draft") {
|
|
16407
|
-
this.store.removeDraft(found.plan.id);
|
|
16408
|
-
} else if (found.status === "archived") {
|
|
16409
|
-
this.store.removeArchived(found.plan.id);
|
|
16410
|
-
}
|
|
16411
|
-
this.setPlan(found.plan);
|
|
16412
|
-
const display = PlanCreator.toPromptBlock(found.plan, 0);
|
|
16589
|
+
const display2 = PlanCreator.toPromptBlock(found.plan, 0);
|
|
16413
16590
|
return {
|
|
16414
16591
|
success: true,
|
|
16415
|
-
output: t("plan.
|
|
16416
|
-
|
|
16417
|
-
|
|
16418
|
-
}),
|
|
16419
|
-
display
|
|
16592
|
+
output: `${t("plan.show_header")}
|
|
16593
|
+
${display2}`,
|
|
16594
|
+
display: display2
|
|
16420
16595
|
};
|
|
16421
16596
|
}
|
|
16422
|
-
if (
|
|
16423
|
-
|
|
16424
|
-
return { success: false, output: t("plan.no_active") };
|
|
16425
|
-
}
|
|
16426
|
-
const newSteps = Array.isArray(args.steps) ? args.steps.map(String) : [];
|
|
16427
|
-
if (newSteps.length === 0) {
|
|
16428
|
-
return { success: false, output: t("plan.replan_no_steps") };
|
|
16429
|
-
}
|
|
16430
|
-
const oldPlan = this.tracker.getPlan();
|
|
16431
|
-
const replanned = PlanCreator.replan(oldPlan, newSteps, args.title ? String(args.title) : undefined);
|
|
16432
|
-
const keptCount = replanned.steps.length - newSteps.length;
|
|
16433
|
-
this.setPlan(replanned);
|
|
16434
|
-
const display = PlanCreator.toPromptBlock(replanned, keptCount);
|
|
16435
|
-
return {
|
|
16436
|
-
success: true,
|
|
16437
|
-
output: t("plan.replanned", {
|
|
16438
|
-
kept: String(keptCount),
|
|
16439
|
-
steps: String(newSteps.length)
|
|
16440
|
-
}),
|
|
16441
|
-
display
|
|
16442
|
-
};
|
|
16597
|
+
if (!deps.trackerRef.current) {
|
|
16598
|
+
return { success: false, output: t("plan.no_active") };
|
|
16443
16599
|
}
|
|
16444
|
-
|
|
16445
|
-
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
|
|
16449
|
-
|
|
16450
|
-
|
|
16451
|
-
|
|
16452
|
-
|
|
16453
|
-
|
|
16454
|
-
|
|
16455
|
-
|
|
16456
|
-
|
|
16457
|
-
}
|
|
16458
|
-
let displayOut = display;
|
|
16459
|
-
const taskText = this.getTaskText(_ctx);
|
|
16460
|
-
if (taskText) {
|
|
16461
|
-
const { missing } = checkPlanCoverage(taskText, steps);
|
|
16462
|
-
if (missing.length > 0) {
|
|
16463
|
-
const warn = t("plan.coverage_warning", {
|
|
16464
|
-
missing: missing.join(", ")
|
|
16465
|
-
});
|
|
16466
|
-
output += `
|
|
16467
|
-
⚠️ ${warn}`;
|
|
16468
|
-
displayOut = `${display}
|
|
16469
|
-
⚠️ ${warn}`;
|
|
16470
|
-
}
|
|
16471
|
-
}
|
|
16472
|
-
return {
|
|
16473
|
-
success: true,
|
|
16474
|
-
output,
|
|
16475
|
-
display: displayOut
|
|
16476
|
-
};
|
|
16600
|
+
const display = deps.trackerRef.current.toPromptBlock();
|
|
16601
|
+
return {
|
|
16602
|
+
success: true,
|
|
16603
|
+
output: `${t("plan.show_header")}
|
|
16604
|
+
${display}`,
|
|
16605
|
+
display
|
|
16606
|
+
};
|
|
16607
|
+
}
|
|
16608
|
+
if (action === "update" && args.step && deps.trackerRef.current) {
|
|
16609
|
+
const tracker = deps.trackerRef.current;
|
|
16610
|
+
const stepId = Number(args.step);
|
|
16611
|
+
const target = tracker.getStep(stepId);
|
|
16612
|
+
if (!target) {
|
|
16613
|
+
return { success: false, output: t("plan.step_not_found") };
|
|
16477
16614
|
}
|
|
16478
|
-
|
|
16479
|
-
|
|
16480
|
-
|
|
16481
|
-
|
|
16482
|
-
if (!found) {
|
|
16483
|
-
return {
|
|
16484
|
-
success: false,
|
|
16485
|
-
output: t("plan.not_found", { id: planId })
|
|
16486
|
-
};
|
|
16487
|
-
}
|
|
16488
|
-
const display2 = PlanCreator.toPromptBlock(found.plan, 0);
|
|
16489
|
-
return {
|
|
16490
|
-
success: true,
|
|
16491
|
-
output: `${t("plan.show_header")}
|
|
16492
|
-
${display2}`,
|
|
16493
|
-
display: display2
|
|
16494
|
-
};
|
|
16495
|
-
}
|
|
16496
|
-
if (!this.tracker) {
|
|
16497
|
-
return { success: false, output: t("plan.no_active") };
|
|
16498
|
-
}
|
|
16499
|
-
const display = this.tracker.toPromptBlock();
|
|
16615
|
+
const status = String(args.status || "done");
|
|
16616
|
+
if (status === "done" && target.status === "done") {
|
|
16617
|
+
const progress2 = tracker.getProgressString();
|
|
16618
|
+
const display2 = tracker.toPromptBlock();
|
|
16500
16619
|
return {
|
|
16501
16620
|
success: true,
|
|
16502
|
-
output: `${t("plan.
|
|
16503
|
-
|
|
16504
|
-
|
|
16621
|
+
output: `${t("plan.step_already_done", {
|
|
16622
|
+
step: String(stepId)
|
|
16623
|
+
})}
|
|
16624
|
+
${progress2}`,
|
|
16625
|
+
display: display2
|
|
16505
16626
|
};
|
|
16506
16627
|
}
|
|
16507
|
-
if (
|
|
16508
|
-
const
|
|
16509
|
-
|
|
16510
|
-
if (!target) {
|
|
16511
|
-
return { success: false, output: t("plan.step_not_found") };
|
|
16512
|
-
}
|
|
16513
|
-
const status = String(args.status || "done");
|
|
16514
|
-
if (status === "done" && target.status === "done") {
|
|
16515
|
-
const progress2 = this.tracker.getProgressString();
|
|
16516
|
-
const display2 = this.tracker.toPromptBlock();
|
|
16628
|
+
if (status === "done") {
|
|
16629
|
+
const blockers = tracker.getPlan().steps.filter((s) => s.id < stepId && s.status !== "done" && s.status !== "skipped");
|
|
16630
|
+
if (blockers.length > 0) {
|
|
16517
16631
|
return {
|
|
16518
|
-
success:
|
|
16519
|
-
output:
|
|
16520
|
-
step: String(stepId)
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16632
|
+
success: false,
|
|
16633
|
+
output: t("plan.order_blocked", {
|
|
16634
|
+
step: String(stepId),
|
|
16635
|
+
first: String(blockers[0].id),
|
|
16636
|
+
desc: blockers[0].description
|
|
16637
|
+
})
|
|
16524
16638
|
};
|
|
16525
16639
|
}
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16640
|
+
}
|
|
16641
|
+
if (status === "done") {
|
|
16642
|
+
if (target.kind === "delete") {
|
|
16643
|
+
const leftovers = deps.stillExistingDeliverables(target);
|
|
16644
|
+
if (leftovers.length > 0) {
|
|
16529
16645
|
return {
|
|
16530
16646
|
success: false,
|
|
16531
|
-
output: t("plan.
|
|
16647
|
+
output: t("plan.deliverables_remain", {
|
|
16532
16648
|
step: String(stepId),
|
|
16533
|
-
|
|
16534
|
-
desc: blockers[0].description
|
|
16649
|
+
files: leftovers.join(", ")
|
|
16535
16650
|
})
|
|
16536
16651
|
};
|
|
16537
16652
|
}
|
|
16538
|
-
}
|
|
16539
|
-
|
|
16540
|
-
const missing = this.missingStepDeliverables(target);
|
|
16653
|
+
} else {
|
|
16654
|
+
const missing = deps.missingStepDeliverables(target);
|
|
16541
16655
|
if (missing.length > 0) {
|
|
16542
16656
|
return {
|
|
16543
16657
|
success: false,
|
|
@@ -16548,373 +16662,559 @@ ${progress2}`,
|
|
|
16548
16662
|
};
|
|
16549
16663
|
}
|
|
16550
16664
|
}
|
|
16551
|
-
this.tracker.updateStepStatus(stepId, status);
|
|
16552
|
-
if (args.note)
|
|
16553
|
-
this.tracker.addNote(Number(args.step), String(args.note));
|
|
16554
|
-
this.tracker.syncCurrentStep();
|
|
16555
|
-
this.store.saveActive(this.tracker.getPlan());
|
|
16556
|
-
const progress = this.tracker.getProgressString();
|
|
16557
|
-
const display = this.tracker.toPromptBlock();
|
|
16558
|
-
_ctx.sessionLog?.plan("step-update", `${t("plan.step_status", { step: String(args.step), status: String(args.status || "done") })} | ${progress} | current: step ${this.tracker.getCurrentStepIndex() + 1}`);
|
|
16559
|
-
return {
|
|
16560
|
-
success: true,
|
|
16561
|
-
output: `${t("plan.step_status", { step: String(args.step), status: String(args.status || "done") })}
|
|
16562
|
-
${progress}`,
|
|
16563
|
-
display
|
|
16564
|
-
};
|
|
16565
16665
|
}
|
|
16566
|
-
|
|
16567
|
-
|
|
16568
|
-
|
|
16569
|
-
|
|
16570
|
-
|
|
16571
|
-
|
|
16572
|
-
|
|
16573
|
-
|
|
16574
|
-
|
|
16575
|
-
|
|
16576
|
-
|
|
16577
|
-
|
|
16578
|
-
|
|
16579
|
-
|
|
16580
|
-
|
|
16581
|
-
|
|
16582
|
-
|
|
16583
|
-
|
|
16584
|
-
|
|
16585
|
-
|
|
16586
|
-
|
|
16587
|
-
|
|
16588
|
-
return { success: true, output: t("plan.aborted") };
|
|
16589
|
-
}
|
|
16590
|
-
if (!this.tracker) {
|
|
16591
|
-
return { success: false, output: t("plan.no_active") };
|
|
16666
|
+
tracker.updateStepStatus(stepId, status);
|
|
16667
|
+
if (args.note)
|
|
16668
|
+
tracker.addNote(Number(args.step), String(args.note));
|
|
16669
|
+
tracker.syncCurrentStep();
|
|
16670
|
+
deps.store.saveActive(tracker.getPlan());
|
|
16671
|
+
const progress = tracker.getProgressString();
|
|
16672
|
+
const display = tracker.toPromptBlock();
|
|
16673
|
+
_ctx.sessionLog?.plan("step-update", `${t("plan.step_status", { step: String(args.step), status: String(args.status || "done") })} | ${progress} | current: step ${tracker.getCurrentStepIndex() + 1}`);
|
|
16674
|
+
return {
|
|
16675
|
+
success: true,
|
|
16676
|
+
output: `${t("plan.step_status", { step: String(args.step), status: String(args.status || "done") })}
|
|
16677
|
+
${progress}`,
|
|
16678
|
+
display
|
|
16679
|
+
};
|
|
16680
|
+
}
|
|
16681
|
+
if (action === "update" && Array.isArray(args.steps) && args.steps.length > 0 && deps.trackerRef.current) {
|
|
16682
|
+
const tracker = deps.trackerRef.current;
|
|
16683
|
+
const title = String(args.title || tracker.getPlan().title);
|
|
16684
|
+
const steps = args.steps.map(String);
|
|
16685
|
+
const parsed = deps.parseKinds(args, steps);
|
|
16686
|
+
if (parsed.error) {
|
|
16687
|
+
return { success: false, output: parsed.error };
|
|
16592
16688
|
}
|
|
16689
|
+
const plan = PlanCreator.createPlan(title, steps, deps.baseDir, parsed.kinds ?? []);
|
|
16690
|
+
deps.setPlan(plan);
|
|
16691
|
+
const display = PlanCreator.toPromptBlock(plan, 0);
|
|
16692
|
+
const output = t("plan.updated", {
|
|
16693
|
+
title,
|
|
16694
|
+
steps: String(steps.length)
|
|
16695
|
+
});
|
|
16593
16696
|
return {
|
|
16594
|
-
success:
|
|
16595
|
-
output
|
|
16697
|
+
success: true,
|
|
16698
|
+
output,
|
|
16699
|
+
display
|
|
16596
16700
|
};
|
|
16597
16701
|
}
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16601
|
-
|
|
16602
|
-
|
|
16603
|
-
|
|
16604
|
-
|
|
16605
|
-
|
|
16606
|
-
|
|
16607
|
-
|
|
16608
|
-
|
|
16702
|
+
if (action === "abort") {
|
|
16703
|
+
const tracker = deps.trackerRef.current;
|
|
16704
|
+
if (tracker) {
|
|
16705
|
+
deps.store.archivePlan(tracker.getPlan());
|
|
16706
|
+
}
|
|
16707
|
+
deps.trackerRef.current = null;
|
|
16708
|
+
deps.store.clearActive();
|
|
16709
|
+
return { success: true, output: t("plan.aborted") };
|
|
16710
|
+
}
|
|
16711
|
+
if (!deps.trackerRef.current) {
|
|
16712
|
+
return { success: false, output: t("plan.no_active") };
|
|
16713
|
+
}
|
|
16714
|
+
return {
|
|
16715
|
+
success: false,
|
|
16716
|
+
output: t("plan.unknown_action", { action })
|
|
16717
|
+
};
|
|
16718
|
+
}
|
|
16719
|
+
},
|
|
16720
|
+
{
|
|
16721
|
+
name: "todo",
|
|
16722
|
+
description: "Manage sub-tasks within current plan step. Use to break down complex steps into smaller tasks.",
|
|
16723
|
+
parameters: {
|
|
16724
|
+
type: "object",
|
|
16725
|
+
properties: {
|
|
16726
|
+
action: { type: "string", enum: ["add", "done", "list"] },
|
|
16727
|
+
items: { type: "array", items: { type: "string" } }
|
|
16609
16728
|
},
|
|
16610
|
-
|
|
16611
|
-
|
|
16612
|
-
|
|
16729
|
+
required: ["action"]
|
|
16730
|
+
},
|
|
16731
|
+
handler: async (_ctx, args) => {
|
|
16732
|
+
if (!deps.trackerRef.current) {
|
|
16733
|
+
return { success: false, output: t("plan.no_active") };
|
|
16734
|
+
}
|
|
16735
|
+
const tracker = deps.trackerRef.current;
|
|
16736
|
+
const action = String(args.action);
|
|
16737
|
+
const currentStep = tracker.getCurrentStep();
|
|
16738
|
+
if (!currentStep) {
|
|
16739
|
+
return { success: false, output: t("plan.step_not_found") };
|
|
16740
|
+
}
|
|
16741
|
+
if (action === "add" && Array.isArray(args.items)) {
|
|
16742
|
+
const items = args.items.map(String);
|
|
16743
|
+
const existing = currentStep.subtasks ?? [];
|
|
16744
|
+
let nextId = existing.reduce((m, s) => Math.max(m, s.id), 0) + 1;
|
|
16745
|
+
for (const item of items) {
|
|
16746
|
+
existing.push({ id: nextId++, text: item, done: false });
|
|
16613
16747
|
}
|
|
16614
|
-
|
|
16615
|
-
|
|
16616
|
-
|
|
16617
|
-
|
|
16748
|
+
currentStep.subtasks = existing;
|
|
16749
|
+
deps.store.saveActive(tracker.getPlan());
|
|
16750
|
+
const display = tracker.toPromptBlock();
|
|
16751
|
+
return {
|
|
16752
|
+
success: true,
|
|
16753
|
+
output: t("todo.added", {
|
|
16754
|
+
count: String(items.length),
|
|
16755
|
+
items: items.join(", ")
|
|
16756
|
+
}),
|
|
16757
|
+
display
|
|
16758
|
+
};
|
|
16759
|
+
}
|
|
16760
|
+
if (action === "done") {
|
|
16761
|
+
const items = Array.isArray(args.items) ? args.items.map(String) : [];
|
|
16762
|
+
if (items.length === 0) {
|
|
16763
|
+
return {
|
|
16764
|
+
success: false,
|
|
16765
|
+
output: t("todo.no_items")
|
|
16766
|
+
};
|
|
16618
16767
|
}
|
|
16619
|
-
|
|
16620
|
-
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
|
|
16624
|
-
|
|
16768
|
+
const subs = currentStep.subtasks ?? [];
|
|
16769
|
+
let marked = 0;
|
|
16770
|
+
for (const item of items) {
|
|
16771
|
+
const sub = subs.find((s) => !s.done && s.text.toLowerCase() === item.toLowerCase());
|
|
16772
|
+
if (sub) {
|
|
16773
|
+
sub.done = true;
|
|
16774
|
+
marked++;
|
|
16625
16775
|
}
|
|
16626
|
-
|
|
16627
|
-
|
|
16628
|
-
const display = this.tracker.toPromptBlock();
|
|
16776
|
+
}
|
|
16777
|
+
if (marked === 0) {
|
|
16629
16778
|
return {
|
|
16630
|
-
success:
|
|
16631
|
-
output: t("todo.
|
|
16632
|
-
count: String(items.length),
|
|
16779
|
+
success: false,
|
|
16780
|
+
output: t("todo.subtask_not_found", {
|
|
16633
16781
|
items: items.join(", ")
|
|
16634
|
-
})
|
|
16635
|
-
display
|
|
16782
|
+
})
|
|
16636
16783
|
};
|
|
16637
16784
|
}
|
|
16638
|
-
|
|
16639
|
-
|
|
16640
|
-
|
|
16641
|
-
|
|
16642
|
-
|
|
16643
|
-
|
|
16644
|
-
|
|
16645
|
-
|
|
16646
|
-
|
|
16647
|
-
|
|
16648
|
-
for (const item of items) {
|
|
16649
|
-
const sub = subs.find((s) => !s.done && s.text.toLowerCase() === item.toLowerCase());
|
|
16650
|
-
if (sub) {
|
|
16651
|
-
sub.done = true;
|
|
16652
|
-
marked++;
|
|
16653
|
-
}
|
|
16654
|
-
}
|
|
16655
|
-
if (marked === 0) {
|
|
16656
|
-
return {
|
|
16657
|
-
success: false,
|
|
16658
|
-
output: t("todo.subtask_not_found", {
|
|
16659
|
-
items: items.join(", ")
|
|
16660
|
-
})
|
|
16661
|
-
};
|
|
16662
|
-
}
|
|
16663
|
-
currentStep.subtasks = subs;
|
|
16664
|
-
this.store.saveActive(this.tracker.getPlan());
|
|
16665
|
-
const doneCount = subs.filter((s) => s.done).length;
|
|
16666
|
-
const display = this.tracker.toPromptBlock();
|
|
16667
|
-
let output = t("todo.marked_done", {
|
|
16668
|
-
count: String(marked)
|
|
16669
|
-
});
|
|
16670
|
-
output += ` (${doneCount}/${subs.length})`;
|
|
16671
|
-
if (doneCount === subs.length) {
|
|
16672
|
-
output += `
|
|
16785
|
+
currentStep.subtasks = subs;
|
|
16786
|
+
deps.store.saveActive(tracker.getPlan());
|
|
16787
|
+
const doneCount = subs.filter((s) => s.done).length;
|
|
16788
|
+
const display = tracker.toPromptBlock();
|
|
16789
|
+
let output = t("todo.marked_done", {
|
|
16790
|
+
count: String(marked)
|
|
16791
|
+
});
|
|
16792
|
+
output += ` (${doneCount}/${subs.length})`;
|
|
16793
|
+
if (doneCount === subs.length) {
|
|
16794
|
+
output += `
|
|
16673
16795
|
All sub-tasks done — call plan update step=${currentStep.id} status=done to complete this step.`;
|
|
16674
|
-
}
|
|
16675
|
-
return { success: true, output, display };
|
|
16676
16796
|
}
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
|
|
16680
|
-
|
|
16681
|
-
|
|
16682
|
-
|
|
16797
|
+
return { success: true, output, display };
|
|
16798
|
+
}
|
|
16799
|
+
if (action === "list") {
|
|
16800
|
+
const subs = currentStep.subtasks ?? [];
|
|
16801
|
+
const lines = subs.length ? subs.map((s) => `${s.done ? "[x]" : "[ ]"} ${s.text}`) : ["(no sub-tasks)"];
|
|
16802
|
+
return {
|
|
16803
|
+
success: true,
|
|
16804
|
+
output: `Step ${currentStep.id}: ${currentStep.description}
|
|
16683
16805
|
${lines.join(`
|
|
16684
16806
|
`)}`
|
|
16685
|
-
};
|
|
16686
|
-
}
|
|
16687
|
-
return {
|
|
16688
|
-
success: false,
|
|
16689
|
-
output: t("todo.unknown_action", { action })
|
|
16690
16807
|
};
|
|
16691
16808
|
}
|
|
16692
|
-
|
|
16693
|
-
|
|
16694
|
-
|
|
16695
|
-
|
|
16696
|
-
|
|
16697
|
-
|
|
16698
|
-
|
|
16699
|
-
|
|
16700
|
-
|
|
16701
|
-
|
|
16702
|
-
|
|
16703
|
-
|
|
16704
|
-
|
|
16705
|
-
const step = args.step ? this.tracker.getStep(Number(args.step)) : this.tracker.getCurrentStep();
|
|
16706
|
-
if (!step)
|
|
16707
|
-
return { success: false, output: t("plan.step_not_found") };
|
|
16708
|
-
const result = await this.verifier.verifyStep(step.description);
|
|
16709
|
-
return {
|
|
16710
|
-
success: result.passed,
|
|
16711
|
-
output: result.passed ? t("verify.passed") : t("verify.failed", {
|
|
16712
|
-
details: result.failed.map((f) => f.message).join("; ")
|
|
16713
|
-
})
|
|
16714
|
-
};
|
|
16809
|
+
return {
|
|
16810
|
+
success: false,
|
|
16811
|
+
output: t("todo.unknown_action", { action })
|
|
16812
|
+
};
|
|
16813
|
+
}
|
|
16814
|
+
},
|
|
16815
|
+
{
|
|
16816
|
+
name: "verify",
|
|
16817
|
+
description: "Run verification for the current step. Checks files mentioned in the step description.",
|
|
16818
|
+
parameters: {
|
|
16819
|
+
type: "object",
|
|
16820
|
+
properties: {
|
|
16821
|
+
step: { type: "number", description: "Step number to verify" }
|
|
16715
16822
|
}
|
|
16823
|
+
},
|
|
16824
|
+
handler: async (_ctx, args) => {
|
|
16825
|
+
if (!deps.trackerRef.current)
|
|
16826
|
+
return { success: false, output: t("plan.no_active") };
|
|
16827
|
+
const tracker = deps.trackerRef.current;
|
|
16828
|
+
const step = args.step ? tracker.getStep(Number(args.step)) : tracker.getCurrentStep();
|
|
16829
|
+
if (!step)
|
|
16830
|
+
return { success: false, output: t("plan.step_not_found") };
|
|
16831
|
+
const result = await deps.verifier.verifyStep(step.description);
|
|
16832
|
+
return {
|
|
16833
|
+
success: result.passed,
|
|
16834
|
+
output: result.passed ? t("verify.passed") : t("verify.failed", {
|
|
16835
|
+
details: result.failed.map((f) => f.message).join("; ")
|
|
16836
|
+
})
|
|
16837
|
+
};
|
|
16716
16838
|
}
|
|
16717
|
-
|
|
16718
|
-
|
|
16719
|
-
|
|
16720
|
-
|
|
16721
|
-
|
|
16722
|
-
|
|
16723
|
-
|
|
16724
|
-
|
|
16725
|
-
|
|
16839
|
+
}
|
|
16840
|
+
];
|
|
16841
|
+
}
|
|
16842
|
+
var init_plan_tool = __esm(() => {
|
|
16843
|
+
init_i18n();
|
|
16844
|
+
init_plan_coverage();
|
|
16845
|
+
});
|
|
16846
|
+
|
|
16847
|
+
// src/modules/execution/windows-commands.ts
|
|
16848
|
+
function firstWord(command) {
|
|
16849
|
+
const segs = command.trim().split(/[\s;|&]+/);
|
|
16850
|
+
return (segs[0] || "").replace(/[^\w-]/g, "").toLowerCase();
|
|
16851
|
+
}
|
|
16852
|
+
function forbiddenWindowsCommand(command) {
|
|
16853
|
+
const m = command.match(/^\s*cd\s+\S+\s*&&\s*(\S+)/);
|
|
16854
|
+
if (m)
|
|
16855
|
+
return forbiddenWindowsCommand(m[1]);
|
|
16856
|
+
const word = firstWord(command);
|
|
16857
|
+
if (word && FORBIDDEN_COMMANDS.has(word))
|
|
16858
|
+
return word;
|
|
16859
|
+
return null;
|
|
16860
|
+
}
|
|
16861
|
+
var FORBIDDEN_COMMANDS;
|
|
16862
|
+
var init_windows_commands = __esm(() => {
|
|
16863
|
+
FORBIDDEN_COMMANDS = new Set([
|
|
16864
|
+
"grep",
|
|
16865
|
+
"sed",
|
|
16866
|
+
"ls",
|
|
16867
|
+
"find",
|
|
16868
|
+
"rm",
|
|
16869
|
+
"touch",
|
|
16870
|
+
"which",
|
|
16871
|
+
"diff",
|
|
16872
|
+
"cp",
|
|
16873
|
+
"mv"
|
|
16874
|
+
]);
|
|
16875
|
+
});
|
|
16876
|
+
|
|
16877
|
+
// src/modules/execution/execution-plugin.ts
|
|
16878
|
+
import { platform as platform4 } from "os";
|
|
16879
|
+
function createExecutionPlugin(deps) {
|
|
16880
|
+
return {
|
|
16881
|
+
name: "execution",
|
|
16882
|
+
onBeforeThink: (ctx) => {
|
|
16883
|
+
if (ctx.contextManager && deps.pendingMessages.length > 0) {
|
|
16884
|
+
for (const m of deps.pendingMessages.splice(0)) {
|
|
16885
|
+
ctx.contextManager.addMessage(m);
|
|
16886
|
+
}
|
|
16887
|
+
}
|
|
16888
|
+
if (deps.trackerRef.current?.isComplete()) {
|
|
16889
|
+
deps.stuckDetector.resetStepProgress();
|
|
16890
|
+
deps.state.consecutivePlanWarnings = 0;
|
|
16891
|
+
deps.state.lastStepId = -1;
|
|
16892
|
+
deps.state.stuckNotified = false;
|
|
16893
|
+
} else {
|
|
16894
|
+
const step = deps.trackerRef.current?.getCurrentStep();
|
|
16895
|
+
if (deps.trackerRef.current && step) {
|
|
16896
|
+
if (step.id !== deps.state.lastStepId) {
|
|
16897
|
+
deps.state.consecutivePlanWarnings = 0;
|
|
16898
|
+
deps.state.lastStepId = step.id;
|
|
16899
|
+
deps.state.stuckNotified = false;
|
|
16726
16900
|
}
|
|
16727
|
-
|
|
16728
|
-
|
|
16729
|
-
this.stuckDetector.resetStepProgress();
|
|
16730
|
-
this.consecutivePlanWarnings = 0;
|
|
16731
|
-
this.lastStepId = -1;
|
|
16732
|
-
this.stuckNotified = false;
|
|
16901
|
+
deps.stuckDetector.setCurrentStep(step.id, step.description);
|
|
16902
|
+
deps.stuckDetector.recordIteration(step.id);
|
|
16733
16903
|
} else {
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
|
|
16737
|
-
|
|
16738
|
-
|
|
16739
|
-
|
|
16740
|
-
|
|
16741
|
-
|
|
16742
|
-
|
|
16743
|
-
|
|
16744
|
-
this.stuckDetector.reset();
|
|
16745
|
-
this.consecutivePlanWarnings = 0;
|
|
16746
|
-
this.lastStepId = -1;
|
|
16747
|
-
this.stuckNotified = false;
|
|
16748
|
-
const iter = typeof ctx.iteration === "number" ? ctx.iteration : 0;
|
|
16749
|
-
if (iter === 3 && !this.tracker && ctx.contextManager) {
|
|
16750
|
-
ctx.contextManager.addMessage({
|
|
16751
|
-
role: "user",
|
|
16752
|
-
content: `<system-summary>You have made 3 tool calls without creating a plan. For any task that involves creating files, installing packages, or multiple steps — you MUST use plan create BEFORE continuing. Use the plan tool now with concrete steps (exact filenames, commands, deliverables). Do NOT make any more write/edit/bash calls until you have a plan.</system-summary>`
|
|
16753
|
-
});
|
|
16754
|
-
}
|
|
16755
|
-
if (iter >= 6 && !this.tracker && ctx.contextManager) {
|
|
16756
|
-
ctx.contextManager.addMessage({
|
|
16757
|
-
role: "user",
|
|
16758
|
-
content: `<system-summary>STOP. ${iter} iterations without a plan. You MUST call plan create RIGHT NOW. No more tool calls until you create a plan.</system-summary>`
|
|
16759
|
-
});
|
|
16760
|
-
}
|
|
16904
|
+
deps.stuckDetector.reset();
|
|
16905
|
+
deps.state.consecutivePlanWarnings = 0;
|
|
16906
|
+
deps.state.lastStepId = -1;
|
|
16907
|
+
deps.state.stuckNotified = false;
|
|
16908
|
+
const iter = typeof ctx.iteration === "number" ? ctx.iteration : 0;
|
|
16909
|
+
if (iter === 3 && !deps.trackerRef.current && ctx.contextManager) {
|
|
16910
|
+
ctx.contextManager.addMessage({
|
|
16911
|
+
role: "user",
|
|
16912
|
+
content: `<system-summary>You have made 3 tool calls without creating a plan. For any task that involves creating files, installing packages, or multiple steps — you MUST use plan create BEFORE continuing. Use the plan tool now with concrete steps (exact filenames, commands, deliverables). Do NOT make any more write/edit/bash calls until you have a plan.</system-summary>`
|
|
16913
|
+
});
|
|
16761
16914
|
}
|
|
16762
|
-
|
|
16763
|
-
|
|
16764
|
-
|
|
16765
|
-
|
|
16766
|
-
|
|
16767
|
-
ctx.logger?.warn(stuckReason);
|
|
16768
|
-
ctx.sessionLog?.plan("stuck-warning", stuckReason, typeof ctx.iteration === "number" ? ctx.iteration : undefined);
|
|
16769
|
-
if (this.stuckDetector.isStuck())
|
|
16770
|
-
this.stuckNotified = true;
|
|
16915
|
+
if (iter >= 6 && !deps.trackerRef.current && ctx.contextManager) {
|
|
16916
|
+
ctx.contextManager.addMessage({
|
|
16917
|
+
role: "user",
|
|
16918
|
+
content: `<system-summary>STOP. ${iter} iterations without a plan. You MUST call plan create RIGHT NOW. No more tool calls until you create a plan.</system-summary>`
|
|
16919
|
+
});
|
|
16771
16920
|
}
|
|
16772
16921
|
}
|
|
16773
|
-
|
|
16774
|
-
|
|
16775
|
-
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
|
|
16922
|
+
}
|
|
16923
|
+
const stuckReason = deps.stuckDetector.getStuckReason();
|
|
16924
|
+
if (stuckReason) {
|
|
16925
|
+
const logIt = deps.stuckDetector.isStuck() ? !deps.state.stuckNotified : true;
|
|
16926
|
+
if (logIt) {
|
|
16927
|
+
ctx.logger?.warn(stuckReason);
|
|
16928
|
+
ctx.sessionLog?.plan("stuck-warning", stuckReason, typeof ctx.iteration === "number" ? ctx.iteration : undefined);
|
|
16929
|
+
if (deps.stuckDetector.isStuck())
|
|
16930
|
+
deps.state.stuckNotified = true;
|
|
16931
|
+
}
|
|
16932
|
+
}
|
|
16933
|
+
if (deps.stuckDetector.isStuck() || deps.stuckDetector.hasRepetitiveToolCalls() || deps.stuckDetector.hasReadOnlyLoop()) {
|
|
16934
|
+
const currentIter = typeof ctx.iteration === "number" ? ctx.iteration : 0;
|
|
16935
|
+
if (currentIter - deps.state.lastRecoveryIteration >= STUCK_RECOVERY_COOLDOWN) {
|
|
16936
|
+
const recovery = deps.stuckDetector.getRecoveryMessage();
|
|
16937
|
+
if (recovery && ctx.contextManager) {
|
|
16938
|
+
const lastError = deps.stuckDetector.getLastErrorOutput();
|
|
16939
|
+
const skillHint = lastError ? `
|
|
16780
16940
|
If you have relevant skills available, consider loading one with load_skill for expert guidance.` : "";
|
|
16781
|
-
|
|
16782
|
-
|
|
16941
|
+
const actionableHints = deps.stuckDetector.getActionableHints();
|
|
16942
|
+
const actionableHintStr = actionableHints.length > 0 ? `
|
|
16783
16943
|
${t("exec.hints", { hints: actionableHints.map((h) => `- ${h}`).join(`
|
|
16784
16944
|
`) })}` : "";
|
|
16785
|
-
|
|
16786
|
-
|
|
16787
|
-
Tool "${
|
|
16788
|
-
|
|
16789
|
-
|
|
16790
|
-
|
|
16791
|
-
|
|
16792
|
-
|
|
16793
|
-
|
|
16794
|
-
|
|
16795
|
-
|
|
16796
|
-
|
|
16945
|
+
const alternative = deps.stuckDetector.getToolAlternative();
|
|
16946
|
+
const altHint = alternative ? `
|
|
16947
|
+
Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}" instead.` : "";
|
|
16948
|
+
ctx.contextManager.addMessage({
|
|
16949
|
+
role: "user",
|
|
16950
|
+
content: `<system-summary>${recovery}${skillHint}${actionableHintStr}${altHint}</system-summary>`
|
|
16951
|
+
});
|
|
16952
|
+
}
|
|
16953
|
+
const hints = deps.stuckDetector.getHints();
|
|
16954
|
+
if (hints.length > 0 && ctx.contextManager) {
|
|
16955
|
+
const hintMsg = t("exec.hints", {
|
|
16956
|
+
hints: hints.map((h) => `- ${h}`).join(`
|
|
16797
16957
|
`)
|
|
16798
|
-
|
|
16799
|
-
|
|
16800
|
-
|
|
16801
|
-
|
|
16802
|
-
|
|
16803
|
-
|
|
16804
|
-
|
|
16805
|
-
|
|
16806
|
-
|
|
16807
|
-
|
|
16808
|
-
|
|
16809
|
-
|
|
16810
|
-
|
|
16811
|
-
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16958
|
+
});
|
|
16959
|
+
ctx.contextManager.addMessage({
|
|
16960
|
+
role: "user",
|
|
16961
|
+
content: `<system-summary>${hintMsg}</system-summary>`
|
|
16962
|
+
});
|
|
16963
|
+
}
|
|
16964
|
+
deps.stuckDetector.recordEscalation();
|
|
16965
|
+
deps.state.lastRecoveryIteration = currentIter;
|
|
16966
|
+
if (deps.stuckDetector.shouldEscalate() && ctx.onMeta) {
|
|
16967
|
+
const escalation = t("exec.escalation", {
|
|
16968
|
+
stepId: String(deps.trackerRef.current?.getCurrentStep()?.id ?? "?"),
|
|
16969
|
+
description: deps.trackerRef.current?.getCurrentStep()?.description ?? ""
|
|
16970
|
+
});
|
|
16971
|
+
ctx.onMeta(escalation);
|
|
16972
|
+
}
|
|
16973
|
+
if (deps.stuckDetector.getIterationsOnCurrentStep() >= FORCE_SKIP_THRESHOLD && ctx.contextManager) {
|
|
16974
|
+
const step = deps.trackerRef.current?.getCurrentStep();
|
|
16975
|
+
ctx.contextManager.addMessage({
|
|
16976
|
+
role: "user",
|
|
16977
|
+
content: `<system-summary>STOP. Step ${step?.id ?? "?"} ("${step?.description ?? ""}") took ${deps.stuckDetector.getIterationsOnCurrentStep()} iterations with no progress. DO NOT continue this step. Immediately call: plan update step=${step?.id ?? "?"} status=done (if code works despite warnings) OR plan update step=${step?.id ?? "?"} status=skipped note="reason". Do NOT make any other tool calls before updating the plan.</system-summary>`
|
|
16978
|
+
});
|
|
16979
|
+
}
|
|
16980
|
+
}
|
|
16981
|
+
}
|
|
16982
|
+
},
|
|
16983
|
+
onBeforeTool: (_ctx, call) => {
|
|
16984
|
+
const warning = deps.checkPlanAlignment(call);
|
|
16985
|
+
if (warning) {
|
|
16986
|
+
deps.pendingMessages.push({
|
|
16987
|
+
role: "user",
|
|
16988
|
+
content: `<system-summary>${warning}</system-summary>`
|
|
16989
|
+
});
|
|
16990
|
+
deps.state.consecutivePlanWarnings++;
|
|
16991
|
+
if (deps.state.consecutivePlanWarnings >= MAX_PLAN_WARNINGS_BEFORE_BLOCK) {
|
|
16992
|
+
deps.pendingMessages.push({
|
|
16993
|
+
role: "user",
|
|
16994
|
+
content: `<system-summary>${t("exec.plan_blocked", { step: String(deps.trackerRef.current?.getCurrentStep()?.id ?? "?"), max: MAX_PLAN_WARNINGS_BEFORE_BLOCK })}</system-summary>`
|
|
16995
|
+
});
|
|
16996
|
+
return t("exec.plan_blocked", {
|
|
16997
|
+
step: String(deps.trackerRef.current?.getCurrentStep()?.id ?? "?"),
|
|
16998
|
+
max: MAX_PLAN_WARNINGS_BEFORE_BLOCK
|
|
16999
|
+
});
|
|
17000
|
+
}
|
|
17001
|
+
} else {
|
|
17002
|
+
deps.state.consecutivePlanWarnings = 0;
|
|
17003
|
+
}
|
|
17004
|
+
return true;
|
|
17005
|
+
},
|
|
17006
|
+
onToolCall: (ctx) => {
|
|
17007
|
+
const toolName = ctx?.toolName;
|
|
17008
|
+
const args = ctx?.args;
|
|
17009
|
+
if (toolName && args) {
|
|
17010
|
+
deps.stuckDetector.recordToolCall(toolName, args);
|
|
17011
|
+
}
|
|
17012
|
+
},
|
|
17013
|
+
onAfterTool: (ctx, call, result) => {
|
|
17014
|
+
if (call.name === "bash") {
|
|
17015
|
+
deps.stuckDetector.recordBashOutput(String(call.arguments?.command ?? ""), String(result.output ?? ""));
|
|
17016
|
+
}
|
|
17017
|
+
const toolText = String(result.output ?? "");
|
|
17018
|
+
if (/error TS\d+|\[Project typecheck failed\]|\[Syntax check failed\]/.test(toolText)) {
|
|
17019
|
+
deps.stuckDetector.recordToolError(call.name, toolText.slice(0, 300));
|
|
17020
|
+
}
|
|
17021
|
+
if (!result.success) {
|
|
17022
|
+
if (call.name === "bash" && platform4() === "win32") {
|
|
17023
|
+
const cmd = String(call.arguments?.command ?? "");
|
|
17024
|
+
const forbidden = forbiddenWindowsCommand(cmd);
|
|
17025
|
+
if (forbidden) {
|
|
17026
|
+
const n = (deps.forbiddenBashFailures.get(forbidden) || 0) + 1;
|
|
17027
|
+
deps.forbiddenBashFailures.set(forbidden, n);
|
|
17028
|
+
if (n === 2) {
|
|
17029
|
+
deps.pendingMessages.push({
|
|
16816
17030
|
role: "user",
|
|
16817
|
-
content: `<system-summary
|
|
17031
|
+
content: `<system-summary>${t("exec.forbidden_cmd", { cmd: forbidden })}</system-summary>`
|
|
16818
17032
|
});
|
|
16819
17033
|
}
|
|
16820
17034
|
}
|
|
16821
17035
|
}
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
const
|
|
16825
|
-
if (
|
|
16826
|
-
|
|
17036
|
+
deps.stuckDetector.recordToolError(call.name, result.output);
|
|
17037
|
+
const actionableHints = deps.stuckDetector.getActionableHints();
|
|
17038
|
+
const alternative = deps.stuckDetector.getToolAlternative();
|
|
17039
|
+
if (actionableHints.length > 0 || alternative) {
|
|
17040
|
+
const parts = [...actionableHints];
|
|
17041
|
+
if (alternative) {
|
|
17042
|
+
parts.push(`Tool "${call.name}" crashed. Try "${alternative}" instead.`);
|
|
17043
|
+
}
|
|
17044
|
+
deps.pendingMessages.push({
|
|
16827
17045
|
role: "user",
|
|
16828
|
-
content: `<system-summary>${
|
|
17046
|
+
content: `<system-summary>${t("exec.hints", { hints: parts.map((h) => `- ${h}`).join(`
|
|
17047
|
+
`) })}</system-summary>`
|
|
16829
17048
|
});
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
17049
|
+
}
|
|
17050
|
+
} else {
|
|
17051
|
+
deps.stuckDetector.recordToolSuccess();
|
|
17052
|
+
if (call.name === "bash" && result.success) {
|
|
17053
|
+
const cmd = String(call.arguments?.command ?? "");
|
|
17054
|
+
const testRun = detectTestResults(String(result.output ?? ""));
|
|
17055
|
+
if (testRun && testRun.failed > 0) {
|
|
17056
|
+
deps.pendingMessages.push({
|
|
16833
17057
|
role: "user",
|
|
16834
|
-
content: `<system-summary>${
|
|
17058
|
+
content: `<system-summary>${testRun.framework} reported ${testRun.failed} FAILING test(s) (${testRun.passed} passing). Do NOT mark the current step as done — fix the failing tests (read the failure output, correct the code) and re-run them until all pass.</system-summary>`
|
|
16835
17059
|
});
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
17060
|
+
} else if (testRun && testRun.failed === 0 && testRun.passed > 0) {
|
|
17061
|
+
deps.pendingMessages.push({
|
|
17062
|
+
role: "user",
|
|
17063
|
+
content: `<system-summary>${testRun.framework}: all ${testRun.passed} test(s) passed for "${cmd}". You may mark the current step as done via plan update step=N status=done.</system-summary>`
|
|
16839
17064
|
});
|
|
16840
|
-
}
|
|
16841
|
-
|
|
16842
|
-
this.consecutivePlanWarnings = 0;
|
|
16843
|
-
}
|
|
16844
|
-
return true;
|
|
16845
|
-
},
|
|
16846
|
-
onToolCall: (ctx) => {
|
|
16847
|
-
const toolName = ctx?.toolName;
|
|
16848
|
-
const args = ctx?.args;
|
|
16849
|
-
if (toolName && args) {
|
|
16850
|
-
this.stuckDetector.recordToolCall(toolName, args);
|
|
16851
|
-
}
|
|
16852
|
-
},
|
|
16853
|
-
onAfterTool: (ctx, call, result) => {
|
|
16854
|
-
if (call.name === "bash") {
|
|
16855
|
-
this.stuckDetector.recordBashOutput(String(call.arguments?.command ?? ""), String(result.output ?? ""));
|
|
16856
|
-
}
|
|
16857
|
-
const toolText = String(result.output ?? "");
|
|
16858
|
-
if (/error TS\d+|\[Project typecheck failed\]|\[Syntax check failed\]/.test(toolText)) {
|
|
16859
|
-
this.stuckDetector.recordToolError(call.name, toolText.slice(0, 300));
|
|
16860
|
-
}
|
|
16861
|
-
if (!result.success) {
|
|
16862
|
-
this.stuckDetector.recordToolError(call.name, result.output);
|
|
16863
|
-
const actionableHints = this.stuckDetector.getActionableHints();
|
|
16864
|
-
const alternative = this.stuckDetector.getToolAlternative();
|
|
16865
|
-
if (actionableHints.length > 0 || alternative) {
|
|
16866
|
-
const parts = [...actionableHints];
|
|
16867
|
-
if (alternative) {
|
|
16868
|
-
parts.push(`Tool "${call.name}" crashed. Try "${alternative}" instead.`);
|
|
16869
|
-
}
|
|
16870
|
-
this.pendingMessages.push({
|
|
17065
|
+
} else if (/node|tsx|ts-node|python|npm\s+(start|test|run)/.test(cmd)) {
|
|
17066
|
+
deps.pendingMessages.push({
|
|
16871
17067
|
role: "user",
|
|
16872
|
-
content: `<system-summary
|
|
16873
|
-
`) })}</system-summary>`
|
|
17068
|
+
content: `<system-summary>The command "${cmd}" completed successfully. If this was testing your code, mark the current step as done via plan update step=N status=done.</system-summary>`
|
|
16874
17069
|
});
|
|
16875
17070
|
}
|
|
16876
|
-
} else {
|
|
16877
|
-
this.stuckDetector.recordToolSuccess();
|
|
16878
|
-
if (call.name === "bash" && result.success) {
|
|
16879
|
-
const cmd = String(call.arguments?.command ?? "");
|
|
16880
|
-
const testRun = detectTestResults(String(result.output ?? ""));
|
|
16881
|
-
if (testRun && testRun.failed > 0) {
|
|
16882
|
-
this.pendingMessages.push({
|
|
16883
|
-
role: "user",
|
|
16884
|
-
content: `<system-summary>${testRun.framework} reported ${testRun.failed} FAILING test(s) (${testRun.passed} passing). Do NOT mark the current step as done — fix the failing tests (read the failure output, correct the code) and re-run them until all pass.</system-summary>`
|
|
16885
|
-
});
|
|
16886
|
-
} else if (testRun && testRun.failed === 0 && testRun.passed > 0) {
|
|
16887
|
-
this.pendingMessages.push({
|
|
16888
|
-
role: "user",
|
|
16889
|
-
content: `<system-summary>${testRun.framework}: all ${testRun.passed} test(s) passed for "${cmd}". You may mark the current step as done via plan update step=N status=done.</system-summary>`
|
|
16890
|
-
});
|
|
16891
|
-
} else if (/node|tsx|ts-node|python|npm\s+(start|test|run)/.test(cmd)) {
|
|
16892
|
-
this.pendingMessages.push({
|
|
16893
|
-
role: "user",
|
|
16894
|
-
content: `<system-summary>The command "${cmd}" completed successfully. If this was testing your code, mark the current step as done via plan update step=N status=done.</system-summary>`
|
|
16895
|
-
});
|
|
16896
|
-
}
|
|
16897
|
-
}
|
|
16898
17071
|
}
|
|
16899
|
-
|
|
16900
|
-
|
|
16901
|
-
|
|
16902
|
-
|
|
16903
|
-
|
|
16904
|
-
|
|
16905
|
-
|
|
16906
|
-
|
|
16907
|
-
|
|
16908
|
-
|
|
16909
|
-
|
|
16910
|
-
|
|
16911
|
-
}
|
|
17072
|
+
}
|
|
17073
|
+
if (result.success && (call.name === "write_file" || call.name === "edit_file")) {
|
|
17074
|
+
const filePath = call.arguments?.path;
|
|
17075
|
+
if (filePath) {
|
|
17076
|
+
deps.stuckDetector.recordFileRewrite(filePath);
|
|
17077
|
+
if (deps.stuckDetector.hasExcessiveRewrites()) {
|
|
17078
|
+
const file = deps.stuckDetector.getExcessiveRewriteFile();
|
|
17079
|
+
const count = deps.stuckDetector.getFileRewriteCount(file);
|
|
17080
|
+
if (ctx.onMeta) {
|
|
17081
|
+
ctx.onMeta(t("exec.file_rewrite_warning", {
|
|
17082
|
+
file,
|
|
17083
|
+
count: String(count)
|
|
17084
|
+
}));
|
|
16912
17085
|
}
|
|
16913
17086
|
}
|
|
16914
|
-
this.advancePlanIfStepComplete(ctx.contextManager, ctx.sessionLog);
|
|
16915
17087
|
}
|
|
17088
|
+
deps.advancePlanIfStepComplete(ctx.contextManager, ctx.sessionLog);
|
|
17089
|
+
}
|
|
17090
|
+
}
|
|
17091
|
+
};
|
|
17092
|
+
}
|
|
17093
|
+
var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3, FORCE_SKIP_THRESHOLD = 10;
|
|
17094
|
+
var init_execution_plugin = __esm(() => {
|
|
17095
|
+
init_i18n();
|
|
17096
|
+
init_bash();
|
|
17097
|
+
init_windows_commands();
|
|
17098
|
+
});
|
|
17099
|
+
|
|
17100
|
+
// src/modules/execution/module.ts
|
|
17101
|
+
import { existsSync as existsSync30, readFileSync as readFileSync17 } from "fs";
|
|
17102
|
+
import { resolve as resolve18 } from "path";
|
|
17103
|
+
|
|
17104
|
+
class ExecutionModule {
|
|
17105
|
+
name = "execution";
|
|
17106
|
+
tracker = null;
|
|
17107
|
+
verifier;
|
|
17108
|
+
stuckDetector;
|
|
17109
|
+
auditor;
|
|
17110
|
+
store;
|
|
17111
|
+
baseDir;
|
|
17112
|
+
_auditSkipsRemaining = 0;
|
|
17113
|
+
pendingMessages = [];
|
|
17114
|
+
forbiddenBashFailures = new Map;
|
|
17115
|
+
state = {
|
|
17116
|
+
lastRecoveryIteration: -STUCK_RECOVERY_COOLDOWN,
|
|
17117
|
+
consecutivePlanWarnings: 0,
|
|
17118
|
+
lastStepId: -1,
|
|
17119
|
+
stuckNotified: false,
|
|
17120
|
+
depsGateHints: new Map
|
|
17121
|
+
};
|
|
17122
|
+
trackerRef = (() => {
|
|
17123
|
+
const self = this;
|
|
17124
|
+
return {
|
|
17125
|
+
get current() {
|
|
17126
|
+
return self.tracker;
|
|
17127
|
+
},
|
|
17128
|
+
set current(v) {
|
|
17129
|
+
self.tracker = v;
|
|
16916
17130
|
}
|
|
16917
17131
|
};
|
|
17132
|
+
})();
|
|
17133
|
+
constructor(baseDir, stuckThreshold = 6) {
|
|
17134
|
+
this.baseDir = baseDir;
|
|
17135
|
+
this.verifier = new StepVerifier(baseDir);
|
|
17136
|
+
this.stuckDetector = new StuckDetector(stuckThreshold);
|
|
17137
|
+
this.auditor = new Auditor(baseDir);
|
|
17138
|
+
this.store = new PlanStore(baseDir);
|
|
17139
|
+
}
|
|
17140
|
+
setPlan(plan) {
|
|
17141
|
+
this.tracker = new PlanTracker(plan);
|
|
17142
|
+
this.store.saveActive(plan);
|
|
17143
|
+
this._auditSkipsRemaining = 0;
|
|
17144
|
+
}
|
|
17145
|
+
restorePlan() {
|
|
17146
|
+
const plan = this.store.loadActive();
|
|
17147
|
+
if (!plan)
|
|
17148
|
+
return false;
|
|
17149
|
+
this.tracker = new PlanTracker(plan);
|
|
17150
|
+
this.tracker.syncCurrentStep();
|
|
17151
|
+
this._auditSkipsRemaining = 1;
|
|
17152
|
+
return true;
|
|
17153
|
+
}
|
|
17154
|
+
getTracker() {
|
|
17155
|
+
return this.tracker;
|
|
17156
|
+
}
|
|
17157
|
+
getStore() {
|
|
17158
|
+
return this.store;
|
|
17159
|
+
}
|
|
17160
|
+
getStuckDetector() {
|
|
17161
|
+
return this.stuckDetector;
|
|
17162
|
+
}
|
|
17163
|
+
async runFinalAudit() {
|
|
17164
|
+
if (!this.tracker)
|
|
17165
|
+
return null;
|
|
17166
|
+
if (this._auditSkipsRemaining > 0) {
|
|
17167
|
+
this._auditSkipsRemaining--;
|
|
17168
|
+
return null;
|
|
17169
|
+
}
|
|
17170
|
+
const plan = this.tracker.getPlan();
|
|
17171
|
+
const audit = await this.auditor.audit(plan);
|
|
17172
|
+
const pendingSteps = plan.steps.flatMap((s) => s.status !== "done" && s.status !== "skipped" ? [`${s.id}. ${s.description}`] : []);
|
|
17173
|
+
const done = plan.steps.filter((s) => s.status === "done").length;
|
|
17174
|
+
const passed = audit.passed && pendingSteps.length === 0;
|
|
17175
|
+
return {
|
|
17176
|
+
passed,
|
|
17177
|
+
done,
|
|
17178
|
+
total: plan.steps.length,
|
|
17179
|
+
pendingSteps,
|
|
17180
|
+
missingFiles: audit.missingFiles,
|
|
17181
|
+
summary: audit.summary
|
|
17182
|
+
};
|
|
17183
|
+
}
|
|
17184
|
+
getSystemPromptBlock() {
|
|
17185
|
+
if (!this.tracker)
|
|
17186
|
+
return null;
|
|
17187
|
+
return {
|
|
17188
|
+
content: this.tracker.toPromptBlock(),
|
|
17189
|
+
priority: "critical",
|
|
17190
|
+
essential: true,
|
|
17191
|
+
estimatedTokens: 200
|
|
17192
|
+
};
|
|
17193
|
+
}
|
|
17194
|
+
getToolDefinitions() {
|
|
17195
|
+
return createPlanToolDefinitions({
|
|
17196
|
+
store: this.store,
|
|
17197
|
+
verifier: this.verifier,
|
|
17198
|
+
trackerRef: this.trackerRef,
|
|
17199
|
+
preserveActive: () => this.preserveActive(),
|
|
17200
|
+
setPlan: (p) => this.setPlan(p),
|
|
17201
|
+
missingStepDeliverables: (s) => this.missingStepDeliverables(s),
|
|
17202
|
+
stillExistingDeliverables: (s) => this.stillExistingDeliverables(s),
|
|
17203
|
+
parseKinds: (a, st) => this.parseKinds(a, st),
|
|
17204
|
+
getTaskText: (c) => this.getTaskText(c),
|
|
17205
|
+
baseDir: this.baseDir
|
|
17206
|
+
});
|
|
17207
|
+
}
|
|
17208
|
+
getPlugin() {
|
|
17209
|
+
return createExecutionPlugin({
|
|
17210
|
+
stuckDetector: this.stuckDetector,
|
|
17211
|
+
trackerRef: this.trackerRef,
|
|
17212
|
+
pendingMessages: this.pendingMessages,
|
|
17213
|
+
forbiddenBashFailures: this.forbiddenBashFailures,
|
|
17214
|
+
state: this.state,
|
|
17215
|
+
checkPlanAlignment: (call) => this.checkPlanAlignment(call),
|
|
17216
|
+
advancePlanIfStepComplete: (cm, sl) => this.advancePlanIfStepComplete(cm, sl)
|
|
17217
|
+
});
|
|
16918
17218
|
}
|
|
16919
17219
|
preserveActive() {
|
|
16920
17220
|
if (!this.tracker)
|
|
@@ -16945,19 +17245,18 @@ Tool "${this.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
16945
17245
|
];
|
|
16946
17246
|
if (allowedAlways.includes(call.name))
|
|
16947
17247
|
return null;
|
|
16948
|
-
const stepPaths = (step.description
|
|
17248
|
+
const stepPaths = extractFileLikeTokens(stripUrls(step.description)).map((p) => p.toLowerCase());
|
|
16949
17249
|
if (stepPaths.length === 0)
|
|
16950
17250
|
return null;
|
|
16951
|
-
const argStr = JSON.stringify(call.arguments)
|
|
16952
|
-
const callPaths = (argStr
|
|
17251
|
+
const argStr = JSON.stringify(call.arguments);
|
|
17252
|
+
const callPaths = extractFileLikeTokens(stripUrls(argStr)).map((p) => p.toLowerCase());
|
|
16953
17253
|
if (callPaths.length === 0)
|
|
16954
17254
|
return null;
|
|
16955
17255
|
const plan = this.tracker.getPlan();
|
|
16956
17256
|
const finishedPaths = new Set;
|
|
16957
17257
|
for (const s of plan.steps) {
|
|
16958
17258
|
if (s.status === "done" || s.status === "skipped") {
|
|
16959
|
-
|
|
16960
|
-
ps.forEach((p) => finishedPaths.add(p));
|
|
17259
|
+
extractFileLikeTokens(stripUrls(s.description)).map((p) => p.toLowerCase()).forEach((p) => finishedPaths.add(p));
|
|
16961
17260
|
}
|
|
16962
17261
|
}
|
|
16963
17262
|
const offPath = callPaths.some((p) => {
|
|
@@ -16979,7 +17278,7 @@ Tool "${this.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
16979
17278
|
if (!step)
|
|
16980
17279
|
return;
|
|
16981
17280
|
const stepText = step.description.toLowerCase();
|
|
16982
|
-
const stepPaths = step.description
|
|
17281
|
+
const stepPaths = extractFileLikeTokens(stripUrls(step.description)) || [];
|
|
16983
17282
|
const isDepsStep = stepText.includes("install") || stepText.includes("зависим") || stepText.includes("init") || stepText.includes("инициализац");
|
|
16984
17283
|
if (isDepsStep) {
|
|
16985
17284
|
const lockFiles = [
|
|
@@ -16997,8 +17296,8 @@ Tool "${this.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
16997
17296
|
const hasLockFile = lockFiles.some((f) => existsSync30(resolve18(this.baseDir, f)));
|
|
16998
17297
|
if (!hasLockFile) {
|
|
16999
17298
|
if (contextManager) {
|
|
17000
|
-
const hints = this.depsGateHints.get(step.id) || 0;
|
|
17001
|
-
this.depsGateHints.set(step.id, hints + 1);
|
|
17299
|
+
const hints = this.state.depsGateHints.get(step.id) || 0;
|
|
17300
|
+
this.state.depsGateHints.set(step.id, hints + 1);
|
|
17002
17301
|
const force = hints >= 1;
|
|
17003
17302
|
const content = force ? t("exec.step_gate_deps_force", { step: String(step.id) }) : t("exec.step_gate_deps", {
|
|
17004
17303
|
step: String(step.id),
|
|
@@ -17015,23 +17314,27 @@ Tool "${this.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17015
17314
|
if (stepPaths.length === 0)
|
|
17016
17315
|
return;
|
|
17017
17316
|
const allExist = stepPaths.every((p) => existsSync30(resolve18(this.baseDir, p)));
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
for (const p of stepPaths) {
|
|
17022
|
-
try {
|
|
17023
|
-
const content = readFileSync17(resolve18(this.baseDir, p), "utf-8");
|
|
17024
|
-
if (content.trim().length < 10) {
|
|
17025
|
-
emptyFiles.push(p);
|
|
17026
|
-
}
|
|
17027
|
-
} catch {}
|
|
17028
|
-
}
|
|
17029
|
-
if (emptyFiles.length > 0 && contextManager) {
|
|
17030
|
-
contextManager.addMessage({
|
|
17031
|
-
role: "user",
|
|
17032
|
-
content: `<system-summary>${t("exec.step_gate_empty", { step: String(step.id), files: emptyFiles.join(", ") })}</system-summary>`
|
|
17033
|
-
});
|
|
17317
|
+
const allGone = stepPaths.every((p) => !existsSync30(resolve18(this.baseDir, p)));
|
|
17318
|
+
const satisfied = step.kind === "delete" ? allGone && !allExist : allExist;
|
|
17319
|
+
if (!satisfied)
|
|
17034
17320
|
return;
|
|
17321
|
+
if (step.kind !== "delete") {
|
|
17322
|
+
const emptyFiles = [];
|
|
17323
|
+
for (const p of stepPaths) {
|
|
17324
|
+
try {
|
|
17325
|
+
const content = readFileSync17(resolve18(this.baseDir, p), "utf-8");
|
|
17326
|
+
if (content.trim().length < 10) {
|
|
17327
|
+
emptyFiles.push(p);
|
|
17328
|
+
}
|
|
17329
|
+
} catch {}
|
|
17330
|
+
}
|
|
17331
|
+
if (emptyFiles.length > 0 && contextManager) {
|
|
17332
|
+
contextManager.addMessage({
|
|
17333
|
+
role: "user",
|
|
17334
|
+
content: `<system-summary>${t("exec.step_gate_empty", { step: String(step.id), files: emptyFiles.join(", ") })}</system-summary>`
|
|
17335
|
+
});
|
|
17336
|
+
return;
|
|
17337
|
+
}
|
|
17035
17338
|
}
|
|
17036
17339
|
this.tracker?.updateStepStatus(step.id, "done");
|
|
17037
17340
|
const hadNext = this.tracker?.advance() ?? false;
|
|
@@ -17058,18 +17361,49 @@ Tool "${this.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17058
17361
|
return [];
|
|
17059
17362
|
return tokens.filter((p) => !findExistingFile(this.baseDir, p));
|
|
17060
17363
|
}
|
|
17364
|
+
stillExistingDeliverables(step) {
|
|
17365
|
+
const tokens = extractFileLikeTokens(stripUrls(step.description));
|
|
17366
|
+
if (tokens.length === 0)
|
|
17367
|
+
return [];
|
|
17368
|
+
return tokens.filter((p) => findExistingFile(this.baseDir, p));
|
|
17369
|
+
}
|
|
17370
|
+
parseKinds(args, steps) {
|
|
17371
|
+
if (args.kinds === undefined)
|
|
17372
|
+
return { kinds: null, error: null };
|
|
17373
|
+
if (!Array.isArray(args.kinds)) {
|
|
17374
|
+
return { kinds: null, error: t("plan.kinds_not_array") };
|
|
17375
|
+
}
|
|
17376
|
+
const kindsRaw = args.kinds.map(String);
|
|
17377
|
+
if (kindsRaw.length !== steps.length) {
|
|
17378
|
+
return { kinds: null, error: t("plan.kinds_mismatch") };
|
|
17379
|
+
}
|
|
17380
|
+
const invalid = kindsRaw.filter((k) => k !== "create" && k !== "delete");
|
|
17381
|
+
if (invalid.length > 0) {
|
|
17382
|
+
return {
|
|
17383
|
+
kinds: null,
|
|
17384
|
+
error: t("plan.kinds_invalid", {
|
|
17385
|
+
kinds: invalid.join(", ")
|
|
17386
|
+
})
|
|
17387
|
+
};
|
|
17388
|
+
}
|
|
17389
|
+
return { kinds: kindsRaw, error: null };
|
|
17390
|
+
}
|
|
17061
17391
|
getTaskText(ctx) {
|
|
17062
17392
|
const manager = ctx?.contextManager;
|
|
17063
17393
|
if (!manager)
|
|
17064
17394
|
return "";
|
|
17065
17395
|
const history = manager.getActiveHistory();
|
|
17066
|
-
const firstUser = history.find((m) =>
|
|
17396
|
+
const firstUser = history.find((m) => {
|
|
17397
|
+
if (m.role !== "user")
|
|
17398
|
+
return false;
|
|
17399
|
+
const text = getMessageText(m.content);
|
|
17400
|
+
return !text.startsWith("<system-summary>") && !text.includes("[Compressed:");
|
|
17401
|
+
});
|
|
17067
17402
|
if (!firstUser)
|
|
17068
17403
|
return "";
|
|
17069
17404
|
return getMessageText(firstUser.content).trim();
|
|
17070
17405
|
}
|
|
17071
17406
|
}
|
|
17072
|
-
var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3, FORCE_SKIP_THRESHOLD = 10;
|
|
17073
17407
|
var init_module = __esm(() => {
|
|
17074
17408
|
init_i18n();
|
|
17075
17409
|
init_tracker();
|
|
@@ -17077,9 +17411,9 @@ var init_module = __esm(() => {
|
|
|
17077
17411
|
init_stuck_detector();
|
|
17078
17412
|
init_auditor();
|
|
17079
17413
|
init_plan_store();
|
|
17080
|
-
init_plan_coverage();
|
|
17081
|
-
init_bash();
|
|
17082
17414
|
init_js_identifiers();
|
|
17415
|
+
init_plan_tool();
|
|
17416
|
+
init_execution_plugin();
|
|
17083
17417
|
});
|
|
17084
17418
|
|
|
17085
17419
|
// src/modules/security/session-encryption.ts
|
|
@@ -17087,10 +17421,10 @@ import {
|
|
|
17087
17421
|
readFileSync as readFileSync18,
|
|
17088
17422
|
writeFileSync as writeFileSync11,
|
|
17089
17423
|
existsSync as existsSync31,
|
|
17090
|
-
readdirSync as
|
|
17424
|
+
readdirSync as readdirSync11,
|
|
17091
17425
|
unlinkSync as unlinkSync4
|
|
17092
17426
|
} from "fs";
|
|
17093
|
-
import { join as
|
|
17427
|
+
import { join as join26 } from "path";
|
|
17094
17428
|
import { homedir as homedir8 } from "os";
|
|
17095
17429
|
|
|
17096
17430
|
class SessionFileEncryptor {
|
|
@@ -17099,7 +17433,7 @@ class SessionFileEncryptor {
|
|
|
17099
17433
|
constructor(config) {
|
|
17100
17434
|
this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
|
|
17101
17435
|
this.encryptor = new ConfigEncryptor({
|
|
17102
|
-
keyPath: config?.keyPath ||
|
|
17436
|
+
keyPath: config?.keyPath || join26(homedir8(), ".mma", ".session-encryption-key")
|
|
17103
17437
|
});
|
|
17104
17438
|
}
|
|
17105
17439
|
isEnabled() {
|
|
@@ -17183,9 +17517,9 @@ class SessionFileEncryptor {
|
|
|
17183
17517
|
encryptSessionDirectory(sessionDir) {
|
|
17184
17518
|
if (!this.config.enabled)
|
|
17185
17519
|
return;
|
|
17186
|
-
const files =
|
|
17520
|
+
const files = readdirSync11(sessionDir);
|
|
17187
17521
|
for (const file of files) {
|
|
17188
|
-
const filePath =
|
|
17522
|
+
const filePath = join26(sessionDir, file);
|
|
17189
17523
|
if (existsSync31(filePath) && !file.endsWith(".enc")) {
|
|
17190
17524
|
try {
|
|
17191
17525
|
const content = readFileSync18(filePath, "utf8");
|
|
@@ -17199,10 +17533,10 @@ class SessionFileEncryptor {
|
|
|
17199
17533
|
decryptSessionDirectory(sessionDir) {
|
|
17200
17534
|
if (!this.config.enabled)
|
|
17201
17535
|
return;
|
|
17202
|
-
const files =
|
|
17536
|
+
const files = readdirSync11(sessionDir);
|
|
17203
17537
|
for (const file of files) {
|
|
17204
17538
|
if (file.endsWith(".enc")) {
|
|
17205
|
-
const encFilePath =
|
|
17539
|
+
const encFilePath = join26(sessionDir, file);
|
|
17206
17540
|
const decFilePath = encFilePath.slice(0, -4);
|
|
17207
17541
|
try {
|
|
17208
17542
|
const content = readFileSync18(encFilePath, "utf8");
|
|
@@ -17229,13 +17563,13 @@ var init_session_encryption = __esm(() => {
|
|
|
17229
17563
|
import {
|
|
17230
17564
|
existsSync as existsSync32,
|
|
17231
17565
|
mkdirSync as mkdirSync15,
|
|
17232
|
-
readdirSync as
|
|
17566
|
+
readdirSync as readdirSync12,
|
|
17233
17567
|
readFileSync as readFileSync19,
|
|
17234
17568
|
rmSync as rmSync2,
|
|
17235
17569
|
writeFileSync as writeFileSync12,
|
|
17236
17570
|
appendFileSync as appendFileSync6
|
|
17237
17571
|
} from "fs";
|
|
17238
|
-
import { join as
|
|
17572
|
+
import { join as join27 } from "path";
|
|
17239
17573
|
import { gzipSync } from "zlib";
|
|
17240
17574
|
|
|
17241
17575
|
class SessionStore {
|
|
@@ -17249,7 +17583,7 @@ class SessionStore {
|
|
|
17249
17583
|
}
|
|
17250
17584
|
}
|
|
17251
17585
|
getSessionDir(id) {
|
|
17252
|
-
return
|
|
17586
|
+
return join27(this.baseDir, id);
|
|
17253
17587
|
}
|
|
17254
17588
|
updateEncryption(config) {
|
|
17255
17589
|
if (config?.enabled) {
|
|
@@ -17265,16 +17599,16 @@ class SessionStore {
|
|
|
17265
17599
|
mkdirSync15(this.baseDir, { recursive: true });
|
|
17266
17600
|
}
|
|
17267
17601
|
sessionDir(id) {
|
|
17268
|
-
return
|
|
17602
|
+
return join27(this.baseDir, id);
|
|
17269
17603
|
}
|
|
17270
17604
|
metaPath(id) {
|
|
17271
|
-
return
|
|
17605
|
+
return join27(this.sessionDir(id), "meta.json");
|
|
17272
17606
|
}
|
|
17273
17607
|
historyPath(id) {
|
|
17274
|
-
return
|
|
17608
|
+
return join27(this.sessionDir(id), "history.jsonl");
|
|
17275
17609
|
}
|
|
17276
17610
|
sessionLogPath(id) {
|
|
17277
|
-
return
|
|
17611
|
+
return join27(this.sessionDir(id), "session.jsonl");
|
|
17278
17612
|
}
|
|
17279
17613
|
sessionExists(id) {
|
|
17280
17614
|
return existsSync32(this.metaPath(id));
|
|
@@ -17398,7 +17732,7 @@ class SessionStore {
|
|
|
17398
17732
|
listSessions() {
|
|
17399
17733
|
if (!existsSync32(this.baseDir))
|
|
17400
17734
|
return [];
|
|
17401
|
-
const entries =
|
|
17735
|
+
const entries = readdirSync12(this.baseDir, { withFileTypes: true });
|
|
17402
17736
|
const sessions = [];
|
|
17403
17737
|
for (const entry of entries) {
|
|
17404
17738
|
if (entry.isDirectory()) {
|
|
@@ -17428,7 +17762,7 @@ class SessionStore {
|
|
|
17428
17762
|
if (existsSync32(historyPath)) {
|
|
17429
17763
|
const content = readFileSync19(historyPath, "utf-8");
|
|
17430
17764
|
const compressed = gzipSync(content);
|
|
17431
|
-
const gzPath =
|
|
17765
|
+
const gzPath = join27(this.baseDir, `${session2.id}.jsonl.gz`);
|
|
17432
17766
|
writeFileSync12(gzPath, compressed);
|
|
17433
17767
|
rmSync2(historyPath);
|
|
17434
17768
|
}
|
|
@@ -17639,8 +17973,8 @@ class ProfileCompressor {
|
|
|
17639
17973
|
|
|
17640
17974
|
// src/modules/user-profile/profile.ts
|
|
17641
17975
|
import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync33, mkdirSync as mkdirSync16 } from "fs";
|
|
17642
|
-
import { join as
|
|
17643
|
-
import { homedir as homedir9, hostname, platform as
|
|
17976
|
+
import { join as join28 } from "path";
|
|
17977
|
+
import { homedir as homedir9, hostname, platform as platform5, type } from "os";
|
|
17644
17978
|
import { env } from "process";
|
|
17645
17979
|
|
|
17646
17980
|
class UserProfile {
|
|
@@ -17652,7 +17986,7 @@ class UserProfile {
|
|
|
17652
17986
|
}
|
|
17653
17987
|
collect() {
|
|
17654
17988
|
this.info = {
|
|
17655
|
-
platform:
|
|
17989
|
+
platform: platform5(),
|
|
17656
17990
|
os: `${type()} ${hostname()}`,
|
|
17657
17991
|
hostname: hostname(),
|
|
17658
17992
|
shell: env.SHELL || env.ComSpec || "unknown",
|
|
@@ -17666,10 +18000,10 @@ class UserProfile {
|
|
|
17666
18000
|
if (!existsSync33(this.profileDir)) {
|
|
17667
18001
|
mkdirSync16(this.profileDir, { recursive: true });
|
|
17668
18002
|
}
|
|
17669
|
-
writeFileSync13(
|
|
18003
|
+
writeFileSync13(join28(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
|
|
17670
18004
|
}
|
|
17671
18005
|
load() {
|
|
17672
|
-
const path =
|
|
18006
|
+
const path = join28(this.profileDir, "profile.json");
|
|
17673
18007
|
if (!existsSync33(path))
|
|
17674
18008
|
return null;
|
|
17675
18009
|
try {
|
|
@@ -17708,8 +18042,8 @@ class UserProfile {
|
|
|
17708
18042
|
var init_profile = () => {};
|
|
17709
18043
|
|
|
17710
18044
|
// src/modules/skills/loader.ts
|
|
17711
|
-
import { readdirSync as
|
|
17712
|
-
import { join as
|
|
18045
|
+
import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as existsSync34, statSync as statSync6 } from "fs";
|
|
18046
|
+
import { join as join29 } from "path";
|
|
17713
18047
|
|
|
17714
18048
|
class SkillsLoader {
|
|
17715
18049
|
loadFromDir(dirPath) {
|
|
@@ -17720,9 +18054,9 @@ class SkillsLoader {
|
|
|
17720
18054
|
return skills;
|
|
17721
18055
|
}
|
|
17722
18056
|
scanDir(dirPath, skills) {
|
|
17723
|
-
const entries =
|
|
18057
|
+
const entries = readdirSync13(dirPath);
|
|
17724
18058
|
for (const entry of entries) {
|
|
17725
|
-
const fullPath =
|
|
18059
|
+
const fullPath = join29(dirPath, entry);
|
|
17726
18060
|
const stat = statSync6(fullPath);
|
|
17727
18061
|
if (stat.isDirectory()) {
|
|
17728
18062
|
this.scanDir(fullPath, skills);
|
|
@@ -17966,10 +18300,10 @@ var init_browser2 = __esm(() => {
|
|
|
17966
18300
|
});
|
|
17967
18301
|
|
|
17968
18302
|
// src/modules/lsp/command.ts
|
|
17969
|
-
import { delimiter, join as
|
|
18303
|
+
import { delimiter, join as join30 } from "path";
|
|
17970
18304
|
import { existsSync as existsSync35 } from "fs";
|
|
17971
|
-
import { platform as
|
|
17972
|
-
function resolveSpawnCommand(command, platformName =
|
|
18305
|
+
import { platform as platform6 } from "os";
|
|
18306
|
+
function resolveSpawnCommand(command, platformName = platform6(), pathEnv = process.env.PATH ?? "") {
|
|
17973
18307
|
if (platformName !== "win32")
|
|
17974
18308
|
return command;
|
|
17975
18309
|
if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
|
|
@@ -17978,7 +18312,7 @@ function resolveSpawnCommand(command, platformName = platform5(), pathEnv = proc
|
|
|
17978
18312
|
const dirs = pathEnv.split(delimiter).filter(Boolean);
|
|
17979
18313
|
for (const dir of dirs) {
|
|
17980
18314
|
for (const ext of WIN_EXTS) {
|
|
17981
|
-
const candidate =
|
|
18315
|
+
const candidate = join30(dir, `${command}${ext}`);
|
|
17982
18316
|
if (existsSync35(candidate))
|
|
17983
18317
|
return `${command}${ext}`;
|
|
17984
18318
|
}
|
|
@@ -18006,7 +18340,7 @@ import {
|
|
|
18006
18340
|
execSync as execSync2
|
|
18007
18341
|
} from "child_process";
|
|
18008
18342
|
import { resolve as resolve19 } from "path";
|
|
18009
|
-
import { platform as
|
|
18343
|
+
import { platform as platform7 } from "os";
|
|
18010
18344
|
|
|
18011
18345
|
class LspClient {
|
|
18012
18346
|
process = null;
|
|
@@ -18069,7 +18403,7 @@ class LspClient {
|
|
|
18069
18403
|
}
|
|
18070
18404
|
return new Promise((resolve20, reject) => {
|
|
18071
18405
|
const args = config.args ?? [];
|
|
18072
|
-
const isWin =
|
|
18406
|
+
const isWin = platform7() === "win32";
|
|
18073
18407
|
let spawnCommand = resolveSpawnCommand(config.command);
|
|
18074
18408
|
let spawnArgs = args;
|
|
18075
18409
|
const spawnOpts = {
|
|
@@ -18359,8 +18693,8 @@ var init_lsp = __esm(() => {
|
|
|
18359
18693
|
});
|
|
18360
18694
|
|
|
18361
18695
|
// src/modules/indexer/walker.ts
|
|
18362
|
-
import { readdirSync as
|
|
18363
|
-
import { join as
|
|
18696
|
+
import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync37, watch } from "fs";
|
|
18697
|
+
import { join as join31, relative as relative2, extname as extname5 } from "path";
|
|
18364
18698
|
|
|
18365
18699
|
class Indexer {
|
|
18366
18700
|
baseDir;
|
|
@@ -18391,14 +18725,14 @@ class Indexer {
|
|
|
18391
18725
|
return;
|
|
18392
18726
|
let entries;
|
|
18393
18727
|
try {
|
|
18394
|
-
entries =
|
|
18728
|
+
entries = readdirSync14(dir);
|
|
18395
18729
|
} catch {
|
|
18396
18730
|
return;
|
|
18397
18731
|
}
|
|
18398
18732
|
for (const entry of entries) {
|
|
18399
18733
|
if (count >= this.MAX_FILES)
|
|
18400
18734
|
return;
|
|
18401
|
-
const fullPath =
|
|
18735
|
+
const fullPath = join31(dir, entry);
|
|
18402
18736
|
const relPath = relative2(this.baseDir, fullPath);
|
|
18403
18737
|
const stat = statSync7(fullPath);
|
|
18404
18738
|
if (stat.isDirectory()) {
|
|
@@ -18462,13 +18796,13 @@ var init_walker = __esm(() => {
|
|
|
18462
18796
|
|
|
18463
18797
|
// src/modules/indexer/cache.ts
|
|
18464
18798
|
import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync38, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
|
|
18465
|
-
import { join as
|
|
18799
|
+
import { join as join32 } from "path";
|
|
18466
18800
|
|
|
18467
18801
|
class IndexCache {
|
|
18468
18802
|
cachePath;
|
|
18469
18803
|
cache = null;
|
|
18470
18804
|
constructor(cacheDir) {
|
|
18471
|
-
this.cachePath =
|
|
18805
|
+
this.cachePath = join32(cacheDir, "index-cache.json");
|
|
18472
18806
|
}
|
|
18473
18807
|
load() {
|
|
18474
18808
|
if (this.cache)
|
|
@@ -18484,7 +18818,7 @@ class IndexCache {
|
|
|
18484
18818
|
}
|
|
18485
18819
|
save(result) {
|
|
18486
18820
|
this.cache = result;
|
|
18487
|
-
const dir =
|
|
18821
|
+
const dir = join32(this.cachePath, "..");
|
|
18488
18822
|
if (!existsSync38(dir))
|
|
18489
18823
|
mkdirSync17(dir, { recursive: true });
|
|
18490
18824
|
writeFileSync14(this.cachePath, JSON.stringify(result), "utf-8");
|
|
@@ -18502,10 +18836,10 @@ var init_cache = () => {};
|
|
|
18502
18836
|
|
|
18503
18837
|
// src/modules/indexer/project-profile.ts
|
|
18504
18838
|
import { readFileSync as readFileSync24, existsSync as existsSync39 } from "fs";
|
|
18505
|
-
import { join as
|
|
18839
|
+
import { join as join33 } from "path";
|
|
18506
18840
|
function detectManifest(baseDir) {
|
|
18507
18841
|
for (const manifest of MANIFEST_ORDER) {
|
|
18508
|
-
if (existsSync39(
|
|
18842
|
+
if (existsSync39(join33(baseDir, manifest)))
|
|
18509
18843
|
return manifest;
|
|
18510
18844
|
}
|
|
18511
18845
|
return null;
|
|
@@ -18522,7 +18856,7 @@ function cleanDependency(entry) {
|
|
|
18522
18856
|
}
|
|
18523
18857
|
function readPackageJson(baseDir) {
|
|
18524
18858
|
try {
|
|
18525
|
-
const raw = JSON.parse(readFileSync24(
|
|
18859
|
+
const raw = JSON.parse(readFileSync24(join33(baseDir, "package.json"), "utf-8"));
|
|
18526
18860
|
if (!raw || typeof raw !== "object")
|
|
18527
18861
|
return null;
|
|
18528
18862
|
const profile = {
|
|
@@ -18546,7 +18880,7 @@ function readPackageJson(baseDir) {
|
|
|
18546
18880
|
}
|
|
18547
18881
|
function readPyproject(baseDir) {
|
|
18548
18882
|
try {
|
|
18549
|
-
const content = readFileSync24(
|
|
18883
|
+
const content = readFileSync24(join33(baseDir, "pyproject.toml"), "utf-8");
|
|
18550
18884
|
const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
|
|
18551
18885
|
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
18552
18886
|
if (nameMatch)
|
|
@@ -18562,7 +18896,7 @@ function readPyproject(baseDir) {
|
|
|
18562
18896
|
}
|
|
18563
18897
|
function readCargo(baseDir) {
|
|
18564
18898
|
try {
|
|
18565
|
-
const content = readFileSync24(
|
|
18899
|
+
const content = readFileSync24(join33(baseDir, "Cargo.toml"), "utf-8");
|
|
18566
18900
|
const profile = { runtime: "rust", deps: [], devDeps: [], scripts: {} };
|
|
18567
18901
|
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
18568
18902
|
if (nameMatch)
|
|
@@ -18586,7 +18920,7 @@ function readCargo(baseDir) {
|
|
|
18586
18920
|
}
|
|
18587
18921
|
function readGoMod(baseDir) {
|
|
18588
18922
|
try {
|
|
18589
|
-
const content = readFileSync24(
|
|
18923
|
+
const content = readFileSync24(join33(baseDir, "go.mod"), "utf-8");
|
|
18590
18924
|
const profile = { runtime: "go", deps: [], devDeps: [], scripts: {} };
|
|
18591
18925
|
const moduleMatch = content.match(/^module\s+(\S+)/m);
|
|
18592
18926
|
if (moduleMatch)
|
|
@@ -18604,7 +18938,7 @@ function readGoMod(baseDir) {
|
|
|
18604
18938
|
}
|
|
18605
18939
|
function readRequirements(baseDir) {
|
|
18606
18940
|
try {
|
|
18607
|
-
const content = readFileSync24(
|
|
18941
|
+
const content = readFileSync24(join33(baseDir, "requirements.txt"), "utf-8");
|
|
18608
18942
|
const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
|
|
18609
18943
|
for (const line of content.split(`
|
|
18610
18944
|
`)) {
|
|
@@ -19058,7 +19392,7 @@ var init_mcp = __esm(() => {
|
|
|
19058
19392
|
|
|
19059
19393
|
// src/modules/memory/module.ts
|
|
19060
19394
|
import { homedir as homedir10 } from "os";
|
|
19061
|
-
import { join as
|
|
19395
|
+
import { join as join34 } from "path";
|
|
19062
19396
|
|
|
19063
19397
|
class MemoryModule {
|
|
19064
19398
|
name = "memory";
|
|
@@ -19067,7 +19401,7 @@ class MemoryModule {
|
|
|
19067
19401
|
if (storeOrDir instanceof MemoryStore) {
|
|
19068
19402
|
this.store = storeOrDir;
|
|
19069
19403
|
} else {
|
|
19070
|
-
const dir = storeOrDir ||
|
|
19404
|
+
const dir = storeOrDir || join34(homedir10(), ".mma", "memory");
|
|
19071
19405
|
this.store = new MemoryStore(dir);
|
|
19072
19406
|
}
|
|
19073
19407
|
}
|
|
@@ -19159,7 +19493,7 @@ __export(exports_bootstrap, {
|
|
|
19159
19493
|
bootstrap: () => bootstrap
|
|
19160
19494
|
});
|
|
19161
19495
|
import { homedir as homedir11 } from "os";
|
|
19162
|
-
import { join as
|
|
19496
|
+
import { join as join35, resolve as resolve21 } from "path";
|
|
19163
19497
|
import { existsSync as existsSync40, readFileSync as readFileSync25, writeFileSync as writeFileSync15 } from "fs";
|
|
19164
19498
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
19165
19499
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
@@ -19186,8 +19520,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
19186
19520
|
`);
|
|
19187
19521
|
}
|
|
19188
19522
|
async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
19189
|
-
const dir = configDir ||
|
|
19190
|
-
const projectConfigPath = projectDir ?
|
|
19523
|
+
const dir = configDir || join35(homedir11(), ".mma");
|
|
19524
|
+
const projectConfigPath = projectDir ? join35(projectDir, ".mmrc") : join35(process.cwd(), ".mmrc");
|
|
19191
19525
|
const config = loadConfig({ configDir: dir, projectConfigPath });
|
|
19192
19526
|
setLocale(config.locale);
|
|
19193
19527
|
try {
|
|
@@ -19197,7 +19531,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19197
19531
|
}
|
|
19198
19532
|
} catch {}
|
|
19199
19533
|
const logger = new Logger(config.logLevel);
|
|
19200
|
-
logger.setLogDir(
|
|
19534
|
+
logger.setLogDir(join35(dir, "logs"));
|
|
19201
19535
|
logger.debug("MMA bootstrap", {
|
|
19202
19536
|
version: config.version,
|
|
19203
19537
|
model: config.model
|
|
@@ -19219,7 +19553,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19219
19553
|
logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
|
|
19220
19554
|
}
|
|
19221
19555
|
}
|
|
19222
|
-
const profile = new UserProfile(
|
|
19556
|
+
const profile = new UserProfile(join35(dir));
|
|
19223
19557
|
profile.load() || profile.collect();
|
|
19224
19558
|
profile.save();
|
|
19225
19559
|
const llmProvider = new OpenAICompatProvider({
|
|
@@ -19231,7 +19565,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19231
19565
|
rateLimits: config.security?.rateLimits
|
|
19232
19566
|
});
|
|
19233
19567
|
const baseDir = projectDir ? resolve21(projectDir) : process.cwd();
|
|
19234
|
-
const projectMapCacheDir =
|
|
19568
|
+
const projectMapCacheDir = join35(baseDir, ".mma");
|
|
19235
19569
|
const indexerModule = new IndexerModule({
|
|
19236
19570
|
baseDir,
|
|
19237
19571
|
cacheDir: projectMapCacheDir
|
|
@@ -19242,9 +19576,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19242
19576
|
logger.warn(`Project indexing failed: ${err.message}`);
|
|
19243
19577
|
}
|
|
19244
19578
|
const skillsLoader = new SkillsLoader;
|
|
19245
|
-
const builtinDir =
|
|
19246
|
-
const globalDir =
|
|
19247
|
-
const projectSkillsDir =
|
|
19579
|
+
const builtinDir = join35(import.meta.dirname, "skills", "builtin");
|
|
19580
|
+
const globalDir = join35(homedir11(), ".agents", "skills");
|
|
19581
|
+
const projectSkillsDir = join35(baseDir, ".mma", "skills");
|
|
19248
19582
|
const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
|
|
19249
19583
|
const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
|
|
19250
19584
|
const skillsModule = new SkillsModule(availableSkills, skillsBudget);
|
|
@@ -19258,11 +19592,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19258
19592
|
essential: true,
|
|
19259
19593
|
estimatedTokens: Math.ceil(systemInfoContent.length / 4)
|
|
19260
19594
|
};
|
|
19261
|
-
const agentsMdGlobal =
|
|
19595
|
+
const agentsMdGlobal = join35(dir, "AGENTS.md");
|
|
19262
19596
|
if (!existsSync40(agentsMdGlobal)) {
|
|
19263
19597
|
writeFileSync15(agentsMdGlobal, "", "utf-8");
|
|
19264
19598
|
}
|
|
19265
|
-
const sessionDir =
|
|
19599
|
+
const sessionDir = join35(dir, "sessions");
|
|
19266
19600
|
const sessionStore = new SessionStore(sessionDir);
|
|
19267
19601
|
sessionStore.init();
|
|
19268
19602
|
const sessionManager = new SessionManager(sessionStore, {
|
|
@@ -19329,7 +19663,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19329
19663
|
const mcpModule = new MCPModule(config);
|
|
19330
19664
|
await mcpModule.initialize();
|
|
19331
19665
|
moduleRegistry.register(mcpModule);
|
|
19332
|
-
const memoryStore = new MemoryStore(
|
|
19666
|
+
const memoryStore = new MemoryStore(join35(dir, "memory"));
|
|
19333
19667
|
const memoryModule = new MemoryModule(memoryStore);
|
|
19334
19668
|
moduleRegistry.register(memoryModule);
|
|
19335
19669
|
if (config.browser.enabled) {
|
|
@@ -19380,8 +19714,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19380
19714
|
pluginManager.register(plugin);
|
|
19381
19715
|
pluginManager.register(plugin2);
|
|
19382
19716
|
const pluginLoader = new PluginLoader;
|
|
19383
|
-
const globalPluginsDir =
|
|
19384
|
-
const projectPluginsDir =
|
|
19717
|
+
const globalPluginsDir = join35(homedir11(), ".mma", "plugins");
|
|
19718
|
+
const projectPluginsDir = join35(baseDir, ".mma", "plugins");
|
|
19385
19719
|
pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
|
|
19386
19720
|
pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
|
|
19387
19721
|
contextManager.onCompact = (summary) => {
|
|
@@ -19399,9 +19733,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19399
19733
|
const skipAgentsMd = noAgentsMd === true;
|
|
19400
19734
|
if (!skipAgentsMd) {
|
|
19401
19735
|
const agentsMdCandidates = [
|
|
19402
|
-
|
|
19403
|
-
|
|
19404
|
-
|
|
19736
|
+
join35(baseDir, "AGENTS.md"),
|
|
19737
|
+
join35(baseDir, ".mma", "AGENTS.md"),
|
|
19738
|
+
join35(dir, "AGENTS.md")
|
|
19405
19739
|
];
|
|
19406
19740
|
for (const p of agentsMdCandidates) {
|
|
19407
19741
|
if (existsSync40(p)) {
|
|
@@ -20261,7 +20595,7 @@ __export(exports_manifest, {
|
|
|
20261
20595
|
});
|
|
20262
20596
|
import { existsSync as existsSync41, readFileSync as readFileSync26, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
20263
20597
|
import { homedir as homedir13 } from "os";
|
|
20264
|
-
import { join as
|
|
20598
|
+
import { join as join37 } from "path";
|
|
20265
20599
|
function readManifest(path = MANIFEST_PATH) {
|
|
20266
20600
|
try {
|
|
20267
20601
|
if (existsSync41(path)) {
|
|
@@ -20272,7 +20606,7 @@ function readManifest(path = MANIFEST_PATH) {
|
|
|
20272
20606
|
return { version: 1, certifications: [] };
|
|
20273
20607
|
}
|
|
20274
20608
|
function saveManifest(m, path = MANIFEST_PATH) {
|
|
20275
|
-
mkdirSync18(
|
|
20609
|
+
mkdirSync18(join37(homedir13(), ".mma"), { recursive: true });
|
|
20276
20610
|
writeFileSync16(path, JSON.stringify(m, null, 2), "utf-8");
|
|
20277
20611
|
}
|
|
20278
20612
|
function upsertCertification(entry, path = MANIFEST_PATH) {
|
|
@@ -20307,7 +20641,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
|
|
|
20307
20641
|
}
|
|
20308
20642
|
var MANIFEST_PATH;
|
|
20309
20643
|
var init_manifest = __esm(() => {
|
|
20310
|
-
MANIFEST_PATH =
|
|
20644
|
+
MANIFEST_PATH = join37(homedir13(), ".mma", "certifications.json");
|
|
20311
20645
|
});
|
|
20312
20646
|
|
|
20313
20647
|
// node_modules/yaml/dist/nodes/identity.js
|
|
@@ -27430,8 +27764,8 @@ var init_scenarios = __esm(() => {
|
|
|
27430
27764
|
});
|
|
27431
27765
|
|
|
27432
27766
|
// src/modules/certification/loader.ts
|
|
27433
|
-
import { existsSync as existsSync42, readdirSync as
|
|
27434
|
-
import { join as
|
|
27767
|
+
import { existsSync as existsSync42, readdirSync as readdirSync15, readFileSync as readFileSync27 } from "fs";
|
|
27768
|
+
import { join as join38 } from "path";
|
|
27435
27769
|
function validateScenario(s) {
|
|
27436
27770
|
const errors2 = [];
|
|
27437
27771
|
const isSkip = s.mode === "skip";
|
|
@@ -27481,11 +27815,11 @@ function loadScenarios(userDir) {
|
|
|
27481
27815
|
scenarios.push(s);
|
|
27482
27816
|
}
|
|
27483
27817
|
if (userDir && existsSync42(userDir)) {
|
|
27484
|
-
for (const file of
|
|
27818
|
+
for (const file of readdirSync15(userDir)) {
|
|
27485
27819
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
|
|
27486
27820
|
continue;
|
|
27487
27821
|
try {
|
|
27488
|
-
const raw = readFileSync27(
|
|
27822
|
+
const raw = readFileSync27(join38(userDir, file), "utf-8");
|
|
27489
27823
|
const data = $parse(raw);
|
|
27490
27824
|
const parsed = normalizeScenario(data, file);
|
|
27491
27825
|
const errs = validateScenario(parsed);
|
|
@@ -27539,7 +27873,7 @@ var init_loader3 = __esm(() => {
|
|
|
27539
27873
|
|
|
27540
27874
|
// src/modules/certification/fact-checker.ts
|
|
27541
27875
|
import { existsSync as existsSync43, readFileSync as readFileSync28, statSync as statSync8 } from "fs";
|
|
27542
|
-
import { join as
|
|
27876
|
+
import { join as join39 } from "path";
|
|
27543
27877
|
function checkSandbox(sandboxDir, checks, exitCode, output) {
|
|
27544
27878
|
const failures = [];
|
|
27545
27879
|
for (const check of checks) {
|
|
@@ -27556,13 +27890,13 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
27556
27890
|
case "outputContains":
|
|
27557
27891
|
return output.includes(check.text);
|
|
27558
27892
|
case "fileExists":
|
|
27559
|
-
return isFile(
|
|
27893
|
+
return isFile(join39(sandboxDir, check.path));
|
|
27560
27894
|
case "fileNotExists":
|
|
27561
|
-
return !existsSync43(
|
|
27895
|
+
return !existsSync43(join39(sandboxDir, check.path));
|
|
27562
27896
|
case "dirExists":
|
|
27563
|
-
return isDir(
|
|
27897
|
+
return isDir(join39(sandboxDir, check.path));
|
|
27564
27898
|
case "fileContent": {
|
|
27565
|
-
const abs =
|
|
27899
|
+
const abs = join39(sandboxDir, check.path);
|
|
27566
27900
|
if (!isFile(abs))
|
|
27567
27901
|
return false;
|
|
27568
27902
|
const content = readFileSync28(abs, "utf-8");
|
|
@@ -27573,7 +27907,7 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
27573
27907
|
return false;
|
|
27574
27908
|
}
|
|
27575
27909
|
case "fileRegex": {
|
|
27576
|
-
const abs =
|
|
27910
|
+
const abs = join39(sandboxDir, check.path);
|
|
27577
27911
|
if (!isFile(abs))
|
|
27578
27912
|
return false;
|
|
27579
27913
|
return new RegExp(check.pattern).test(readFileSync28(abs, "utf-8"));
|
|
@@ -27623,8 +27957,8 @@ var init_fact_checker = () => {};
|
|
|
27623
27957
|
// src/modules/certification/runner.ts
|
|
27624
27958
|
import { spawn as spawn7 } from "child_process";
|
|
27625
27959
|
import { existsSync as existsSync44, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
|
|
27626
|
-
import { platform as
|
|
27627
|
-
import { join as
|
|
27960
|
+
import { platform as platform8 } from "os";
|
|
27961
|
+
import { join as join40, resolve as resolve22, dirname as dirname12 } from "path";
|
|
27628
27962
|
async function runScenario(scenario, opts) {
|
|
27629
27963
|
if (scenario.mode === "skip") {
|
|
27630
27964
|
return {
|
|
@@ -27643,7 +27977,7 @@ async function runScenario(scenario, opts) {
|
|
|
27643
27977
|
let passed = 0;
|
|
27644
27978
|
let firstError;
|
|
27645
27979
|
for (let i = 1;i <= reps; i++) {
|
|
27646
|
-
const sandbox =
|
|
27980
|
+
const sandbox = join40(opts.sandboxBase, `run-${scenario.id}-${i}`);
|
|
27647
27981
|
let failures = [];
|
|
27648
27982
|
let exitCode = -1;
|
|
27649
27983
|
let output = "";
|
|
@@ -27704,20 +28038,20 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
|
|
|
27704
28038
|
rmSync4(sandbox, { recursive: true, force: true });
|
|
27705
28039
|
mkdirSync19(sandbox, { recursive: true });
|
|
27706
28040
|
for (const f of scenario.fixtures ?? []) {
|
|
27707
|
-
const src =
|
|
28041
|
+
const src = join40(mmaRoot, f.source);
|
|
27708
28042
|
if (!existsSync44(src)) {
|
|
27709
28043
|
throw new Error(`fixture missing: ${f.source}`);
|
|
27710
28044
|
}
|
|
27711
|
-
const dest =
|
|
28045
|
+
const dest = join40(sandbox, f.dest);
|
|
27712
28046
|
mkdirSync19(dirname12(dest), { recursive: true });
|
|
27713
28047
|
cpSync2(src, dest);
|
|
27714
28048
|
}
|
|
27715
28049
|
}
|
|
27716
28050
|
function resolveMmaEntry(mmaRoot) {
|
|
27717
|
-
const dev =
|
|
28051
|
+
const dev = join40(mmaRoot, "src", "cli", "main.ts");
|
|
27718
28052
|
if (existsSync44(dev))
|
|
27719
28053
|
return dev;
|
|
27720
|
-
return
|
|
28054
|
+
return join40(mmaRoot, "dist", "main.js");
|
|
27721
28055
|
}
|
|
27722
28056
|
function findMmaRoot(fromDir) {
|
|
27723
28057
|
const candidates = [
|
|
@@ -27725,7 +28059,7 @@ function findMmaRoot(fromDir) {
|
|
|
27725
28059
|
resolve22(fromDir, "..")
|
|
27726
28060
|
];
|
|
27727
28061
|
for (const c of candidates) {
|
|
27728
|
-
if (existsSync44(
|
|
28062
|
+
if (existsSync44(join40(c, "package.json")))
|
|
27729
28063
|
return c;
|
|
27730
28064
|
}
|
|
27731
28065
|
return process.cwd();
|
|
@@ -27734,7 +28068,7 @@ function killTree2(child) {
|
|
|
27734
28068
|
const pid = child.pid;
|
|
27735
28069
|
if (!pid)
|
|
27736
28070
|
return;
|
|
27737
|
-
if (
|
|
28071
|
+
if (platform8() === "win32") {
|
|
27738
28072
|
spawn7("taskkill", ["/pid", String(pid), "/T", "/F"], {
|
|
27739
28073
|
windowsHide: true,
|
|
27740
28074
|
stdio: "ignore"
|
|
@@ -27793,11 +28127,11 @@ __export(exports_cli, {
|
|
|
27793
28127
|
});
|
|
27794
28128
|
import { rmSync as rmSync5 } from "fs";
|
|
27795
28129
|
import { homedir as homedir14 } from "os";
|
|
27796
|
-
import { join as
|
|
28130
|
+
import { join as join41, dirname as dirname13 } from "path";
|
|
27797
28131
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
27798
28132
|
import { existsSync as existsSync45, readFileSync as readFileSync29 } from "fs";
|
|
27799
28133
|
function readVersion() {
|
|
27800
|
-
const candidates = [
|
|
28134
|
+
const candidates = [join41(MMA_ROOT, "package.json")];
|
|
27801
28135
|
for (const p of candidates) {
|
|
27802
28136
|
if (existsSync45(p)) {
|
|
27803
28137
|
try {
|
|
@@ -27837,7 +28171,7 @@ async function certify(opts) {
|
|
|
27837
28171
|
return;
|
|
27838
28172
|
}
|
|
27839
28173
|
console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
|
|
27840
|
-
const sandboxBase =
|
|
28174
|
+
const sandboxBase = join41(process.cwd(), ".mma", "certification");
|
|
27841
28175
|
const results = [];
|
|
27842
28176
|
const total = selected.length;
|
|
27843
28177
|
let idx = 0;
|
|
@@ -27951,7 +28285,7 @@ var init_cli = __esm(() => {
|
|
|
27951
28285
|
init_manifest();
|
|
27952
28286
|
HERE = dirname13(fileURLToPath2(import.meta.url));
|
|
27953
28287
|
MMA_ROOT = findMmaRoot(HERE);
|
|
27954
|
-
USER_SCENARIO_DIR =
|
|
28288
|
+
USER_SCENARIO_DIR = join41(homedir14(), ".mma", "certification", "scenarios");
|
|
27955
28289
|
});
|
|
27956
28290
|
|
|
27957
28291
|
// src/cli/repl-commands.ts
|
|
@@ -27960,15 +28294,15 @@ __export(exports_repl_commands, {
|
|
|
27960
28294
|
registerAllCommands: () => registerAllCommands,
|
|
27961
28295
|
COMMAND_GROUPS: () => COMMAND_GROUPS
|
|
27962
28296
|
});
|
|
27963
|
-
import { join as
|
|
28297
|
+
import { join as join43, dirname as dirname15 } from "path";
|
|
27964
28298
|
import { homedir as homedir16 } from "os";
|
|
27965
28299
|
import { existsSync as existsSync47, readFileSync as readFileSync31 } from "fs";
|
|
27966
28300
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
27967
28301
|
function readVersion3() {
|
|
27968
28302
|
const here = dirname15(fileURLToPath4(import.meta.url));
|
|
27969
28303
|
const candidates = [
|
|
27970
|
-
|
|
27971
|
-
|
|
28304
|
+
join43(here, "..", "..", "package.json"),
|
|
28305
|
+
join43(here, "..", "package.json")
|
|
27972
28306
|
];
|
|
27973
28307
|
for (const p of candidates) {
|
|
27974
28308
|
if (existsSync47(p)) {
|
|
@@ -28136,7 +28470,7 @@ function registerMmaCommands(ctx) {
|
|
|
28136
28470
|
console.log(pc2.yellow(t("repl.wizard_running")));
|
|
28137
28471
|
await ctx.withExclusiveInput(async () => {
|
|
28138
28472
|
const answers = await runSetup(ctx.rl);
|
|
28139
|
-
const configPath =
|
|
28473
|
+
const configPath = join43(homedir16(), ".mma", "config.json");
|
|
28140
28474
|
ctx.config.provider.type = answers.provider;
|
|
28141
28475
|
ctx.config.provider.baseUrl = answers.apiBase;
|
|
28142
28476
|
ctx.config.provider.apiKey = answers.apiKey;
|
|
@@ -28190,7 +28524,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
28190
28524
|
return;
|
|
28191
28525
|
}
|
|
28192
28526
|
ctx.config.provider.type = name;
|
|
28193
|
-
const configPath =
|
|
28527
|
+
const configPath = join43(homedir16(), ".mma", "config.json");
|
|
28194
28528
|
saveConfig(ctx.config, configPath);
|
|
28195
28529
|
await ctx.agent.reconfigure(ctx.config);
|
|
28196
28530
|
console.log(pc2.green(t("repl.provider_set", { name })));
|
|
@@ -28246,7 +28580,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
28246
28580
|
return;
|
|
28247
28581
|
}
|
|
28248
28582
|
ctx.config.model = name;
|
|
28249
|
-
const configPath =
|
|
28583
|
+
const configPath = join43(homedir16(), ".mma", "config.json");
|
|
28250
28584
|
saveConfig(ctx.config, configPath);
|
|
28251
28585
|
await ctx.agent.reconfigure(ctx.config);
|
|
28252
28586
|
console.log(pc2.green(t("repl.model_set", { name })));
|
|
@@ -28271,7 +28605,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
28271
28605
|
return;
|
|
28272
28606
|
}
|
|
28273
28607
|
ctx.config.contextWindow = size;
|
|
28274
|
-
const configPath =
|
|
28608
|
+
const configPath = join43(homedir16(), ".mma", "config.json");
|
|
28275
28609
|
saveConfig(ctx.config, configPath);
|
|
28276
28610
|
await ctx.agent.reconfigure(ctx.config);
|
|
28277
28611
|
console.log(pc2.green(t("cli.context_set", { size })));
|
|
@@ -28290,10 +28624,10 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
28290
28624
|
ctx.agent.shutdown();
|
|
28291
28625
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
|
|
28292
28626
|
const { homedir: homedir17 } = await import("os");
|
|
28293
|
-
const { join:
|
|
28627
|
+
const { join: join44 } = await import("path");
|
|
28294
28628
|
const configDir = ctx.configDir;
|
|
28295
28629
|
const baseDir = ctx.baseDir;
|
|
28296
|
-
const projectConfigPath =
|
|
28630
|
+
const projectConfigPath = join44(baseDir, ".mmrc");
|
|
28297
28631
|
const freshConfig = loadConfig2({ configDir, projectConfigPath });
|
|
28298
28632
|
Object.assign(ctx.config, freshConfig);
|
|
28299
28633
|
const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
|
|
@@ -28593,14 +28927,14 @@ init_bootstrap();
|
|
|
28593
28927
|
init_config2();
|
|
28594
28928
|
init_setup();
|
|
28595
28929
|
init_i18n();
|
|
28596
|
-
import { join as
|
|
28930
|
+
import { join as join42, dirname as dirname14 } from "path";
|
|
28597
28931
|
import { homedir as homedir15 } from "os";
|
|
28598
28932
|
import { existsSync as existsSync46, readFileSync as readFileSync30 } from "fs";
|
|
28599
28933
|
|
|
28600
28934
|
// src/cli/security-commands.ts
|
|
28601
28935
|
init_bootstrap();
|
|
28602
28936
|
init_config2();
|
|
28603
|
-
import { join as
|
|
28937
|
+
import { join as join36 } from "path";
|
|
28604
28938
|
import { homedir as homedir12 } from "os";
|
|
28605
28939
|
|
|
28606
28940
|
// src/modules/security/security-policies.ts
|
|
@@ -29130,7 +29464,7 @@ function createSecurityCommand(program2) {
|
|
|
29130
29464
|
}
|
|
29131
29465
|
});
|
|
29132
29466
|
securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
|
|
29133
|
-
const configPath =
|
|
29467
|
+
const configPath = join36(homedir12(), ".mma", "config.json");
|
|
29134
29468
|
const { config: appConfig } = await bootstrap();
|
|
29135
29469
|
const validPresets = ["strict", "balanced", "permissive"];
|
|
29136
29470
|
if (!validPresets.includes(preset)) {
|
|
@@ -29145,7 +29479,7 @@ function createSecurityCommand(program2) {
|
|
|
29145
29479
|
console.log(t("cli.security.policy_description", { description: policy.description }));
|
|
29146
29480
|
});
|
|
29147
29481
|
securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
|
|
29148
|
-
const configPath =
|
|
29482
|
+
const configPath = join36(homedir12(), ".mma", "config.json");
|
|
29149
29483
|
const { config: appConfig } = await bootstrap();
|
|
29150
29484
|
appConfig.security = appConfig.security || {};
|
|
29151
29485
|
appConfig.security.sessionEncryption = {
|
|
@@ -29157,7 +29491,7 @@ function createSecurityCommand(program2) {
|
|
|
29157
29491
|
console.log(t("cli.security.encryption_enabled"));
|
|
29158
29492
|
});
|
|
29159
29493
|
securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
|
|
29160
|
-
const configPath =
|
|
29494
|
+
const configPath = join36(homedir12(), ".mma", "config.json");
|
|
29161
29495
|
const { config: appConfig } = await bootstrap();
|
|
29162
29496
|
appConfig.security = appConfig.security || {};
|
|
29163
29497
|
appConfig.security.sessionEncryption = {
|
|
@@ -29169,7 +29503,7 @@ function createSecurityCommand(program2) {
|
|
|
29169
29503
|
console.log(t("cli.security.encryption_disabled"));
|
|
29170
29504
|
});
|
|
29171
29505
|
securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
|
|
29172
|
-
const configPath =
|
|
29506
|
+
const configPath = join36(homedir12(), ".mma", "config.json");
|
|
29173
29507
|
const { config: appConfig } = await bootstrap();
|
|
29174
29508
|
appConfig.security = appConfig.security || {};
|
|
29175
29509
|
appConfig.security.auditNotifier = {
|
|
@@ -29183,7 +29517,7 @@ function createSecurityCommand(program2) {
|
|
|
29183
29517
|
console.log(t("cli.security.audit_enabled"));
|
|
29184
29518
|
});
|
|
29185
29519
|
securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
|
|
29186
|
-
const configPath =
|
|
29520
|
+
const configPath = join36(homedir12(), ".mma", "config.json");
|
|
29187
29521
|
const { config: appConfig } = await bootstrap();
|
|
29188
29522
|
appConfig.security = appConfig.security || {};
|
|
29189
29523
|
appConfig.security.auditNotifier = {
|
|
@@ -29219,8 +29553,8 @@ import { fileURLToPath as fileURLToPath3 } from "url";
|
|
|
29219
29553
|
function readVersion2() {
|
|
29220
29554
|
const here = dirname14(fileURLToPath3(import.meta.url));
|
|
29221
29555
|
const candidates = [
|
|
29222
|
-
|
|
29223
|
-
|
|
29556
|
+
join42(here, "..", "..", "package.json"),
|
|
29557
|
+
join42(here, "..", "package.json")
|
|
29224
29558
|
];
|
|
29225
29559
|
for (const p of candidates) {
|
|
29226
29560
|
if (existsSync46(p)) {
|
|
@@ -29238,7 +29572,7 @@ function createProgram() {
|
|
|
29238
29572
|
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"));
|
|
29239
29573
|
program2.command("init").description(t("cli.init")).action(async () => {
|
|
29240
29574
|
const answers = await runSetup();
|
|
29241
|
-
const configPath =
|
|
29575
|
+
const configPath = join42(homedir15(), ".mma", "config.json");
|
|
29242
29576
|
const { config } = await bootstrap();
|
|
29243
29577
|
config.provider.type = answers.provider;
|
|
29244
29578
|
config.provider.baseUrl = answers.apiBase;
|
|
@@ -29283,7 +29617,7 @@ function createProgram() {
|
|
|
29283
29617
|
});
|
|
29284
29618
|
const configCmd = program2.command("config").description(t("cli.manage_config"));
|
|
29285
29619
|
configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
|
|
29286
|
-
const configPath =
|
|
29620
|
+
const configPath = join42(homedir15(), ".mma", "config.json");
|
|
29287
29621
|
const { config } = await bootstrap();
|
|
29288
29622
|
const keys = key.split(".");
|
|
29289
29623
|
let obj = config;
|
|
@@ -29346,7 +29680,7 @@ function createProgram() {
|
|
|
29346
29680
|
console.log(t("cli.model_hint"));
|
|
29347
29681
|
});
|
|
29348
29682
|
model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
|
|
29349
|
-
const configPath =
|
|
29683
|
+
const configPath = join42(homedir15(), ".mma", "config.json");
|
|
29350
29684
|
const { config } = await bootstrap();
|
|
29351
29685
|
config.model = name;
|
|
29352
29686
|
saveConfig(config, configPath);
|
|
@@ -29382,7 +29716,7 @@ function createProgram() {
|
|
|
29382
29716
|
await uncertify2(name, config);
|
|
29383
29717
|
});
|
|
29384
29718
|
program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
|
|
29385
|
-
const configPath =
|
|
29719
|
+
const configPath = join42(homedir15(), ".mma", "config.json");
|
|
29386
29720
|
const { config } = await bootstrap();
|
|
29387
29721
|
const contextWindow = parseInt(size, 10);
|
|
29388
29722
|
if (isNaN(contextWindow) || contextWindow < 1024) {
|
|
@@ -29400,7 +29734,7 @@ function createProgram() {
|
|
|
29400
29734
|
console.log(t("cli.base_url"), config.provider.baseUrl);
|
|
29401
29735
|
});
|
|
29402
29736
|
provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
|
|
29403
|
-
const configPath =
|
|
29737
|
+
const configPath = join42(homedir15(), ".mma", "config.json");
|
|
29404
29738
|
const { config } = await bootstrap();
|
|
29405
29739
|
config.provider.type = name;
|
|
29406
29740
|
saveConfig(config, configPath);
|
|
@@ -30171,7 +30505,7 @@ class LineEditor {
|
|
|
30171
30505
|
|
|
30172
30506
|
// src/cli/repl.ts
|
|
30173
30507
|
import { existsSync as existsSync48, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
|
|
30174
|
-
import { join as
|
|
30508
|
+
import { join as join44, dirname as dirname16 } from "path";
|
|
30175
30509
|
import { homedir as homedir17 } from "os";
|
|
30176
30510
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
30177
30511
|
|
|
@@ -30677,8 +31011,8 @@ init_repl_commands();
|
|
|
30677
31011
|
function readVersion4() {
|
|
30678
31012
|
const here = dirname16(fileURLToPath5(import.meta.url));
|
|
30679
31013
|
const candidates = [
|
|
30680
|
-
|
|
30681
|
-
|
|
31014
|
+
join44(here, "..", "..", "package.json"),
|
|
31015
|
+
join44(here, "..", "package.json")
|
|
30682
31016
|
];
|
|
30683
31017
|
for (const p of candidates) {
|
|
30684
31018
|
if (existsSync48(p)) {
|
|
@@ -30739,10 +31073,10 @@ class Repl {
|
|
|
30739
31073
|
this.skillsModule = skillsModule;
|
|
30740
31074
|
this.pluginManager = pluginManager;
|
|
30741
31075
|
this.logger = logger;
|
|
30742
|
-
this.configDir = configDir ||
|
|
31076
|
+
this.configDir = configDir || join44(homedir17(), ".mma");
|
|
30743
31077
|
this.baseDir = baseDir || process.cwd();
|
|
30744
31078
|
this.noAgentsMd = noAgentsMd === true;
|
|
30745
|
-
this.historyPath =
|
|
31079
|
+
this.historyPath = join44(homedir17(), ".mma", "repl-history");
|
|
30746
31080
|
this.loadHistory();
|
|
30747
31081
|
this.rl = process.stdin.isTTY ? new LineEditor({
|
|
30748
31082
|
input: process.stdin,
|
|
@@ -31134,9 +31468,9 @@ ${t("image.clipboard_empty")}`));
|
|
|
31134
31468
|
row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
|
|
31135
31469
|
} else {
|
|
31136
31470
|
const agentsMdCandidates = [
|
|
31137
|
-
|
|
31138
|
-
|
|
31139
|
-
|
|
31471
|
+
join44(this.baseDir, "AGENTS.md"),
|
|
31472
|
+
join44(this.baseDir, ".mma", "AGENTS.md"),
|
|
31473
|
+
join44(this.configDir, "AGENTS.md")
|
|
31140
31474
|
];
|
|
31141
31475
|
const foundAgents = agentsMdCandidates.filter((p) => existsSync48(p));
|
|
31142
31476
|
if (foundAgents.length > 0) {
|
|
@@ -31149,7 +31483,7 @@ ${t("image.clipboard_empty")}`));
|
|
|
31149
31483
|
}
|
|
31150
31484
|
const meta = this.sessionManager?.getActiveMeta();
|
|
31151
31485
|
if (meta) {
|
|
31152
|
-
const sessionPath =
|
|
31486
|
+
const sessionPath = join44(this.configDir, "sessions", meta.id);
|
|
31153
31487
|
row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
|
|
31154
31488
|
}
|
|
31155
31489
|
const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
|
|
@@ -31191,13 +31525,13 @@ init_config2();
|
|
|
31191
31525
|
init_i18n();
|
|
31192
31526
|
init_colors();
|
|
31193
31527
|
import { existsSync as existsSync49, readFileSync as readFileSync33 } from "fs";
|
|
31194
|
-
import { join as
|
|
31528
|
+
import { join as join45, dirname as dirname17 } from "path";
|
|
31195
31529
|
import { homedir as homedir18 } from "os";
|
|
31196
31530
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
31197
31531
|
|
|
31198
31532
|
// src/modules/updater/checker.ts
|
|
31199
31533
|
init_command();
|
|
31200
|
-
import { platform as
|
|
31534
|
+
import { platform as platform9 } from "os";
|
|
31201
31535
|
var defaultRunner2 = async (command, args, options) => {
|
|
31202
31536
|
const { execFile } = await import("child_process");
|
|
31203
31537
|
return new Promise((resolve23) => {
|
|
@@ -31259,7 +31593,7 @@ class Updater {
|
|
|
31259
31593
|
buildInstallCommand(latest) {
|
|
31260
31594
|
const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
|
|
31261
31595
|
const command = resolveSpawnCommand("npm");
|
|
31262
|
-
if (
|
|
31596
|
+
if (platform9() === "win32" && /\.(cmd|bat)$/i.test(command)) {
|
|
31263
31597
|
return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
|
|
31264
31598
|
}
|
|
31265
31599
|
return { command, args: npmArgs };
|
|
@@ -31355,8 +31689,8 @@ class UpdaterModule {
|
|
|
31355
31689
|
function readVersion5() {
|
|
31356
31690
|
const here = dirname17(fileURLToPath6(import.meta.url));
|
|
31357
31691
|
const candidates = [
|
|
31358
|
-
|
|
31359
|
-
|
|
31692
|
+
join45(here, "..", "..", "package.json"),
|
|
31693
|
+
join45(here, "..", "package.json")
|
|
31360
31694
|
];
|
|
31361
31695
|
for (const p of candidates) {
|
|
31362
31696
|
if (existsSync49(p)) {
|
|
@@ -31432,15 +31766,15 @@ async function main() {
|
|
|
31432
31766
|
agent.shutdown();
|
|
31433
31767
|
process.exit(exitCode);
|
|
31434
31768
|
} else {
|
|
31435
|
-
const configPath =
|
|
31769
|
+
const configPath = join45(homedir18(), ".mma", "config.json");
|
|
31436
31770
|
if (!existsSync49(configPath)) {
|
|
31437
31771
|
console.log(pc2.yellow(`
|
|
31438
31772
|
` + t("cli.first_run") + `
|
|
31439
31773
|
`));
|
|
31440
31774
|
const answers = await runSetup();
|
|
31441
31775
|
const config2 = loadConfig({
|
|
31442
|
-
configDir:
|
|
31443
|
-
projectConfigPath: projectDir ?
|
|
31776
|
+
configDir: join45(homedir18(), ".mma"),
|
|
31777
|
+
projectConfigPath: projectDir ? join45(projectDir, ".mmrc") : join45(process.cwd(), ".mmrc")
|
|
31444
31778
|
});
|
|
31445
31779
|
config2.provider.type = answers.provider;
|
|
31446
31780
|
config2.provider.baseUrl = answers.apiBase;
|