micro-models-agent 0.37.0 → 0.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +813 -426
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2393,6 +2393,7 @@ var init_en = __esm(() => {
|
|
|
2393
2393
|
"tool.friendly.search_history": "Searching history",
|
|
2394
2394
|
"tool.friendly.pipeline_run": "Running pipeline",
|
|
2395
2395
|
"tool.friendly.mcp_call": "MCP call",
|
|
2396
|
+
"tool.friendly.lsp_check": "Checking code",
|
|
2396
2397
|
"tool.truncated": "[Truncated: {tokens} tokens removed]",
|
|
2397
2398
|
"tool.subagent_queued": "Sub-agent task queued: {task}",
|
|
2398
2399
|
"tool.subagent_artifact": `Sub-agent completed. Full result saved to artifact: {path}
|
|
@@ -2485,6 +2486,9 @@ Command: {command}`,
|
|
|
2485
2486
|
"plan.switched": "Switched to plan {id}: {title}",
|
|
2486
2487
|
"plan.replanned": "Plan re-planned: {kept} completed steps kept, {steps} new steps added",
|
|
2487
2488
|
"plan.replan_no_steps": "Provide new steps for re-planning",
|
|
2489
|
+
"plan.active_in_progress": 'Cannot create a new plan: active plan {id} already has progress ({done}/{total} done, current: step {current}). Resume it — use "plan show" to view, then continue working. To replace it, call "plan abort" first, then "plan create" again.',
|
|
2490
|
+
"plan.id_ignored": 'note: plan ids are auto-generated; use "plan switch" to activate an existing plan by id.',
|
|
2491
|
+
"plan.existing_fresh": "note: the previous active plan had no progress and was preserved as a draft.",
|
|
2488
2492
|
"todo.added": "Added {count} todo(s): {items}",
|
|
2489
2493
|
"todo.marked_done": "Marked {count} item(s) as done",
|
|
2490
2494
|
"todo.no_active": "No active todos",
|
|
@@ -2500,6 +2504,11 @@ Command: {command}`,
|
|
|
2500
2504
|
"verify.script_failed": "Script '{script}' failed: {message}",
|
|
2501
2505
|
"verify.syntax_error": "Syntax error in: {path}",
|
|
2502
2506
|
"lsp.unavailable": "static checks are unavailable (server not found). Verify via the project's own build/test instead.",
|
|
2507
|
+
"lsp.check_disabled": "LSP checks are disabled in the config.",
|
|
2508
|
+
"lsp.check_no_path": "Provide a path (file or directory) to check.",
|
|
2509
|
+
"lsp.check_notfound": "Path not found: {path}",
|
|
2510
|
+
"lsp.check_unsupported": "No LSP server configured for: {path}",
|
|
2511
|
+
"lsp.check_clean": "No errors or warnings detected ({count} file(s) checked).",
|
|
2503
2512
|
"cli.description": "Micro Models Agent — AI coding agent for small models",
|
|
2504
2513
|
"cli.init": "Run interactive setup wizard",
|
|
2505
2514
|
"cli.config_saved": "Configuration saved to ~/.mma/config.json",
|
|
@@ -2613,6 +2622,13 @@ Available commands:`,
|
|
|
2613
2622
|
"cli.security.recommended_for": "Recommended for",
|
|
2614
2623
|
"cli.yes": "Yes",
|
|
2615
2624
|
"cli.no": "No",
|
|
2625
|
+
"cli.plugins.description": "Manage plugins",
|
|
2626
|
+
"cli.plugins.list": "List loaded plugins (name, version, source)",
|
|
2627
|
+
"cli.plugins.all": "Include builtin plugins",
|
|
2628
|
+
"cli.plugins.only_external": "(builtin plugins omitted — use --all to show them)",
|
|
2629
|
+
"cli.plugins.none": "No plugins loaded",
|
|
2630
|
+
"cli.plugins.header": "Plugins: {count} loaded (MMA v{mma})",
|
|
2631
|
+
"cli.plugins.builtin_mark": "●",
|
|
2616
2632
|
"repl.help": "Show available commands",
|
|
2617
2633
|
"repl.help_usage": "Usage: /help",
|
|
2618
2634
|
"repl.exit": "Exit the REPL",
|
|
@@ -2822,6 +2838,8 @@ Use this knowledge to answer the user's question.`,
|
|
|
2822
2838
|
"pipeline.circular": "Circular dependency: {stepId}",
|
|
2823
2839
|
"plugin.loaded": "Loaded plugin: {name}",
|
|
2824
2840
|
"plugin.skipped": "Skipped incompatible plugin: {entry} ({message})",
|
|
2841
|
+
"plugin.incompatible": "Skipped plugin {name}: requires MMA v{min}, current is v{current}",
|
|
2842
|
+
"plugin.dedup_older": "Plugin {name} v{version} skipped: a newer version is already loaded",
|
|
2825
2843
|
"migration.detected": "[MMA] Detected old config. {summary}",
|
|
2826
2844
|
"migration.summary": "[MMA] {summary}",
|
|
2827
2845
|
"migration.config_bak": "- config → config.json.bak",
|
|
@@ -2992,6 +3010,7 @@ var init_ru = __esm(() => {
|
|
|
2992
3010
|
"tool.friendly.search_history": "Поиск в истории",
|
|
2993
3011
|
"tool.friendly.pipeline_run": "Запуск пайплайна",
|
|
2994
3012
|
"tool.friendly.mcp_call": "MCP вызов",
|
|
3013
|
+
"tool.friendly.lsp_check": "Проверка кода",
|
|
2995
3014
|
"tool.truncated": "[Обрезано: удалено {tokens} токенов]",
|
|
2996
3015
|
"tool.subagent_queued": "Задача подагенту добавлена: {task}",
|
|
2997
3016
|
"tool.subagent_artifact": `Суб-агент завершён. Полный результат сохранён в артефакт: {path}
|
|
@@ -3084,6 +3103,9 @@ var init_ru = __esm(() => {
|
|
|
3084
3103
|
"plan.switched": "Переключено на план {id}: {title}",
|
|
3085
3104
|
"plan.replanned": "План перепланирован: {kept} выполненных шагов сохранено, {steps} новых шагов добавлено",
|
|
3086
3105
|
"plan.replan_no_steps": "Укажите новые шаги для перепланирования",
|
|
3106
|
+
"plan.active_in_progress": 'Нельзя создать новый план: активный план {id} уже имеет прогресс ({done}/{total} выполнено, текущий: шаг {current}). Продолжай его — вызови "plan show", чтобы увидеть, и продолжай работу. Чтобы заменить план, сначала вызови "plan abort", затем "plan create".',
|
|
3107
|
+
"plan.id_ignored": 'примечание: id плана генерируется автоматически; используй "plan switch", чтобы активировать существующий план по id.',
|
|
3108
|
+
"plan.existing_fresh": "примечание: предыдущий активный план не имел прогресса и сохранён как черновик.",
|
|
3087
3109
|
"todo.added": "Добавлено {count} задач: {items}",
|
|
3088
3110
|
"todo.marked_done": "Отмечено выполненными: {count}",
|
|
3089
3111
|
"todo.no_active": "Нет активных задач",
|
|
@@ -3099,6 +3121,11 @@ var init_ru = __esm(() => {
|
|
|
3099
3121
|
"verify.script_failed": "Скрипт '{script}' не пройден: {message}",
|
|
3100
3122
|
"verify.syntax_error": "Синтаксическая ошибка в: {path}",
|
|
3101
3123
|
"lsp.unavailable": "статические проверки недоступны (сервер не найден). Проверяйте через собственный build/test проекта.",
|
|
3124
|
+
"lsp.check_disabled": "LSP-проверки отключены в конфигурации.",
|
|
3125
|
+
"lsp.check_no_path": "Укажите путь (файл или каталог) для проверки.",
|
|
3126
|
+
"lsp.check_notfound": "Путь не найден: {path}",
|
|
3127
|
+
"lsp.check_unsupported": "Для файла не настроен LSP-сервер: {path}",
|
|
3128
|
+
"lsp.check_clean": "Ошибок и предупреждений не обнаружено (проверено файлов: {count}).",
|
|
3102
3129
|
"cli.description": "Micro Models Agent — ИИ-агент для кодинга на малых моделях",
|
|
3103
3130
|
"cli.init": "Запустить мастер настройки",
|
|
3104
3131
|
"cli.config_saved": "Конфигурация сохранена в ~/.mma/config.json",
|
|
@@ -3208,6 +3235,13 @@ var init_ru = __esm(() => {
|
|
|
3208
3235
|
"cli.security.recommended_for": "Рекомендуется для",
|
|
3209
3236
|
"cli.yes": "Да",
|
|
3210
3237
|
"cli.no": "Нет",
|
|
3238
|
+
"cli.plugins.description": "Управление плагинами",
|
|
3239
|
+
"cli.plugins.list": "Список загруженных плагинов (имя, версия, источник)",
|
|
3240
|
+
"cli.plugins.all": "Включить встроенные плагины",
|
|
3241
|
+
"cli.plugins.only_external": "(встроенные плагины скрыты — используйте --all)",
|
|
3242
|
+
"cli.plugins.none": "Плагины не загружены",
|
|
3243
|
+
"cli.plugins.header": "Плагины: {count} загружено (MMA v{mma})",
|
|
3244
|
+
"cli.plugins.builtin_mark": "●",
|
|
3211
3245
|
"repl.help": "Показать доступные команды",
|
|
3212
3246
|
"repl.help_usage": "Использование: /help",
|
|
3213
3247
|
"repl.exit": "Выйти из REPL",
|
|
@@ -3421,6 +3455,8 @@ var init_ru = __esm(() => {
|
|
|
3421
3455
|
"pipeline.circular": "Циклическая зависимость: {stepId}",
|
|
3422
3456
|
"plugin.loaded": "Загружен плагин: {name}",
|
|
3423
3457
|
"plugin.skipped": "Пропущен несовместимый плагин: {entry} ({message})",
|
|
3458
|
+
"plugin.incompatible": "Пропущен плагин {name}: требуется MMA v{min}, текущая v{current}",
|
|
3459
|
+
"plugin.dedup_older": "Плагин {name} v{version} пропущен: уже загружена более новая версия",
|
|
3424
3460
|
"migration.detected": "[MMA] Обнаружен старый конфиг. {summary}",
|
|
3425
3461
|
"migration.summary": "[MMA] {summary}",
|
|
3426
3462
|
"migration.config_bak": "- config → config.json.bak",
|
|
@@ -11196,6 +11232,7 @@ class FactExtractor {
|
|
|
11196
11232
|
deletedFacts = [];
|
|
11197
11233
|
decisionFacts = [];
|
|
11198
11234
|
errorFacts = [];
|
|
11235
|
+
readFacts = [];
|
|
11199
11236
|
static MAX_FACTS = 20;
|
|
11200
11237
|
get errorCount() {
|
|
11201
11238
|
return this.errorFacts.length;
|
|
@@ -11211,13 +11248,19 @@ class FactExtractor {
|
|
|
11211
11248
|
new RegExp(`Deleted ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi"),
|
|
11212
11249
|
new RegExp(`(?:Удалён|Файл удалён):? ${DRIVE}([\\w./\\\\-]+\\.[a-z]+)`, "gi")
|
|
11213
11250
|
];
|
|
11251
|
+
const readPatterns = [
|
|
11252
|
+
new RegExp(`── (${DRIVE}[\\w./\\\\-]+\\.[a-z]+) \\(`, "gi")
|
|
11253
|
+
];
|
|
11214
11254
|
const newFiles = [];
|
|
11215
11255
|
const newDeleted = [];
|
|
11216
11256
|
const newDecisions = [];
|
|
11217
11257
|
const newErrors = [];
|
|
11258
|
+
const newReads = [];
|
|
11218
11259
|
const lastEvent = new Map;
|
|
11219
11260
|
for (const msg of turns) {
|
|
11220
11261
|
const content = getMessageText(msg.content);
|
|
11262
|
+
if (msg.role === "system")
|
|
11263
|
+
continue;
|
|
11221
11264
|
if (msg.role === "user" && (content.startsWith("<system-summary>") || content.includes("[Compressed:"))) {
|
|
11222
11265
|
continue;
|
|
11223
11266
|
}
|
|
@@ -11234,6 +11277,11 @@ class FactExtractor {
|
|
|
11234
11277
|
lastEvent.set(match[1], "deleted");
|
|
11235
11278
|
}
|
|
11236
11279
|
}
|
|
11280
|
+
for (const pattern of readPatterns) {
|
|
11281
|
+
for (const match of content.matchAll(pattern)) {
|
|
11282
|
+
newReads.push(match[1]);
|
|
11283
|
+
}
|
|
11284
|
+
}
|
|
11237
11285
|
if (content.includes("Plan:") && content.includes("[")) {
|
|
11238
11286
|
const planLine = content.split(`
|
|
11239
11287
|
`).find((line) => line.includes("Plan:"));
|
|
@@ -11249,11 +11297,13 @@ class FactExtractor {
|
|
|
11249
11297
|
newDecisions.push(line.trim().slice(0, 200));
|
|
11250
11298
|
}
|
|
11251
11299
|
}
|
|
11252
|
-
if (
|
|
11253
|
-
|
|
11300
|
+
if (msg.role === "tool" || msg.role === "assistant") {
|
|
11301
|
+
if (content.includes("Error:") || content.includes("failed") || content.includes("Ошибка:") || content.includes("не удалось")) {
|
|
11302
|
+
const line = content.split(`
|
|
11254
11303
|
`).find((l) => l.includes("Error:") || l.includes("failed") || l.includes("Ошибка:") || l.includes("не удалось"));
|
|
11255
|
-
|
|
11256
|
-
|
|
11304
|
+
if (line)
|
|
11305
|
+
newErrors.push(line.trim().slice(0, 250));
|
|
11306
|
+
}
|
|
11257
11307
|
}
|
|
11258
11308
|
}
|
|
11259
11309
|
const dedup = (arr) => [...new Set(arr)];
|
|
@@ -11263,6 +11313,7 @@ class FactExtractor {
|
|
|
11263
11313
|
this.deletedFacts = dedup([...this.deletedFacts, ...finalDeleted].filter((p) => !finalFiles.includes(p))).slice(-FactExtractor.MAX_FACTS);
|
|
11264
11314
|
this.decisionFacts = dedup([...this.decisionFacts, ...newDecisions]).slice(-FactExtractor.MAX_FACTS);
|
|
11265
11315
|
this.errorFacts = dedup([...this.errorFacts, ...newErrors]).slice(-FactExtractor.MAX_FACTS);
|
|
11316
|
+
this.readFacts = dedup([...this.readFacts, ...newReads]).slice(-FactExtractor.MAX_FACTS);
|
|
11266
11317
|
}
|
|
11267
11318
|
filesLine() {
|
|
11268
11319
|
const deletedSet = new Set(this.deletedFacts);
|
|
@@ -11286,6 +11337,11 @@ class FactExtractor {
|
|
|
11286
11337
|
return null;
|
|
11287
11338
|
return `[Errors: ${this.errorFacts.slice(-3).join("; ")}]`;
|
|
11288
11339
|
}
|
|
11340
|
+
readLine() {
|
|
11341
|
+
if (this.readFacts.length === 0)
|
|
11342
|
+
return null;
|
|
11343
|
+
return `[Read: ${this.readFacts.slice(-12).join("; ")}]`;
|
|
11344
|
+
}
|
|
11289
11345
|
}
|
|
11290
11346
|
var init_fact_extractor = () => {};
|
|
11291
11347
|
|
|
@@ -11358,12 +11414,16 @@ class ContextManager {
|
|
|
11358
11414
|
pendingImageParts = [];
|
|
11359
11415
|
toolTokens = 0;
|
|
11360
11416
|
onCompact = null;
|
|
11417
|
+
planSummaryProvider = null;
|
|
11361
11418
|
constructor(contextWindow, contextBudget, tokenCounter) {
|
|
11362
11419
|
this.contextWindow = contextWindow;
|
|
11363
11420
|
this.compactionThreshold = contextBudget?.compactionThreshold ?? 0.75;
|
|
11364
11421
|
this.budget = this.calculateBudget(contextWindow, contextBudget);
|
|
11365
11422
|
this.tokenCounter = tokenCounter ?? null;
|
|
11366
11423
|
}
|
|
11424
|
+
setPlanSummaryProvider(fn) {
|
|
11425
|
+
this.planSummaryProvider = fn;
|
|
11426
|
+
}
|
|
11367
11427
|
calculateBudget(window, contextBudget) {
|
|
11368
11428
|
if (contextBudget) {
|
|
11369
11429
|
const systemPrompt = Math.floor(window * contextBudget.systemPrompt);
|
|
@@ -11516,12 +11576,18 @@ class ContextManager {
|
|
|
11516
11576
|
if (this.lastUserFeedback && !task.startsWith(this.lastUserFeedback)) {
|
|
11517
11577
|
parts.push(`[User feedback: ${this.lastUserFeedback}]`);
|
|
11518
11578
|
}
|
|
11579
|
+
const planLine = this.planSummaryProvider?.();
|
|
11580
|
+
if (planLine)
|
|
11581
|
+
parts.push(`[Plan: ${planLine}]`);
|
|
11519
11582
|
const filesLine = this.facts.filesLine();
|
|
11520
11583
|
if (filesLine)
|
|
11521
11584
|
parts.push(filesLine);
|
|
11522
11585
|
const deletedLine = this.facts.deletedLine();
|
|
11523
11586
|
if (deletedLine)
|
|
11524
11587
|
parts.push(deletedLine);
|
|
11588
|
+
const readLine = this.facts.readLine();
|
|
11589
|
+
if (readLine)
|
|
11590
|
+
parts.push(readLine);
|
|
11525
11591
|
const decisionsLine = this.facts.decisionsLine();
|
|
11526
11592
|
if (decisionsLine)
|
|
11527
11593
|
parts.push(decisionsLine);
|
|
@@ -12174,16 +12240,157 @@ var init_detector = __esm(() => {
|
|
|
12174
12240
|
init_llm_judge();
|
|
12175
12241
|
});
|
|
12176
12242
|
|
|
12243
|
+
// src/modules/lsp/command.ts
|
|
12244
|
+
import { delimiter, join as join13 } from "path";
|
|
12245
|
+
import { existsSync as existsSync22 } from "fs";
|
|
12246
|
+
import { platform as platform3 } from "os";
|
|
12247
|
+
function resolveSpawnCommand(command, platformName = platform3(), pathEnv = process.env.PATH ?? "") {
|
|
12248
|
+
if (platformName !== "win32")
|
|
12249
|
+
return command;
|
|
12250
|
+
if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
|
|
12251
|
+
return command;
|
|
12252
|
+
}
|
|
12253
|
+
const dirs = pathEnv.split(delimiter).filter(Boolean);
|
|
12254
|
+
for (const dir of dirs) {
|
|
12255
|
+
for (const ext of WIN_EXTS) {
|
|
12256
|
+
const candidate = join13(dir, `${command}${ext}`);
|
|
12257
|
+
if (existsSync22(candidate))
|
|
12258
|
+
return `${command}${ext}`;
|
|
12259
|
+
}
|
|
12260
|
+
}
|
|
12261
|
+
return command;
|
|
12262
|
+
}
|
|
12263
|
+
function buildWinCommandLine(command, args) {
|
|
12264
|
+
const quote = (part) => {
|
|
12265
|
+
if (part === "")
|
|
12266
|
+
return '""';
|
|
12267
|
+
if (!/[\s"&|^<>()%!]/.test(part))
|
|
12268
|
+
return part;
|
|
12269
|
+
return `"${part.replace(/"/g, "\\\"")}"`;
|
|
12270
|
+
};
|
|
12271
|
+
return [command, ...args].map(quote).join(" ");
|
|
12272
|
+
}
|
|
12273
|
+
var WIN_EXTS;
|
|
12274
|
+
var init_command = __esm(() => {
|
|
12275
|
+
WIN_EXTS = [".cmd", ".bat", ".exe", ".com"];
|
|
12276
|
+
});
|
|
12277
|
+
|
|
12278
|
+
// src/modules/updater/checker.ts
|
|
12279
|
+
import { platform as platform4 } from "os";
|
|
12280
|
+
function semverGt(a, b) {
|
|
12281
|
+
const pa = a.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
12282
|
+
const pb = b.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
12283
|
+
for (let i = 0;i < 3; i++) {
|
|
12284
|
+
const na = pa[i] ?? 0;
|
|
12285
|
+
const nb = pb[i] ?? 0;
|
|
12286
|
+
if (na !== nb)
|
|
12287
|
+
return na > nb;
|
|
12288
|
+
}
|
|
12289
|
+
return false;
|
|
12290
|
+
}
|
|
12291
|
+
|
|
12292
|
+
class Updater {
|
|
12293
|
+
currentVersion;
|
|
12294
|
+
packageName;
|
|
12295
|
+
runner;
|
|
12296
|
+
constructor(currentVersion, packageName, runner) {
|
|
12297
|
+
this.currentVersion = currentVersion;
|
|
12298
|
+
this.packageName = packageName;
|
|
12299
|
+
this.runner = runner ?? defaultRunner;
|
|
12300
|
+
}
|
|
12301
|
+
getCurrentVersion() {
|
|
12302
|
+
return this.currentVersion;
|
|
12303
|
+
}
|
|
12304
|
+
getPackageName() {
|
|
12305
|
+
return this.packageName;
|
|
12306
|
+
}
|
|
12307
|
+
async check() {
|
|
12308
|
+
try {
|
|
12309
|
+
const response = await fetch(`https://registry.npmjs.org/${this.packageName}`, {
|
|
12310
|
+
headers: { Accept: "application/vnd.npm.install-v1+json" },
|
|
12311
|
+
signal: AbortSignal.timeout(5000)
|
|
12312
|
+
});
|
|
12313
|
+
if (!response.ok) {
|
|
12314
|
+
return { updateAvailable: false, current: this.currentVersion, error: `HTTP ${response.status}` };
|
|
12315
|
+
}
|
|
12316
|
+
const data = await response.json();
|
|
12317
|
+
const latest = data["dist-tags"]?.latest;
|
|
12318
|
+
if (!latest) {
|
|
12319
|
+
return { updateAvailable: false, current: this.currentVersion, error: "No latest tag" };
|
|
12320
|
+
}
|
|
12321
|
+
const updateAvailable = semverGt(latest, this.currentVersion);
|
|
12322
|
+
return { updateAvailable, current: this.currentVersion, latest };
|
|
12323
|
+
} catch (e) {
|
|
12324
|
+
return { updateAvailable: false, current: this.currentVersion, error: e.message };
|
|
12325
|
+
}
|
|
12326
|
+
}
|
|
12327
|
+
async install(latest) {
|
|
12328
|
+
try {
|
|
12329
|
+
const { command, args } = this.buildInstallCommand(latest);
|
|
12330
|
+
const res = await this.runner(command, args, {
|
|
12331
|
+
timeout: 120000,
|
|
12332
|
+
windowsHide: true
|
|
12333
|
+
});
|
|
12334
|
+
if (res.error)
|
|
12335
|
+
return { success: false, error: res.error };
|
|
12336
|
+
return { success: true, installed: latest };
|
|
12337
|
+
} catch (e) {
|
|
12338
|
+
const msg = e?.message ?? String(e);
|
|
12339
|
+
return { success: false, error: msg.split(`
|
|
12340
|
+
`)[0] };
|
|
12341
|
+
}
|
|
12342
|
+
}
|
|
12343
|
+
buildInstallCommand(latest) {
|
|
12344
|
+
const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
|
|
12345
|
+
const command = resolveSpawnCommand("npm");
|
|
12346
|
+
if (platform4() === "win32" && /\.(cmd|bat)$/i.test(command)) {
|
|
12347
|
+
return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
|
|
12348
|
+
}
|
|
12349
|
+
return { command, args: npmArgs };
|
|
12350
|
+
}
|
|
12351
|
+
}
|
|
12352
|
+
var defaultRunner = async (command, args, options) => {
|
|
12353
|
+
const { execFile } = await import("child_process");
|
|
12354
|
+
return new Promise((resolve13) => {
|
|
12355
|
+
execFile(command, args, options, (err) => resolve13({ error: err?.message }));
|
|
12356
|
+
});
|
|
12357
|
+
};
|
|
12358
|
+
var init_checker = __esm(() => {
|
|
12359
|
+
init_command();
|
|
12360
|
+
});
|
|
12361
|
+
|
|
12177
12362
|
// src/modules/plugins/manager.ts
|
|
12178
12363
|
class PluginManager {
|
|
12179
12364
|
plugins = [];
|
|
12180
|
-
register(plugin) {
|
|
12365
|
+
register(plugin, source) {
|
|
12366
|
+
if (source)
|
|
12367
|
+
plugin.source = source;
|
|
12368
|
+
const existing = this.plugins.find((p) => p.name === plugin.name);
|
|
12369
|
+
if (existing) {
|
|
12370
|
+
if (semverGt(plugin.version || "0.0.0", existing.version || "0.0.0")) {
|
|
12371
|
+
this.plugins = this.plugins.filter((p) => p.name !== plugin.name);
|
|
12372
|
+
this.plugins.push(plugin);
|
|
12373
|
+
this.sort();
|
|
12374
|
+
return { status: "registered" };
|
|
12375
|
+
}
|
|
12376
|
+
return { status: "skipped_older", existing };
|
|
12377
|
+
}
|
|
12181
12378
|
this.plugins.push(plugin);
|
|
12379
|
+
this.sort();
|
|
12380
|
+
return { status: "registered" };
|
|
12381
|
+
}
|
|
12382
|
+
sort() {
|
|
12182
12383
|
this.plugins.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
12183
12384
|
}
|
|
12184
12385
|
getAllPlugins() {
|
|
12185
12386
|
return [...this.plugins];
|
|
12186
12387
|
}
|
|
12388
|
+
getPluginInfos() {
|
|
12389
|
+
return [...this.plugins].map((plugin) => ({ plugin, source: plugin.source }));
|
|
12390
|
+
}
|
|
12391
|
+
getPlugin(name) {
|
|
12392
|
+
return this.plugins.find((p) => p.name === name) ?? null;
|
|
12393
|
+
}
|
|
12187
12394
|
runOnBuildPrompt() {
|
|
12188
12395
|
return this.plugins.map((p) => {
|
|
12189
12396
|
try {
|
|
@@ -12320,6 +12527,9 @@ class PluginManager {
|
|
|
12320
12527
|
return chunk;
|
|
12321
12528
|
}
|
|
12322
12529
|
}
|
|
12530
|
+
var init_manager2 = __esm(() => {
|
|
12531
|
+
init_checker();
|
|
12532
|
+
});
|
|
12323
12533
|
|
|
12324
12534
|
// src/tools/subagent.ts
|
|
12325
12535
|
function buildSubagentSystemPrompt(context, stable) {
|
|
@@ -12339,6 +12549,7 @@ var init_subagent = __esm(() => {
|
|
|
12339
12549
|
init_agent();
|
|
12340
12550
|
init_manager();
|
|
12341
12551
|
init_detector();
|
|
12552
|
+
init_manager2();
|
|
12342
12553
|
init_audit_log();
|
|
12343
12554
|
init_session_isolation();
|
|
12344
12555
|
init_store();
|
|
@@ -13393,6 +13604,7 @@ var init_pipeline_run = __esm(() => {
|
|
|
13393
13604
|
init_parser();
|
|
13394
13605
|
init_agent();
|
|
13395
13606
|
init_manager();
|
|
13607
|
+
init_manager2();
|
|
13396
13608
|
init_detector();
|
|
13397
13609
|
init_audit_log();
|
|
13398
13610
|
init_session_isolation();
|
|
@@ -13976,7 +14188,7 @@ ${JSON.stringify(result, null, 2)}`
|
|
|
13976
14188
|
|
|
13977
14189
|
// src/tools/search-history.ts
|
|
13978
14190
|
import * as fs from "fs";
|
|
13979
|
-
import { join as
|
|
14191
|
+
import { join as join14 } from "path";
|
|
13980
14192
|
import { homedir as homedir5 } from "os";
|
|
13981
14193
|
function searchFile(filePath, query, maxResults, results) {
|
|
13982
14194
|
if (!fs.existsSync(filePath))
|
|
@@ -14020,7 +14232,7 @@ var init_search_history = __esm(() => {
|
|
|
14020
14232
|
const query = String(args.query || "").toLowerCase();
|
|
14021
14233
|
const maxResults = Number(args.maxResults) || 5;
|
|
14022
14234
|
const sessionId = args.sessionId ? String(args.sessionId) : null;
|
|
14023
|
-
const sessionDir =
|
|
14235
|
+
const sessionDir = join14(homedir5(), ".mma", "sessions");
|
|
14024
14236
|
const results = [];
|
|
14025
14237
|
try {
|
|
14026
14238
|
if (!fs.existsSync(sessionDir)) {
|
|
@@ -14035,7 +14247,7 @@ var init_search_history = __esm(() => {
|
|
|
14035
14247
|
continue;
|
|
14036
14248
|
if (sessionId && entry.name !== sessionId)
|
|
14037
14249
|
continue;
|
|
14038
|
-
const historyFile =
|
|
14250
|
+
const historyFile = join14(sessionDir, entry.name, "history.jsonl");
|
|
14039
14251
|
searchFile(historyFile, query, maxResults, results);
|
|
14040
14252
|
if (results.length >= maxResults)
|
|
14041
14253
|
break;
|
|
@@ -14062,8 +14274,8 @@ var init_search_history = __esm(() => {
|
|
|
14062
14274
|
});
|
|
14063
14275
|
|
|
14064
14276
|
// src/modules/memory/search.ts
|
|
14065
|
-
import { readFileSync as readFileSync12, existsSync as
|
|
14066
|
-
import { join as
|
|
14277
|
+
import { readFileSync as readFileSync12, existsSync as existsSync24 } from "fs";
|
|
14278
|
+
import { join as join15 } from "path";
|
|
14067
14279
|
|
|
14068
14280
|
class MemorySearch {
|
|
14069
14281
|
memoryDir;
|
|
@@ -14074,8 +14286,8 @@ class MemorySearch {
|
|
|
14074
14286
|
const results = [];
|
|
14075
14287
|
const lowerQuery = query.toLowerCase();
|
|
14076
14288
|
for (const name of MEMORY_FILES) {
|
|
14077
|
-
const path =
|
|
14078
|
-
if (!
|
|
14289
|
+
const path = join15(this.memoryDir, `${name}.md`);
|
|
14290
|
+
if (!existsSync24(path))
|
|
14079
14291
|
continue;
|
|
14080
14292
|
const content = readFileSync12(path, "utf-8");
|
|
14081
14293
|
const lines = content.split(`
|
|
@@ -14086,8 +14298,8 @@ class MemorySearch {
|
|
|
14086
14298
|
}
|
|
14087
14299
|
}
|
|
14088
14300
|
}
|
|
14089
|
-
const prefsPath =
|
|
14090
|
-
if (
|
|
14301
|
+
const prefsPath = join15(this.memoryDir, "preferences.json");
|
|
14302
|
+
if (existsSync24(prefsPath)) {
|
|
14091
14303
|
try {
|
|
14092
14304
|
const prefs = JSON.parse(readFileSync12(prefsPath, "utf-8"));
|
|
14093
14305
|
for (const [key, value] of Object.entries(prefs)) {
|
|
@@ -14107,8 +14319,8 @@ var init_search = __esm(() => {
|
|
|
14107
14319
|
});
|
|
14108
14320
|
|
|
14109
14321
|
// src/modules/memory/store.ts
|
|
14110
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, existsSync as
|
|
14111
|
-
import { join as
|
|
14322
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, existsSync as existsSync25, mkdirSync as mkdirSync13 } from "fs";
|
|
14323
|
+
import { join as join16 } from "path";
|
|
14112
14324
|
|
|
14113
14325
|
class MemoryStore {
|
|
14114
14326
|
memoryDir;
|
|
@@ -14116,8 +14328,8 @@ class MemoryStore {
|
|
|
14116
14328
|
this.memoryDir = memoryDir;
|
|
14117
14329
|
this.ensureDir();
|
|
14118
14330
|
for (const name of MEMORY_FILES2) {
|
|
14119
|
-
const path =
|
|
14120
|
-
if (!
|
|
14331
|
+
const path = join16(this.memoryDir, `${name}.md`);
|
|
14332
|
+
if (!existsSync25(path)) {
|
|
14121
14333
|
writeFileSync9(path, `# ${name.charAt(0).toUpperCase() + name.slice(1)}
|
|
14122
14334
|
|
|
14123
14335
|
`, "utf-8");
|
|
@@ -14125,18 +14337,18 @@ class MemoryStore {
|
|
|
14125
14337
|
}
|
|
14126
14338
|
}
|
|
14127
14339
|
ensureDir() {
|
|
14128
|
-
if (!
|
|
14340
|
+
if (!existsSync25(this.memoryDir)) {
|
|
14129
14341
|
mkdirSync13(this.memoryDir, { recursive: true });
|
|
14130
14342
|
}
|
|
14131
14343
|
}
|
|
14132
14344
|
read(name) {
|
|
14133
|
-
const path =
|
|
14134
|
-
if (!
|
|
14345
|
+
const path = join16(this.memoryDir, `${name}.md`);
|
|
14346
|
+
if (!existsSync25(path))
|
|
14135
14347
|
return "";
|
|
14136
14348
|
return readFileSync13(path, "utf-8");
|
|
14137
14349
|
}
|
|
14138
14350
|
append(name, entry) {
|
|
14139
|
-
const path =
|
|
14351
|
+
const path = join16(this.memoryDir, `${name}.md`);
|
|
14140
14352
|
const timestamp = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
14141
14353
|
const formatted = `- **${timestamp}** — ${entry}
|
|
14142
14354
|
`;
|
|
@@ -14147,11 +14359,11 @@ class MemoryStore {
|
|
|
14147
14359
|
return searchModule.query(query);
|
|
14148
14360
|
}
|
|
14149
14361
|
prefsPath() {
|
|
14150
|
-
return
|
|
14362
|
+
return join16(this.memoryDir, "preferences.json");
|
|
14151
14363
|
}
|
|
14152
14364
|
getPreferences() {
|
|
14153
14365
|
const path = this.prefsPath();
|
|
14154
|
-
if (!
|
|
14366
|
+
if (!existsSync25(path))
|
|
14155
14367
|
return {};
|
|
14156
14368
|
try {
|
|
14157
14369
|
return JSON.parse(readFileSync13(path, "utf-8"));
|
|
@@ -14187,7 +14399,7 @@ var init_store2 = __esm(() => {
|
|
|
14187
14399
|
|
|
14188
14400
|
// src/tools/remember.ts
|
|
14189
14401
|
import { homedir as homedir6 } from "os";
|
|
14190
|
-
import { join as
|
|
14402
|
+
import { join as join17 } from "path";
|
|
14191
14403
|
var CATEGORIES, rememberTool;
|
|
14192
14404
|
var init_remember = __esm(() => {
|
|
14193
14405
|
init_i18n();
|
|
@@ -14225,7 +14437,7 @@ var init_remember = __esm(() => {
|
|
|
14225
14437
|
if (!CATEGORIES.includes(category)) {
|
|
14226
14438
|
return { success: false, output: t("tool.invalid_params") };
|
|
14227
14439
|
}
|
|
14228
|
-
const memoryDir =
|
|
14440
|
+
const memoryDir = join17(homedir6(), ".mma", "memory");
|
|
14229
14441
|
const store = new MemoryStore(memoryDir);
|
|
14230
14442
|
try {
|
|
14231
14443
|
if (category === "preferences") {
|
|
@@ -14258,7 +14470,7 @@ var init_remember = __esm(() => {
|
|
|
14258
14470
|
|
|
14259
14471
|
// src/tools/recall.ts
|
|
14260
14472
|
import { homedir as homedir7 } from "os";
|
|
14261
|
-
import { join as
|
|
14473
|
+
import { join as join18 } from "path";
|
|
14262
14474
|
function formatAll(store) {
|
|
14263
14475
|
const parts = [];
|
|
14264
14476
|
const prefs = store.getPreferences();
|
|
@@ -14341,7 +14553,7 @@ var init_recall = __esm(() => {
|
|
|
14341
14553
|
handler: async (_ctx, args) => {
|
|
14342
14554
|
const query = args.query ? String(args.query) : "";
|
|
14343
14555
|
const category = args.category ? String(args.category) : "";
|
|
14344
|
-
const memoryDir =
|
|
14556
|
+
const memoryDir = join18(homedir7(), ".mma", "memory");
|
|
14345
14557
|
const store = new MemoryStore(memoryDir);
|
|
14346
14558
|
try {
|
|
14347
14559
|
if (!query && !category) {
|
|
@@ -14372,6 +14584,13 @@ var init_recall = __esm(() => {
|
|
|
14372
14584
|
};
|
|
14373
14585
|
});
|
|
14374
14586
|
|
|
14587
|
+
// src/modules/browser/bridge-path.ts
|
|
14588
|
+
import { existsSync as existsSync26 } from "fs";
|
|
14589
|
+
function pickExistingPath(candidates, fallback = candidates[0]) {
|
|
14590
|
+
return candidates.find((p) => existsSync26(p)) ?? fallback;
|
|
14591
|
+
}
|
|
14592
|
+
var init_bridge_path = () => {};
|
|
14593
|
+
|
|
14375
14594
|
// src/modules/browser/bridge-client.ts
|
|
14376
14595
|
var exports_bridge_client = {};
|
|
14377
14596
|
__export(exports_bridge_client, {
|
|
@@ -14379,10 +14598,15 @@ __export(exports_bridge_client, {
|
|
|
14379
14598
|
});
|
|
14380
14599
|
import { spawn as spawn4 } from "child_process";
|
|
14381
14600
|
import { createInterface } from "readline";
|
|
14382
|
-
import { dirname as dirname9, join as
|
|
14601
|
+
import { dirname as dirname9, join as join19 } from "path";
|
|
14383
14602
|
import { fileURLToPath } from "url";
|
|
14384
14603
|
function bridgeScriptPath() {
|
|
14385
|
-
|
|
14604
|
+
const dir = dirname9(fileURLToPath(import.meta.url));
|
|
14605
|
+
const candidates = [
|
|
14606
|
+
join19(dir, "bridge-server.mjs"),
|
|
14607
|
+
join19(dir, "modules", "browser", "bridge-server.mjs")
|
|
14608
|
+
];
|
|
14609
|
+
return pickExistingPath(candidates);
|
|
14386
14610
|
}
|
|
14387
14611
|
|
|
14388
14612
|
class BridgeDriver {
|
|
@@ -14560,6 +14784,7 @@ class BridgeDriver {
|
|
|
14560
14784
|
var BRIDGE_REQUEST_TIMEOUT_MS = 30000;
|
|
14561
14785
|
var init_bridge_client = __esm(() => {
|
|
14562
14786
|
init_session();
|
|
14787
|
+
init_bridge_path();
|
|
14563
14788
|
});
|
|
14564
14789
|
|
|
14565
14790
|
// src/modules/browser/driver.ts
|
|
@@ -14939,15 +15164,15 @@ function buildTextExtractionScript() {
|
|
|
14939
15164
|
|
|
14940
15165
|
// src/modules/browser/cookie-store.ts
|
|
14941
15166
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
14942
|
-
import { join as
|
|
15167
|
+
import { join as join20 } from "path";
|
|
14943
15168
|
|
|
14944
15169
|
class CookieStore {
|
|
14945
15170
|
filePath;
|
|
14946
15171
|
constructor(cookieDir) {
|
|
14947
|
-
this.filePath =
|
|
15172
|
+
this.filePath = join20(cookieDir, "cookies.json");
|
|
14948
15173
|
}
|
|
14949
15174
|
async save(cookies) {
|
|
14950
|
-
await mkdir(
|
|
15175
|
+
await mkdir(join20(this.filePath, ".."), { recursive: true });
|
|
14951
15176
|
await writeFile(this.filePath, JSON.stringify(cookies, null, 2), "utf-8");
|
|
14952
15177
|
}
|
|
14953
15178
|
async load() {
|
|
@@ -15302,10 +15527,10 @@ var init_session = __esm(() => {
|
|
|
15302
15527
|
});
|
|
15303
15528
|
|
|
15304
15529
|
// src/tools/browser.ts
|
|
15305
|
-
import { join as
|
|
15530
|
+
import { join as join21 } from "path";
|
|
15306
15531
|
function getSession(ctx) {
|
|
15307
15532
|
if (!session) {
|
|
15308
|
-
const cookieDir =
|
|
15533
|
+
const cookieDir = join21(ctx.baseDir, ".mma", "browser");
|
|
15309
15534
|
session = new BrowserSession({
|
|
15310
15535
|
...DEFAULT_BROWSER_CONFIG,
|
|
15311
15536
|
headless: ctx.config.browser?.headless ?? true,
|
|
@@ -15438,13 +15663,13 @@ async function readClipboardImage() {
|
|
|
15438
15663
|
return readClipboardFallback();
|
|
15439
15664
|
}
|
|
15440
15665
|
async function readClipboardFallback() {
|
|
15441
|
-
const { platform:
|
|
15666
|
+
const { platform: platform5 } = await import("os");
|
|
15442
15667
|
const { execSync } = await import("child_process");
|
|
15443
15668
|
const { readFileSync: readFileSync15, unlinkSync: unlinkSync4 } = await import("fs");
|
|
15444
|
-
const { join:
|
|
15445
|
-
const tmpPath =
|
|
15669
|
+
const { join: join22 } = await import("path");
|
|
15670
|
+
const tmpPath = join22(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
|
|
15446
15671
|
try {
|
|
15447
|
-
if (
|
|
15672
|
+
if (platform5() === "linux") {
|
|
15448
15673
|
execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, { timeout: 5000 });
|
|
15449
15674
|
} else {
|
|
15450
15675
|
return null;
|
|
@@ -15520,7 +15745,7 @@ var init_image_utils = __esm(() => {
|
|
|
15520
15745
|
});
|
|
15521
15746
|
|
|
15522
15747
|
// src/tools/attach-image.ts
|
|
15523
|
-
import { existsSync as
|
|
15748
|
+
import { existsSync as existsSync27 } from "fs";
|
|
15524
15749
|
import { resolve as resolve15 } from "path";
|
|
15525
15750
|
var attachImageTool;
|
|
15526
15751
|
var init_attach_image = __esm(() => {
|
|
@@ -15563,7 +15788,7 @@ var init_attach_image = __esm(() => {
|
|
|
15563
15788
|
dataUrl = result.dataUrl;
|
|
15564
15789
|
} else {
|
|
15565
15790
|
const absPath = resolve15(ctx.baseDir, source);
|
|
15566
|
-
if (!
|
|
15791
|
+
if (!existsSync27(absPath)) {
|
|
15567
15792
|
return {
|
|
15568
15793
|
success: false,
|
|
15569
15794
|
output: t("image.not_found", { path: source })
|
|
@@ -15725,44 +15950,59 @@ class ModuleRegistry {
|
|
|
15725
15950
|
}
|
|
15726
15951
|
|
|
15727
15952
|
// src/modules/plugins/loader.ts
|
|
15728
|
-
import { readdirSync as readdirSync7, existsSync as
|
|
15729
|
-
import { join as
|
|
15953
|
+
import { readdirSync as readdirSync7, existsSync as existsSync28, statSync as statSync5 } from "fs";
|
|
15954
|
+
import { join as join22, basename as basename2 } from "path";
|
|
15730
15955
|
|
|
15731
15956
|
class PluginLoader {
|
|
15732
|
-
loadFromDir(dirPath, pluginManager, logger) {
|
|
15733
|
-
if (!
|
|
15957
|
+
loadFromDir(dirPath, pluginManager, logger, options) {
|
|
15958
|
+
if (!existsSync28(dirPath))
|
|
15734
15959
|
return;
|
|
15735
15960
|
const entries = readdirSync7(dirPath).sort();
|
|
15736
15961
|
for (const entry of entries) {
|
|
15737
|
-
const fullPath =
|
|
15962
|
+
const fullPath = join22(dirPath, entry);
|
|
15738
15963
|
const stat = statSync5(fullPath);
|
|
15739
15964
|
if (stat.isFile()) {
|
|
15740
15965
|
if (!entry.endsWith(".ts") && !entry.endsWith(".js"))
|
|
15741
15966
|
continue;
|
|
15742
|
-
this.tryLoad(fullPath, entry, pluginManager, logger);
|
|
15967
|
+
this.tryLoad(fullPath, entry, pluginManager, logger, options);
|
|
15743
15968
|
} else if (stat.isDirectory()) {
|
|
15744
15969
|
const entryFile = this.findEntryFile(fullPath);
|
|
15745
15970
|
if (entryFile) {
|
|
15746
|
-
this.tryLoad(entryFile, `${entry}/${basename2(entryFile)}`, pluginManager, logger);
|
|
15971
|
+
this.tryLoad(entryFile, `${entry}/${basename2(entryFile)}`, pluginManager, logger, options);
|
|
15747
15972
|
}
|
|
15748
15973
|
}
|
|
15749
15974
|
}
|
|
15750
15975
|
}
|
|
15751
15976
|
findEntryFile(dir) {
|
|
15752
15977
|
for (const name of FOLDER_ENTRY_NAMES) {
|
|
15753
|
-
const candidate =
|
|
15754
|
-
if (
|
|
15978
|
+
const candidate = join22(dir, name);
|
|
15979
|
+
if (existsSync28(candidate))
|
|
15755
15980
|
return candidate;
|
|
15756
15981
|
}
|
|
15757
15982
|
return null;
|
|
15758
15983
|
}
|
|
15759
|
-
tryLoad(fullPath, label, pluginManager, logger) {
|
|
15984
|
+
tryLoad(fullPath, label, pluginManager, logger, options) {
|
|
15760
15985
|
try {
|
|
15761
15986
|
const mod = __require(fullPath);
|
|
15762
15987
|
const plugin = mod.default || mod.plugin;
|
|
15763
15988
|
if (plugin && plugin.name) {
|
|
15764
|
-
|
|
15765
|
-
|
|
15989
|
+
if (plugin.minMmaVersion && options?.mmaVersion && semverGt(plugin.minMmaVersion, options.mmaVersion)) {
|
|
15990
|
+
logger?.warn(t("plugin.incompatible", {
|
|
15991
|
+
name: plugin.name,
|
|
15992
|
+
min: plugin.minMmaVersion,
|
|
15993
|
+
current: options.mmaVersion
|
|
15994
|
+
}));
|
|
15995
|
+
return;
|
|
15996
|
+
}
|
|
15997
|
+
const result = pluginManager.register(plugin, options?.source);
|
|
15998
|
+
if (result.status === "registered") {
|
|
15999
|
+
logger?.warn(t("plugin.loaded", { name: plugin.name }));
|
|
16000
|
+
} else if (result.status === "skipped_older") {
|
|
16001
|
+
logger?.warn(t("plugin.dedup_older", {
|
|
16002
|
+
name: plugin.name,
|
|
16003
|
+
version: plugin.version || "0.0.0"
|
|
16004
|
+
}));
|
|
16005
|
+
}
|
|
15766
16006
|
}
|
|
15767
16007
|
} catch (e) {
|
|
15768
16008
|
logger?.warn(t("plugin.skipped", { entry: label, message: e.message }));
|
|
@@ -15772,14 +16012,15 @@ class PluginLoader {
|
|
|
15772
16012
|
var FOLDER_ENTRY_NAMES;
|
|
15773
16013
|
var init_loader = __esm(() => {
|
|
15774
16014
|
init_i18n();
|
|
16015
|
+
init_checker();
|
|
15775
16016
|
FOLDER_ENTRY_NAMES = ["plugin.ts", "plugin.js", "index.ts", "index.js"];
|
|
15776
16017
|
});
|
|
15777
16018
|
|
|
15778
16019
|
// src/modules/plugins/builtin/lint-on-write.ts
|
|
15779
16020
|
import { spawn as spawn5, execSync } from "child_process";
|
|
15780
|
-
import { existsSync as
|
|
15781
|
-
import { resolve as resolve16, extname as extname4, join as
|
|
15782
|
-
import { platform as
|
|
16021
|
+
import { existsSync as existsSync29, readFileSync as readFileSync15 } from "fs";
|
|
16022
|
+
import { resolve as resolve16, extname as extname4, join as join23 } from "path";
|
|
16023
|
+
import { platform as platform5 } from "os";
|
|
15783
16024
|
function contentHash(content) {
|
|
15784
16025
|
let h = 5381;
|
|
15785
16026
|
for (let i = 0;i < content.length; i++) {
|
|
@@ -15789,7 +16030,7 @@ function contentHash(content) {
|
|
|
15789
16030
|
}
|
|
15790
16031
|
function getWinDecoder() {
|
|
15791
16032
|
if (_winDecoder === undefined) {
|
|
15792
|
-
if (
|
|
16033
|
+
if (platform5() !== "win32") {
|
|
15793
16034
|
_winDecoder = null;
|
|
15794
16035
|
} else {
|
|
15795
16036
|
try {
|
|
@@ -15811,6 +16052,7 @@ function getWinDecoder() {
|
|
|
15811
16052
|
class LintOnWritePlugin {
|
|
15812
16053
|
name = "lint-on-write";
|
|
15813
16054
|
priority = 10;
|
|
16055
|
+
isBuiltin = true;
|
|
15814
16056
|
_checkPromise = null;
|
|
15815
16057
|
_checkTimestamp = 0;
|
|
15816
16058
|
async onAfterTool(ctx, call, result) {
|
|
@@ -15824,7 +16066,7 @@ class LintOnWritePlugin {
|
|
|
15824
16066
|
if (!path)
|
|
15825
16067
|
return;
|
|
15826
16068
|
const fullPath = resolve16(ctx.baseDir, path);
|
|
15827
|
-
if (!
|
|
16069
|
+
if (!existsSync29(fullPath))
|
|
15828
16070
|
return;
|
|
15829
16071
|
const ext = extname4(fullPath);
|
|
15830
16072
|
const syntaxError = await this.checkSyntax(fullPath, ext, ctx.baseDir);
|
|
@@ -15880,8 +16122,8 @@ class LintOnWritePlugin {
|
|
|
15880
16122
|
}
|
|
15881
16123
|
async runProjectLint(ctx, result) {
|
|
15882
16124
|
try {
|
|
15883
|
-
const packageJsonPath =
|
|
15884
|
-
if (!
|
|
16125
|
+
const packageJsonPath = join23(ctx.baseDir, "package.json");
|
|
16126
|
+
if (!existsSync29(packageJsonPath)) {
|
|
15885
16127
|
return;
|
|
15886
16128
|
}
|
|
15887
16129
|
const packageJson = JSON.parse(readFileSync15(packageJsonPath, "utf-8"));
|
|
@@ -15904,8 +16146,8 @@ class LintOnWritePlugin {
|
|
|
15904
16146
|
"tsconfig.json",
|
|
15905
16147
|
"package.json"
|
|
15906
16148
|
]);
|
|
15907
|
-
const tsconfigPath =
|
|
15908
|
-
if (!
|
|
16149
|
+
const tsconfigPath = join23(projectRoot, "tsconfig.json");
|
|
16150
|
+
if (!existsSync29(tsconfigPath)) {
|
|
15909
16151
|
return;
|
|
15910
16152
|
}
|
|
15911
16153
|
const now = Date.now();
|
|
@@ -15997,6 +16239,7 @@ var init_lint_on_write = __esm(() => {
|
|
|
15997
16239
|
class NotifyPlugin {
|
|
15998
16240
|
name = "notify";
|
|
15999
16241
|
priority = 5;
|
|
16242
|
+
isBuiltin = true;
|
|
16000
16243
|
onSessionEnd(ctx) {
|
|
16001
16244
|
ctx.logger.info("Session ended");
|
|
16002
16245
|
}
|
|
@@ -16153,8 +16396,8 @@ class PlanTracker {
|
|
|
16153
16396
|
var init_tracker = () => {};
|
|
16154
16397
|
|
|
16155
16398
|
// src/modules/execution/audit-runners.ts
|
|
16156
|
-
import { existsSync as
|
|
16157
|
-
import { dirname as dirname10, join as
|
|
16399
|
+
import { existsSync as existsSync30, readdirSync as readdirSync8 } from "fs";
|
|
16400
|
+
import { dirname as dirname10, join as join24, resolve as resolve17 } from "path";
|
|
16158
16401
|
function findTestFile(dir, depth = 0) {
|
|
16159
16402
|
if (depth > 5)
|
|
16160
16403
|
return null;
|
|
@@ -16165,7 +16408,7 @@ function findTestFile(dir, depth = 0) {
|
|
|
16165
16408
|
return null;
|
|
16166
16409
|
}
|
|
16167
16410
|
for (const e of entries) {
|
|
16168
|
-
const full =
|
|
16411
|
+
const full = join24(dir, e.name);
|
|
16169
16412
|
if (e.isDirectory()) {
|
|
16170
16413
|
if (SKIP_DIRS.has(e.name))
|
|
16171
16414
|
continue;
|
|
@@ -16240,7 +16483,7 @@ function findTypecheckRoot(baseDir, existingFiles = []) {
|
|
|
16240
16483
|
for (const start of candidates) {
|
|
16241
16484
|
let dir = resolve17(start);
|
|
16242
16485
|
for (let depth = 0;depth <= 10; depth++) {
|
|
16243
|
-
if (
|
|
16486
|
+
if (existsSync30(join24(dir, "tsconfig.json"))) {
|
|
16244
16487
|
if (!best || depth < best.depth)
|
|
16245
16488
|
best = { depth, root: dir };
|
|
16246
16489
|
break;
|
|
@@ -16283,11 +16526,11 @@ var init_audit_runners = __esm(() => {
|
|
|
16283
16526
|
});
|
|
16284
16527
|
|
|
16285
16528
|
// src/modules/execution/auditor.ts
|
|
16286
|
-
import { existsSync as
|
|
16287
|
-
import { resolve as resolve18, join as
|
|
16529
|
+
import { existsSync as existsSync31, readdirSync as readdirSync9 } from "fs";
|
|
16530
|
+
import { resolve as resolve18, join as join25, basename as basename3 } from "path";
|
|
16288
16531
|
function findExistingFile(baseDir, filePath) {
|
|
16289
16532
|
const direct = resolve18(baseDir, filePath);
|
|
16290
|
-
if (
|
|
16533
|
+
if (existsSync31(direct))
|
|
16291
16534
|
return direct;
|
|
16292
16535
|
const name = basename3(filePath).toLowerCase();
|
|
16293
16536
|
const suffix = filePath.replace(/\\/g, "/").toLowerCase();
|
|
@@ -16304,7 +16547,7 @@ function findExistingFile(baseDir, filePath) {
|
|
|
16304
16547
|
for (const e of entries) {
|
|
16305
16548
|
if (found)
|
|
16306
16549
|
return;
|
|
16307
|
-
const full =
|
|
16550
|
+
const full = join25(dir, e.name);
|
|
16308
16551
|
if (e.isDirectory()) {
|
|
16309
16552
|
if (SKIP_DIRS.has(e.name))
|
|
16310
16553
|
continue;
|
|
@@ -16442,8 +16685,8 @@ var init_auditor = __esm(() => {
|
|
|
16442
16685
|
});
|
|
16443
16686
|
|
|
16444
16687
|
// src/modules/execution/plan-store.ts
|
|
16445
|
-
import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as
|
|
16446
|
-
import { join as
|
|
16688
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync32, readdirSync as readdirSync10, rmSync } from "fs";
|
|
16689
|
+
import { join as join26 } from "path";
|
|
16447
16690
|
function readPlanFile(path, fallbackBaseDir) {
|
|
16448
16691
|
try {
|
|
16449
16692
|
const raw = readFileSync16(path, "utf-8");
|
|
@@ -16468,10 +16711,10 @@ function writePlanFile(path, plan) {
|
|
|
16468
16711
|
writeFileSync10(path, JSON.stringify(plan, null, 2), "utf-8");
|
|
16469
16712
|
}
|
|
16470
16713
|
function listDir(dir, baseDir) {
|
|
16471
|
-
if (!
|
|
16714
|
+
if (!existsSync32(dir))
|
|
16472
16715
|
return [];
|
|
16473
16716
|
const files = readdirSync10(dir).filter((f) => f.endsWith(".json"));
|
|
16474
|
-
return files.map((f) => readPlanFile(
|
|
16717
|
+
return files.map((f) => readPlanFile(join26(dir, f), baseDir)).filter((p) => p !== null);
|
|
16475
16718
|
}
|
|
16476
16719
|
function toMeta(plan, status) {
|
|
16477
16720
|
return {
|
|
@@ -16492,33 +16735,33 @@ class PlanStore {
|
|
|
16492
16735
|
archiveDir;
|
|
16493
16736
|
legacyPath;
|
|
16494
16737
|
constructor(baseDir) {
|
|
16495
|
-
const mmaDir =
|
|
16496
|
-
if (!
|
|
16738
|
+
const mmaDir = join26(baseDir, ".mma");
|
|
16739
|
+
if (!existsSync32(mmaDir))
|
|
16497
16740
|
mkdirSync14(mmaDir, { recursive: true });
|
|
16498
16741
|
this.baseDir = baseDir;
|
|
16499
|
-
this.plansDir =
|
|
16500
|
-
this.draftsDir =
|
|
16501
|
-
this.archiveDir =
|
|
16502
|
-
this.legacyPath =
|
|
16742
|
+
this.plansDir = join26(mmaDir, "plans");
|
|
16743
|
+
this.draftsDir = join26(this.plansDir, "drafts");
|
|
16744
|
+
this.archiveDir = join26(this.plansDir, "archive");
|
|
16745
|
+
this.legacyPath = join26(mmaDir, LEGACY_FILE);
|
|
16503
16746
|
for (const dir of [this.plansDir, this.draftsDir, this.archiveDir]) {
|
|
16504
|
-
if (!
|
|
16747
|
+
if (!existsSync32(dir))
|
|
16505
16748
|
mkdirSync14(dir, { recursive: true });
|
|
16506
16749
|
}
|
|
16507
16750
|
}
|
|
16508
16751
|
activePath() {
|
|
16509
|
-
return
|
|
16752
|
+
return join26(this.plansDir, "active.json");
|
|
16510
16753
|
}
|
|
16511
16754
|
saveActive(plan) {
|
|
16512
16755
|
writePlanFile(this.activePath(), plan);
|
|
16513
16756
|
}
|
|
16514
16757
|
loadActive() {
|
|
16515
16758
|
const activePath = this.activePath();
|
|
16516
|
-
if (
|
|
16759
|
+
if (existsSync32(activePath)) {
|
|
16517
16760
|
const plan = readPlanFile(activePath, this.baseDir);
|
|
16518
16761
|
if (plan)
|
|
16519
16762
|
return plan;
|
|
16520
16763
|
}
|
|
16521
|
-
if (
|
|
16764
|
+
if (existsSync32(this.legacyPath)) {
|
|
16522
16765
|
const legacy = readPlanFile(this.legacyPath, this.baseDir);
|
|
16523
16766
|
if (legacy) {
|
|
16524
16767
|
this.saveActive(legacy);
|
|
@@ -16532,26 +16775,26 @@ class PlanStore {
|
|
|
16532
16775
|
}
|
|
16533
16776
|
clearActive() {
|
|
16534
16777
|
const p = this.activePath();
|
|
16535
|
-
if (
|
|
16778
|
+
if (existsSync32(p))
|
|
16536
16779
|
rmSync(p, { force: true });
|
|
16537
16780
|
}
|
|
16538
16781
|
saveDraft(plan) {
|
|
16539
|
-
writePlanFile(
|
|
16782
|
+
writePlanFile(join26(this.draftsDir, `${plan.id}.json`), plan);
|
|
16540
16783
|
}
|
|
16541
16784
|
loadDraft(id) {
|
|
16542
|
-
const p =
|
|
16543
|
-
return
|
|
16785
|
+
const p = join26(this.draftsDir, `${id}.json`);
|
|
16786
|
+
return existsSync32(p) ? readPlanFile(p, this.baseDir) : null;
|
|
16544
16787
|
}
|
|
16545
16788
|
removeDraft(id) {
|
|
16546
|
-
const p =
|
|
16547
|
-
if (
|
|
16789
|
+
const p = join26(this.draftsDir, `${id}.json`);
|
|
16790
|
+
if (existsSync32(p))
|
|
16548
16791
|
rmSync(p, { force: true });
|
|
16549
16792
|
}
|
|
16550
16793
|
listDrafts() {
|
|
16551
16794
|
return listDir(this.draftsDir, this.baseDir);
|
|
16552
16795
|
}
|
|
16553
16796
|
archivePlan(plan) {
|
|
16554
|
-
writePlanFile(
|
|
16797
|
+
writePlanFile(join26(this.archiveDir, `${plan.id}.json`), plan);
|
|
16555
16798
|
this.removeDraft(plan.id);
|
|
16556
16799
|
const active = this.loadActive();
|
|
16557
16800
|
if (active && active.id === plan.id) {
|
|
@@ -16562,8 +16805,8 @@ class PlanStore {
|
|
|
16562
16805
|
return listDir(this.archiveDir, this.baseDir);
|
|
16563
16806
|
}
|
|
16564
16807
|
removeArchived(id) {
|
|
16565
|
-
const p =
|
|
16566
|
-
if (
|
|
16808
|
+
const p = join26(this.archiveDir, `${id}.json`);
|
|
16809
|
+
if (existsSync32(p))
|
|
16567
16810
|
rmSync(p, { force: true });
|
|
16568
16811
|
}
|
|
16569
16812
|
listAll() {
|
|
@@ -16790,6 +17033,23 @@ ${lines.join(`
|
|
|
16790
17033
|
if (parsed.error) {
|
|
16791
17034
|
return { success: false, output: parsed.error };
|
|
16792
17035
|
}
|
|
17036
|
+
const existing = deps.trackerRef.current;
|
|
17037
|
+
if (existing) {
|
|
17038
|
+
const activePlan = existing.getPlan();
|
|
17039
|
+
const progressed = activePlan.steps.some((s) => s.status === "done" || s.status === "failed" || s.status === "skipped");
|
|
17040
|
+
if (progressed) {
|
|
17041
|
+
const done = activePlan.steps.filter((s) => s.status === "done").length;
|
|
17042
|
+
return {
|
|
17043
|
+
success: false,
|
|
17044
|
+
output: t("plan.active_in_progress", {
|
|
17045
|
+
id: activePlan.id,
|
|
17046
|
+
done: String(done),
|
|
17047
|
+
total: String(activePlan.steps.length),
|
|
17048
|
+
current: String(existing.getCurrentStepIndex() + 1)
|
|
17049
|
+
})
|
|
17050
|
+
};
|
|
17051
|
+
}
|
|
17052
|
+
}
|
|
16793
17053
|
deps.preserveActive();
|
|
16794
17054
|
const plan = PlanCreator.createPlan(title, steps, deps.baseDir, parsed.kinds ?? []);
|
|
16795
17055
|
deps.setPlan(plan);
|
|
@@ -16798,6 +17058,14 @@ ${lines.join(`
|
|
|
16798
17058
|
title,
|
|
16799
17059
|
steps: String(steps.length)
|
|
16800
17060
|
});
|
|
17061
|
+
if (args.id) {
|
|
17062
|
+
output += `
|
|
17063
|
+
${t("plan.id_ignored")}`;
|
|
17064
|
+
}
|
|
17065
|
+
if (existing) {
|
|
17066
|
+
output += `
|
|
17067
|
+
${t("plan.existing_fresh")}`;
|
|
17068
|
+
}
|
|
16801
17069
|
let displayOut = display;
|
|
16802
17070
|
const taskText = deps.getTaskText(_ctx);
|
|
16803
17071
|
if (taskText) {
|
|
@@ -17117,7 +17385,7 @@ var init_windows_commands = __esm(() => {
|
|
|
17117
17385
|
});
|
|
17118
17386
|
|
|
17119
17387
|
// src/modules/execution/execution-plugin.ts
|
|
17120
|
-
import { platform as
|
|
17388
|
+
import { platform as platform6 } from "os";
|
|
17121
17389
|
function createExecutionPlugin(deps) {
|
|
17122
17390
|
return {
|
|
17123
17391
|
name: "execution",
|
|
@@ -17261,7 +17529,7 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17261
17529
|
deps.stuckDetector.recordToolError(call.name, toolText.slice(0, 300));
|
|
17262
17530
|
}
|
|
17263
17531
|
if (!result.success) {
|
|
17264
|
-
if (call.name === "bash" &&
|
|
17532
|
+
if (call.name === "bash" && platform6() === "win32") {
|
|
17265
17533
|
const cmd = String(call.arguments?.command ?? "");
|
|
17266
17534
|
const forbidden = forbiddenWindowsCommand(cmd);
|
|
17267
17535
|
if (forbidden) {
|
|
@@ -17340,7 +17608,7 @@ var init_execution_plugin = __esm(() => {
|
|
|
17340
17608
|
});
|
|
17341
17609
|
|
|
17342
17610
|
// src/modules/execution/module.ts
|
|
17343
|
-
import { existsSync as
|
|
17611
|
+
import { existsSync as existsSync33, readFileSync as readFileSync17 } from "fs";
|
|
17344
17612
|
import { resolve as resolve19 } from "path";
|
|
17345
17613
|
|
|
17346
17614
|
class ExecutionModule {
|
|
@@ -17433,6 +17701,14 @@ class ExecutionModule {
|
|
|
17433
17701
|
estimatedTokens: 200
|
|
17434
17702
|
};
|
|
17435
17703
|
}
|
|
17704
|
+
getPlanSummary() {
|
|
17705
|
+
if (!this.tracker)
|
|
17706
|
+
return null;
|
|
17707
|
+
const plan = this.tracker.getPlan();
|
|
17708
|
+
const done = plan.steps.filter((s) => s.status === "done").length;
|
|
17709
|
+
const current = this.tracker.getCurrentStepIndex() + 1;
|
|
17710
|
+
return `[${plan.id}] "${plan.title}" ${done}/${plan.steps.length} done, current: step ${current} — continue it (plan show / re-plan), do NOT create a new plan`;
|
|
17711
|
+
}
|
|
17436
17712
|
getToolDefinitions() {
|
|
17437
17713
|
return createPlanToolDefinitions({
|
|
17438
17714
|
store: this.store,
|
|
@@ -17535,7 +17811,7 @@ class ExecutionModule {
|
|
|
17535
17811
|
"poetry.lock",
|
|
17536
17812
|
"requirements.txt"
|
|
17537
17813
|
];
|
|
17538
|
-
const hasLockFile = lockFiles.some((f) =>
|
|
17814
|
+
const hasLockFile = lockFiles.some((f) => existsSync33(resolve19(this.baseDir, f)));
|
|
17539
17815
|
if (!hasLockFile) {
|
|
17540
17816
|
if (contextManager) {
|
|
17541
17817
|
const hints = this.state.depsGateHints.get(step.id) || 0;
|
|
@@ -17555,8 +17831,8 @@ class ExecutionModule {
|
|
|
17555
17831
|
}
|
|
17556
17832
|
if (stepPaths.length === 0)
|
|
17557
17833
|
return;
|
|
17558
|
-
const allExist = stepPaths.every((p) =>
|
|
17559
|
-
const allGone = stepPaths.every((p) => !
|
|
17834
|
+
const allExist = stepPaths.every((p) => existsSync33(resolve19(this.baseDir, p)));
|
|
17835
|
+
const allGone = stepPaths.every((p) => !existsSync33(resolve19(this.baseDir, p)));
|
|
17560
17836
|
const satisfied = step.kind === "delete" ? allGone && !allExist : allExist;
|
|
17561
17837
|
if (!satisfied)
|
|
17562
17838
|
return;
|
|
@@ -17662,11 +17938,11 @@ var init_module = __esm(() => {
|
|
|
17662
17938
|
import {
|
|
17663
17939
|
readFileSync as readFileSync18,
|
|
17664
17940
|
writeFileSync as writeFileSync11,
|
|
17665
|
-
existsSync as
|
|
17941
|
+
existsSync as existsSync34,
|
|
17666
17942
|
readdirSync as readdirSync11,
|
|
17667
17943
|
unlinkSync as unlinkSync4
|
|
17668
17944
|
} from "fs";
|
|
17669
|
-
import { join as
|
|
17945
|
+
import { join as join27 } from "path";
|
|
17670
17946
|
import { homedir as homedir8 } from "os";
|
|
17671
17947
|
|
|
17672
17948
|
class SessionFileEncryptor {
|
|
@@ -17675,7 +17951,7 @@ class SessionFileEncryptor {
|
|
|
17675
17951
|
constructor(config) {
|
|
17676
17952
|
this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
|
|
17677
17953
|
this.encryptor = new ConfigEncryptor({
|
|
17678
|
-
keyPath: config?.keyPath ||
|
|
17954
|
+
keyPath: config?.keyPath || join27(homedir8(), ".mma", ".session-encryption-key")
|
|
17679
17955
|
});
|
|
17680
17956
|
}
|
|
17681
17957
|
isEnabled() {
|
|
@@ -17761,8 +18037,8 @@ class SessionFileEncryptor {
|
|
|
17761
18037
|
return;
|
|
17762
18038
|
const files = readdirSync11(sessionDir);
|
|
17763
18039
|
for (const file of files) {
|
|
17764
|
-
const filePath =
|
|
17765
|
-
if (
|
|
18040
|
+
const filePath = join27(sessionDir, file);
|
|
18041
|
+
if (existsSync34(filePath) && !file.endsWith(".enc")) {
|
|
17766
18042
|
try {
|
|
17767
18043
|
const content = readFileSync18(filePath, "utf8");
|
|
17768
18044
|
const encrypted = this.encryptFileContent(content);
|
|
@@ -17778,7 +18054,7 @@ class SessionFileEncryptor {
|
|
|
17778
18054
|
const files = readdirSync11(sessionDir);
|
|
17779
18055
|
for (const file of files) {
|
|
17780
18056
|
if (file.endsWith(".enc")) {
|
|
17781
|
-
const encFilePath =
|
|
18057
|
+
const encFilePath = join27(sessionDir, file);
|
|
17782
18058
|
const decFilePath = encFilePath.slice(0, -4);
|
|
17783
18059
|
try {
|
|
17784
18060
|
const content = readFileSync18(encFilePath, "utf8");
|
|
@@ -17803,7 +18079,7 @@ var init_session_encryption = __esm(() => {
|
|
|
17803
18079
|
|
|
17804
18080
|
// src/modules/session/store.ts
|
|
17805
18081
|
import {
|
|
17806
|
-
existsSync as
|
|
18082
|
+
existsSync as existsSync35,
|
|
17807
18083
|
mkdirSync as mkdirSync15,
|
|
17808
18084
|
readdirSync as readdirSync12,
|
|
17809
18085
|
readFileSync as readFileSync19,
|
|
@@ -17811,7 +18087,7 @@ import {
|
|
|
17811
18087
|
writeFileSync as writeFileSync12,
|
|
17812
18088
|
appendFileSync as appendFileSync6
|
|
17813
18089
|
} from "fs";
|
|
17814
|
-
import { join as
|
|
18090
|
+
import { join as join28 } from "path";
|
|
17815
18091
|
import { gzipSync } from "zlib";
|
|
17816
18092
|
|
|
17817
18093
|
class SessionStore {
|
|
@@ -17825,7 +18101,7 @@ class SessionStore {
|
|
|
17825
18101
|
}
|
|
17826
18102
|
}
|
|
17827
18103
|
getSessionDir(id) {
|
|
17828
|
-
return
|
|
18104
|
+
return join28(this.baseDir, id);
|
|
17829
18105
|
}
|
|
17830
18106
|
updateEncryption(config) {
|
|
17831
18107
|
if (config?.enabled) {
|
|
@@ -17841,19 +18117,19 @@ class SessionStore {
|
|
|
17841
18117
|
mkdirSync15(this.baseDir, { recursive: true });
|
|
17842
18118
|
}
|
|
17843
18119
|
sessionDir(id) {
|
|
17844
|
-
return
|
|
18120
|
+
return join28(this.baseDir, id);
|
|
17845
18121
|
}
|
|
17846
18122
|
metaPath(id) {
|
|
17847
|
-
return
|
|
18123
|
+
return join28(this.sessionDir(id), "meta.json");
|
|
17848
18124
|
}
|
|
17849
18125
|
historyPath(id) {
|
|
17850
|
-
return
|
|
18126
|
+
return join28(this.sessionDir(id), "history.jsonl");
|
|
17851
18127
|
}
|
|
17852
18128
|
sessionLogPath(id) {
|
|
17853
|
-
return
|
|
18129
|
+
return join28(this.sessionDir(id), "session.jsonl");
|
|
17854
18130
|
}
|
|
17855
18131
|
sessionExists(id) {
|
|
17856
|
-
return
|
|
18132
|
+
return existsSync35(this.metaPath(id));
|
|
17857
18133
|
}
|
|
17858
18134
|
saveMeta(id, meta) {
|
|
17859
18135
|
this._metaCache.set(id, meta);
|
|
@@ -17871,7 +18147,7 @@ class SessionStore {
|
|
|
17871
18147
|
if (cached)
|
|
17872
18148
|
return cached;
|
|
17873
18149
|
const path = this.metaPath(id);
|
|
17874
|
-
if (!
|
|
18150
|
+
if (!existsSync35(path))
|
|
17875
18151
|
return null;
|
|
17876
18152
|
try {
|
|
17877
18153
|
const raw = readFileSync19(path, "utf-8");
|
|
@@ -17903,7 +18179,7 @@ class SessionStore {
|
|
|
17903
18179
|
}
|
|
17904
18180
|
loadHistory(id) {
|
|
17905
18181
|
const path = this.historyPath(id);
|
|
17906
|
-
if (!
|
|
18182
|
+
if (!existsSync35(path))
|
|
17907
18183
|
return [];
|
|
17908
18184
|
try {
|
|
17909
18185
|
const raw = readFileSync19(path, "utf-8");
|
|
@@ -17944,7 +18220,7 @@ class SessionStore {
|
|
|
17944
18220
|
}
|
|
17945
18221
|
loadSessionLog(id) {
|
|
17946
18222
|
const path = this.sessionLogPath(id);
|
|
17947
|
-
if (!
|
|
18223
|
+
if (!existsSync35(path))
|
|
17948
18224
|
return [];
|
|
17949
18225
|
try {
|
|
17950
18226
|
const raw = readFileSync19(path, "utf-8");
|
|
@@ -17972,7 +18248,7 @@ class SessionStore {
|
|
|
17972
18248
|
}
|
|
17973
18249
|
}
|
|
17974
18250
|
listSessions() {
|
|
17975
|
-
if (!
|
|
18251
|
+
if (!existsSync35(this.baseDir))
|
|
17976
18252
|
return [];
|
|
17977
18253
|
const entries = readdirSync12(this.baseDir, { withFileTypes: true });
|
|
17978
18254
|
const sessions = [];
|
|
@@ -17989,7 +18265,7 @@ class SessionStore {
|
|
|
17989
18265
|
deleteSession(id) {
|
|
17990
18266
|
this._metaCache.delete(id);
|
|
17991
18267
|
const dir = this.sessionDir(id);
|
|
17992
|
-
if (
|
|
18268
|
+
if (existsSync35(dir)) {
|
|
17993
18269
|
rmSync2(dir, { recursive: true, force: true });
|
|
17994
18270
|
}
|
|
17995
18271
|
}
|
|
@@ -18001,10 +18277,10 @@ class SessionStore {
|
|
|
18001
18277
|
const updatedAt = new Date(session2.updatedAt);
|
|
18002
18278
|
if (updatedAt < thirtyDaysAgo) {
|
|
18003
18279
|
const historyPath = this.historyPath(session2.id);
|
|
18004
|
-
if (
|
|
18280
|
+
if (existsSync35(historyPath)) {
|
|
18005
18281
|
const content = readFileSync19(historyPath, "utf-8");
|
|
18006
18282
|
const compressed = gzipSync(content);
|
|
18007
|
-
const gzPath =
|
|
18283
|
+
const gzPath = join28(this.baseDir, `${session2.id}.jsonl.gz`);
|
|
18008
18284
|
writeFileSync12(gzPath, compressed);
|
|
18009
18285
|
rmSync2(historyPath);
|
|
18010
18286
|
}
|
|
@@ -18157,7 +18433,7 @@ class SessionManager {
|
|
|
18157
18433
|
}
|
|
18158
18434
|
}
|
|
18159
18435
|
}
|
|
18160
|
-
var
|
|
18436
|
+
var init_manager3 = __esm(() => {
|
|
18161
18437
|
init_i18n();
|
|
18162
18438
|
init_session_isolation();
|
|
18163
18439
|
});
|
|
@@ -18193,7 +18469,7 @@ var init_module2 = __esm(() => {
|
|
|
18193
18469
|
// src/modules/session/index.ts
|
|
18194
18470
|
var init_session2 = __esm(() => {
|
|
18195
18471
|
init_store3();
|
|
18196
|
-
|
|
18472
|
+
init_manager3();
|
|
18197
18473
|
init_module2();
|
|
18198
18474
|
});
|
|
18199
18475
|
|
|
@@ -18214,9 +18490,9 @@ class ProfileCompressor {
|
|
|
18214
18490
|
}
|
|
18215
18491
|
|
|
18216
18492
|
// src/modules/user-profile/profile.ts
|
|
18217
|
-
import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as
|
|
18218
|
-
import { join as
|
|
18219
|
-
import { homedir as homedir9, hostname, platform as
|
|
18493
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync36, mkdirSync as mkdirSync16 } from "fs";
|
|
18494
|
+
import { join as join29 } from "path";
|
|
18495
|
+
import { homedir as homedir9, hostname, platform as platform7, type } from "os";
|
|
18220
18496
|
import { env } from "process";
|
|
18221
18497
|
|
|
18222
18498
|
class UserProfile {
|
|
@@ -18228,7 +18504,7 @@ class UserProfile {
|
|
|
18228
18504
|
}
|
|
18229
18505
|
collect() {
|
|
18230
18506
|
this.info = {
|
|
18231
|
-
platform:
|
|
18507
|
+
platform: platform7(),
|
|
18232
18508
|
os: `${type()} ${hostname()}`,
|
|
18233
18509
|
hostname: hostname(),
|
|
18234
18510
|
shell: env.SHELL || env.ComSpec || "unknown",
|
|
@@ -18239,14 +18515,14 @@ class UserProfile {
|
|
|
18239
18515
|
return this.info;
|
|
18240
18516
|
}
|
|
18241
18517
|
save() {
|
|
18242
|
-
if (!
|
|
18518
|
+
if (!existsSync36(this.profileDir)) {
|
|
18243
18519
|
mkdirSync16(this.profileDir, { recursive: true });
|
|
18244
18520
|
}
|
|
18245
|
-
writeFileSync13(
|
|
18521
|
+
writeFileSync13(join29(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
|
|
18246
18522
|
}
|
|
18247
18523
|
load() {
|
|
18248
|
-
const path =
|
|
18249
|
-
if (!
|
|
18524
|
+
const path = join29(this.profileDir, "profile.json");
|
|
18525
|
+
if (!existsSync36(path))
|
|
18250
18526
|
return null;
|
|
18251
18527
|
try {
|
|
18252
18528
|
const data = JSON.parse(readFileSync20(path, "utf-8"));
|
|
@@ -18284,12 +18560,12 @@ class UserProfile {
|
|
|
18284
18560
|
var init_profile = () => {};
|
|
18285
18561
|
|
|
18286
18562
|
// src/modules/skills/loader.ts
|
|
18287
|
-
import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as
|
|
18288
|
-
import { join as
|
|
18563
|
+
import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as existsSync37, statSync as statSync6 } from "fs";
|
|
18564
|
+
import { join as join30 } from "path";
|
|
18289
18565
|
|
|
18290
18566
|
class SkillsLoader {
|
|
18291
18567
|
loadFromDir(dirPath) {
|
|
18292
|
-
if (!
|
|
18568
|
+
if (!existsSync37(dirPath))
|
|
18293
18569
|
return [];
|
|
18294
18570
|
const skills = [];
|
|
18295
18571
|
this.scanDir(dirPath, skills);
|
|
@@ -18298,7 +18574,7 @@ class SkillsLoader {
|
|
|
18298
18574
|
scanDir(dirPath, skills) {
|
|
18299
18575
|
const entries = readdirSync13(dirPath);
|
|
18300
18576
|
for (const entry of entries) {
|
|
18301
|
-
const fullPath =
|
|
18577
|
+
const fullPath = join30(dirPath, entry);
|
|
18302
18578
|
const stat = statSync6(fullPath);
|
|
18303
18579
|
if (stat.isDirectory()) {
|
|
18304
18580
|
this.scanDir(fullPath, skills);
|
|
@@ -18541,45 +18817,10 @@ var init_browser2 = __esm(() => {
|
|
|
18541
18817
|
init_types();
|
|
18542
18818
|
});
|
|
18543
18819
|
|
|
18544
|
-
// src/modules/lsp/command.ts
|
|
18545
|
-
import { delimiter, join as join30 } from "path";
|
|
18546
|
-
import { existsSync as existsSync36 } from "fs";
|
|
18547
|
-
import { platform as platform6 } from "os";
|
|
18548
|
-
function resolveSpawnCommand(command, platformName = platform6(), pathEnv = process.env.PATH ?? "") {
|
|
18549
|
-
if (platformName !== "win32")
|
|
18550
|
-
return command;
|
|
18551
|
-
if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
|
|
18552
|
-
return command;
|
|
18553
|
-
}
|
|
18554
|
-
const dirs = pathEnv.split(delimiter).filter(Boolean);
|
|
18555
|
-
for (const dir of dirs) {
|
|
18556
|
-
for (const ext of WIN_EXTS) {
|
|
18557
|
-
const candidate = join30(dir, `${command}${ext}`);
|
|
18558
|
-
if (existsSync36(candidate))
|
|
18559
|
-
return `${command}${ext}`;
|
|
18560
|
-
}
|
|
18561
|
-
}
|
|
18562
|
-
return command;
|
|
18563
|
-
}
|
|
18564
|
-
function buildWinCommandLine(command, args) {
|
|
18565
|
-
const quote = (part) => {
|
|
18566
|
-
if (part === "")
|
|
18567
|
-
return '""';
|
|
18568
|
-
if (!/[\s"&|^<>()%!]/.test(part))
|
|
18569
|
-
return part;
|
|
18570
|
-
return `"${part.replace(/"/g, "\\\"")}"`;
|
|
18571
|
-
};
|
|
18572
|
-
return [command, ...args].map(quote).join(" ");
|
|
18573
|
-
}
|
|
18574
|
-
var WIN_EXTS;
|
|
18575
|
-
var init_command = __esm(() => {
|
|
18576
|
-
WIN_EXTS = [".cmd", ".bat", ".exe", ".com"];
|
|
18577
|
-
});
|
|
18578
|
-
|
|
18579
18820
|
// src/modules/lsp/client.ts
|
|
18580
18821
|
import { spawn as spawn6, execSync as execSync2 } from "child_process";
|
|
18581
18822
|
import { resolve as resolve20 } from "path";
|
|
18582
|
-
import { platform as
|
|
18823
|
+
import { platform as platform8 } from "os";
|
|
18583
18824
|
|
|
18584
18825
|
class LspClient {
|
|
18585
18826
|
process = null;
|
|
@@ -18649,7 +18890,7 @@ class LspClient {
|
|
|
18649
18890
|
}
|
|
18650
18891
|
return new Promise((resolve21, reject) => {
|
|
18651
18892
|
const args = config.args ?? [];
|
|
18652
|
-
const isWin =
|
|
18893
|
+
const isWin = platform8() === "win32";
|
|
18653
18894
|
let spawnCommand = resolveSpawnCommand(config.command);
|
|
18654
18895
|
let spawnArgs = args;
|
|
18655
18896
|
const spawnOpts = {
|
|
@@ -18823,18 +19064,70 @@ var init_client2 = __esm(() => {
|
|
|
18823
19064
|
init_command();
|
|
18824
19065
|
});
|
|
18825
19066
|
|
|
19067
|
+
// src/modules/lsp/check-tool.ts
|
|
19068
|
+
import { readdir, stat } from "fs/promises";
|
|
19069
|
+
import { resolve as resolve21, relative as relative2 } from "path";
|
|
19070
|
+
async function collectCheckFiles(resolved, config) {
|
|
19071
|
+
const info = await stat(resolved).catch(() => null);
|
|
19072
|
+
if (!info)
|
|
19073
|
+
return [];
|
|
19074
|
+
if (info.isFile())
|
|
19075
|
+
return [resolved];
|
|
19076
|
+
const out = [];
|
|
19077
|
+
await walkDir(resolved, 0, out, config);
|
|
19078
|
+
return out;
|
|
19079
|
+
}
|
|
19080
|
+
async function walkDir(dir, depth, out, config) {
|
|
19081
|
+
if (depth > MAX_LSP_WALK_DEPTH || out.length >= MAX_LSP_CHECK_FILES)
|
|
19082
|
+
return;
|
|
19083
|
+
const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
19084
|
+
for (const entry of entries) {
|
|
19085
|
+
if (out.length >= MAX_LSP_CHECK_FILES)
|
|
19086
|
+
break;
|
|
19087
|
+
if (entry.isDirectory()) {
|
|
19088
|
+
if (SKIP_DIRS2.has(entry.name))
|
|
19089
|
+
continue;
|
|
19090
|
+
await walkDir(resolve21(dir, entry.name), depth + 1, out, config);
|
|
19091
|
+
} else if (entry.isFile() && getServerForFile(resolve21(dir, entry.name), config)) {
|
|
19092
|
+
out.push(resolve21(dir, entry.name));
|
|
19093
|
+
}
|
|
19094
|
+
}
|
|
19095
|
+
}
|
|
19096
|
+
function formatCheckDiagnostics(items, baseDir) {
|
|
19097
|
+
return items.slice(0, 40).map(({ file, diag }) => {
|
|
19098
|
+
const rel = relative2(baseDir, file).replace(/\\/g, "/");
|
|
19099
|
+
const line = diag.range.start.line + 1;
|
|
19100
|
+
const col = diag.range.start.character + 1;
|
|
19101
|
+
const sev = severityLabels[diag.severity] ?? "unknown";
|
|
19102
|
+
return ` ${rel}(${line},${col}): ${sev}: ${diag.message}`;
|
|
19103
|
+
}).join(`
|
|
19104
|
+
`);
|
|
19105
|
+
}
|
|
19106
|
+
var MAX_LSP_CHECK_FILES = 15, MAX_LSP_WALK_DEPTH = 4, SKIP_DIRS2, severityLabels;
|
|
19107
|
+
var init_check_tool = __esm(() => {
|
|
19108
|
+
init_config();
|
|
19109
|
+
SKIP_DIRS2 = new Set(["node_modules", ".git", ".mma", "dist"]);
|
|
19110
|
+
severityLabels = {
|
|
19111
|
+
1: "error",
|
|
19112
|
+
2: "warning",
|
|
19113
|
+
3: "info",
|
|
19114
|
+
4: "hint"
|
|
19115
|
+
};
|
|
19116
|
+
});
|
|
19117
|
+
|
|
18826
19118
|
// src/modules/lsp/module.ts
|
|
18827
|
-
import { existsSync as
|
|
18828
|
-
import { resolve as
|
|
19119
|
+
import { existsSync as existsSync38 } from "fs";
|
|
19120
|
+
import { resolve as resolve22 } from "path";
|
|
18829
19121
|
|
|
18830
19122
|
class LspModule {
|
|
18831
19123
|
name = "lsp";
|
|
18832
19124
|
config;
|
|
18833
|
-
client
|
|
19125
|
+
client;
|
|
18834
19126
|
failuresByServer = new Map;
|
|
18835
19127
|
disabledServers = new Set;
|
|
18836
|
-
constructor(config) {
|
|
19128
|
+
constructor(config, client) {
|
|
18837
19129
|
this.config = { ...DEFAULT_LSP_CONFIG, ...config };
|
|
19130
|
+
this.client = client ?? new LspClient;
|
|
18838
19131
|
}
|
|
18839
19132
|
isLspDisabled() {
|
|
18840
19133
|
return this.disabledServers.size > 0;
|
|
@@ -18860,8 +19153,8 @@ class LspModule {
|
|
|
18860
19153
|
const filePath = String(call.arguments.path ?? "");
|
|
18861
19154
|
if (!filePath)
|
|
18862
19155
|
return;
|
|
18863
|
-
const fullPath =
|
|
18864
|
-
if (!
|
|
19156
|
+
const fullPath = resolve22(_ctx.baseDir, filePath);
|
|
19157
|
+
if (!existsSync38(fullPath))
|
|
18865
19158
|
return;
|
|
18866
19159
|
const serverConfig = getServerForFile(fullPath, self.config);
|
|
18867
19160
|
if (!serverConfig)
|
|
@@ -18910,6 +19203,110 @@ ${items}`;
|
|
|
18910
19203
|
}
|
|
18911
19204
|
};
|
|
18912
19205
|
}
|
|
19206
|
+
getToolDefinitions() {
|
|
19207
|
+
const self = this;
|
|
19208
|
+
return [
|
|
19209
|
+
{
|
|
19210
|
+
name: "lsp_check",
|
|
19211
|
+
description: 'Run static checks (LSP diagnostics) on a file or directory. For "check for errors" tasks: pass a file to check it, or a directory to check its source files (capped at 15). Returns [LSP errors] / [LSP warnings] for files with a configured LSP server.',
|
|
19212
|
+
tags: ["code", "check"],
|
|
19213
|
+
boundedOutput: true,
|
|
19214
|
+
timeoutMs: 90000,
|
|
19215
|
+
parameters: {
|
|
19216
|
+
type: "object",
|
|
19217
|
+
properties: {
|
|
19218
|
+
path: {
|
|
19219
|
+
type: "string",
|
|
19220
|
+
description: "File or directory to check"
|
|
19221
|
+
}
|
|
19222
|
+
},
|
|
19223
|
+
required: ["path"]
|
|
19224
|
+
},
|
|
19225
|
+
handler: async (ctx, args) => self.runCheck(ctx, args)
|
|
19226
|
+
}
|
|
19227
|
+
];
|
|
19228
|
+
}
|
|
19229
|
+
async runCheck(ctx, args) {
|
|
19230
|
+
if (!this.config.enabled) {
|
|
19231
|
+
return { success: false, output: t("lsp.check_disabled") };
|
|
19232
|
+
}
|
|
19233
|
+
const path = String(args.path ?? "");
|
|
19234
|
+
if (!path)
|
|
19235
|
+
return { success: false, output: t("lsp.check_no_path") };
|
|
19236
|
+
const resolved = safeResolvePath(ctx.baseDir, path);
|
|
19237
|
+
const securityPaths = ctx.config?.security?.paths || DEFAULT_SECURITY_CONFIG.paths;
|
|
19238
|
+
const scopeCheck = isPathInScope(ctx.baseDir, resolved, ctx.scope, securityPaths);
|
|
19239
|
+
if (!scopeCheck.allowed) {
|
|
19240
|
+
return {
|
|
19241
|
+
success: false,
|
|
19242
|
+
output: t("file.path_not_allowed", {
|
|
19243
|
+
path: `${path} — ${scopeCheck.reason}`
|
|
19244
|
+
})
|
|
19245
|
+
};
|
|
19246
|
+
}
|
|
19247
|
+
if (!existsSync38(resolved)) {
|
|
19248
|
+
return { success: false, output: t("lsp.check_notfound", { path }) };
|
|
19249
|
+
}
|
|
19250
|
+
const files = await collectCheckFiles(resolved, this.config);
|
|
19251
|
+
const errors = [];
|
|
19252
|
+
const warnings = [];
|
|
19253
|
+
const notes = [];
|
|
19254
|
+
let checked = 0;
|
|
19255
|
+
for (const file of files) {
|
|
19256
|
+
const serverConfig = getServerForFile(file, this.config);
|
|
19257
|
+
if (!serverConfig)
|
|
19258
|
+
continue;
|
|
19259
|
+
const key = this.serverKey(serverConfig);
|
|
19260
|
+
if (this.disabledServers.has(key))
|
|
19261
|
+
continue;
|
|
19262
|
+
const projectRoot = findProjectRoot(file, ctx.baseDir, serverConfig.workspaceMarkers ?? []);
|
|
19263
|
+
try {
|
|
19264
|
+
const diags = await this.client.checkFile(file, ctx.baseDir, serverConfig, projectRoot);
|
|
19265
|
+
this.failuresByServer.set(key, 0);
|
|
19266
|
+
checked++;
|
|
19267
|
+
for (const d of diags) {
|
|
19268
|
+
if (d.severity === 1)
|
|
19269
|
+
errors.push({ file, diag: d });
|
|
19270
|
+
else if (d.severity === 2)
|
|
19271
|
+
warnings.push({ file, diag: d });
|
|
19272
|
+
}
|
|
19273
|
+
} catch (e) {
|
|
19274
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
19275
|
+
const failures = (this.failuresByServer.get(key) ?? 0) + 1;
|
|
19276
|
+
this.failuresByServer.set(key, failures);
|
|
19277
|
+
try {
|
|
19278
|
+
ctx.logger?.warn(`LSP check failed for ${file}: ${msg}`);
|
|
19279
|
+
} catch {}
|
|
19280
|
+
if (failures >= MAX_CONSECUTIVE_LSP_FAILURES) {
|
|
19281
|
+
this.disabledServers.add(key);
|
|
19282
|
+
notes.push(`[LSP disabled: ${t("lsp.unavailable")}]`);
|
|
19283
|
+
} else {
|
|
19284
|
+
notes.push(`[LSP check failed for ${file}: ${msg}]`);
|
|
19285
|
+
}
|
|
19286
|
+
}
|
|
19287
|
+
}
|
|
19288
|
+
const lines = [];
|
|
19289
|
+
if (errors.length > 0) {
|
|
19290
|
+
lines.push(`[LSP errors] (${errors.length}):`);
|
|
19291
|
+
lines.push(formatCheckDiagnostics(errors, ctx.baseDir));
|
|
19292
|
+
}
|
|
19293
|
+
if (warnings.length > 0) {
|
|
19294
|
+
lines.push(`[LSP warnings] (${warnings.length}):`);
|
|
19295
|
+
lines.push(formatCheckDiagnostics(warnings, ctx.baseDir));
|
|
19296
|
+
}
|
|
19297
|
+
if (checked > 0 && errors.length === 0 && warnings.length === 0) {
|
|
19298
|
+
lines.push(t("lsp.check_clean", { count: String(checked) }));
|
|
19299
|
+
}
|
|
19300
|
+
lines.push(...notes);
|
|
19301
|
+
if (lines.length === 0) {
|
|
19302
|
+
return {
|
|
19303
|
+
success: true,
|
|
19304
|
+
output: t("lsp.check_clean", { count: String(checked) })
|
|
19305
|
+
};
|
|
19306
|
+
}
|
|
19307
|
+
return { success: errors.length === 0, output: lines.join(`
|
|
19308
|
+
`) };
|
|
19309
|
+
}
|
|
18913
19310
|
}
|
|
18914
19311
|
function formatDiagnostics(diagnostics, filePath) {
|
|
18915
19312
|
const filename = filePath.replace(/\\/g, "/").split("/").pop() ?? filePath;
|
|
@@ -18921,18 +19318,16 @@ function formatDiagnostics(diagnostics, filePath) {
|
|
|
18921
19318
|
}).join(`
|
|
18922
19319
|
`);
|
|
18923
19320
|
}
|
|
18924
|
-
var
|
|
19321
|
+
var MAX_CONSECUTIVE_LSP_FAILURES = 3;
|
|
18925
19322
|
var init_module5 = __esm(() => {
|
|
18926
19323
|
init_client2();
|
|
18927
19324
|
init_config();
|
|
18928
19325
|
init_project_root();
|
|
19326
|
+
init_path_validator();
|
|
19327
|
+
init_security();
|
|
19328
|
+
init_path_utils();
|
|
18929
19329
|
init_i18n();
|
|
18930
|
-
|
|
18931
|
-
1: "error",
|
|
18932
|
-
2: "warning",
|
|
18933
|
-
3: "info",
|
|
18934
|
-
4: "hint"
|
|
18935
|
-
};
|
|
19330
|
+
init_check_tool();
|
|
18936
19331
|
});
|
|
18937
19332
|
|
|
18938
19333
|
// src/modules/lsp/index.ts
|
|
@@ -18943,8 +19338,8 @@ var init_lsp = __esm(() => {
|
|
|
18943
19338
|
});
|
|
18944
19339
|
|
|
18945
19340
|
// src/modules/indexer/walker.ts
|
|
18946
|
-
import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as
|
|
18947
|
-
import { join as join31, relative as
|
|
19341
|
+
import { readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync7, existsSync as existsSync39, watch } from "fs";
|
|
19342
|
+
import { join as join31, relative as relative3, extname as extname5 } from "path";
|
|
18948
19343
|
|
|
18949
19344
|
class Indexer {
|
|
18950
19345
|
baseDir;
|
|
@@ -18970,8 +19365,8 @@ class Indexer {
|
|
|
18970
19365
|
const files = [];
|
|
18971
19366
|
let totalSize = 0;
|
|
18972
19367
|
let count = 0;
|
|
18973
|
-
const
|
|
18974
|
-
if (!
|
|
19368
|
+
const walkDir2 = (dir) => {
|
|
19369
|
+
if (!existsSync39(dir))
|
|
18975
19370
|
return;
|
|
18976
19371
|
let entries;
|
|
18977
19372
|
try {
|
|
@@ -18983,26 +19378,26 @@ class Indexer {
|
|
|
18983
19378
|
if (count >= this.MAX_FILES)
|
|
18984
19379
|
return;
|
|
18985
19380
|
const fullPath = join31(dir, entry);
|
|
18986
|
-
const relPath =
|
|
18987
|
-
const
|
|
18988
|
-
if (
|
|
19381
|
+
const relPath = relative3(this.baseDir, fullPath);
|
|
19382
|
+
const stat2 = statSync7(fullPath);
|
|
19383
|
+
if (stat2.isDirectory()) {
|
|
18989
19384
|
if (!IGNORE_DIRS.has(entry)) {
|
|
18990
|
-
|
|
19385
|
+
walkDir2(fullPath);
|
|
18991
19386
|
}
|
|
18992
|
-
} else if (
|
|
19387
|
+
} else if (stat2.isFile()) {
|
|
18993
19388
|
const ext = extname5(entry).toLowerCase();
|
|
18994
19389
|
const language = LANGUAGES[ext];
|
|
18995
19390
|
if (language) {
|
|
18996
19391
|
const content = readFileSync22(fullPath, "utf-8");
|
|
18997
19392
|
const exports = this.extractExports(content, language);
|
|
18998
|
-
files.push({ path: relPath, language, exports, size:
|
|
18999
|
-
totalSize +=
|
|
19393
|
+
files.push({ path: relPath, language, exports, size: stat2.size });
|
|
19394
|
+
totalSize += stat2.size;
|
|
19000
19395
|
count++;
|
|
19001
19396
|
}
|
|
19002
19397
|
}
|
|
19003
19398
|
}
|
|
19004
19399
|
};
|
|
19005
|
-
|
|
19400
|
+
walkDir2(this.baseDir);
|
|
19006
19401
|
return { files, totalSize };
|
|
19007
19402
|
}
|
|
19008
19403
|
extractExports(content, language) {
|
|
@@ -19045,7 +19440,7 @@ var init_walker = __esm(() => {
|
|
|
19045
19440
|
});
|
|
19046
19441
|
|
|
19047
19442
|
// src/modules/indexer/cache.ts
|
|
19048
|
-
import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as
|
|
19443
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync40, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
|
|
19049
19444
|
import { join as join32 } from "path";
|
|
19050
19445
|
|
|
19051
19446
|
class IndexCache {
|
|
@@ -19057,7 +19452,7 @@ class IndexCache {
|
|
|
19057
19452
|
load() {
|
|
19058
19453
|
if (this.cache)
|
|
19059
19454
|
return this.cache;
|
|
19060
|
-
if (!
|
|
19455
|
+
if (!existsSync40(this.cachePath))
|
|
19061
19456
|
return null;
|
|
19062
19457
|
try {
|
|
19063
19458
|
this.cache = JSON.parse(readFileSync23(this.cachePath, "utf-8"));
|
|
@@ -19069,13 +19464,13 @@ class IndexCache {
|
|
|
19069
19464
|
save(result) {
|
|
19070
19465
|
this.cache = result;
|
|
19071
19466
|
const dir = join32(this.cachePath, "..");
|
|
19072
|
-
if (!
|
|
19467
|
+
if (!existsSync40(dir))
|
|
19073
19468
|
mkdirSync17(dir, { recursive: true });
|
|
19074
19469
|
writeFileSync14(this.cachePath, JSON.stringify(result), "utf-8");
|
|
19075
19470
|
}
|
|
19076
19471
|
invalidate() {
|
|
19077
19472
|
this.cache = null;
|
|
19078
|
-
if (
|
|
19473
|
+
if (existsSync40(this.cachePath)) {
|
|
19079
19474
|
try {
|
|
19080
19475
|
rmSync3(this.cachePath);
|
|
19081
19476
|
} catch {}
|
|
@@ -19085,11 +19480,11 @@ class IndexCache {
|
|
|
19085
19480
|
var init_cache = () => {};
|
|
19086
19481
|
|
|
19087
19482
|
// src/modules/indexer/project-profile.ts
|
|
19088
|
-
import { readFileSync as readFileSync24, existsSync as
|
|
19483
|
+
import { readFileSync as readFileSync24, existsSync as existsSync41 } from "fs";
|
|
19089
19484
|
import { join as join33 } from "path";
|
|
19090
19485
|
function detectManifest(baseDir) {
|
|
19091
19486
|
for (const manifest of MANIFEST_ORDER) {
|
|
19092
|
-
if (
|
|
19487
|
+
if (existsSync41(join33(baseDir, manifest)))
|
|
19093
19488
|
return manifest;
|
|
19094
19489
|
}
|
|
19095
19490
|
return null;
|
|
@@ -19736,6 +20131,29 @@ var init_module8 = __esm(() => {
|
|
|
19736
20131
|
MEMORY_MD_FILES = ["errors", "conventions", "decisions", "facts"];
|
|
19737
20132
|
});
|
|
19738
20133
|
|
|
20134
|
+
// src/core/version.ts
|
|
20135
|
+
import { existsSync as existsSync42, readFileSync as readFileSync25 } from "fs";
|
|
20136
|
+
import { join as join35, dirname as dirname13 } from "path";
|
|
20137
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20138
|
+
function readMmaVersion() {
|
|
20139
|
+
const here = dirname13(fileURLToPath2(import.meta.url));
|
|
20140
|
+
const candidates = [
|
|
20141
|
+
join35(here, "..", "..", "package.json"),
|
|
20142
|
+
join35(here, "..", "package.json")
|
|
20143
|
+
];
|
|
20144
|
+
for (const p of candidates) {
|
|
20145
|
+
if (existsSync42(p)) {
|
|
20146
|
+
try {
|
|
20147
|
+
const raw = JSON.parse(readFileSync25(p, "utf8"));
|
|
20148
|
+
if (raw.version)
|
|
20149
|
+
return raw.version;
|
|
20150
|
+
} catch {}
|
|
20151
|
+
}
|
|
20152
|
+
}
|
|
20153
|
+
return "0.0.0";
|
|
20154
|
+
}
|
|
20155
|
+
var init_version = () => {};
|
|
20156
|
+
|
|
19739
20157
|
// src/core/bootstrap.ts
|
|
19740
20158
|
var exports_bootstrap = {};
|
|
19741
20159
|
__export(exports_bootstrap, {
|
|
@@ -19743,8 +20161,8 @@ __export(exports_bootstrap, {
|
|
|
19743
20161
|
bootstrap: () => bootstrap
|
|
19744
20162
|
});
|
|
19745
20163
|
import { homedir as homedir11 } from "os";
|
|
19746
|
-
import { join as
|
|
19747
|
-
import { existsSync as
|
|
20164
|
+
import { join as join36, resolve as resolve23 } from "path";
|
|
20165
|
+
import { existsSync as existsSync43, readFileSync as readFileSync26, writeFileSync as writeFileSync15 } from "fs";
|
|
19748
20166
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
19749
20167
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
19750
20168
|
const isWin = profileCompressed.toLowerCase().includes("win32");
|
|
@@ -19757,7 +20175,7 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
19757
20175
|
lines.push(`Windows (PowerShell): use list_dir/read_file/delete_file/create_dir tools instead of dir/type/del/mkdir. No PowerShell cmdlets (Get-Content, Select-Object, Write-Output), no head/tail/grep/cat. Use forward slashes in paths. CWD: ${baseDir}`);
|
|
19758
20176
|
}
|
|
19759
20177
|
lines.push(`Runtime: Bun is available — run TypeScript directly with "bun <file.ts>" and tests with "bun test" (no tsx/ts-node/npm install needed for that).`);
|
|
19760
|
-
lines.push(`Bash: use "workdir" param instead of "cd dir && cmd". One command per call. Long-running processes: pass "background: true" (id immediately), otherwise auto-backgrounded after a few seconds — check with process_log.`, `DEVELOPMENT RULES (strict): 1) install deps BEFORE writing source (npm/pip/cargo, verify lockfile exists; never import uninstalled packages); 2) framework/toolkit init BEFORE app code; 3) follow plan sequentially, after each step verify deliverables exist with real content, then "plan update step=N status=done"; 4) verify work on disk + command output — don't assume success; 5) no premature work (no files/imports for future steps); 6) stuck after 2+ failures: STOP, try a different approach, write files directly, ask the user.`, `PLAN QUALITY: each step = CONCRETE deliverables (exact file paths with extensions, exact packages, exact commands). Vague steps ("Setup the project") forbidden. Cover init → deps → framework → code → verification. 5-8 steps.`);
|
|
20178
|
+
lines.push(`Bash: use "workdir" param instead of "cd dir && cmd". One command per call. Long-running processes: pass "background: true" (id immediately), otherwise auto-backgrounded after a few seconds — check with process_log.`, `DEVELOPMENT RULES (strict): 1) install deps BEFORE writing source (npm/pip/cargo, verify lockfile exists; never import uninstalled packages); 2) framework/toolkit init BEFORE app code; 3) follow plan sequentially, after each step verify deliverables exist with real content, then "plan update step=N status=done"; 4) verify work on disk + command output — don't assume success; 5) no premature work (no files/imports for future steps); 6) stuck after 2+ failures: STOP, try a different approach, write files directly, ask the user.`, `PLAN QUALITY: each step = CONCRETE deliverables (exact file paths with extensions, exact packages, exact commands). Vague steps ("Setup the project") forbidden. Cover init → deps → framework → code → verification. 5-8 steps.`, `For "check/fix errors" tasks, each verification step must name the exact command that proves the errors are gone — "bun run build", "bun test", or the "lsp_check" tool — and the step is done only after that check reports clean.`);
|
|
19761
20179
|
if (config.autoPlan) {
|
|
19762
20180
|
lines.push(`Plan rule (MANDATORY): any task creating files, installing packages, or requiring multiple actions MUST create a plan with the "plan" tool BEFORE starting. Each step = a concrete deliverable.`);
|
|
19763
20181
|
}
|
|
@@ -19770,8 +20188,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
19770
20188
|
`);
|
|
19771
20189
|
}
|
|
19772
20190
|
async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
19773
|
-
const dir = configDir ||
|
|
19774
|
-
const projectConfigPath = projectDir ?
|
|
20191
|
+
const dir = configDir || join36(homedir11(), ".mma");
|
|
20192
|
+
const projectConfigPath = projectDir ? join36(projectDir, ".mmrc") : join36(process.cwd(), ".mmrc");
|
|
19775
20193
|
const config = loadConfig({ configDir: dir, projectConfigPath });
|
|
19776
20194
|
setLocale(config.locale);
|
|
19777
20195
|
try {
|
|
@@ -19781,7 +20199,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19781
20199
|
}
|
|
19782
20200
|
} catch {}
|
|
19783
20201
|
const logger = new Logger(config.logLevel);
|
|
19784
|
-
logger.setLogDir(
|
|
20202
|
+
logger.setLogDir(join36(dir, "logs"));
|
|
19785
20203
|
logger.debug("MMA bootstrap", {
|
|
19786
20204
|
version: config.version,
|
|
19787
20205
|
model: config.model
|
|
@@ -19803,7 +20221,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19803
20221
|
logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
|
|
19804
20222
|
}
|
|
19805
20223
|
}
|
|
19806
|
-
const profile = new UserProfile(
|
|
20224
|
+
const profile = new UserProfile(join36(dir));
|
|
19807
20225
|
profile.load() || profile.collect();
|
|
19808
20226
|
profile.save();
|
|
19809
20227
|
const llmProvider = new OpenAICompatProvider({
|
|
@@ -19814,8 +20232,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19814
20232
|
retry: config.retry,
|
|
19815
20233
|
rateLimits: config.security?.rateLimits
|
|
19816
20234
|
});
|
|
19817
|
-
const baseDir = projectDir ?
|
|
19818
|
-
const projectMapCacheDir =
|
|
20235
|
+
const baseDir = projectDir ? resolve23(projectDir) : process.cwd();
|
|
20236
|
+
const projectMapCacheDir = join36(baseDir, ".mma");
|
|
19819
20237
|
const indexerModule = new IndexerModule({
|
|
19820
20238
|
baseDir,
|
|
19821
20239
|
cacheDir: projectMapCacheDir
|
|
@@ -19826,9 +20244,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19826
20244
|
logger.warn(`Project indexing failed: ${err.message}`);
|
|
19827
20245
|
}
|
|
19828
20246
|
const skillsLoader = new SkillsLoader;
|
|
19829
|
-
const builtinDir =
|
|
19830
|
-
const globalDir =
|
|
19831
|
-
const projectSkillsDir =
|
|
20247
|
+
const builtinDir = join36(import.meta.dirname, "skills", "builtin");
|
|
20248
|
+
const globalDir = join36(homedir11(), ".agents", "skills");
|
|
20249
|
+
const projectSkillsDir = join36(baseDir, ".mma", "skills");
|
|
19832
20250
|
const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
|
|
19833
20251
|
const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
|
|
19834
20252
|
const skillsModule = new SkillsModule(availableSkills, skillsBudget);
|
|
@@ -19842,11 +20260,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19842
20260
|
essential: true,
|
|
19843
20261
|
estimatedTokens: Math.ceil(systemInfoContent.length / 4)
|
|
19844
20262
|
};
|
|
19845
|
-
const agentsMdGlobal =
|
|
19846
|
-
if (!
|
|
20263
|
+
const agentsMdGlobal = join36(dir, "AGENTS.md");
|
|
20264
|
+
if (!existsSync43(agentsMdGlobal)) {
|
|
19847
20265
|
writeFileSync15(agentsMdGlobal, "", "utf-8");
|
|
19848
20266
|
}
|
|
19849
|
-
const sessionDir =
|
|
20267
|
+
const sessionDir = join36(dir, "sessions");
|
|
19850
20268
|
const sessionStore = new SessionStore(sessionDir);
|
|
19851
20269
|
sessionStore.init();
|
|
19852
20270
|
const sessionManager = new SessionManager(sessionStore, {
|
|
@@ -19913,7 +20331,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19913
20331
|
const mcpModule = new MCPModule(config);
|
|
19914
20332
|
await mcpModule.initialize();
|
|
19915
20333
|
moduleRegistry.register(mcpModule);
|
|
19916
|
-
const memoryStore = new MemoryStore(
|
|
20334
|
+
const memoryStore = new MemoryStore(join36(dir, "memory"));
|
|
19917
20335
|
const memoryModule = new MemoryModule(memoryStore);
|
|
19918
20336
|
moduleRegistry.register(memoryModule);
|
|
19919
20337
|
if (config.browser.enabled) {
|
|
@@ -19964,10 +20382,17 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19964
20382
|
pluginManager.register(plugin);
|
|
19965
20383
|
pluginManager.register(plugin2);
|
|
19966
20384
|
const pluginLoader = new PluginLoader;
|
|
19967
|
-
const globalPluginsDir =
|
|
19968
|
-
const projectPluginsDir =
|
|
19969
|
-
|
|
19970
|
-
pluginLoader.loadFromDir(
|
|
20385
|
+
const globalPluginsDir = join36(homedir11(), ".mma", "plugins");
|
|
20386
|
+
const projectPluginsDir = join36(baseDir, ".mma", "plugins");
|
|
20387
|
+
const mmaVersion = readMmaVersion();
|
|
20388
|
+
pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger, {
|
|
20389
|
+
source: "global",
|
|
20390
|
+
mmaVersion
|
|
20391
|
+
});
|
|
20392
|
+
pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger, {
|
|
20393
|
+
source: "project",
|
|
20394
|
+
mmaVersion
|
|
20395
|
+
});
|
|
19971
20396
|
contextManager.onCompact = (summary) => {
|
|
19972
20397
|
const meta = sessionManager.getActiveMeta();
|
|
19973
20398
|
if (!meta || !config.session.autoSave)
|
|
@@ -19979,17 +20404,18 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
19979
20404
|
timestamp: new Date().toISOString()
|
|
19980
20405
|
});
|
|
19981
20406
|
};
|
|
20407
|
+
contextManager.setPlanSummaryProvider(() => execModule.getPlanSummary());
|
|
19982
20408
|
const agentsMdBlocks = [];
|
|
19983
20409
|
const skipAgentsMd = noAgentsMd === true;
|
|
19984
20410
|
if (!skipAgentsMd) {
|
|
19985
20411
|
const agentsMdCandidates = [
|
|
19986
|
-
|
|
19987
|
-
|
|
19988
|
-
|
|
20412
|
+
join36(baseDir, "AGENTS.md"),
|
|
20413
|
+
join36(baseDir, ".mma", "AGENTS.md"),
|
|
20414
|
+
join36(dir, "AGENTS.md")
|
|
19989
20415
|
];
|
|
19990
20416
|
for (const p of agentsMdCandidates) {
|
|
19991
|
-
if (
|
|
19992
|
-
const content =
|
|
20417
|
+
if (existsSync43(p)) {
|
|
20418
|
+
const content = readFileSync26(p, "utf-8").trim();
|
|
19993
20419
|
if (content) {
|
|
19994
20420
|
agentsMdBlocks.push({
|
|
19995
20421
|
content,
|
|
@@ -20053,6 +20479,7 @@ var init_bootstrap = __esm(() => {
|
|
|
20053
20479
|
init_openai_compat();
|
|
20054
20480
|
init_tools();
|
|
20055
20481
|
init_executor();
|
|
20482
|
+
init_manager2();
|
|
20056
20483
|
init_loader();
|
|
20057
20484
|
init_lint_on_write();
|
|
20058
20485
|
init_notify();
|
|
@@ -20071,6 +20498,7 @@ var init_bootstrap = __esm(() => {
|
|
|
20071
20498
|
init_store2();
|
|
20072
20499
|
init_i18n();
|
|
20073
20500
|
init_agent();
|
|
20501
|
+
init_version();
|
|
20074
20502
|
});
|
|
20075
20503
|
|
|
20076
20504
|
// node_modules/ansi-regex/index.js
|
|
@@ -20621,10 +21049,10 @@ function menuList(items) {
|
|
|
20621
21049
|
console.log(l);
|
|
20622
21050
|
}
|
|
20623
21051
|
function ask(rl, question, defaultValue) {
|
|
20624
|
-
return new Promise((
|
|
21052
|
+
return new Promise((resolve24) => {
|
|
20625
21053
|
const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
|
|
20626
21054
|
rl.question(prompt, (answer) => {
|
|
20627
|
-
|
|
21055
|
+
resolve24(answer.trim() || defaultValue || "");
|
|
20628
21056
|
});
|
|
20629
21057
|
});
|
|
20630
21058
|
}
|
|
@@ -20843,20 +21271,20 @@ __export(exports_manifest, {
|
|
|
20843
21271
|
getCertMark: () => getCertMark,
|
|
20844
21272
|
MANIFEST_PATH: () => MANIFEST_PATH
|
|
20845
21273
|
});
|
|
20846
|
-
import { existsSync as
|
|
21274
|
+
import { existsSync as existsSync44, readFileSync as readFileSync27, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
20847
21275
|
import { homedir as homedir13 } from "os";
|
|
20848
|
-
import { join as
|
|
21276
|
+
import { join as join38 } from "path";
|
|
20849
21277
|
function readManifest(path = MANIFEST_PATH) {
|
|
20850
21278
|
try {
|
|
20851
|
-
if (
|
|
20852
|
-
const raw = JSON.parse(
|
|
21279
|
+
if (existsSync44(path)) {
|
|
21280
|
+
const raw = JSON.parse(readFileSync27(path, "utf-8"));
|
|
20853
21281
|
return { version: 1, certifications: raw.certifications ?? [] };
|
|
20854
21282
|
}
|
|
20855
21283
|
} catch {}
|
|
20856
21284
|
return { version: 1, certifications: [] };
|
|
20857
21285
|
}
|
|
20858
21286
|
function saveManifest(m, path = MANIFEST_PATH) {
|
|
20859
|
-
mkdirSync18(
|
|
21287
|
+
mkdirSync18(join38(homedir13(), ".mma"), { recursive: true });
|
|
20860
21288
|
writeFileSync16(path, JSON.stringify(m, null, 2), "utf-8");
|
|
20861
21289
|
}
|
|
20862
21290
|
function upsertCertification(entry, path = MANIFEST_PATH) {
|
|
@@ -20891,7 +21319,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
|
|
|
20891
21319
|
}
|
|
20892
21320
|
var MANIFEST_PATH;
|
|
20893
21321
|
var init_manifest = __esm(() => {
|
|
20894
|
-
MANIFEST_PATH =
|
|
21322
|
+
MANIFEST_PATH = join38(homedir13(), ".mma", "certifications.json");
|
|
20895
21323
|
});
|
|
20896
21324
|
|
|
20897
21325
|
// node_modules/yaml/dist/nodes/identity.js
|
|
@@ -28014,8 +28442,8 @@ var init_scenarios = __esm(() => {
|
|
|
28014
28442
|
});
|
|
28015
28443
|
|
|
28016
28444
|
// src/modules/certification/loader.ts
|
|
28017
|
-
import { existsSync as
|
|
28018
|
-
import { join as
|
|
28445
|
+
import { existsSync as existsSync45, readdirSync as readdirSync15, readFileSync as readFileSync28 } from "fs";
|
|
28446
|
+
import { join as join39 } from "path";
|
|
28019
28447
|
function validateScenario(s) {
|
|
28020
28448
|
const errors2 = [];
|
|
28021
28449
|
const isSkip = s.mode === "skip";
|
|
@@ -28064,12 +28492,12 @@ function loadScenarios(userDir) {
|
|
|
28064
28492
|
else
|
|
28065
28493
|
scenarios.push(s);
|
|
28066
28494
|
}
|
|
28067
|
-
if (userDir &&
|
|
28495
|
+
if (userDir && existsSync45(userDir)) {
|
|
28068
28496
|
for (const file of readdirSync15(userDir)) {
|
|
28069
28497
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
|
|
28070
28498
|
continue;
|
|
28071
28499
|
try {
|
|
28072
|
-
const raw =
|
|
28500
|
+
const raw = readFileSync28(join39(userDir, file), "utf-8");
|
|
28073
28501
|
const data = $parse(raw);
|
|
28074
28502
|
const parsed = normalizeScenario(data, file);
|
|
28075
28503
|
const errs = validateScenario(parsed);
|
|
@@ -28122,8 +28550,8 @@ var init_loader3 = __esm(() => {
|
|
|
28122
28550
|
});
|
|
28123
28551
|
|
|
28124
28552
|
// src/modules/certification/fact-checker.ts
|
|
28125
|
-
import { existsSync as
|
|
28126
|
-
import { join as
|
|
28553
|
+
import { existsSync as existsSync46, readFileSync as readFileSync29, statSync as statSync8 } from "fs";
|
|
28554
|
+
import { join as join40 } from "path";
|
|
28127
28555
|
function checkSandbox(sandboxDir, checks, exitCode, output) {
|
|
28128
28556
|
const failures = [];
|
|
28129
28557
|
for (const check of checks) {
|
|
@@ -28140,16 +28568,16 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
28140
28568
|
case "outputContains":
|
|
28141
28569
|
return output.includes(check.text);
|
|
28142
28570
|
case "fileExists":
|
|
28143
|
-
return isFile(
|
|
28571
|
+
return isFile(join40(sandboxDir, check.path));
|
|
28144
28572
|
case "fileNotExists":
|
|
28145
|
-
return !
|
|
28573
|
+
return !existsSync46(join40(sandboxDir, check.path));
|
|
28146
28574
|
case "dirExists":
|
|
28147
|
-
return isDir(
|
|
28575
|
+
return isDir(join40(sandboxDir, check.path));
|
|
28148
28576
|
case "fileContent": {
|
|
28149
|
-
const abs =
|
|
28577
|
+
const abs = join40(sandboxDir, check.path);
|
|
28150
28578
|
if (!isFile(abs))
|
|
28151
28579
|
return false;
|
|
28152
|
-
const content =
|
|
28580
|
+
const content = readFileSync29(abs, "utf-8");
|
|
28153
28581
|
if (check.contains !== undefined)
|
|
28154
28582
|
return content.includes(check.contains);
|
|
28155
28583
|
if (check.equals !== undefined)
|
|
@@ -28157,10 +28585,10 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
28157
28585
|
return false;
|
|
28158
28586
|
}
|
|
28159
28587
|
case "fileRegex": {
|
|
28160
|
-
const abs =
|
|
28588
|
+
const abs = join40(sandboxDir, check.path);
|
|
28161
28589
|
if (!isFile(abs))
|
|
28162
28590
|
return false;
|
|
28163
|
-
return new RegExp(check.pattern).test(
|
|
28591
|
+
return new RegExp(check.pattern).test(readFileSync29(abs, "utf-8"));
|
|
28164
28592
|
}
|
|
28165
28593
|
default:
|
|
28166
28594
|
return false;
|
|
@@ -28168,14 +28596,14 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
28168
28596
|
}
|
|
28169
28597
|
function isFile(p) {
|
|
28170
28598
|
try {
|
|
28171
|
-
return
|
|
28599
|
+
return existsSync46(p) && statSync8(p).isFile();
|
|
28172
28600
|
} catch {
|
|
28173
28601
|
return false;
|
|
28174
28602
|
}
|
|
28175
28603
|
}
|
|
28176
28604
|
function isDir(p) {
|
|
28177
28605
|
try {
|
|
28178
|
-
return
|
|
28606
|
+
return existsSync46(p) && statSync8(p).isDirectory();
|
|
28179
28607
|
} catch {
|
|
28180
28608
|
return false;
|
|
28181
28609
|
}
|
|
@@ -28206,9 +28634,9 @@ var init_fact_checker = () => {};
|
|
|
28206
28634
|
|
|
28207
28635
|
// src/modules/certification/runner.ts
|
|
28208
28636
|
import { spawn as spawn7 } from "child_process";
|
|
28209
|
-
import { existsSync as
|
|
28210
|
-
import { platform as
|
|
28211
|
-
import { join as
|
|
28637
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
|
|
28638
|
+
import { platform as platform9 } from "os";
|
|
28639
|
+
import { join as join41, resolve as resolve24, dirname as dirname14 } from "path";
|
|
28212
28640
|
async function runScenario(scenario, opts) {
|
|
28213
28641
|
if (scenario.mode === "skip") {
|
|
28214
28642
|
return {
|
|
@@ -28221,13 +28649,13 @@ async function runScenario(scenario, opts) {
|
|
|
28221
28649
|
}
|
|
28222
28650
|
const reps = scenario.reps ?? opts.defaultReps;
|
|
28223
28651
|
const threshold = Math.min(scenario.passThreshold ?? opts.defaultThreshold, reps);
|
|
28224
|
-
const runner = opts.runner ??
|
|
28652
|
+
const runner = opts.runner ?? defaultRunner2;
|
|
28225
28653
|
const timeoutMs = opts.timeoutMs ?? 120000;
|
|
28226
28654
|
const entryPoint = resolveMmaEntry(opts.mmaRoot);
|
|
28227
28655
|
let passed = 0;
|
|
28228
28656
|
let firstError;
|
|
28229
28657
|
for (let i = 1;i <= reps; i++) {
|
|
28230
|
-
const sandbox =
|
|
28658
|
+
const sandbox = join41(opts.sandboxBase, `run-${scenario.id}-${i}`);
|
|
28231
28659
|
let failures = [];
|
|
28232
28660
|
let exitCode = -1;
|
|
28233
28661
|
let output = "";
|
|
@@ -28288,28 +28716,28 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
|
|
|
28288
28716
|
rmSync4(sandbox, { recursive: true, force: true });
|
|
28289
28717
|
mkdirSync19(sandbox, { recursive: true });
|
|
28290
28718
|
for (const f of scenario.fixtures ?? []) {
|
|
28291
|
-
const src =
|
|
28292
|
-
if (!
|
|
28719
|
+
const src = join41(mmaRoot, f.source);
|
|
28720
|
+
if (!existsSync47(src)) {
|
|
28293
28721
|
throw new Error(`fixture missing: ${f.source}`);
|
|
28294
28722
|
}
|
|
28295
|
-
const dest =
|
|
28296
|
-
mkdirSync19(
|
|
28723
|
+
const dest = join41(sandbox, f.dest);
|
|
28724
|
+
mkdirSync19(dirname14(dest), { recursive: true });
|
|
28297
28725
|
cpSync2(src, dest);
|
|
28298
28726
|
}
|
|
28299
28727
|
}
|
|
28300
28728
|
function resolveMmaEntry(mmaRoot) {
|
|
28301
|
-
const dev =
|
|
28302
|
-
if (
|
|
28729
|
+
const dev = join41(mmaRoot, "src", "cli", "main.ts");
|
|
28730
|
+
if (existsSync47(dev))
|
|
28303
28731
|
return dev;
|
|
28304
|
-
return
|
|
28732
|
+
return join41(mmaRoot, "dist", "main.js");
|
|
28305
28733
|
}
|
|
28306
28734
|
function findMmaRoot(fromDir) {
|
|
28307
28735
|
const candidates = [
|
|
28308
|
-
|
|
28309
|
-
|
|
28736
|
+
resolve24(fromDir, "..", "..", ".."),
|
|
28737
|
+
resolve24(fromDir, "..")
|
|
28310
28738
|
];
|
|
28311
28739
|
for (const c of candidates) {
|
|
28312
|
-
if (
|
|
28740
|
+
if (existsSync47(join41(c, "package.json")))
|
|
28313
28741
|
return c;
|
|
28314
28742
|
}
|
|
28315
28743
|
return process.cwd();
|
|
@@ -28318,7 +28746,7 @@ function killTree2(child) {
|
|
|
28318
28746
|
const pid = child.pid;
|
|
28319
28747
|
if (!pid)
|
|
28320
28748
|
return;
|
|
28321
|
-
if (
|
|
28749
|
+
if (platform9() === "win32") {
|
|
28322
28750
|
spawn7("taskkill", ["/pid", String(pid), "/T", "/F"], {
|
|
28323
28751
|
windowsHide: true,
|
|
28324
28752
|
stdio: "ignore"
|
|
@@ -28333,7 +28761,7 @@ function killTree2(child) {
|
|
|
28333
28761
|
} catch {}
|
|
28334
28762
|
}
|
|
28335
28763
|
}
|
|
28336
|
-
var
|
|
28764
|
+
var defaultRunner2 = (env2, cwd, args, timeoutMs) => new Promise((resolvePromise) => {
|
|
28337
28765
|
const child = spawn7(process.execPath, args, {
|
|
28338
28766
|
cwd,
|
|
28339
28767
|
env: env2,
|
|
@@ -28377,15 +28805,15 @@ __export(exports_cli, {
|
|
|
28377
28805
|
});
|
|
28378
28806
|
import { rmSync as rmSync5 } from "fs";
|
|
28379
28807
|
import { homedir as homedir14 } from "os";
|
|
28380
|
-
import { join as
|
|
28381
|
-
import { fileURLToPath as
|
|
28382
|
-
import { existsSync as
|
|
28808
|
+
import { join as join42, dirname as dirname15 } from "path";
|
|
28809
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
28810
|
+
import { existsSync as existsSync48, readFileSync as readFileSync30 } from "fs";
|
|
28383
28811
|
function readVersion() {
|
|
28384
|
-
const candidates = [
|
|
28812
|
+
const candidates = [join42(MMA_ROOT, "package.json")];
|
|
28385
28813
|
for (const p of candidates) {
|
|
28386
|
-
if (
|
|
28814
|
+
if (existsSync48(p)) {
|
|
28387
28815
|
try {
|
|
28388
|
-
const raw = JSON.parse(
|
|
28816
|
+
const raw = JSON.parse(readFileSync30(p, "utf-8"));
|
|
28389
28817
|
if (raw.version)
|
|
28390
28818
|
return raw.version;
|
|
28391
28819
|
} catch {}
|
|
@@ -28421,7 +28849,7 @@ async function certify(opts) {
|
|
|
28421
28849
|
return;
|
|
28422
28850
|
}
|
|
28423
28851
|
console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
|
|
28424
|
-
const sandboxBase =
|
|
28852
|
+
const sandboxBase = join42(process.cwd(), ".mma", "certification");
|
|
28425
28853
|
const results = [];
|
|
28426
28854
|
const total = selected.length;
|
|
28427
28855
|
let idx = 0;
|
|
@@ -28533,9 +28961,9 @@ var init_cli = __esm(() => {
|
|
|
28533
28961
|
init_loader3();
|
|
28534
28962
|
init_runner2();
|
|
28535
28963
|
init_manifest();
|
|
28536
|
-
HERE =
|
|
28964
|
+
HERE = dirname15(fileURLToPath3(import.meta.url));
|
|
28537
28965
|
MMA_ROOT = findMmaRoot(HERE);
|
|
28538
|
-
USER_SCENARIO_DIR =
|
|
28966
|
+
USER_SCENARIO_DIR = join42(homedir14(), ".mma", "certification", "scenarios");
|
|
28539
28967
|
});
|
|
28540
28968
|
|
|
28541
28969
|
// src/cli/repl-commands.ts
|
|
@@ -28544,20 +28972,20 @@ __export(exports_repl_commands, {
|
|
|
28544
28972
|
registerAllCommands: () => registerAllCommands,
|
|
28545
28973
|
COMMAND_GROUPS: () => COMMAND_GROUPS
|
|
28546
28974
|
});
|
|
28547
|
-
import { join as
|
|
28975
|
+
import { join as join44, dirname as dirname17 } from "path";
|
|
28548
28976
|
import { homedir as homedir16 } from "os";
|
|
28549
|
-
import { existsSync as
|
|
28550
|
-
import { fileURLToPath as
|
|
28977
|
+
import { existsSync as existsSync50, readFileSync as readFileSync32 } from "fs";
|
|
28978
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
28551
28979
|
function readVersion3() {
|
|
28552
|
-
const here =
|
|
28980
|
+
const here = dirname17(fileURLToPath5(import.meta.url));
|
|
28553
28981
|
const candidates = [
|
|
28554
|
-
|
|
28555
|
-
|
|
28982
|
+
join44(here, "..", "..", "package.json"),
|
|
28983
|
+
join44(here, "..", "package.json")
|
|
28556
28984
|
];
|
|
28557
28985
|
for (const p of candidates) {
|
|
28558
|
-
if (
|
|
28986
|
+
if (existsSync50(p)) {
|
|
28559
28987
|
try {
|
|
28560
|
-
const raw = JSON.parse(
|
|
28988
|
+
const raw = JSON.parse(readFileSync32(p, "utf8"));
|
|
28561
28989
|
if (raw.version)
|
|
28562
28990
|
return raw.version;
|
|
28563
28991
|
} catch {}
|
|
@@ -28621,8 +29049,8 @@ function registerMmaCommands(ctx) {
|
|
|
28621
29049
|
}
|
|
28622
29050
|
try {
|
|
28623
29051
|
const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
|
|
28624
|
-
const { existsSync:
|
|
28625
|
-
const { resolve:
|
|
29052
|
+
const { existsSync: existsSync51 } = await import("fs");
|
|
29053
|
+
const { resolve: resolve25 } = await import("path");
|
|
28626
29054
|
let dataUrl;
|
|
28627
29055
|
let label;
|
|
28628
29056
|
if (source.toLowerCase() === "clipboard") {
|
|
@@ -28640,8 +29068,8 @@ function registerMmaCommands(ctx) {
|
|
|
28640
29068
|
dataUrl = result.dataUrl;
|
|
28641
29069
|
label = source;
|
|
28642
29070
|
} else {
|
|
28643
|
-
const absPath =
|
|
28644
|
-
if (!
|
|
29071
|
+
const absPath = resolve25(process.cwd(), source);
|
|
29072
|
+
if (!existsSync51(absPath)) {
|
|
28645
29073
|
console.log(pc2.red(t("image.not_found", { path: source })));
|
|
28646
29074
|
return;
|
|
28647
29075
|
}
|
|
@@ -28720,7 +29148,7 @@ function registerMmaCommands(ctx) {
|
|
|
28720
29148
|
console.log(pc2.yellow(t("repl.wizard_running")));
|
|
28721
29149
|
await ctx.withExclusiveInput(async () => {
|
|
28722
29150
|
const answers = await runSetup(ctx.rl);
|
|
28723
|
-
const configPath =
|
|
29151
|
+
const configPath = join44(homedir16(), ".mma", "config.json");
|
|
28724
29152
|
ctx.config.provider.type = answers.provider;
|
|
28725
29153
|
ctx.config.provider.baseUrl = answers.apiBase;
|
|
28726
29154
|
ctx.config.provider.apiKey = answers.apiKey;
|
|
@@ -28774,7 +29202,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
28774
29202
|
return;
|
|
28775
29203
|
}
|
|
28776
29204
|
ctx.config.provider.type = name;
|
|
28777
|
-
const configPath =
|
|
29205
|
+
const configPath = join44(homedir16(), ".mma", "config.json");
|
|
28778
29206
|
saveConfig(ctx.config, configPath);
|
|
28779
29207
|
await ctx.agent.reconfigure(ctx.config);
|
|
28780
29208
|
console.log(pc2.green(t("repl.provider_set", { name })));
|
|
@@ -28830,7 +29258,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
28830
29258
|
return;
|
|
28831
29259
|
}
|
|
28832
29260
|
ctx.config.model = name;
|
|
28833
|
-
const configPath =
|
|
29261
|
+
const configPath = join44(homedir16(), ".mma", "config.json");
|
|
28834
29262
|
saveConfig(ctx.config, configPath);
|
|
28835
29263
|
await ctx.agent.reconfigure(ctx.config);
|
|
28836
29264
|
console.log(pc2.green(t("repl.model_set", { name })));
|
|
@@ -28855,7 +29283,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
28855
29283
|
return;
|
|
28856
29284
|
}
|
|
28857
29285
|
ctx.config.contextWindow = size;
|
|
28858
|
-
const configPath =
|
|
29286
|
+
const configPath = join44(homedir16(), ".mma", "config.json");
|
|
28859
29287
|
saveConfig(ctx.config, configPath);
|
|
28860
29288
|
await ctx.agent.reconfigure(ctx.config);
|
|
28861
29289
|
console.log(pc2.green(t("cli.context_set", { size })));
|
|
@@ -28874,10 +29302,10 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
28874
29302
|
ctx.agent.shutdown();
|
|
28875
29303
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
|
|
28876
29304
|
const { homedir: homedir17 } = await import("os");
|
|
28877
|
-
const { join:
|
|
29305
|
+
const { join: join45 } = await import("path");
|
|
28878
29306
|
const configDir = ctx.configDir;
|
|
28879
29307
|
const baseDir = ctx.baseDir;
|
|
28880
|
-
const projectConfigPath =
|
|
29308
|
+
const projectConfigPath = join45(baseDir, ".mmrc");
|
|
28881
29309
|
const freshConfig = loadConfig2({ configDir, projectConfigPath });
|
|
28882
29310
|
Object.assign(ctx.config, freshConfig);
|
|
28883
29311
|
const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
|
|
@@ -29177,14 +29605,14 @@ init_bootstrap();
|
|
|
29177
29605
|
init_config2();
|
|
29178
29606
|
init_setup();
|
|
29179
29607
|
init_i18n();
|
|
29180
|
-
import { join as
|
|
29608
|
+
import { join as join43, dirname as dirname16 } from "path";
|
|
29181
29609
|
import { homedir as homedir15 } from "os";
|
|
29182
|
-
import { existsSync as
|
|
29610
|
+
import { existsSync as existsSync49, readFileSync as readFileSync31 } from "fs";
|
|
29183
29611
|
|
|
29184
29612
|
// src/cli/security-commands.ts
|
|
29185
29613
|
init_bootstrap();
|
|
29186
29614
|
init_config2();
|
|
29187
|
-
import { join as
|
|
29615
|
+
import { join as join37 } from "path";
|
|
29188
29616
|
import { homedir as homedir12 } from "os";
|
|
29189
29617
|
|
|
29190
29618
|
// src/modules/security/security-policies.ts
|
|
@@ -29714,7 +30142,7 @@ function createSecurityCommand(program2) {
|
|
|
29714
30142
|
}
|
|
29715
30143
|
});
|
|
29716
30144
|
securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
|
|
29717
|
-
const configPath =
|
|
30145
|
+
const configPath = join37(homedir12(), ".mma", "config.json");
|
|
29718
30146
|
const { config: appConfig } = await bootstrap();
|
|
29719
30147
|
const validPresets = ["strict", "balanced", "permissive"];
|
|
29720
30148
|
if (!validPresets.includes(preset)) {
|
|
@@ -29729,7 +30157,7 @@ function createSecurityCommand(program2) {
|
|
|
29729
30157
|
console.log(t("cli.security.policy_description", { description: policy.description }));
|
|
29730
30158
|
});
|
|
29731
30159
|
securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
|
|
29732
|
-
const configPath =
|
|
30160
|
+
const configPath = join37(homedir12(), ".mma", "config.json");
|
|
29733
30161
|
const { config: appConfig } = await bootstrap();
|
|
29734
30162
|
appConfig.security = appConfig.security || {};
|
|
29735
30163
|
appConfig.security.sessionEncryption = {
|
|
@@ -29741,7 +30169,7 @@ function createSecurityCommand(program2) {
|
|
|
29741
30169
|
console.log(t("cli.security.encryption_enabled"));
|
|
29742
30170
|
});
|
|
29743
30171
|
securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
|
|
29744
|
-
const configPath =
|
|
30172
|
+
const configPath = join37(homedir12(), ".mma", "config.json");
|
|
29745
30173
|
const { config: appConfig } = await bootstrap();
|
|
29746
30174
|
appConfig.security = appConfig.security || {};
|
|
29747
30175
|
appConfig.security.sessionEncryption = {
|
|
@@ -29753,7 +30181,7 @@ function createSecurityCommand(program2) {
|
|
|
29753
30181
|
console.log(t("cli.security.encryption_disabled"));
|
|
29754
30182
|
});
|
|
29755
30183
|
securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
|
|
29756
|
-
const configPath =
|
|
30184
|
+
const configPath = join37(homedir12(), ".mma", "config.json");
|
|
29757
30185
|
const { config: appConfig } = await bootstrap();
|
|
29758
30186
|
appConfig.security = appConfig.security || {};
|
|
29759
30187
|
appConfig.security.auditNotifier = {
|
|
@@ -29767,7 +30195,7 @@ function createSecurityCommand(program2) {
|
|
|
29767
30195
|
console.log(t("cli.security.audit_enabled"));
|
|
29768
30196
|
});
|
|
29769
30197
|
securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
|
|
29770
|
-
const configPath =
|
|
30198
|
+
const configPath = join37(homedir12(), ".mma", "config.json");
|
|
29771
30199
|
const { config: appConfig } = await bootstrap();
|
|
29772
30200
|
appConfig.security = appConfig.security || {};
|
|
29773
30201
|
appConfig.security.auditNotifier = {
|
|
@@ -29798,18 +30226,49 @@ function createSecurityCommand(program2) {
|
|
|
29798
30226
|
});
|
|
29799
30227
|
}
|
|
29800
30228
|
|
|
30229
|
+
// src/cli/plugin-commands.ts
|
|
30230
|
+
init_bootstrap();
|
|
30231
|
+
init_version();
|
|
30232
|
+
init_i18n();
|
|
30233
|
+
function createPluginCommand(program2) {
|
|
30234
|
+
const pluginsCmd = program2.command("plugins").description(t("cli.plugins.description"));
|
|
30235
|
+
pluginsCmd.command("list").description(t("cli.plugins.list")).option("-a, --all", t("cli.plugins.all")).action(async (cmdOpts) => {
|
|
30236
|
+
const { pluginManager } = await bootstrap();
|
|
30237
|
+
const all = cmdOpts.all === true;
|
|
30238
|
+
let infos = pluginManager.getPluginInfos();
|
|
30239
|
+
if (!all) {
|
|
30240
|
+
infos = infos.filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
|
|
30241
|
+
}
|
|
30242
|
+
if (infos.length === 0) {
|
|
30243
|
+
console.log(t("cli.plugins.none"));
|
|
30244
|
+
return;
|
|
30245
|
+
}
|
|
30246
|
+
const mmaVersion = readMmaVersion();
|
|
30247
|
+
console.log(t("cli.plugins.header", { count: String(infos.length), mma: mmaVersion }));
|
|
30248
|
+
for (const { plugin: plugin3, source } of infos) {
|
|
30249
|
+
const version = plugin3.version || "-";
|
|
30250
|
+
const origin = source || "builtin";
|
|
30251
|
+
const builtin = plugin3.isBuiltin ? t("cli.plugins.builtin_mark") : " ";
|
|
30252
|
+
console.log(` ${builtin} ${plugin3.name} v${version} [${origin}]`);
|
|
30253
|
+
}
|
|
30254
|
+
if (!all) {
|
|
30255
|
+
console.log(t("cli.plugins.only_external"));
|
|
30256
|
+
}
|
|
30257
|
+
});
|
|
30258
|
+
}
|
|
30259
|
+
|
|
29801
30260
|
// src/cli/commands.ts
|
|
29802
|
-
import { fileURLToPath as
|
|
30261
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
29803
30262
|
function readVersion2() {
|
|
29804
|
-
const here =
|
|
30263
|
+
const here = dirname16(fileURLToPath4(import.meta.url));
|
|
29805
30264
|
const candidates = [
|
|
29806
|
-
|
|
29807
|
-
|
|
30265
|
+
join43(here, "..", "..", "package.json"),
|
|
30266
|
+
join43(here, "..", "package.json")
|
|
29808
30267
|
];
|
|
29809
30268
|
for (const p of candidates) {
|
|
29810
|
-
if (
|
|
30269
|
+
if (existsSync49(p)) {
|
|
29811
30270
|
try {
|
|
29812
|
-
const raw = JSON.parse(
|
|
30271
|
+
const raw = JSON.parse(readFileSync31(p, "utf8"));
|
|
29813
30272
|
if (raw.version)
|
|
29814
30273
|
return raw.version;
|
|
29815
30274
|
} catch {}
|
|
@@ -29822,7 +30281,7 @@ function createProgram() {
|
|
|
29822
30281
|
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"));
|
|
29823
30282
|
program2.command("init").description(t("cli.init")).action(async () => {
|
|
29824
30283
|
const answers = await runSetup();
|
|
29825
|
-
const configPath =
|
|
30284
|
+
const configPath = join43(homedir15(), ".mma", "config.json");
|
|
29826
30285
|
const { config } = await bootstrap();
|
|
29827
30286
|
config.provider.type = answers.provider;
|
|
29828
30287
|
config.provider.baseUrl = answers.apiBase;
|
|
@@ -29867,7 +30326,7 @@ function createProgram() {
|
|
|
29867
30326
|
});
|
|
29868
30327
|
const configCmd = program2.command("config").description(t("cli.manage_config"));
|
|
29869
30328
|
configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
|
|
29870
|
-
const configPath =
|
|
30329
|
+
const configPath = join43(homedir15(), ".mma", "config.json");
|
|
29871
30330
|
const { config } = await bootstrap();
|
|
29872
30331
|
const keys = key.split(".");
|
|
29873
30332
|
let obj = config;
|
|
@@ -29930,7 +30389,7 @@ function createProgram() {
|
|
|
29930
30389
|
console.log(t("cli.model_hint"));
|
|
29931
30390
|
});
|
|
29932
30391
|
model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
|
|
29933
|
-
const configPath =
|
|
30392
|
+
const configPath = join43(homedir15(), ".mma", "config.json");
|
|
29934
30393
|
const { config } = await bootstrap();
|
|
29935
30394
|
config.model = name;
|
|
29936
30395
|
saveConfig(config, configPath);
|
|
@@ -29966,7 +30425,7 @@ function createProgram() {
|
|
|
29966
30425
|
await uncertify2(name, config);
|
|
29967
30426
|
});
|
|
29968
30427
|
program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
|
|
29969
|
-
const configPath =
|
|
30428
|
+
const configPath = join43(homedir15(), ".mma", "config.json");
|
|
29970
30429
|
const { config } = await bootstrap();
|
|
29971
30430
|
const contextWindow = parseInt(size, 10);
|
|
29972
30431
|
if (isNaN(contextWindow) || contextWindow < 1024) {
|
|
@@ -29984,7 +30443,7 @@ function createProgram() {
|
|
|
29984
30443
|
console.log(t("cli.base_url"), config.provider.baseUrl);
|
|
29985
30444
|
});
|
|
29986
30445
|
provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
|
|
29987
|
-
const configPath =
|
|
30446
|
+
const configPath = join43(homedir15(), ".mma", "config.json");
|
|
29988
30447
|
const { config } = await bootstrap();
|
|
29989
30448
|
config.provider.type = name;
|
|
29990
30449
|
saveConfig(config, configPath);
|
|
@@ -30026,6 +30485,7 @@ function createProgram() {
|
|
|
30026
30485
|
console.log(t("session.deleted", { id }));
|
|
30027
30486
|
});
|
|
30028
30487
|
createSecurityCommand(program2);
|
|
30488
|
+
createPluginCommand(program2);
|
|
30029
30489
|
program2.argument("[prompt...]", "Prompt to execute").description("Run a single prompt").action((prompt) => {});
|
|
30030
30490
|
return program2;
|
|
30031
30491
|
}
|
|
@@ -30791,10 +31251,10 @@ class LineEditor {
|
|
|
30791
31251
|
}
|
|
30792
31252
|
|
|
30793
31253
|
// src/cli/repl.ts
|
|
30794
|
-
import { existsSync as
|
|
30795
|
-
import { join as
|
|
31254
|
+
import { existsSync as existsSync51, readFileSync as readFileSync33, writeFileSync as writeFileSync17 } from "fs";
|
|
31255
|
+
import { join as join45, dirname as dirname18 } from "path";
|
|
30796
31256
|
import { homedir as homedir17 } from "os";
|
|
30797
|
-
import { fileURLToPath as
|
|
31257
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
30798
31258
|
|
|
30799
31259
|
// src/cli/completer.ts
|
|
30800
31260
|
class SlashCommandProvider {
|
|
@@ -31296,15 +31756,15 @@ init_box();
|
|
|
31296
31756
|
init_i18n();
|
|
31297
31757
|
init_repl_commands();
|
|
31298
31758
|
function readVersion4() {
|
|
31299
|
-
const here =
|
|
31759
|
+
const here = dirname18(fileURLToPath6(import.meta.url));
|
|
31300
31760
|
const candidates = [
|
|
31301
|
-
|
|
31302
|
-
|
|
31761
|
+
join45(here, "..", "..", "package.json"),
|
|
31762
|
+
join45(here, "..", "package.json")
|
|
31303
31763
|
];
|
|
31304
31764
|
for (const p of candidates) {
|
|
31305
|
-
if (
|
|
31765
|
+
if (existsSync51(p)) {
|
|
31306
31766
|
try {
|
|
31307
|
-
const raw = JSON.parse(
|
|
31767
|
+
const raw = JSON.parse(readFileSync33(p, "utf8"));
|
|
31308
31768
|
if (raw.version)
|
|
31309
31769
|
return raw.version;
|
|
31310
31770
|
} catch {}
|
|
@@ -31360,10 +31820,10 @@ class Repl {
|
|
|
31360
31820
|
this.skillsModule = skillsModule;
|
|
31361
31821
|
this.pluginManager = pluginManager;
|
|
31362
31822
|
this.logger = logger;
|
|
31363
|
-
this.configDir = configDir ||
|
|
31823
|
+
this.configDir = configDir || join45(homedir17(), ".mma");
|
|
31364
31824
|
this.baseDir = baseDir || process.cwd();
|
|
31365
31825
|
this.noAgentsMd = noAgentsMd === true;
|
|
31366
|
-
this.historyPath =
|
|
31826
|
+
this.historyPath = join45(homedir17(), ".mma", "repl-history");
|
|
31367
31827
|
this.loadHistory();
|
|
31368
31828
|
this.rl = process.stdin.isTTY ? new LineEditor({
|
|
31369
31829
|
input: process.stdin,
|
|
@@ -31396,9 +31856,9 @@ class Repl {
|
|
|
31396
31856
|
this.setupListeners();
|
|
31397
31857
|
}
|
|
31398
31858
|
loadHistory() {
|
|
31399
|
-
if (
|
|
31859
|
+
if (existsSync51(this.historyPath)) {
|
|
31400
31860
|
try {
|
|
31401
|
-
const raw =
|
|
31861
|
+
const raw = readFileSync33(this.historyPath, "utf-8");
|
|
31402
31862
|
this.history = raw.split(`
|
|
31403
31863
|
`).filter(Boolean).slice(-this.maxHistory);
|
|
31404
31864
|
} catch {
|
|
@@ -31737,10 +32197,14 @@ ${t("image.clipboard_empty")}`));
|
|
|
31737
32197
|
row(t("repl.skills_label"), `${pc2.white(String(this.skillsModule.getAvailable().length))} available, ${pc2.dim(`budget: ${budget.total} tokens`)}`);
|
|
31738
32198
|
}
|
|
31739
32199
|
if (this.pluginManager) {
|
|
31740
|
-
const
|
|
31741
|
-
if (
|
|
31742
|
-
const pluginNames =
|
|
31743
|
-
|
|
32200
|
+
const infos = this.pluginManager.getPluginInfos().filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
|
|
32201
|
+
if (infos.length > 0) {
|
|
32202
|
+
const pluginNames = infos.map(({ plugin: plugin3, source }) => {
|
|
32203
|
+
const version4 = plugin3.version ? `${pc2.dim(plugin3.version)}` : "";
|
|
32204
|
+
const origin = source ? pc2.dim(` [${source}]`) : "";
|
|
32205
|
+
return `${plugin3.name}${version4}${origin}`;
|
|
32206
|
+
}).join(", ");
|
|
32207
|
+
row(t("repl.plugins_label"), `${pc2.white(String(infos.length))} active ${pc2.dim(`(${pluginNames})`)}`);
|
|
31744
32208
|
}
|
|
31745
32209
|
}
|
|
31746
32210
|
const mcpServers = this.config.mcpServers || {};
|
|
@@ -31755,11 +32219,11 @@ ${t("image.clipboard_empty")}`));
|
|
|
31755
32219
|
row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
|
|
31756
32220
|
} else {
|
|
31757
32221
|
const agentsMdCandidates = [
|
|
31758
|
-
|
|
31759
|
-
|
|
31760
|
-
|
|
32222
|
+
join45(this.baseDir, "AGENTS.md"),
|
|
32223
|
+
join45(this.baseDir, ".mma", "AGENTS.md"),
|
|
32224
|
+
join45(this.configDir, "AGENTS.md")
|
|
31761
32225
|
];
|
|
31762
|
-
const foundAgents = agentsMdCandidates.filter((p) =>
|
|
32226
|
+
const foundAgents = agentsMdCandidates.filter((p) => existsSync51(p));
|
|
31763
32227
|
if (foundAgents.length > 0) {
|
|
31764
32228
|
for (const p of foundAgents) {
|
|
31765
32229
|
row(t("repl.agents_label"), pc2.dim(p));
|
|
@@ -31770,7 +32234,7 @@ ${t("image.clipboard_empty")}`));
|
|
|
31770
32234
|
}
|
|
31771
32235
|
const meta = this.sessionManager?.getActiveMeta();
|
|
31772
32236
|
if (meta) {
|
|
31773
|
-
const sessionPath =
|
|
32237
|
+
const sessionPath = join45(this.configDir, "sessions", meta.id);
|
|
31774
32238
|
row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
|
|
31775
32239
|
}
|
|
31776
32240
|
const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
|
|
@@ -31811,93 +32275,16 @@ init_setup();
|
|
|
31811
32275
|
init_config2();
|
|
31812
32276
|
init_i18n();
|
|
31813
32277
|
init_colors();
|
|
31814
|
-
import { existsSync as
|
|
31815
|
-
import { join as
|
|
32278
|
+
import { existsSync as existsSync52, readFileSync as readFileSync34 } from "fs";
|
|
32279
|
+
import { join as join46, dirname as dirname19 } from "path";
|
|
31816
32280
|
import { homedir as homedir18 } from "os";
|
|
31817
|
-
import { fileURLToPath as
|
|
32281
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
31818
32282
|
|
|
31819
|
-
// src/modules/updater/
|
|
31820
|
-
|
|
31821
|
-
import { platform as platform9 } from "os";
|
|
31822
|
-
function semverGt(a, b) {
|
|
31823
|
-
const pa = a.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
31824
|
-
const pb = b.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
31825
|
-
for (let i = 0;i < 3; i++) {
|
|
31826
|
-
const na = pa[i] ?? 0;
|
|
31827
|
-
const nb = pb[i] ?? 0;
|
|
31828
|
-
if (na !== nb)
|
|
31829
|
-
return na > nb;
|
|
31830
|
-
}
|
|
31831
|
-
return false;
|
|
31832
|
-
}
|
|
31833
|
-
var defaultRunner2 = async (command, args, options) => {
|
|
31834
|
-
const { execFile } = await import("child_process");
|
|
31835
|
-
return new Promise((resolve24) => {
|
|
31836
|
-
execFile(command, args, options, (err) => resolve24({ error: err?.message }));
|
|
31837
|
-
});
|
|
31838
|
-
};
|
|
32283
|
+
// src/modules/updater/index.ts
|
|
32284
|
+
init_checker();
|
|
31839
32285
|
|
|
31840
|
-
class Updater {
|
|
31841
|
-
currentVersion;
|
|
31842
|
-
packageName;
|
|
31843
|
-
runner;
|
|
31844
|
-
constructor(currentVersion, packageName, runner) {
|
|
31845
|
-
this.currentVersion = currentVersion;
|
|
31846
|
-
this.packageName = packageName;
|
|
31847
|
-
this.runner = runner ?? defaultRunner2;
|
|
31848
|
-
}
|
|
31849
|
-
getCurrentVersion() {
|
|
31850
|
-
return this.currentVersion;
|
|
31851
|
-
}
|
|
31852
|
-
getPackageName() {
|
|
31853
|
-
return this.packageName;
|
|
31854
|
-
}
|
|
31855
|
-
async check() {
|
|
31856
|
-
try {
|
|
31857
|
-
const response = await fetch(`https://registry.npmjs.org/${this.packageName}`, {
|
|
31858
|
-
headers: { Accept: "application/vnd.npm.install-v1+json" },
|
|
31859
|
-
signal: AbortSignal.timeout(5000)
|
|
31860
|
-
});
|
|
31861
|
-
if (!response.ok) {
|
|
31862
|
-
return { updateAvailable: false, current: this.currentVersion, error: `HTTP ${response.status}` };
|
|
31863
|
-
}
|
|
31864
|
-
const data = await response.json();
|
|
31865
|
-
const latest = data["dist-tags"]?.latest;
|
|
31866
|
-
if (!latest) {
|
|
31867
|
-
return { updateAvailable: false, current: this.currentVersion, error: "No latest tag" };
|
|
31868
|
-
}
|
|
31869
|
-
const updateAvailable = semverGt(latest, this.currentVersion);
|
|
31870
|
-
return { updateAvailable, current: this.currentVersion, latest };
|
|
31871
|
-
} catch (e) {
|
|
31872
|
-
return { updateAvailable: false, current: this.currentVersion, error: e.message };
|
|
31873
|
-
}
|
|
31874
|
-
}
|
|
31875
|
-
async install(latest) {
|
|
31876
|
-
try {
|
|
31877
|
-
const { command, args } = this.buildInstallCommand(latest);
|
|
31878
|
-
const res = await this.runner(command, args, {
|
|
31879
|
-
timeout: 120000,
|
|
31880
|
-
windowsHide: true
|
|
31881
|
-
});
|
|
31882
|
-
if (res.error)
|
|
31883
|
-
return { success: false, error: res.error };
|
|
31884
|
-
return { success: true, installed: latest };
|
|
31885
|
-
} catch (e) {
|
|
31886
|
-
const msg = e?.message ?? String(e);
|
|
31887
|
-
return { success: false, error: msg.split(`
|
|
31888
|
-
`)[0] };
|
|
31889
|
-
}
|
|
31890
|
-
}
|
|
31891
|
-
buildInstallCommand(latest) {
|
|
31892
|
-
const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
|
|
31893
|
-
const command = resolveSpawnCommand("npm");
|
|
31894
|
-
if (platform9() === "win32" && /\.(cmd|bat)$/i.test(command)) {
|
|
31895
|
-
return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
|
|
31896
|
-
}
|
|
31897
|
-
return { command, args: npmArgs };
|
|
31898
|
-
}
|
|
31899
|
-
}
|
|
31900
32286
|
// src/modules/updater/module.ts
|
|
32287
|
+
init_checker();
|
|
31901
32288
|
init_i18n();
|
|
31902
32289
|
init_colors();
|
|
31903
32290
|
|
|
@@ -31992,15 +32379,15 @@ class UpdaterModule {
|
|
|
31992
32379
|
}
|
|
31993
32380
|
// src/cli/main.ts
|
|
31994
32381
|
function readVersion5() {
|
|
31995
|
-
const here =
|
|
32382
|
+
const here = dirname19(fileURLToPath7(import.meta.url));
|
|
31996
32383
|
const candidates = [
|
|
31997
|
-
|
|
31998
|
-
|
|
32384
|
+
join46(here, "..", "..", "package.json"),
|
|
32385
|
+
join46(here, "..", "package.json")
|
|
31999
32386
|
];
|
|
32000
32387
|
for (const p of candidates) {
|
|
32001
|
-
if (
|
|
32388
|
+
if (existsSync52(p)) {
|
|
32002
32389
|
try {
|
|
32003
|
-
const raw = JSON.parse(
|
|
32390
|
+
const raw = JSON.parse(readFileSync34(p, "utf8"));
|
|
32004
32391
|
if (raw.version)
|
|
32005
32392
|
return raw.version;
|
|
32006
32393
|
} catch {}
|
|
@@ -32083,15 +32470,15 @@ async function main() {
|
|
|
32083
32470
|
await updater?.waitForIdle();
|
|
32084
32471
|
process.exit(exitCode);
|
|
32085
32472
|
} else {
|
|
32086
|
-
const configPath =
|
|
32087
|
-
if (!
|
|
32473
|
+
const configPath = join46(homedir18(), ".mma", "config.json");
|
|
32474
|
+
if (!existsSync52(configPath)) {
|
|
32088
32475
|
console.log(pc2.yellow(`
|
|
32089
32476
|
` + t("cli.first_run") + `
|
|
32090
32477
|
`));
|
|
32091
32478
|
const answers = await runSetup();
|
|
32092
32479
|
const config2 = loadConfig({
|
|
32093
|
-
configDir:
|
|
32094
|
-
projectConfigPath: projectDir ?
|
|
32480
|
+
configDir: join46(homedir18(), ".mma"),
|
|
32481
|
+
projectConfigPath: projectDir ? join46(projectDir, ".mmrc") : join46(process.cwd(), ".mmrc")
|
|
32095
32482
|
});
|
|
32096
32483
|
config2.provider.type = answers.provider;
|
|
32097
32484
|
config2.provider.baseUrl = answers.apiBase;
|