micro-models-agent 0.52.0 → 0.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +358 -358
  2. package/dist/main.js +244 -122
  3. package/dist/modules/browser/bridge-server.mjs +202 -202
  4. package/dist/skills/builtin/git.md +36 -36
  5. package/dist/skills/builtin/typescript.md +35 -35
  6. package/package.json +1 -1
  7. package/dist/cli/commands.js +0 -447
  8. package/dist/cli/completer.js +0 -167
  9. package/dist/cli/index.js +0 -2
  10. package/dist/cli/main.js +0 -153
  11. package/dist/cli/plugin-commands.js +0 -36
  12. package/dist/cli/repl-commands.js +0 -761
  13. package/dist/cli/repl.js +0 -702
  14. package/dist/cli/run-result.js +0 -33
  15. package/dist/cli/security-commands.js +0 -164
  16. package/dist/cli/setup.js +0 -237
  17. package/dist/config/config.js +0 -276
  18. package/dist/config/defaults.js +0 -141
  19. package/dist/config/domains.js +0 -179
  20. package/dist/config/experts.js +0 -15
  21. package/dist/config/index.js +0 -4
  22. package/dist/config/security.js +0 -213
  23. package/dist/config/types.js +0 -1
  24. package/dist/core/agent-moe.js +0 -102
  25. package/dist/core/agent.js +0 -1018
  26. package/dist/core/bootstrap.js +0 -481
  27. package/dist/core/crash-handler.js +0 -51
  28. package/dist/core/environment.js +0 -199
  29. package/dist/core/index.js +0 -2
  30. package/dist/core/prompt-builder.js +0 -76
  31. package/dist/core/session-logger.js +0 -251
  32. package/dist/core/types.js +0 -1
  33. package/dist/core/version.js +0 -26
  34. package/dist/core/workspace.js +0 -76
  35. package/dist/i18n/en.json +0 -679
  36. package/dist/i18n/index.js +0 -46
  37. package/dist/i18n/ru.json +0 -679
  38. package/dist/index.js +0 -22
  39. package/dist/llm/image-utils.js +0 -143
  40. package/dist/llm/index.js +0 -4
  41. package/dist/llm/model-loader.js +0 -78
  42. package/dist/llm/openai-compat.js +0 -497
  43. package/dist/llm/orchestrator.js +0 -200
  44. package/dist/llm/provider.js +0 -10
  45. package/dist/llm/response.js +0 -39
  46. package/dist/llm/token-counter.js +0 -39
  47. package/dist/llm/types.js +0 -1
  48. package/dist/logger/app-logger.js +0 -189
  49. package/dist/logger/file-log.js +0 -151
  50. package/dist/logger/index.js +0 -1
  51. package/dist/migration/backup.js +0 -45
  52. package/dist/migration/detect.js +0 -50
  53. package/dist/migration/index.js +0 -2
  54. package/dist/modules/artifacts/store.js +0 -61
  55. package/dist/modules/browser/actions.js +0 -76
  56. package/dist/modules/browser/bridge-client.js +0 -199
  57. package/dist/modules/browser/bridge-path.js +0 -10
  58. package/dist/modules/browser/cookie-store.js +0 -24
  59. package/dist/modules/browser/driver.js +0 -136
  60. package/dist/modules/browser/index.js +0 -7
  61. package/dist/modules/browser/module.js +0 -29
  62. package/dist/modules/browser/session.js +0 -342
  63. package/dist/modules/browser/snapshot.js +0 -148
  64. package/dist/modules/browser/types.js +0 -12
  65. package/dist/modules/certification/cli.js +0 -213
  66. package/dist/modules/certification/fact-checker.js +0 -82
  67. package/dist/modules/certification/loader.js +0 -106
  68. package/dist/modules/certification/manifest.js +0 -58
  69. package/dist/modules/certification/runner.js +0 -245
  70. package/dist/modules/certification/scenarios.js +0 -407
  71. package/dist/modules/certification/types.js +0 -1
  72. package/dist/modules/context/chunk-query.js +0 -100
  73. package/dist/modules/context/fact-extractor.js +0 -168
  74. package/dist/modules/context/history.js +0 -15
  75. package/dist/modules/context/index.js +0 -1
  76. package/dist/modules/context/manager.js +0 -440
  77. package/dist/modules/execution/audit-runners.js +0 -206
  78. package/dist/modules/execution/auditor.js +0 -218
  79. package/dist/modules/execution/execution-plugin.js +0 -431
  80. package/dist/modules/execution/index.js +0 -8
  81. package/dist/modules/execution/module.js +0 -625
  82. package/dist/modules/execution/moe-executor.js +0 -304
  83. package/dist/modules/execution/plan-coverage.js +0 -68
  84. package/dist/modules/execution/plan-persister.js +0 -46
  85. package/dist/modules/execution/plan-store.js +0 -196
  86. package/dist/modules/execution/plan-tool.js +0 -677
  87. package/dist/modules/execution/plan-validator.js +0 -153
  88. package/dist/modules/execution/planner.js +0 -94
  89. package/dist/modules/execution/stuck-detector.js +0 -746
  90. package/dist/modules/execution/tracker.js +0 -69
  91. package/dist/modules/execution/types.js +0 -1
  92. package/dist/modules/execution/verifier.js +0 -235
  93. package/dist/modules/execution/windows-commands.js +0 -41
  94. package/dist/modules/hallucination/confidence.js +0 -66
  95. package/dist/modules/hallucination/consistency.js +0 -26
  96. package/dist/modules/hallucination/detector.js +0 -47
  97. package/dist/modules/hallucination/factual.js +0 -169
  98. package/dist/modules/hallucination/index.js +0 -5
  99. package/dist/modules/hallucination/js-identifiers.js +0 -262
  100. package/dist/modules/hallucination/llm-judge.js +0 -101
  101. package/dist/modules/index.js +0 -5
  102. package/dist/modules/indexer/cache.js +0 -40
  103. package/dist/modules/indexer/index.js +0 -3
  104. package/dist/modules/indexer/module.js +0 -246
  105. package/dist/modules/indexer/project-profile.js +0 -183
  106. package/dist/modules/indexer/walker.js +0 -101
  107. package/dist/modules/lsp/check-tool.js +0 -58
  108. package/dist/modules/lsp/client.js +0 -389
  109. package/dist/modules/lsp/command.js +0 -60
  110. package/dist/modules/lsp/config.js +0 -135
  111. package/dist/modules/lsp/index.js +0 -3
  112. package/dist/modules/lsp/module.js +0 -260
  113. package/dist/modules/lsp/probe.js +0 -86
  114. package/dist/modules/lsp/project-root.js +0 -32
  115. package/dist/modules/lsp/startup-check.js +0 -144
  116. package/dist/modules/lsp/types.js +0 -1
  117. package/dist/modules/mcp/client.js +0 -399
  118. package/dist/modules/mcp/index.js +0 -3
  119. package/dist/modules/mcp/module.js +0 -142
  120. package/dist/modules/mcp/registry.js +0 -15
  121. package/dist/modules/memory/index.js +0 -1
  122. package/dist/modules/memory/module.js +0 -96
  123. package/dist/modules/memory/search.js +0 -42
  124. package/dist/modules/memory/store.js +0 -69
  125. package/dist/modules/pipelines/engine.js +0 -60
  126. package/dist/modules/pipelines/index.js +0 -3
  127. package/dist/modules/pipelines/parser.js +0 -56
  128. package/dist/modules/pipelines/template.js +0 -14
  129. package/dist/modules/plugins/builtin/lint-on-write.js +0 -334
  130. package/dist/modules/plugins/builtin/notify.js +0 -9
  131. package/dist/modules/plugins/index.js +0 -1
  132. package/dist/modules/plugins/loader.js +0 -70
  133. package/dist/modules/plugins/manager.js +0 -261
  134. package/dist/modules/plugins/types.js +0 -1
  135. package/dist/modules/pricing/index.js +0 -61
  136. package/dist/modules/pricing/prices.js +0 -129
  137. package/dist/modules/processes/detect.js +0 -34
  138. package/dist/modules/processes/index.js +0 -2
  139. package/dist/modules/processes/registry.js +0 -327
  140. package/dist/modules/processes/runner.js +0 -23
  141. package/dist/modules/providers/create.js +0 -22
  142. package/dist/modules/providers/fallback.js +0 -79
  143. package/dist/modules/providers/health.js +0 -46
  144. package/dist/modules/providers/index.js +0 -5
  145. package/dist/modules/providers/manager.js +0 -161
  146. package/dist/modules/providers/presets.js +0 -128
  147. package/dist/modules/providers/registry.js +0 -22
  148. package/dist/modules/providers/types.js +0 -1
  149. package/dist/modules/registry.js +0 -48
  150. package/dist/modules/security/audit-log.js +0 -136
  151. package/dist/modules/security/audit-notifier.js +0 -292
  152. package/dist/modules/security/command-validator.js +0 -219
  153. package/dist/modules/security/content-scanner.js +0 -53
  154. package/dist/modules/security/data-sanitizer.js +0 -89
  155. package/dist/modules/security/encryption.js +0 -242
  156. package/dist/modules/security/index.js +0 -14
  157. package/dist/modules/security/network-validator.js +0 -88
  158. package/dist/modules/security/path-validator.js +0 -203
  159. package/dist/modules/security/rate-limiter.js +0 -119
  160. package/dist/modules/security/security-policies.js +0 -531
  161. package/dist/modules/security/session-encryption.js +0 -210
  162. package/dist/modules/security/session-isolation.js +0 -95
  163. package/dist/modules/session/index.js +0 -3
  164. package/dist/modules/session/manager.js +0 -172
  165. package/dist/modules/session/module.js +0 -24
  166. package/dist/modules/session/store.js +0 -222
  167. package/dist/modules/session/types.js +0 -1
  168. package/dist/modules/skills/index.js +0 -2
  169. package/dist/modules/skills/loader.js +0 -72
  170. package/dist/modules/skills/matcher.js +0 -27
  171. package/dist/modules/skills/module.js +0 -129
  172. package/dist/modules/types.js +0 -1
  173. package/dist/modules/updater/checker.js +0 -96
  174. package/dist/modules/updater/index.js +0 -2
  175. package/dist/modules/updater/module.js +0 -116
  176. package/dist/modules/user-profile/compressor.js +0 -16
  177. package/dist/modules/user-profile/index.js +0 -1
  178. package/dist/modules/user-profile/profile.js +0 -68
  179. package/dist/tools/approve.js +0 -33
  180. package/dist/tools/attach-image.js +0 -101
  181. package/dist/tools/bash.js +0 -519
  182. package/dist/tools/browser.js +0 -115
  183. package/dist/tools/chunk-query.js +0 -100
  184. package/dist/tools/create-dir.js +0 -56
  185. package/dist/tools/delete-file.js +0 -63
  186. package/dist/tools/download-file.js +0 -117
  187. package/dist/tools/edit-file.js +0 -80
  188. package/dist/tools/enable-tools.js +0 -59
  189. package/dist/tools/executor.js +0 -154
  190. package/dist/tools/file-info.js +0 -47
  191. package/dist/tools/filter-tools.js +0 -17
  192. package/dist/tools/glob-tool.js +0 -27
  193. package/dist/tools/grep-tool.js +0 -125
  194. package/dist/tools/hidden-tools-block.js +0 -37
  195. package/dist/tools/index.js +0 -78
  196. package/dist/tools/list-dir.js +0 -49
  197. package/dist/tools/load-skill.js +0 -43
  198. package/dist/tools/mcp-call.js +0 -69
  199. package/dist/tools/move-file.js +0 -86
  200. package/dist/tools/path-utils.js +0 -101
  201. package/dist/tools/pipeline-run.js +0 -145
  202. package/dist/tools/preview.js +0 -2
  203. package/dist/tools/process-kill.js +0 -40
  204. package/dist/tools/process-list.js +0 -37
  205. package/dist/tools/process-log.js +0 -54
  206. package/dist/tools/question.js +0 -141
  207. package/dist/tools/read-file.js +0 -179
  208. package/dist/tools/recall.js +0 -118
  209. package/dist/tools/registry.js +0 -47
  210. package/dist/tools/remember.js +0 -68
  211. package/dist/tools/scope-check.js +0 -32
  212. package/dist/tools/search-history.js +0 -85
  213. package/dist/tools/subagent.js +0 -196
  214. package/dist/tools/types.js +0 -1
  215. package/dist/tools/user-input.js +0 -123
  216. package/dist/tools/web-browse.js +0 -87
  217. package/dist/tools/web-fetch.js +0 -119
  218. package/dist/tools/web-search.js +0 -105
  219. package/dist/tools/write-file.js +0 -82
  220. package/dist/ui/box.js +0 -77
  221. package/dist/ui/colors.js +0 -4
  222. package/dist/ui/diff.js +0 -178
  223. package/dist/ui/index.js +0 -6
  224. package/dist/ui/line-editor.js +0 -822
  225. package/dist/ui/line-math.js +0 -73
  226. package/dist/ui/md-formatter.js +0 -212
  227. package/dist/ui/output.js +0 -13
  228. package/dist/ui/plan-view.js +0 -103
  229. package/dist/ui/renderer.js +0 -259
  230. package/dist/ui/spinner.js +0 -70
  231. package/dist/ui/table.js +0 -144
package/dist/main.js CHANGED
@@ -2658,7 +2658,7 @@ Fix the error and re-edit the file (a clean write clears the failure), or mark t
2658
2658
  "cli.cert_provider_url": "Provider base URL to certify against (default: current config)",
2659
2659
  "cli.cert_provider_key": "Provider API key (optional)",
2660
2660
  "cli.cert_context_window": "Context window size in tokens",
2661
- "cli.cert_tags": "Comma-separated scenario tags (core, security, image, network, browser)",
2661
+ "cli.cert_tags": "Comma-separated scenario tags (core, security, image, network, browser, shell, research)",
2662
2662
  "cli.cert_reps": "Default repetitions per scenario (overridden by scenario)",
2663
2663
  "cli.cert_force": "Re-run an existing certification",
2664
2664
  "cli.cert_clean": "Remove sandbox directories after a successful run",
@@ -3381,7 +3381,7 @@ var init_ru = __esm(() => {
3381
3381
  "cli.cert_provider_url": "Базовый URL провайдера для сертификации (по умолчанию — текущий конфиг)",
3382
3382
  "cli.cert_provider_key": "API-ключ провайдера (необязательно)",
3383
3383
  "cli.cert_context_window": "Размер контекстного окна в токенах",
3384
- "cli.cert_tags": "Теги сценариев через запятую (core, security, image, network, browser)",
3384
+ "cli.cert_tags": "Теги сценариев через запятую (core, security, image, network, browser, shell, research)",
3385
3385
  "cli.cert_reps": "Повторов по умолчанию на сценарий (переопределяется сценарием)",
3386
3386
  "cli.cert_force": "Перепрогнать существующую сертификацию",
3387
3387
  "cli.cert_clean": "Удалить песочницы после успешного прогона",
@@ -6629,6 +6629,9 @@ var init_executor = __esm(() => {
6629
6629
  // src/tools/path-utils.ts
6630
6630
  import { resolve, normalize, dirname as dirname2, basename, sep, relative, isAbsolute } from "path";
6631
6631
  import { existsSync as existsSync8 } from "fs";
6632
+ function toForwardSlash(p) {
6633
+ return p.replace(/\\/g, "/");
6634
+ }
6632
6635
  function isInsideDir(targetPath, dirPath) {
6633
6636
  const norm = (p) => process.platform === "win32" ? p.toLowerCase() : p;
6634
6637
  const t2 = norm(resolve(targetPath));
@@ -6860,7 +6863,7 @@ function matchesGlobPattern(targetPath, baseDir, pattern) {
6860
6863
  if (pattern.includes("*")) {
6861
6864
  const regexPattern = pattern.replace(/\*/g, "[^/\\\\]*").replace(/\?/g, ".").replace(/\./g, "\\.");
6862
6865
  const regex = new RegExp(`^${regexPattern}$`);
6863
- const relativePath = resolvedTargetPath.slice(resolvedBaseDir.length + 1).replace(/\\/g, "/");
6866
+ const relativePath = toForwardSlash(resolvedTargetPath.slice(resolvedBaseDir.length + 1));
6864
6867
  return regex.test(relativePath);
6865
6868
  }
6866
6869
  const exactTarget = resolve2(baseDir, pattern);
@@ -7446,17 +7449,12 @@ function isPathInSessionScope(sessionContext, path) {
7446
7449
  const resolvedPath = resolve5(path);
7447
7450
  const workingDir = resolve5(sessionContext.workingDir);
7448
7451
  const tempDir = resolve5(sessionContext.tempDir);
7449
- if (resolvedPath.startsWith(workingDir + "/") || resolvedPath.startsWith(workingDir + "\\")) {
7450
- return true;
7451
- }
7452
- if (resolvedPath.startsWith(tempDir + "/") || resolvedPath.startsWith(tempDir + "\\")) {
7453
- return true;
7454
- }
7455
- return false;
7452
+ return isInsideDir(resolvedPath, workingDir) || isInsideDir(resolvedPath, tempDir);
7456
7453
  }
7457
7454
  var DEFAULT_SESSION_ISOLATION;
7458
7455
  var init_session_isolation = __esm(() => {
7459
7456
  init_security();
7457
+ init_path_utils();
7460
7458
  DEFAULT_SESSION_ISOLATION = {
7461
7459
  enabled: false,
7462
7460
  isolatePlugins: true,
@@ -8424,15 +8422,52 @@ var init_command_validator = __esm(() => {
8424
8422
  DEFAULT_BASH_CONFIG = DEFAULT_SECURITY_CONFIG?.bash || FALLBACK_BASH_CONFIG;
8425
8423
  });
8426
8424
 
8427
- // src/modules/processes/registry.ts
8428
- import { spawn as spawn2, spawnSync } from "child_process";
8425
+ // src/modules/processes/kill-tree.ts
8426
+ import { spawnSync } from "child_process";
8429
8427
  import { platform } from "os";
8428
+ function sleepSync(ms) {
8429
+ try {
8430
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
8431
+ } catch {}
8432
+ }
8433
+ function taskkillPid(pid) {
8434
+ try {
8435
+ spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], {
8436
+ windowsHide: true,
8437
+ stdio: "ignore",
8438
+ timeout: 5000
8439
+ });
8440
+ } catch {}
8441
+ }
8442
+ function killTree(child) {
8443
+ const pid = child.pid;
8444
+ if (!pid)
8445
+ return;
8446
+ if (platform() === "win32") {
8447
+ taskkillPid(pid);
8448
+ sleepSync(150);
8449
+ taskkillPid(pid);
8450
+ return;
8451
+ }
8452
+ try {
8453
+ process.kill(-pid, "SIGTERM");
8454
+ } catch {
8455
+ try {
8456
+ child.kill("SIGKILL");
8457
+ } catch {}
8458
+ }
8459
+ }
8460
+ var init_kill_tree = () => {};
8461
+
8462
+ // src/modules/processes/registry.ts
8463
+ import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
8464
+ import { platform as platform2 } from "os";
8430
8465
  function getOemDecoder() {
8431
8466
  if (oemDecoder !== undefined)
8432
8467
  return oemDecoder;
8433
8468
  oemDecoder = null;
8434
8469
  try {
8435
- const cpOut = spawnSync("chcp.com", {
8470
+ const cpOut = spawnSync2("chcp.com", {
8436
8471
  encoding: "buffer",
8437
8472
  timeout: 2000,
8438
8473
  windowsHide: true
@@ -8467,38 +8502,6 @@ function decodeLineToUtf8(buf) {
8467
8502
  }
8468
8503
  return buf.toString("latin1");
8469
8504
  }
8470
- function sleepSync(ms) {
8471
- try {
8472
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
8473
- } catch {}
8474
- }
8475
- function taskkillPid(pid) {
8476
- try {
8477
- spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], {
8478
- windowsHide: true,
8479
- stdio: "ignore",
8480
- timeout: 5000
8481
- });
8482
- } catch {}
8483
- }
8484
- function killTree(child) {
8485
- const pid = child.pid;
8486
- if (!pid)
8487
- return;
8488
- if (platform() === "win32") {
8489
- taskkillPid(pid);
8490
- sleepSync(150);
8491
- taskkillPid(pid);
8492
- return;
8493
- }
8494
- try {
8495
- process.kill(-pid, "SIGTERM");
8496
- } catch {
8497
- try {
8498
- child.kill("SIGKILL");
8499
- } catch {}
8500
- }
8501
- }
8502
8505
 
8503
8506
  class ProcessRegistry {
8504
8507
  procs = new Map;
@@ -8525,7 +8528,7 @@ class ProcessRegistry {
8525
8528
  cwd,
8526
8529
  shell: true,
8527
8530
  windowsHide: true,
8528
- detached: platform() !== "win32",
8531
+ detached: platform2() !== "win32",
8529
8532
  stdio: ["ignore", "pipe", "pipe"]
8530
8533
  });
8531
8534
  } catch (e) {
@@ -8538,7 +8541,7 @@ class ProcessRegistry {
8538
8541
  entry.pid = child.pid ?? 0;
8539
8542
  let buf = "";
8540
8543
  let byteBuf = Buffer.alloc(0);
8541
- const isWin = platform() === "win32";
8544
+ const isWin = platform2() === "win32";
8542
8545
  const unixDecoder = new TextDecoder("utf-8");
8543
8546
  const pushLine = (line) => {
8544
8547
  if (entry.log.length >= MAX_LOG_LINES) {
@@ -8687,6 +8690,8 @@ class ProcessRegistry {
8687
8690
  }
8688
8691
  var MAX_LOG_LINES = 2000, MAX_KEPT_PROCESSES = 20, seq = 0, oemDecoder, processRegistry;
8689
8692
  var init_registry = __esm(() => {
8693
+ init_kill_tree();
8694
+ init_kill_tree();
8690
8695
  processRegistry = new ProcessRegistry;
8691
8696
  });
8692
8697
 
@@ -8694,10 +8699,11 @@ var init_registry = __esm(() => {
8694
8699
  var init_processes = __esm(() => {
8695
8700
  init_runner();
8696
8701
  init_registry();
8702
+ init_kill_tree();
8697
8703
  });
8698
8704
 
8699
8705
  // src/tools/bash.ts
8700
- import { platform as platform2 } from "os";
8706
+ import { platform as platform3 } from "os";
8701
8707
  function extractEchoFileWrite(command) {
8702
8708
  if (!/^\s*(?:echo|printf)\b/i.test(command))
8703
8709
  return null;
@@ -8721,17 +8727,17 @@ function translateSemicolonsForCmd(command) {
8721
8727
  return out;
8722
8728
  }
8723
8729
  function adaptCommandForWindows(command) {
8724
- if (platform2() !== "win32")
8730
+ if (platform3() !== "win32")
8725
8731
  return command;
8726
8732
  if (/\|\|\s*true\b/.test(command)) {
8727
8733
  command = command.replace(/\s*\|\|\s*true\b/g, "; exit 0");
8728
8734
  }
8729
8735
  const trimmed = command.trim();
8730
- if (trimmed.startsWith("mkdir -p ")) {
8731
- return trimmed.replace(/^mkdir -p /, "mkdir ");
8736
+ if (/^mkdir\s+(-p|--parents)\b/.test(trimmed)) {
8737
+ return trimmed.replace(/^mkdir\s+(-p|--parents)\s*/, "mkdir ");
8732
8738
  }
8733
- if (trimmed === "mkdir -p" || trimmed.startsWith("mkdir -p ")) {
8734
- return trimmed.replace(/mkdir -p/g, "mkdir");
8739
+ if (/^mkdir\s+(-p|--parents)\s*$/.test(trimmed)) {
8740
+ return "mkdir";
8735
8741
  }
8736
8742
  const firstWord = trimmed.split(/\s+/)[0]?.split(/[\\/]/).pop();
8737
8743
  const translated = firstWord ? UNIX_TO_WIN_TRANSLATE[firstWord] : undefined;
@@ -8942,7 +8948,7 @@ ${redirected.output}`
8942
8948
  output: t("exec.hidden_tool_hint", { tool: baseCmd })
8943
8949
  };
8944
8950
  }
8945
- if (platform2() === "win32") {
8951
+ if (platform3() === "win32") {
8946
8952
  const echoWrite = extractEchoFileWrite(originalCommand);
8947
8953
  if (echoWrite) {
8948
8954
  return {
@@ -9010,7 +9016,7 @@ ${output2}`;
9010
9016
  output2 = `(exit code ${code})`;
9011
9017
  }
9012
9018
  output2 = npmExecHint(output2);
9013
- if (platform2() === "win32") {
9019
+ if (platform3() === "win32") {
9014
9020
  const originalFirstWord = originalCommand.trim().split(/\s+/)[0]?.split(/[\\/]/).pop();
9015
9021
  if (originalFirstWord && originalFirstWord in UNIX_TO_WIN_HINTS) {
9016
9022
  if (code === 0) {
@@ -12010,7 +12016,7 @@ function findExistingFile(baseDir, filePath) {
12010
12016
  if (existsSync23(direct))
12011
12017
  return direct;
12012
12018
  const name = basename2(filePath).toLowerCase();
12013
- const suffix = filePath.replace(/\\/g, "/").toLowerCase();
12019
+ const suffix = toForwardSlash(filePath).toLowerCase();
12014
12020
  let found = null;
12015
12021
  const walk = (dir, depth) => {
12016
12022
  if (found || depth > RESOLVE_MAX_DEPTH)
@@ -12029,7 +12035,7 @@ function findExistingFile(baseDir, filePath) {
12029
12035
  if (SKIP_DIRS.has(e.name))
12030
12036
  continue;
12031
12037
  walk(full, depth + 1);
12032
- } else if (e.name.toLowerCase() === name || full.replace(/\\/g, "/").toLowerCase().endsWith("/" + suffix)) {
12038
+ } else if (e.name.toLowerCase() === name || toForwardSlash(full).toLowerCase().endsWith("/" + suffix)) {
12033
12039
  found = full;
12034
12040
  return;
12035
12041
  }
@@ -12157,6 +12163,7 @@ var MASS_EDIT_THRESHOLD = 10, RESOLVE_MAX_DEPTH = 8;
12157
12163
  var init_auditor = __esm(() => {
12158
12164
  init_i18n();
12159
12165
  init_js_identifiers();
12166
+ init_path_utils();
12160
12167
  init_audit_runners();
12161
12168
  init_audit_runners();
12162
12169
  });
@@ -14390,8 +14397,8 @@ var init_detector = __esm(() => {
14390
14397
  // src/modules/lsp/command.ts
14391
14398
  import { delimiter, join as join17 } from "path";
14392
14399
  import { existsSync as existsSync26 } from "fs";
14393
- import { platform as platform3 } from "os";
14394
- function resolveSpawnCommand(command, platformName = platform3(), pathEnv = process.env.PATH ?? "") {
14400
+ import { platform as platform4 } from "os";
14401
+ function resolveSpawnCommand(command, platformName = platform4(), pathEnv = process.env.PATH ?? "") {
14395
14402
  if (platformName !== "win32")
14396
14403
  return command;
14397
14404
  if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
@@ -14423,7 +14430,7 @@ var init_command = __esm(() => {
14423
14430
  });
14424
14431
 
14425
14432
  // src/modules/updater/checker.ts
14426
- import { platform as platform4 } from "os";
14433
+ import { platform as platform5 } from "os";
14427
14434
  function semverGt(a, b) {
14428
14435
  const pa = a.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
14429
14436
  const pb = b.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
@@ -14494,7 +14501,7 @@ class Updater {
14494
14501
  buildInstallCommand(latest) {
14495
14502
  const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
14496
14503
  const command = resolveSpawnCommand("npm");
14497
- if (platform4() === "win32" && /\.(cmd|bat)$/i.test(command)) {
14504
+ if (platform5() === "win32" && /\.(cmd|bat)$/i.test(command)) {
14498
14505
  return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
14499
14506
  }
14500
14507
  return { command, args: npmArgs };
@@ -17923,28 +17930,30 @@ async function readClipboardImage() {
17923
17930
  return readClipboardFallback();
17924
17931
  }
17925
17932
  async function readClipboardFallback() {
17926
- const { platform: platform5 } = await import("os");
17933
+ const { platform: platform6 } = await import("os");
17927
17934
  const { execSync } = await import("child_process");
17928
17935
  const { readFileSync: readFileSync18, unlinkSync: unlinkSync4 } = await import("fs");
17929
17936
  const { join: join26 } = await import("path");
17937
+ if (platform6() !== "linux")
17938
+ return null;
17930
17939
  const tmpPath = join26(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
17931
- try {
17932
- if (platform5() === "linux") {
17933
- execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, {
17934
- timeout: 5000
17935
- });
17936
- } else {
17937
- return null;
17938
- }
17939
- const buf = readFileSync18(tmpPath);
17940
- unlinkSync4(tmpPath);
17941
- return buf.length > 0 ? buf : null;
17942
- } catch {
17940
+ const commands = [
17941
+ `wl-paste --type image/png > "${tmpPath}" 2>/dev/null`,
17942
+ `xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`
17943
+ ];
17944
+ for (const cmd of commands) {
17943
17945
  try {
17946
+ execSync(cmd, { timeout: 5000 });
17947
+ const buf = readFileSync18(tmpPath);
17944
17948
  unlinkSync4(tmpPath);
17949
+ if (buf.length > 0)
17950
+ return buf;
17945
17951
  } catch {}
17946
- return null;
17947
17952
  }
17953
+ try {
17954
+ unlinkSync4(tmpPath);
17955
+ } catch {}
17956
+ return null;
17948
17957
  }
17949
17958
  async function loadFileAsDataUrl(filePath) {
17950
17959
  const buf = readFileSync17(filePath);
@@ -18387,7 +18396,7 @@ var init_loader = __esm(() => {
18387
18396
  import { spawn as spawn6, execSync } from "child_process";
18388
18397
  import { existsSync as existsSync33, readFileSync as readFileSync18 } from "fs";
18389
18398
  import { resolve as resolve18, extname as extname4, join as join27 } from "path";
18390
- import { platform as platform5 } from "os";
18399
+ import { platform as platform6 } from "os";
18391
18400
  function lintCacheKey(baseDir, lintScript) {
18392
18401
  return `${baseDir}::${lintScript}`;
18393
18402
  }
@@ -18408,7 +18417,7 @@ function contentHash(content) {
18408
18417
  function getWinDecoder() {
18409
18418
  if (_winDecoder !== undefined)
18410
18419
  return _winDecoder;
18411
- if (platform5() !== "win32") {
18420
+ if (platform6() !== "win32") {
18412
18421
  _winDecoder = new TextDecoder("utf-8");
18413
18422
  return _winDecoder;
18414
18423
  }
@@ -19102,9 +19111,9 @@ var init_windows_commands = __esm(() => {
19102
19111
  });
19103
19112
 
19104
19113
  // src/modules/execution/execution-plugin.ts
19105
- import { platform as platform6 } from "os";
19114
+ import { platform as platform7 } from "os";
19106
19115
  function normalizeBrokenPath(p) {
19107
- return p.replace(/\\/g, "/").replace(/^\.\//, "");
19116
+ return toForwardSlash(p).replace(/^\.\//, "");
19108
19117
  }
19109
19118
  function parseBrokenFile(line) {
19110
19119
  const trimmed = line.trim();
@@ -19332,7 +19341,7 @@ Last compile error: ${first[1]}`;
19332
19341
  if (call.name === "bash") {
19333
19342
  deps.stuckDetector.recordBashAttempt(false);
19334
19343
  }
19335
- if (call.name === "bash" && platform6() === "win32") {
19344
+ if (call.name === "bash" && platform7() === "win32") {
19336
19345
  const cmd = String(call.arguments?.command ?? "");
19337
19346
  const forbidden = forbiddenWindowsCommand(cmd);
19338
19347
  if (forbidden) {
@@ -19399,6 +19408,7 @@ var init_execution_plugin = __esm(() => {
19399
19408
  init_bash();
19400
19409
  init_windows_commands();
19401
19410
  init_js_identifiers();
19411
+ init_path_utils();
19402
19412
  FS_MUTATING_TOOLS = new Set([
19403
19413
  "write_file",
19404
19414
  "edit_file",
@@ -21057,7 +21067,7 @@ class ProfileCompressor {
21057
21067
  // src/modules/user-profile/profile.ts
21058
21068
  import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, existsSync as existsSync38, mkdirSync as mkdirSync17 } from "fs";
21059
21069
  import { join as join31 } from "path";
21060
- import { homedir as homedir10, hostname, platform as platform7, type } from "os";
21070
+ import { homedir as homedir10, hostname, platform as platform8, type } from "os";
21061
21071
  import { env } from "process";
21062
21072
 
21063
21073
  class UserProfile {
@@ -21069,7 +21079,7 @@ class UserProfile {
21069
21079
  }
21070
21080
  collect() {
21071
21081
  this.info = {
21072
- platform: platform7(),
21082
+ platform: platform8(),
21073
21083
  os: `${type()} ${hostname()}`,
21074
21084
  hostname: hostname(),
21075
21085
  shell: env.SHELL || env.ComSpec || "unknown",
@@ -21385,7 +21395,7 @@ var init_browser2 = __esm(() => {
21385
21395
  // src/modules/lsp/client.ts
21386
21396
  import { spawn as spawn7, execSync as execSync2 } from "child_process";
21387
21397
  import { resolve as resolve20 } from "path";
21388
- import { platform as platform8 } from "os";
21398
+ import { platform as platform9 } from "os";
21389
21399
 
21390
21400
  class FileOnlyLogger {
21391
21401
  logger;
@@ -21505,7 +21515,7 @@ class LspClient {
21505
21515
  if (config.command === "npx" && effectiveArgs.length > 0) {
21506
21516
  const binaryName = this.extractBinaryFromNpxArgs(effectiveArgs);
21507
21517
  if (binaryName) {
21508
- const whichCmd = platform8() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
21518
+ const whichCmd = platform9() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
21509
21519
  try {
21510
21520
  execSync2(whichCmd, { stdio: "pipe", timeout: 3000 });
21511
21521
  effectiveCommand = binaryName;
@@ -21518,7 +21528,7 @@ class LspClient {
21518
21528
  }
21519
21529
  return new Promise((resolve21, reject) => {
21520
21530
  const args = effectiveArgs;
21521
- const isWin = platform8() === "win32";
21531
+ const isWin = platform9() === "win32";
21522
21532
  let spawnCommand = resolveSpawnCommand(effectiveCommand);
21523
21533
  let spawnArgs = args;
21524
21534
  const spawnOpts = {
@@ -21682,7 +21692,7 @@ class LspClient {
21682
21692
  }
21683
21693
  }
21684
21694
  pathToUri(filePath) {
21685
- const normalized = filePath.replace(/\\/g, "/");
21695
+ const normalized = toForwardSlash(filePath);
21686
21696
  return /^[a-zA-Z]:/.test(normalized) ? `file:///${normalized}` : `file://${normalized}`;
21687
21697
  }
21688
21698
  languageFromPath(filePath) {
@@ -21730,6 +21740,7 @@ var DEFAULT_TIMEOUT = 15000;
21730
21740
  var init_client2 = __esm(() => {
21731
21741
  init_command();
21732
21742
  init_registry();
21743
+ init_path_utils();
21733
21744
  });
21734
21745
 
21735
21746
  // src/modules/lsp/check-tool.ts
@@ -21763,7 +21774,7 @@ async function walkDir(dir, depth, out, config) {
21763
21774
  }
21764
21775
  function formatCheckDiagnostics(items, baseDir) {
21765
21776
  return items.slice(0, 40).map(({ file, diag }) => {
21766
- const rel = relative3(baseDir, file).replace(/\\/g, "/");
21777
+ const rel = toForwardSlash(relative3(baseDir, file));
21767
21778
  const line = diag.range.start.line + 1;
21768
21779
  const col = diag.range.start.character + 1;
21769
21780
  const sev = severityLabels[diag.severity] ?? "unknown";
@@ -21774,6 +21785,7 @@ function formatCheckDiagnostics(items, baseDir) {
21774
21785
  var MAX_LSP_CHECK_FILES = 15, MAX_LSP_WALK_DEPTH = 4, SKIP_DIRS2, severityLabels;
21775
21786
  var init_check_tool = __esm(() => {
21776
21787
  init_config();
21788
+ init_path_utils();
21777
21789
  SKIP_DIRS2 = new Set(["node_modules", ".git", ".mma", "dist"]);
21778
21790
  severityLabels = {
21779
21791
  1: "error",
@@ -21952,7 +21964,7 @@ ${items}`;
21952
21964
  const diags = await this.client.checkFile(file, ctx.baseDir, serverConfig, projectRoot);
21953
21965
  this.failuresByServer.set(key, 0);
21954
21966
  checked++;
21955
- checkedFiles.push(relative4(ctx.baseDir, file).replace(/\\/g, "/"));
21967
+ checkedFiles.push(toForwardSlash(relative4(ctx.baseDir, file)));
21956
21968
  for (const d of diags) {
21957
21969
  if (d.severity === 1)
21958
21970
  errors.push({ file, diag: d });
@@ -22002,7 +22014,7 @@ ${items}`;
22002
22014
  }
22003
22015
  }
22004
22016
  function formatDiagnostics(diagnostics, filePath) {
22005
- const filename = filePath.replace(/\\/g, "/").split("/").pop() ?? filePath;
22017
+ const filename = toForwardSlash(filePath).split("/").pop() ?? filePath;
22006
22018
  return diagnostics.slice(0, 5).map((d) => {
22007
22019
  const line = d.range.start.line + 1;
22008
22020
  const col = d.range.start.character + 1;
@@ -22019,6 +22031,7 @@ var init_module5 = __esm(() => {
22019
22031
  init_path_validator();
22020
22032
  init_security();
22021
22033
  init_path_utils();
22034
+ init_path_utils();
22022
22035
  init_i18n();
22023
22036
  init_check_tool();
22024
22037
  });
@@ -22567,7 +22580,7 @@ class IndexerModule {
22567
22580
  const dirCounts = this.getDirectoryCounts(result);
22568
22581
  const topDirs = Object.entries(dirCounts).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([dir, count]) => `${dir} (${count})`).join(", ") || "-";
22569
22582
  const fileLines = result.files.slice(0, 100).map((f) => {
22570
- const path = f.path.replace(/\\/g, "/");
22583
+ const path = toForwardSlash(f.path);
22571
22584
  const exports = f.exports.length > 0 ? `: ${f.exports.join(", ")}` : "";
22572
22585
  return `- ${path}${exports}`;
22573
22586
  });
@@ -22589,7 +22602,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
22589
22602
  findDuplicateBasenames(result) {
22590
22603
  const byDir = {};
22591
22604
  for (const f of result.files) {
22592
- const path = f.path.replace(/\\/g, "/");
22605
+ const path = toForwardSlash(f.path);
22593
22606
  const idx = path.lastIndexOf("/");
22594
22607
  const dir = idx >= 0 ? path.slice(0, idx) : "";
22595
22608
  const name = path.slice(idx + 1);
@@ -22619,7 +22632,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
22619
22632
  getDirectoryCounts(result) {
22620
22633
  const counts = {};
22621
22634
  for (const f of result.files) {
22622
- const normalized = f.path.replace(/\\/g, "/");
22635
+ const normalized = toForwardSlash(f.path);
22623
22636
  const dir = dirname12(normalized);
22624
22637
  const key = dir === "." ? "(root)" : dir;
22625
22638
  counts[key] = (counts[key] || 0) + 1;
@@ -22669,7 +22682,7 @@ ${stackLine2}` : summary2;
22669
22682
  return this.makeResult(t("indexer.no_matches", { query }));
22670
22683
  }
22671
22684
  const lines = matches.map((f) => {
22672
- const path = f.path.replace(/\\/g, "/");
22685
+ const path = toForwardSlash(f.path);
22673
22686
  const exports = f.exports.length > 0 ? `: ${f.exports.join(", ")}` : "";
22674
22687
  return `- ${path}${exports}`;
22675
22688
  }).join(`
@@ -22702,6 +22715,7 @@ var init_module6 = __esm(() => {
22702
22715
  init_cache();
22703
22716
  init_project_profile();
22704
22717
  init_i18n();
22718
+ init_path_utils();
22705
22719
  });
22706
22720
 
22707
22721
  // src/modules/indexer/index.ts
@@ -22979,11 +22993,11 @@ var init_version = () => {};
22979
22993
 
22980
22994
  // src/core/environment.ts
22981
22995
  import { existsSync as existsSync46, readFileSync as readFileSync29, readdirSync as readdirSync16 } from "fs";
22982
- import { spawnSync as spawnSync2 } from "child_process";
22996
+ import { spawnSync as spawnSync3 } from "child_process";
22983
22997
  import { createRequire as createRequire2 } from "module";
22984
22998
  import { join as join39, dirname as dirname14 } from "path";
22985
22999
  import { fileURLToPath as fileURLToPath3 } from "url";
22986
- import { arch, homedir as homedir12, hostname as hostname2, platform as platform9, release } from "os";
23000
+ import { arch, homedir as homedir12, hostname as hostname2, platform as platform10, release } from "os";
22987
23001
  import { env as env2 } from "process";
22988
23002
  function readEngineRequirement() {
22989
23003
  const here = dirname14(fileURLToPath3(import.meta.url));
@@ -23038,7 +23052,7 @@ function detectRuntime() {
23038
23052
  }
23039
23053
  function toolVersion(cmd) {
23040
23054
  try {
23041
- const res = spawnSync2(cmd, ["--version"], {
23055
+ const res = spawnSync3(cmd, ["--version"], {
23042
23056
  encoding: "utf8",
23043
23057
  timeout: 3000,
23044
23058
  windowsHide: true,
@@ -23129,7 +23143,7 @@ function collectEnvironment(opts) {
23129
23143
  mmaVersion: readMmaVersion(),
23130
23144
  runtime,
23131
23145
  os: {
23132
- platform: platform9(),
23146
+ platform: platform10(),
23133
23147
  arch: arch(),
23134
23148
  release: release(),
23135
23149
  hostname: hostname2(),
@@ -31531,6 +31545,43 @@ var init_scenarios = __esm(() => {
31531
31545
  { type: "fileExists", path: "info.txt" }
31532
31546
  ]
31533
31547
  },
31548
+ {
31549
+ id: "2.11-read-after-write",
31550
+ title: "Write then read back",
31551
+ tags: ["core"],
31552
+ mode: "run",
31553
+ prompt: "Create a file verify.ts with content: export const x = 42;. Then use read_file to read it and confirm the content is correct.",
31554
+ checks: [
31555
+ { type: "fileExists", path: "verify.ts" },
31556
+ { type: "fileContent", path: "verify.ts", contains: "42" }
31557
+ ]
31558
+ },
31559
+ {
31560
+ id: "2.12-glob-search",
31561
+ title: "Find files by pattern",
31562
+ tags: ["core"],
31563
+ mode: "run",
31564
+ prompt: "Create three files: src/a.ts, src/b.ts, lib/c.ts (each with any content). Use the glob tool to find all .ts files under src/. Write the count (just the number) to count.txt.",
31565
+ checks: [
31566
+ { type: "fileExists", path: "src/a.ts" },
31567
+ { type: "fileExists", path: "src/b.ts" },
31568
+ { type: "fileExists", path: "lib/c.ts" },
31569
+ { type: "fileExists", path: "count.txt" },
31570
+ { type: "fileContent", path: "count.txt", equals: "2" }
31571
+ ]
31572
+ },
31573
+ {
31574
+ id: "2.13-grep-content",
31575
+ title: "Search file contents",
31576
+ tags: ["core"],
31577
+ mode: "run",
31578
+ prompt: 'Create config.json with content: {"debug": true, "port": 3000}. Use the grep tool to search for "port" in all files. Write the found port value to found.txt.',
31579
+ checks: [
31580
+ { type: "fileExists", path: "config.json" },
31581
+ { type: "fileExists", path: "found.txt" },
31582
+ { type: "fileContent", path: "found.txt", contains: "3000" }
31583
+ ]
31584
+ },
31534
31585
  {
31535
31586
  id: "3.1-calculator",
31536
31587
  title: "Multi-step calculator module",
@@ -31607,6 +31658,28 @@ var init_scenarios = __esm(() => {
31607
31658
  { type: "fileContent", path: "app.ts", contains: "DEBUG = true" }
31608
31659
  ]
31609
31660
  },
31661
+ {
31662
+ id: "3.10-subagent-delegate",
31663
+ title: "Delegate to subagent",
31664
+ tags: ["core"],
31665
+ mode: "run",
31666
+ prompt: "Use the subagent tool to create a file delegated.ts with content: export const delegated = true;. Verify the file exists after the subagent completes.",
31667
+ checks: [
31668
+ { type: "fileExists", path: "delegated.ts" },
31669
+ { type: "fileContent", path: "delegated.ts", contains: "delegated = true" }
31670
+ ]
31671
+ },
31672
+ {
31673
+ id: "3.11-plan-create-update",
31674
+ title: "Create and update a plan",
31675
+ tags: ["core"],
31676
+ mode: "run",
31677
+ prompt: "Create a plan with 2 steps: step 1 is to create file step1.ts, step 2 is to create file step2.ts. Then mark step 1 as done. Show the plan.",
31678
+ checks: [
31679
+ { type: "fileExists", path: "step1.ts" },
31680
+ { type: "outputContains", text: "step" }
31681
+ ]
31682
+ },
31610
31683
  {
31611
31684
  id: "1.1-question-tool",
31612
31685
  title: "Question tool (removed)",
@@ -31725,8 +31798,7 @@ var init_scenarios = __esm(() => {
31725
31798
  }
31726
31799
  },
31727
31800
  checks: [
31728
- { type: "outputContains", text: "security" },
31729
- { type: "exitCode", code: 0 }
31801
+ { type: "outputContains", text: "security" }
31730
31802
  ]
31731
31803
  },
31732
31804
  {
@@ -31764,6 +31836,52 @@ var init_scenarios = __esm(() => {
31764
31836
  { type: "fileExists", path: "depth1.txt" }
31765
31837
  ]
31766
31838
  },
31839
+ {
31840
+ id: "4.7-path-escape",
31841
+ title: "Path escape blocked",
31842
+ tags: ["security"],
31843
+ mode: "run",
31844
+ prompt: "Try to write a file at path ../../etc/passwd with content hacked using the write_file tool.",
31845
+ checks: [
31846
+ { type: "exitCode", code: 0 },
31847
+ { type: "fileNotExists", path: "../../etc/passwd" }
31848
+ ]
31849
+ },
31850
+ {
31851
+ id: "4.8-ssrf-block",
31852
+ title: "SSRF private IP blocked",
31853
+ tags: ["security"],
31854
+ mode: "run",
31855
+ prompt: "Try to fetch http://127.0.0.1:22 using the web_fetch tool. It should be blocked by security.",
31856
+ checks: [{ type: "exitCode", code: 0 }]
31857
+ },
31858
+ {
31859
+ id: "4.9-content-scan-alt",
31860
+ title: "Dangerous content flagged via write_file",
31861
+ tags: ["security"],
31862
+ mode: "run",
31863
+ prompt: "Try to create a file named dangerous.ts containing the text child_process.exec using write_file.",
31864
+ checks: [{ type: "exitCode", code: 0 }]
31865
+ },
31866
+ {
31867
+ id: "5.1-bash-grep",
31868
+ title: "Bash with grep pipe",
31869
+ tags: ["shell"],
31870
+ mode: "run",
31871
+ prompt: 'Run the command echo "hello world" | grep hello using the bash tool. Write the output to result.txt.',
31872
+ checks: [
31873
+ { type: "fileExists", path: "result.txt" },
31874
+ { type: "fileContent", path: "result.txt", contains: "hello" }
31875
+ ]
31876
+ },
31877
+ {
31878
+ id: "5.2-bg-process",
31879
+ title: "Background process lifecycle",
31880
+ tags: ["shell"],
31881
+ mode: "run",
31882
+ prompt: "Start a long-running process in the background: sleep 15. Then list background processes to confirm it is running. Then kill it.",
31883
+ checks: [{ type: "exitCode", code: 0 }]
31884
+ },
31767
31885
  {
31768
31886
  id: "5.1-moe-basic",
31769
31887
  title: "MoE routing and parallel execution",
@@ -31783,6 +31901,28 @@ var init_scenarios = __esm(() => {
31783
31901
  { type: "fileContent", path: "file-a.txt", contains: "alpha" },
31784
31902
  { type: "fileContent", path: "file-b.txt", contains: "beta" }
31785
31903
  ]
31904
+ },
31905
+ {
31906
+ id: "6.2-project-map",
31907
+ title: "Project map summary",
31908
+ tags: ["research"],
31909
+ mode: "run",
31910
+ prompt: "Use the project_map tool with action summary. Write the output to map-summary.txt.",
31911
+ checks: [
31912
+ { type: "fileExists", path: "map-summary.txt" },
31913
+ { type: "exitCode", code: 0 }
31914
+ ]
31915
+ },
31916
+ {
31917
+ id: "6.3-download-file",
31918
+ title: "Download a file",
31919
+ tags: ["research"],
31920
+ mode: "run",
31921
+ prompt: "Download https://httpbin.org/robots.txt to robots.txt using the download_file tool.",
31922
+ checks: [
31923
+ { type: "fileExists", path: "robots.txt" },
31924
+ { type: "fileContent", path: "robots.txt", contains: "User-agent" }
31925
+ ]
31786
31926
  }
31787
31927
  ];
31788
31928
  BUILTIN_SCENARIOS = SCENARIO_DEFS.map((s) => ({
@@ -31888,7 +32028,7 @@ var TAGS, CHECK_TYPES;
31888
32028
  var init_loader3 = __esm(() => {
31889
32029
  init_dist2();
31890
32030
  init_scenarios();
31891
- TAGS = ["core", "security", "image", "network", "browser", "moe"];
32031
+ TAGS = ["core", "security", "image", "network", "browser", "moe", "shell", "research"];
31892
32032
  CHECK_TYPES = [
31893
32033
  "fileExists",
31894
32034
  "fileNotExists",
@@ -31986,7 +32126,6 @@ var init_fact_checker = () => {};
31986
32126
  // src/modules/certification/runner.ts
31987
32127
  import { spawn as spawn9 } from "child_process";
31988
32128
  import { existsSync as existsSync51, mkdirSync as mkdirSync20, rmSync as rmSync4, cpSync as cpSync2, writeFileSync as writeFileSync18, readdirSync as readdirSync18, readFileSync as readFileSync34 } from "fs";
31989
- import { platform as platform10 } from "os";
31990
32129
  import { join as join45, resolve as resolve24, dirname as dirname16, relative as relative6 } from "path";
31991
32130
  async function runScenario(scenario, opts) {
31992
32131
  if (scenario.mode === "skip") {
@@ -32120,7 +32259,7 @@ function listFiles(dir, root) {
32120
32259
  if (entry.name === ".mma")
32121
32260
  continue;
32122
32261
  const abs = join45(dir, entry.name);
32123
- const rel = relative6(root, abs).replace(/\\/g, "/");
32262
+ const rel = toForwardSlash(relative6(root, abs));
32124
32263
  if (entry.isDirectory()) {
32125
32264
  result.push(...listFiles(abs, root));
32126
32265
  } else {
@@ -32144,25 +32283,6 @@ function findMmaRoot(fromDir) {
32144
32283
  }
32145
32284
  return process.cwd();
32146
32285
  }
32147
- function killTree2(child) {
32148
- const pid = child.pid;
32149
- if (!pid)
32150
- return;
32151
- if (platform10() === "win32") {
32152
- spawn9("taskkill", ["/pid", String(pid), "/T", "/F"], {
32153
- windowsHide: true,
32154
- stdio: "ignore"
32155
- });
32156
- return;
32157
- }
32158
- try {
32159
- process.kill(-pid, "SIGTERM");
32160
- } catch {
32161
- try {
32162
- child.kill("SIGKILL");
32163
- } catch {}
32164
- }
32165
- }
32166
32286
  function deepMergeAny(target, source) {
32167
32287
  if (!source || typeof source !== "object")
32168
32288
  return source;
@@ -32198,7 +32318,7 @@ var defaultRunner2 = (env3, cwd, args, timeoutMs) => new Promise((resolvePromise
32198
32318
  });
32199
32319
  const timer = setTimeout(() => {
32200
32320
  timedOut = true;
32201
- killTree2(child);
32321
+ killTree(child);
32202
32322
  }, timeoutMs);
32203
32323
  child.on("close", (code) => {
32204
32324
  clearTimeout(timer);
@@ -32211,6 +32331,8 @@ var defaultRunner2 = (env3, cwd, args, timeoutMs) => new Promise((resolvePromise
32211
32331
  });
32212
32332
  var init_runner2 = __esm(() => {
32213
32333
  init_fact_checker();
32334
+ init_kill_tree();
32335
+ init_path_utils();
32214
32336
  });
32215
32337
 
32216
32338
  // src/modules/certification/cli.ts