turbollm 1.13.6 → 1.13.7

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 (117) hide show
  1. package/dist/cli.js +229 -122
  2. package/dist/webdist/assets/{AgentEditPage-BzG20IJo.js → AgentEditPage-E7HtOsup.js} +1 -1
  3. package/dist/webdist/assets/{ChatScreen-CGTfgk6t.js → ChatScreen-dEouSpAv.js} +1 -1
  4. package/dist/webdist/assets/{CodeComposer-DkaX0aou.js → CodeComposer-CkqctDdp.js} +1 -1
  5. package/dist/webdist/assets/{CodeHomeScreen-C6Mx3KKG.js → CodeHomeScreen-W_lZHAT2.js} +1 -1
  6. package/dist/webdist/assets/{CodeSessionScreen-BF_ck2zI.js → CodeSessionScreen-BX1Eaqga.js} +1 -1
  7. package/dist/webdist/assets/{CustomizeScreen-BB4hjJHh.js → CustomizeScreen-BszOveS0.js} +1 -1
  8. package/dist/webdist/assets/EnginesScreen-C3Tr39oE.js +10 -0
  9. package/dist/webdist/assets/{HardwareSection-CHCi45EV.js → HardwareSection-Cvzgs-RM.js} +1 -1
  10. package/dist/webdist/assets/{ModelDetailDialog-C3tk_RxR.js → ModelDetailDialog-CQ_x0n0p.js} +1 -1
  11. package/dist/webdist/assets/{ModelLoadMenu-FcRnPBLY.js → ModelLoadMenu-Lir_ZeaD.js} +1 -1
  12. package/dist/webdist/assets/{ModelsScreen-C4X4NjE2.js → ModelsScreen-BwzqukhW.js} +1 -1
  13. package/dist/webdist/assets/{OnboardingScreen-CaM7ExyF.js → OnboardingScreen-Df_1EYOW.js} +1 -1
  14. package/dist/webdist/assets/{RoutineEditPage-BAfZYpYu.js → RoutineEditPage-CdZnyBEw.js} +1 -1
  15. package/dist/webdist/assets/{RoutinesPanel-B3iJfoD3.js → RoutinesPanel-CBOpHq9E.js} +1 -1
  16. package/dist/webdist/assets/{SettingsScreen-DBwDO8TR.js → SettingsScreen-Bhih9go0.js} +1 -1
  17. package/dist/webdist/assets/{SidebarResizeHandle-CJUpye8c.js → SidebarResizeHandle-CNnIPZEp.js} +1 -1
  18. package/dist/webdist/assets/{SkillEditPage-CHhkakhI.js → SkillEditPage-CCtOQTmq.js} +1 -1
  19. package/dist/webdist/assets/{ToolApprovalBar-C6_ZJDzC.js → ToolApprovalBar-PlYgG25-.js} +3 -3
  20. package/dist/webdist/assets/WorkspaceScreen-CqmBBbxz.js +1 -0
  21. package/dist/webdist/assets/{abnfDiagram-N423BO3Z-CjZCDJJe.js → abnfDiagram-N423BO3Z-DsZ93mAM.js} +1 -1
  22. package/dist/webdist/assets/{agent-api-Q07TJf7T.js → agent-api-BQn5nZNX.js} +1 -1
  23. package/dist/webdist/assets/{alert-dialog-fWVjIQYe.js → alert-dialog-D9Z7ppH_.js} +1 -1
  24. package/dist/webdist/assets/{arc-DEmyGdWp.js → arc-BGrHHnrw.js} +1 -1
  25. package/dist/webdist/assets/{architectureDiagram-T3A2C74G-BuR_LXcC.js → architectureDiagram-T3A2C74G-Ey1UrzU-.js} +1 -1
  26. package/dist/webdist/assets/{blockDiagram-VBNYF7ZC-uBPjcCWa.js → blockDiagram-VBNYF7ZC-D78LM23z.js} +1 -1
  27. package/dist/webdist/assets/{c4Diagram-5PPSVZJV-B2N1IXTa.js → c4Diagram-5PPSVZJV-CvPfXzDr.js} +1 -1
  28. package/dist/webdist/assets/channel-DCuz_wdC.js +1 -0
  29. package/dist/webdist/assets/{chat-api-CP-1zHWH.js → chat-api-BKO4BTWe.js} +1 -1
  30. package/dist/webdist/assets/{chat-queries-C19981zO.js → chat-queries-CqiPDqGV.js} +1 -1
  31. package/dist/webdist/assets/{chevron-down-Be9un6T0.js → chevron-down-SLGilXKT.js} +1 -1
  32. package/dist/webdist/assets/{chevron-left-8-aTOHPO.js → chevron-left-CU5U4gIb.js} +1 -1
  33. package/dist/webdist/assets/{chevron-right-DQlioXo8.js → chevron-right-BY4anLEq.js} +1 -1
  34. package/dist/webdist/assets/{chunk-2GRJ4B5K-TlR5T4Vi.js → chunk-2GRJ4B5K-P3cu6Bc0.js} +1 -1
  35. package/dist/webdist/assets/{chunk-2Q5K7J3B-5kezfKDh.js → chunk-2Q5K7J3B-BgP7AimG.js} +1 -1
  36. package/dist/webdist/assets/{chunk-5RXB4S5H-C8ItBvcB.js → chunk-5RXB4S5H-B-FXWALA.js} +1 -1
  37. package/dist/webdist/assets/{chunk-5VM5RSS4-BXvuKQZV.js → chunk-5VM5RSS4-C-lQ75_C.js} +1 -1
  38. package/dist/webdist/assets/{chunk-6Q2QTUOP-Cbta8vGG.js → chunk-6Q2QTUOP-Cv-tXjKv.js} +1 -1
  39. package/dist/webdist/assets/{chunk-GF5L2VYU-CIuHLncz.js → chunk-GF5L2VYU-C3sxcn3E.js} +1 -1
  40. package/dist/webdist/assets/{chunk-JWPE2WC7-8rGGjIyo.js → chunk-JWPE2WC7-C-AvRcoC.js} +1 -1
  41. package/dist/webdist/assets/{chunk-KBJHAD2P-DFvvwuKz.js → chunk-KBJHAD2P-DMDEB7Sy.js} +1 -1
  42. package/dist/webdist/assets/{chunk-RYQCIY6F-B3c_vHIM.js → chunk-RYQCIY6F-DX_4YbYG.js} +1 -1
  43. package/dist/webdist/assets/{chunk-XXDRQBXY-DFBG-ven.js → chunk-XXDRQBXY-C-C12qlP.js} +1 -1
  44. package/dist/webdist/assets/{circle-check-DWL-BNw2.js → circle-check-D0IMfrYq.js} +1 -1
  45. package/dist/webdist/assets/{circle-x-CCKv4SGG.js → circle-x-pqL2JhJm.js} +1 -1
  46. package/dist/webdist/assets/classDiagram-JCYQIIEL-DFsr_nh-.js +1 -0
  47. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-DFsr_nh-.js +1 -0
  48. package/dist/webdist/assets/{collapsible-B09fxy0d.js → collapsible-Bwm3DfUf.js} +1 -1
  49. package/dist/webdist/assets/{cose-bilkent-JH36ORCC-xnHX_e1i.js → cose-bilkent-JH36ORCC-0_jV9L5K.js} +1 -1
  50. package/dist/webdist/assets/{cynefin-VYW2F7L2-DqLKYsq-.js → cynefin-VYW2F7L2-D-cQNJqC.js} +1 -1
  51. package/dist/webdist/assets/{cynefinDiagram-MW4NZA55-B_QMRv50.js → cynefinDiagram-MW4NZA55-QRp_3yKa.js} +1 -1
  52. package/dist/webdist/assets/{dagre-VZM6K2ZE-DCFGMRws.js → dagre-VZM6K2ZE-DYHS_FuW.js} +1 -1
  53. package/dist/webdist/assets/{diagram-7IWD3JNH-1ct9pPXF.js → diagram-7IWD3JNH-js1EUUk6.js} +1 -1
  54. package/dist/webdist/assets/{diagram-B4RE2ZJO-DqYEblJb.js → diagram-B4RE2ZJO-BHVEhFez.js} +1 -1
  55. package/dist/webdist/assets/{diagram-LBJQPF4R-CT-3lsOW.js → diagram-LBJQPF4R-Cc-5wAwq.js} +1 -1
  56. package/dist/webdist/assets/{diagram-Q27KOJAE-Bspp2eCN.js → diagram-Q27KOJAE-jTxFyyeN.js} +1 -1
  57. package/dist/webdist/assets/{diagram-UB23O5K3-DB_Hg65f.js → diagram-UB23O5K3-LP8zrNnQ.js} +1 -1
  58. package/dist/webdist/assets/{dropdown-menu-dzMJR6N9.js → dropdown-menu-IOTY3_-B.js} +1 -1
  59. package/dist/webdist/assets/{ebnfDiagram-BXEA7PRR-kk9-pxcN.js → ebnfDiagram-BXEA7PRR-qDNqlger.js} +1 -1
  60. package/dist/webdist/assets/{erDiagram-JOGREHBK-BCI0nybn.js → erDiagram-JOGREHBK-owRtaAi_.js} +1 -1
  61. package/dist/webdist/assets/{file-text-B94KmADS.js → file-text-BotUNsIW.js} +1 -1
  62. package/dist/webdist/assets/{flowDiagram-UKHOOZJN-CPzxY-LP.js → flowDiagram-UKHOOZJN-D26LSAka.js} +1 -1
  63. package/dist/webdist/assets/{folder-input-DL3mQB2F.js → folder-input-D3qEcRaK.js} +1 -1
  64. package/dist/webdist/assets/{folder-plus-Wpcb9ENt.js → folder-plus-4hzyN--0.js} +1 -1
  65. package/dist/webdist/assets/{ganttDiagram-PKOTCBZU-DozbuEKD.js → ganttDiagram-PKOTCBZU-FOBYQpFD.js} +1 -1
  66. package/dist/webdist/assets/{git-branch-yfPP244o.js → git-branch-CSkwfOC2.js} +1 -1
  67. package/dist/webdist/assets/{gitGraphDiagram-DS77QQ5N-CA_nEHp7.js → gitGraphDiagram-DS77QQ5N-D1pwlyQx.js} +1 -1
  68. package/dist/webdist/assets/{globe-DnAghWjQ.js → globe-BvQjzBKb.js} +1 -1
  69. package/dist/webdist/assets/{index-C14bv39c.js → index-CXLOA4-7.js} +2 -2
  70. package/dist/webdist/assets/{infoDiagram-6WML65LV-EBvusVlh.js → infoDiagram-6WML65LV-DAxebGLC.js} +1 -1
  71. package/dist/webdist/assets/{ishikawaDiagram-WSZJBQD7-VEUjJ6iO.js → ishikawaDiagram-WSZJBQD7-DIdOYDDr.js} +1 -1
  72. package/dist/webdist/assets/{journeyDiagram-NVQOT4AX-DNV1VMnS.js → journeyDiagram-NVQOT4AX-BLvkNn5k.js} +1 -1
  73. package/dist/webdist/assets/{kanban-definition-27J2QSJJ-B7bGb4hd.js → kanban-definition-27J2QSJJ-DKyJQb6a.js} +1 -1
  74. package/dist/webdist/assets/{linear-C5BAUlj1.js → linear-sR1aOS-1.js} +1 -1
  75. package/dist/webdist/assets/{lock-B4ECw-T0.js → lock-K-a91AFa.js} +1 -1
  76. package/dist/webdist/assets/{mermaid.core-BGxUfnBa.js → mermaid.core-sVxlfu4j.js} +4 -4
  77. package/dist/webdist/assets/{mindmap-definition-FAOFIHXS-BcuS9e3b.js → mindmap-definition-FAOFIHXS-Yo_cYEEu.js} +1 -1
  78. package/dist/webdist/assets/{monitor-o9jnBqQh.js → monitor-_13VL1du.js} +1 -1
  79. package/dist/webdist/assets/{pegDiagram-VL7TDLO6-B8r_GRtJ.js → pegDiagram-VL7TDLO6-BSAx7r44.js} +1 -1
  80. package/dist/webdist/assets/{pencil-MwR3RvUZ.js → pencil-CshqlsN6.js} +1 -1
  81. package/dist/webdist/assets/{pieDiagram-7S7Q4E2Y-VlB8e0KH.js → pieDiagram-7S7Q4E2Y-DJDpIi_G.js} +1 -1
  82. package/dist/webdist/assets/{quadrantDiagram-CIZ2JOQS-BMvoitnW.js → quadrantDiagram-CIZ2JOQS-BYUOd1Ld.js} +1 -1
  83. package/dist/webdist/assets/{railroadDiagram-AXF67PYL-CnDluqgH.js → railroadDiagram-AXF67PYL-Cp7ActLQ.js} +1 -1
  84. package/dist/webdist/assets/{refresh-cw-BzGTCNVs.js → refresh-cw-BgvgHNs_.js} +1 -1
  85. package/dist/webdist/assets/{remote-failure-Bc9jLh0G.js → remote-failure-CU6FQAv2.js} +1 -1
  86. package/dist/webdist/assets/{requirementDiagram-LRYGKXZP-Cf_bcWKz.js → requirementDiagram-LRYGKXZP-BRIn9Bao.js} +1 -1
  87. package/dist/webdist/assets/{rocket-3zkwetoN.js → rocket-Bdyspsau.js} +1 -1
  88. package/dist/webdist/assets/{rotate-ccw-fyN6mgMa.js → rotate-ccw-CXchjxoU.js} +1 -1
  89. package/dist/webdist/assets/{sankeyDiagram-W5VNT64P-abjcXFrR.js → sankeyDiagram-W5VNT64P-DrfFnEda.js} +1 -1
  90. package/dist/webdist/assets/{sequenceDiagram-SI44F4Z6-BAzSl86z.js → sequenceDiagram-SI44F4Z6-BRvCwGTa.js} +1 -1
  91. package/dist/webdist/assets/{sheet-E29qj5H3.js → sheet-BEHvWodM.js} +1 -1
  92. package/dist/webdist/assets/{sizeCapture-X5ZJPWSS-X6FTXo_P.js → sizeCapture-X5ZJPWSS-BLSbFiEe.js} +1 -1
  93. package/dist/webdist/assets/{skeleton-BOHWHwm6.js → skeleton-_WE_l7Ss.js} +1 -1
  94. package/dist/webdist/assets/{sliders-horizontal-CUBfMzM4.js → sliders-horizontal-X0H751ey.js} +1 -1
  95. package/dist/webdist/assets/{sparkles-B_nFb4N9.js → sparkles-B57ip_p2.js} +1 -1
  96. package/dist/webdist/assets/{star-DQIcK5P8.js → star-DFChWJ1H.js} +1 -1
  97. package/dist/webdist/assets/{stateDiagram-OKZ733FA-BhH_WS-y.js → stateDiagram-OKZ733FA-dWf7zqCN.js} +1 -1
  98. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-CQPsdlPu.js +1 -0
  99. package/dist/webdist/assets/{swimlanes-SLNWSIFB-BvuBhRif.js → swimlanes-SLNWSIFB-lCDiXKRw.js} +2 -2
  100. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-CzicNSYv.js +8 -0
  101. package/dist/webdist/assets/{switch-D-bpf0ou.js → switch-1qn4bGLW.js} +1 -1
  102. package/dist/webdist/assets/{terminal-Bi_kg8jX.js → terminal-BiLS4W9p.js} +1 -1
  103. package/dist/webdist/assets/{timeline-definition-Z64GVDOM-CT4o3tCm.js → timeline-definition-Z64GVDOM-DSxynxhf.js} +1 -1
  104. package/dist/webdist/assets/{trash-2-BXeiMvg8.js → trash-2-JXgZx0Gm.js} +1 -1
  105. package/dist/webdist/assets/{vennDiagram-T6HMQDX7-D7hteJww.js → vennDiagram-T6HMQDX7-AFtVyBx_.js} +1 -1
  106. package/dist/webdist/assets/{wardleyDiagram-T6FBY63Y-C6kQIV_N.js → wardleyDiagram-T6FBY63Y-Bi_TjYlH.js} +1 -1
  107. package/dist/webdist/assets/{wrench-CcGmlTUS.js → wrench-C6y9CDpZ.js} +1 -1
  108. package/dist/webdist/assets/{xychartDiagram-ELKLHX3M-DPy3Pkbw.js → xychartDiagram-ELKLHX3M-BaREW8xI.js} +1 -1
  109. package/dist/webdist/index.html +1 -1
  110. package/package.json +1 -1
  111. package/dist/webdist/assets/EnginesScreen-DlfORHsE.js +0 -10
  112. package/dist/webdist/assets/WorkspaceScreen-B6mjHG3v.js +0 -1
  113. package/dist/webdist/assets/channel-CzDLlXHw.js +0 -1
  114. package/dist/webdist/assets/classDiagram-JCYQIIEL-xDdy69O-.js +0 -1
  115. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-xDdy69O-.js +0 -1
  116. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-BXZstPHr.js +0 -1
  117. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-B75QTfBv.js +0 -8
package/dist/cli.js CHANGED
@@ -788,7 +788,7 @@ function clampMaxTokens(requested, limit) {
788
788
  }
789
789
 
790
790
  // src/engines/manager.ts
791
- import { execFile as execFile6, spawn, spawnSync } from "child_process";
791
+ import { execFile as execFile7, spawn, spawnSync } from "child_process";
792
792
  import { createWriteStream, existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync2, rmSync as rmSync5, writeFileSync as writeFileSync2 } from "fs";
793
793
  import { createConnection, createServer } from "net";
794
794
  import { dirname as dirname2, join as join10 } from "path";
@@ -1213,10 +1213,99 @@ async function restoreSlot(p) {
1213
1213
 
1214
1214
  // src/engines/vllm.ts
1215
1215
  import { existsSync as existsSync8 } from "fs";
1216
- import { execFile as execFile4 } from "child_process";
1216
+ import { execFile as execFile5 } from "child_process";
1217
1217
  import { join as join8 } from "path";
1218
+ import { promisify as promisify5 } from "util";
1219
+
1220
+ // src/engines/py-engine-blocker.ts
1221
+ import { execFile as execFile4 } from "child_process";
1222
+ import { homedir as homedir2 } from "os";
1218
1223
  import { promisify as promisify4 } from "util";
1219
1224
  var execFileP4 = promisify4(execFile4);
1225
+ var DETAIL_LIMIT = 200;
1226
+ var UvloopPreflight = class {
1227
+ constructor(engine, homeDirectory = homedir2) {
1228
+ this.engine = engine;
1229
+ this.homeDirectory = homeDirectory;
1230
+ }
1231
+ engine;
1232
+ homeDirectory;
1233
+ async blockerFor(python) {
1234
+ try {
1235
+ await execFileP4(python, ["-c", "import uvloop"], { timeout: 2e4 });
1236
+ return null;
1237
+ } catch (error) {
1238
+ return this.classify(process.platform, error);
1239
+ }
1240
+ }
1241
+ // uvloop publishes manylinux *and* macOS wheels, so only Windows is a real platform wall —
1242
+ // anywhere else a failed import is a broken local environment the user can reinstall.
1243
+ classify(platform, error) {
1244
+ if (platform === "win32") return this.unsupportedPlatform();
1245
+ const failure = error;
1246
+ if (failure?.code === "ENOENT") return this.missingInterpreter();
1247
+ return this.brokenEnvironment(platform, failure);
1248
+ }
1249
+ unsupportedPlatform() {
1250
+ return `${this.engine} cannot run on Windows: its server requires uvloop (and other Linux-only components such as NCCL/Triton), which have no Windows build. Use the llama.cpp / TurboQuant engine for GGUF models here, or run ${this.engine} under WSL2 / Linux.`;
1251
+ }
1252
+ missingInterpreter() {
1253
+ return `${this.engine}'s environment looks missing or broken (interpreter not found). Reinstall the ${this.engine} engine from the Engines page.`;
1254
+ }
1255
+ brokenEnvironment(platform, failure) {
1256
+ return `${this.engine}'s environment looks broken or incomplete (uvloop failed to import: ${failureDetail(failure, this.homeOrEmpty())}). ${this.platformStanding(platform)}`;
1257
+ }
1258
+ // homedir() throws (uv_os_homedir ENOENT) for a uid with no passwd entry and no HOME, e.g. a container.
1259
+ homeOrEmpty() {
1260
+ try {
1261
+ return this.homeDirectory();
1262
+ } catch {
1263
+ return "";
1264
+ }
1265
+ }
1266
+ // Only what is true is claimed: Linux is where these engines are officially supported, while on
1267
+ // macOS the catalog rates them experimental / unsupported upstream, so only uvloop's own support
1268
+ // may be asserted there.
1269
+ platformStanding(platform) {
1270
+ const plat = platformDisplay(platform);
1271
+ if (platform === "linux") {
1272
+ return `${plat} is a supported platform for ${this.engine} \u2014 reinstall the ${this.engine} engine from the Engines page rather than switching engines.`;
1273
+ }
1274
+ if (platform === "darwin") {
1275
+ return `uvloop itself supports ${plat}, so reinstall the ${this.engine} engine from the Engines page first \u2014 though ${plat} is not a first-class platform for ${this.engine} upstream.`;
1276
+ }
1277
+ return `${this.engine} support on ${plat} is unverified \u2014 reinstall the ${this.engine} engine from the Engines page; if the import keeps failing, ${this.engine} may have no working build here.`;
1278
+ }
1279
+ };
1280
+ function platformDisplay(platform) {
1281
+ if (platform === "win32") return "Windows";
1282
+ if (platform === "darwin") return "macOS";
1283
+ if (platform === "linux") return "Linux";
1284
+ return platform;
1285
+ }
1286
+ function failureDetail(failure, home) {
1287
+ const raw = failure?.stderr ? String(failure.stderr) : failure?.message ?? "";
1288
+ return capped(redactHome(lastMeaningfulLine(raw), home));
1289
+ }
1290
+ function lastMeaningfulLine(text) {
1291
+ const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
1292
+ return lines.at(-1) ?? "unknown error";
1293
+ }
1294
+ function redactHome(text, home) {
1295
+ if (home.length < 2) return text;
1296
+ const spellings = /* @__PURE__ */ new Set([home, home.split("\\").join("/"), home.split("/").join("\\")]);
1297
+ const anySpelling = new RegExp([...spellings].map(escapeRegExp).join("|"), "gi");
1298
+ return text.replace(anySpelling, "~");
1299
+ }
1300
+ function escapeRegExp(text) {
1301
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1302
+ }
1303
+ function capped(detail) {
1304
+ return detail.length <= DETAIL_LIMIT ? detail : `${detail.slice(0, DETAIL_LIMIT)}\u2026`;
1305
+ }
1306
+
1307
+ // src/engines/vllm.ts
1308
+ var execFileP5 = promisify5(execFile5);
1220
1309
  var VLLM_PYTHON = "3.12";
1221
1310
  function venvPython4(envDir) {
1222
1311
  return process.platform === "win32" ? join8(envDir, "Scripts", "python.exe") : join8(envDir, "bin", "python");
@@ -1227,43 +1316,23 @@ async function ensureVllmEnv(root, onProgress, upgrade = false) {
1227
1316
  const py = venvPython4(envDir);
1228
1317
  if (!existsSync8(py)) {
1229
1318
  onProgress?.({ phase: "extracting", pct: -1 });
1230
- await execFileP4(uv, ["venv", "--python", VLLM_PYTHON, envDir], { cwd: root });
1319
+ await execFileP5(uv, ["venv", "--python", VLLM_PYTHON, envDir], { cwd: root });
1231
1320
  }
1232
1321
  onProgress?.({ phase: "extracting", pct: -1 });
1233
1322
  const installArgs = ["pip", "install", "--python", py, ...upgrade ? ["-U"] : [], "vllm"];
1234
- await execFileP4(uv, installArgs, {
1323
+ await execFileP5(uv, installArgs, {
1235
1324
  cwd: root,
1236
1325
  maxBuffer: 64 * 1024 * 1024
1237
1326
  });
1238
1327
  const version2 = await probeVllm(py);
1239
1328
  return { python: py, version: version2 };
1240
1329
  }
1241
- function platformDisplay(platform) {
1242
- return platform === "win32" ? "Windows" : platform === "darwin" ? "macOS" : platform;
1243
- }
1244
- function classifyVllmBlocker(platform, error) {
1245
- const plat = platformDisplay(platform);
1246
- if (platform === "win32" || platform === "darwin") {
1247
- return `vLLM cannot run on ${plat}: its OpenAI server requires uvloop (and other Linux-only components such as NCCL/Triton), which have no ${plat} build. Use the llama.cpp / TurboQuant engine for GGUF models here, or run vLLM under WSL2 / Linux.`;
1248
- }
1249
- const err9 = error;
1250
- if (err9?.code === "ENOENT") {
1251
- return `vLLM's environment looks missing or broken (interpreter not found). Reinstall the vLLM engine from the Engines page.`;
1252
- }
1253
- const raw = err9?.stderr ? String(err9.stderr) : err9?.message ?? "unknown error";
1254
- const detail = raw.trim().split("\n").filter(Boolean).slice(-1)[0] ?? raw.trim();
1255
- return `vLLM's environment looks broken or incomplete (uvloop failed to import: ${detail}). ${plat} is a supported platform for vLLM \u2014 reinstall the vLLM engine from the Engines page rather than switching engines.`;
1256
- }
1257
- async function vllmServeBlocker(python) {
1258
- try {
1259
- await execFileP4(python, ["-c", "import uvloop"], { timeout: 2e4 });
1260
- return null;
1261
- } catch (error) {
1262
- return classifyVllmBlocker(process.platform, error);
1263
- }
1330
+ var uvloopPreflight = new UvloopPreflight("vLLM");
1331
+ function vllmServeBlocker(python) {
1332
+ return uvloopPreflight.blockerFor(python);
1264
1333
  }
1265
1334
  async function probeVllm(python) {
1266
- const { stdout } = await execFileP4(
1335
+ const { stdout } = await execFileP5(
1267
1336
  python,
1268
1337
  ["-c", 'import importlib.metadata as m; print(m.version("vllm"))'],
1269
1338
  { timeout: 3e4 }
@@ -1293,10 +1362,10 @@ function vllmServerCommand(python, model, port2, host2, tensorParallelSize = 1,
1293
1362
 
1294
1363
  // src/engines/sglang.ts
1295
1364
  import { existsSync as existsSync9 } from "fs";
1296
- import { execFile as execFile5 } from "child_process";
1365
+ import { execFile as execFile6 } from "child_process";
1297
1366
  import { join as join9 } from "path";
1298
- import { promisify as promisify5 } from "util";
1299
- var execFileP5 = promisify5(execFile5);
1367
+ import { promisify as promisify6 } from "util";
1368
+ var execFileP6 = promisify6(execFile6);
1300
1369
  var SGLANG_PYTHON = "3.12";
1301
1370
  function venvPython5(envDir) {
1302
1371
  return process.platform === "win32" ? join9(envDir, "Scripts", "python.exe") : join9(envDir, "bin", "python");
@@ -1307,40 +1376,20 @@ async function ensureSglangEnv(root, onProgress, upgrade = false) {
1307
1376
  const py = venvPython5(envDir);
1308
1377
  if (!existsSync9(py)) {
1309
1378
  onProgress?.({ phase: "extracting", pct: -1 });
1310
- await execFileP5(uv, ["venv", "--python", SGLANG_PYTHON, envDir], { cwd: root });
1379
+ await execFileP6(uv, ["venv", "--python", SGLANG_PYTHON, envDir], { cwd: root });
1311
1380
  }
1312
1381
  onProgress?.({ phase: "extracting", pct: -1 });
1313
1382
  const installArgs = ["pip", "install", "--python", py, ...upgrade ? ["-U"] : [], "sglang[all]"];
1314
- await execFileP5(uv, installArgs, { cwd: root, maxBuffer: 64 * 1024 * 1024 });
1383
+ await execFileP6(uv, installArgs, { cwd: root, maxBuffer: 64 * 1024 * 1024 });
1315
1384
  const version2 = await probeSglang(py);
1316
1385
  return { python: py, version: version2 };
1317
1386
  }
1318
- function platformDisplay2(platform) {
1319
- return platform === "win32" ? "Windows" : platform === "darwin" ? "macOS" : platform;
1320
- }
1321
- function classifySglangBlocker(platform, error) {
1322
- const plat = platformDisplay2(platform);
1323
- if (platform === "win32" || platform === "darwin") {
1324
- return `SGLang cannot run on ${plat}: its server requires uvloop (and other Linux-only components), which have no ${plat} build. Use the llama.cpp / TurboQuant engine for GGUF models here, or run SGLang under WSL2 / Linux.`;
1325
- }
1326
- const err9 = error;
1327
- if (err9?.code === "ENOENT") {
1328
- return `SGLang's environment looks missing or broken (interpreter not found). Reinstall the SGLang engine from the Engines page.`;
1329
- }
1330
- const raw = err9?.stderr ? String(err9.stderr) : err9?.message ?? "unknown error";
1331
- const detail = raw.trim().split("\n").filter(Boolean).slice(-1)[0] ?? raw.trim();
1332
- return `SGLang's environment looks broken or incomplete (uvloop failed to import: ${detail}). ${plat} is a supported platform for SGLang \u2014 reinstall the SGLang engine from the Engines page rather than switching engines.`;
1333
- }
1334
- async function sgLangServeBlocker(python) {
1335
- try {
1336
- await execFileP5(python, ["-c", "import uvloop"], { timeout: 2e4 });
1337
- return null;
1338
- } catch (error) {
1339
- return classifySglangBlocker(process.platform, error);
1340
- }
1387
+ var uvloopPreflight2 = new UvloopPreflight("SGLang");
1388
+ function sgLangServeBlocker(python) {
1389
+ return uvloopPreflight2.blockerFor(python);
1341
1390
  }
1342
1391
  async function probeSglang(python) {
1343
- const { stdout } = await execFileP5(
1392
+ const { stdout } = await execFileP6(
1344
1393
  python,
1345
1394
  ["-c", 'import importlib.metadata as m; print(m.version("sglang"))'],
1346
1395
  { timeout: 3e4 }
@@ -1952,7 +2001,7 @@ async function gracefulStop(child, exited) {
1952
2001
  function signalTerm(child) {
1953
2002
  if (!child.pid) return;
1954
2003
  if (process.platform === "win32") {
1955
- execFile6("taskkill", ["/PID", String(child.pid), "/T"], () => {
2004
+ execFile7("taskkill", ["/PID", String(child.pid), "/T"], () => {
1956
2005
  });
1957
2006
  } else {
1958
2007
  child.kill("SIGTERM");
@@ -1961,7 +2010,7 @@ function signalTerm(child) {
1961
2010
  function forceKill(child) {
1962
2011
  if (!child.pid) return;
1963
2012
  if (process.platform === "win32") {
1964
- execFile6("taskkill", ["/PID", String(child.pid), "/F", "/T"], () => {
2013
+ execFile7("taskkill", ["/PID", String(child.pid), "/F", "/T"], () => {
1965
2014
  });
1966
2015
  } else {
1967
2016
  child.kill("SIGKILL");
@@ -2066,7 +2115,7 @@ function killTrackedEnginesSync(dataDir) {
2066
2115
  }
2067
2116
  function killPidTree(pid) {
2068
2117
  if (process.platform === "win32") {
2069
- execFile6("taskkill", ["/PID", String(pid), "/F", "/T"], () => {
2118
+ execFile7("taskkill", ["/PID", String(pid), "/F", "/T"], () => {
2070
2119
  });
2071
2120
  } else {
2072
2121
  try {
@@ -2321,7 +2370,7 @@ import { existsSync as existsSync14 } from "fs";
2321
2370
  import { randomUUID as randomUUID2 } from "crypto";
2322
2371
 
2323
2372
  // src/engines/probe.ts
2324
- import { execFile as execFile7 } from "child_process";
2373
+ import { execFile as execFile8 } from "child_process";
2325
2374
  import { closeSync, existsSync as existsSync11, openSync, readSync, statSync as statSync2 } from "fs";
2326
2375
  import { dirname as dirname3 } from "path";
2327
2376
  function probeEnv(bin) {
@@ -2350,7 +2399,7 @@ function runCaptured(bin, arg) {
2350
2399
  return new Promise((resolve6) => {
2351
2400
  try {
2352
2401
  const timeoutMs = process.platform === "darwin" ? 6e4 : 15e3;
2353
- execFile7(bin, [arg], { cwd: dirname3(bin), env: probeEnv(bin), timeout: timeoutMs, windowsHide: true, maxBuffer: 4 * 1024 * 1024 }, (error, stdout, stderr) => {
2402
+ execFile8(bin, [arg], { cwd: dirname3(bin), env: probeEnv(bin), timeout: timeoutMs, windowsHide: true, maxBuffer: 4 * 1024 * 1024 }, (error, stdout, stderr) => {
2354
2403
  resolve6({ out: (stdout || "") + (stderr || ""), err: error });
2355
2404
  });
2356
2405
  } catch (e) {
@@ -2507,17 +2556,17 @@ function trimLen(s, n) {
2507
2556
  }
2508
2557
 
2509
2558
  // src/engines/build-runner.ts
2510
- import { execFile as execFile9, spawn as spawn2 } from "child_process";
2559
+ import { execFile as execFile10, spawn as spawn2 } from "child_process";
2511
2560
  import { createHash as createHash2 } from "crypto";
2512
2561
  import { copyFileSync, existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync3, readdirSync as readdirSync3, rmSync as rmSync6, writeFileSync as writeFileSync3 } from "fs";
2513
2562
  import { delimiter as delimiter2, dirname as dirname5, join as join12 } from "path";
2514
- import { promisify as promisify7 } from "util";
2563
+ import { promisify as promisify8 } from "util";
2515
2564
 
2516
2565
  // src/engines/build-prereqs.ts
2517
- import { execFile as execFile8 } from "child_process";
2566
+ import { execFile as execFile9 } from "child_process";
2518
2567
  import { delimiter, join as join11 } from "path";
2519
- import { promisify as promisify6 } from "util";
2520
- var execFileP6 = promisify6(execFile8);
2568
+ import { promisify as promisify7 } from "util";
2569
+ var execFileP7 = promisify7(execFile9);
2521
2570
  function buildEnv(toolchainDirs = []) {
2522
2571
  const dirs = toolchainDirs.map((d) => d.trim()).filter(Boolean);
2523
2572
  const env = { ...process.env };
@@ -2579,7 +2628,7 @@ var INSTALL_URLS = {
2579
2628
  gcc: "https://gcc.gnu.org/install/"
2580
2629
  };
2581
2630
  async function runVersion(cmd, args, env) {
2582
- const { stdout, stderr } = await execFileP6(cmd, args, {
2631
+ const { stdout, stderr } = await execFileP7(cmd, args, {
2583
2632
  timeout: 8e3,
2584
2633
  windowsHide: true,
2585
2634
  maxBuffer: 1024 * 1024,
@@ -2777,10 +2826,10 @@ function suggestEngineName(binPath, version2) {
2777
2826
  }
2778
2827
 
2779
2828
  // src/engines/build-runner.ts
2780
- var execFileP7 = promisify7(execFile9);
2829
+ var execFileP8 = promisify8(execFile10);
2781
2830
  async function findLibcudaDir(signal) {
2782
2831
  try {
2783
- const { stdout } = await execFileP7("ldconfig", ["-p"], {
2832
+ const { stdout } = await execFileP8("ldconfig", ["-p"], {
2784
2833
  timeout: 5e3,
2785
2834
  maxBuffer: 4 * 1024 * 1024,
2786
2835
  signal
@@ -2801,13 +2850,14 @@ function findPriorEngine(engines, build2) {
2801
2850
  const sameTarget = engines.filter(
2802
2851
  (e) => sameRepo(e.sourceRepo, build2.sourceRepo) && (e.sourceCommit ?? "") === (build2.sourceCommit ?? "")
2803
2852
  );
2804
- const storedBranch = (build2.sourceBranch ?? "").trim();
2805
- const wantedBranch = effectiveBranch(build2.sourceBranch, build2.defaultBranch);
2806
- return sameTarget.find((e) => (e.sourceBranch ?? "").trim() === storedBranch) ?? sameTarget.find((e) => effectiveBranch(e.sourceBranch, build2.defaultBranch) === wantedBranch);
2853
+ return pickByBranch(sameTarget, (build2.sourceBranch ?? "").trim(), effectiveBranch(build2.sourceBranch, build2.defaultBranch), build2.defaultBranch);
2807
2854
  }
2808
2855
  function effectiveBranch(branch, defaultBranch) {
2809
2856
  return (branch ?? "").trim() || (defaultBranch ?? "").trim();
2810
2857
  }
2858
+ function pickByBranch(candidates, exactBranch, effective, defaultBranch) {
2859
+ return candidates.find((e) => (e.sourceBranch ?? "").trim() === exactBranch) ?? candidates.find((e) => effectiveBranch(e.sourceBranch, defaultBranch) === effective);
2860
+ }
2811
2861
  var isPinnedEntry = (entry) => !!(entry.sourceCommit || entry.patchUrl);
2812
2862
  function findEngineForCatalogEntry(engines, entry, requestedBranch) {
2813
2863
  const sameBuild = engines.filter(
@@ -2815,7 +2865,7 @@ function findEngineForCatalogEntry(engines, entry, requestedBranch) {
2815
2865
  );
2816
2866
  if (isPinnedEntry(entry)) return sameBuild[0];
2817
2867
  const wanted = effectiveBranch(requestedBranch, entry.defaultBranch);
2818
- return sameBuild.find((e) => (e.sourceBranch ?? "").trim() === wanted) ?? sameBuild.find((e) => effectiveBranch(e.sourceBranch, entry.defaultBranch) === wanted);
2868
+ return pickByBranch(sameBuild, wanted, wanted, entry.defaultBranch);
2819
2869
  }
2820
2870
  function catalogBranchesToScan(entry, requestedBranch) {
2821
2871
  if (isPinnedEntry(entry)) return [void 0];
@@ -2823,6 +2873,43 @@ function catalogBranchesToScan(entry, requestedBranch) {
2823
2873
  if (!wanted) return [void 0];
2824
2874
  return wanted === (entry.defaultBranch ?? "").trim() ? [wanted, void 0] : [wanted];
2825
2875
  }
2876
+ function legacyBuildDirName(repoUrl, branch, commit) {
2877
+ const last = repoUrl.trim().replace(/\/+$/, "").split(/[\\/]/).pop() ?? "";
2878
+ const repo = last.replace(/\.git$/i, "").trim() || "engine";
2879
+ const b = (branch ?? "").trim();
2880
+ const sha = (commit ?? "").trim();
2881
+ return asDirName(sha ? `${repo}-${sha.slice(0, 12)}` : b ? `${repo}-${b}` : repo);
2882
+ }
2883
+ function serverBinaryIn(enginesRoot, dirName) {
2884
+ const root = join12(enginesRoot, "build", dirName);
2885
+ return resolveServerBinary(join12(root, "build")) ?? resolveServerBinary(root);
2886
+ }
2887
+ function findCatalogBuildOnDisk(enginesRoot, entry, requestedBranch) {
2888
+ for (const branch of catalogBranchesToScan(entry, requestedBranch)) {
2889
+ const binPath = sourceBuildBinary(enginesRoot, entry.homepage, branch, entry.sourceCommit);
2890
+ if (binPath) return { binPath, branch: branch ?? "" };
2891
+ }
2892
+ if (!entry.sourceCommit) return void 0;
2893
+ const legacy = serverBinaryIn(enginesRoot, legacyBuildDirName(entry.homepage, void 0, entry.sourceCommit));
2894
+ return legacy ? { binPath: legacy, branch: "" } : void 0;
2895
+ }
2896
+ var slashed = (path) => path.replace(/\\/g, "/").toLowerCase();
2897
+ function isEngineInBuildDir(binPath, buildRoot) {
2898
+ return slashed(binPath).startsWith(`${slashed(buildRoot).replace(/\/+$/, "")}/`);
2899
+ }
2900
+ var branchesProvablyDiffer = (a, b) => {
2901
+ const x = (a ?? "").trim();
2902
+ const y = (b ?? "").trim();
2903
+ return !!x && !!y && x !== y;
2904
+ };
2905
+ function findNameConflict(engines, name, build2) {
2906
+ const wanted = (name ?? "").trim().toLowerCase();
2907
+ if (!wanted) return void 0;
2908
+ const holder = engines.find((e) => e.name.trim().toLowerCase() === wanted);
2909
+ if (!holder) return void 0;
2910
+ const replaced = isEngineInBuildDir(holder.binPath, build2.buildRoot) || sameRepo(holder.sourceRepo, build2.sourceRepo) && (holder.sourceCommit ?? "") === (build2.sourceCommit ?? "") && !branchesProvablyDiffer(holder.sourceBranch, build2.sourceBranch);
2911
+ return replaced ? void 0 : holder;
2912
+ }
2826
2913
  function parseDefaultBranch(lsRemoteOutput) {
2827
2914
  return /^ref:\s+refs\/heads\/(\S+)\s+HEAD\s*$/m.exec(lsRemoteOutput)?.[1];
2828
2915
  }
@@ -2830,8 +2917,14 @@ function buildDirName(repoUrl, branch, commit) {
2830
2917
  const repo = normRepoUrl(repoUrl) || "engine";
2831
2918
  const b = (branch ?? "").trim();
2832
2919
  const sha = (commit ?? "").trim();
2833
- const raw = sha ? `${repo}-${sha.slice(0, 12)}` : b ? `${repo}-${b}` : repo;
2834
- return raw.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "engine";
2920
+ return asDirName(sha ? `${repo}-${sha.slice(0, 12)}` : b ? `${repo}-${b}` : repo);
2921
+ }
2922
+ function asDirName(raw) {
2923
+ const slug = raw.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
2924
+ return isPathStep(slug) ? "engine" : slug;
2925
+ }
2926
+ function isPathStep(name) {
2927
+ return /^\.*$/.test(name);
2835
2928
  }
2836
2929
  function sameRepo(a, b) {
2837
2930
  const na = normRepoUrl(a);
@@ -2841,12 +2934,11 @@ function normRepoUrl(s) {
2841
2934
  return (s ?? "").trim().toLowerCase().replace(/^https?:\/\//, "").replace(/^github\.com\//, "").replace(/\/+$/, "").replace(/\.git$/, "");
2842
2935
  }
2843
2936
  function sourceBuildBinary(enginesRoot, repoUrl, branch, commit) {
2844
- const root = join12(enginesRoot, "build", buildDirName(repoUrl, branch, commit));
2845
- return resolveServerBinary(join12(root, "build")) ?? resolveServerBinary(root);
2937
+ return serverBinaryIn(enginesRoot, buildDirName(repoUrl, branch, commit));
2846
2938
  }
2847
2939
  function sourceBuildDirOf(binPath, enginesRoot) {
2848
2940
  const m = binPath.replace(/\\/g, "/").match(/\/engines\/build\/([^/]+)(?:\/|$)/i);
2849
- if (!m) return null;
2941
+ if (!m || isPathStep(m[1])) return null;
2850
2942
  return join12(enginesRoot, "build", m[1]);
2851
2943
  }
2852
2944
  function pickGenerator(hasNinja, isWindows) {
@@ -2998,7 +3090,7 @@ async function findVcvarsall() {
2998
3090
  try {
2999
3091
  const programFilesX86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
3000
3092
  const vswhere = join12(programFilesX86, "Microsoft Visual Studio", "Installer", "vswhere.exe");
3001
- const { stdout } = await execFileP7(
3093
+ const { stdout } = await execFileP8(
3002
3094
  vswhere,
3003
3095
  ["-latest", "-products", "*", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-find", "VC\\Auxiliary\\Build\\vcvarsall.bat"],
3004
3096
  { timeout: 8e3, windowsHide: true, maxBuffer: 1024 * 1024 }
@@ -3300,11 +3392,19 @@ var NotFoundError = class extends Error {
3300
3392
  }
3301
3393
  };
3302
3394
  var NameTakenError = class extends Error {
3303
- constructor() {
3304
- super("Name already in use \u2014 choose a different name.");
3395
+ constructor(holder, incoming) {
3396
+ super(nameTakenMessage(holder, incoming));
3305
3397
  this.name = "NameTakenError";
3306
3398
  }
3307
3399
  };
3400
+ function nameTakenMessage(holder, incoming) {
3401
+ if (!holder) return "Name already in use \u2014 choose a different name.";
3402
+ const base2 = `Name already in use by "${holder.name}" \u2014 choose a different name.`;
3403
+ const held = holder.sourceBranch?.trim();
3404
+ const wanted = incoming?.sourceBranch?.trim();
3405
+ const anotherBranchOfTheSameRepo = !!held && !!wanted && held !== wanted && sameRepo(holder.sourceRepo, incoming?.sourceRepo);
3406
+ return anotherBranchOfTheSameRepo ? `${base2} It is a build of branch "${held}"; a build of "${wanted}" is a separate engine and needs its own name.` : base2;
3407
+ }
3308
3408
  var Registry = class {
3309
3409
  constructor(store2) {
3310
3410
  this.store = store2;
@@ -3323,7 +3423,7 @@ var Registry = class {
3323
3423
  }
3324
3424
  async add(name, binPath, source) {
3325
3425
  const finalName = name.trim() || "llama-server";
3326
- this.assertNameFree(finalName);
3426
+ this.assertNameFree(finalName, source);
3327
3427
  const pr = await probe(binPath);
3328
3428
  const sourceRepo = source?.sourceRepo?.trim() || void 0;
3329
3429
  const sourceBranch = source?.sourceBranch?.trim() || void 0;
@@ -3343,19 +3443,21 @@ var Registry = class {
3343
3443
  ...sourcePatchUrl ? { sourcePatchUrl } : {}
3344
3444
  };
3345
3445
  this.store.update((c) => {
3346
- if (this.nameClash(c.engines, finalName)) throw new NameTakenError();
3446
+ const holder = this.nameHolder(c.engines, finalName);
3447
+ if (holder) throw new NameTakenError(holder, source);
3347
3448
  c.engines.push(eng);
3348
3449
  if (!c.activeEngineId) c.activeEngineId = eng.id;
3349
3450
  });
3350
3451
  return { engine: eng, warning: pr.version === "unknown" ? "no_version" : void 0 };
3351
3452
  }
3352
- /** True if any registered engine already uses `name` (case-insensitive, trimmed). */
3353
- nameClash(engines, name) {
3453
+ /** The registered engine that already uses `name` (case-insensitive, trimmed), if any. */
3454
+ nameHolder(engines, name) {
3354
3455
  const n = name.trim().toLowerCase();
3355
- return engines.some((e) => e.name.trim().toLowerCase() === n);
3456
+ return engines.find((e) => e.name.trim().toLowerCase() === n);
3356
3457
  }
3357
- assertNameFree(name) {
3358
- if (this.nameClash(this.store.snapshot().engines, name)) throw new NameTakenError();
3458
+ assertNameFree(name, incoming) {
3459
+ const holder = this.nameHolder(this.store.snapshot().engines, name);
3460
+ if (holder) throw new NameTakenError(holder, incoming);
3359
3461
  }
3360
3462
  /** Register an MLX engine (kind='mlx'). No llama-server probe — the binPath is
3361
3463
  * a venv python, not a llama-server, so capabilities/flags don't apply. */
@@ -5177,9 +5279,9 @@ ${e.message}`, timedOut });
5177
5279
  resolve6({ exitCode, stdout, stderr, timedOut });
5178
5280
  };
5179
5281
  const armGrace = (ms) => {
5180
- const capped = hardDeadlineAt === void 0 ? ms : Math.max(0, Math.min(ms, hardDeadlineAt - Date.now()));
5282
+ const capped2 = hardDeadlineAt === void 0 ? ms : Math.max(0, Math.min(ms, hardDeadlineAt - Date.now()));
5181
5283
  if (graceTimer) clearTimeout(graceTimer);
5182
- graceTimer = setTimeout(finish, capped);
5284
+ graceTimer = setTimeout(finish, capped2);
5183
5285
  };
5184
5286
  const finishIfDrained = () => {
5185
5287
  if (!exited || settled) return;
@@ -5292,7 +5394,7 @@ function parseClaudeCliStreamJson(stdout) {
5292
5394
 
5293
5395
  // src/cli-launch.ts
5294
5396
  import { spawn as spawn4 } from "child_process";
5295
- import { homedir as homedir2 } from "os";
5397
+ import { homedir as homedir3 } from "os";
5296
5398
  import { readFile, writeFile, mkdir } from "fs/promises";
5297
5399
  import { join as join15, dirname as dirname7 } from "path";
5298
5400
 
@@ -5465,7 +5567,7 @@ function resolveModelKey(models, input) {
5465
5567
  return null;
5466
5568
  }
5467
5569
  var realFs = {
5468
- home: homedir2(),
5570
+ home: homedir3(),
5469
5571
  readFile: (p) => readFile(p, "utf8"),
5470
5572
  writeFile: (p, data) => writeFile(p, data, "utf8"),
5471
5573
  mkdir: async (p) => {
@@ -7875,7 +7977,7 @@ var AppUpdateChecker = class {
7875
7977
  };
7876
7978
 
7877
7979
  // src/app-update-apply.ts
7878
- import { execFile as execFile10, spawn as spawn6 } from "child_process";
7980
+ import { execFile as execFile11, spawn as spawn6 } from "child_process";
7879
7981
  import { existsSync as existsSync17, openSync as openSync2, readFileSync as readFileSync6, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
7880
7982
  import { dirname as dirname8, join as join18, resolve as resolve2 } from "path";
7881
7983
  import { fileURLToPath } from "url";
@@ -7972,7 +8074,7 @@ async function npmGlobalRoot() {
7972
8074
  if (npmRootCache) return npmRootCache.value;
7973
8075
  const value = await new Promise((res) => {
7974
8076
  const cmd = process.platform === "win32" ? "npm.cmd" : "npm";
7975
- execFile10(cmd, ["root", "-g"], { timeout: 1e4, windowsHide: true }, (e, stdout) => {
8077
+ execFile11(cmd, ["root", "-g"], { timeout: 1e4, windowsHide: true }, (e, stdout) => {
7976
8078
  if (e) return res(null);
7977
8079
  const out = String(stdout).trim();
7978
8080
  res(out || null);
@@ -10168,9 +10270,9 @@ async function loadPrimaryModel(opts, { manager: manager2, comfy: comfy2, modelR
10168
10270
 
10169
10271
  // src/models/hf-cache.ts
10170
10272
  import { existsSync as existsSync20, mkdirSync as mkdirSync8 } from "fs";
10171
- import { homedir as homedir3 } from "os";
10273
+ import { homedir as homedir4 } from "os";
10172
10274
  import { join as join22 } from "path";
10173
- function hfHubCacheDir(env = process.env, home = homedir3()) {
10275
+ function hfHubCacheDir(env = process.env, home = homedir4()) {
10174
10276
  const explicit = env.HUGGINGFACE_HUB_CACHE;
10175
10277
  if (explicit && explicit.trim()) return explicit;
10176
10278
  const hfHome = env.HF_HOME;
@@ -13703,7 +13805,7 @@ function repoSubdir(repo) {
13703
13805
  }
13704
13806
 
13705
13807
  // src/bench/bench.ts
13706
- import { execFile as execFile11 } from "child_process";
13808
+ import { execFile as execFile12 } from "child_process";
13707
13809
  import { readFileSync as readFileSync11 } from "fs";
13708
13810
  import { randomUUID as randomUUID8 } from "crypto";
13709
13811
 
@@ -16012,7 +16114,7 @@ function kvSpeedAdvisory(tps, currentKv, supportedKvTypes) {
16012
16114
  function readNvidiaVramMb() {
16013
16115
  return new Promise((resolve6) => {
16014
16116
  try {
16015
- execFile11(
16117
+ execFile12(
16016
16118
  "nvidia-smi",
16017
16119
  ["--query-gpu=memory.used", "--format=csv,noheader,nounits"],
16018
16120
  { timeout: 8e3, windowsHide: true },
@@ -16045,7 +16147,7 @@ function parseRocmVramUsed(memJson) {
16045
16147
  function readRocmVramMb() {
16046
16148
  return new Promise((resolve6) => {
16047
16149
  try {
16048
- execFile11("rocm-smi", ["--showmeminfo", "vram", "--json"], { timeout: 8e3, windowsHide: true }, (err9, stdout) => {
16150
+ execFile12("rocm-smi", ["--showmeminfo", "vram", "--json"], { timeout: 8e3, windowsHide: true }, (err9, stdout) => {
16049
16151
  resolve6(err9 || !stdout ? null : parseRocmVramUsed(stdout));
16050
16152
  });
16051
16153
  } catch {
@@ -16065,7 +16167,7 @@ function readWddmSharedMb() {
16065
16167
  if (process.platform !== "win32" || wddmSharedUnsupported) return Promise.resolve(null);
16066
16168
  return new Promise((resolve6) => {
16067
16169
  try {
16068
- execFile11(
16170
+ execFile12(
16069
16171
  "powershell",
16070
16172
  ["-NoProfile", "-NonInteractive", "-Command", WDDM_SHARED_PS],
16071
16173
  { timeout: 1e4, windowsHide: true },
@@ -16104,7 +16206,7 @@ function parseRocmGttUsed(memJson) {
16104
16206
  function readRocmGttMb() {
16105
16207
  return new Promise((resolve6) => {
16106
16208
  try {
16107
- execFile11("rocm-smi", ["--showmeminfo", "gtt", "--json"], { timeout: 8e3, windowsHide: true }, (err9, stdout) => {
16209
+ execFile12("rocm-smi", ["--showmeminfo", "gtt", "--json"], { timeout: 8e3, windowsHide: true }, (err9, stdout) => {
16108
16210
  if (err9 || !stdout) return resolve6(null);
16109
16211
  resolve6(parseRocmGttUsed(stdout));
16110
16212
  });
@@ -19362,7 +19464,7 @@ __all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
19362
19464
 
19363
19465
  // src/api/routes.ts
19364
19466
  import { randomUUID as randomUUID12 } from "crypto";
19365
- import { homedir as homedir4 } from "os";
19467
+ import { homedir as homedir5 } from "os";
19366
19468
 
19367
19469
  // src/config/config-bounds.ts
19368
19470
  var CONFIG_BOUNDS = {
@@ -22100,12 +22202,12 @@ function catalogEngine(id) {
22100
22202
  }
22101
22203
 
22102
22204
  // src/engines/cuda-provision.ts
22103
- import { execFile as execFile12 } from "child_process";
22205
+ import { execFile as execFile13 } from "child_process";
22104
22206
  import { cpSync as cpSync2, existsSync as existsSync24, mkdirSync as mkdirSync14, readdirSync as readdirSync8, rmSync as rmSync13 } from "fs";
22105
22207
  import { tmpdir } from "os";
22106
22208
  import { join as join30 } from "path";
22107
- import { promisify as promisify8 } from "util";
22108
- var execFileP8 = promisify8(execFile12);
22209
+ import { promisify as promisify9 } from "util";
22210
+ var execFileP9 = promisify9(execFile13);
22109
22211
  var REDIST_BASE = "https://developer.download.nvidia.com/compute/cuda/redist/";
22110
22212
  var CUDA_REQUIRED_COMPONENTS = ["cuda_nvcc", "cuda_cudart", "libcublas", "cuda_cccl"];
22111
22213
  var CUDA_OPTIONAL_COMPONENTS = ["libnvvm", "cuda_crt"];
@@ -22121,7 +22223,7 @@ function cmpMajorMinor(a, b) {
22121
22223
  }
22122
22224
  async function driverMaxCuda() {
22123
22225
  try {
22124
- const { stdout } = await execFileP8("nvidia-smi", [], { timeout: 8e3, windowsHide: true, maxBuffer: 1024 * 1024 });
22226
+ const { stdout } = await execFileP9("nvidia-smi", [], { timeout: 8e3, windowsHide: true, maxBuffer: 1024 * 1024 });
22125
22227
  const m = stdout.match(/CUDA Version:\s*([\d.]+)/i);
22126
22228
  return m ? m[1] : null;
22127
22229
  } catch {
@@ -22283,7 +22385,7 @@ function recommendEngines(p, engines) {
22283
22385
  }
22284
22386
 
22285
22387
  // src/sysinfo/usage.ts
22286
- import { execFile as execFile13, spawn as spawn8 } from "child_process";
22388
+ import { execFile as execFile14, spawn as spawn8 } from "child_process";
22287
22389
  import { existsSync as existsSync25, readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
22288
22390
  import os2 from "os";
22289
22391
 
@@ -22533,7 +22635,7 @@ var MAX_CONSECUTIVE_FAILURES = 3;
22533
22635
  function run(cmd, args) {
22534
22636
  return new Promise((resolve6, reject) => {
22535
22637
  try {
22536
- execFile13(cmd, args, { timeout: READER_TIMEOUT_MS, windowsHide: true, maxBuffer: 4 * 1024 * 1024 }, (err9, stdout) => {
22638
+ execFile14(cmd, args, { timeout: READER_TIMEOUT_MS, windowsHide: true, maxBuffer: 4 * 1024 * 1024 }, (err9, stdout) => {
22537
22639
  if (err9) reject(err9);
22538
22640
  else resolve6(String(stdout ?? ""));
22539
22641
  });
@@ -23851,10 +23953,8 @@ function registerApi(app2, d) {
23851
23953
  enabled = regEngines.some((x) => x.kind === "llamafile");
23852
23954
  }
23853
23955
  const srcEng = e.excludeFromSourceMatch ? void 0 : findEngineForCatalogEntry(regEngines, e, branchParam);
23854
- let sourceBinPath = srcEng?.binPath;
23855
- if (!srcEng && !e.excludeFromSourceMatch) {
23856
- sourceBinPath = catalogBranchesToScan(e, branchParam).map((branch) => sourceBuildBinary(enginesRoot, e.homepage, branch, e.sourceCommit)).find((bin) => bin !== null) ?? void 0;
23857
- }
23956
+ const onDisk = !srcEng && !e.excludeFromSourceMatch ? findCatalogBuildOnDisk(enginesRoot, e, branchParam) : void 0;
23957
+ const sourceBinPath = srcEng?.binPath ?? onDisk?.binPath;
23858
23958
  const sourceBuilt = !!srcEng || !!sourceBinPath;
23859
23959
  if (srcEng) {
23860
23960
  installed2 = true;
@@ -23869,7 +23969,7 @@ function registerApi(app2, d) {
23869
23969
  enabled,
23870
23970
  sourceBuilt,
23871
23971
  sourceEngineId: srcEng?.id,
23872
- sourceBranch: srcEng?.sourceBranch ?? "",
23972
+ sourceBranch: srcEng?.sourceBranch ?? onDisk?.branch ?? "",
23873
23973
  sourceBinPath: sourceBinPath ?? ""
23874
23974
  };
23875
23975
  });
@@ -23954,6 +24054,12 @@ function registerApi(app2, d) {
23954
24054
  const enginesRoot = join34(d.store.dir(), "engines");
23955
24055
  const toolchainDirs = d.store.snapshot().build.toolchainDirs;
23956
24056
  const buildRoot = join34(enginesRoot, "build", buildDirName(repoUrl, branch, commit));
24057
+ const engines = d.registry.list().engines;
24058
+ const conflict = findNameConflict(engines, name, { buildRoot, sourceRepo: repoUrl, sourceBranch: branch, sourceCommit: commit });
24059
+ if (conflict) return err5(c, 400, "name_already_taken", nameTakenMessage(conflict, { sourceRepo: repoUrl, sourceBranch: branch }));
24060
+ const running2 = d.registry.active();
24061
+ if (running2 && engineBusy(d) && isEngineInBuildDir(running2.binPath, buildRoot))
24062
+ return err5(c, 409, "engine_in_use", `Stop "${running2.name}" before rebuilding it \u2014 the rebuild replaces its files.`);
23957
24063
  const ac = new AbortController();
23958
24064
  buildAbort = ac;
23959
24065
  d.build.start(name ?? repoUrl);
@@ -24239,10 +24345,11 @@ function registerApi(app2, d) {
24239
24345
  const { engine, warning } = await d.registry.add(b.name ?? "", b.binPath, {
24240
24346
  sourceRepo: b.sourceRepo,
24241
24347
  sourceBranch: b.sourceBranch,
24242
- sourceCommit: b.sourceCommit
24348
+ sourceCommit: b.sourceCommit,
24349
+ sourcePatchUrl: b.sourcePatchUrl
24243
24350
  });
24244
24351
  if (!isCatalogRepo(b.sourceRepo)) {
24245
- d.registry.recordCustomSource({ name: engine.name, binPath: engine.binPath, kind: engine.kind, sourceRepo: b.sourceRepo, sourceBranch: b.sourceBranch, sourceCommit: b.sourceCommit });
24352
+ d.registry.recordCustomSource({ name: engine.name, binPath: engine.binPath, kind: engine.kind, sourceRepo: b.sourceRepo, sourceBranch: b.sourceBranch, sourceCommit: b.sourceCommit, sourcePatchUrl: b.sourcePatchUrl });
24246
24353
  }
24247
24354
  return c.json({ ...engine, warning: warning ?? null }, 201);
24248
24355
  } catch (e) {
@@ -24470,7 +24577,7 @@ function registerApi(app2, d) {
24470
24577
  if (raw === FS_DRIVES_ROOT && process.platform === "win32") {
24471
24578
  return c.json({ path: FS_DRIVES_ROOT, parent: null, entries: listWindowsDrives() });
24472
24579
  }
24473
- const target = raw ? resolve5(raw) : homedir4();
24580
+ const target = raw ? resolve5(raw) : homedir5();
24474
24581
  let real;
24475
24582
  try {
24476
24583
  real = realpathSync3(target);
@@ -25011,7 +25118,7 @@ function registerApi(app2, d) {
25011
25118
  };
25012
25119
  const isMemoryServer = server2.transport === "stdio" && (server2.command?.includes("server-memory") || server2.args?.some((a) => a.includes("server-memory")));
25013
25120
  if (isMemoryServer && !server2.env?.MEMORY_FILE_PATH) {
25014
- server2.env = { ...server2.env, MEMORY_FILE_PATH: join34(homedir4(), ".turbollm", "mcp-memory.jsonl") };
25121
+ server2.env = { ...server2.env, MEMORY_FILE_PATH: join34(homedir5(), ".turbollm", "mcp-memory.jsonl") };
25015
25122
  }
25016
25123
  d.store.update((cfg2) => {
25017
25124
  cfg2.mcp.servers.push(server2);
@@ -25820,8 +25927,8 @@ function isValidMachineName(name) {
25820
25927
  }
25821
25928
  function sanitizeMachineName(raw) {
25822
25929
  const collapsed = (raw ?? "").replace(/[\\/]+/g, "-").replace(/\s+/g, " ").trim();
25823
- const capped = collapsed.slice(0, MAX_NAME_LEN).trim();
25824
- return /[^\s-]/.test(capped) ? capped : FALLBACK_MACHINE_NAME;
25930
+ const capped2 = collapsed.slice(0, MAX_NAME_LEN).trim();
25931
+ return /[^\s-]/.test(capped2) ? capped2 : FALLBACK_MACHINE_NAME;
25825
25932
  }
25826
25933
  function uniqueMachineName(desired, taken) {
25827
25934
  const used = /* @__PURE__ */ new Set();
@@ -25911,7 +26018,7 @@ function redactDownload(rec) {
25911
26018
  // src/link/link-client.ts
25912
26019
  var DEFAULT_TIMEOUT_MS = 8e3;
25913
26020
  var ERROR_CODE = /^[a-z][a-z0-9_]{0,63}$/i;
25914
- async function failureDetail(res) {
26021
+ async function failureDetail2(res) {
25915
26022
  if (!(res.headers.get("content-type") ?? "").includes("application/json")) return {};
25916
26023
  try {
25917
26024
  const body10 = await res.json();
@@ -26136,7 +26243,7 @@ var LinkClient = class {
26136
26243
  ...json === void 0 ? {} : { body: JSON.stringify(json) },
26137
26244
  signal: AbortSignal.timeout(this.timeoutMs)
26138
26245
  });
26139
- if (!res.ok) return { kind: "http", status: res.status, ...await failureDetail(res) };
26246
+ if (!res.ok) return { kind: "http", status: res.status, ...await failureDetail2(res) };
26140
26247
  const ct = res.headers.get("content-type") ?? "";
26141
26248
  if (!ct.includes("application/json")) return { kind: "network" };
26142
26249
  const parsed = await res.json();