opencode-swarm 7.160.0 → 7.160.2

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 (97) hide show
  1. package/.opencode/skills/critic-gate/SKILL.md +8 -1
  2. package/.opencode/skills/execute/SKILL.md +4 -3
  3. package/.opencode/skills/phase-wrap/SKILL.md +2 -0
  4. package/.opencode/skills/running-tests/SKILL.md +6 -0
  5. package/.opencode/skills/swarm-implement/SKILL.md +2 -0
  6. package/.opencode/skills/swarm-pr-review/SKILL.md +29 -29
  7. package/.opencode/skills/swarm-pr-review/references/prompt-templates.md +21 -5
  8. package/dist/agents/architect.d.ts +1 -1
  9. package/dist/background/pending-delegations.d.ts +46 -1
  10. package/dist/background/pr-review-contract.d.ts +245 -2
  11. package/dist/build/command-resolution.d.ts +13 -0
  12. package/dist/build/discovery.d.ts +11 -4
  13. package/dist/cli/{coder-settlement-zn552sp9.js → coder-settlement-gzar5ypz.js} +9 -9
  14. package/dist/cli/{config-doctor-ddtdz2g0.js → config-doctor-ancn1sj7.js} +3 -3
  15. package/dist/cli/{core-embasn2j.js → core-bhmqtxev.js} +2 -2
  16. package/dist/cli/{curation-policy-agr6ga1s.js → curation-policy-47przjwg.js} +4 -4
  17. package/dist/cli/curator-llm-factory-6mw01jx1.js +67 -0
  18. package/dist/cli/{curator-dgp6dxxn.js → curator-sgmynbpm.js} +32 -32
  19. package/dist/cli/{dispatch-7r46tfr9.js → dispatch-q4v8x2pk.js} +1 -1
  20. package/dist/cli/{evidence-summary-service-sbnyann4.js → evidence-summary-service-1pcfsqhv.js} +13 -13
  21. package/dist/cli/{gate-evidence-5v67a1dz.js → gate-evidence-w0kjqmew.js} +5 -5
  22. package/dist/cli/guardrail-explain-k99eje1y.js +68 -0
  23. package/dist/cli/{guardrail-log-zbnbff1y.js → guardrail-log-md5gcpk7.js} +7 -7
  24. package/dist/cli/{guardrail-reset-3cnz54hx.js → guardrail-reset-3385eqmq.js} +32 -32
  25. package/dist/cli/{hive-promoter-7cr7t2kg.js → hive-promoter-r0ekyn5m.js} +32 -32
  26. package/dist/cli/{index-wzx6atbv.js → index-2123hwbj.js} +3 -3
  27. package/dist/cli/{index-nj6rmyeh.js → index-3146wmgv.js} +352 -149
  28. package/dist/cli/{index-5m7qjj29.js → index-3a35tt6a.js} +6 -6
  29. package/dist/cli/{index-q6gjwy7m.js → index-497a3hhj.js} +2 -2
  30. package/dist/cli/{index-7qv869f0.js → index-4d8cq6e1.js} +5 -5
  31. package/dist/cli/{index-w699ekk9.js → index-4dcz9fpn.js} +2 -2
  32. package/dist/cli/{index-zjvf7edj.js → index-5th50g17.js} +1 -1
  33. package/dist/cli/{index-va1edd2n.js → index-5xfx5sbw.js} +5 -5
  34. package/dist/cli/{index-1f4n43yz.js → index-6scakreq.js} +5 -4
  35. package/dist/cli/{index-962jgzdq.js → index-717pmdce.js} +1 -1
  36. package/dist/cli/{index-rq7k03rk.js → index-7ezv5j23.js} +1 -1
  37. package/dist/cli/{index-4mm22fzj.js → index-7h2armwf.js} +1 -1
  38. package/dist/cli/{index-gt8cxfbp.js → index-am5bz6mf.js} +2 -2
  39. package/dist/cli/{index-cn233hsy.js → index-awjx0wgk.js} +1 -1
  40. package/dist/cli/{index-h3re5c78.js → index-c9zp4xwc.js} +12 -1
  41. package/dist/cli/{index-p39xem8b.js → index-dh5q6z7y.js} +3 -3
  42. package/dist/cli/{index-xs15netk.js → index-j3ss86kf.js} +1 -1
  43. package/dist/cli/{index-d9s5hb0m.js → index-k0qy284k.js} +5 -5
  44. package/dist/cli/{index-sy5aeegg.js → index-k50kxd3w.js} +866 -37
  45. package/dist/cli/{index-fzkx24q5.js → index-kqzba6ex.js} +2 -2
  46. package/dist/cli/{index-e75bzfgd.js → index-mmr96pwr.js} +1 -1
  47. package/dist/cli/{index-85qjc7b2.js → index-nk498mx6.js} +1 -1
  48. package/dist/cli/{index-9fspg1xw.js → index-prv20xq6.js} +1 -1
  49. package/dist/cli/{index-ebz97mks.js → index-q8hm27yj.js} +8 -1
  50. package/dist/cli/{index-8bjv01t8.js → index-re338hf1.js} +4 -4
  51. package/dist/cli/{index-rnyt2z5r.js → index-s7w6ntw6.js} +321 -448
  52. package/dist/cli/{index-jmths6jj.js → index-vsy942dt.js} +34 -34
  53. package/dist/cli/{index-rhc8jve7.js → index-vv760pbg.js} +2 -2
  54. package/dist/cli/{index-3yh737hc.js → index-war2dt6a.js} +6 -6
  55. package/dist/cli/{index-yrar1ask.js → index-xkmzsfg5.js} +3 -3
  56. package/dist/cli/{index-3055dgzp.js → index-xsd7y4hp.js} +4 -4
  57. package/dist/cli/{index-py6bqwnb.js → index-xtwny1ae.js} +16 -2
  58. package/dist/cli/{index-9q6w7kke.js → index-yd6y4qr7.js} +1 -1
  59. package/dist/cli/{index-kkfgygvn.js → index-yp81ebrx.js} +4 -4
  60. package/dist/cli/{index-9k3zc2t8.js → index-zbnf26br.js} +6 -6
  61. package/dist/cli/{index-s7w428r3.js → index-znf683sm.js} +1 -1
  62. package/dist/cli/index.js +32 -32
  63. package/dist/cli/{knowledge-escalator-zksm9833.js → knowledge-escalator-saekqp8t.js} +12 -12
  64. package/dist/cli/{knowledge-events-ayta750w.js → knowledge-events-ej8yz3yq.js} +10 -10
  65. package/dist/cli/{knowledge-link-7c7fjnzc.js → knowledge-link-xezm8hr3.js} +3 -3
  66. package/dist/cli/{knowledge-store-q5axge8b.js → knowledge-store-3jamj5n4.js} +4 -4
  67. package/dist/cli/{knowledge-validator-3rrbva2p.js → knowledge-validator-26w2mvqv.js} +6 -6
  68. package/dist/cli/{model-preflight-x9szw1v4.js → model-preflight-yqqchzjn.js} +1 -1
  69. package/dist/cli/{pending-delegations-kc7tzxg9.js → pending-delegations-7xak7g59.js} +5 -3
  70. package/dist/cli/{pr-review-reentry-authorization-vag5gh50.js → pr-review-reentry-authorization-v97q63q4.js} +34 -33
  71. package/dist/cli/{pr-subscriptions-wbdw9a82.js → pr-subscriptions-asjevc5p.js} +3 -3
  72. package/dist/cli/{runner-p9wg6z34.js → runner-wsdcy2d6.js} +4 -4
  73. package/dist/cli/{scan-cursor-4fjwtt1k.js → scan-cursor-1agr50f8.js} +5 -5
  74. package/dist/cli/{schema-d0nbzj5k.js → schema-z0ygrqgy.js} +4 -2
  75. package/dist/cli/{scope-persistence-bckcbc8h.js → scope-persistence-tncg38by.js} +8 -8
  76. package/dist/cli/{skill-generator-kebhevet.js → skill-generator-jq20a09m.js} +14 -14
  77. package/dist/cli/{worktree-collision-ownership-h8qswnrp.js → worktree-collision-ownership-b9cp9zvw.js} +4 -4
  78. package/dist/cli/{worktree-isolation-q0kbmadz.js → worktree-isolation-dzyxf8hn.js} +32 -32
  79. package/dist/config/constants.d.ts +8 -0
  80. package/dist/config/evidence-schema.d.ts +21 -0
  81. package/dist/config/schema.d.ts +8 -0
  82. package/dist/hooks/pr-workflow-gate.d.ts +25 -1
  83. package/dist/index.js +333 -319
  84. package/dist/lang/default-backend.d.ts +1 -13
  85. package/dist/tools/build-check.d.ts +4 -0
  86. package/dist/tools/dispatch-lanes.d.ts +27 -3
  87. package/dist/tools/index.d.ts +1 -0
  88. package/dist/tools/manifest.d.ts +1 -0
  89. package/dist/tools/sast-baseline.d.ts +2 -0
  90. package/dist/tools/sast-scan.d.ts +2 -2
  91. package/dist/tools/submit-pr-review-result.d.ts +5 -0
  92. package/dist/tools/test-runner.d.ts +2 -0
  93. package/dist/tools/tool-metadata.d.ts +8 -0
  94. package/opencode-swarm.schema.json +4 -0
  95. package/package.json +1 -1
  96. package/dist/cli/curator-llm-factory-7cwvmc46.js +0 -67
  97. package/dist/cli/guardrail-explain-2gwarnca.js +0 -68
@@ -95,13 +95,13 @@ LANGUAGE_REGISTRY.register({
95
95
  },
96
96
  {
97
97
  name: "tsc",
98
- cmd: "npx tsc --noEmit",
98
+ cmd: "tsc --noEmit",
99
99
  detectFile: "tsconfig.json",
100
100
  priority: 9
101
101
  },
102
102
  {
103
103
  name: "vite build",
104
- cmd: "npx vite build",
104
+ cmd: "vite build",
105
105
  detectFile: "vite.config.ts",
106
106
  priority: 8
107
107
  }
@@ -122,7 +122,7 @@ LANGUAGE_REGISTRY.register({
122
122
  cmd: "bun test",
123
123
  priority: 10
124
124
  },
125
- { name: "jest", detect: "jest.config.js", cmd: "npx jest", priority: 9 },
125
+ { name: "jest", detect: "jest.config.js", cmd: "jest", priority: 9 },
126
126
  {
127
127
  name: "bun:test",
128
128
  detect: "bun.lock",
@@ -132,7 +132,7 @@ LANGUAGE_REGISTRY.register({
132
132
  {
133
133
  name: "mocha",
134
134
  detect: ".mocharc.json",
135
- cmd: "npx mocha",
135
+ cmd: "mocha",
136
136
  priority: 7
137
137
  }
138
138
  ]
@@ -154,7 +154,7 @@ LANGUAGE_REGISTRY.register({
154
154
  {
155
155
  name: "eslint",
156
156
  detect: ".eslintrc.js",
157
- cmd: "npx eslint --fix .",
157
+ cmd: "eslint --fix .",
158
158
  priority: 9
159
159
  }
160
160
  ]
@@ -203,13 +203,13 @@ LANGUAGE_REGISTRY.register({
203
203
  },
204
204
  {
205
205
  name: "tsc",
206
- cmd: "npx tsc --noEmit",
206
+ cmd: "tsc --noEmit",
207
207
  detectFile: "tsconfig.json",
208
208
  priority: 9
209
209
  },
210
210
  {
211
211
  name: "vite build",
212
- cmd: "npx vite build",
212
+ cmd: "vite build",
213
213
  detectFile: "vite.config.ts",
214
214
  priority: 8
215
215
  }
@@ -230,7 +230,7 @@ LANGUAGE_REGISTRY.register({
230
230
  cmd: "bun test",
231
231
  priority: 10
232
232
  },
233
- { name: "jest", detect: "jest.config.js", cmd: "npx jest", priority: 9 },
233
+ { name: "jest", detect: "jest.config.js", cmd: "jest", priority: 9 },
234
234
  {
235
235
  name: "bun:test",
236
236
  detect: "bun.lock",
@@ -240,7 +240,7 @@ LANGUAGE_REGISTRY.register({
240
240
  {
241
241
  name: "mocha",
242
242
  detect: ".mocharc.json",
243
- cmd: "npx mocha",
243
+ cmd: "mocha",
244
244
  priority: 7
245
245
  }
246
246
  ]
@@ -262,7 +262,7 @@ LANGUAGE_REGISTRY.register({
262
262
  {
263
263
  name: "eslint",
264
264
  detect: ".eslintrc.js",
265
- cmd: "npx eslint --fix .",
265
+ cmd: "eslint --fix .",
266
266
  priority: 9
267
267
  }
268
268
  ]
@@ -1231,12 +1231,138 @@ async function detectProjectLanguages(projectDir) {
1231
1231
  }
1232
1232
 
1233
1233
  // src/lang/default-backend.ts
1234
- import * as fs2 from "fs";
1235
- import * as path2 from "path";
1234
+ import * as fs3 from "fs";
1235
+ import * as path3 from "path";
1236
1236
 
1237
- // src/build/discovery.ts
1237
+ // src/build/command-resolution.ts
1238
1238
  import * as fs from "fs";
1239
1239
  import * as path from "path";
1240
+ var WINDOWS_LOCAL_SHIM_CANDIDATES = [
1241
+ { suffix: ".cmd", requiresNode: true },
1242
+ { suffix: ".exe", requiresNode: false },
1243
+ { suffix: ".bat", requiresNode: true },
1244
+ { suffix: ".ps1", requiresNode: true },
1245
+ { suffix: "", requiresNode: true }
1246
+ ];
1247
+ function tokenizeCommand(command) {
1248
+ const out = [];
1249
+ let buf = "";
1250
+ let quote = null;
1251
+ for (const ch of command.trim()) {
1252
+ if (quote) {
1253
+ if (ch === quote) {
1254
+ quote = null;
1255
+ } else {
1256
+ buf += ch;
1257
+ }
1258
+ continue;
1259
+ }
1260
+ if (ch === '"' || ch === "'") {
1261
+ quote = ch;
1262
+ continue;
1263
+ }
1264
+ if (ch === " " || ch === "\t") {
1265
+ if (buf.length > 0) {
1266
+ out.push(buf);
1267
+ buf = "";
1268
+ }
1269
+ continue;
1270
+ }
1271
+ buf += ch;
1272
+ }
1273
+ if (buf.length > 0)
1274
+ out.push(buf);
1275
+ return out;
1276
+ }
1277
+ function findCommandSuffixStart(command) {
1278
+ let quote = null;
1279
+ let sawTokenChar = false;
1280
+ for (let i = 0;i < command.length; i++) {
1281
+ const ch = command[i];
1282
+ if (quote) {
1283
+ if (ch === quote) {
1284
+ quote = null;
1285
+ } else {
1286
+ sawTokenChar = true;
1287
+ }
1288
+ continue;
1289
+ }
1290
+ if (ch === '"' || ch === "'") {
1291
+ quote = ch;
1292
+ sawTokenChar = true;
1293
+ continue;
1294
+ }
1295
+ if ((ch === " " || ch === "\t") && sawTokenChar) {
1296
+ return i;
1297
+ }
1298
+ if (ch !== " " && ch !== "\t") {
1299
+ sawTokenChar = true;
1300
+ }
1301
+ }
1302
+ return command.length;
1303
+ }
1304
+ function resolveLocalCandidate(binary, workingDir, platform = process.platform, isAvailable) {
1305
+ const candidates = platform === "win32" ? WINDOWS_LOCAL_SHIM_CANDIDATES : [{ suffix: "", requiresNode: true }];
1306
+ for (const candidate of candidates) {
1307
+ const executable = `${binary}${candidate.suffix}`;
1308
+ const absolute = path.join(workingDir, "node_modules", ".bin", executable);
1309
+ if (!fs.existsSync(absolute))
1310
+ continue;
1311
+ if (candidate.requiresNode && isAvailable && !isAvailable("node"))
1312
+ continue;
1313
+ const relative = platform === "win32" ? path.win32.join("node_modules", ".bin", executable) : path.posix.join("node_modules", ".bin", executable);
1314
+ return {
1315
+ absolute,
1316
+ relative,
1317
+ requiresNode: candidate.requiresNode
1318
+ };
1319
+ }
1320
+ return null;
1321
+ }
1322
+ function hasAnyLocalCandidate(binary, workingDir, platform = process.platform) {
1323
+ const candidates = platform === "win32" ? WINDOWS_LOCAL_SHIM_CANDIDATES : [{ suffix: "", requiresNode: true }];
1324
+ for (const candidate of candidates) {
1325
+ const executable = `${binary}${candidate.suffix}`;
1326
+ if (fs.existsSync(path.join(workingDir, "node_modules", ".bin", executable))) {
1327
+ return true;
1328
+ }
1329
+ }
1330
+ return false;
1331
+ }
1332
+ function resolveLocalCommand(command, workingDir, isAvailable, platform = process.platform) {
1333
+ const tokens = tokenizeCommand(command);
1334
+ if (tokens.length === 0)
1335
+ return null;
1336
+ const [binary, ...args] = tokens;
1337
+ if (["npx", "bunx", "pnpx"].includes(binary))
1338
+ return null;
1339
+ if (binary.includes("/") || binary.includes("\\"))
1340
+ return null;
1341
+ const trimmed = command.trim();
1342
+ const local = resolveLocalCandidate(binary, workingDir, platform, isAvailable);
1343
+ if (local) {
1344
+ const shellPath = platform === "win32" ? local.relative : `./${local.relative}`;
1345
+ return {
1346
+ argv: [local.absolute, ...args],
1347
+ shellCommand: `${shellPath}${trimmed.slice(findCommandSuffixStart(trimmed))}`
1348
+ };
1349
+ }
1350
+ if (hasAnyLocalCandidate(binary, workingDir, platform))
1351
+ return null;
1352
+ return isAvailable(binary) ? { argv: tokens, shellCommand: command } : null;
1353
+ }
1354
+ function resolveLocalNodeTool(tool, args, workingDir, platform = process.platform, isAvailable) {
1355
+ const local = resolveLocalCandidate(tool, workingDir, platform, platform === "win32" ? isAvailable : undefined);
1356
+ if (local)
1357
+ return [local.absolute, ...args];
1358
+ if (hasAnyLocalCandidate(tool, workingDir, platform))
1359
+ return null;
1360
+ return isAvailable?.(tool) ? [tool, ...args] : null;
1361
+ }
1362
+
1363
+ // src/build/discovery.ts
1364
+ import * as fs2 from "fs";
1365
+ import * as path2 from "path";
1240
1366
 
1241
1367
  // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
1242
1368
  var exports_external = {};
@@ -1967,10 +2093,10 @@ function mergeDefs(...defs) {
1967
2093
  function cloneDef(schema) {
1968
2094
  return mergeDefs(schema._zod.def);
1969
2095
  }
1970
- function getElementAtPath(obj, path) {
1971
- if (!path)
2096
+ function getElementAtPath(obj, path2) {
2097
+ if (!path2)
1972
2098
  return obj;
1973
- return path.reduce((acc, key) => acc?.[key], obj);
2099
+ return path2.reduce((acc, key) => acc?.[key], obj);
1974
2100
  }
1975
2101
  function promiseAllObject(promisesObj) {
1976
2102
  const keys = Object.keys(promisesObj);
@@ -2329,11 +2455,11 @@ function aborted(x, startIndex = 0) {
2329
2455
  }
2330
2456
  return false;
2331
2457
  }
2332
- function prefixIssues(path, issues) {
2458
+ function prefixIssues(path2, issues) {
2333
2459
  return issues.map((iss) => {
2334
2460
  var _a;
2335
2461
  (_a = iss).path ?? (_a.path = []);
2336
- iss.path.unshift(path);
2462
+ iss.path.unshift(path2);
2337
2463
  return iss;
2338
2464
  });
2339
2465
  }
@@ -2501,7 +2627,7 @@ function treeifyError(error, _mapper) {
2501
2627
  return issue2.message;
2502
2628
  };
2503
2629
  const result = { errors: [] };
2504
- const processError = (error2, path = []) => {
2630
+ const processError = (error2, path2 = []) => {
2505
2631
  var _a, _b;
2506
2632
  for (const issue2 of error2.issues) {
2507
2633
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -2511,7 +2637,7 @@ function treeifyError(error, _mapper) {
2511
2637
  } else if (issue2.code === "invalid_element") {
2512
2638
  processError({ issues: issue2.issues }, issue2.path);
2513
2639
  } else {
2514
- const fullpath = [...path, ...issue2.path];
2640
+ const fullpath = [...path2, ...issue2.path];
2515
2641
  if (fullpath.length === 0) {
2516
2642
  result.errors.push(mapper(issue2));
2517
2643
  continue;
@@ -2543,8 +2669,8 @@ function treeifyError(error, _mapper) {
2543
2669
  }
2544
2670
  function toDotPath(_path) {
2545
2671
  const segs = [];
2546
- const path = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2547
- for (const seg of path) {
2672
+ const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2673
+ for (const seg of path2) {
2548
2674
  if (typeof seg === "number")
2549
2675
  segs.push(`[${seg}]`);
2550
2676
  else if (typeof seg === "symbol")
@@ -13559,11 +13685,13 @@ function tool(input) {
13559
13685
  }
13560
13686
  tool.schema = exports_external;
13561
13687
  // src/build/discovery.ts
13688
+ var SUPPORTED_NODE_PACKAGE_MANAGERS = ["bun", "npm", "pnpm", "yarn"];
13689
+ var MAX_PACKAGE_MANAGER_EVIDENCE_CHARS = 120;
13562
13690
  var ECOSYSTEMS = [
13563
13691
  {
13564
13692
  ecosystem: "node",
13565
13693
  buildFiles: ["package.json"],
13566
- toolchainCommands: ["npm", "yarn", "pnpm"],
13694
+ toolchainCommands: [...SUPPORTED_NODE_PACKAGE_MANAGERS],
13567
13695
  commands: [
13568
13696
  { command: "npm run build", priority: 30 },
13569
13697
  { command: "npm run typecheck", priority: 20 },
@@ -13657,6 +13785,7 @@ var ECOSYSTEMS = [
13657
13785
  ];
13658
13786
  var PROFILE_TO_ECOSYSTEM_NAMES = {
13659
13787
  typescript: ["node"],
13788
+ javascript: ["node"],
13660
13789
  python: ["python"],
13661
13790
  rust: ["rust"],
13662
13791
  go: ["go"],
@@ -13694,52 +13823,120 @@ function isCommandAvailable(command) {
13694
13823
  }
13695
13824
  }
13696
13825
  function checkToolchain(commands) {
13697
- return commands.some((cmd) => isCommandAvailable(cmd));
13826
+ return commands.some((cmd) => _internals.isCommandAvailable(cmd));
13698
13827
  }
13699
13828
  function findBuildFiles(workingDir, patterns) {
13700
13829
  for (const pattern of patterns) {
13701
13830
  if (pattern.includes("*")) {
13702
13831
  const dir = workingDir;
13703
13832
  try {
13704
- const files = fs.readdirSync(dir);
13833
+ const files = fs2.readdirSync(dir);
13705
13834
  const regex = simpleGlobToRegex(pattern);
13706
13835
  const matches = files.filter((f) => regex.test(f));
13707
13836
  if (matches.length > 0) {
13708
- return path.join(dir, matches[0]);
13837
+ return path2.join(dir, matches[0]);
13709
13838
  }
13710
13839
  } catch {}
13711
13840
  } else {
13712
- const filePath = path.join(workingDir, pattern);
13713
- if (fs.existsSync(filePath)) {
13841
+ const filePath = path2.join(workingDir, pattern);
13842
+ if (fs2.existsSync(filePath)) {
13714
13843
  return filePath;
13715
13844
  }
13716
13845
  }
13717
13846
  }
13718
13847
  return null;
13719
13848
  }
13849
+ function sanitizeEvidenceText(raw, maxChars) {
13850
+ let withoutControls = "";
13851
+ for (const char of raw) {
13852
+ const code = char.charCodeAt(0);
13853
+ withoutControls += code < 32 || code === 127 ? " " : char;
13854
+ }
13855
+ const normalized = withoutControls.replace(/\s+/g, " ").trim();
13856
+ if (!normalized)
13857
+ return "(empty)";
13858
+ if (normalized.length <= maxChars)
13859
+ return normalized;
13860
+ if (maxChars <= 3)
13861
+ return normalized.slice(0, maxChars);
13862
+ return `${normalized.slice(0, maxChars - 3)}...`;
13863
+ }
13864
+ function sanitizeRequiredCommand(command) {
13865
+ const sanitized = sanitizeEvidenceText(command, 40);
13866
+ return sanitized === "(empty)" ? null : sanitized;
13867
+ }
13868
+ function getBinaryFromCommand(command) {
13869
+ return command.trim().split(/\s+/)[0] ?? "";
13870
+ }
13871
+ function getProfileRequiredCommands(commands) {
13872
+ const uniqueCommands = new Set;
13873
+ for (const command of commands) {
13874
+ const binary = sanitizeRequiredCommand(getBinaryFromCommand(command.cmd));
13875
+ if (binary)
13876
+ uniqueCommands.add(binary);
13877
+ }
13878
+ return Array.from(uniqueCommands);
13879
+ }
13880
+ function getNoMatchingBuildFilesReason(profileId, commands) {
13881
+ const detectFiles = Array.from(new Set(commands.map((command) => command.detectFile?.trim()).filter((detectFile) => Boolean(detectFile))));
13882
+ if (detectFiles.length === 0) {
13883
+ return `No matching build files for profile ${profileId}`;
13884
+ }
13885
+ return `No matching build files for profile ${profileId}: expected ${detectFiles.join(" or ")}`;
13886
+ }
13720
13887
  function getRepoDefinedScripts(workingDir, scripts) {
13721
- const packageJsonPath = path.join(workingDir, "package.json");
13722
- if (!fs.existsSync(packageJsonPath)) {
13723
- return [];
13888
+ const packageJsonPath = path2.join(workingDir, "package.json");
13889
+ if (!fs2.existsSync(packageJsonPath)) {
13890
+ return { commands: [], hasScripts: false };
13724
13891
  }
13725
13892
  try {
13726
- const content = fs.readFileSync(packageJsonPath, "utf-8");
13893
+ const content = fs2.readFileSync(packageJsonPath, "utf-8");
13727
13894
  const pkg = JSON.parse(content);
13728
13895
  if (!pkg.scripts || typeof pkg.scripts !== "object") {
13729
- return [];
13730
- }
13731
- const found = [];
13732
- for (const scriptName of scripts) {
13733
- if (pkg.scripts[scriptName]) {
13734
- found.push({
13735
- script: `npm run ${scriptName}`,
13736
- priority: 100
13737
- });
13738
- }
13896
+ return { commands: [], hasScripts: false };
13897
+ }
13898
+ const scriptNames = scripts.filter((name) => typeof pkg.scripts[name] === "string" && pkg.scripts[name].trim());
13899
+ if (scriptNames.length === 0)
13900
+ return { commands: [], hasScripts: false };
13901
+ const rawPackageManager = typeof pkg.packageManager === "string" ? pkg.packageManager.trim() : undefined;
13902
+ const declared = rawPackageManager?.split("@")[0]?.trim();
13903
+ const supported = [...SUPPORTED_NODE_PACKAGE_MANAGERS];
13904
+ const sanitizedDeclared = declared ? sanitizeRequiredCommand(declared) : null;
13905
+ const candidates = declared ? [declared] : supported;
13906
+ if (rawPackageManager !== undefined && (!declared || !supported.includes(declared))) {
13907
+ return {
13908
+ commands: [],
13909
+ hasScripts: true,
13910
+ skip: {
13911
+ ecosystem: "node",
13912
+ code: "environment_unavailable",
13913
+ required_commands: sanitizedDeclared ? [sanitizedDeclared] : [],
13914
+ reason: `Unsupported packageManager: ${sanitizeEvidenceText(rawPackageManager, MAX_PACKAGE_MANAGER_EVIDENCE_CHARS)}`
13915
+ }
13916
+ };
13917
+ }
13918
+ const manager = candidates.find((candidate) => _internals.isCommandAvailable(candidate));
13919
+ if (!manager) {
13920
+ return {
13921
+ commands: [],
13922
+ hasScripts: true,
13923
+ skip: {
13924
+ ecosystem: "node",
13925
+ code: "environment_unavailable",
13926
+ required_commands: candidates,
13927
+ reason: `Package manager not available: ${candidates.join(" or ")}`
13928
+ }
13929
+ };
13739
13930
  }
13740
- return found;
13931
+ return {
13932
+ hasScripts: true,
13933
+ commands: scriptNames.map((scriptName) => ({
13934
+ command: `${manager} run ${scriptName}`,
13935
+ priority: 100
13936
+ }))
13937
+ };
13741
13938
  } catch {
13742
- return [];
13939
+ return { commands: [], hasScripts: false };
13743
13940
  }
13744
13941
  }
13745
13942
  function filterByScope(workingDir, scope, changedFiles) {
@@ -13759,8 +13956,8 @@ function findAllBuildFiles(workingDir) {
13759
13956
  const regex = simpleGlobToRegex(pattern);
13760
13957
  findFilesRecursive(workingDir, regex, allBuildFiles);
13761
13958
  } else {
13762
- const filePath = path.join(workingDir, pattern);
13763
- if (fs.existsSync(filePath)) {
13959
+ const filePath = path2.join(workingDir, pattern);
13960
+ if (fs2.existsSync(filePath)) {
13764
13961
  allBuildFiles.add(filePath);
13765
13962
  }
13766
13963
  }
@@ -13770,9 +13967,9 @@ function findAllBuildFiles(workingDir) {
13770
13967
  }
13771
13968
  function findFilesRecursive(dir, regex, results) {
13772
13969
  try {
13773
- const entries = fs.readdirSync(dir, { withFileTypes: true });
13970
+ const entries = fs2.readdirSync(dir, { withFileTypes: true });
13774
13971
  for (const entry of entries) {
13775
- const fullPath = path.join(dir, entry.name);
13972
+ const fullPath = path2.join(dir, entry.name);
13776
13973
  if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
13777
13974
  findFilesRecursive(fullPath, regex, results);
13778
13975
  } else if (entry.isFile() && regex.test(entry.name)) {
@@ -13787,32 +13984,41 @@ var _internals = {
13787
13984
  discoverBuildCommands,
13788
13985
  clearToolchainCache,
13789
13986
  getEcosystems,
13987
+ detectProjectLanguagesImpl: detectProjectLanguages,
13988
+ getLanguageProfileImpl: LANGUAGE_REGISTRY.get.bind(LANGUAGE_REGISTRY),
13790
13989
  spawnSyncImpl: bunSpawnSync
13791
13990
  };
13792
13991
  async function discoverBuildCommandsFromProfiles(workingDir) {
13793
13992
  const commands = [];
13794
13993
  const skipped = [];
13795
- const detectedProfiles = await detectProjectLanguages(workingDir);
13994
+ const detectedProfiles = await _internals.detectProjectLanguagesImpl(workingDir);
13796
13995
  for (const profile of detectedProfiles) {
13797
- const fullProfile = LANGUAGE_REGISTRY.get(profile.id);
13996
+ const fullProfile = _internals.getLanguageProfileImpl(profile.id);
13798
13997
  if (!fullProfile) {
13799
13998
  warn(`[build-discovery] profile ${profile.id} not found in registry, skipping`);
13800
13999
  continue;
13801
14000
  }
13802
14001
  const sortedCommands = [...fullProfile.build.commands].sort((a, b) => b.priority - a.priority);
14002
+ const applicableCommands = sortedCommands.filter((cmd) => {
14003
+ if (!cmd.detectFile)
14004
+ return true;
14005
+ const detectFilePath = path2.join(workingDir, cmd.detectFile);
14006
+ return fs2.existsSync(detectFilePath);
14007
+ });
14008
+ if (applicableCommands.length === 0) {
14009
+ skipped.push({
14010
+ ecosystem: fullProfile.id,
14011
+ reason: getNoMatchingBuildFilesReason(fullProfile.id, sortedCommands)
14012
+ });
14013
+ continue;
14014
+ }
13803
14015
  let foundCommand = false;
13804
- for (const cmd of sortedCommands) {
13805
- if (cmd.detectFile) {
13806
- const detectFilePath = path.join(workingDir, cmd.detectFile);
13807
- if (!fs.existsSync(detectFilePath)) {
13808
- continue;
13809
- }
13810
- }
13811
- const binaryName = cmd.cmd.split(" ")[0];
13812
- if (isCommandAvailable(binaryName)) {
14016
+ for (const cmd of applicableCommands) {
14017
+ const resolved = resolveLocalCommand(cmd.cmd, workingDir, _internals.isCommandAvailable);
14018
+ if (resolved) {
13813
14019
  commands.push({
13814
14020
  ecosystem: fullProfile.id,
13815
- command: cmd.cmd,
14021
+ command: resolved.shellCommand,
13816
14022
  cwd: workingDir,
13817
14023
  priority: cmd.priority
13818
14024
  });
@@ -13821,10 +14027,13 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
13821
14027
  }
13822
14028
  }
13823
14029
  if (!foundCommand) {
13824
- const triedBinaries = sortedCommands.map((c) => c.name || c.cmd.split(" ")[0]).join(", ");
14030
+ const requiredCommands = getProfileRequiredCommands(applicableCommands);
14031
+ const triedBinaries = requiredCommands.join(", ");
13825
14032
  const reason = `No binary available for profile ${fullProfile.id}: tried ${triedBinaries}`;
13826
14033
  skipped.push({
13827
14034
  ecosystem: fullProfile.id,
14035
+ code: "environment_unavailable",
14036
+ required_commands: requiredCommands,
13828
14037
  reason
13829
14038
  });
13830
14039
  warn(`[build-discovery] profile ${fullProfile.id}: no binary available, skipping`);
@@ -13839,16 +14048,53 @@ async function discoverBuildCommands(workingDir, options) {
13839
14048
  const profileResult = await _internals.discoverBuildCommandsFromProfiles(workingDir);
13840
14049
  const profileCommands = profileResult.commands;
13841
14050
  const profileSkipped = profileResult.skipped;
14051
+ const repoDefinedScriptsByEcosystem = new Map;
14052
+ const repoScriptSkips = [];
14053
+ const repoDeclaredEcosystems = new Set;
14054
+ for (const ecosystem of ECOSYSTEMS) {
14055
+ if (!ecosystem.repoDefinedScripts)
14056
+ continue;
14057
+ const repoResult = getRepoDefinedScripts(workingDir, ecosystem.repoDefinedScripts);
14058
+ if (repoResult.commands.length > 0) {
14059
+ repoDefinedScriptsByEcosystem.set(ecosystem.ecosystem, repoResult.commands);
14060
+ }
14061
+ if (repoResult.hasScripts)
14062
+ repoDeclaredEcosystems.add(ecosystem.ecosystem);
14063
+ if (repoResult.skip)
14064
+ repoScriptSkips.push(repoResult.skip);
14065
+ }
14066
+ const filteredProfileCommands = profileCommands.filter((cmd) => {
14067
+ const ecosystemNames = PROFILE_TO_ECOSYSTEM_NAMES[cmd.ecosystem] ?? [];
14068
+ return ecosystemNames.every((name) => !repoDeclaredEcosystems.has(name));
14069
+ });
13842
14070
  const coveredEcosystems = new Set;
13843
- for (const cmd of profileCommands) {
14071
+ for (const cmd of filteredProfileCommands) {
13844
14072
  const ecosystemNames = PROFILE_TO_ECOSYSTEM_NAMES[cmd.ecosystem] ?? [];
13845
14073
  for (const name of ecosystemNames) {
13846
14074
  coveredEcosystems.add(name);
13847
14075
  }
13848
14076
  }
13849
- const commands = [...profileCommands];
13850
- const skipped = [...profileSkipped];
14077
+ const commands = [...filteredProfileCommands];
14078
+ const skipped = [...profileSkipped, ...repoScriptSkips];
13851
14079
  for (const ecosystem of ECOSYSTEMS) {
14080
+ const buildFile = findBuildFiles(workingDir, ecosystem.buildFiles);
14081
+ if (!buildFile)
14082
+ continue;
14083
+ const repoScripts = repoDefinedScriptsByEcosystem.get(ecosystem.ecosystem);
14084
+ if (repoScripts && repoScripts.length > 0) {
14085
+ for (const script of repoScripts) {
14086
+ commands.push({
14087
+ ecosystem: ecosystem.ecosystem,
14088
+ command: script.command,
14089
+ cwd: workingDir,
14090
+ priority: script.priority
14091
+ });
14092
+ }
14093
+ continue;
14094
+ }
14095
+ if (repoDeclaredEcosystems.has(ecosystem.ecosystem)) {
14096
+ continue;
14097
+ }
13852
14098
  if (coveredEcosystems.has(ecosystem.ecosystem)) {
13853
14099
  skipped.push({
13854
14100
  ecosystem: ecosystem.ecosystem,
@@ -13859,28 +14105,13 @@ async function discoverBuildCommands(workingDir, options) {
13859
14105
  if (!checkToolchain(ecosystem.toolchainCommands)) {
13860
14106
  skipped.push({
13861
14107
  ecosystem: ecosystem.ecosystem,
14108
+ code: "environment_unavailable",
14109
+ required_commands: ecosystem.toolchainCommands,
13862
14110
  reason: `Toolchain not found: ${ecosystem.toolchainCommands.join(" or ")} not on PATH`
13863
14111
  });
13864
14112
  continue;
13865
14113
  }
13866
- const buildFile = findBuildFiles(workingDir, ecosystem.buildFiles);
13867
- if (!buildFile) {
13868
- skipped.push({
13869
- ecosystem: ecosystem.ecosystem,
13870
- reason: `No build file found: ${ecosystem.buildFiles.join(", ")}`
13871
- });
13872
- continue;
13873
- }
13874
- let availableCommands = ecosystem.commands;
13875
- if (ecosystem.repoDefinedScripts) {
13876
- const repoScripts = getRepoDefinedScripts(workingDir, ecosystem.repoDefinedScripts);
13877
- if (repoScripts.length > 0) {
13878
- availableCommands = repoScripts.map((s) => ({
13879
- command: s.script,
13880
- priority: s.priority
13881
- }));
13882
- }
13883
- }
14114
+ const availableCommands = ecosystem.commands;
13884
14115
  for (const cmd of availableCommands) {
13885
14116
  commands.push({
13886
14117
  ecosystem: ecosystem.ecosystem,
@@ -13919,7 +14150,7 @@ var build_discovery = tool({
13919
14150
  function detectFileExists(dir, pattern) {
13920
14151
  if (pattern.includes("*") || pattern.includes("?")) {
13921
14152
  try {
13922
- const files = fs2.readdirSync(dir);
14153
+ const files = fs3.readdirSync(dir);
13923
14154
  const regex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
13924
14155
  return files.some((f) => regex.test(f));
13925
14156
  } catch {
@@ -13927,42 +14158,12 @@ function detectFileExists(dir, pattern) {
13927
14158
  }
13928
14159
  }
13929
14160
  try {
13930
- fs2.accessSync(path2.join(dir, pattern));
14161
+ fs3.accessSync(path3.join(dir, pattern));
13931
14162
  return true;
13932
14163
  } catch {
13933
14164
  return false;
13934
14165
  }
13935
14166
  }
13936
- function tokenizeCommand(cmd) {
13937
- const out = [];
13938
- let buf = "";
13939
- let quote = null;
13940
- for (const ch of cmd) {
13941
- if (quote) {
13942
- if (ch === quote) {
13943
- quote = null;
13944
- } else {
13945
- buf += ch;
13946
- }
13947
- continue;
13948
- }
13949
- if (ch === '"' || ch === "'") {
13950
- quote = ch;
13951
- continue;
13952
- }
13953
- if (ch === " " || ch === "\t") {
13954
- if (buf.length > 0) {
13955
- out.push(buf);
13956
- buf = "";
13957
- }
13958
- continue;
13959
- }
13960
- buf += ch;
13961
- }
13962
- if (buf.length > 0)
13963
- out.push(buf);
13964
- return out;
13965
- }
13966
14167
  async function defaultSelectTestFramework(profile, dir) {
13967
14168
  const sorted = [...profile.test.frameworks].sort((a, b) => b.priority - a.priority);
13968
14169
  for (const fw of sorted) {
@@ -14006,14 +14207,14 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
14006
14207
  return args;
14007
14208
  }
14008
14209
  case "vitest": {
14009
- const args = [
14010
- "npx",
14011
- "vitest",
14210
+ const args = resolveLocalNodeTool("vitest", [
14012
14211
  "run",
14013
14212
  "--reporter=json",
14014
14213
  "--outputFile",
14015
14214
  ".swarm/cache/test-runner-vitest.json"
14016
- ];
14215
+ ], dir, process.platform, isCommandAvailable);
14216
+ if (!args)
14217
+ return null;
14017
14218
  if (coverage)
14018
14219
  args.push("--coverage");
14019
14220
  if (bail)
@@ -14023,7 +14224,9 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
14023
14224
  return args;
14024
14225
  }
14025
14226
  case "jest": {
14026
- const args = ["npx", "jest", "--json"];
14227
+ const args = resolveLocalNodeTool("jest", ["--json"], dir, process.platform, isCommandAvailable);
14228
+ if (!args)
14229
+ return null;
14027
14230
  if (coverage)
14028
14231
  args.push("--coverage");
14029
14232
  if (bail)
@@ -14033,7 +14236,9 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
14033
14236
  return args;
14034
14237
  }
14035
14238
  case "mocha": {
14036
- const args = ["npx", "mocha"];
14239
+ const args = resolveLocalNodeTool("mocha", [], dir, process.platform, isCommandAvailable);
14240
+ if (!args)
14241
+ return null;
14037
14242
  if (bail)
14038
14243
  args.push("--bail");
14039
14244
  if (scope !== "all" && files.length > 0)
@@ -14087,8 +14292,8 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
14087
14292
  }
14088
14293
  case "gradle": {
14089
14294
  const isWindows = process.platform === "win32";
14090
- const hasGradlewBat = fs2.existsSync(path2.join(dir, "gradlew.bat"));
14091
- const hasGradlew = fs2.existsSync(path2.join(dir, "gradlew"));
14295
+ const hasGradlewBat = fs3.existsSync(path3.join(dir, "gradlew.bat"));
14296
+ const hasGradlew = fs3.existsSync(path3.join(dir, "gradlew"));
14092
14297
  const args = [];
14093
14298
  if (hasGradlewBat && isWindows)
14094
14299
  args.push("gradlew.bat");
@@ -14119,7 +14324,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
14119
14324
  "cmake-build-release",
14120
14325
  "out"
14121
14326
  ];
14122
- const actualBuildDir = buildDirCandidates.find((d) => fs2.existsSync(path2.join(dir, d, "CMakeCache.txt"))) ?? "build";
14327
+ const actualBuildDir = buildDirCandidates.find((d) => fs3.existsSync(path3.join(dir, d, "CMakeCache.txt"))) ?? "build";
14123
14328
  const args = ["ctest", "--test-dir", actualBuildDir];
14124
14329
  if (targets && targets.length > 0) {
14125
14330
  args.push("-R", targets.join("|"));
@@ -14205,7 +14410,7 @@ function buildNativeTargetCommand(target) {
14205
14410
  return ["go", "test", "-v", "-run", selector, packagePath];
14206
14411
  }
14207
14412
  function phpVendorBin(name) {
14208
- return path2.join("vendor", "bin", process.platform === "win32" ? `${name}.bat` : name);
14413
+ return path3.join("vendor", "bin", process.platform === "win32" ? `${name}.bat` : name);
14209
14414
  }
14210
14415
  function defaultParseTestOutput(framework, stdout, stderr, exitCode) {
14211
14416
  const output = stdout && stderr ? `${stdout}
@@ -14468,14 +14673,12 @@ async function defaultSelectBuildCommand(profile, dir) {
14468
14673
  for (const cmd of sorted) {
14469
14674
  if (cmd.detectFile && !detectFileExists(dir, cmd.detectFile))
14470
14675
  continue;
14471
- const argv = tokenizeCommand(cmd.cmd);
14472
- if (argv.length === 0)
14473
- continue;
14474
- if (!isCommandAvailable(argv[0]))
14676
+ const resolved = resolveLocalCommand(cmd.cmd, dir, isCommandAvailable);
14677
+ if (!resolved)
14475
14678
  continue;
14476
14679
  return {
14477
14680
  name: cmd.name,
14478
- cmd: argv,
14681
+ cmd: resolved.argv,
14479
14682
  cwd: dir,
14480
14683
  detectedVia: cmd.detectFile ?? `${profile.id} default`
14481
14684
  };
@@ -14483,23 +14686,23 @@ async function defaultSelectBuildCommand(profile, dir) {
14483
14686
  return null;
14484
14687
  }
14485
14688
  async function defaultTestFilesFor(profile, sourceFile, dir) {
14486
- const ext = path2.extname(sourceFile);
14689
+ const ext = path3.extname(sourceFile);
14487
14690
  if (!profile.extensions.includes(ext))
14488
14691
  return [];
14489
- const base = path2.basename(sourceFile, ext);
14490
- const rel = path2.relative(dir, sourceFile);
14491
- const relDir = path2.dirname(rel);
14692
+ const base = path3.basename(sourceFile, ext);
14693
+ const rel = path3.relative(dir, sourceFile);
14694
+ const relDir = path3.dirname(rel);
14492
14695
  const stripSrc = relDir.replace(/^src(\/|\\)/, "");
14493
14696
  const candidates = new Set;
14494
14697
  for (const tDir of ["tests", "test", "__tests__", "spec"]) {
14495
14698
  for (const suffix of ["", "_test", ".test", "_spec", ".spec"]) {
14496
- candidates.add(path2.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
14699
+ candidates.add(path3.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
14497
14700
  }
14498
14701
  }
14499
14702
  const existing = [];
14500
14703
  for (const c of candidates) {
14501
14704
  try {
14502
- fs2.accessSync(c);
14705
+ fs3.accessSync(c);
14503
14706
  existing.push(c);
14504
14707
  } catch {}
14505
14708
  }
@@ -14530,8 +14733,8 @@ function defaultBackendFor(profile) {
14530
14733
  }
14531
14734
 
14532
14735
  // src/lang/backends/go.ts
14533
- import * as fs3 from "fs";
14534
- import * as path3 from "path";
14736
+ import * as fs4 from "fs";
14737
+ import * as path4 from "path";
14535
14738
  var PROFILE_ID = "go";
14536
14739
  var IMPORT_REGEX_SINGLE = /^\s*import\s+(?:[a-zA-Z_.][a-zA-Z0-9_]*\s+)?"([^"]+)"/gm;
14537
14740
  var IMPORT_REGEX_GROUP = /^\s*import\s*\(([\s\S]*?)\)/gm;
@@ -14561,7 +14764,7 @@ function extractImports(_sourceFile, source) {
14561
14764
  async function selectFramework(dir) {
14562
14765
  let content;
14563
14766
  try {
14564
- content = fs3.readFileSync(path3.join(dir, "go.mod"), "utf-8");
14767
+ content = fs4.readFileSync(path4.join(dir, "go.mod"), "utf-8");
14565
14768
  } catch {
14566
14769
  return null;
14567
14770
  }
@@ -14582,16 +14785,16 @@ async function selectFramework(dir) {
14582
14785
  async function selectEntryPoints(dir) {
14583
14786
  const points = [];
14584
14787
  try {
14585
- fs3.accessSync(path3.join(dir, "main.go"));
14788
+ fs4.accessSync(path4.join(dir, "main.go"));
14586
14789
  points.push("main.go");
14587
14790
  } catch {}
14588
14791
  try {
14589
- const cmdDir = path3.join(dir, "cmd");
14590
- const subdirs = fs3.readdirSync(cmdDir, { withFileTypes: true }).filter((d) => d.isDirectory());
14792
+ const cmdDir = path4.join(dir, "cmd");
14793
+ const subdirs = fs4.readdirSync(cmdDir, { withFileTypes: true }).filter((d) => d.isDirectory());
14591
14794
  for (const sub of subdirs) {
14592
- const main = path3.join("cmd", sub.name, "main.go");
14795
+ const main = path4.join("cmd", sub.name, "main.go");
14593
14796
  try {
14594
- fs3.accessSync(path3.join(dir, main));
14797
+ fs4.accessSync(path4.join(dir, main));
14595
14798
  points.push(main);
14596
14799
  } catch {}
14597
14800
  }
@@ -14613,8 +14816,8 @@ function buildGoBackend() {
14613
14816
  var _internals2 = { extractImports };
14614
14817
 
14615
14818
  // src/lang/backends/python.ts
14616
- import * as fs4 from "fs";
14617
- import * as path4 from "path";
14819
+ import * as fs5 from "fs";
14820
+ import * as path5 from "path";
14618
14821
  var PROFILE_ID2 = "python";
14619
14822
  var IMPORT_REGEX_FROM_WITH_TARGETS = /^\s*from\s+(\.*[\w.]*)\s+import\s+(\([^)]*\)|[^\n#]+)/gm;
14620
14823
  var IMPORT_REGEX_IMPORT = /^\s*import\s+([^\n#]+)/gm;
@@ -14677,7 +14880,7 @@ async function selectFramework2(dir) {
14677
14880
  ];
14678
14881
  for (const candidate of ["pyproject.toml", "requirements.txt", "setup.py"]) {
14679
14882
  try {
14680
- const content = fs4.readFileSync(path4.join(dir, candidate), "utf-8");
14883
+ const content = fs5.readFileSync(path5.join(dir, candidate), "utf-8");
14681
14884
  const lower = content.toLowerCase();
14682
14885
  for (const [pkg, name] of candidates) {
14683
14886
  if (lower.includes(pkg)) {
@@ -14691,7 +14894,7 @@ async function selectFramework2(dir) {
14691
14894
  async function selectEntryPoints2(dir) {
14692
14895
  const points = new Set;
14693
14896
  try {
14694
- const content = fs4.readFileSync(path4.join(dir, "pyproject.toml"), "utf-8");
14897
+ const content = fs5.readFileSync(path5.join(dir, "pyproject.toml"), "utf-8");
14695
14898
  const scriptsBlock = content.match(/\[project\.scripts\][\s\S]*?(?=\n\[|$)/);
14696
14899
  if (scriptsBlock) {
14697
14900
  for (const line of scriptsBlock[0].split(`
@@ -14706,7 +14909,7 @@ async function selectEntryPoints2(dir) {
14706
14909
  } catch {}
14707
14910
  for (const name of ["manage.py", "main.py", "app.py", "__main__.py"]) {
14708
14911
  try {
14709
- fs4.accessSync(path4.join(dir, name));
14912
+ fs5.accessSync(path5.join(dir, name));
14710
14913
  points.add(name);
14711
14914
  } catch {}
14712
14915
  }
@@ -14726,4 +14929,4 @@ function buildPythonBackend() {
14726
14929
  }
14727
14930
  var _internals3 = { extractImports: extractImports2 };
14728
14931
 
14729
- export { tool, LANGUAGE_REGISTRY, getProfileForFile, detectProjectLanguages, isCommandAvailable, tokenizeCommand, defaultSelectTestFramework, defaultBuildTestCommand, buildNativeTargetCommand, defaultParseTestOutput, defaultSelectBuildCommand, defaultTestFilesFor, defaultBackendFor, buildGoBackend, _internals2 as _internals, buildPythonBackend, _internals3 as _internals1 };
14932
+ export { tool, LANGUAGE_REGISTRY, getProfileForFile, detectProjectLanguages, tokenizeCommand, resolveLocalNodeTool, isCommandAvailable, defaultSelectTestFramework, defaultBuildTestCommand, buildNativeTargetCommand, defaultParseTestOutput, defaultSelectBuildCommand, defaultTestFilesFor, defaultBackendFor, buildGoBackend, _internals2 as _internals, buildPythonBackend, _internals3 as _internals1 };