micro-models-agent 0.38.0 → 0.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.js +569 -387
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2151,8 +2151,12 @@ var init_config = __esm(() => {
2151
2151
  LANGUAGE_MAP = {
2152
2152
  ts: "typescript",
2153
2153
  tsx: "typescript",
2154
+ mts: "typescript",
2155
+ cts: "typescript",
2154
2156
  js: "javascript",
2155
2157
  jsx: "javascript",
2158
+ mjs: "javascript",
2159
+ cjs: "javascript",
2156
2160
  py: "python",
2157
2161
  rs: "rust",
2158
2162
  go: "go",
@@ -2622,6 +2626,13 @@ Available commands:`,
2622
2626
  "cli.security.recommended_for": "Recommended for",
2623
2627
  "cli.yes": "Yes",
2624
2628
  "cli.no": "No",
2629
+ "cli.plugins.description": "Manage plugins",
2630
+ "cli.plugins.list": "List loaded plugins (name, version, source)",
2631
+ "cli.plugins.all": "Include builtin plugins",
2632
+ "cli.plugins.only_external": "(builtin plugins omitted — use --all to show them)",
2633
+ "cli.plugins.none": "No plugins loaded",
2634
+ "cli.plugins.header": "Plugins: {count} loaded (MMA v{mma})",
2635
+ "cli.plugins.builtin_mark": "●",
2625
2636
  "repl.help": "Show available commands",
2626
2637
  "repl.help_usage": "Usage: /help",
2627
2638
  "repl.exit": "Exit the REPL",
@@ -2636,6 +2647,8 @@ Available commands:`,
2636
2647
  "repl.reasoning_usage": "Usage: /reasoning",
2637
2648
  "repl.status": "Show agent status",
2638
2649
  "repl.status_usage": "Usage: /status",
2650
+ "repl.plugins": "List loaded plugins",
2651
+ "repl.plugins_usage": "Usage: /plugins [--all]",
2639
2652
  "repl.sessions": "List all sessions (* active)",
2640
2653
  "repl.sessions_usage": "Usage: /sessions",
2641
2654
  "repl.new": "Create a new session",
@@ -2831,6 +2844,8 @@ Use this knowledge to answer the user's question.`,
2831
2844
  "pipeline.circular": "Circular dependency: {stepId}",
2832
2845
  "plugin.loaded": "Loaded plugin: {name}",
2833
2846
  "plugin.skipped": "Skipped incompatible plugin: {entry} ({message})",
2847
+ "plugin.incompatible": "Skipped plugin {name}: requires MMA v{min}, current is v{current}",
2848
+ "plugin.dedup_older": "Plugin {name} v{version} skipped: a newer version is already loaded",
2834
2849
  "migration.detected": "[MMA] Detected old config. {summary}",
2835
2850
  "migration.summary": "[MMA] {summary}",
2836
2851
  "migration.config_bak": "- config → config.json.bak",
@@ -3226,6 +3241,13 @@ var init_ru = __esm(() => {
3226
3241
  "cli.security.recommended_for": "Рекомендуется для",
3227
3242
  "cli.yes": "Да",
3228
3243
  "cli.no": "Нет",
3244
+ "cli.plugins.description": "Управление плагинами",
3245
+ "cli.plugins.list": "Список загруженных плагинов (имя, версия, источник)",
3246
+ "cli.plugins.all": "Включить встроенные плагины",
3247
+ "cli.plugins.only_external": "(встроенные плагины скрыты — используйте --all)",
3248
+ "cli.plugins.none": "Плагины не загружены",
3249
+ "cli.plugins.header": "Плагины: {count} загружено (MMA v{mma})",
3250
+ "cli.plugins.builtin_mark": "●",
3229
3251
  "repl.help": "Показать доступные команды",
3230
3252
  "repl.help_usage": "Использование: /help",
3231
3253
  "repl.exit": "Выйти из REPL",
@@ -3240,6 +3262,8 @@ var init_ru = __esm(() => {
3240
3262
  "repl.reasoning_usage": "Использование: /reasoning",
3241
3263
  "repl.status": "Показать статус агента",
3242
3264
  "repl.status_usage": "Использование: /status",
3265
+ "repl.plugins": "Список загруженных плагинов",
3266
+ "repl.plugins_usage": "Использование: /plugins [--all]",
3243
3267
  "repl.sessions": "Список всех сессий (* активная)",
3244
3268
  "repl.sessions_usage": "Использование: /sessions",
3245
3269
  "repl.new": "Создать новую сессию",
@@ -3439,6 +3463,8 @@ var init_ru = __esm(() => {
3439
3463
  "pipeline.circular": "Циклическая зависимость: {stepId}",
3440
3464
  "plugin.loaded": "Загружен плагин: {name}",
3441
3465
  "plugin.skipped": "Пропущен несовместимый плагин: {entry} ({message})",
3466
+ "plugin.incompatible": "Пропущен плагин {name}: требуется MMA v{min}, текущая v{current}",
3467
+ "plugin.dedup_older": "Плагин {name} v{version} пропущен: уже загружена более новая версия",
3442
3468
  "migration.detected": "[MMA] Обнаружен старый конфиг. {summary}",
3443
3469
  "migration.summary": "[MMA] {summary}",
3444
3470
  "migration.config_bak": "- config → config.json.bak",
@@ -12222,16 +12248,157 @@ var init_detector = __esm(() => {
12222
12248
  init_llm_judge();
12223
12249
  });
12224
12250
 
12251
+ // src/modules/lsp/command.ts
12252
+ import { delimiter, join as join13 } from "path";
12253
+ import { existsSync as existsSync22 } from "fs";
12254
+ import { platform as platform3 } from "os";
12255
+ function resolveSpawnCommand(command, platformName = platform3(), pathEnv = process.env.PATH ?? "") {
12256
+ if (platformName !== "win32")
12257
+ return command;
12258
+ if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
12259
+ return command;
12260
+ }
12261
+ const dirs = pathEnv.split(delimiter).filter(Boolean);
12262
+ for (const dir of dirs) {
12263
+ for (const ext of WIN_EXTS) {
12264
+ const candidate = join13(dir, `${command}${ext}`);
12265
+ if (existsSync22(candidate))
12266
+ return `${command}${ext}`;
12267
+ }
12268
+ }
12269
+ return command;
12270
+ }
12271
+ function buildWinCommandLine(command, args) {
12272
+ const quote = (part) => {
12273
+ if (part === "")
12274
+ return '""';
12275
+ if (!/[\s"&|^<>()%!]/.test(part))
12276
+ return part;
12277
+ return `"${part.replace(/"/g, "\\\"")}"`;
12278
+ };
12279
+ return [command, ...args].map(quote).join(" ");
12280
+ }
12281
+ var WIN_EXTS;
12282
+ var init_command = __esm(() => {
12283
+ WIN_EXTS = [".cmd", ".bat", ".exe", ".com"];
12284
+ });
12285
+
12286
+ // src/modules/updater/checker.ts
12287
+ import { platform as platform4 } from "os";
12288
+ function semverGt(a, b) {
12289
+ const pa = a.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
12290
+ const pb = b.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
12291
+ for (let i = 0;i < 3; i++) {
12292
+ const na = pa[i] ?? 0;
12293
+ const nb = pb[i] ?? 0;
12294
+ if (na !== nb)
12295
+ return na > nb;
12296
+ }
12297
+ return false;
12298
+ }
12299
+
12300
+ class Updater {
12301
+ currentVersion;
12302
+ packageName;
12303
+ runner;
12304
+ constructor(currentVersion, packageName, runner) {
12305
+ this.currentVersion = currentVersion;
12306
+ this.packageName = packageName;
12307
+ this.runner = runner ?? defaultRunner;
12308
+ }
12309
+ getCurrentVersion() {
12310
+ return this.currentVersion;
12311
+ }
12312
+ getPackageName() {
12313
+ return this.packageName;
12314
+ }
12315
+ async check() {
12316
+ try {
12317
+ const response = await fetch(`https://registry.npmjs.org/${this.packageName}`, {
12318
+ headers: { Accept: "application/vnd.npm.install-v1+json" },
12319
+ signal: AbortSignal.timeout(5000)
12320
+ });
12321
+ if (!response.ok) {
12322
+ return { updateAvailable: false, current: this.currentVersion, error: `HTTP ${response.status}` };
12323
+ }
12324
+ const data = await response.json();
12325
+ const latest = data["dist-tags"]?.latest;
12326
+ if (!latest) {
12327
+ return { updateAvailable: false, current: this.currentVersion, error: "No latest tag" };
12328
+ }
12329
+ const updateAvailable = semverGt(latest, this.currentVersion);
12330
+ return { updateAvailable, current: this.currentVersion, latest };
12331
+ } catch (e) {
12332
+ return { updateAvailable: false, current: this.currentVersion, error: e.message };
12333
+ }
12334
+ }
12335
+ async install(latest) {
12336
+ try {
12337
+ const { command, args } = this.buildInstallCommand(latest);
12338
+ const res = await this.runner(command, args, {
12339
+ timeout: 120000,
12340
+ windowsHide: true
12341
+ });
12342
+ if (res.error)
12343
+ return { success: false, error: res.error };
12344
+ return { success: true, installed: latest };
12345
+ } catch (e) {
12346
+ const msg = e?.message ?? String(e);
12347
+ return { success: false, error: msg.split(`
12348
+ `)[0] };
12349
+ }
12350
+ }
12351
+ buildInstallCommand(latest) {
12352
+ const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
12353
+ const command = resolveSpawnCommand("npm");
12354
+ if (platform4() === "win32" && /\.(cmd|bat)$/i.test(command)) {
12355
+ return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
12356
+ }
12357
+ return { command, args: npmArgs };
12358
+ }
12359
+ }
12360
+ var defaultRunner = async (command, args, options) => {
12361
+ const { execFile } = await import("child_process");
12362
+ return new Promise((resolve13) => {
12363
+ execFile(command, args, options, (err) => resolve13({ error: err?.message }));
12364
+ });
12365
+ };
12366
+ var init_checker = __esm(() => {
12367
+ init_command();
12368
+ });
12369
+
12225
12370
  // src/modules/plugins/manager.ts
12226
12371
  class PluginManager {
12227
12372
  plugins = [];
12228
- register(plugin) {
12373
+ register(plugin, source) {
12374
+ if (source)
12375
+ plugin.source = source;
12376
+ const existing = this.plugins.find((p) => p.name === plugin.name);
12377
+ if (existing) {
12378
+ if (semverGt(plugin.version || "0.0.0", existing.version || "0.0.0")) {
12379
+ this.plugins = this.plugins.filter((p) => p.name !== plugin.name);
12380
+ this.plugins.push(plugin);
12381
+ this.sort();
12382
+ return { status: "registered" };
12383
+ }
12384
+ return { status: "skipped_older", existing };
12385
+ }
12229
12386
  this.plugins.push(plugin);
12387
+ this.sort();
12388
+ return { status: "registered" };
12389
+ }
12390
+ sort() {
12230
12391
  this.plugins.sort((a, b) => (b.priority || 0) - (a.priority || 0));
12231
12392
  }
12232
12393
  getAllPlugins() {
12233
12394
  return [...this.plugins];
12234
12395
  }
12396
+ getPluginInfos() {
12397
+ return [...this.plugins].map((plugin) => ({ plugin, source: plugin.source }));
12398
+ }
12399
+ getPlugin(name) {
12400
+ return this.plugins.find((p) => p.name === name) ?? null;
12401
+ }
12235
12402
  runOnBuildPrompt() {
12236
12403
  return this.plugins.map((p) => {
12237
12404
  try {
@@ -12368,6 +12535,9 @@ class PluginManager {
12368
12535
  return chunk;
12369
12536
  }
12370
12537
  }
12538
+ var init_manager2 = __esm(() => {
12539
+ init_checker();
12540
+ });
12371
12541
 
12372
12542
  // src/tools/subagent.ts
12373
12543
  function buildSubagentSystemPrompt(context, stable) {
@@ -12387,6 +12557,7 @@ var init_subagent = __esm(() => {
12387
12557
  init_agent();
12388
12558
  init_manager();
12389
12559
  init_detector();
12560
+ init_manager2();
12390
12561
  init_audit_log();
12391
12562
  init_session_isolation();
12392
12563
  init_store();
@@ -13441,6 +13612,7 @@ var init_pipeline_run = __esm(() => {
13441
13612
  init_parser();
13442
13613
  init_agent();
13443
13614
  init_manager();
13615
+ init_manager2();
13444
13616
  init_detector();
13445
13617
  init_audit_log();
13446
13618
  init_session_isolation();
@@ -14024,7 +14196,7 @@ ${JSON.stringify(result, null, 2)}`
14024
14196
 
14025
14197
  // src/tools/search-history.ts
14026
14198
  import * as fs from "fs";
14027
- import { join as join13 } from "path";
14199
+ import { join as join14 } from "path";
14028
14200
  import { homedir as homedir5 } from "os";
14029
14201
  function searchFile(filePath, query, maxResults, results) {
14030
14202
  if (!fs.existsSync(filePath))
@@ -14068,7 +14240,7 @@ var init_search_history = __esm(() => {
14068
14240
  const query = String(args.query || "").toLowerCase();
14069
14241
  const maxResults = Number(args.maxResults) || 5;
14070
14242
  const sessionId = args.sessionId ? String(args.sessionId) : null;
14071
- const sessionDir = join13(homedir5(), ".mma", "sessions");
14243
+ const sessionDir = join14(homedir5(), ".mma", "sessions");
14072
14244
  const results = [];
14073
14245
  try {
14074
14246
  if (!fs.existsSync(sessionDir)) {
@@ -14083,7 +14255,7 @@ var init_search_history = __esm(() => {
14083
14255
  continue;
14084
14256
  if (sessionId && entry.name !== sessionId)
14085
14257
  continue;
14086
- const historyFile = join13(sessionDir, entry.name, "history.jsonl");
14258
+ const historyFile = join14(sessionDir, entry.name, "history.jsonl");
14087
14259
  searchFile(historyFile, query, maxResults, results);
14088
14260
  if (results.length >= maxResults)
14089
14261
  break;
@@ -14110,8 +14282,8 @@ var init_search_history = __esm(() => {
14110
14282
  });
14111
14283
 
14112
14284
  // src/modules/memory/search.ts
14113
- import { readFileSync as readFileSync12, existsSync as existsSync23 } from "fs";
14114
- import { join as join14 } from "path";
14285
+ import { readFileSync as readFileSync12, existsSync as existsSync24 } from "fs";
14286
+ import { join as join15 } from "path";
14115
14287
 
14116
14288
  class MemorySearch {
14117
14289
  memoryDir;
@@ -14122,8 +14294,8 @@ class MemorySearch {
14122
14294
  const results = [];
14123
14295
  const lowerQuery = query.toLowerCase();
14124
14296
  for (const name of MEMORY_FILES) {
14125
- const path = join14(this.memoryDir, `${name}.md`);
14126
- if (!existsSync23(path))
14297
+ const path = join15(this.memoryDir, `${name}.md`);
14298
+ if (!existsSync24(path))
14127
14299
  continue;
14128
14300
  const content = readFileSync12(path, "utf-8");
14129
14301
  const lines = content.split(`
@@ -14134,8 +14306,8 @@ class MemorySearch {
14134
14306
  }
14135
14307
  }
14136
14308
  }
14137
- const prefsPath = join14(this.memoryDir, "preferences.json");
14138
- if (existsSync23(prefsPath)) {
14309
+ const prefsPath = join15(this.memoryDir, "preferences.json");
14310
+ if (existsSync24(prefsPath)) {
14139
14311
  try {
14140
14312
  const prefs = JSON.parse(readFileSync12(prefsPath, "utf-8"));
14141
14313
  for (const [key, value] of Object.entries(prefs)) {
@@ -14155,8 +14327,8 @@ var init_search = __esm(() => {
14155
14327
  });
14156
14328
 
14157
14329
  // src/modules/memory/store.ts
14158
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, existsSync as existsSync24, mkdirSync as mkdirSync13 } from "fs";
14159
- import { join as join15 } from "path";
14330
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, existsSync as existsSync25, mkdirSync as mkdirSync13 } from "fs";
14331
+ import { join as join16 } from "path";
14160
14332
 
14161
14333
  class MemoryStore {
14162
14334
  memoryDir;
@@ -14164,8 +14336,8 @@ class MemoryStore {
14164
14336
  this.memoryDir = memoryDir;
14165
14337
  this.ensureDir();
14166
14338
  for (const name of MEMORY_FILES2) {
14167
- const path = join15(this.memoryDir, `${name}.md`);
14168
- if (!existsSync24(path)) {
14339
+ const path = join16(this.memoryDir, `${name}.md`);
14340
+ if (!existsSync25(path)) {
14169
14341
  writeFileSync9(path, `# ${name.charAt(0).toUpperCase() + name.slice(1)}
14170
14342
 
14171
14343
  `, "utf-8");
@@ -14173,18 +14345,18 @@ class MemoryStore {
14173
14345
  }
14174
14346
  }
14175
14347
  ensureDir() {
14176
- if (!existsSync24(this.memoryDir)) {
14348
+ if (!existsSync25(this.memoryDir)) {
14177
14349
  mkdirSync13(this.memoryDir, { recursive: true });
14178
14350
  }
14179
14351
  }
14180
14352
  read(name) {
14181
- const path = join15(this.memoryDir, `${name}.md`);
14182
- if (!existsSync24(path))
14353
+ const path = join16(this.memoryDir, `${name}.md`);
14354
+ if (!existsSync25(path))
14183
14355
  return "";
14184
14356
  return readFileSync13(path, "utf-8");
14185
14357
  }
14186
14358
  append(name, entry) {
14187
- const path = join15(this.memoryDir, `${name}.md`);
14359
+ const path = join16(this.memoryDir, `${name}.md`);
14188
14360
  const timestamp = new Date().toISOString().replace("T", " ").slice(0, 19);
14189
14361
  const formatted = `- **${timestamp}** — ${entry}
14190
14362
  `;
@@ -14195,11 +14367,11 @@ class MemoryStore {
14195
14367
  return searchModule.query(query);
14196
14368
  }
14197
14369
  prefsPath() {
14198
- return join15(this.memoryDir, "preferences.json");
14370
+ return join16(this.memoryDir, "preferences.json");
14199
14371
  }
14200
14372
  getPreferences() {
14201
14373
  const path = this.prefsPath();
14202
- if (!existsSync24(path))
14374
+ if (!existsSync25(path))
14203
14375
  return {};
14204
14376
  try {
14205
14377
  return JSON.parse(readFileSync13(path, "utf-8"));
@@ -14235,7 +14407,7 @@ var init_store2 = __esm(() => {
14235
14407
 
14236
14408
  // src/tools/remember.ts
14237
14409
  import { homedir as homedir6 } from "os";
14238
- import { join as join16 } from "path";
14410
+ import { join as join17 } from "path";
14239
14411
  var CATEGORIES, rememberTool;
14240
14412
  var init_remember = __esm(() => {
14241
14413
  init_i18n();
@@ -14273,7 +14445,7 @@ var init_remember = __esm(() => {
14273
14445
  if (!CATEGORIES.includes(category)) {
14274
14446
  return { success: false, output: t("tool.invalid_params") };
14275
14447
  }
14276
- const memoryDir = join16(homedir6(), ".mma", "memory");
14448
+ const memoryDir = join17(homedir6(), ".mma", "memory");
14277
14449
  const store = new MemoryStore(memoryDir);
14278
14450
  try {
14279
14451
  if (category === "preferences") {
@@ -14306,7 +14478,7 @@ var init_remember = __esm(() => {
14306
14478
 
14307
14479
  // src/tools/recall.ts
14308
14480
  import { homedir as homedir7 } from "os";
14309
- import { join as join17 } from "path";
14481
+ import { join as join18 } from "path";
14310
14482
  function formatAll(store) {
14311
14483
  const parts = [];
14312
14484
  const prefs = store.getPreferences();
@@ -14389,7 +14561,7 @@ var init_recall = __esm(() => {
14389
14561
  handler: async (_ctx, args) => {
14390
14562
  const query = args.query ? String(args.query) : "";
14391
14563
  const category = args.category ? String(args.category) : "";
14392
- const memoryDir = join17(homedir7(), ".mma", "memory");
14564
+ const memoryDir = join18(homedir7(), ".mma", "memory");
14393
14565
  const store = new MemoryStore(memoryDir);
14394
14566
  try {
14395
14567
  if (!query && !category) {
@@ -14421,9 +14593,9 @@ var init_recall = __esm(() => {
14421
14593
  });
14422
14594
 
14423
14595
  // src/modules/browser/bridge-path.ts
14424
- import { existsSync as existsSync25 } from "fs";
14596
+ import { existsSync as existsSync26 } from "fs";
14425
14597
  function pickExistingPath(candidates, fallback = candidates[0]) {
14426
- return candidates.find((p) => existsSync25(p)) ?? fallback;
14598
+ return candidates.find((p) => existsSync26(p)) ?? fallback;
14427
14599
  }
14428
14600
  var init_bridge_path = () => {};
14429
14601
 
@@ -14434,13 +14606,13 @@ __export(exports_bridge_client, {
14434
14606
  });
14435
14607
  import { spawn as spawn4 } from "child_process";
14436
14608
  import { createInterface } from "readline";
14437
- import { dirname as dirname9, join as join18 } from "path";
14609
+ import { dirname as dirname9, join as join19 } from "path";
14438
14610
  import { fileURLToPath } from "url";
14439
14611
  function bridgeScriptPath() {
14440
14612
  const dir = dirname9(fileURLToPath(import.meta.url));
14441
14613
  const candidates = [
14442
- join18(dir, "bridge-server.mjs"),
14443
- join18(dir, "modules", "browser", "bridge-server.mjs")
14614
+ join19(dir, "bridge-server.mjs"),
14615
+ join19(dir, "modules", "browser", "bridge-server.mjs")
14444
14616
  ];
14445
14617
  return pickExistingPath(candidates);
14446
14618
  }
@@ -15000,15 +15172,15 @@ function buildTextExtractionScript() {
15000
15172
 
15001
15173
  // src/modules/browser/cookie-store.ts
15002
15174
  import { readFile, writeFile, mkdir } from "fs/promises";
15003
- import { join as join19 } from "path";
15175
+ import { join as join20 } from "path";
15004
15176
 
15005
15177
  class CookieStore {
15006
15178
  filePath;
15007
15179
  constructor(cookieDir) {
15008
- this.filePath = join19(cookieDir, "cookies.json");
15180
+ this.filePath = join20(cookieDir, "cookies.json");
15009
15181
  }
15010
15182
  async save(cookies) {
15011
- await mkdir(join19(this.filePath, ".."), { recursive: true });
15183
+ await mkdir(join20(this.filePath, ".."), { recursive: true });
15012
15184
  await writeFile(this.filePath, JSON.stringify(cookies, null, 2), "utf-8");
15013
15185
  }
15014
15186
  async load() {
@@ -15363,10 +15535,10 @@ var init_session = __esm(() => {
15363
15535
  });
15364
15536
 
15365
15537
  // src/tools/browser.ts
15366
- import { join as join20 } from "path";
15538
+ import { join as join21 } from "path";
15367
15539
  function getSession(ctx) {
15368
15540
  if (!session) {
15369
- const cookieDir = join20(ctx.baseDir, ".mma", "browser");
15541
+ const cookieDir = join21(ctx.baseDir, ".mma", "browser");
15370
15542
  session = new BrowserSession({
15371
15543
  ...DEFAULT_BROWSER_CONFIG,
15372
15544
  headless: ctx.config.browser?.headless ?? true,
@@ -15499,13 +15671,13 @@ async function readClipboardImage() {
15499
15671
  return readClipboardFallback();
15500
15672
  }
15501
15673
  async function readClipboardFallback() {
15502
- const { platform: platform3 } = await import("os");
15674
+ const { platform: platform5 } = await import("os");
15503
15675
  const { execSync } = await import("child_process");
15504
15676
  const { readFileSync: readFileSync15, unlinkSync: unlinkSync4 } = await import("fs");
15505
- const { join: join21 } = await import("path");
15506
- const tmpPath = join21(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
15677
+ const { join: join22 } = await import("path");
15678
+ const tmpPath = join22(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
15507
15679
  try {
15508
- if (platform3() === "linux") {
15680
+ if (platform5() === "linux") {
15509
15681
  execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, { timeout: 5000 });
15510
15682
  } else {
15511
15683
  return null;
@@ -15581,7 +15753,7 @@ var init_image_utils = __esm(() => {
15581
15753
  });
15582
15754
 
15583
15755
  // src/tools/attach-image.ts
15584
- import { existsSync as existsSync26 } from "fs";
15756
+ import { existsSync as existsSync27 } from "fs";
15585
15757
  import { resolve as resolve15 } from "path";
15586
15758
  var attachImageTool;
15587
15759
  var init_attach_image = __esm(() => {
@@ -15624,7 +15796,7 @@ var init_attach_image = __esm(() => {
15624
15796
  dataUrl = result.dataUrl;
15625
15797
  } else {
15626
15798
  const absPath = resolve15(ctx.baseDir, source);
15627
- if (!existsSync26(absPath)) {
15799
+ if (!existsSync27(absPath)) {
15628
15800
  return {
15629
15801
  success: false,
15630
15802
  output: t("image.not_found", { path: source })
@@ -15786,44 +15958,59 @@ class ModuleRegistry {
15786
15958
  }
15787
15959
 
15788
15960
  // src/modules/plugins/loader.ts
15789
- import { readdirSync as readdirSync7, existsSync as existsSync27, statSync as statSync5 } from "fs";
15790
- import { join as join21, basename as basename2 } from "path";
15961
+ import { readdirSync as readdirSync7, existsSync as existsSync28, statSync as statSync5 } from "fs";
15962
+ import { join as join22, basename as basename2 } from "path";
15791
15963
 
15792
15964
  class PluginLoader {
15793
- loadFromDir(dirPath, pluginManager, logger) {
15794
- if (!existsSync27(dirPath))
15965
+ loadFromDir(dirPath, pluginManager, logger, options) {
15966
+ if (!existsSync28(dirPath))
15795
15967
  return;
15796
15968
  const entries = readdirSync7(dirPath).sort();
15797
15969
  for (const entry of entries) {
15798
- const fullPath = join21(dirPath, entry);
15970
+ const fullPath = join22(dirPath, entry);
15799
15971
  const stat = statSync5(fullPath);
15800
15972
  if (stat.isFile()) {
15801
15973
  if (!entry.endsWith(".ts") && !entry.endsWith(".js"))
15802
15974
  continue;
15803
- this.tryLoad(fullPath, entry, pluginManager, logger);
15975
+ this.tryLoad(fullPath, entry, pluginManager, logger, options);
15804
15976
  } else if (stat.isDirectory()) {
15805
15977
  const entryFile = this.findEntryFile(fullPath);
15806
15978
  if (entryFile) {
15807
- this.tryLoad(entryFile, `${entry}/${basename2(entryFile)}`, pluginManager, logger);
15979
+ this.tryLoad(entryFile, `${entry}/${basename2(entryFile)}`, pluginManager, logger, options);
15808
15980
  }
15809
15981
  }
15810
15982
  }
15811
15983
  }
15812
15984
  findEntryFile(dir) {
15813
15985
  for (const name of FOLDER_ENTRY_NAMES) {
15814
- const candidate = join21(dir, name);
15815
- if (existsSync27(candidate))
15986
+ const candidate = join22(dir, name);
15987
+ if (existsSync28(candidate))
15816
15988
  return candidate;
15817
15989
  }
15818
15990
  return null;
15819
15991
  }
15820
- tryLoad(fullPath, label, pluginManager, logger) {
15992
+ tryLoad(fullPath, label, pluginManager, logger, options) {
15821
15993
  try {
15822
15994
  const mod = __require(fullPath);
15823
15995
  const plugin = mod.default || mod.plugin;
15824
15996
  if (plugin && plugin.name) {
15825
- pluginManager.register(plugin);
15826
- logger?.warn(t("plugin.loaded", { name: plugin.name }));
15997
+ if (plugin.minMmaVersion && options?.mmaVersion && semverGt(plugin.minMmaVersion, options.mmaVersion)) {
15998
+ logger?.warn(t("plugin.incompatible", {
15999
+ name: plugin.name,
16000
+ min: plugin.minMmaVersion,
16001
+ current: options.mmaVersion
16002
+ }));
16003
+ return;
16004
+ }
16005
+ const result = pluginManager.register(plugin, options?.source);
16006
+ if (result.status === "registered") {
16007
+ logger?.warn(t("plugin.loaded", { name: plugin.name }));
16008
+ } else if (result.status === "skipped_older") {
16009
+ logger?.warn(t("plugin.dedup_older", {
16010
+ name: plugin.name,
16011
+ version: plugin.version || "0.0.0"
16012
+ }));
16013
+ }
15827
16014
  }
15828
16015
  } catch (e) {
15829
16016
  logger?.warn(t("plugin.skipped", { entry: label, message: e.message }));
@@ -15833,14 +16020,15 @@ class PluginLoader {
15833
16020
  var FOLDER_ENTRY_NAMES;
15834
16021
  var init_loader = __esm(() => {
15835
16022
  init_i18n();
16023
+ init_checker();
15836
16024
  FOLDER_ENTRY_NAMES = ["plugin.ts", "plugin.js", "index.ts", "index.js"];
15837
16025
  });
15838
16026
 
15839
16027
  // src/modules/plugins/builtin/lint-on-write.ts
15840
16028
  import { spawn as spawn5, execSync } from "child_process";
15841
- import { existsSync as existsSync28, readFileSync as readFileSync15 } from "fs";
15842
- import { resolve as resolve16, extname as extname4, join as join22 } from "path";
15843
- import { platform as platform3 } from "os";
16029
+ import { existsSync as existsSync29, readFileSync as readFileSync15 } from "fs";
16030
+ import { resolve as resolve16, extname as extname4, join as join23 } from "path";
16031
+ import { platform as platform5 } from "os";
15844
16032
  function contentHash(content) {
15845
16033
  let h = 5381;
15846
16034
  for (let i = 0;i < content.length; i++) {
@@ -15850,7 +16038,7 @@ function contentHash(content) {
15850
16038
  }
15851
16039
  function getWinDecoder() {
15852
16040
  if (_winDecoder === undefined) {
15853
- if (platform3() !== "win32") {
16041
+ if (platform5() !== "win32") {
15854
16042
  _winDecoder = null;
15855
16043
  } else {
15856
16044
  try {
@@ -15872,6 +16060,7 @@ function getWinDecoder() {
15872
16060
  class LintOnWritePlugin {
15873
16061
  name = "lint-on-write";
15874
16062
  priority = 10;
16063
+ isBuiltin = true;
15875
16064
  _checkPromise = null;
15876
16065
  _checkTimestamp = 0;
15877
16066
  async onAfterTool(ctx, call, result) {
@@ -15885,7 +16074,7 @@ class LintOnWritePlugin {
15885
16074
  if (!path)
15886
16075
  return;
15887
16076
  const fullPath = resolve16(ctx.baseDir, path);
15888
- if (!existsSync28(fullPath))
16077
+ if (!existsSync29(fullPath))
15889
16078
  return;
15890
16079
  const ext = extname4(fullPath);
15891
16080
  const syntaxError = await this.checkSyntax(fullPath, ext, ctx.baseDir);
@@ -15941,8 +16130,8 @@ class LintOnWritePlugin {
15941
16130
  }
15942
16131
  async runProjectLint(ctx, result) {
15943
16132
  try {
15944
- const packageJsonPath = join22(ctx.baseDir, "package.json");
15945
- if (!existsSync28(packageJsonPath)) {
16133
+ const packageJsonPath = join23(ctx.baseDir, "package.json");
16134
+ if (!existsSync29(packageJsonPath)) {
15946
16135
  return;
15947
16136
  }
15948
16137
  const packageJson = JSON.parse(readFileSync15(packageJsonPath, "utf-8"));
@@ -15965,8 +16154,8 @@ class LintOnWritePlugin {
15965
16154
  "tsconfig.json",
15966
16155
  "package.json"
15967
16156
  ]);
15968
- const tsconfigPath = join22(projectRoot, "tsconfig.json");
15969
- if (!existsSync28(tsconfigPath)) {
16157
+ const tsconfigPath = join23(projectRoot, "tsconfig.json");
16158
+ if (!existsSync29(tsconfigPath)) {
15970
16159
  return;
15971
16160
  }
15972
16161
  const now = Date.now();
@@ -16058,6 +16247,7 @@ var init_lint_on_write = __esm(() => {
16058
16247
  class NotifyPlugin {
16059
16248
  name = "notify";
16060
16249
  priority = 5;
16250
+ isBuiltin = true;
16061
16251
  onSessionEnd(ctx) {
16062
16252
  ctx.logger.info("Session ended");
16063
16253
  }
@@ -16214,8 +16404,8 @@ class PlanTracker {
16214
16404
  var init_tracker = () => {};
16215
16405
 
16216
16406
  // src/modules/execution/audit-runners.ts
16217
- import { existsSync as existsSync29, readdirSync as readdirSync8 } from "fs";
16218
- import { dirname as dirname10, join as join23, resolve as resolve17 } from "path";
16407
+ import { existsSync as existsSync30, readdirSync as readdirSync8 } from "fs";
16408
+ import { dirname as dirname10, join as join24, resolve as resolve17 } from "path";
16219
16409
  function findTestFile(dir, depth = 0) {
16220
16410
  if (depth > 5)
16221
16411
  return null;
@@ -16226,7 +16416,7 @@ function findTestFile(dir, depth = 0) {
16226
16416
  return null;
16227
16417
  }
16228
16418
  for (const e of entries) {
16229
- const full = join23(dir, e.name);
16419
+ const full = join24(dir, e.name);
16230
16420
  if (e.isDirectory()) {
16231
16421
  if (SKIP_DIRS.has(e.name))
16232
16422
  continue;
@@ -16301,7 +16491,7 @@ function findTypecheckRoot(baseDir, existingFiles = []) {
16301
16491
  for (const start of candidates) {
16302
16492
  let dir = resolve17(start);
16303
16493
  for (let depth = 0;depth <= 10; depth++) {
16304
- if (existsSync29(join23(dir, "tsconfig.json"))) {
16494
+ if (existsSync30(join24(dir, "tsconfig.json"))) {
16305
16495
  if (!best || depth < best.depth)
16306
16496
  best = { depth, root: dir };
16307
16497
  break;
@@ -16344,11 +16534,11 @@ var init_audit_runners = __esm(() => {
16344
16534
  });
16345
16535
 
16346
16536
  // src/modules/execution/auditor.ts
16347
- import { existsSync as existsSync30, readdirSync as readdirSync9 } from "fs";
16348
- import { resolve as resolve18, join as join24, basename as basename3 } from "path";
16537
+ import { existsSync as existsSync31, readdirSync as readdirSync9 } from "fs";
16538
+ import { resolve as resolve18, join as join25, basename as basename3 } from "path";
16349
16539
  function findExistingFile(baseDir, filePath) {
16350
16540
  const direct = resolve18(baseDir, filePath);
16351
- if (existsSync30(direct))
16541
+ if (existsSync31(direct))
16352
16542
  return direct;
16353
16543
  const name = basename3(filePath).toLowerCase();
16354
16544
  const suffix = filePath.replace(/\\/g, "/").toLowerCase();
@@ -16365,7 +16555,7 @@ function findExistingFile(baseDir, filePath) {
16365
16555
  for (const e of entries) {
16366
16556
  if (found)
16367
16557
  return;
16368
- const full = join24(dir, e.name);
16558
+ const full = join25(dir, e.name);
16369
16559
  if (e.isDirectory()) {
16370
16560
  if (SKIP_DIRS.has(e.name))
16371
16561
  continue;
@@ -16503,8 +16693,8 @@ var init_auditor = __esm(() => {
16503
16693
  });
16504
16694
 
16505
16695
  // src/modules/execution/plan-store.ts
16506
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync31, readdirSync as readdirSync10, rmSync } from "fs";
16507
- import { join as join25 } from "path";
16696
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync32, readdirSync as readdirSync10, rmSync } from "fs";
16697
+ import { join as join26 } from "path";
16508
16698
  function readPlanFile(path, fallbackBaseDir) {
16509
16699
  try {
16510
16700
  const raw = readFileSync16(path, "utf-8");
@@ -16529,10 +16719,10 @@ function writePlanFile(path, plan) {
16529
16719
  writeFileSync10(path, JSON.stringify(plan, null, 2), "utf-8");
16530
16720
  }
16531
16721
  function listDir(dir, baseDir) {
16532
- if (!existsSync31(dir))
16722
+ if (!existsSync32(dir))
16533
16723
  return [];
16534
16724
  const files = readdirSync10(dir).filter((f) => f.endsWith(".json"));
16535
- return files.map((f) => readPlanFile(join25(dir, f), baseDir)).filter((p) => p !== null);
16725
+ return files.map((f) => readPlanFile(join26(dir, f), baseDir)).filter((p) => p !== null);
16536
16726
  }
16537
16727
  function toMeta(plan, status) {
16538
16728
  return {
@@ -16553,33 +16743,33 @@ class PlanStore {
16553
16743
  archiveDir;
16554
16744
  legacyPath;
16555
16745
  constructor(baseDir) {
16556
- const mmaDir = join25(baseDir, ".mma");
16557
- if (!existsSync31(mmaDir))
16746
+ const mmaDir = join26(baseDir, ".mma");
16747
+ if (!existsSync32(mmaDir))
16558
16748
  mkdirSync14(mmaDir, { recursive: true });
16559
16749
  this.baseDir = baseDir;
16560
- this.plansDir = join25(mmaDir, "plans");
16561
- this.draftsDir = join25(this.plansDir, "drafts");
16562
- this.archiveDir = join25(this.plansDir, "archive");
16563
- this.legacyPath = join25(mmaDir, LEGACY_FILE);
16750
+ this.plansDir = join26(mmaDir, "plans");
16751
+ this.draftsDir = join26(this.plansDir, "drafts");
16752
+ this.archiveDir = join26(this.plansDir, "archive");
16753
+ this.legacyPath = join26(mmaDir, LEGACY_FILE);
16564
16754
  for (const dir of [this.plansDir, this.draftsDir, this.archiveDir]) {
16565
- if (!existsSync31(dir))
16755
+ if (!existsSync32(dir))
16566
16756
  mkdirSync14(dir, { recursive: true });
16567
16757
  }
16568
16758
  }
16569
16759
  activePath() {
16570
- return join25(this.plansDir, "active.json");
16760
+ return join26(this.plansDir, "active.json");
16571
16761
  }
16572
16762
  saveActive(plan) {
16573
16763
  writePlanFile(this.activePath(), plan);
16574
16764
  }
16575
16765
  loadActive() {
16576
16766
  const activePath = this.activePath();
16577
- if (existsSync31(activePath)) {
16767
+ if (existsSync32(activePath)) {
16578
16768
  const plan = readPlanFile(activePath, this.baseDir);
16579
16769
  if (plan)
16580
16770
  return plan;
16581
16771
  }
16582
- if (existsSync31(this.legacyPath)) {
16772
+ if (existsSync32(this.legacyPath)) {
16583
16773
  const legacy = readPlanFile(this.legacyPath, this.baseDir);
16584
16774
  if (legacy) {
16585
16775
  this.saveActive(legacy);
@@ -16593,26 +16783,26 @@ class PlanStore {
16593
16783
  }
16594
16784
  clearActive() {
16595
16785
  const p = this.activePath();
16596
- if (existsSync31(p))
16786
+ if (existsSync32(p))
16597
16787
  rmSync(p, { force: true });
16598
16788
  }
16599
16789
  saveDraft(plan) {
16600
- writePlanFile(join25(this.draftsDir, `${plan.id}.json`), plan);
16790
+ writePlanFile(join26(this.draftsDir, `${plan.id}.json`), plan);
16601
16791
  }
16602
16792
  loadDraft(id) {
16603
- const p = join25(this.draftsDir, `${id}.json`);
16604
- return existsSync31(p) ? readPlanFile(p, this.baseDir) : null;
16793
+ const p = join26(this.draftsDir, `${id}.json`);
16794
+ return existsSync32(p) ? readPlanFile(p, this.baseDir) : null;
16605
16795
  }
16606
16796
  removeDraft(id) {
16607
- const p = join25(this.draftsDir, `${id}.json`);
16608
- if (existsSync31(p))
16797
+ const p = join26(this.draftsDir, `${id}.json`);
16798
+ if (existsSync32(p))
16609
16799
  rmSync(p, { force: true });
16610
16800
  }
16611
16801
  listDrafts() {
16612
16802
  return listDir(this.draftsDir, this.baseDir);
16613
16803
  }
16614
16804
  archivePlan(plan) {
16615
- writePlanFile(join25(this.archiveDir, `${plan.id}.json`), plan);
16805
+ writePlanFile(join26(this.archiveDir, `${plan.id}.json`), plan);
16616
16806
  this.removeDraft(plan.id);
16617
16807
  const active = this.loadActive();
16618
16808
  if (active && active.id === plan.id) {
@@ -16623,8 +16813,8 @@ class PlanStore {
16623
16813
  return listDir(this.archiveDir, this.baseDir);
16624
16814
  }
16625
16815
  removeArchived(id) {
16626
- const p = join25(this.archiveDir, `${id}.json`);
16627
- if (existsSync31(p))
16816
+ const p = join26(this.archiveDir, `${id}.json`);
16817
+ if (existsSync32(p))
16628
16818
  rmSync(p, { force: true });
16629
16819
  }
16630
16820
  listAll() {
@@ -17203,7 +17393,7 @@ var init_windows_commands = __esm(() => {
17203
17393
  });
17204
17394
 
17205
17395
  // src/modules/execution/execution-plugin.ts
17206
- import { platform as platform4 } from "os";
17396
+ import { platform as platform6 } from "os";
17207
17397
  function createExecutionPlugin(deps) {
17208
17398
  return {
17209
17399
  name: "execution",
@@ -17347,7 +17537,7 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
17347
17537
  deps.stuckDetector.recordToolError(call.name, toolText.slice(0, 300));
17348
17538
  }
17349
17539
  if (!result.success) {
17350
- if (call.name === "bash" && platform4() === "win32") {
17540
+ if (call.name === "bash" && platform6() === "win32") {
17351
17541
  const cmd = String(call.arguments?.command ?? "");
17352
17542
  const forbidden = forbiddenWindowsCommand(cmd);
17353
17543
  if (forbidden) {
@@ -17426,7 +17616,7 @@ var init_execution_plugin = __esm(() => {
17426
17616
  });
17427
17617
 
17428
17618
  // src/modules/execution/module.ts
17429
- import { existsSync as existsSync32, readFileSync as readFileSync17 } from "fs";
17619
+ import { existsSync as existsSync33, readFileSync as readFileSync17 } from "fs";
17430
17620
  import { resolve as resolve19 } from "path";
17431
17621
 
17432
17622
  class ExecutionModule {
@@ -17629,7 +17819,7 @@ class ExecutionModule {
17629
17819
  "poetry.lock",
17630
17820
  "requirements.txt"
17631
17821
  ];
17632
- const hasLockFile = lockFiles.some((f) => existsSync32(resolve19(this.baseDir, f)));
17822
+ const hasLockFile = lockFiles.some((f) => existsSync33(resolve19(this.baseDir, f)));
17633
17823
  if (!hasLockFile) {
17634
17824
  if (contextManager) {
17635
17825
  const hints = this.state.depsGateHints.get(step.id) || 0;
@@ -17649,8 +17839,8 @@ class ExecutionModule {
17649
17839
  }
17650
17840
  if (stepPaths.length === 0)
17651
17841
  return;
17652
- const allExist = stepPaths.every((p) => existsSync32(resolve19(this.baseDir, p)));
17653
- const allGone = stepPaths.every((p) => !existsSync32(resolve19(this.baseDir, p)));
17842
+ const allExist = stepPaths.every((p) => existsSync33(resolve19(this.baseDir, p)));
17843
+ const allGone = stepPaths.every((p) => !existsSync33(resolve19(this.baseDir, p)));
17654
17844
  const satisfied = step.kind === "delete" ? allGone && !allExist : allExist;
17655
17845
  if (!satisfied)
17656
17846
  return;
@@ -17756,11 +17946,11 @@ var init_module = __esm(() => {
17756
17946
  import {
17757
17947
  readFileSync as readFileSync18,
17758
17948
  writeFileSync as writeFileSync11,
17759
- existsSync as existsSync33,
17949
+ existsSync as existsSync34,
17760
17950
  readdirSync as readdirSync11,
17761
17951
  unlinkSync as unlinkSync4
17762
17952
  } from "fs";
17763
- import { join as join26 } from "path";
17953
+ import { join as join27 } from "path";
17764
17954
  import { homedir as homedir8 } from "os";
17765
17955
 
17766
17956
  class SessionFileEncryptor {
@@ -17769,7 +17959,7 @@ class SessionFileEncryptor {
17769
17959
  constructor(config) {
17770
17960
  this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
17771
17961
  this.encryptor = new ConfigEncryptor({
17772
- keyPath: config?.keyPath || join26(homedir8(), ".mma", ".session-encryption-key")
17962
+ keyPath: config?.keyPath || join27(homedir8(), ".mma", ".session-encryption-key")
17773
17963
  });
17774
17964
  }
17775
17965
  isEnabled() {
@@ -17855,8 +18045,8 @@ class SessionFileEncryptor {
17855
18045
  return;
17856
18046
  const files = readdirSync11(sessionDir);
17857
18047
  for (const file of files) {
17858
- const filePath = join26(sessionDir, file);
17859
- if (existsSync33(filePath) && !file.endsWith(".enc")) {
18048
+ const filePath = join27(sessionDir, file);
18049
+ if (existsSync34(filePath) && !file.endsWith(".enc")) {
17860
18050
  try {
17861
18051
  const content = readFileSync18(filePath, "utf8");
17862
18052
  const encrypted = this.encryptFileContent(content);
@@ -17872,7 +18062,7 @@ class SessionFileEncryptor {
17872
18062
  const files = readdirSync11(sessionDir);
17873
18063
  for (const file of files) {
17874
18064
  if (file.endsWith(".enc")) {
17875
- const encFilePath = join26(sessionDir, file);
18065
+ const encFilePath = join27(sessionDir, file);
17876
18066
  const decFilePath = encFilePath.slice(0, -4);
17877
18067
  try {
17878
18068
  const content = readFileSync18(encFilePath, "utf8");
@@ -17897,7 +18087,7 @@ var init_session_encryption = __esm(() => {
17897
18087
 
17898
18088
  // src/modules/session/store.ts
17899
18089
  import {
17900
- existsSync as existsSync34,
18090
+ existsSync as existsSync35,
17901
18091
  mkdirSync as mkdirSync15,
17902
18092
  readdirSync as readdirSync12,
17903
18093
  readFileSync as readFileSync19,
@@ -17905,7 +18095,7 @@ import {
17905
18095
  writeFileSync as writeFileSync12,
17906
18096
  appendFileSync as appendFileSync6
17907
18097
  } from "fs";
17908
- import { join as join27 } from "path";
18098
+ import { join as join28 } from "path";
17909
18099
  import { gzipSync } from "zlib";
17910
18100
 
17911
18101
  class SessionStore {
@@ -17919,7 +18109,7 @@ class SessionStore {
17919
18109
  }
17920
18110
  }
17921
18111
  getSessionDir(id) {
17922
- return join27(this.baseDir, id);
18112
+ return join28(this.baseDir, id);
17923
18113
  }
17924
18114
  updateEncryption(config) {
17925
18115
  if (config?.enabled) {
@@ -17935,19 +18125,19 @@ class SessionStore {
17935
18125
  mkdirSync15(this.baseDir, { recursive: true });
17936
18126
  }
17937
18127
  sessionDir(id) {
17938
- return join27(this.baseDir, id);
18128
+ return join28(this.baseDir, id);
17939
18129
  }
17940
18130
  metaPath(id) {
17941
- return join27(this.sessionDir(id), "meta.json");
18131
+ return join28(this.sessionDir(id), "meta.json");
17942
18132
  }
17943
18133
  historyPath(id) {
17944
- return join27(this.sessionDir(id), "history.jsonl");
18134
+ return join28(this.sessionDir(id), "history.jsonl");
17945
18135
  }
17946
18136
  sessionLogPath(id) {
17947
- return join27(this.sessionDir(id), "session.jsonl");
18137
+ return join28(this.sessionDir(id), "session.jsonl");
17948
18138
  }
17949
18139
  sessionExists(id) {
17950
- return existsSync34(this.metaPath(id));
18140
+ return existsSync35(this.metaPath(id));
17951
18141
  }
17952
18142
  saveMeta(id, meta) {
17953
18143
  this._metaCache.set(id, meta);
@@ -17965,7 +18155,7 @@ class SessionStore {
17965
18155
  if (cached)
17966
18156
  return cached;
17967
18157
  const path = this.metaPath(id);
17968
- if (!existsSync34(path))
18158
+ if (!existsSync35(path))
17969
18159
  return null;
17970
18160
  try {
17971
18161
  const raw = readFileSync19(path, "utf-8");
@@ -17997,7 +18187,7 @@ class SessionStore {
17997
18187
  }
17998
18188
  loadHistory(id) {
17999
18189
  const path = this.historyPath(id);
18000
- if (!existsSync34(path))
18190
+ if (!existsSync35(path))
18001
18191
  return [];
18002
18192
  try {
18003
18193
  const raw = readFileSync19(path, "utf-8");
@@ -18038,7 +18228,7 @@ class SessionStore {
18038
18228
  }
18039
18229
  loadSessionLog(id) {
18040
18230
  const path = this.sessionLogPath(id);
18041
- if (!existsSync34(path))
18231
+ if (!existsSync35(path))
18042
18232
  return [];
18043
18233
  try {
18044
18234
  const raw = readFileSync19(path, "utf-8");
@@ -18066,7 +18256,7 @@ class SessionStore {
18066
18256
  }
18067
18257
  }
18068
18258
  listSessions() {
18069
- if (!existsSync34(this.baseDir))
18259
+ if (!existsSync35(this.baseDir))
18070
18260
  return [];
18071
18261
  const entries = readdirSync12(this.baseDir, { withFileTypes: true });
18072
18262
  const sessions = [];
@@ -18083,7 +18273,7 @@ class SessionStore {
18083
18273
  deleteSession(id) {
18084
18274
  this._metaCache.delete(id);
18085
18275
  const dir = this.sessionDir(id);
18086
- if (existsSync34(dir)) {
18276
+ if (existsSync35(dir)) {
18087
18277
  rmSync2(dir, { recursive: true, force: true });
18088
18278
  }
18089
18279
  }
@@ -18095,10 +18285,10 @@ class SessionStore {
18095
18285
  const updatedAt = new Date(session2.updatedAt);
18096
18286
  if (updatedAt < thirtyDaysAgo) {
18097
18287
  const historyPath = this.historyPath(session2.id);
18098
- if (existsSync34(historyPath)) {
18288
+ if (existsSync35(historyPath)) {
18099
18289
  const content = readFileSync19(historyPath, "utf-8");
18100
18290
  const compressed = gzipSync(content);
18101
- const gzPath = join27(this.baseDir, `${session2.id}.jsonl.gz`);
18291
+ const gzPath = join28(this.baseDir, `${session2.id}.jsonl.gz`);
18102
18292
  writeFileSync12(gzPath, compressed);
18103
18293
  rmSync2(historyPath);
18104
18294
  }
@@ -18251,7 +18441,7 @@ class SessionManager {
18251
18441
  }
18252
18442
  }
18253
18443
  }
18254
- var init_manager2 = __esm(() => {
18444
+ var init_manager3 = __esm(() => {
18255
18445
  init_i18n();
18256
18446
  init_session_isolation();
18257
18447
  });
@@ -18287,7 +18477,7 @@ var init_module2 = __esm(() => {
18287
18477
  // src/modules/session/index.ts
18288
18478
  var init_session2 = __esm(() => {
18289
18479
  init_store3();
18290
- init_manager2();
18480
+ init_manager3();
18291
18481
  init_module2();
18292
18482
  });
18293
18483
 
@@ -18308,9 +18498,9 @@ class ProfileCompressor {
18308
18498
  }
18309
18499
 
18310
18500
  // src/modules/user-profile/profile.ts
18311
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync35, mkdirSync as mkdirSync16 } from "fs";
18312
- import { join as join28 } from "path";
18313
- import { homedir as homedir9, hostname, platform as platform5, type } from "os";
18501
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync36, mkdirSync as mkdirSync16 } from "fs";
18502
+ import { join as join29 } from "path";
18503
+ import { homedir as homedir9, hostname, platform as platform7, type } from "os";
18314
18504
  import { env } from "process";
18315
18505
 
18316
18506
  class UserProfile {
@@ -18322,7 +18512,7 @@ class UserProfile {
18322
18512
  }
18323
18513
  collect() {
18324
18514
  this.info = {
18325
- platform: platform5(),
18515
+ platform: platform7(),
18326
18516
  os: `${type()} ${hostname()}`,
18327
18517
  hostname: hostname(),
18328
18518
  shell: env.SHELL || env.ComSpec || "unknown",
@@ -18333,14 +18523,14 @@ class UserProfile {
18333
18523
  return this.info;
18334
18524
  }
18335
18525
  save() {
18336
- if (!existsSync35(this.profileDir)) {
18526
+ if (!existsSync36(this.profileDir)) {
18337
18527
  mkdirSync16(this.profileDir, { recursive: true });
18338
18528
  }
18339
- writeFileSync13(join28(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
18529
+ writeFileSync13(join29(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
18340
18530
  }
18341
18531
  load() {
18342
- const path = join28(this.profileDir, "profile.json");
18343
- if (!existsSync35(path))
18532
+ const path = join29(this.profileDir, "profile.json");
18533
+ if (!existsSync36(path))
18344
18534
  return null;
18345
18535
  try {
18346
18536
  const data = JSON.parse(readFileSync20(path, "utf-8"));
@@ -18378,12 +18568,12 @@ class UserProfile {
18378
18568
  var init_profile = () => {};
18379
18569
 
18380
18570
  // src/modules/skills/loader.ts
18381
- import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as existsSync36, statSync as statSync6 } from "fs";
18382
- import { join as join29 } from "path";
18571
+ import { readdirSync as readdirSync13, readFileSync as readFileSync21, existsSync as existsSync37, statSync as statSync6 } from "fs";
18572
+ import { join as join30 } from "path";
18383
18573
 
18384
18574
  class SkillsLoader {
18385
18575
  loadFromDir(dirPath) {
18386
- if (!existsSync36(dirPath))
18576
+ if (!existsSync37(dirPath))
18387
18577
  return [];
18388
18578
  const skills = [];
18389
18579
  this.scanDir(dirPath, skills);
@@ -18392,7 +18582,7 @@ class SkillsLoader {
18392
18582
  scanDir(dirPath, skills) {
18393
18583
  const entries = readdirSync13(dirPath);
18394
18584
  for (const entry of entries) {
18395
- const fullPath = join29(dirPath, entry);
18585
+ const fullPath = join30(dirPath, entry);
18396
18586
  const stat = statSync6(fullPath);
18397
18587
  if (stat.isDirectory()) {
18398
18588
  this.scanDir(fullPath, skills);
@@ -18635,45 +18825,10 @@ var init_browser2 = __esm(() => {
18635
18825
  init_types();
18636
18826
  });
18637
18827
 
18638
- // src/modules/lsp/command.ts
18639
- import { delimiter, join as join30 } from "path";
18640
- import { existsSync as existsSync37 } from "fs";
18641
- import { platform as platform6 } from "os";
18642
- function resolveSpawnCommand(command, platformName = platform6(), pathEnv = process.env.PATH ?? "") {
18643
- if (platformName !== "win32")
18644
- return command;
18645
- if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
18646
- return command;
18647
- }
18648
- const dirs = pathEnv.split(delimiter).filter(Boolean);
18649
- for (const dir of dirs) {
18650
- for (const ext of WIN_EXTS) {
18651
- const candidate = join30(dir, `${command}${ext}`);
18652
- if (existsSync37(candidate))
18653
- return `${command}${ext}`;
18654
- }
18655
- }
18656
- return command;
18657
- }
18658
- function buildWinCommandLine(command, args) {
18659
- const quote = (part) => {
18660
- if (part === "")
18661
- return '""';
18662
- if (!/[\s"&|^<>()%!]/.test(part))
18663
- return part;
18664
- return `"${part.replace(/"/g, "\\\"")}"`;
18665
- };
18666
- return [command, ...args].map(quote).join(" ");
18667
- }
18668
- var WIN_EXTS;
18669
- var init_command = __esm(() => {
18670
- WIN_EXTS = [".cmd", ".bat", ".exe", ".com"];
18671
- });
18672
-
18673
18828
  // src/modules/lsp/client.ts
18674
18829
  import { spawn as spawn6, execSync as execSync2 } from "child_process";
18675
18830
  import { resolve as resolve20 } from "path";
18676
- import { platform as platform7 } from "os";
18831
+ import { platform as platform8 } from "os";
18677
18832
 
18678
18833
  class LspClient {
18679
18834
  process = null;
@@ -18743,7 +18898,7 @@ class LspClient {
18743
18898
  }
18744
18899
  return new Promise((resolve21, reject) => {
18745
18900
  const args = config.args ?? [];
18746
- const isWin = platform7() === "win32";
18901
+ const isWin = platform8() === "win32";
18747
18902
  let spawnCommand = resolveSpawnCommand(config.command);
18748
18903
  let spawnArgs = args;
18749
18904
  const spawnOpts = {
@@ -19984,6 +20139,29 @@ var init_module8 = __esm(() => {
19984
20139
  MEMORY_MD_FILES = ["errors", "conventions", "decisions", "facts"];
19985
20140
  });
19986
20141
 
20142
+ // src/core/version.ts
20143
+ import { existsSync as existsSync42, readFileSync as readFileSync25 } from "fs";
20144
+ import { join as join35, dirname as dirname13 } from "path";
20145
+ import { fileURLToPath as fileURLToPath2 } from "url";
20146
+ function readMmaVersion() {
20147
+ const here = dirname13(fileURLToPath2(import.meta.url));
20148
+ const candidates = [
20149
+ join35(here, "..", "..", "package.json"),
20150
+ join35(here, "..", "package.json")
20151
+ ];
20152
+ for (const p of candidates) {
20153
+ if (existsSync42(p)) {
20154
+ try {
20155
+ const raw = JSON.parse(readFileSync25(p, "utf8"));
20156
+ if (raw.version)
20157
+ return raw.version;
20158
+ } catch {}
20159
+ }
20160
+ }
20161
+ return "0.0.0";
20162
+ }
20163
+ var init_version = () => {};
20164
+
19987
20165
  // src/core/bootstrap.ts
19988
20166
  var exports_bootstrap = {};
19989
20167
  __export(exports_bootstrap, {
@@ -19991,8 +20169,8 @@ __export(exports_bootstrap, {
19991
20169
  bootstrap: () => bootstrap
19992
20170
  });
19993
20171
  import { homedir as homedir11 } from "os";
19994
- import { join as join35, resolve as resolve23 } from "path";
19995
- import { existsSync as existsSync42, readFileSync as readFileSync25, writeFileSync as writeFileSync15 } from "fs";
20172
+ import { join as join36, resolve as resolve23 } from "path";
20173
+ import { existsSync as existsSync43, readFileSync as readFileSync26, writeFileSync as writeFileSync15 } from "fs";
19996
20174
  function buildSystemInfo(config, baseDir, profileCompressed) {
19997
20175
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
19998
20176
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -20018,8 +20196,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
20018
20196
  `);
20019
20197
  }
20020
20198
  async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
20021
- const dir = configDir || join35(homedir11(), ".mma");
20022
- const projectConfigPath = projectDir ? join35(projectDir, ".mmrc") : join35(process.cwd(), ".mmrc");
20199
+ const dir = configDir || join36(homedir11(), ".mma");
20200
+ const projectConfigPath = projectDir ? join36(projectDir, ".mmrc") : join36(process.cwd(), ".mmrc");
20023
20201
  const config = loadConfig({ configDir: dir, projectConfigPath });
20024
20202
  setLocale(config.locale);
20025
20203
  try {
@@ -20029,7 +20207,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
20029
20207
  }
20030
20208
  } catch {}
20031
20209
  const logger = new Logger(config.logLevel);
20032
- logger.setLogDir(join35(dir, "logs"));
20210
+ logger.setLogDir(join36(dir, "logs"));
20033
20211
  logger.debug("MMA bootstrap", {
20034
20212
  version: config.version,
20035
20213
  model: config.model
@@ -20051,7 +20229,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
20051
20229
  logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
20052
20230
  }
20053
20231
  }
20054
- const profile = new UserProfile(join35(dir));
20232
+ const profile = new UserProfile(join36(dir));
20055
20233
  profile.load() || profile.collect();
20056
20234
  profile.save();
20057
20235
  const llmProvider = new OpenAICompatProvider({
@@ -20063,7 +20241,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
20063
20241
  rateLimits: config.security?.rateLimits
20064
20242
  });
20065
20243
  const baseDir = projectDir ? resolve23(projectDir) : process.cwd();
20066
- const projectMapCacheDir = join35(baseDir, ".mma");
20244
+ const projectMapCacheDir = join36(baseDir, ".mma");
20067
20245
  const indexerModule = new IndexerModule({
20068
20246
  baseDir,
20069
20247
  cacheDir: projectMapCacheDir
@@ -20074,9 +20252,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
20074
20252
  logger.warn(`Project indexing failed: ${err.message}`);
20075
20253
  }
20076
20254
  const skillsLoader = new SkillsLoader;
20077
- const builtinDir = join35(import.meta.dirname, "skills", "builtin");
20078
- const globalDir = join35(homedir11(), ".agents", "skills");
20079
- const projectSkillsDir = join35(baseDir, ".mma", "skills");
20255
+ const builtinDir = join36(import.meta.dirname, "skills", "builtin");
20256
+ const globalDir = join36(homedir11(), ".agents", "skills");
20257
+ const projectSkillsDir = join36(baseDir, ".mma", "skills");
20080
20258
  const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
20081
20259
  const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
20082
20260
  const skillsModule = new SkillsModule(availableSkills, skillsBudget);
@@ -20090,11 +20268,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
20090
20268
  essential: true,
20091
20269
  estimatedTokens: Math.ceil(systemInfoContent.length / 4)
20092
20270
  };
20093
- const agentsMdGlobal = join35(dir, "AGENTS.md");
20094
- if (!existsSync42(agentsMdGlobal)) {
20271
+ const agentsMdGlobal = join36(dir, "AGENTS.md");
20272
+ if (!existsSync43(agentsMdGlobal)) {
20095
20273
  writeFileSync15(agentsMdGlobal, "", "utf-8");
20096
20274
  }
20097
- const sessionDir = join35(dir, "sessions");
20275
+ const sessionDir = join36(dir, "sessions");
20098
20276
  const sessionStore = new SessionStore(sessionDir);
20099
20277
  sessionStore.init();
20100
20278
  const sessionManager = new SessionManager(sessionStore, {
@@ -20161,7 +20339,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
20161
20339
  const mcpModule = new MCPModule(config);
20162
20340
  await mcpModule.initialize();
20163
20341
  moduleRegistry.register(mcpModule);
20164
- const memoryStore = new MemoryStore(join35(dir, "memory"));
20342
+ const memoryStore = new MemoryStore(join36(dir, "memory"));
20165
20343
  const memoryModule = new MemoryModule(memoryStore);
20166
20344
  moduleRegistry.register(memoryModule);
20167
20345
  if (config.browser.enabled) {
@@ -20212,10 +20390,17 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
20212
20390
  pluginManager.register(plugin);
20213
20391
  pluginManager.register(plugin2);
20214
20392
  const pluginLoader = new PluginLoader;
20215
- const globalPluginsDir = join35(homedir11(), ".mma", "plugins");
20216
- const projectPluginsDir = join35(baseDir, ".mma", "plugins");
20217
- pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
20218
- pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
20393
+ const globalPluginsDir = join36(homedir11(), ".mma", "plugins");
20394
+ const projectPluginsDir = join36(baseDir, ".mma", "plugins");
20395
+ const mmaVersion = readMmaVersion();
20396
+ pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger, {
20397
+ source: "global",
20398
+ mmaVersion
20399
+ });
20400
+ pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger, {
20401
+ source: "project",
20402
+ mmaVersion
20403
+ });
20219
20404
  contextManager.onCompact = (summary) => {
20220
20405
  const meta = sessionManager.getActiveMeta();
20221
20406
  if (!meta || !config.session.autoSave)
@@ -20232,13 +20417,13 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
20232
20417
  const skipAgentsMd = noAgentsMd === true;
20233
20418
  if (!skipAgentsMd) {
20234
20419
  const agentsMdCandidates = [
20235
- join35(baseDir, "AGENTS.md"),
20236
- join35(baseDir, ".mma", "AGENTS.md"),
20237
- join35(dir, "AGENTS.md")
20420
+ join36(baseDir, "AGENTS.md"),
20421
+ join36(baseDir, ".mma", "AGENTS.md"),
20422
+ join36(dir, "AGENTS.md")
20238
20423
  ];
20239
20424
  for (const p of agentsMdCandidates) {
20240
- if (existsSync42(p)) {
20241
- const content = readFileSync25(p, "utf-8").trim();
20425
+ if (existsSync43(p)) {
20426
+ const content = readFileSync26(p, "utf-8").trim();
20242
20427
  if (content) {
20243
20428
  agentsMdBlocks.push({
20244
20429
  content,
@@ -20302,6 +20487,7 @@ var init_bootstrap = __esm(() => {
20302
20487
  init_openai_compat();
20303
20488
  init_tools();
20304
20489
  init_executor();
20490
+ init_manager2();
20305
20491
  init_loader();
20306
20492
  init_lint_on_write();
20307
20493
  init_notify();
@@ -20320,6 +20506,7 @@ var init_bootstrap = __esm(() => {
20320
20506
  init_store2();
20321
20507
  init_i18n();
20322
20508
  init_agent();
20509
+ init_version();
20323
20510
  });
20324
20511
 
20325
20512
  // node_modules/ansi-regex/index.js
@@ -21092,20 +21279,20 @@ __export(exports_manifest, {
21092
21279
  getCertMark: () => getCertMark,
21093
21280
  MANIFEST_PATH: () => MANIFEST_PATH
21094
21281
  });
21095
- import { existsSync as existsSync43, readFileSync as readFileSync26, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
21282
+ import { existsSync as existsSync44, readFileSync as readFileSync27, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
21096
21283
  import { homedir as homedir13 } from "os";
21097
- import { join as join37 } from "path";
21284
+ import { join as join38 } from "path";
21098
21285
  function readManifest(path = MANIFEST_PATH) {
21099
21286
  try {
21100
- if (existsSync43(path)) {
21101
- const raw = JSON.parse(readFileSync26(path, "utf-8"));
21287
+ if (existsSync44(path)) {
21288
+ const raw = JSON.parse(readFileSync27(path, "utf-8"));
21102
21289
  return { version: 1, certifications: raw.certifications ?? [] };
21103
21290
  }
21104
21291
  } catch {}
21105
21292
  return { version: 1, certifications: [] };
21106
21293
  }
21107
21294
  function saveManifest(m, path = MANIFEST_PATH) {
21108
- mkdirSync18(join37(homedir13(), ".mma"), { recursive: true });
21295
+ mkdirSync18(join38(homedir13(), ".mma"), { recursive: true });
21109
21296
  writeFileSync16(path, JSON.stringify(m, null, 2), "utf-8");
21110
21297
  }
21111
21298
  function upsertCertification(entry, path = MANIFEST_PATH) {
@@ -21140,7 +21327,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
21140
21327
  }
21141
21328
  var MANIFEST_PATH;
21142
21329
  var init_manifest = __esm(() => {
21143
- MANIFEST_PATH = join37(homedir13(), ".mma", "certifications.json");
21330
+ MANIFEST_PATH = join38(homedir13(), ".mma", "certifications.json");
21144
21331
  });
21145
21332
 
21146
21333
  // node_modules/yaml/dist/nodes/identity.js
@@ -28263,8 +28450,8 @@ var init_scenarios = __esm(() => {
28263
28450
  });
28264
28451
 
28265
28452
  // src/modules/certification/loader.ts
28266
- import { existsSync as existsSync44, readdirSync as readdirSync15, readFileSync as readFileSync27 } from "fs";
28267
- import { join as join38 } from "path";
28453
+ import { existsSync as existsSync45, readdirSync as readdirSync15, readFileSync as readFileSync28 } from "fs";
28454
+ import { join as join39 } from "path";
28268
28455
  function validateScenario(s) {
28269
28456
  const errors2 = [];
28270
28457
  const isSkip = s.mode === "skip";
@@ -28313,12 +28500,12 @@ function loadScenarios(userDir) {
28313
28500
  else
28314
28501
  scenarios.push(s);
28315
28502
  }
28316
- if (userDir && existsSync44(userDir)) {
28503
+ if (userDir && existsSync45(userDir)) {
28317
28504
  for (const file of readdirSync15(userDir)) {
28318
28505
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
28319
28506
  continue;
28320
28507
  try {
28321
- const raw = readFileSync27(join38(userDir, file), "utf-8");
28508
+ const raw = readFileSync28(join39(userDir, file), "utf-8");
28322
28509
  const data = $parse(raw);
28323
28510
  const parsed = normalizeScenario(data, file);
28324
28511
  const errs = validateScenario(parsed);
@@ -28371,8 +28558,8 @@ var init_loader3 = __esm(() => {
28371
28558
  });
28372
28559
 
28373
28560
  // src/modules/certification/fact-checker.ts
28374
- import { existsSync as existsSync45, readFileSync as readFileSync28, statSync as statSync8 } from "fs";
28375
- import { join as join39 } from "path";
28561
+ import { existsSync as existsSync46, readFileSync as readFileSync29, statSync as statSync8 } from "fs";
28562
+ import { join as join40 } from "path";
28376
28563
  function checkSandbox(sandboxDir, checks, exitCode, output) {
28377
28564
  const failures = [];
28378
28565
  for (const check of checks) {
@@ -28389,16 +28576,16 @@ function runCheck(sandboxDir, check, exitCode, output) {
28389
28576
  case "outputContains":
28390
28577
  return output.includes(check.text);
28391
28578
  case "fileExists":
28392
- return isFile(join39(sandboxDir, check.path));
28579
+ return isFile(join40(sandboxDir, check.path));
28393
28580
  case "fileNotExists":
28394
- return !existsSync45(join39(sandboxDir, check.path));
28581
+ return !existsSync46(join40(sandboxDir, check.path));
28395
28582
  case "dirExists":
28396
- return isDir(join39(sandboxDir, check.path));
28583
+ return isDir(join40(sandboxDir, check.path));
28397
28584
  case "fileContent": {
28398
- const abs = join39(sandboxDir, check.path);
28585
+ const abs = join40(sandboxDir, check.path);
28399
28586
  if (!isFile(abs))
28400
28587
  return false;
28401
- const content = readFileSync28(abs, "utf-8");
28588
+ const content = readFileSync29(abs, "utf-8");
28402
28589
  if (check.contains !== undefined)
28403
28590
  return content.includes(check.contains);
28404
28591
  if (check.equals !== undefined)
@@ -28406,10 +28593,10 @@ function runCheck(sandboxDir, check, exitCode, output) {
28406
28593
  return false;
28407
28594
  }
28408
28595
  case "fileRegex": {
28409
- const abs = join39(sandboxDir, check.path);
28596
+ const abs = join40(sandboxDir, check.path);
28410
28597
  if (!isFile(abs))
28411
28598
  return false;
28412
- return new RegExp(check.pattern).test(readFileSync28(abs, "utf-8"));
28599
+ return new RegExp(check.pattern).test(readFileSync29(abs, "utf-8"));
28413
28600
  }
28414
28601
  default:
28415
28602
  return false;
@@ -28417,14 +28604,14 @@ function runCheck(sandboxDir, check, exitCode, output) {
28417
28604
  }
28418
28605
  function isFile(p) {
28419
28606
  try {
28420
- return existsSync45(p) && statSync8(p).isFile();
28607
+ return existsSync46(p) && statSync8(p).isFile();
28421
28608
  } catch {
28422
28609
  return false;
28423
28610
  }
28424
28611
  }
28425
28612
  function isDir(p) {
28426
28613
  try {
28427
- return existsSync45(p) && statSync8(p).isDirectory();
28614
+ return existsSync46(p) && statSync8(p).isDirectory();
28428
28615
  } catch {
28429
28616
  return false;
28430
28617
  }
@@ -28455,9 +28642,9 @@ var init_fact_checker = () => {};
28455
28642
 
28456
28643
  // src/modules/certification/runner.ts
28457
28644
  import { spawn as spawn7 } from "child_process";
28458
- import { existsSync as existsSync46, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
28459
- import { platform as platform8 } from "os";
28460
- import { join as join40, resolve as resolve24, dirname as dirname13 } from "path";
28645
+ import { existsSync as existsSync47, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
28646
+ import { platform as platform9 } from "os";
28647
+ import { join as join41, resolve as resolve24, dirname as dirname14 } from "path";
28461
28648
  async function runScenario(scenario, opts) {
28462
28649
  if (scenario.mode === "skip") {
28463
28650
  return {
@@ -28470,13 +28657,13 @@ async function runScenario(scenario, opts) {
28470
28657
  }
28471
28658
  const reps = scenario.reps ?? opts.defaultReps;
28472
28659
  const threshold = Math.min(scenario.passThreshold ?? opts.defaultThreshold, reps);
28473
- const runner = opts.runner ?? defaultRunner;
28660
+ const runner = opts.runner ?? defaultRunner2;
28474
28661
  const timeoutMs = opts.timeoutMs ?? 120000;
28475
28662
  const entryPoint = resolveMmaEntry(opts.mmaRoot);
28476
28663
  let passed = 0;
28477
28664
  let firstError;
28478
28665
  for (let i = 1;i <= reps; i++) {
28479
- const sandbox = join40(opts.sandboxBase, `run-${scenario.id}-${i}`);
28666
+ const sandbox = join41(opts.sandboxBase, `run-${scenario.id}-${i}`);
28480
28667
  let failures = [];
28481
28668
  let exitCode = -1;
28482
28669
  let output = "";
@@ -28537,20 +28724,20 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
28537
28724
  rmSync4(sandbox, { recursive: true, force: true });
28538
28725
  mkdirSync19(sandbox, { recursive: true });
28539
28726
  for (const f of scenario.fixtures ?? []) {
28540
- const src = join40(mmaRoot, f.source);
28541
- if (!existsSync46(src)) {
28727
+ const src = join41(mmaRoot, f.source);
28728
+ if (!existsSync47(src)) {
28542
28729
  throw new Error(`fixture missing: ${f.source}`);
28543
28730
  }
28544
- const dest = join40(sandbox, f.dest);
28545
- mkdirSync19(dirname13(dest), { recursive: true });
28731
+ const dest = join41(sandbox, f.dest);
28732
+ mkdirSync19(dirname14(dest), { recursive: true });
28546
28733
  cpSync2(src, dest);
28547
28734
  }
28548
28735
  }
28549
28736
  function resolveMmaEntry(mmaRoot) {
28550
- const dev = join40(mmaRoot, "src", "cli", "main.ts");
28551
- if (existsSync46(dev))
28737
+ const dev = join41(mmaRoot, "src", "cli", "main.ts");
28738
+ if (existsSync47(dev))
28552
28739
  return dev;
28553
- return join40(mmaRoot, "dist", "main.js");
28740
+ return join41(mmaRoot, "dist", "main.js");
28554
28741
  }
28555
28742
  function findMmaRoot(fromDir) {
28556
28743
  const candidates = [
@@ -28558,7 +28745,7 @@ function findMmaRoot(fromDir) {
28558
28745
  resolve24(fromDir, "..")
28559
28746
  ];
28560
28747
  for (const c of candidates) {
28561
- if (existsSync46(join40(c, "package.json")))
28748
+ if (existsSync47(join41(c, "package.json")))
28562
28749
  return c;
28563
28750
  }
28564
28751
  return process.cwd();
@@ -28567,7 +28754,7 @@ function killTree2(child) {
28567
28754
  const pid = child.pid;
28568
28755
  if (!pid)
28569
28756
  return;
28570
- if (platform8() === "win32") {
28757
+ if (platform9() === "win32") {
28571
28758
  spawn7("taskkill", ["/pid", String(pid), "/T", "/F"], {
28572
28759
  windowsHide: true,
28573
28760
  stdio: "ignore"
@@ -28582,7 +28769,7 @@ function killTree2(child) {
28582
28769
  } catch {}
28583
28770
  }
28584
28771
  }
28585
- var defaultRunner = (env2, cwd, args, timeoutMs) => new Promise((resolvePromise) => {
28772
+ var defaultRunner2 = (env2, cwd, args, timeoutMs) => new Promise((resolvePromise) => {
28586
28773
  const child = spawn7(process.execPath, args, {
28587
28774
  cwd,
28588
28775
  env: env2,
@@ -28626,15 +28813,15 @@ __export(exports_cli, {
28626
28813
  });
28627
28814
  import { rmSync as rmSync5 } from "fs";
28628
28815
  import { homedir as homedir14 } from "os";
28629
- import { join as join41, dirname as dirname14 } from "path";
28630
- import { fileURLToPath as fileURLToPath2 } from "url";
28631
- import { existsSync as existsSync47, readFileSync as readFileSync29 } from "fs";
28816
+ import { join as join42, dirname as dirname15 } from "path";
28817
+ import { fileURLToPath as fileURLToPath3 } from "url";
28818
+ import { existsSync as existsSync48, readFileSync as readFileSync30 } from "fs";
28632
28819
  function readVersion() {
28633
- const candidates = [join41(MMA_ROOT, "package.json")];
28820
+ const candidates = [join42(MMA_ROOT, "package.json")];
28634
28821
  for (const p of candidates) {
28635
- if (existsSync47(p)) {
28822
+ if (existsSync48(p)) {
28636
28823
  try {
28637
- const raw = JSON.parse(readFileSync29(p, "utf-8"));
28824
+ const raw = JSON.parse(readFileSync30(p, "utf-8"));
28638
28825
  if (raw.version)
28639
28826
  return raw.version;
28640
28827
  } catch {}
@@ -28670,7 +28857,7 @@ async function certify(opts) {
28670
28857
  return;
28671
28858
  }
28672
28859
  console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
28673
- const sandboxBase = join41(process.cwd(), ".mma", "certification");
28860
+ const sandboxBase = join42(process.cwd(), ".mma", "certification");
28674
28861
  const results = [];
28675
28862
  const total = selected.length;
28676
28863
  let idx = 0;
@@ -28782,9 +28969,9 @@ var init_cli = __esm(() => {
28782
28969
  init_loader3();
28783
28970
  init_runner2();
28784
28971
  init_manifest();
28785
- HERE = dirname14(fileURLToPath2(import.meta.url));
28972
+ HERE = dirname15(fileURLToPath3(import.meta.url));
28786
28973
  MMA_ROOT = findMmaRoot(HERE);
28787
- USER_SCENARIO_DIR = join41(homedir14(), ".mma", "certification", "scenarios");
28974
+ USER_SCENARIO_DIR = join42(homedir14(), ".mma", "certification", "scenarios");
28788
28975
  });
28789
28976
 
28790
28977
  // src/cli/repl-commands.ts
@@ -28793,20 +28980,20 @@ __export(exports_repl_commands, {
28793
28980
  registerAllCommands: () => registerAllCommands,
28794
28981
  COMMAND_GROUPS: () => COMMAND_GROUPS
28795
28982
  });
28796
- import { join as join43, dirname as dirname16 } from "path";
28983
+ import { join as join44, dirname as dirname17 } from "path";
28797
28984
  import { homedir as homedir16 } from "os";
28798
- import { existsSync as existsSync49, readFileSync as readFileSync31 } from "fs";
28799
- import { fileURLToPath as fileURLToPath4 } from "url";
28985
+ import { existsSync as existsSync50, readFileSync as readFileSync32 } from "fs";
28986
+ import { fileURLToPath as fileURLToPath5 } from "url";
28800
28987
  function readVersion3() {
28801
- const here = dirname16(fileURLToPath4(import.meta.url));
28988
+ const here = dirname17(fileURLToPath5(import.meta.url));
28802
28989
  const candidates = [
28803
- join43(here, "..", "..", "package.json"),
28804
- join43(here, "..", "package.json")
28990
+ join44(here, "..", "..", "package.json"),
28991
+ join44(here, "..", "package.json")
28805
28992
  ];
28806
28993
  for (const p of candidates) {
28807
- if (existsSync49(p)) {
28994
+ if (existsSync50(p)) {
28808
28995
  try {
28809
- const raw = JSON.parse(readFileSync31(p, "utf8"));
28996
+ const raw = JSON.parse(readFileSync32(p, "utf8"));
28810
28997
  if (raw.version)
28811
28998
  return raw.version;
28812
28999
  } catch {}
@@ -28870,7 +29057,7 @@ function registerMmaCommands(ctx) {
28870
29057
  }
28871
29058
  try {
28872
29059
  const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
28873
- const { existsSync: existsSync50 } = await import("fs");
29060
+ const { existsSync: existsSync51 } = await import("fs");
28874
29061
  const { resolve: resolve25 } = await import("path");
28875
29062
  let dataUrl;
28876
29063
  let label;
@@ -28890,7 +29077,7 @@ function registerMmaCommands(ctx) {
28890
29077
  label = source;
28891
29078
  } else {
28892
29079
  const absPath = resolve25(process.cwd(), source);
28893
- if (!existsSync50(absPath)) {
29080
+ if (!existsSync51(absPath)) {
28894
29081
  console.log(pc2.red(t("image.not_found", { path: source })));
28895
29082
  return;
28896
29083
  }
@@ -28969,7 +29156,7 @@ function registerMmaCommands(ctx) {
28969
29156
  console.log(pc2.yellow(t("repl.wizard_running")));
28970
29157
  await ctx.withExclusiveInput(async () => {
28971
29158
  const answers = await runSetup(ctx.rl);
28972
- const configPath = join43(homedir16(), ".mma", "config.json");
29159
+ const configPath = join44(homedir16(), ".mma", "config.json");
28973
29160
  ctx.config.provider.type = answers.provider;
28974
29161
  ctx.config.provider.baseUrl = answers.apiBase;
28975
29162
  ctx.config.provider.apiKey = answers.apiKey;
@@ -29023,7 +29210,7 @@ Excluded blocks: ${info.excluded.length}`));
29023
29210
  return;
29024
29211
  }
29025
29212
  ctx.config.provider.type = name;
29026
- const configPath = join43(homedir16(), ".mma", "config.json");
29213
+ const configPath = join44(homedir16(), ".mma", "config.json");
29027
29214
  saveConfig(ctx.config, configPath);
29028
29215
  await ctx.agent.reconfigure(ctx.config);
29029
29216
  console.log(pc2.green(t("repl.provider_set", { name })));
@@ -29079,7 +29266,7 @@ Excluded blocks: ${info.excluded.length}`));
29079
29266
  return;
29080
29267
  }
29081
29268
  ctx.config.model = name;
29082
- const configPath = join43(homedir16(), ".mma", "config.json");
29269
+ const configPath = join44(homedir16(), ".mma", "config.json");
29083
29270
  saveConfig(ctx.config, configPath);
29084
29271
  await ctx.agent.reconfigure(ctx.config);
29085
29272
  console.log(pc2.green(t("repl.model_set", { name })));
@@ -29104,7 +29291,7 @@ Excluded blocks: ${info.excluded.length}`));
29104
29291
  return;
29105
29292
  }
29106
29293
  ctx.config.contextWindow = size;
29107
- const configPath = join43(homedir16(), ".mma", "config.json");
29294
+ const configPath = join44(homedir16(), ".mma", "config.json");
29108
29295
  saveConfig(ctx.config, configPath);
29109
29296
  await ctx.agent.reconfigure(ctx.config);
29110
29297
  console.log(pc2.green(t("cli.context_set", { size })));
@@ -29123,10 +29310,10 @@ Excluded blocks: ${info.excluded.length}`));
29123
29310
  ctx.agent.shutdown();
29124
29311
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
29125
29312
  const { homedir: homedir17 } = await import("os");
29126
- const { join: join44 } = await import("path");
29313
+ const { join: join45 } = await import("path");
29127
29314
  const configDir = ctx.configDir;
29128
29315
  const baseDir = ctx.baseDir;
29129
- const projectConfigPath = join44(baseDir, ".mmrc");
29316
+ const projectConfigPath = join45(baseDir, ".mmrc");
29130
29317
  const freshConfig = loadConfig2({ configDir, projectConfigPath });
29131
29318
  Object.assign(ctx.config, freshConfig);
29132
29319
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
@@ -29142,6 +29329,41 @@ Excluded blocks: ${info.excluded.length}`));
29142
29329
  console.log(`${t("repl.provider")} ${ctx.config.provider.type} @ ${ctx.config.provider.baseUrl}`);
29143
29330
  }
29144
29331
  });
29332
+ ctx.registerCommand({
29333
+ name: "plugins",
29334
+ description: t("repl.plugins"),
29335
+ usage: t("repl.plugins_usage"),
29336
+ action: (args) => {
29337
+ if (!ctx.pluginManager) {
29338
+ console.log(t("cli.plugins.none"));
29339
+ return;
29340
+ }
29341
+ const showAll = args.includes("--all");
29342
+ const infos = ctx.pluginManager.getPluginInfos();
29343
+ const filtered = showAll ? infos : infos.filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
29344
+ if (filtered.length === 0) {
29345
+ console.log(t("cli.plugins.none"));
29346
+ return;
29347
+ }
29348
+ const mmaVersion = version2;
29349
+ console.log(t("cli.plugins.header", {
29350
+ count: String(filtered.length),
29351
+ mma: mmaVersion
29352
+ }));
29353
+ for (const { plugin: plugin3, source } of filtered) {
29354
+ const v = plugin3.version || "-";
29355
+ const origin = source || "builtin";
29356
+ const mark = plugin3.isBuiltin ? t("cli.plugins.builtin_mark") : " ";
29357
+ console.log(` ${mark} ${plugin3.name} v${v} [${origin}]`);
29358
+ }
29359
+ if (!showAll) {
29360
+ const builtinCount = infos.filter(({ plugin: plugin3 }) => plugin3.isBuiltin).length;
29361
+ if (builtinCount > 0) {
29362
+ console.log(pc2.dim(` (${builtinCount} builtin hidden — /plugins --all to show)`));
29363
+ }
29364
+ }
29365
+ }
29366
+ });
29145
29367
  }
29146
29368
  function registerSessionCommands(ctx) {
29147
29369
  if (!ctx.sessionManager)
@@ -29401,7 +29623,8 @@ var init_repl_commands = __esm(() => {
29401
29623
  resume: "session",
29402
29624
  rename: "session",
29403
29625
  delete: "session",
29404
- skill: "skill"
29626
+ skill: "skill",
29627
+ plugins: "agent"
29405
29628
  };
29406
29629
  });
29407
29630
 
@@ -29426,14 +29649,14 @@ init_bootstrap();
29426
29649
  init_config2();
29427
29650
  init_setup();
29428
29651
  init_i18n();
29429
- import { join as join42, dirname as dirname15 } from "path";
29652
+ import { join as join43, dirname as dirname16 } from "path";
29430
29653
  import { homedir as homedir15 } from "os";
29431
- import { existsSync as existsSync48, readFileSync as readFileSync30 } from "fs";
29654
+ import { existsSync as existsSync49, readFileSync as readFileSync31 } from "fs";
29432
29655
 
29433
29656
  // src/cli/security-commands.ts
29434
29657
  init_bootstrap();
29435
29658
  init_config2();
29436
- import { join as join36 } from "path";
29659
+ import { join as join37 } from "path";
29437
29660
  import { homedir as homedir12 } from "os";
29438
29661
 
29439
29662
  // src/modules/security/security-policies.ts
@@ -29963,7 +30186,7 @@ function createSecurityCommand(program2) {
29963
30186
  }
29964
30187
  });
29965
30188
  securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
29966
- const configPath = join36(homedir12(), ".mma", "config.json");
30189
+ const configPath = join37(homedir12(), ".mma", "config.json");
29967
30190
  const { config: appConfig } = await bootstrap();
29968
30191
  const validPresets = ["strict", "balanced", "permissive"];
29969
30192
  if (!validPresets.includes(preset)) {
@@ -29978,7 +30201,7 @@ function createSecurityCommand(program2) {
29978
30201
  console.log(t("cli.security.policy_description", { description: policy.description }));
29979
30202
  });
29980
30203
  securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
29981
- const configPath = join36(homedir12(), ".mma", "config.json");
30204
+ const configPath = join37(homedir12(), ".mma", "config.json");
29982
30205
  const { config: appConfig } = await bootstrap();
29983
30206
  appConfig.security = appConfig.security || {};
29984
30207
  appConfig.security.sessionEncryption = {
@@ -29990,7 +30213,7 @@ function createSecurityCommand(program2) {
29990
30213
  console.log(t("cli.security.encryption_enabled"));
29991
30214
  });
29992
30215
  securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
29993
- const configPath = join36(homedir12(), ".mma", "config.json");
30216
+ const configPath = join37(homedir12(), ".mma", "config.json");
29994
30217
  const { config: appConfig } = await bootstrap();
29995
30218
  appConfig.security = appConfig.security || {};
29996
30219
  appConfig.security.sessionEncryption = {
@@ -30002,7 +30225,7 @@ function createSecurityCommand(program2) {
30002
30225
  console.log(t("cli.security.encryption_disabled"));
30003
30226
  });
30004
30227
  securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
30005
- const configPath = join36(homedir12(), ".mma", "config.json");
30228
+ const configPath = join37(homedir12(), ".mma", "config.json");
30006
30229
  const { config: appConfig } = await bootstrap();
30007
30230
  appConfig.security = appConfig.security || {};
30008
30231
  appConfig.security.auditNotifier = {
@@ -30016,7 +30239,7 @@ function createSecurityCommand(program2) {
30016
30239
  console.log(t("cli.security.audit_enabled"));
30017
30240
  });
30018
30241
  securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
30019
- const configPath = join36(homedir12(), ".mma", "config.json");
30242
+ const configPath = join37(homedir12(), ".mma", "config.json");
30020
30243
  const { config: appConfig } = await bootstrap();
30021
30244
  appConfig.security = appConfig.security || {};
30022
30245
  appConfig.security.auditNotifier = {
@@ -30047,18 +30270,49 @@ function createSecurityCommand(program2) {
30047
30270
  });
30048
30271
  }
30049
30272
 
30273
+ // src/cli/plugin-commands.ts
30274
+ init_bootstrap();
30275
+ init_version();
30276
+ init_i18n();
30277
+ function createPluginCommand(program2) {
30278
+ const pluginsCmd = program2.command("plugins").description(t("cli.plugins.description"));
30279
+ pluginsCmd.command("list").description(t("cli.plugins.list")).option("-a, --all", t("cli.plugins.all")).action(async (cmdOpts) => {
30280
+ const { pluginManager } = await bootstrap();
30281
+ const all = cmdOpts.all === true;
30282
+ let infos = pluginManager.getPluginInfos();
30283
+ if (!all) {
30284
+ infos = infos.filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
30285
+ }
30286
+ if (infos.length === 0) {
30287
+ console.log(t("cli.plugins.none"));
30288
+ return;
30289
+ }
30290
+ const mmaVersion = readMmaVersion();
30291
+ console.log(t("cli.plugins.header", { count: String(infos.length), mma: mmaVersion }));
30292
+ for (const { plugin: plugin3, source } of infos) {
30293
+ const version = plugin3.version || "-";
30294
+ const origin = source || "builtin";
30295
+ const builtin = plugin3.isBuiltin ? t("cli.plugins.builtin_mark") : " ";
30296
+ console.log(` ${builtin} ${plugin3.name} v${version} [${origin}]`);
30297
+ }
30298
+ if (!all) {
30299
+ console.log(t("cli.plugins.only_external"));
30300
+ }
30301
+ });
30302
+ }
30303
+
30050
30304
  // src/cli/commands.ts
30051
- import { fileURLToPath as fileURLToPath3 } from "url";
30305
+ import { fileURLToPath as fileURLToPath4 } from "url";
30052
30306
  function readVersion2() {
30053
- const here = dirname15(fileURLToPath3(import.meta.url));
30307
+ const here = dirname16(fileURLToPath4(import.meta.url));
30054
30308
  const candidates = [
30055
- join42(here, "..", "..", "package.json"),
30056
- join42(here, "..", "package.json")
30309
+ join43(here, "..", "..", "package.json"),
30310
+ join43(here, "..", "package.json")
30057
30311
  ];
30058
30312
  for (const p of candidates) {
30059
- if (existsSync48(p)) {
30313
+ if (existsSync49(p)) {
30060
30314
  try {
30061
- const raw = JSON.parse(readFileSync30(p, "utf8"));
30315
+ const raw = JSON.parse(readFileSync31(p, "utf8"));
30062
30316
  if (raw.version)
30063
30317
  return raw.version;
30064
30318
  } catch {}
@@ -30071,7 +30325,7 @@ function createProgram() {
30071
30325
  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"));
30072
30326
  program2.command("init").description(t("cli.init")).action(async () => {
30073
30327
  const answers = await runSetup();
30074
- const configPath = join42(homedir15(), ".mma", "config.json");
30328
+ const configPath = join43(homedir15(), ".mma", "config.json");
30075
30329
  const { config } = await bootstrap();
30076
30330
  config.provider.type = answers.provider;
30077
30331
  config.provider.baseUrl = answers.apiBase;
@@ -30116,7 +30370,7 @@ function createProgram() {
30116
30370
  });
30117
30371
  const configCmd = program2.command("config").description(t("cli.manage_config"));
30118
30372
  configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
30119
- const configPath = join42(homedir15(), ".mma", "config.json");
30373
+ const configPath = join43(homedir15(), ".mma", "config.json");
30120
30374
  const { config } = await bootstrap();
30121
30375
  const keys = key.split(".");
30122
30376
  let obj = config;
@@ -30179,7 +30433,7 @@ function createProgram() {
30179
30433
  console.log(t("cli.model_hint"));
30180
30434
  });
30181
30435
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
30182
- const configPath = join42(homedir15(), ".mma", "config.json");
30436
+ const configPath = join43(homedir15(), ".mma", "config.json");
30183
30437
  const { config } = await bootstrap();
30184
30438
  config.model = name;
30185
30439
  saveConfig(config, configPath);
@@ -30215,7 +30469,7 @@ function createProgram() {
30215
30469
  await uncertify2(name, config);
30216
30470
  });
30217
30471
  program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
30218
- const configPath = join42(homedir15(), ".mma", "config.json");
30472
+ const configPath = join43(homedir15(), ".mma", "config.json");
30219
30473
  const { config } = await bootstrap();
30220
30474
  const contextWindow = parseInt(size, 10);
30221
30475
  if (isNaN(contextWindow) || contextWindow < 1024) {
@@ -30233,7 +30487,7 @@ function createProgram() {
30233
30487
  console.log(t("cli.base_url"), config.provider.baseUrl);
30234
30488
  });
30235
30489
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
30236
- const configPath = join42(homedir15(), ".mma", "config.json");
30490
+ const configPath = join43(homedir15(), ".mma", "config.json");
30237
30491
  const { config } = await bootstrap();
30238
30492
  config.provider.type = name;
30239
30493
  saveConfig(config, configPath);
@@ -30275,6 +30529,7 @@ function createProgram() {
30275
30529
  console.log(t("session.deleted", { id }));
30276
30530
  });
30277
30531
  createSecurityCommand(program2);
30532
+ createPluginCommand(program2);
30278
30533
  program2.argument("[prompt...]", "Prompt to execute").description("Run a single prompt").action((prompt) => {});
30279
30534
  return program2;
30280
30535
  }
@@ -31040,10 +31295,10 @@ class LineEditor {
31040
31295
  }
31041
31296
 
31042
31297
  // src/cli/repl.ts
31043
- import { existsSync as existsSync50, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
31044
- import { join as join44, dirname as dirname17 } from "path";
31298
+ import { existsSync as existsSync51, readFileSync as readFileSync33, writeFileSync as writeFileSync17 } from "fs";
31299
+ import { join as join45, dirname as dirname18 } from "path";
31045
31300
  import { homedir as homedir17 } from "os";
31046
- import { fileURLToPath as fileURLToPath5 } from "url";
31301
+ import { fileURLToPath as fileURLToPath6 } from "url";
31047
31302
 
31048
31303
  // src/cli/completer.ts
31049
31304
  class SlashCommandProvider {
@@ -31545,15 +31800,15 @@ init_box();
31545
31800
  init_i18n();
31546
31801
  init_repl_commands();
31547
31802
  function readVersion4() {
31548
- const here = dirname17(fileURLToPath5(import.meta.url));
31803
+ const here = dirname18(fileURLToPath6(import.meta.url));
31549
31804
  const candidates = [
31550
- join44(here, "..", "..", "package.json"),
31551
- join44(here, "..", "package.json")
31805
+ join45(here, "..", "..", "package.json"),
31806
+ join45(here, "..", "package.json")
31552
31807
  ];
31553
31808
  for (const p of candidates) {
31554
- if (existsSync50(p)) {
31809
+ if (existsSync51(p)) {
31555
31810
  try {
31556
- const raw = JSON.parse(readFileSync32(p, "utf8"));
31811
+ const raw = JSON.parse(readFileSync33(p, "utf8"));
31557
31812
  if (raw.version)
31558
31813
  return raw.version;
31559
31814
  } catch {}
@@ -31609,10 +31864,10 @@ class Repl {
31609
31864
  this.skillsModule = skillsModule;
31610
31865
  this.pluginManager = pluginManager;
31611
31866
  this.logger = logger;
31612
- this.configDir = configDir || join44(homedir17(), ".mma");
31867
+ this.configDir = configDir || join45(homedir17(), ".mma");
31613
31868
  this.baseDir = baseDir || process.cwd();
31614
31869
  this.noAgentsMd = noAgentsMd === true;
31615
- this.historyPath = join44(homedir17(), ".mma", "repl-history");
31870
+ this.historyPath = join45(homedir17(), ".mma", "repl-history");
31616
31871
  this.loadHistory();
31617
31872
  this.rl = process.stdin.isTTY ? new LineEditor({
31618
31873
  input: process.stdin,
@@ -31645,9 +31900,9 @@ class Repl {
31645
31900
  this.setupListeners();
31646
31901
  }
31647
31902
  loadHistory() {
31648
- if (existsSync50(this.historyPath)) {
31903
+ if (existsSync51(this.historyPath)) {
31649
31904
  try {
31650
- const raw = readFileSync32(this.historyPath, "utf-8");
31905
+ const raw = readFileSync33(this.historyPath, "utf-8");
31651
31906
  this.history = raw.split(`
31652
31907
  `).filter(Boolean).slice(-this.maxHistory);
31653
31908
  } catch {
@@ -31986,10 +32241,14 @@ ${t("image.clipboard_empty")}`));
31986
32241
  row(t("repl.skills_label"), `${pc2.white(String(this.skillsModule.getAvailable().length))} available, ${pc2.dim(`budget: ${budget.total} tokens`)}`);
31987
32242
  }
31988
32243
  if (this.pluginManager) {
31989
- const plugins = this.pluginManager.getAllPlugins().filter((p) => !p.isBuiltin);
31990
- if (plugins.length > 0) {
31991
- const pluginNames = plugins.map((p) => p.name).join(", ");
31992
- row(t("repl.plugins_label"), `${pc2.white(String(plugins.length))} active ${pc2.dim(`(${pluginNames})`)}`);
32244
+ const infos = this.pluginManager.getPluginInfos().filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
32245
+ if (infos.length > 0) {
32246
+ const pluginNames = infos.map(({ plugin: plugin3, source }) => {
32247
+ const version4 = plugin3.version ? `${pc2.dim(plugin3.version)}` : "";
32248
+ const origin = source ? pc2.dim(` [${source}]`) : "";
32249
+ return `${plugin3.name}${version4}${origin}`;
32250
+ }).join(", ");
32251
+ row(t("repl.plugins_label"), `${pc2.white(String(infos.length))} active ${pc2.dim(`(${pluginNames})`)}`);
31993
32252
  }
31994
32253
  }
31995
32254
  const mcpServers = this.config.mcpServers || {};
@@ -32004,11 +32263,11 @@ ${t("image.clipboard_empty")}`));
32004
32263
  row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
32005
32264
  } else {
32006
32265
  const agentsMdCandidates = [
32007
- join44(this.baseDir, "AGENTS.md"),
32008
- join44(this.baseDir, ".mma", "AGENTS.md"),
32009
- join44(this.configDir, "AGENTS.md")
32266
+ join45(this.baseDir, "AGENTS.md"),
32267
+ join45(this.baseDir, ".mma", "AGENTS.md"),
32268
+ join45(this.configDir, "AGENTS.md")
32010
32269
  ];
32011
- const foundAgents = agentsMdCandidates.filter((p) => existsSync50(p));
32270
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync51(p));
32012
32271
  if (foundAgents.length > 0) {
32013
32272
  for (const p of foundAgents) {
32014
32273
  row(t("repl.agents_label"), pc2.dim(p));
@@ -32019,7 +32278,7 @@ ${t("image.clipboard_empty")}`));
32019
32278
  }
32020
32279
  const meta = this.sessionManager?.getActiveMeta();
32021
32280
  if (meta) {
32022
- const sessionPath = join44(this.configDir, "sessions", meta.id);
32281
+ const sessionPath = join45(this.configDir, "sessions", meta.id);
32023
32282
  row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
32024
32283
  }
32025
32284
  const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
@@ -32060,93 +32319,16 @@ init_setup();
32060
32319
  init_config2();
32061
32320
  init_i18n();
32062
32321
  init_colors();
32063
- import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
32064
- import { join as join45, dirname as dirname18 } from "path";
32322
+ import { existsSync as existsSync52, readFileSync as readFileSync34 } from "fs";
32323
+ import { join as join46, dirname as dirname19 } from "path";
32065
32324
  import { homedir as homedir18 } from "os";
32066
- import { fileURLToPath as fileURLToPath6 } from "url";
32325
+ import { fileURLToPath as fileURLToPath7 } from "url";
32067
32326
 
32068
- // src/modules/updater/checker.ts
32069
- init_command();
32070
- import { platform as platform9 } from "os";
32071
- function semverGt(a, b) {
32072
- const pa = a.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
32073
- const pb = b.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
32074
- for (let i = 0;i < 3; i++) {
32075
- const na = pa[i] ?? 0;
32076
- const nb = pb[i] ?? 0;
32077
- if (na !== nb)
32078
- return na > nb;
32079
- }
32080
- return false;
32081
- }
32082
- var defaultRunner2 = async (command, args, options) => {
32083
- const { execFile } = await import("child_process");
32084
- return new Promise((resolve25) => {
32085
- execFile(command, args, options, (err) => resolve25({ error: err?.message }));
32086
- });
32087
- };
32327
+ // src/modules/updater/index.ts
32328
+ init_checker();
32088
32329
 
32089
- class Updater {
32090
- currentVersion;
32091
- packageName;
32092
- runner;
32093
- constructor(currentVersion, packageName, runner) {
32094
- this.currentVersion = currentVersion;
32095
- this.packageName = packageName;
32096
- this.runner = runner ?? defaultRunner2;
32097
- }
32098
- getCurrentVersion() {
32099
- return this.currentVersion;
32100
- }
32101
- getPackageName() {
32102
- return this.packageName;
32103
- }
32104
- async check() {
32105
- try {
32106
- const response = await fetch(`https://registry.npmjs.org/${this.packageName}`, {
32107
- headers: { Accept: "application/vnd.npm.install-v1+json" },
32108
- signal: AbortSignal.timeout(5000)
32109
- });
32110
- if (!response.ok) {
32111
- return { updateAvailable: false, current: this.currentVersion, error: `HTTP ${response.status}` };
32112
- }
32113
- const data = await response.json();
32114
- const latest = data["dist-tags"]?.latest;
32115
- if (!latest) {
32116
- return { updateAvailable: false, current: this.currentVersion, error: "No latest tag" };
32117
- }
32118
- const updateAvailable = semverGt(latest, this.currentVersion);
32119
- return { updateAvailable, current: this.currentVersion, latest };
32120
- } catch (e) {
32121
- return { updateAvailable: false, current: this.currentVersion, error: e.message };
32122
- }
32123
- }
32124
- async install(latest) {
32125
- try {
32126
- const { command, args } = this.buildInstallCommand(latest);
32127
- const res = await this.runner(command, args, {
32128
- timeout: 120000,
32129
- windowsHide: true
32130
- });
32131
- if (res.error)
32132
- return { success: false, error: res.error };
32133
- return { success: true, installed: latest };
32134
- } catch (e) {
32135
- const msg = e?.message ?? String(e);
32136
- return { success: false, error: msg.split(`
32137
- `)[0] };
32138
- }
32139
- }
32140
- buildInstallCommand(latest) {
32141
- const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
32142
- const command = resolveSpawnCommand("npm");
32143
- if (platform9() === "win32" && /\.(cmd|bat)$/i.test(command)) {
32144
- return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
32145
- }
32146
- return { command, args: npmArgs };
32147
- }
32148
- }
32149
32330
  // src/modules/updater/module.ts
32331
+ init_checker();
32150
32332
  init_i18n();
32151
32333
  init_colors();
32152
32334
 
@@ -32241,15 +32423,15 @@ class UpdaterModule {
32241
32423
  }
32242
32424
  // src/cli/main.ts
32243
32425
  function readVersion5() {
32244
- const here = dirname18(fileURLToPath6(import.meta.url));
32426
+ const here = dirname19(fileURLToPath7(import.meta.url));
32245
32427
  const candidates = [
32246
- join45(here, "..", "..", "package.json"),
32247
- join45(here, "..", "package.json")
32428
+ join46(here, "..", "..", "package.json"),
32429
+ join46(here, "..", "package.json")
32248
32430
  ];
32249
32431
  for (const p of candidates) {
32250
- if (existsSync51(p)) {
32432
+ if (existsSync52(p)) {
32251
32433
  try {
32252
- const raw = JSON.parse(readFileSync33(p, "utf8"));
32434
+ const raw = JSON.parse(readFileSync34(p, "utf8"));
32253
32435
  if (raw.version)
32254
32436
  return raw.version;
32255
32437
  } catch {}
@@ -32332,15 +32514,15 @@ async function main() {
32332
32514
  await updater?.waitForIdle();
32333
32515
  process.exit(exitCode);
32334
32516
  } else {
32335
- const configPath = join45(homedir18(), ".mma", "config.json");
32336
- if (!existsSync51(configPath)) {
32517
+ const configPath = join46(homedir18(), ".mma", "config.json");
32518
+ if (!existsSync52(configPath)) {
32337
32519
  console.log(pc2.yellow(`
32338
32520
  ` + t("cli.first_run") + `
32339
32521
  `));
32340
32522
  const answers = await runSetup();
32341
32523
  const config2 = loadConfig({
32342
- configDir: join45(homedir18(), ".mma"),
32343
- projectConfigPath: projectDir ? join45(projectDir, ".mmrc") : join45(process.cwd(), ".mmrc")
32524
+ configDir: join46(homedir18(), ".mma"),
32525
+ projectConfigPath: projectDir ? join46(projectDir, ".mmrc") : join46(process.cwd(), ".mmrc")
32344
32526
  });
32345
32527
  config2.provider.type = answers.provider;
32346
32528
  config2.provider.baseUrl = answers.apiBase;