micro-models-agent 0.57.2 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/main.js +657 -246
  3. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2290,22 +2290,26 @@ var init_defaults = __esm(() => {
2290
2290
  code: {
2291
2291
  model: DEFAULT_MODEL,
2292
2292
  tool_tags: ["file", "code", "shell"],
2293
- max_attempts: 3
2293
+ max_attempts: 3,
2294
+ description: "file operations, code editing, shell commands"
2294
2295
  },
2295
2296
  research: {
2296
2297
  model: DEFAULT_MODEL,
2297
2298
  tool_tags: ["research"],
2298
- max_attempts: 3
2299
+ max_attempts: 3,
2300
+ description: "web search, web fetch, web browse, history search"
2299
2301
  },
2300
2302
  browser: {
2301
2303
  model: DEFAULT_MODEL,
2302
2304
  tool_tags: ["browser", "vision"],
2303
- max_attempts: 3
2305
+ max_attempts: 3,
2306
+ description: "browser automation, screenshots"
2304
2307
  },
2305
2308
  vision: {
2306
2309
  model: DEFAULT_MODEL,
2307
2310
  tool_tags: ["browser", "vision", "file"],
2308
- max_attempts: 2
2311
+ max_attempts: 2,
2312
+ description: "browser + file reading for visual tasks"
2309
2313
  }
2310
2314
  },
2311
2315
  contextWindow: 32768,
@@ -3010,7 +3014,7 @@ Use this knowledge to answer the user's question.`,
3010
3014
  "exec.audit_leftovers": "[✗] Task incomplete: {done}/{total} steps done, {files} files from delete-steps still exist",
3011
3015
  "exec.audit_fail_tests": "[✗] Task incomplete: {done}/{total} steps done, tests FAILING: {failed} failed / {passed} passed — {detail}",
3012
3016
  "exec.audit_fail_typecheck": "[✗] Task incomplete: {done}/{total} steps done, {missing} files missing, typecheck error: {typeError}",
3013
- "exec.audit_incomplete": "[⚠ Final audit incomplete: {summary}. Task is NOT finished — continue working. Remaining steps: {steps}]",
3017
+ "exec.audit_incomplete": " Final audit incomplete: {summary}. Task is NOT finished. Remaining steps: {steps}. Resolve them - pick ONE path: (a) if the step's deliverable already exists on disk, mark it done (plan update step=N status=done); (b) if the step is no longer needed, mark it skipped; (c) if the plan drifted from reality (wrong file names, changed approach), re-plan to align it. Do NOT retry plan update repeatedly without changing anything.",
3014
3018
  "exec.mass_edit_warning": "⚠️ Plan affects {count} files — review the full list before proceeding.",
3015
3019
  "exec.escalation": `
3016
3020
 
@@ -3777,7 +3781,7 @@ var init_ru = __esm(() => {
3777
3781
  "exec.audit_leftovers": "[✗] Задача не выполнена: {done}/{total} шагов, {files} файлов из delete-шагов всё ещё существуют",
3778
3782
  "exec.audit_fail_tests": "[✗] Задача не выполнена: {done}/{total} шагов, тесты ПАДАЮТ: {failed} failed / {passed} passed — {detail}",
3779
3783
  "exec.audit_fail_typecheck": "[✗] Задача не выполнена: {done}/{total} шагов, {missing} файлов отсутствует, ошибка typecheck: {typeError}",
3780
- "exec.audit_incomplete": "[⚠ Финальная проверка не пройдена: {summary}. Задача НЕ завершенапродолжайте работу. Оставшиеся шаги: {steps}]",
3784
+ "exec.audit_incomplete": " Финальная проверка не пройдена: {summary}. Задача НЕ завершена. Незакрытые шаги: {steps}. Устрани одним путём: (a) если результат шага уже существует на диске закрой шаг (plan update step=N status=done); (b) если шаг больше не нужен — status=skipped; (c) если план разошёлся с реальностью (другие имена файлов, сменился подход) — сделай re-plan. Не повторяй plan update без изменений.",
3781
3785
  "exec.mass_edit_warning": "⚠️ План затрагивает {count} файлов — проверьте полный список перед продолжением.",
3782
3786
  "exec.escalation": `
3783
3787
 
@@ -9539,12 +9543,24 @@ var init_bash = __esm(() => {
9539
9543
  mv: "Use the move_file tool instead.",
9540
9544
  rm: "Use the delete_file tool instead.",
9541
9545
  grep: "Use the grep tool instead.",
9546
+ sed: "Use the edit_file tool instead.",
9547
+ awk: "Not available in cmd.exe. Use a Node.js one-liner or the grep tool instead.",
9542
9548
  chmod: "Use the chmod tool instead.",
9543
9549
  touch: "Use the write_file tool instead.",
9544
9550
  find: "Use the glob tool instead.",
9545
9551
  head: "Use the read_file tool with offset/limit instead.",
9546
9552
  tail: "Use the read_file tool instead.",
9547
9553
  wc: "Use the read_file tool instead.",
9554
+ uniq: "Not available in cmd.exe. Use a Node.js one-liner instead.",
9555
+ xargs: "Not available in cmd.exe. Use a Node.js one-liner instead.",
9556
+ cut: "Not available in cmd.exe. Use a Node.js one-liner instead.",
9557
+ tr: "Not available in cmd.exe. Use a Node.js one-liner instead.",
9558
+ basename: "Not available in cmd.exe. Use a Node.js one-liner instead.",
9559
+ dirname: "Not available in cmd.exe. Use a Node.js one-liner instead.",
9560
+ export: 'cmd.exe has no export - use "set VAR=value" (no spaces around =).',
9561
+ source: 'cmd.exe has no source - use "call script.bat".',
9562
+ sleep: 'Use "timeout /t N" instead.',
9563
+ env: "cmd.exe has no env - use set to list/set variables.",
9548
9564
  diff: "Use the diff tool instead.",
9549
9565
  which: 'Use "where" instead.',
9550
9566
  echo: "echo works on Windows, but avoid pipes (|).",
@@ -10179,6 +10195,14 @@ class SessionLogger {
10179
10195
  source: data.source
10180
10196
  });
10181
10197
  }
10198
+ logMoE(event, data) {
10199
+ this.session?.appendLog({
10200
+ ts: new Date().toISOString(),
10201
+ type: event,
10202
+ content: data.detail ?? data.explanation ?? event,
10203
+ ...data
10204
+ });
10205
+ }
10182
10206
  }
10183
10207
  var init_session_logger = __esm(() => {
10184
10208
  init_audit_log();
@@ -10993,23 +11017,58 @@ function parseChunks(chunks) {
10993
11017
  }
10994
11018
 
10995
11019
  // src/llm/orchestrator.ts
11020
+ function buildPlanSystemPrompt(experts) {
11021
+ if (!experts || Object.keys(experts).length === 0) {
11022
+ return PLAN_SYSTEM_PROMPT;
11023
+ }
11024
+ const lines = Object.entries(experts).map(([tag, cfg]) => {
11025
+ const desc = cfg.description || (cfg.tool_tags?.length ? `tools: ${cfg.tool_tags.join(", ")}` : "general purpose");
11026
+ return `- ${tag}: ${desc}`;
11027
+ });
11028
+ return `You are a planning assistant for an agent system with multiple expert sub-agents.
11029
+ Break down the user's task into subtasks that can be executed by different expert agents.
11030
+
11031
+ Available experts and their tool tags:
11032
+ ${lines.join(`
11033
+ `)}
11034
+
11035
+ ${PLAN_SYSTEM_PROMPT_RULES}`;
11036
+ }
11037
+
10996
11038
  class OrchestratorClient {
10997
11039
  config;
10998
11040
  provider = null;
10999
11041
  constructor(config, defaultProvider) {
11000
11042
  this.config = config;
11001
- if (config.model) {
11002
- if (config.provider) {
11003
- this.provider = this.createProviderInstance(config.provider.type ?? "openai-compat", config.model, config.provider.baseUrl || DEFAULT_BASE_URL, config.provider.apiKey, config.retry);
11004
- } else if (defaultProvider) {
11005
- this.provider = defaultProvider;
11006
- } else {
11007
- this.provider = this.createProviderInstance("openai-compat", config.model, DEFAULT_BASE_URL, undefined, config.retry);
11008
- }
11043
+ if (!config.model)
11044
+ return;
11045
+ if (config.provider) {
11046
+ this.provider = this.buildManagedProvider(config);
11047
+ } else if (defaultProvider) {
11048
+ this.provider = defaultProvider;
11049
+ } else {
11050
+ this.provider = this.buildManagedProvider({
11051
+ ...config,
11052
+ provider: { type: "openai-compat", baseUrl: DEFAULT_BASE_URL }
11053
+ });
11009
11054
  }
11010
11055
  }
11011
- createProviderInstance(type, model, baseUrl, apiKey, retry) {
11012
- return createProvider(type, { model, baseUrl, apiKey, contextWindow: 32768, retry });
11056
+ buildManagedProvider(config) {
11057
+ const providerCfg = config.provider;
11058
+ const manager = new ProviderManager({ ...providerCfg, baseUrl: providerCfg.baseUrl || DEFAULT_BASE_URL }, {
11059
+ contextWindow: config.contextWindow ?? DEFAULT_ORCH_CONTEXT_WINDOW,
11060
+ retry: config.retry,
11061
+ rateLimits: config.rateLimits,
11062
+ logger: config.logger
11063
+ });
11064
+ manager.setModel(config.model);
11065
+ let provider = manager.active;
11066
+ if (providerCfg.fallback && manager.listNames().length > 1) {
11067
+ provider = new FallbackProvider(manager, (from, to, error) => {
11068
+ config.logger?.warn(`orchestrator provider failover: ${from} -> ${to} (${error.message.slice(0, 120)})`);
11069
+ });
11070
+ }
11071
+ return provider;
11013
11072
  }
11014
11073
  isEnabled() {
11015
11074
  return this.provider !== null;
@@ -11047,7 +11106,7 @@ class OrchestratorClient {
11047
11106
  if (!this.provider)
11048
11107
  return { error: "Orchestrator not enabled — no orchestrator model configured" };
11049
11108
  const messages = [
11050
- { role: "system", content: PLAN_SYSTEM_PROMPT },
11109
+ { role: "system", content: buildPlanSystemPrompt(this.config.experts) },
11051
11110
  { role: "user", content: userPrompt }
11052
11111
  ];
11053
11112
  const text = await this.chat(messages, signal);
@@ -11137,16 +11196,7 @@ class OrchestratorClient {
11137
11196
  return parsed.type === "text" ? parsed.content : "";
11138
11197
  }
11139
11198
  }
11140
- var PLAN_SYSTEM_PROMPT = `You are a planning assistant for an agent system with multiple expert sub-agents.
11141
- Break down the user's task into subtasks that can be executed by different expert agents.
11142
-
11143
- Available experts and their tool tags:
11144
- - code: file operations, code editing, shell commands
11145
- - research: web search, web fetch, web browse, history search
11146
- - browser: browser automation, screenshots
11147
- - vision: browser + file reading for visual tasks
11148
-
11149
- Rules:
11199
+ var PLAN_SYSTEM_PROMPT_RULES = `Rules:
11150
11200
  1. Each subtask must have an expert_tag from the available experts.
11151
11201
  2. Use depends_on for ordering when subtask B reads what subtask A writes.
11152
11202
  3. Independent subtasks should NOT depend on each other (they run in parallel).
@@ -11175,7 +11225,7 @@ Respond with a JSON object only (no markdown fences):
11175
11225
  "rules": ["rule 1"],
11176
11226
  "refs": []
11177
11227
  }
11178
- }`, VERIFY_SYSTEM_PROMPT = `You are a verification and merge assistant for an agent system with multiple expert sub-agents.
11228
+ }`, PLAN_SYSTEM_PROMPT, VERIFY_SYSTEM_PROMPT = `You are a verification and merge assistant for an agent system with multiple expert sub-agents.
11179
11229
  You receive the original plan, the results from each subtask, and any verification errors.
11180
11230
  Your job is to determine if the overall task was completed successfully or if re-planning is needed.
11181
11231
 
@@ -11191,10 +11241,21 @@ Decide what to do with its scope request:
11191
11241
  Respond with JSON only (no markdown fences):
11192
11242
  {"action": "approve", "write": ["file1"], "read": ["file2"]}
11193
11243
  or
11194
- {"action": "reject", "explanation": "why"}`, DEFAULT_BASE_URL = "http://localhost:1234/v1";
11244
+ {"action": "reject", "explanation": "why"}`, DEFAULT_BASE_URL = "http://localhost:1234/v1", DEFAULT_ORCH_CONTEXT_WINDOW = 32768;
11195
11245
  var init_orchestrator = __esm(() => {
11196
- init_create();
11246
+ init_manager();
11247
+ init_fallback();
11197
11248
  init_esm();
11249
+ PLAN_SYSTEM_PROMPT = `You are a planning assistant for an agent system with multiple expert sub-agents.
11250
+ Break down the user's task into subtasks that can be executed by different expert agents.
11251
+
11252
+ Available experts and their tool tags:
11253
+ - code: file operations, code editing, shell commands
11254
+ - research: web search, web fetch, web browse, history search
11255
+ - browser: browser automation, screenshots
11256
+ - vision: browser + file reading for visual tasks
11257
+
11258
+ ${PLAN_SYSTEM_PROMPT_RULES}`;
11198
11259
  });
11199
11260
 
11200
11261
  // src/modules/execution/input-from.ts
@@ -12208,7 +12269,7 @@ function topologicalSort(subtasks) {
12208
12269
  }
12209
12270
  return sorted;
12210
12271
  }
12211
- async function executeSubtask(subtask, deps, depResults, sharedContext) {
12272
+ async function executeSubtask(subtask, deps, depResults, sharedContext, onUsage) {
12212
12273
  const startTime = Date.now();
12213
12274
  const expertConfig = getExpertConfig(deps.config, subtask.expert_tag);
12214
12275
  if (!expertConfig) {
@@ -12290,8 +12351,11 @@ ${(subtask.success_criteria || []).map((c) => `- ${c}`).join(`
12290
12351
  logger: deps.logger,
12291
12352
  llmProvider: deps.llmProvider,
12292
12353
  toolExecutor: deps.toolExecutor,
12293
- sessionId: "moe"
12354
+ sessionId: deps.sessionId || "moe"
12294
12355
  }, subagentArgs);
12356
+ if (result.usage) {
12357
+ onUsage?.(subtask.expert_tag, result.usage);
12358
+ }
12295
12359
  deps.onTool?.({
12296
12360
  type: "end",
12297
12361
  tool: "subagent",
@@ -12305,7 +12369,7 @@ ${(subtask.success_criteria || []).map((c) => `- ${c}`).join(`
12305
12369
  if (abs) {
12306
12370
  const store = new ArtifactStore({
12307
12371
  baseDir: deps.baseDir,
12308
- sessionId: "moe"
12372
+ sessionId: deps.sessionId || "moe"
12309
12373
  });
12310
12374
  const full = store.read(abs.split(/[\\/]/).pop() || "");
12311
12375
  deps.logger.debug(`MoE subtask "${subtask.id}" attached artifact ${abs} (${full?.length ?? 0} chars) to Router`);
@@ -12395,14 +12459,34 @@ ${stuckReason}`;
12395
12459
 
12396
12460
  class MoEExecutor {
12397
12461
  deps;
12462
+ usageByTag = new Map;
12398
12463
  constructor(deps) {
12399
12464
  this.deps = deps;
12400
12465
  }
12401
- async executePlan(plan) {
12402
- const results = [];
12466
+ getUsageByTag() {
12467
+ return Object.fromEntries(this.usageByTag);
12468
+ }
12469
+ recordUsage(expertTag, usage) {
12470
+ const entry = this.usageByTag.get(expertTag) ?? {
12471
+ promptTokens: 0,
12472
+ completionTokens: 0,
12473
+ totalTokens: 0,
12474
+ subtasks: 0
12475
+ };
12476
+ entry.promptTokens += usage.promptTokens;
12477
+ entry.completionTokens += usage.completionTokens;
12478
+ entry.totalTokens += usage.totalTokens;
12479
+ entry.subtasks += 1;
12480
+ this.usageByTag.set(expertTag, entry);
12481
+ }
12482
+ async executePlan(plan, opts) {
12483
+ const skipIds = opts?.skipIds;
12484
+ const carried = opts?.carriedResults ?? [];
12485
+ const results = carried.map((r) => ({ ...r }));
12403
12486
  const errors = [];
12404
12487
  const warnings = [];
12405
- const waves = topologicalSort(plan.subtasks);
12488
+ const subtasks = skipIds && skipIds.size > 0 ? plan.subtasks.filter((s) => !skipIds.has(s.id)) : plan.subtasks;
12489
+ const waves = topologicalSort(subtasks);
12406
12490
  if (waves.length === 0) {
12407
12491
  return {
12408
12492
  success: false,
@@ -12412,8 +12496,8 @@ class MoEExecutor {
12412
12496
  };
12413
12497
  }
12414
12498
  const sortedCount = waves.flat().length;
12415
- if (sortedCount < plan.subtasks.length) {
12416
- const missing = plan.subtasks.filter((s) => !waves.flat().some((w) => w.id === s.id)).map((s) => s.id);
12499
+ if (sortedCount < subtasks.length) {
12500
+ const missing = subtasks.filter((s) => !waves.flat().some((w) => w.id === s.id)).map((s) => s.id);
12417
12501
  return {
12418
12502
  success: false,
12419
12503
  results: [],
@@ -12442,9 +12526,13 @@ class MoEExecutor {
12442
12526
  release();
12443
12527
  throw newAbortError();
12444
12528
  }
12529
+ this.deps.onEvent?.({
12530
+ type: "moe_subtask",
12531
+ data: { subtaskId: subtask.id, expertTag: subtask.expert_tag, status: "start" }
12532
+ });
12445
12533
  let result;
12446
12534
  try {
12447
- result = await executeSubtask(subtask, this.deps, depResults, plan.shared_context);
12535
+ result = await executeSubtask(subtask, this.deps, depResults, plan.shared_context, (tag, usage) => this.recordUsage(tag, usage));
12448
12536
  if (!result.success && this.deps.onScopeRequest) {
12449
12537
  result = await this.resolveScopeAndRetry(subtask, result, depResults, plan.shared_context);
12450
12538
  }
@@ -12462,6 +12550,16 @@ class MoEExecutor {
12462
12550
  } finally {
12463
12551
  release();
12464
12552
  }
12553
+ this.deps.onEvent?.({
12554
+ type: "moe_subtask",
12555
+ data: {
12556
+ subtaskId: subtask.id,
12557
+ expertTag: subtask.expert_tag,
12558
+ status: result.success ? "done" : "failed",
12559
+ durationMs: result.durationMs,
12560
+ summary: result.summary
12561
+ }
12562
+ });
12465
12563
  results.push(result);
12466
12564
  return result;
12467
12565
  });
@@ -12473,7 +12571,13 @@ class MoEExecutor {
12473
12571
  if (failed.length > 0) {
12474
12572
  errors.push(...failed.map((f) => `[${f.subtaskId}] ${f.error || f.summary}`));
12475
12573
  }
12476
- return { success: failed.length === 0, results, errors, warnings };
12574
+ return {
12575
+ success: failed.length === 0,
12576
+ results,
12577
+ errors,
12578
+ warnings,
12579
+ ...carried.length > 0 ? { carriedSubtaskIds: carried.map((r) => r.subtaskId) } : {}
12580
+ };
12477
12581
  }
12478
12582
  async resolveScopeAndRetry(subtask, failed, depResults, sharedContext) {
12479
12583
  let current = failed;
@@ -12493,7 +12597,7 @@ Router rejected scope request for files: ${req.files.join(", ")}`
12493
12597
  subtask.allowed_files = uniq([...subtask.allowed_files || [], ...decision.write]);
12494
12598
  subtask.read_only_files = uniq([...subtask.read_only_files || [], ...decision.read]);
12495
12599
  this.deps.logger.info?.(`MoE: approved scope expansion for "${subtask.id}": +write [${decision.write.join(", ")}] +read [${decision.read.join(", ")}]`);
12496
- const retry = await executeSubtask(subtask, this.deps, depResults, sharedContext);
12600
+ const retry = await executeSubtask(subtask, this.deps, depResults, sharedContext, (tag, usage) => this.recordUsage(tag, usage));
12497
12601
  if (retry.success || !retry.scopeRequest)
12498
12602
  return retry;
12499
12603
  current = retry;
@@ -13084,7 +13188,7 @@ var init_auditor = __esm(() => {
13084
13188
  });
13085
13189
 
13086
13190
  // src/modules/execution/verifier.ts
13087
- import { existsSync as existsSync26 } from "fs";
13191
+ import { existsSync as existsSync26, readFileSync as readFileSync13 } from "fs";
13088
13192
  import { resolve as resolve13, extname as extname3, join as join16 } from "path";
13089
13193
  import { spawn as spawn4 } from "child_process";
13090
13194
 
@@ -13155,6 +13259,65 @@ class StepVerifier {
13155
13259
  async verifyArtifactFiles(files) {
13156
13260
  return Promise.all(files.map((f) => this.checkFileExists(f)));
13157
13261
  }
13262
+ async verifySubtaskCriteria(subtask) {
13263
+ const errors = [];
13264
+ const warnings = [];
13265
+ const details = [];
13266
+ for (const criterion of subtask.success_criteria || []) {
13267
+ const sep2 = criterion.indexOf(":");
13268
+ if (sep2 <= 0) {
13269
+ warnings.push(`Subtask "${subtask.id}": non-machine criterion "${criterion}" (LLM-only)`);
13270
+ continue;
13271
+ }
13272
+ const kind = criterion.slice(0, sep2);
13273
+ const rest = criterion.slice(sep2 + 1);
13274
+ if (kind === "file-exists") {
13275
+ const check = await this.checkFileExists(rest);
13276
+ details.push(check);
13277
+ if (!check.passed)
13278
+ errors.push(`[${subtask.id}] ${check.message}`);
13279
+ continue;
13280
+ }
13281
+ if (kind === "substring-in-file") {
13282
+ const colon = rest.indexOf(":");
13283
+ if (colon <= 0) {
13284
+ warnings.push(`Subtask "${subtask.id}": malformed substring-in-file criterion "${criterion}"`);
13285
+ continue;
13286
+ }
13287
+ const path = rest.slice(0, colon);
13288
+ const needle = rest.slice(colon + 1);
13289
+ const resolved = resolve13(this.baseDir, path);
13290
+ if (!existsSync26(resolved)) {
13291
+ const item = { passed: false, message: t("verify.file_not_found", { path }) };
13292
+ details.push(item);
13293
+ errors.push(`[${subtask.id}] ${item.message}`);
13294
+ continue;
13295
+ }
13296
+ const content = readFileSync13(resolved, "utf-8");
13297
+ const passed = content.includes(needle);
13298
+ details.push({ passed, message: `substring "${needle}" in ${path}: ${passed}` });
13299
+ if (!passed)
13300
+ errors.push(`[${subtask.id}] "${needle}" not found in ${path}`);
13301
+ continue;
13302
+ }
13303
+ if (kind === "command-exit-0") {
13304
+ try {
13305
+ await this.runAsync(rest, this.baseDir, 30000);
13306
+ details.push({ passed: true, message: `command ok: ${rest}` });
13307
+ } catch (e) {
13308
+ const item = {
13309
+ passed: false,
13310
+ message: `command failed: ${rest} (${String(e.message).slice(0, 200)})`
13311
+ };
13312
+ details.push(item);
13313
+ errors.push(`[${subtask.id}] ${item.message}`);
13314
+ }
13315
+ continue;
13316
+ }
13317
+ warnings.push(`Subtask "${subtask.id}": unknown criterion kind "${kind}" (LLM-only)`);
13318
+ }
13319
+ return { errors, warnings, details };
13320
+ }
13158
13321
  async verifyMoEManifest(plan, config, allToolTags) {
13159
13322
  const errors = [];
13160
13323
  const warnings = [];
@@ -13177,6 +13340,10 @@ class StepVerifier {
13177
13340
  errors.push(check.message);
13178
13341
  }
13179
13342
  }
13343
+ const criteria = await this.verifySubtaskCriteria(sub);
13344
+ errors.push(...criteria.errors);
13345
+ warnings.push(...criteria.warnings);
13346
+ details.push(...criteria.details);
13180
13347
  }
13181
13348
  return {
13182
13349
  success: errors.length === 0,
@@ -13295,7 +13462,8 @@ var init_verifier = __esm(() => {
13295
13462
  // src/core/agent-moe.ts
13296
13463
  async function runWithMoE(deps, input, fallback, opts = {}) {
13297
13464
  const { config, llmProvider, logger, toolExecutor, baseDir } = deps;
13298
- const { onMeta, onPhase, onTool, signal } = opts;
13465
+ const { onMeta, onPhase, onTool, signal, onEvent, sessionId } = opts;
13466
+ const emit = (type, data) => onEvent?.({ type, data });
13299
13467
  const ensureNotAborted = () => {
13300
13468
  if (signal?.aborted)
13301
13469
  throw newAbortError();
@@ -13305,11 +13473,16 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
13305
13473
  if (!orchestrator) {
13306
13474
  orchestrator = new OrchestratorClient({
13307
13475
  model: config.orchestrator.model,
13308
- provider: config.orchestrator.provider
13476
+ provider: config.orchestrator.provider,
13477
+ contextWindow: config.orchestrator.contextWindow,
13478
+ retry: config.retry,
13479
+ rateLimits: config.security?.rateLimits,
13480
+ logger,
13481
+ experts: config.experts
13309
13482
  }, llmProvider);
13310
13483
  }
13311
13484
  if (!orchestrator.isEnabled()) {
13312
- logger.debug("MoE enabled but no orchestrator model configured — falling back to single-agent");
13485
+ logger.warn("MoE enabled but no orchestrator model configured — falling back to single-agent. Set orchestrator.model to activate MoE.");
13313
13486
  return fallback();
13314
13487
  }
13315
13488
  onMeta?.(`\uD83E\uDD16 Planning with MoE mode...
@@ -13319,16 +13492,28 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
13319
13492
  onPhase?.("done");
13320
13493
  if ("error" in planResult) {
13321
13494
  logger.warn(`MoE plan failed: ${planResult.error} — falling back to single-agent`);
13495
+ emit("moe_plan", { status: "error", error: planResult.error });
13322
13496
  return fallback();
13323
13497
  }
13498
+ emit("moe_plan", {
13499
+ status: "ok",
13500
+ title: planResult.plan.title,
13501
+ subtaskIds: planResult.plan.subtasks.map((s) => s.id)
13502
+ });
13324
13503
  const maxCycles = Math.max(1, config.moe?.maxReplanCycles ?? DEFAULT_MOE_MAX_REPLAN_CYCLES);
13325
13504
  const mergedResults = new Map;
13326
13505
  let currentPlan = planResult.plan;
13506
+ const usageByTag = {};
13327
13507
  for (let cycle = 1;cycle <= maxCycles; cycle++) {
13328
13508
  ensureNotAborted();
13329
13509
  if (cycle > 1) {
13330
13510
  onMeta?.(t("moe.replan_started", { cycle, max: maxCycles }) + `
13331
13511
  `);
13512
+ emit("moe_replan", {
13513
+ cycle,
13514
+ title: currentPlan.title,
13515
+ subtaskIds: currentPlan.subtasks.map((s) => s.id)
13516
+ });
13332
13517
  }
13333
13518
  const validation = validatePlan(currentPlan, config);
13334
13519
  if (!validation.valid) {
@@ -13357,6 +13542,8 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
13357
13542
  logger,
13358
13543
  baseDir,
13359
13544
  onTool,
13545
+ sessionId,
13546
+ onEvent: (e) => emit(e.type, e.data),
13360
13547
  onScopeRequest: async (subtaskId, req) => {
13361
13548
  const decision = await orchestrator.resolveScopeRequest(subtaskId, req, signal);
13362
13549
  if (decision.action === "approve") {
@@ -13374,8 +13561,36 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
13374
13561
  });
13375
13562
  onMeta?.(t("moe.executing", { count: String(currentPlan.subtasks.length), cycle: String(cycle) }) + `
13376
13563
  `);
13377
- const planResults = await executor.executePlan(currentPlan);
13564
+ const skipIds = new Set;
13565
+ const carriedResults = [];
13566
+ for (const s of currentPlan.subtasks) {
13567
+ const prev = mergedResults.get(s.id);
13568
+ if (prev?.success) {
13569
+ skipIds.add(s.id);
13570
+ carriedResults.push(prev);
13571
+ }
13572
+ }
13573
+ for (const id of skipIds) {
13574
+ emit("moe_subtask", { subtaskId: id, status: "carried", cycle });
13575
+ }
13576
+ const planResults = await executor.executePlan(currentPlan, { skipIds, carriedResults });
13378
13577
  ensureNotAborted();
13578
+ const cycleUsage = executor.getUsageByTag?.();
13579
+ if (cycleUsage) {
13580
+ for (const [tag, usage] of Object.entries(cycleUsage)) {
13581
+ const agg = usageByTag[tag] ?? {
13582
+ promptTokens: 0,
13583
+ completionTokens: 0,
13584
+ totalTokens: 0,
13585
+ subtasks: 0
13586
+ };
13587
+ agg.promptTokens += usage.promptTokens;
13588
+ agg.completionTokens += usage.completionTokens;
13589
+ agg.totalTokens += usage.totalTokens;
13590
+ agg.subtasks += usage.subtasks;
13591
+ usageByTag[tag] = agg;
13592
+ }
13593
+ }
13379
13594
  for (const r of planResults.results) {
13380
13595
  mergedResults.set(r.subtaskId, r);
13381
13596
  }
@@ -13405,6 +13620,7 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
13405
13620
  onPhase?.("done");
13406
13621
  if (err?.name === "AbortError")
13407
13622
  throw err;
13623
+ emit("moe_verify", { status: "error", error: err.message });
13408
13624
  return {
13409
13625
  success: false,
13410
13626
  text: `MoE verifyAndMerge crashed: ${err.message}`,
@@ -13413,6 +13629,11 @@ async function runWithMoE(deps, input, fallback, opts = {}) {
13413
13629
  };
13414
13630
  }
13415
13631
  onPhase?.("done");
13632
+ emit("moe_verify", {
13633
+ decision: verifyResult.type,
13634
+ explanation: verifyResult.explanation,
13635
+ usageByTag: Object.keys(usageByTag).length > 0 ? usageByTag : undefined
13636
+ });
13416
13637
  if (verifyResult.type === "final") {
13417
13638
  return buildFinalResult(mergedResults, verification.success, verifyResult);
13418
13639
  }
@@ -13674,7 +13895,7 @@ function evaluateReasoningPolicy(input, state) {
13674
13895
  var DECAY_THRESHOLD = 5;
13675
13896
 
13676
13897
  // src/core/agent/constants.ts
13677
- var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000, QUALITY_TRIGGER_THRESHOLD = 40, TOOL_ARGS_SUMMARY_MAX_CHARS = 240, FORCED_COMPACTION_COOLDOWN = 3, MAX_LLM_ERROR_RETRIES = 2, MAX_HALLUCINATION_RETRIES = 3, MAX_CONSECUTIVE_TOOL_FAILURES = 5, MIN_REPEATED_TOOL_FAILURES = 3, MAX_AUDIT_RETRIES = 3, MAX_EMPTY_RESPONSE_RETRIES = 2, MAX_REPEATED_TOOL_CALLS = 2;
13898
+ var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000, QUALITY_TRIGGER_THRESHOLD = 40, TOOL_ARGS_SUMMARY_MAX_CHARS = 240, FORCED_COMPACTION_COOLDOWN = 3, MAX_LLM_ERROR_RETRIES = 2, MAX_HALLUCINATION_RETRIES = 3, MAX_CONSECUTIVE_TOOL_FAILURES = 5, MIN_REPEATED_TOOL_FAILURES = 3, MAX_AUDIT_RETRIES = 3, MAX_EMPTY_RESPONSE_RETRIES = 2, MAX_REPEATED_TOOL_CALLS = 2, MUTATION_CYCLE_NUDGE_THRESHOLD = 5;
13678
13899
 
13679
13900
  // src/core/agent/loop-state.ts
13680
13901
  function createLoopState() {
@@ -13690,6 +13911,8 @@ function createLoopState() {
13690
13911
  repeatedToolCount: 0,
13691
13912
  toolFailureCounts: new Map,
13692
13913
  memoryRuleRecorded: new Set,
13914
+ toolTargetCounts: new Map,
13915
+ cycleNudgedKeys: new Set,
13693
13916
  apiPromptTokens: 0,
13694
13917
  apiCompletionTokens: 0,
13695
13918
  apiCompletionChars: 0,
@@ -13866,7 +14089,7 @@ class ReasoningEffortResolver {
13866
14089
  planCreated: state.iterPlanCreated,
13867
14090
  consecutiveSuccesses: state.consecutiveToolSuccesses,
13868
14091
  isRepetitive: state.iterRepetitive,
13869
- baseline: "medium"
14092
+ baseline: reasoningConfig?.baseline ?? "medium"
13870
14093
  }, deps.policyState);
13871
14094
  level = policyResult.level;
13872
14095
  source = "policy";
@@ -14256,6 +14479,32 @@ var init_audit_gate = __esm(() => {
14256
14479
  });
14257
14480
 
14258
14481
  // src/core/agent.ts
14482
+ function mutationTargetKey(name, rawArgs) {
14483
+ let a = null;
14484
+ if (typeof rawArgs === "string") {
14485
+ try {
14486
+ a = JSON.parse(rawArgs);
14487
+ } catch {
14488
+ return null;
14489
+ }
14490
+ } else if (rawArgs && typeof rawArgs === "object") {
14491
+ a = rawArgs;
14492
+ }
14493
+ if (!a)
14494
+ return null;
14495
+ if ((name === "edit_file" || name === "write_file") && typeof a.path === "string") {
14496
+ return `write:${a.path.replace(/\\/g, "/").toLowerCase()}`;
14497
+ }
14498
+ if (name === "bash" && typeof a.command === "string") {
14499
+ const cmd = a.command.replace(/\s+/g, " ").trim().slice(0, 80).toLowerCase();
14500
+ return cmd ? `bash:${cmd}` : null;
14501
+ }
14502
+ if ((name === "plan" || name === "todo") && typeof a.action === "string") {
14503
+ return `book:${name}:${a.action.toLowerCase()}`;
14504
+ }
14505
+ return null;
14506
+ }
14507
+
14259
14508
  class Agent {
14260
14509
  deps;
14261
14510
  systemPromptAdded = false;
@@ -14450,7 +14699,8 @@ class Agent {
14450
14699
  };
14451
14700
  try {
14452
14701
  const moeEnabled = config.moe?.enabled === true;
14453
- const result = moeEnabled ? await runWithMoE({
14702
+ const moeRunner = this.deps.runWithMoEOverride ?? runWithMoE;
14703
+ const result = moeEnabled ? await moeRunner({
14454
14704
  config,
14455
14705
  llmProvider,
14456
14706
  toolExecutor,
@@ -14460,7 +14710,9 @@ class Agent {
14460
14710
  onMeta,
14461
14711
  onTool: countTool,
14462
14712
  onPhase,
14463
- signal: this.abortController.signal
14713
+ signal: this.abortController.signal,
14714
+ onEvent: (event) => slog.logMoE(event.type, event.data),
14715
+ sessionId: this.deps.sessionManager?.getActiveMeta()?.id
14464
14716
  }) : await this.executeSingleAgentLoop(input, slog, onChunk, onMeta, countTool, onPhase);
14465
14717
  if (moeEnabled && result.moeHandled) {
14466
14718
  if (result.text) {
@@ -14674,27 +14926,49 @@ class Agent {
14674
14926
  const signature = toolCalls.map((tc) => `${tc.name}:${JSON.stringify(tc.arguments)}`).join("|");
14675
14927
  if (signature && signature === state.lastToolSignature) {
14676
14928
  state.iterRepetitive = true;
14929
+ logger.info(`Repeated identical tool call detected (iteration ${state.iteration}) — nudging model to finish or change approach`);
14930
+ contextManager.addMessage({
14931
+ role: "user",
14932
+ content: `<system-summary>You just called the same tool with identical arguments. If the task is done, answer with a final text response NOW. If the command failed, try a different approach.</system-summary>`
14933
+ });
14677
14934
  if (this.deps.exitOnComplete) {
14678
14935
  state.repeatedToolCount++;
14679
14936
  if (state.repeatedToolCount >= MAX_REPEATED_TOOL_CALLS) {
14680
14937
  logger.debug("Exit-on-complete: repeated identical tool call, stopping");
14681
14938
  break;
14682
14939
  }
14683
- contextManager.addMessage({
14684
- role: "user",
14685
- content: `<system-summary>You just called the same tool with identical arguments. If the task is done, answer with a final text response NOW. If the command failed, try a different approach.</system-summary>`
14686
- });
14687
14940
  }
14688
14941
  } else {
14689
14942
  state.repeatedToolCount = 0;
14690
14943
  }
14691
14944
  state.lastToolSignature = signature;
14692
14945
  }
14946
+ const cycleNudges = [];
14947
+ if (sawToolCall) {
14948
+ for (const tc of toolCalls) {
14949
+ const target = mutationTargetKey(tc.name, tc.arguments);
14950
+ if (!target)
14951
+ continue;
14952
+ const count = (state.toolTargetCounts.get(target) ?? 0) + 1;
14953
+ state.toolTargetCounts.set(target, count);
14954
+ if (count >= MUTATION_CYCLE_NUDGE_THRESHOLD && !state.cycleNudgedKeys.has(target)) {
14955
+ state.cycleNudgedKeys.add(target);
14956
+ cycleNudges.push(target);
14957
+ }
14958
+ }
14959
+ }
14693
14960
  if (sawToolCall) {
14694
14961
  const batch = await toolBatch.execute(state, toolCalls, boundedToolNames, textContent, reasoningContent, input, onTool, onMeta, slog);
14695
14962
  if (batch.interrupted) {
14696
14963
  break;
14697
14964
  }
14965
+ if (cycleNudges.length > 0) {
14966
+ logger.info(`Perfectionism cycle detected (${cycleNudges.length} target(s) at ${MUTATION_CYCLE_NUDGE_THRESHOLD}+ mutations) — nudging model to finalize`);
14967
+ contextManager.addMessage({
14968
+ role: "user",
14969
+ content: `<system-summary>You have already modified or re-run the same target many times (e.g. ${cycleNudges[0]}). If the latest output is correct, STOP polishing and answer with a final text response. More identical edits will not change the result.</system-summary>`
14970
+ });
14971
+ }
14698
14972
  this.contextRenderer.render(this.deps.config.ui, contextManager, onMeta);
14699
14973
  state.suppressRepetitionRetry = false;
14700
14974
  continue;
@@ -16253,8 +16527,9 @@ var init_subagent = __esm(() => {
16253
16527
  essential: true,
16254
16528
  estimatedTokens: 150
16255
16529
  };
16530
+ const subConfig = { ...ctx.config, moe: { ...ctx.config.moe, enabled: false } };
16256
16531
  const subDeps = {
16257
- config: ctx.config,
16532
+ config: subConfig,
16258
16533
  llmProvider: ctx.llmProvider,
16259
16534
  toolExecutor: ctx.toolExecutor,
16260
16535
  pluginManager: subPluginManager,
@@ -16266,12 +16541,17 @@ var init_subagent = __esm(() => {
16266
16541
  toolTags,
16267
16542
  promptBlocks: [systemPrompt]
16268
16543
  };
16269
- const subAgent = new Agent(subDeps);
16544
+ const subAgent = (ctx.agentFactory ?? ((d) => new Agent(d)))(subDeps);
16270
16545
  const fullTask = context ? `${task}
16271
16546
 
16272
16547
  Context: ${context}` : task;
16273
16548
  try {
16274
16549
  const result = await subAgent.run(fullTask);
16550
+ const pickUsage = () => result.promptTokens !== undefined || result.totalTokens !== undefined ? {
16551
+ promptTokens: result.promptTokens ?? 0,
16552
+ completionTokens: result.completionTokens ?? 0,
16553
+ totalTokens: result.totalTokens ?? 0
16554
+ } : undefined;
16275
16555
  if (!result.success) {
16276
16556
  let output = `Sub-agent failed: ${result.error}
16277
16557
  Partial output: ${result.text}`;
@@ -16298,7 +16578,8 @@ ${formatScopeRequest(scopeReq)}`;
16298
16578
  iterations: String(result.iterationCount),
16299
16579
  summary
16300
16580
  }),
16301
- artifactPath: abs
16581
+ artifactPath: abs,
16582
+ usage: pickUsage()
16302
16583
  };
16303
16584
  }
16304
16585
  return {
@@ -16306,7 +16587,8 @@ ${formatScopeRequest(scopeReq)}`;
16306
16587
  output: `Sub-agent completed:
16307
16588
  ${result.text}
16308
16589
 
16309
- Iterations: ${result.iterationCount}`
16590
+ Iterations: ${result.iterationCount}`,
16591
+ usage: pickUsage()
16310
16592
  };
16311
16593
  } finally {
16312
16594
  ctx.toolExecutor.setScope(parentScope);
@@ -16442,7 +16724,7 @@ var init_chunk_query = __esm(() => {
16442
16724
  });
16443
16725
 
16444
16726
  // src/tools/chunk-query.ts
16445
- import { readFileSync as readFileSync13 } from "node:fs";
16727
+ import { readFileSync as readFileSync14 } from "node:fs";
16446
16728
  import { resolve as resolve15 } from "node:path";
16447
16729
  var chunkQueryTool;
16448
16730
  var init_chunk_query2 = __esm(() => {
@@ -16454,7 +16736,7 @@ var init_chunk_query2 = __esm(() => {
16454
16736
  name: "chunk_query",
16455
16737
  icon: "\uD83E\uDDE9",
16456
16738
  description: "Answer a query over a large text (file or inline) by splitting it into chunks and querying the model per chunk in parallel, then optionally synthesizing a final answer. Use when the input is too large for the context window.",
16457
- tags: ["research", "code"],
16739
+ tags: ["research"],
16458
16740
  timeoutMs: 300000,
16459
16741
  parameters: {
16460
16742
  type: "object",
@@ -16515,7 +16797,7 @@ var init_chunk_query2 = __esm(() => {
16515
16797
  return { success: false, output: `[SCOPE] ${check.reason || "Path not allowed"}` };
16516
16798
  }
16517
16799
  try {
16518
- content = readFileSync13(resolvedInput, "utf8");
16800
+ content = readFileSync14(resolvedInput, "utf8");
16519
16801
  } catch (e) {
16520
16802
  return { success: false, output: `Cannot read ${inputPath}: ${e.message}` };
16521
16803
  }
@@ -16983,7 +17265,7 @@ var init_download_file = __esm(() => {
16983
17265
  name: "download_file",
16984
17266
  icon: "⬇️",
16985
17267
  description: "Download a file (image, archive, binary, font, etc.) from a URL and save it to disk. Returns only the path, size and content type — read the saved file with read_file/attach_image afterwards. Use this for binary files; web_fetch/web_browse return text only and cannot save bytes.",
16986
- tags: ["file", "research"],
17268
+ tags: ["research"],
16987
17269
  parameters: {
16988
17270
  type: "object",
16989
17271
  properties: {
@@ -17320,7 +17602,7 @@ var init_pipeline_run = __esm(() => {
17320
17602
  name: "pipeline_run",
17321
17603
  icon: "▶️",
17322
17604
  description: "Run a named pipeline with YAML definition. Creates a DAG of sub-agents that execute in dependency order.",
17323
- tags: ["shell", "code"],
17605
+ tags: ["shell"],
17324
17606
  parameters: {
17325
17607
  type: "object",
17326
17608
  properties: {
@@ -17878,7 +18160,7 @@ var init_mcp_call = __esm(() => {
17878
18160
  name: "mcp_call",
17879
18161
  icon: "\uD83D\uDD17",
17880
18162
  description: "Call a tool on an MCP (Model Context Protocol) server. MCP servers provide external capabilities like databases, APIs, or specialized tools.",
17881
- tags: ["code", "research"],
18163
+ tags: ["research"],
17882
18164
  parameters: {
17883
18165
  type: "object",
17884
18166
  properties: {
@@ -18010,7 +18292,7 @@ var init_search_history = __esm(() => {
18010
18292
  });
18011
18293
 
18012
18294
  // src/modules/memory/search.ts
18013
- import { readFileSync as readFileSync15, existsSync as existsSync30 } from "fs";
18295
+ import { readFileSync as readFileSync16, existsSync as existsSync30 } from "fs";
18014
18296
  import { join as join20 } from "path";
18015
18297
 
18016
18298
  class MemorySearch {
@@ -18025,7 +18307,7 @@ class MemorySearch {
18025
18307
  const path = join20(this.memoryDir, `${name}.md`);
18026
18308
  if (!existsSync30(path))
18027
18309
  continue;
18028
- const content = readFileSync15(path, "utf-8");
18310
+ const content = readFileSync16(path, "utf-8");
18029
18311
  const lines = content.split(`
18030
18312
  `);
18031
18313
  for (const line of lines) {
@@ -18037,7 +18319,7 @@ class MemorySearch {
18037
18319
  const prefsPath = join20(this.memoryDir, "preferences.json");
18038
18320
  if (existsSync30(prefsPath)) {
18039
18321
  try {
18040
- const prefs = JSON.parse(readFileSync15(prefsPath, "utf-8"));
18322
+ const prefs = JSON.parse(readFileSync16(prefsPath, "utf-8"));
18041
18323
  for (const [key, value] of Object.entries(prefs)) {
18042
18324
  const searchStr = `${key}=${value}`;
18043
18325
  if (searchStr.toLowerCase().includes(lowerQuery)) {
@@ -18055,7 +18337,7 @@ var init_search = __esm(() => {
18055
18337
  });
18056
18338
 
18057
18339
  // src/modules/memory/store.ts
18058
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync11, appendFileSync as appendFileSync5, existsSync as existsSync31, mkdirSync as mkdirSync14 } from "fs";
18340
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, appendFileSync as appendFileSync5, existsSync as existsSync31, mkdirSync as mkdirSync14 } from "fs";
18059
18341
  import { join as join21 } from "path";
18060
18342
 
18061
18343
  class MemoryStore {
@@ -18081,7 +18363,7 @@ class MemoryStore {
18081
18363
  const path = join21(this.memoryDir, `${name}.md`);
18082
18364
  if (!existsSync31(path))
18083
18365
  return "";
18084
- return readFileSync16(path, "utf-8");
18366
+ return readFileSync17(path, "utf-8");
18085
18367
  }
18086
18368
  append(name, entry) {
18087
18369
  const path = join21(this.memoryDir, `${name}.md`);
@@ -18102,7 +18384,7 @@ class MemoryStore {
18102
18384
  if (!existsSync31(path))
18103
18385
  return {};
18104
18386
  try {
18105
- return JSON.parse(readFileSync16(path, "utf-8"));
18387
+ return JSON.parse(readFileSync17(path, "utf-8"));
18106
18388
  } catch {
18107
18389
  return {};
18108
18390
  }
@@ -19397,7 +19679,7 @@ __export(exports_image_utils, {
19397
19679
  detectMime: () => detectMime,
19398
19680
  bufferToDataUrl: () => bufferToDataUrl
19399
19681
  });
19400
- import { readFileSync as readFileSync17 } from "fs";
19682
+ import { readFileSync as readFileSync18 } from "fs";
19401
19683
  import { extname as extname4 } from "path";
19402
19684
  function detectMime(filePath) {
19403
19685
  const ext = extname4(filePath).toLowerCase();
@@ -19418,7 +19700,7 @@ async function readClipboardImage() {
19418
19700
  async function readClipboardFallback() {
19419
19701
  const { platform: platform6 } = await import("os");
19420
19702
  const { execSync } = await import("child_process");
19421
- const { readFileSync: readFileSync18, unlinkSync: unlinkSync5 } = await import("fs");
19703
+ const { readFileSync: readFileSync19, unlinkSync: unlinkSync5 } = await import("fs");
19422
19704
  const { join: join27 } = await import("path");
19423
19705
  if (platform6() !== "linux")
19424
19706
  return null;
@@ -19430,7 +19712,7 @@ async function readClipboardFallback() {
19430
19712
  for (const cmd of commands) {
19431
19713
  try {
19432
19714
  execSync(cmd, { timeout: 5000 });
19433
- const buf = readFileSync18(tmpPath);
19715
+ const buf = readFileSync19(tmpPath);
19434
19716
  unlinkSync5(tmpPath);
19435
19717
  if (buf.length > 0)
19436
19718
  return buf;
@@ -19442,7 +19724,7 @@ async function readClipboardFallback() {
19442
19724
  return null;
19443
19725
  }
19444
19726
  async function loadFileAsDataUrl(filePath) {
19445
- const buf = readFileSync17(filePath);
19727
+ const buf = readFileSync18(filePath);
19446
19728
  if (typeof Bun !== "undefined" && typeof Bun.Image !== "undefined") {
19447
19729
  try {
19448
19730
  const img = new Bun.Image(buf);
@@ -20042,7 +20324,7 @@ var init_auto_fixer = __esm(() => {
20042
20324
 
20043
20325
  // src/modules/plugins/builtin/lint-on-write.ts
20044
20326
  import { spawn as spawn7, execSync } from "child_process";
20045
- import { existsSync as existsSync35, readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "fs";
20327
+ import { existsSync as existsSync35, readFileSync as readFileSync19, writeFileSync as writeFileSync12 } from "fs";
20046
20328
  import { resolve as resolve17, extname as extname6, join as join28 } from "path";
20047
20329
  import { platform as platform6 } from "os";
20048
20330
  function lintCacheKey(baseDir, lintScript) {
@@ -20143,7 +20425,7 @@ class LintOnWritePlugin {
20143
20425
  if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
20144
20426
  let content = "";
20145
20427
  try {
20146
- content = readFileSync18(filePath, "utf-8");
20428
+ content = readFileSync19(filePath, "utf-8");
20147
20429
  } catch {
20148
20430
  return null;
20149
20431
  }
@@ -20189,7 +20471,7 @@ class LintOnWritePlugin {
20189
20471
  if (!existsSync35(packageJsonPath)) {
20190
20472
  return;
20191
20473
  }
20192
- const packageJson = JSON.parse(readFileSync18(packageJsonPath, "utf-8"));
20474
+ const packageJson = JSON.parse(readFileSync19(packageJsonPath, "utf-8"));
20193
20475
  lintScript = packageJson.scripts?.lint;
20194
20476
  if (!lintScript) {
20195
20477
  return;
@@ -20244,7 +20526,7 @@ ${stdout}`;
20244
20526
  const output = stderr || stdout;
20245
20527
  const errors = parseTscOutput(output);
20246
20528
  if (errors.length > 0) {
20247
- const fixResult = autoFixErrors(filePath, readFileSync18(filePath, "utf-8"), errors);
20529
+ const fixResult = autoFixErrors(filePath, readFileSync19(filePath, "utf-8"), errors);
20248
20530
  if (fixResult.fixed) {
20249
20531
  writeFileSync12(filePath, fixResult.newContent, "utf-8");
20250
20532
  result.output += `
@@ -20509,11 +20791,11 @@ class PlanTracker {
20509
20791
  var init_tracker = () => {};
20510
20792
 
20511
20793
  // src/modules/execution/plan-store.ts
20512
- import { readFileSync as readFileSync19, writeFileSync as writeFileSync13, renameSync as renameSync3, mkdirSync as mkdirSync15, existsSync as existsSync36, readdirSync as readdirSync11, rmSync } from "fs";
20794
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, renameSync as renameSync3, mkdirSync as mkdirSync15, existsSync as existsSync36, readdirSync as readdirSync11, rmSync } from "fs";
20513
20795
  import { join as join29 } from "path";
20514
20796
  function readPlanFile(path, fallbackBaseDir) {
20515
20797
  try {
20516
- const raw = readFileSync19(path, "utf-8");
20798
+ const raw = readFileSync20(path, "utf-8");
20517
20799
  if (!raw.trim())
20518
20800
  return null;
20519
20801
  const parsed = JSON.parse(raw);
@@ -20725,6 +21007,17 @@ var init_windows_commands = __esm(() => {
20725
21007
  FORBIDDEN_COMMANDS = new Set([
20726
21008
  "grep",
20727
21009
  "sed",
21010
+ "awk",
21011
+ "uniq",
21012
+ "xargs",
21013
+ "cut",
21014
+ "tr",
21015
+ "basename",
21016
+ "dirname",
21017
+ "export",
21018
+ "source",
21019
+ "sleep",
21020
+ "env",
20728
21021
  "ls",
20729
21022
  "find",
20730
21023
  "rm",
@@ -21784,7 +22077,7 @@ var init_plan_tool = __esm(() => {
21784
22077
  });
21785
22078
 
21786
22079
  // src/modules/execution/module.ts
21787
- import { existsSync as existsSync37, readFileSync as readFileSync20 } from "fs";
22080
+ import { existsSync as existsSync37, readFileSync as readFileSync21 } from "fs";
21788
22081
  import { resolve as resolve18 } from "path";
21789
22082
 
21790
22083
  class ExecutionModule {
@@ -21934,14 +22227,35 @@ class ExecutionModule {
21934
22227
  });
21935
22228
  }).catch((e) => ctx.logger?.warn(`error web search: ${e.message}`));
21936
22229
  }
22230
+ autoCloseEvidenceSteps(plan) {
22231
+ let closed = 0;
22232
+ for (const step of plan.steps) {
22233
+ if (step.status === "done" || step.status === "skipped")
22234
+ continue;
22235
+ const tokens = extractFileLikeTokens(stripUrls(step.description));
22236
+ if (tokens.length === 0)
22237
+ continue;
22238
+ const allExist = tokens.every((f) => findExistingFile(this.baseDir, f) !== null);
22239
+ if (!allExist)
22240
+ continue;
22241
+ step.status = "done";
22242
+ step.note = `auto-closed by final audit: all named files exist (${tokens.join(", ")})`;
22243
+ closed++;
22244
+ }
22245
+ return closed;
22246
+ }
21937
22247
  async runFinalAudit() {
21938
22248
  if (!this.tracker) {
21939
22249
  if (!this.completedPlan)
21940
22250
  return null;
21941
22251
  const plan2 = this.completedPlan;
22252
+ const autoClosed2 = this.autoCloseEvidenceSteps(plan2);
21942
22253
  const audit2 = await this.auditor.audit(plan2);
21943
22254
  const pendingSteps2 = plan2.steps.flatMap((s) => s.status !== "done" && s.status !== "skipped" ? [`${s.id}. ${s.description}`] : []);
21944
22255
  const done2 = plan2.steps.filter((s) => s.status === "done").length;
22256
+ if (autoClosed2 > 0) {
22257
+ this.store.saveActive(plan2);
22258
+ }
21945
22259
  return {
21946
22260
  passed: audit2.passed && pendingSteps2.length === 0,
21947
22261
  done: done2,
@@ -21956,6 +22270,10 @@ class ExecutionModule {
21956
22270
  return null;
21957
22271
  }
21958
22272
  const plan = this.tracker.getPlan();
22273
+ const autoClosed = this.autoCloseEvidenceSteps(plan);
22274
+ if (autoClosed > 0) {
22275
+ this.store.saveActive(plan);
22276
+ }
21959
22277
  const audit = await this.auditor.audit(plan);
21960
22278
  const pendingSteps = plan.steps.flatMap((s) => s.status !== "done" && s.status !== "skipped" ? [`${s.id}. ${s.description}`] : []);
21961
22279
  const done = plan.steps.filter((s) => s.status === "done").length;
@@ -22150,7 +22468,7 @@ class ExecutionModule {
22150
22468
  if (!r)
22151
22469
  continue;
22152
22470
  try {
22153
- const content = readFileSync20(r, "utf-8");
22471
+ const content = readFileSync21(r, "utf-8");
22154
22472
  if (content.trim().length < 10) {
22155
22473
  emptyFiles.push(r);
22156
22474
  }
@@ -22258,7 +22576,7 @@ var init_module = __esm(() => {
22258
22576
  });
22259
22577
 
22260
22578
  // src/modules/security/session-encryption.ts
22261
- import { readFileSync as readFileSync21, writeFileSync as writeFileSync14, existsSync as existsSync38, readdirSync as readdirSync12, unlinkSync as unlinkSync5 } from "fs";
22579
+ import { readFileSync as readFileSync22, writeFileSync as writeFileSync14, existsSync as existsSync38, readdirSync as readdirSync12, unlinkSync as unlinkSync5 } from "fs";
22262
22580
  import { join as join30 } from "path";
22263
22581
  import { homedir as homedir9 } from "os";
22264
22582
 
@@ -22320,7 +22638,7 @@ class SessionFileEncryptor {
22320
22638
  });
22321
22639
  }
22322
22640
  readSessionFile(filePath) {
22323
- const content = readFileSync21(filePath, "utf8");
22641
+ const content = readFileSync22(filePath, "utf8");
22324
22642
  return this.decryptFileContent(content);
22325
22643
  }
22326
22644
  writeSessionFile(filePath, content) {
@@ -22328,7 +22646,7 @@ class SessionFileEncryptor {
22328
22646
  writeFileSync14(filePath, encrypted, "utf8");
22329
22647
  }
22330
22648
  readSessionJSON(filePath) {
22331
- const content = readFileSync21(filePath, "utf8");
22649
+ const content = readFileSync22(filePath, "utf8");
22332
22650
  return this.decryptJSON(content);
22333
22651
  }
22334
22652
  writeSessionJSON(filePath, obj) {
@@ -22336,7 +22654,7 @@ class SessionFileEncryptor {
22336
22654
  writeFileSync14(filePath, content, "utf8");
22337
22655
  }
22338
22656
  readSessionJSONL(filePath) {
22339
- const content = readFileSync21(filePath, "utf8");
22657
+ const content = readFileSync22(filePath, "utf8");
22340
22658
  const lines = content.split(`
22341
22659
  `).filter((line) => line.trim());
22342
22660
  const decryptedLines = this.decryptJSONL(lines);
@@ -22364,7 +22682,7 @@ class SessionFileEncryptor {
22364
22682
  const filePath = join30(sessionDir, file);
22365
22683
  if (existsSync38(filePath) && !file.endsWith(".enc")) {
22366
22684
  try {
22367
- const content = readFileSync21(filePath, "utf8");
22685
+ const content = readFileSync22(filePath, "utf8");
22368
22686
  const encrypted = this.encryptFileContent(content);
22369
22687
  writeFileSync14(filePath + ".enc", encrypted, "utf8");
22370
22688
  unlinkSync5(filePath);
@@ -22381,7 +22699,7 @@ class SessionFileEncryptor {
22381
22699
  const encFilePath = join30(sessionDir, file);
22382
22700
  const decFilePath = encFilePath.slice(0, -4);
22383
22701
  try {
22384
- const content = readFileSync21(encFilePath, "utf8");
22702
+ const content = readFileSync22(encFilePath, "utf8");
22385
22703
  const decrypted = this.decryptFileContent(content);
22386
22704
  writeFileSync14(decFilePath, decrypted, "utf8");
22387
22705
  unlinkSync5(encFilePath);
@@ -22406,7 +22724,7 @@ import {
22406
22724
  existsSync as existsSync39,
22407
22725
  mkdirSync as mkdirSync16,
22408
22726
  readdirSync as readdirSync13,
22409
- readFileSync as readFileSync22,
22727
+ readFileSync as readFileSync23,
22410
22728
  rmSync as rmSync2,
22411
22729
  writeFileSync as writeFileSync15,
22412
22730
  appendFileSync as appendFileSync6
@@ -22474,7 +22792,7 @@ class SessionStore {
22474
22792
  if (!existsSync39(path))
22475
22793
  return null;
22476
22794
  try {
22477
- const raw = readFileSync22(path, "utf-8");
22795
+ const raw = readFileSync23(path, "utf-8");
22478
22796
  const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
22479
22797
  const meta = JSON.parse(content);
22480
22798
  this._metaCache.set(id, meta);
@@ -22488,7 +22806,7 @@ class SessionStore {
22488
22806
  if (!existsSync39(path))
22489
22807
  return null;
22490
22808
  try {
22491
- const raw = readFileSync22(path, "utf-8");
22809
+ const raw = readFileSync23(path, "utf-8");
22492
22810
  const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
22493
22811
  return JSON.parse(content);
22494
22812
  } catch {
@@ -22518,7 +22836,7 @@ class SessionStore {
22518
22836
  if (!existsSync39(path))
22519
22837
  return [];
22520
22838
  try {
22521
- const raw = readFileSync22(path, "utf-8");
22839
+ const raw = readFileSync23(path, "utf-8");
22522
22840
  const lines = raw.split(`
22523
22841
  `).filter(Boolean);
22524
22842
  const parseLine = (line) => {
@@ -22559,7 +22877,7 @@ class SessionStore {
22559
22877
  if (!existsSync39(path))
22560
22878
  return [];
22561
22879
  try {
22562
- const raw = readFileSync22(path, "utf-8");
22880
+ const raw = readFileSync23(path, "utf-8");
22563
22881
  const lines = raw.split(`
22564
22882
  `).filter(Boolean);
22565
22883
  const parseLine = (line) => {
@@ -22614,7 +22932,7 @@ class SessionStore {
22614
22932
  if (updatedAt < thirtyDaysAgo) {
22615
22933
  const historyPath = this.historyPath(session2.id);
22616
22934
  if (existsSync39(historyPath)) {
22617
- const content = readFileSync22(historyPath, "utf-8");
22935
+ const content = readFileSync23(historyPath, "utf-8");
22618
22936
  const compressed = gzipSync(content);
22619
22937
  const gzPath = join31(this.baseDir, `${session2.id}.jsonl.gz`);
22620
22938
  writeFileSync15(gzPath, compressed);
@@ -22723,6 +23041,13 @@ class SessionManager {
22723
23041
  return;
22724
23042
  this.store.appendSessionLog(this.activeId, entry);
22725
23043
  }
23044
+ loadSessionLog(id) {
23045
+ try {
23046
+ return this.store.loadSessionLog(id);
23047
+ } catch {
23048
+ return [];
23049
+ }
23050
+ }
22726
23051
  loadHistory() {
22727
23052
  if (!this.activeId)
22728
23053
  return [];
@@ -22834,7 +23159,7 @@ class ProfileCompressor {
22834
23159
  }
22835
23160
 
22836
23161
  // src/modules/user-profile/profile.ts
22837
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync16, existsSync as existsSync40, mkdirSync as mkdirSync17 } from "fs";
23162
+ import { readFileSync as readFileSync24, writeFileSync as writeFileSync16, existsSync as existsSync40, mkdirSync as mkdirSync17 } from "fs";
22838
23163
  import { join as join32 } from "path";
22839
23164
  import { homedir as homedir10, hostname, platform as platform8, type } from "os";
22840
23165
  import { env } from "process";
@@ -22869,7 +23194,7 @@ class UserProfile {
22869
23194
  if (!existsSync40(path))
22870
23195
  return null;
22871
23196
  try {
22872
- const data = JSON.parse(readFileSync23(path, "utf-8"));
23197
+ const data = JSON.parse(readFileSync24(path, "utf-8"));
22873
23198
  this.info = {
22874
23199
  platform: data.platform,
22875
23200
  os: data.os,
@@ -22904,7 +23229,7 @@ class UserProfile {
22904
23229
  var init_profile = () => {};
22905
23230
 
22906
23231
  // src/modules/skills/loader.ts
22907
- import { readdirSync as readdirSync14, readFileSync as readFileSync24, existsSync as existsSync41, statSync as statSync7 } from "fs";
23232
+ import { readdirSync as readdirSync14, readFileSync as readFileSync25, existsSync as existsSync41, statSync as statSync7 } from "fs";
22908
23233
  import { join as join33 } from "path";
22909
23234
 
22910
23235
  class SkillsLoader {
@@ -22931,7 +23256,7 @@ class SkillsLoader {
22931
23256
  }
22932
23257
  if (!entry.endsWith(".md") && !entry.endsWith(".skill.md"))
22933
23258
  continue;
22934
- const content = readFileSync24(fullPath, "utf-8");
23259
+ const content = readFileSync25(fullPath, "utf-8");
22935
23260
  const parsed = this.parseSkillFile(content, fullPath);
22936
23261
  if (parsed)
22937
23262
  skills.push(parsed);
@@ -23580,6 +23905,10 @@ var init_check_tool = __esm(() => {
23580
23905
  // src/modules/lsp/module.ts
23581
23906
  import { existsSync as existsSync42 } from "fs";
23582
23907
  import { relative as relative5, resolve as resolve21 } from "path";
23908
+ import { join as join34 } from "path";
23909
+ function hasTypeEnvironment(projectRoot) {
23910
+ return existsSync42(join34(projectRoot, "tsconfig.json")) || existsSync42(join34(projectRoot, "jsconfig.json")) || existsSync42(join34(projectRoot, "node_modules"));
23911
+ }
23583
23912
 
23584
23913
  class LspModule {
23585
23914
  name = "lsp";
@@ -23734,6 +24063,7 @@ ${items}`;
23734
24063
  const notes = [];
23735
24064
  const checkedFiles = [];
23736
24065
  let checked = 0;
24066
+ let suppressedTypeEnvDiags = 0;
23737
24067
  for (const file of files) {
23738
24068
  const serverConfig = getServerForFile(file, this.config);
23739
24069
  if (!serverConfig)
@@ -23743,10 +24073,20 @@ ${items}`;
23743
24073
  continue;
23744
24074
  const projectRoot = findProjectRoot(file, ctx.baseDir, serverConfig.workspaceMarkers ?? []);
23745
24075
  try {
23746
- const diags = await this.client.checkFile(file, ctx.baseDir, serverConfig, projectRoot);
24076
+ let diags = await this.client.checkFile(file, ctx.baseDir, serverConfig, projectRoot);
23747
24077
  this.failuresByServer.set(key, 0);
23748
24078
  checked++;
23749
24079
  checkedFiles.push(toForwardSlash(relative5(ctx.baseDir, file)));
24080
+ if (!hasTypeEnvironment(projectRoot)) {
24081
+ const kept = diags.filter((d) => {
24082
+ if (TYPE_ENV_DIAG_PATTERN.test(d.message)) {
24083
+ suppressedTypeEnvDiags++;
24084
+ return false;
24085
+ }
24086
+ return true;
24087
+ });
24088
+ diags = kept;
24089
+ }
23750
24090
  for (const d of diags) {
23751
24091
  if (d.severity === 1)
23752
24092
  errors.push({ file, diag: d });
@@ -23784,6 +24124,9 @@ ${items}`;
23784
24124
  if (checked > 0 && errors.length === 0 && warnings.length === 0) {
23785
24125
  lines.push(t("lsp.check_clean", { count: String(checked) }));
23786
24126
  }
24127
+ if (suppressedTypeEnvDiags > 0) {
24128
+ lines.push(`[lsp_check inconclusive: no tsconfig.json / node_modules near project root — ${suppressedTypeEnvDiags} module-resolution diagnostic(s) suppressed. Initialize the project (package.json + types) for accurate TypeScript checks.]`);
24129
+ }
23787
24130
  lines.push(...notes);
23788
24131
  if (lines.length === 0) {
23789
24132
  return {
@@ -23805,7 +24148,7 @@ function formatDiagnostics(diagnostics, filePath) {
23805
24148
  }).join(`
23806
24149
  `);
23807
24150
  }
23808
- var MAX_CONSECUTIVE_LSP_FAILURES = 3;
24151
+ var MAX_CONSECUTIVE_LSP_FAILURES = 3, TYPE_ENV_DIAG_PATTERN;
23809
24152
  var init_module5 = __esm(() => {
23810
24153
  init_client2();
23811
24154
  init_config();
@@ -23817,6 +24160,7 @@ var init_module5 = __esm(() => {
23817
24160
  init_i18n();
23818
24161
  init_check_tool();
23819
24162
  init_utils();
24163
+ TYPE_ENV_DIAG_PATTERN = /Cannot find module ['"][^'"]+['"] or its corresponding type declarations|Cannot find name '(__dirname|__filename|require|process|Buffer|console)'|Do you need to install type definitions/;
23820
24164
  });
23821
24165
 
23822
24166
  // src/modules/lsp/index.ts
@@ -23828,7 +24172,7 @@ var init_lsp = __esm(() => {
23828
24172
 
23829
24173
  // src/modules/lsp/startup-check.ts
23830
24174
  import { existsSync as existsSync43 } from "fs";
23831
- import { join as join34 } from "path";
24175
+ import { join as join35 } from "path";
23832
24176
  import { spawn as spawn9 } from "child_process";
23833
24177
  async function runStartupHealthCheck(config, baseDir, deps = {}) {
23834
24178
  if (!config.enabled)
@@ -23855,7 +24199,7 @@ ${result.lines.join(`
23855
24199
  }
23856
24200
  async function runCheck(config, baseDir, deps) {
23857
24201
  const projectRoot = findProjectRoot(baseDir, baseDir, ["tsconfig.json", "package.json"]);
23858
- if (existsSync43(join34(projectRoot, "tsconfig.json"))) {
24202
+ if (existsSync43(join35(projectRoot, "tsconfig.json"))) {
23859
24203
  const runTsc = deps.runTsc ?? runTscDefault;
23860
24204
  const errors = await runTsc(projectRoot, STARTUP_CHECK_TIMEOUT_MS);
23861
24205
  if (errors.length === 0)
@@ -23957,8 +24301,8 @@ var init_startup_check = __esm(() => {
23957
24301
  });
23958
24302
 
23959
24303
  // src/modules/indexer/walker.ts
23960
- import { readdirSync as readdirSync15, readFileSync as readFileSync25, statSync as statSync8, lstatSync, existsSync as existsSync44, watch } from "fs";
23961
- import { join as join35, relative as relative6, extname as extname7 } from "path";
24304
+ import { readdirSync as readdirSync15, readFileSync as readFileSync26, statSync as statSync8, lstatSync, existsSync as existsSync44, watch } from "fs";
24305
+ import { join as join36, relative as relative6, extname as extname7 } from "path";
23962
24306
 
23963
24307
  class Indexer {
23964
24308
  baseDir;
@@ -23996,7 +24340,7 @@ class Indexer {
23996
24340
  for (const entry of entries) {
23997
24341
  if (count >= this.MAX_FILES)
23998
24342
  return;
23999
- const fullPath = join35(dir, entry);
24343
+ const fullPath = join36(dir, entry);
24000
24344
  const relPath = relative6(this.baseDir, fullPath);
24001
24345
  try {
24002
24346
  const lst = lstatSync(fullPath, { throwIfNoEntry: false });
@@ -24011,7 +24355,7 @@ class Indexer {
24011
24355
  const ext = extname7(entry).toLowerCase();
24012
24356
  const language = LANGUAGES[ext];
24013
24357
  if (language) {
24014
- const content = readFileSync25(fullPath, "utf-8");
24358
+ const content = readFileSync26(fullPath, "utf-8");
24015
24359
  const exports = this.extractExports(content, language);
24016
24360
  files.push({ path: relPath, language, exports, size: stat2.size });
24017
24361
  totalSize += stat2.size;
@@ -24069,14 +24413,14 @@ var init_walker = __esm(() => {
24069
24413
  });
24070
24414
 
24071
24415
  // src/modules/indexer/cache.ts
24072
- import { readFileSync as readFileSync26, writeFileSync as writeFileSync17, existsSync as existsSync45, mkdirSync as mkdirSync18, rmSync as rmSync3 } from "fs";
24073
- import { join as join36 } from "path";
24416
+ import { readFileSync as readFileSync27, writeFileSync as writeFileSync17, existsSync as existsSync45, mkdirSync as mkdirSync18, rmSync as rmSync3 } from "fs";
24417
+ import { join as join37 } from "path";
24074
24418
 
24075
24419
  class IndexCache {
24076
24420
  cachePath;
24077
24421
  cache = null;
24078
24422
  constructor(cacheDir) {
24079
- this.cachePath = join36(cacheDir, "index-cache.json");
24423
+ this.cachePath = join37(cacheDir, "index-cache.json");
24080
24424
  }
24081
24425
  load() {
24082
24426
  if (this.cache)
@@ -24084,7 +24428,7 @@ class IndexCache {
24084
24428
  if (!existsSync45(this.cachePath))
24085
24429
  return null;
24086
24430
  try {
24087
- this.cache = JSON.parse(readFileSync26(this.cachePath, "utf-8"));
24431
+ this.cache = JSON.parse(readFileSync27(this.cachePath, "utf-8"));
24088
24432
  return this.cache;
24089
24433
  } catch {
24090
24434
  return null;
@@ -24092,7 +24436,7 @@ class IndexCache {
24092
24436
  }
24093
24437
  save(result) {
24094
24438
  this.cache = result;
24095
- const dir = join36(this.cachePath, "..");
24439
+ const dir = join37(this.cachePath, "..");
24096
24440
  if (!existsSync45(dir))
24097
24441
  mkdirSync18(dir, { recursive: true });
24098
24442
  writeFileSync17(this.cachePath, JSON.stringify(result), "utf-8");
@@ -24109,11 +24453,11 @@ class IndexCache {
24109
24453
  var init_cache = () => {};
24110
24454
 
24111
24455
  // src/modules/indexer/project-profile.ts
24112
- import { readFileSync as readFileSync27, existsSync as existsSync46 } from "fs";
24113
- import { join as join37 } from "path";
24456
+ import { readFileSync as readFileSync28, existsSync as existsSync46 } from "fs";
24457
+ import { join as join38 } from "path";
24114
24458
  function detectManifest(baseDir) {
24115
24459
  for (const manifest of MANIFEST_ORDER) {
24116
- if (existsSync46(join37(baseDir, manifest)))
24460
+ if (existsSync46(join38(baseDir, manifest)))
24117
24461
  return manifest;
24118
24462
  }
24119
24463
  return null;
@@ -24130,7 +24474,7 @@ function cleanDependency(entry) {
24130
24474
  }
24131
24475
  function readPackageJson(baseDir) {
24132
24476
  try {
24133
- const raw = JSON.parse(readFileSync27(join37(baseDir, "package.json"), "utf-8"));
24477
+ const raw = JSON.parse(readFileSync28(join38(baseDir, "package.json"), "utf-8"));
24134
24478
  if (!raw || typeof raw !== "object")
24135
24479
  return null;
24136
24480
  const profile = {
@@ -24154,7 +24498,7 @@ function readPackageJson(baseDir) {
24154
24498
  }
24155
24499
  function readPyproject(baseDir) {
24156
24500
  try {
24157
- const content = readFileSync27(join37(baseDir, "pyproject.toml"), "utf-8");
24501
+ const content = readFileSync28(join38(baseDir, "pyproject.toml"), "utf-8");
24158
24502
  const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
24159
24503
  const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
24160
24504
  if (nameMatch)
@@ -24170,7 +24514,7 @@ function readPyproject(baseDir) {
24170
24514
  }
24171
24515
  function readCargo(baseDir) {
24172
24516
  try {
24173
- const content = readFileSync27(join37(baseDir, "Cargo.toml"), "utf-8");
24517
+ const content = readFileSync28(join38(baseDir, "Cargo.toml"), "utf-8");
24174
24518
  const profile = { runtime: "rust", deps: [], devDeps: [], scripts: {} };
24175
24519
  const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
24176
24520
  if (nameMatch)
@@ -24194,7 +24538,7 @@ function readCargo(baseDir) {
24194
24538
  }
24195
24539
  function readGoMod(baseDir) {
24196
24540
  try {
24197
- const content = readFileSync27(join37(baseDir, "go.mod"), "utf-8");
24541
+ const content = readFileSync28(join38(baseDir, "go.mod"), "utf-8");
24198
24542
  const profile = { runtime: "go", deps: [], devDeps: [], scripts: {} };
24199
24543
  const moduleMatch = content.match(/^module\s+(\S+)/m);
24200
24544
  if (moduleMatch)
@@ -24212,7 +24556,7 @@ function readGoMod(baseDir) {
24212
24556
  }
24213
24557
  function readRequirements(baseDir) {
24214
24558
  try {
24215
- const content = readFileSync27(join37(baseDir, "requirements.txt"), "utf-8");
24559
+ const content = readFileSync28(join38(baseDir, "requirements.txt"), "utf-8");
24216
24560
  const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
24217
24561
  for (const line of content.split(`
24218
24562
  `)) {
@@ -24761,7 +25105,7 @@ var init_mcp = __esm(() => {
24761
25105
 
24762
25106
  // src/modules/memory/module.ts
24763
25107
  import { homedir as homedir11 } from "os";
24764
- import { join as join38 } from "path";
25108
+ import { join as join39 } from "path";
24765
25109
 
24766
25110
  class MemoryModule {
24767
25111
  name = "memory";
@@ -24770,7 +25114,7 @@ class MemoryModule {
24770
25114
  if (storeOrDir instanceof MemoryStore) {
24771
25115
  this.store = storeOrDir;
24772
25116
  } else {
24773
- const dir = storeOrDir || join38(homedir11(), ".mma", "memory");
25117
+ const dir = storeOrDir || join39(homedir11(), ".mma", "memory");
24774
25118
  this.store = new MemoryStore(dir);
24775
25119
  }
24776
25120
  }
@@ -24857,16 +25201,16 @@ var init_module8 = __esm(() => {
24857
25201
  });
24858
25202
 
24859
25203
  // src/core/version.ts
24860
- import { existsSync as existsSync47, readFileSync as readFileSync28 } from "fs";
24861
- import { join as join39, dirname as dirname15 } from "path";
25204
+ import { existsSync as existsSync47, readFileSync as readFileSync29 } from "fs";
25205
+ import { join as join40, dirname as dirname15 } from "path";
24862
25206
  import { fileURLToPath as fileURLToPath2 } from "url";
24863
25207
  function readMmaVersion() {
24864
25208
  const here = dirname15(fileURLToPath2(import.meta.url));
24865
- const candidates = [join39(here, "..", "..", "package.json"), join39(here, "..", "package.json")];
25209
+ const candidates = [join40(here, "..", "..", "package.json"), join40(here, "..", "package.json")];
24866
25210
  for (const p of candidates) {
24867
25211
  if (existsSync47(p)) {
24868
25212
  try {
24869
- const raw = JSON.parse(readFileSync28(p, "utf8"));
25213
+ const raw = JSON.parse(readFileSync29(p, "utf8"));
24870
25214
  if (raw.version)
24871
25215
  return raw.version;
24872
25216
  } catch {}
@@ -24877,21 +25221,21 @@ function readMmaVersion() {
24877
25221
  var init_version = () => {};
24878
25222
 
24879
25223
  // src/core/environment.ts
24880
- import { existsSync as existsSync48, readFileSync as readFileSync29, readdirSync as readdirSync16 } from "fs";
25224
+ import { existsSync as existsSync48, readFileSync as readFileSync30, readdirSync as readdirSync16 } from "fs";
24881
25225
  import { spawnSync as spawnSync3 } from "child_process";
24882
25226
  import { createRequire as createRequire2 } from "module";
24883
- import { join as join40, dirname as dirname16 } from "path";
25227
+ import { join as join41, dirname as dirname16 } from "path";
24884
25228
  import { fileURLToPath as fileURLToPath3 } from "url";
24885
25229
  import { arch, homedir as homedir12, hostname as hostname2, platform as platform10, release } from "os";
24886
25230
  import { env as env2 } from "process";
24887
25231
  function readEngineRequirement() {
24888
25232
  const here = dirname16(fileURLToPath3(import.meta.url));
24889
- const candidates = [join40(here, "..", "..", "package.json"), join40(here, "..", "package.json")];
25233
+ const candidates = [join41(here, "..", "..", "package.json"), join41(here, "..", "package.json")];
24890
25234
  for (const p of candidates) {
24891
25235
  if (!existsSync48(p))
24892
25236
  continue;
24893
25237
  try {
24894
- const raw = JSON.parse(readFileSync29(p, "utf8"));
25238
+ const raw = JSON.parse(readFileSync30(p, "utf8"));
24895
25239
  if (raw.engines?.node)
24896
25240
  return String(raw.engines.node);
24897
25241
  } catch {}
@@ -24954,7 +25298,7 @@ function toolVersion(cmd) {
24954
25298
  function playwrightBrowsersDir() {
24955
25299
  if (process.env.PLAYWRIGHT_BROWSERS_PATH)
24956
25300
  return process.env.PLAYWRIGHT_BROWSERS_PATH;
24957
- return process.platform === "win32" ? join40(homedir12(), "AppData", "Local", "ms-playwright") : join40(homedir12(), ".cache", "ms-playwright");
25301
+ return process.platform === "win32" ? join41(homedir12(), "AppData", "Local", "ms-playwright") : join41(homedir12(), ".cache", "ms-playwright");
24958
25302
  }
24959
25303
  function playwrightInfo() {
24960
25304
  let installed = false;
@@ -24964,7 +25308,7 @@ function playwrightInfo() {
24964
25308
  const require2 = createRequire2(import.meta.url);
24965
25309
  const pkgPath = require2.resolve("playwright/package.json");
24966
25310
  installed = existsSync48(pkgPath);
24967
- version = JSON.parse(readFileSync29(pkgPath, "utf8")).version || "";
25311
+ version = JSON.parse(readFileSync30(pkgPath, "utf8")).version || "";
24968
25312
  } catch {
24969
25313
  installed = false;
24970
25314
  }
@@ -25077,24 +25421,24 @@ __export(exports_manifest, {
25077
25421
  getCertMark: () => getCertMark,
25078
25422
  bundledManifestPath: () => bundledManifestPath
25079
25423
  });
25080
- import { existsSync as existsSync49, readFileSync as readFileSync30, mkdirSync as mkdirSync19, writeFileSync as writeFileSync18 } from "fs";
25081
- import { dirname as dirname17, join as join41 } from "path";
25424
+ import { existsSync as existsSync49, readFileSync as readFileSync31, mkdirSync as mkdirSync19, writeFileSync as writeFileSync18 } from "fs";
25425
+ import { dirname as dirname17, join as join42 } from "path";
25082
25426
  import { fileURLToPath as fileURLToPath4 } from "url";
25083
25427
  import { homedir as homedir13 } from "os";
25084
25428
  function manifestPath(projectDir) {
25085
- return join41(projectDir, "certification", "certifications.json");
25429
+ return join42(projectDir, "certification", "certifications.json");
25086
25430
  }
25087
25431
  function globalManifestDir(override) {
25088
- return override || process.env.MMA_CERT_HOME || join41(homedir13(), ".mma");
25432
+ return override || process.env.MMA_CERT_HOME || join42(homedir13(), ".mma");
25089
25433
  }
25090
25434
  function globalManifestPath(override) {
25091
- return join41(globalManifestDir(override), "certifications.json");
25435
+ return join42(globalManifestDir(override), "certifications.json");
25092
25436
  }
25093
25437
  function readManifest(projectDir) {
25094
25438
  const path = manifestPath(projectDir);
25095
25439
  try {
25096
25440
  if (existsSync49(path)) {
25097
- const raw = JSON.parse(readFileSync30(path, "utf-8"));
25441
+ const raw = JSON.parse(readFileSync31(path, "utf-8"));
25098
25442
  return { version: 1, certifications: raw.certifications ?? [] };
25099
25443
  }
25100
25444
  } catch {}
@@ -25102,14 +25446,14 @@ function readManifest(projectDir) {
25102
25446
  }
25103
25447
  function saveManifest(m, projectDir) {
25104
25448
  const path = manifestPath(projectDir);
25105
- mkdirSync19(join41(projectDir, "certification"), { recursive: true });
25449
+ mkdirSync19(join42(projectDir, "certification"), { recursive: true });
25106
25450
  writeFileSync18(path, JSON.stringify(m, null, 2), "utf-8");
25107
25451
  }
25108
25452
  function readGlobalManifest(override) {
25109
25453
  const path = globalManifestPath(override);
25110
25454
  try {
25111
25455
  if (existsSync49(path)) {
25112
- const raw = JSON.parse(readFileSync30(path, "utf-8"));
25456
+ const raw = JSON.parse(readFileSync31(path, "utf-8"));
25113
25457
  return { version: 1, certifications: raw.certifications ?? [] };
25114
25458
  }
25115
25459
  } catch {}
@@ -25175,14 +25519,14 @@ function getCertMark(model, providerUrl, currentVersion, projectDir, globalOverr
25175
25519
  return isFullyPassed(entry) ? "certified" : "none";
25176
25520
  }
25177
25521
  function syncSnapshotPath(override) {
25178
- return join41(globalManifestDir(override), "certifications.synced.json");
25522
+ return join42(globalManifestDir(override), "certifications.synced.json");
25179
25523
  }
25180
25524
  function bundledManifestPath() {
25181
25525
  const here = dirname17(fileURLToPath4(import.meta.url));
25182
25526
  const candidates = [
25183
- join41(here, "certification", "certifications.json"),
25184
- join41(here, "..", "certification", "certifications.json"),
25185
- join41(here, "..", "..", "..", "certification", "certifications.json")
25527
+ join42(here, "certification", "certifications.json"),
25528
+ join42(here, "..", "certification", "certifications.json"),
25529
+ join42(here, "..", "..", "..", "certification", "certifications.json")
25186
25530
  ];
25187
25531
  for (const p of candidates) {
25188
25532
  if (existsSync49(p))
@@ -25195,9 +25539,9 @@ function syncGlobalManifest(override, bundledPathOverride) {
25195
25539
  const bundledPath = bundledPathOverride ?? bundledManifestPath();
25196
25540
  if (!bundledPath || !existsSync49(bundledPath))
25197
25541
  return { synced: false, reason: "no-bundled" };
25198
- const raw = readFileSync30(bundledPath, "utf-8");
25542
+ const raw = readFileSync31(bundledPath, "utf-8");
25199
25543
  const snapshotPath = syncSnapshotPath(override);
25200
- if (existsSync49(snapshotPath) && readFileSync30(snapshotPath, "utf-8") === raw) {
25544
+ if (existsSync49(snapshotPath) && readFileSync31(snapshotPath, "utf-8") === raw) {
25201
25545
  return { synced: false, reason: "unchanged" };
25202
25546
  }
25203
25547
  const bundled = JSON.parse(raw);
@@ -25227,11 +25571,11 @@ __export(exports_probe, {
25227
25571
  getCachedProbeResult: () => getCachedProbeResult,
25228
25572
  cacheKey: () => cacheKey
25229
25573
  });
25230
- import { existsSync as existsSync50, readFileSync as readFileSync31, writeFileSync as writeFileSync19, mkdirSync as mkdirSync20 } from "fs";
25231
- import { join as join42, dirname as dirname18 } from "path";
25574
+ import { existsSync as existsSync50, readFileSync as readFileSync32, writeFileSync as writeFileSync19, mkdirSync as mkdirSync20 } from "fs";
25575
+ import { join as join43, dirname as dirname18 } from "path";
25232
25576
  import { homedir as homedir14 } from "os";
25233
25577
  function cachePath() {
25234
- return join42(homedir14(), ".mma", "reasoning-cache.json");
25578
+ return join43(homedir14(), ".mma", "reasoning-cache.json");
25235
25579
  }
25236
25580
  async function probeReasoningSupport(provider, strategy, signal) {
25237
25581
  if (strategy === "none")
@@ -25288,7 +25632,7 @@ function readDiskCache() {
25288
25632
  try {
25289
25633
  const path = cachePath();
25290
25634
  if (existsSync50(path)) {
25291
- return JSON.parse(readFileSync31(path, "utf-8"));
25635
+ return JSON.parse(readFileSync32(path, "utf-8"));
25292
25636
  }
25293
25637
  } catch {}
25294
25638
  return {};
@@ -25389,8 +25733,8 @@ __export(exports_bootstrap, {
25389
25733
  bootstrap: () => bootstrap
25390
25734
  });
25391
25735
  import { homedir as homedir15 } from "os";
25392
- import { join as join43, resolve as resolve22 } from "path";
25393
- import { existsSync as existsSync51, readFileSync as readFileSync32 } from "fs";
25736
+ import { join as join44, resolve as resolve22 } from "path";
25737
+ import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
25394
25738
  function applyReasoningCliOverride(config, reasoningLevel) {
25395
25739
  if (!reasoningLevel || reasoningLevel === "auto")
25396
25740
  return;
@@ -25416,13 +25760,13 @@ function loadAgentsMdBlocks(baseDir, dir, skip) {
25416
25760
  return [];
25417
25761
  const blocks = [];
25418
25762
  const candidates = [
25419
- join43(baseDir, "AGENTS.md"),
25420
- join43(baseDir, ".mma", "AGENTS.md"),
25421
- join43(dir, "AGENTS.md")
25763
+ join44(baseDir, "AGENTS.md"),
25764
+ join44(baseDir, ".mma", "AGENTS.md"),
25765
+ join44(dir, "AGENTS.md")
25422
25766
  ];
25423
25767
  for (const p of candidates) {
25424
25768
  if (existsSync51(p)) {
25425
- const content = readFileSync32(p, "utf-8").trim();
25769
+ const content = readFileSync33(p, "utf-8").trim();
25426
25770
  if (content) {
25427
25771
  blocks.push({
25428
25772
  content,
@@ -25499,8 +25843,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
25499
25843
  `);
25500
25844
  }
25501
25845
  async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reasoningLevel) {
25502
- const dir = configDir || process.env.MMA_CONFIG_DIR || join43(homedir15(), ".mma");
25503
- const projectConfigPath = projectDir ? join43(projectDir, ".mmrc") : join43(process.cwd(), ".mmrc");
25846
+ const dir = configDir || process.env.MMA_CONFIG_DIR || join44(homedir15(), ".mma");
25847
+ const projectConfigPath = projectDir ? join44(projectDir, ".mmrc") : join44(process.cwd(), ".mmrc");
25504
25848
  const { config, legacyDetected } = loadConfig({ configDir: dir, projectConfigPath });
25505
25849
  setLocale(config.locale);
25506
25850
  applyReasoningCliOverride(config, reasoningLevel);
@@ -25511,7 +25855,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
25511
25855
  }
25512
25856
  } catch {}
25513
25857
  const logger4 = new Logger(config.logLevel);
25514
- logger4.setLogDir(join43(dir, "logs"));
25858
+ logger4.setLogDir(join44(dir, "logs"));
25515
25859
  logger4.debug("MMA bootstrap", {
25516
25860
  version: config.version,
25517
25861
  model: config.model
@@ -25540,7 +25884,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
25540
25884
  logger4.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
25541
25885
  }
25542
25886
  }
25543
- const profile = new UserProfile(join43(dir));
25887
+ const profile = new UserProfile(join44(dir));
25544
25888
  profile.load() || profile.collect();
25545
25889
  profile.save();
25546
25890
  const llmProvider = buildActiveProvider(config, logger4).provider;
@@ -25574,7 +25918,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
25574
25918
  for (const warning of envReport.warnings) {
25575
25919
  logger4.warn(warning);
25576
25920
  }
25577
- const projectMapCacheDir = join43(baseDir, ".mma");
25921
+ const projectMapCacheDir = join44(baseDir, ".mma");
25578
25922
  const indexerModule = new IndexerModule({
25579
25923
  baseDir,
25580
25924
  cacheDir: projectMapCacheDir
@@ -25585,9 +25929,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
25585
25929
  logger4.warn(`Project indexing failed: ${err.message}`);
25586
25930
  }
25587
25931
  const skillsLoader = new SkillsLoader;
25588
- const builtinDir = join43(import.meta.dirname, "skills", "builtin");
25589
- const globalDir = join43(homedir15(), ".agents", "skills");
25590
- const projectSkillsDir = join43(baseDir, ".mma", "skills");
25932
+ const builtinDir = join44(import.meta.dirname, "skills", "builtin");
25933
+ const globalDir = join44(homedir15(), ".agents", "skills");
25934
+ const projectSkillsDir = join44(baseDir, ".mma", "skills");
25591
25935
  const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
25592
25936
  const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
25593
25937
  const skillsModule = new SkillsModule(availableSkills, skillsBudget);
@@ -25603,7 +25947,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
25603
25947
  essential: true,
25604
25948
  estimatedTokens: estimateTokens(systemInfoContent)
25605
25949
  };
25606
- const sessionDir = join43(dir, "sessions");
25950
+ const sessionDir = join44(dir, "sessions");
25607
25951
  const sessionStore = new SessionStore(sessionDir);
25608
25952
  sessionStore.init();
25609
25953
  const sessionManager = new SessionManager(sessionStore, {
@@ -25687,7 +26031,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
25687
26031
  logger4.warn(`MCP init failed or timed out (${err instanceof Error ? err.message.slice(0, 120) : String(err)}) — continuing without MCP tools.`);
25688
26032
  }
25689
26033
  moduleRegistry.register(mcpModule);
25690
- const memoryStore = new MemoryStore(join43(dir, "memory"));
26034
+ const memoryStore = new MemoryStore(join44(dir, "memory"));
25691
26035
  const memoryModule = new MemoryModule(memoryStore);
25692
26036
  moduleRegistry.register(memoryModule);
25693
26037
  if (config.browser.enabled) {
@@ -25714,8 +26058,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
25714
26058
  pluginManager.register(plugin);
25715
26059
  pluginManager.register(plugin2);
25716
26060
  const pluginLoader = new PluginLoader;
25717
- const globalPluginsDir = join43(homedir15(), ".mma", "plugins");
25718
- const projectPluginsDir = join43(baseDir, ".mma", "plugins");
26061
+ const globalPluginsDir = join44(homedir15(), ".mma", "plugins");
26062
+ const projectPluginsDir = join44(baseDir, ".mma", "plugins");
25719
26063
  const mmaVersion = readMmaVersion();
25720
26064
  pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger4, {
25721
26065
  source: "global",
@@ -34087,6 +34431,50 @@ var init_scenarios = __esm(() => {
34087
34431
  { type: "fileContent", path: "file-b.txt", contains: "beta" }
34088
34432
  ]
34089
34433
  },
34434
+ {
34435
+ id: "5.2-moe-parallel-waves",
34436
+ title: "MoE parallel waves with distinct deliverables",
34437
+ tags: ["moe"],
34438
+ mode: "run",
34439
+ timeoutMs: 600000,
34440
+ prompt: "Create three files. These are independent tasks that must run in parallel: wave-one.txt containing 'w1-done', wave-two.txt containing 'w2-done', and wave-three.txt containing 'w3-done'. After all three exist, report completion.",
34441
+ config: {
34442
+ moe: { enabled: true },
34443
+ orchestrator: { model: "" },
34444
+ experts: {
34445
+ code: { model: "", tool_tags: ["file", "code"], max_attempts: 3 }
34446
+ }
34447
+ },
34448
+ checks: [
34449
+ { type: "fileExists", path: "wave-one.txt" },
34450
+ { type: "fileExists", path: "wave-two.txt" },
34451
+ { type: "fileExists", path: "wave-three.txt" },
34452
+ { type: "fileContent", path: "wave-one.txt", contains: "w1-done" },
34453
+ { type: "fileContent", path: "wave-two.txt", contains: "w2-done" },
34454
+ { type: "fileContent", path: "wave-three.txt", contains: "w3-done" }
34455
+ ]
34456
+ },
34457
+ {
34458
+ id: "5.3-moe-read-after-write",
34459
+ title: "MoE read-after-write via input_from dependency",
34460
+ tags: ["moe"],
34461
+ mode: "run",
34462
+ timeoutMs: 600000,
34463
+ prompt: "Two sequential steps. Step 1: create data.txt containing the exact token DATA_TOKEN_XYZ. Step 2 (depends on step 1 — it reads data.txt): create summary.txt that contains the exact token DATA_TOKEN_XYZ copied from data.txt. Step 2 must only run after data.txt exists.",
34464
+ config: {
34465
+ moe: { enabled: true },
34466
+ orchestrator: { model: "" },
34467
+ experts: {
34468
+ code: { model: "", tool_tags: ["file", "code"], max_attempts: 3 }
34469
+ }
34470
+ },
34471
+ checks: [
34472
+ { type: "fileExists", path: "data.txt" },
34473
+ { type: "fileExists", path: "summary.txt" },
34474
+ { type: "fileContent", path: "data.txt", contains: "DATA_TOKEN_XYZ" },
34475
+ { type: "fileContent", path: "summary.txt", contains: "DATA_TOKEN_XYZ" }
34476
+ ]
34477
+ },
34090
34478
  {
34091
34479
  id: "6.2-project-map",
34092
34480
  title: "Project map summary",
@@ -34117,8 +34505,8 @@ var init_scenarios = __esm(() => {
34117
34505
  });
34118
34506
 
34119
34507
  // src/modules/certification/loader.ts
34120
- import { existsSync as existsSync53, readdirSync as readdirSync17, readFileSync as readFileSync34 } from "fs";
34121
- import { join as join46 } from "path";
34508
+ import { existsSync as existsSync53, readdirSync as readdirSync17, readFileSync as readFileSync35 } from "fs";
34509
+ import { join as join47 } from "path";
34122
34510
  function validateScenario(s) {
34123
34511
  const errors2 = [];
34124
34512
  const isSkip = s.mode === "skip";
@@ -34175,7 +34563,7 @@ function loadScenarios(userDir) {
34175
34563
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
34176
34564
  continue;
34177
34565
  try {
34178
- const raw = readFileSync34(join46(userDir, file), "utf-8");
34566
+ const raw = readFileSync35(join47(userDir, file), "utf-8");
34179
34567
  const data = $parse(raw);
34180
34568
  const parsed = normalizeScenario(data, file);
34181
34569
  const errs = validateScenario(parsed);
@@ -34238,8 +34626,8 @@ var init_loader3 = __esm(() => {
34238
34626
  });
34239
34627
 
34240
34628
  // src/modules/certification/fact-checker.ts
34241
- import { existsSync as existsSync54, readFileSync as readFileSync35, statSync as statSync9 } from "fs";
34242
- import { join as join47 } from "path";
34629
+ import { existsSync as existsSync54, readFileSync as readFileSync36, statSync as statSync9 } from "fs";
34630
+ import { join as join48 } from "path";
34243
34631
  function checkSandbox(sandboxDir, checks, exitCode, output) {
34244
34632
  const failures = [];
34245
34633
  for (const check of checks) {
@@ -34256,16 +34644,16 @@ function runCheck2(sandboxDir, check, exitCode, output) {
34256
34644
  case "outputContains":
34257
34645
  return output.includes(check.text);
34258
34646
  case "fileExists":
34259
- return isFile(join47(sandboxDir, check.path));
34647
+ return isFile(join48(sandboxDir, check.path));
34260
34648
  case "fileNotExists":
34261
- return !existsSync54(join47(sandboxDir, check.path));
34649
+ return !existsSync54(join48(sandboxDir, check.path));
34262
34650
  case "dirExists":
34263
- return isDir(join47(sandboxDir, check.path));
34651
+ return isDir(join48(sandboxDir, check.path));
34264
34652
  case "fileContent": {
34265
- const abs = join47(sandboxDir, check.path);
34653
+ const abs = join48(sandboxDir, check.path);
34266
34654
  if (!isFile(abs))
34267
34655
  return false;
34268
- const content = readFileSync35(abs, "utf-8");
34656
+ const content = readFileSync36(abs, "utf-8");
34269
34657
  if (check.contains !== undefined)
34270
34658
  return content.includes(check.contains);
34271
34659
  if (check.equals !== undefined)
@@ -34273,10 +34661,10 @@ function runCheck2(sandboxDir, check, exitCode, output) {
34273
34661
  return false;
34274
34662
  }
34275
34663
  case "fileRegex": {
34276
- const abs = join47(sandboxDir, check.path);
34664
+ const abs = join48(sandboxDir, check.path);
34277
34665
  if (!isFile(abs))
34278
34666
  return false;
34279
- return new RegExp(check.pattern).test(readFileSync35(abs, "utf-8"));
34667
+ return new RegExp(check.pattern).test(readFileSync36(abs, "utf-8"));
34280
34668
  }
34281
34669
  default:
34282
34670
  return false;
@@ -34322,8 +34710,8 @@ var init_fact_checker = () => {};
34322
34710
 
34323
34711
  // src/modules/certification/runner.ts
34324
34712
  import { spawn as spawn10 } from "child_process";
34325
- import { existsSync as existsSync55, mkdirSync as mkdirSync21, rmSync as rmSync4, cpSync as cpSync2, writeFileSync as writeFileSync21, readdirSync as readdirSync18, readFileSync as readFileSync36 } from "fs";
34326
- import { join as join48, resolve as resolve23, dirname as dirname21, relative as relative7 } from "path";
34713
+ import { existsSync as existsSync55, mkdirSync as mkdirSync21, rmSync as rmSync4, cpSync as cpSync2, writeFileSync as writeFileSync21, readdirSync as readdirSync18, readFileSync as readFileSync37 } from "fs";
34714
+ import { join as join49, resolve as resolve23, dirname as dirname21, relative as relative7 } from "path";
34327
34715
  async function runScenario(scenario, opts) {
34328
34716
  if (scenario.mode === "skip") {
34329
34717
  return {
@@ -34343,7 +34731,7 @@ async function runScenario(scenario, opts) {
34343
34731
  let firstError;
34344
34732
  let lastFailedSandbox;
34345
34733
  for (let i = 1;i <= reps; i++) {
34346
- const sandbox = join48(opts.sandboxBase, `run-${scenario.id}-${i}`);
34734
+ const sandbox = join49(opts.sandboxBase, `run-${scenario.id}-${i}`);
34347
34735
  let failures = [];
34348
34736
  let exitCode = -1;
34349
34737
  let output = "";
@@ -34367,9 +34755,9 @@ async function runScenario(scenario, opts) {
34367
34755
  env3.MMA_PROVIDER_APIKEY = opts.providerKey;
34368
34756
  if (scenario.config && opts.baseConfig) {
34369
34757
  const merged = deepMergeAny(opts.baseConfig, scenario.config);
34370
- const certConfigDir = join48(sandbox, ".mma");
34758
+ const certConfigDir = join49(sandbox, ".mma");
34371
34759
  mkdirSync21(certConfigDir, { recursive: true });
34372
- writeFileSync21(join48(certConfigDir, "config.json"), JSON.stringify(merged, null, 2), "utf-8");
34760
+ writeFileSync21(join49(certConfigDir, "config.json"), JSON.stringify(merged, null, 2), "utf-8");
34373
34761
  env3.MMA_CONFIG_DIR = certConfigDir;
34374
34762
  }
34375
34763
  const res = await runner(env3, opts.mmaRoot, args, timeoutMs);
@@ -34416,11 +34804,11 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
34416
34804
  rmSync4(sandbox, { recursive: true, force: true });
34417
34805
  mkdirSync21(sandbox, { recursive: true });
34418
34806
  for (const f of scenario.fixtures ?? []) {
34419
- const src = join48(mmaRoot, f.source);
34807
+ const src = join49(mmaRoot, f.source);
34420
34808
  if (!existsSync55(src)) {
34421
34809
  throw new Error(`fixture missing: ${f.source}`);
34422
34810
  }
34423
- const dest = join48(sandbox, f.dest);
34811
+ const dest = join49(sandbox, f.dest);
34424
34812
  mkdirSync21(dirname21(dest), { recursive: true });
34425
34813
  cpSync2(src, dest);
34426
34814
  }
@@ -34433,10 +34821,10 @@ function collectDiagnostics(sandbox) {
34433
34821
  } else {
34434
34822
  lines.push(" Files created: (none)");
34435
34823
  }
34436
- const planPath = join48(sandbox, ".mma", "plans", "active.json");
34824
+ const planPath = join49(sandbox, ".mma", "plans", "active.json");
34437
34825
  if (existsSync55(planPath)) {
34438
34826
  try {
34439
- const plan = JSON.parse(readFileSync36(planPath, "utf-8"));
34827
+ const plan = JSON.parse(readFileSync37(planPath, "utf-8"));
34440
34828
  const steps = plan.steps ?? [];
34441
34829
  const done = steps.filter((s) => s.status === "done").length;
34442
34830
  const pending = steps.filter((s) => s.status === "pending" || s.status === "in_progress");
@@ -34455,7 +34843,7 @@ function listFiles(dir, root) {
34455
34843
  for (const entry of readdirSync18(dir, { withFileTypes: true })) {
34456
34844
  if (entry.name === ".mma")
34457
34845
  continue;
34458
- const abs = join48(dir, entry.name);
34846
+ const abs = join49(dir, entry.name);
34459
34847
  const rel = toForwardSlash(relative7(root, abs));
34460
34848
  if (entry.isDirectory()) {
34461
34849
  result.push(...listFiles(abs, root));
@@ -34467,15 +34855,15 @@ function listFiles(dir, root) {
34467
34855
  return result;
34468
34856
  }
34469
34857
  function resolveMmaEntry(mmaRoot) {
34470
- const dev = join48(mmaRoot, "src", "cli", "main.ts");
34858
+ const dev = join49(mmaRoot, "src", "cli", "main.ts");
34471
34859
  if (existsSync55(dev))
34472
34860
  return dev;
34473
- return join48(mmaRoot, "dist", "main.js");
34861
+ return join49(mmaRoot, "dist", "main.js");
34474
34862
  }
34475
34863
  function findMmaRoot(fromDir) {
34476
34864
  const candidates = [resolve23(fromDir, "..", "..", ".."), resolve23(fromDir, "..")];
34477
34865
  for (const c of candidates) {
34478
- if (existsSync55(join48(c, "package.json")))
34866
+ if (existsSync55(join49(c, "package.json")))
34479
34867
  return c;
34480
34868
  }
34481
34869
  return process.cwd();
@@ -34543,15 +34931,15 @@ __export(exports_cli, {
34543
34931
  certList: () => certList
34544
34932
  });
34545
34933
  import { rmSync as rmSync5, writeFileSync as writeFileSync22 } from "fs";
34546
- import { join as join49, dirname as dirname22 } from "path";
34934
+ import { join as join50, dirname as dirname22 } from "path";
34547
34935
  import { fileURLToPath as fileURLToPath5 } from "url";
34548
- import { existsSync as existsSync56, readFileSync as readFileSync37 } from "fs";
34936
+ import { existsSync as existsSync56, readFileSync as readFileSync38 } from "fs";
34549
34937
  function readVersion() {
34550
- const candidates = [join49(MMA_ROOT, "package.json")];
34938
+ const candidates = [join50(MMA_ROOT, "package.json")];
34551
34939
  for (const p of candidates) {
34552
34940
  if (existsSync56(p)) {
34553
34941
  try {
34554
- const raw = JSON.parse(readFileSync37(p, "utf-8"));
34942
+ const raw = JSON.parse(readFileSync38(p, "utf-8"));
34555
34943
  if (raw.version)
34556
34944
  return raw.version;
34557
34945
  } catch {}
@@ -34564,7 +34952,7 @@ function parseTags(s) {
34564
34952
  }
34565
34953
  async function certify(opts) {
34566
34954
  const providerUrl = opts.providerUrl || opts.config.provider.baseUrl;
34567
- const { scenarios, errors: errors2 } = loadScenarios(join49(opts.projectDir, ".mma", "certification", "scenarios"));
34955
+ const { scenarios, errors: errors2 } = loadScenarios(join50(opts.projectDir, ".mma", "certification", "scenarios"));
34568
34956
  for (const e of errors2)
34569
34957
  console.error(pc2.yellow(` ${e}`));
34570
34958
  let selected = filterByTags(scenarios, opts.tags);
@@ -34595,7 +34983,7 @@ async function certify(opts) {
34595
34983
  return;
34596
34984
  }
34597
34985
  console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
34598
- const sandboxBase = join49(process.cwd(), ".mma", "certification");
34986
+ const sandboxBase = join50(process.cwd(), ".mma", "certification");
34599
34987
  const results = [];
34600
34988
  const total = selected.length;
34601
34989
  let idx = 0;
@@ -34728,10 +35116,10 @@ function printResults(results) {
34728
35116
  }
34729
35117
  }
34730
35118
  function writeReport(entry, projectDir) {
34731
- const reportDir = join49(projectDir, "certification");
35119
+ const reportDir = join50(projectDir, "certification");
34732
35120
  const ts = entry.certifiedAt.replace(/[:.]/g, "-").slice(0, 19);
34733
35121
  const filename = `report-${entry.model.replace(/[/\\:]/g, "_")}-${ts}.json`;
34734
- const reportPath = join49(reportDir, filename);
35122
+ const reportPath = join50(reportDir, filename);
34735
35123
  const report = {
34736
35124
  model: entry.model,
34737
35125
  providerUrl: entry.providerUrl,
@@ -34774,7 +35162,7 @@ __export(exports_repl_commands, {
34774
35162
  registerAllCommands: () => registerAllCommands,
34775
35163
  COMMAND_GROUPS: () => COMMAND_GROUPS
34776
35164
  });
34777
- import { join as join51, dirname as dirname24 } from "path";
35165
+ import { join as join52, dirname as dirname24 } from "path";
34778
35166
  import { existsSync as existsSync58 } from "fs";
34779
35167
  function registerAllCommands(ctx) {
34780
35168
  registerBuiltinCommands(ctx);
@@ -34957,7 +35345,7 @@ function registerConfigCommands(ctx) {
34957
35345
  console.log(pc2.yellow(t("repl.wizard_running")));
34958
35346
  await ctx.withExclusiveInput(async () => {
34959
35347
  const answers = await runSetup(ctx.rl);
34960
- const configPath = join51(ctx.configDir, "config.json");
35348
+ const configPath = join52(ctx.configDir, "config.json");
34961
35349
  ctx.config.provider.type = answers.provider;
34962
35350
  ctx.config.provider.baseUrl = answers.apiBase;
34963
35351
  ctx.config.provider.apiKey = answers.apiKey;
@@ -35081,7 +35469,7 @@ function registerProviderCommands(ctx) {
35081
35469
  return;
35082
35470
  }
35083
35471
  ctx.config.model = name;
35084
- const configPath = join51(ctx.configDir, "config.json");
35472
+ const configPath = join52(ctx.configDir, "config.json");
35085
35473
  saveConfig(ctx.config, configPath, dirname24(configPath));
35086
35474
  await ctx.agent.reconfigure(ctx.config);
35087
35475
  console.log(pc2.green(t("repl.model_set", { name })));
@@ -35106,7 +35494,7 @@ function registerProviderCommands(ctx) {
35106
35494
  return;
35107
35495
  }
35108
35496
  ctx.config.contextWindow = size;
35109
- const configPath = join51(ctx.configDir, "config.json");
35497
+ const configPath = join52(ctx.configDir, "config.json");
35110
35498
  saveConfig(ctx.config, configPath, dirname24(configPath));
35111
35499
  await ctx.agent.reconfigure(ctx.config);
35112
35500
  console.log(pc2.green(t("cli.context_set", { size })));
@@ -35470,7 +35858,7 @@ async function runConfigMigrate(ctx) {
35470
35858
  const { hasDomainFiles: hasDomainFiles3 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
35471
35859
  const { loadConfig: loadCfg } = await Promise.resolve().then(() => (init_config2(), exports_config));
35472
35860
  const configDir = ctx.configDir;
35473
- const configPath = join51(configDir, "config.json");
35861
+ const configPath = join52(configDir, "config.json");
35474
35862
  if (hasDomainFiles3(configDir)) {
35475
35863
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
35476
35864
  return;
@@ -35480,11 +35868,11 @@ async function runConfigMigrate(ctx) {
35480
35868
  return;
35481
35869
  }
35482
35870
  console.log(t("config.migrate_start"));
35483
- const { config } = loadCfg({ configDir, projectConfigPath: join51(configDir, ".mmrc") });
35871
+ const { config } = loadCfg({ configDir, projectConfigPath: join52(configDir, ".mmrc") });
35484
35872
  saveConfig(config, configPath, configDir);
35485
35873
  const { renameSync: renameSync4, readdirSync: readdirSync19 } = await import("fs");
35486
35874
  renameSync4(configPath, configPath + ".bak");
35487
- const domainFiles = readdirSync19(join51(configDir, "config")).filter((f) => f.endsWith(".json"));
35875
+ const domainFiles = readdirSync19(join52(configDir, "config")).filter((f) => f.endsWith(".json"));
35488
35876
  console.log(pc2.green(t("config.migrate_done", { count: String(domainFiles.length) })));
35489
35877
  }
35490
35878
  var version2, COMMAND_GROUPS;
@@ -35546,14 +35934,14 @@ init_config2();
35546
35934
  init_setup();
35547
35935
  init_i18n();
35548
35936
  init_colors();
35549
- import { join as join50, dirname as dirname23 } from "path";
35937
+ import { join as join51, dirname as dirname23 } from "path";
35550
35938
  import { homedir as homedir17 } from "os";
35551
35939
  import { existsSync as existsSync57 } from "fs";
35552
35940
 
35553
35941
  // src/cli/security-commands.ts
35554
35942
  init_bootstrap();
35555
35943
  init_config2();
35556
- import { join as join44, dirname as dirname19 } from "path";
35944
+ import { join as join45, dirname as dirname19 } from "path";
35557
35945
  import { homedir as homedir16 } from "os";
35558
35946
 
35559
35947
  // src/modules/security/security-policies.ts
@@ -36079,7 +36467,7 @@ function createSecurityCommand(program2) {
36079
36467
  }
36080
36468
  });
36081
36469
  securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
36082
- const configPath = join44(homedir16(), ".mma", "config.json");
36470
+ const configPath = join45(homedir16(), ".mma", "config.json");
36083
36471
  const { config: appConfig } = await bootstrap();
36084
36472
  const validPresets = ["strict", "balanced", "permissive"];
36085
36473
  if (!validPresets.includes(preset)) {
@@ -36094,7 +36482,7 @@ function createSecurityCommand(program2) {
36094
36482
  console.log(t("cli.security.policy_description", { description: policy.description }));
36095
36483
  });
36096
36484
  securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
36097
- const configPath = join44(homedir16(), ".mma", "config.json");
36485
+ const configPath = join45(homedir16(), ".mma", "config.json");
36098
36486
  const { config: appConfig } = await bootstrap();
36099
36487
  const security = appConfig.security = appConfig.security || {};
36100
36488
  toggleSessionEncryption(security, true);
@@ -36102,7 +36490,7 @@ function createSecurityCommand(program2) {
36102
36490
  console.log(t("cli.security.encryption_enabled"));
36103
36491
  });
36104
36492
  securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
36105
- const configPath = join44(homedir16(), ".mma", "config.json");
36493
+ const configPath = join45(homedir16(), ".mma", "config.json");
36106
36494
  const { config: appConfig } = await bootstrap();
36107
36495
  const security = appConfig.security = appConfig.security || {};
36108
36496
  toggleSessionEncryption(security, false);
@@ -36110,7 +36498,7 @@ function createSecurityCommand(program2) {
36110
36498
  console.log(t("cli.security.encryption_disabled"));
36111
36499
  });
36112
36500
  securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
36113
- const configPath = join44(homedir16(), ".mma", "config.json");
36501
+ const configPath = join45(homedir16(), ".mma", "config.json");
36114
36502
  const { config: appConfig } = await bootstrap();
36115
36503
  const security = appConfig.security = appConfig.security || {};
36116
36504
  toggleAuditNotifier(security, true);
@@ -36118,7 +36506,7 @@ function createSecurityCommand(program2) {
36118
36506
  console.log(t("cli.security.audit_enabled"));
36119
36507
  });
36120
36508
  securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
36121
- const configPath = join44(homedir16(), ".mma", "config.json");
36509
+ const configPath = join45(homedir16(), ".mma", "config.json");
36122
36510
  const { config: appConfig } = await bootstrap();
36123
36511
  const security = appConfig.security = appConfig.security || {};
36124
36512
  toggleAuditNotifier(security, false);
@@ -36225,8 +36613,8 @@ function targetsFromProviders(entries) {
36225
36613
  init_version();
36226
36614
 
36227
36615
  // src/modules/updater/changelog-reader.ts
36228
- import { readFileSync as readFileSync33, existsSync as existsSync52 } from "fs";
36229
- import { dirname as dirname20, join as join45 } from "path";
36616
+ import { readFileSync as readFileSync34, existsSync as existsSync52 } from "fs";
36617
+ import { dirname as dirname20, join as join46 } from "path";
36230
36618
  function readChangelog(packageName) {
36231
36619
  try {
36232
36620
  let dir = dirname20(import.meta.url);
@@ -36234,13 +36622,13 @@ function readChangelog(packageName) {
36234
36622
  dir = decodeURIComponent(dir.slice(7));
36235
36623
  }
36236
36624
  for (let i = 0;i < 10; i++) {
36237
- const pkgPath = join45(dir, "package.json");
36625
+ const pkgPath = join46(dir, "package.json");
36238
36626
  if (existsSync52(pkgPath)) {
36239
- const pkg = JSON.parse(readFileSync33(pkgPath, "utf-8"));
36627
+ const pkg = JSON.parse(readFileSync34(pkgPath, "utf-8"));
36240
36628
  if (pkg.name === packageName) {
36241
- const changelogPath = join45(dir, "CHANGELOG.md");
36629
+ const changelogPath = join46(dir, "CHANGELOG.md");
36242
36630
  if (existsSync52(changelogPath)) {
36243
- return readFileSync33(changelogPath, "utf-8");
36631
+ return readFileSync34(changelogPath, "utf-8");
36244
36632
  }
36245
36633
  return null;
36246
36634
  }
@@ -36307,7 +36695,7 @@ var version = readMmaVersion();
36307
36695
  function buildInitCommand(program2) {
36308
36696
  program2.command("init").description(t("cli.init")).action(async () => {
36309
36697
  const answers = await runSetup();
36310
- const configPath = join50(homedir17(), ".mma", "config.json");
36698
+ const configPath = join51(homedir17(), ".mma", "config.json");
36311
36699
  const { config } = await bootstrap();
36312
36700
  config.provider.type = answers.provider;
36313
36701
  config.provider.baseUrl = answers.apiBase;
@@ -36354,7 +36742,7 @@ function buildInitCommand(program2) {
36354
36742
  function buildConfigCommands(program2) {
36355
36743
  const configCmd = program2.command("config").description(t("cli.manage_config"));
36356
36744
  configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
36357
- const configPath = join50(homedir17(), ".mma", "config.json");
36745
+ const configPath = join51(homedir17(), ".mma", "config.json");
36358
36746
  const { config } = await bootstrap();
36359
36747
  const keys = key.split(".");
36360
36748
  let obj = config;
@@ -36384,8 +36772,8 @@ function buildConfigCommands(program2) {
36384
36772
  configCmd.command("migrate").description(t("cli.migrate_config")).action(async () => {
36385
36773
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
36386
36774
  const { hasDomainFiles: hasDomainFiles3 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
36387
- const configDir = join50(homedir17(), ".mma");
36388
- const configPath = join50(configDir, "config.json");
36775
+ const configDir = join51(homedir17(), ".mma");
36776
+ const configPath = join51(configDir, "config.json");
36389
36777
  if (hasDomainFiles3(configDir)) {
36390
36778
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
36391
36779
  return;
@@ -36395,13 +36783,13 @@ function buildConfigCommands(program2) {
36395
36783
  return;
36396
36784
  }
36397
36785
  console.log(t("config.migrate_start"));
36398
- const { config } = loadConfig2({ configDir, projectConfigPath: join50(configDir, ".mmrc") });
36786
+ const { config } = loadConfig2({ configDir, projectConfigPath: join51(configDir, ".mmrc") });
36399
36787
  saveConfig(config, configPath, configDir);
36400
36788
  const bakPath = configPath + ".bak";
36401
36789
  const { renameSync: renameSync4 } = await import("fs");
36402
36790
  renameSync4(configPath, bakPath);
36403
36791
  const { readdirSync: readdirSync19 } = await import("fs");
36404
- const domainFiles = readdirSync19(join50(configDir, "config")).filter((f) => f.endsWith(".json"));
36792
+ const domainFiles = readdirSync19(join51(configDir, "config")).filter((f) => f.endsWith(".json"));
36405
36793
  console.log(pc2.green(t("config.migrate_done", { count: String(domainFiles.length) })));
36406
36794
  });
36407
36795
  }
@@ -36443,7 +36831,7 @@ function buildModelCommands(program2) {
36443
36831
  console.log(t("cli.model_hint"));
36444
36832
  });
36445
36833
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
36446
- const configPath = join50(homedir17(), ".mma", "config.json");
36834
+ const configPath = join51(homedir17(), ".mma", "config.json");
36447
36835
  const { config } = await bootstrap();
36448
36836
  config.model = name;
36449
36837
  saveConfig(config, configPath, dirname23(configPath));
@@ -36484,7 +36872,7 @@ function buildModelCommands(program2) {
36484
36872
  }
36485
36873
  function buildContextCommand(program2) {
36486
36874
  program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
36487
- const configPath = join50(homedir17(), ".mma", "config.json");
36875
+ const configPath = join51(homedir17(), ".mma", "config.json");
36488
36876
  const { config } = await bootstrap();
36489
36877
  const contextWindow = parseInt(size, 10);
36490
36878
  if (isNaN(contextWindow) || contextWindow < 1024) {
@@ -36532,7 +36920,7 @@ function buildProviderCommands(program2) {
36532
36920
  console.log(t("cli.base_url"), config.provider.baseUrl);
36533
36921
  });
36534
36922
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
36535
- const configPath = join50(homedir17(), ".mma", "config.json");
36923
+ const configPath = join51(homedir17(), ".mma", "config.json");
36536
36924
  const { config, agent } = await bootstrap();
36537
36925
  if (config.provider.entries && config.provider.entries.length > 0) {
36538
36926
  try {
@@ -36555,7 +36943,7 @@ function buildProviderCommands(program2) {
36555
36943
  }
36556
36944
  });
36557
36945
  provider.command("add").argument("<name>", "Provider type or label").option("--url <url>", "Base URL").option("--key <key>", "API key").option("--priority <n>", "Fallback priority (lower = tried first)").option("--context-window <n>", "Context window override for this entry").option("--rpm <n>", "Max requests per minute for this entry").option("--parallel <n>", "Max parallel tasks for this entry").description(t("cli.add_provider")).action(async (name, opts) => {
36558
- const configPath = join50(homedir17(), ".mma", "config.json");
36946
+ const configPath = join51(homedir17(), ".mma", "config.json");
36559
36947
  const { config } = await bootstrap();
36560
36948
  const entries = Array.isArray(config.provider.entries) ? config.provider.entries : [];
36561
36949
  if (entries.length === 0) {
@@ -36622,6 +37010,24 @@ function buildSessionCommands(program2) {
36622
37010
  console.log(`Model: ${meta.model}`);
36623
37011
  console.log(`Context: ${meta.contextWindow}`);
36624
37012
  console.log(`Project: ${meta.projectDir}`);
37013
+ const moeEvents = sessionManager.loadSessionLog(id).filter((e) => e.type.startsWith("moe_"));
37014
+ if (moeEvents.length > 0) {
37015
+ console.log("");
37016
+ console.log(pc2.cyan("MoE events:"));
37017
+ for (const e of moeEvents) {
37018
+ const ts = e.ts.slice(11, 19);
37019
+ if (e.type === "moe_subtask") {
37020
+ console.log(` ${pc2.dim(ts)} [subtask] ${e.subtaskId} (${e.expertTag}) ${e.status ?? ""}${e.durationMs !== undefined ? ` ${e.durationMs}ms` : ""}`);
37021
+ } else if (e.type === "moe_plan") {
37022
+ console.log(` ${pc2.dim(ts)} [plan] ${e.status === "ok" ? e.subtaskIds?.join(", ") : e.status}`);
37023
+ } else if (e.type === "moe_replan") {
37024
+ console.log(` ${pc2.dim(ts)} [replan] cycle ${e.cycle}: ${e.subtaskIds?.join(", ")}`);
37025
+ } else {
37026
+ const usage = e.usageByTag ? " | usage: " + Object.entries(e.usageByTag).map(([tag, u]) => `${tag}=${u.totalTokens}t`).join(", ") : "";
37027
+ console.log(` ${pc2.dim(ts)} [verify] ${e.decision ?? e.status ?? "?"}${e.explanation ? ` — ${e.explanation}` : ""}${usage}`);
37028
+ }
37029
+ }
37030
+ }
36625
37031
  });
36626
37032
  session2.command("delete").argument("<id>", "Session id").description(t("cli.delete_session")).action(async (id) => {
36627
37033
  const { sessionManager } = await bootstrap();
@@ -36667,6 +37073,11 @@ function createProgram() {
36667
37073
  createPluginCommand(program2);
36668
37074
  buildChangelogCommand(program2);
36669
37075
  program2.argument("[prompt...]", "Prompt to execute").description("Run a single prompt").action((prompt) => {});
37076
+ for (const cmd of program2.commands) {
37077
+ cmd.hook("postAction", () => {
37078
+ process.exit(0);
37079
+ });
37080
+ }
36670
37081
  return program2;
36671
37082
  }
36672
37083
 
@@ -37543,8 +37954,8 @@ class LineEditor {
37543
37954
  }
37544
37955
 
37545
37956
  // src/cli/repl.ts
37546
- import { existsSync as existsSync59, readFileSync as readFileSync39, writeFileSync as writeFileSync23 } from "fs";
37547
- import { join as join52 } from "path";
37957
+ import { existsSync as existsSync59, readFileSync as readFileSync40, writeFileSync as writeFileSync23 } from "fs";
37958
+ import { join as join53 } from "path";
37548
37959
  import { homedir as homedir18 } from "os";
37549
37960
 
37550
37961
  // src/cli/completer.ts
@@ -38376,10 +38787,10 @@ class Repl {
38376
38787
  this.envReport = envReport;
38377
38788
  this.execModule = execModule;
38378
38789
  this.slog = new SessionLogger(sessionManager, logger4);
38379
- this.configDir = configDir || join52(homedir18(), ".mma");
38790
+ this.configDir = configDir || join53(homedir18(), ".mma");
38380
38791
  this.baseDir = baseDir || process.cwd();
38381
38792
  this.noAgentsMd = noAgentsMd === true;
38382
- this.historyPath = historyPath ?? join52(homedir18(), ".mma", "repl-history");
38793
+ this.historyPath = historyPath ?? join53(homedir18(), ".mma", "repl-history");
38383
38794
  this.loadHistory();
38384
38795
  this.rl = process.stdin.isTTY ? new LineEditor({
38385
38796
  input: process.stdin,
@@ -38434,7 +38845,7 @@ class Repl {
38434
38845
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
38435
38846
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
38436
38847
  this.agent.shutdown();
38437
- const projectConfigPath = join52(this.baseDir, ".mmrc");
38848
+ const projectConfigPath = join53(this.baseDir, ".mmrc");
38438
38849
  const { config: freshConfig } = loadConfig2({
38439
38850
  configDir: this.configDir,
38440
38851
  projectConfigPath
@@ -38452,7 +38863,7 @@ class Repl {
38452
38863
  loadHistory() {
38453
38864
  if (existsSync59(this.historyPath)) {
38454
38865
  try {
38455
- const raw = readFileSync39(this.historyPath, "utf-8");
38866
+ const raw = readFileSync40(this.historyPath, "utf-8");
38456
38867
  this.history = raw.split(`
38457
38868
  `).filter(Boolean).slice(-this.maxHistory);
38458
38869
  } catch {
@@ -38853,9 +39264,9 @@ ${t("image.clipboard_empty")}`));
38853
39264
  row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
38854
39265
  } else {
38855
39266
  const agentsMdCandidates = [
38856
- join52(this.baseDir, "AGENTS.md"),
38857
- join52(this.baseDir, ".mma", "AGENTS.md"),
38858
- join52(this.configDir, "AGENTS.md")
39267
+ join53(this.baseDir, "AGENTS.md"),
39268
+ join53(this.baseDir, ".mma", "AGENTS.md"),
39269
+ join53(this.configDir, "AGENTS.md")
38859
39270
  ];
38860
39271
  const foundAgents = agentsMdCandidates.filter((p) => existsSync59(p));
38861
39272
  if (foundAgents.length > 0) {
@@ -38868,7 +39279,7 @@ ${t("image.clipboard_empty")}`));
38868
39279
  }
38869
39280
  const meta = this.sessionManager?.getActiveMeta();
38870
39281
  if (meta) {
38871
- const sessionPath = join52(this.configDir, "sessions", meta.id);
39282
+ const sessionPath = join53(this.configDir, "sessions", meta.id);
38872
39283
  row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
38873
39284
  }
38874
39285
  const isTty2 = process.stdout.isTTY === true;
@@ -38984,7 +39395,7 @@ init_config2();
38984
39395
  init_i18n();
38985
39396
  init_colors();
38986
39397
  import { existsSync as existsSync60 } from "fs";
38987
- import { join as join54, dirname as dirname25 } from "path";
39398
+ import { join as join55, dirname as dirname25 } from "path";
38988
39399
  import { homedir as homedir20 } from "os";
38989
39400
 
38990
39401
  // src/modules/updater/index.ts
@@ -39099,9 +39510,9 @@ init_data_sanitizer();
39099
39510
  init_i18n();
39100
39511
  init_utils();
39101
39512
  import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync22 } from "fs";
39102
- import { join as join53 } from "path";
39513
+ import { join as join54 } from "path";
39103
39514
  import { homedir as homedir19 } from "os";
39104
- var CRASH_LOG_DIR = join53(homedir19(), ".mma", "logs");
39515
+ var CRASH_LOG_DIR = join54(homedir19(), ".mma", "logs");
39105
39516
  var CRASH_LOG_FILE = "crash.jsonl";
39106
39517
  function formatCrashEntry(type2, err) {
39107
39518
  const message = errMsg(err);
@@ -39117,7 +39528,7 @@ function formatCrashEntry(type2, err) {
39117
39528
  function writeCrashEntry(dir, entry) {
39118
39529
  try {
39119
39530
  mkdirSync22(dir, { recursive: true });
39120
- appendFileSync7(join53(dir, CRASH_LOG_FILE), JSON.stringify(entry) + `
39531
+ appendFileSync7(join54(dir, CRASH_LOG_FILE), JSON.stringify(entry) + `
39121
39532
  `, "utf-8");
39122
39533
  } catch {}
39123
39534
  }
@@ -39294,8 +39705,8 @@ async function main() {
39294
39705
  await updater?.waitForIdle();
39295
39706
  process.exit(exitCode);
39296
39707
  } else {
39297
- const mmaDir = process.env.MMA_CONFIG_DIR || join54(homedir20(), ".mma");
39298
- const legacyConfigPath = join54(mmaDir, "config.json");
39708
+ const mmaDir = process.env.MMA_CONFIG_DIR || join55(homedir20(), ".mma");
39709
+ const legacyConfigPath = join55(mmaDir, "config.json");
39299
39710
  let hasAnyConfig = existsSync60(legacyConfigPath);
39300
39711
  if (!hasAnyConfig) {
39301
39712
  try {