turbollm 1.13.2 → 1.13.3

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 (122) hide show
  1. package/README.md +3 -2
  2. package/dist/{chunk-HOKZAC3U.js → chunk-Y3TMLJQD.js} +43 -5
  3. package/dist/cli.js +213 -45
  4. package/dist/{factory-7ITNXXOI.js → factory-NOUUQICH.js} +1 -1
  5. package/dist/webdist/assets/{AgentEditPage-DS2SLHM_.js → AgentEditPage-8XwklBCN.js} +1 -1
  6. package/dist/webdist/assets/{ChatScreen-COYA_6ek.js → ChatScreen-BG-gWo8i.js} +1 -1
  7. package/dist/webdist/assets/CodeComposer-Bui_gqhF.js +1 -0
  8. package/dist/webdist/assets/{CodeHomeScreen-Csc_MF8U.js → CodeHomeScreen-CEaCj3je.js} +1 -1
  9. package/dist/webdist/assets/{CodeSessionScreen-6E3XY4su.js → CodeSessionScreen-DUTkKMNW.js} +1 -1
  10. package/dist/webdist/assets/{CustomizeScreen-CFr1srQu.js → CustomizeScreen-ze18T4hb.js} +1 -1
  11. package/dist/webdist/assets/{EnginesScreen-D2keJZ8l.js → EnginesScreen-CmJVhifa.js} +1 -1
  12. package/dist/webdist/assets/HardwareSection-63UUvSMO.js +1 -0
  13. package/dist/webdist/assets/{ModelDetailDialog-BQCs3W1u.js → ModelDetailDialog-C2lnCsw6.js} +1 -1
  14. package/dist/webdist/assets/{ModelLoadMenu-Bk0HSsac.js → ModelLoadMenu-D0bpk6p2.js} +1 -1
  15. package/dist/webdist/assets/{ModelsScreen-BSnFI83c.js → ModelsScreen-DYSvF-AP.js} +1 -1
  16. package/dist/webdist/assets/OnboardingScreen-Bti1XKVZ.js +1 -0
  17. package/dist/webdist/assets/{RoutineEditPage-C0GmeKlu.js → RoutineEditPage-Dytik45T.js} +1 -1
  18. package/dist/webdist/assets/{RoutinesPanel-CZ7kGceG.js → RoutinesPanel-CK2_OmGj.js} +1 -1
  19. package/dist/webdist/assets/{SettingsScreen-BnC6qSFo.js → SettingsScreen-qcB-Wlhm.js} +1 -1
  20. package/dist/webdist/assets/{SidebarResizeHandle-D-1cxpNM.js → SidebarResizeHandle-C6DzzA0i.js} +2 -2
  21. package/dist/webdist/assets/{SkillEditPage-BFnoGYE4.js → SkillEditPage-BoVodeSt.js} +1 -1
  22. package/dist/webdist/assets/{ToolApprovalBar-gBl1Pne_.js → ToolApprovalBar-CkVy2BpV.js} +3 -3
  23. package/dist/webdist/assets/WorkspaceScreen-BzYimITz.js +1 -0
  24. package/dist/webdist/assets/{abnfDiagram-N423BO3Z-B-yxOJAr.js → abnfDiagram-N423BO3Z-BsFZfp7v.js} +1 -1
  25. package/dist/webdist/assets/{agent-api-1EptCITO.js → agent-api-CeGvce9t.js} +1 -1
  26. package/dist/webdist/assets/{alert-dialog-DId8mvnn.js → alert-dialog-Crc_A3Jz.js} +1 -1
  27. package/dist/webdist/assets/{arc-CmG0J3F-.js → arc-DBKAh_3p.js} +1 -1
  28. package/dist/webdist/assets/{architectureDiagram-T3A2C74G-CLcR4aXc.js → architectureDiagram-T3A2C74G-DF2Iau9y.js} +1 -1
  29. package/dist/webdist/assets/{blockDiagram-VBNYF7ZC-ImyoZH5n.js → blockDiagram-VBNYF7ZC-EIM7OH8W.js} +1 -1
  30. package/dist/webdist/assets/{c4Diagram-5PPSVZJV-Dn1etOjf.js → c4Diagram-5PPSVZJV-DfTJQH_y.js} +1 -1
  31. package/dist/webdist/assets/channel-BF2z4CLG.js +1 -0
  32. package/dist/webdist/assets/{chat-api-CCZfNFmH.js → chat-api-BspgdIew.js} +1 -1
  33. package/dist/webdist/assets/{chat-queries-6aDORXMQ.js → chat-queries-dQVxfOyx.js} +1 -1
  34. package/dist/webdist/assets/{chevron-down-CquxAQxl.js → chevron-down-DNeXZ14t.js} +1 -1
  35. package/dist/webdist/assets/{chevron-left-irxTskG3.js → chevron-left-yPpon0Zo.js} +1 -1
  36. package/dist/webdist/assets/{chevron-right-BxDhzUZl.js → chevron-right-qwzlPkv4.js} +1 -1
  37. package/dist/webdist/assets/{chunk-2GRJ4B5K-et7nGso8.js → chunk-2GRJ4B5K-g8WkdrcJ.js} +1 -1
  38. package/dist/webdist/assets/{chunk-2Q5K7J3B-C7vz-PvX.js → chunk-2Q5K7J3B-DiSXrpfm.js} +1 -1
  39. package/dist/webdist/assets/{chunk-5RXB4S5H-DWdBsuyj.js → chunk-5RXB4S5H--rX8NQES.js} +1 -1
  40. package/dist/webdist/assets/{chunk-5VM5RSS4-DqfZvvbb.js → chunk-5VM5RSS4-D0bbkNOA.js} +1 -1
  41. package/dist/webdist/assets/{chunk-6Q2QTUOP-qF-CNBFu.js → chunk-6Q2QTUOP-CyjvDHy7.js} +1 -1
  42. package/dist/webdist/assets/{chunk-GF5L2VYU-CrVRwghC.js → chunk-GF5L2VYU-DBsZFyHH.js} +1 -1
  43. package/dist/webdist/assets/{chunk-JWPE2WC7-BRr2laYf.js → chunk-JWPE2WC7-BJX8rZY8.js} +1 -1
  44. package/dist/webdist/assets/{chunk-KBJHAD2P-JxaAF9FJ.js → chunk-KBJHAD2P-CzHI537O.js} +1 -1
  45. package/dist/webdist/assets/{chunk-RYQCIY6F-W9k-woT3.js → chunk-RYQCIY6F-DcQ5BoLP.js} +1 -1
  46. package/dist/webdist/assets/{chunk-XXDRQBXY-BEf2Mob4.js → chunk-XXDRQBXY-DwaqNMb3.js} +1 -1
  47. package/dist/webdist/assets/{circle-check-oj-qQsUY.js → circle-check-Brhy4Orf.js} +1 -1
  48. package/dist/webdist/assets/{circle-x-gGXzROsQ.js → circle-x-BvhAr_O9.js} +1 -1
  49. package/dist/webdist/assets/classDiagram-JCYQIIEL-D-pqoTab.js +1 -0
  50. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-D-pqoTab.js +1 -0
  51. package/dist/webdist/assets/{collapsible-DL9VySa3.js → collapsible-Bg5PA5Nz.js} +1 -1
  52. package/dist/webdist/assets/{cose-bilkent-JH36ORCC-tkfBcHU9.js → cose-bilkent-JH36ORCC-DT2idxjo.js} +1 -1
  53. package/dist/webdist/assets/{cynefin-VYW2F7L2-zJZI0irR.js → cynefin-VYW2F7L2-9kVBD_9a.js} +1 -1
  54. package/dist/webdist/assets/{cynefinDiagram-MW4NZA55-BbH3UWYG.js → cynefinDiagram-MW4NZA55-CTix7oEO.js} +1 -1
  55. package/dist/webdist/assets/{dagre-VZM6K2ZE-DyC5hntE.js → dagre-VZM6K2ZE-DbRB_1Ng.js} +1 -1
  56. package/dist/webdist/assets/{diagram-7IWD3JNH-Cn3vmigd.js → diagram-7IWD3JNH-ClCpikH_.js} +1 -1
  57. package/dist/webdist/assets/{diagram-B4RE2ZJO-DzIzUUTv.js → diagram-B4RE2ZJO-wQlXyd4e.js} +1 -1
  58. package/dist/webdist/assets/{diagram-LBJQPF4R-BbtaHnkO.js → diagram-LBJQPF4R-zgM6REwi.js} +1 -1
  59. package/dist/webdist/assets/{diagram-Q27KOJAE-CFenKIgI.js → diagram-Q27KOJAE-DvIssBlm.js} +1 -1
  60. package/dist/webdist/assets/{diagram-UB23O5K3-CuyPU_Mu.js → diagram-UB23O5K3-DdQiF9NE.js} +1 -1
  61. package/dist/webdist/assets/{dropdown-menu-Be7l1fxe.js → dropdown-menu-HI5N3Rmt.js} +1 -1
  62. package/dist/webdist/assets/{ebnfDiagram-BXEA7PRR-DOODd0MH.js → ebnfDiagram-BXEA7PRR-CpSxEGTe.js} +1 -1
  63. package/dist/webdist/assets/{erDiagram-JOGREHBK-Dcr04SmE.js → erDiagram-JOGREHBK-BrhRHXD4.js} +1 -1
  64. package/dist/webdist/assets/{file-text-FE03rWAa.js → file-text-Cx83fgk0.js} +1 -1
  65. package/dist/webdist/assets/{flowDiagram-UKHOOZJN-Bz7rFGfl.js → flowDiagram-UKHOOZJN-CIxMbmNO.js} +1 -1
  66. package/dist/webdist/assets/{folder-input-D15LVeML.js → folder-input-BN5lzecG.js} +1 -1
  67. package/dist/webdist/assets/{folder-plus-DzkiCb2B.js → folder-plus-B-imiY57.js} +1 -1
  68. package/dist/webdist/assets/{ganttDiagram-PKOTCBZU-Bj_ZOPAJ.js → ganttDiagram-PKOTCBZU-CiO9YNNt.js} +1 -1
  69. package/dist/webdist/assets/{git-branch-HP8nxDTj.js → git-branch-BY-pdlSo.js} +1 -1
  70. package/dist/webdist/assets/{gitGraphDiagram-DS77QQ5N-8baKuWz3.js → gitGraphDiagram-DS77QQ5N-Dz_fBDX6.js} +1 -1
  71. package/dist/webdist/assets/{globe-r-Gk9vO_.js → globe-FB3s-Kjz.js} +1 -1
  72. package/dist/webdist/assets/{index-DWD1Hz6g.js → index-CfwXVQIu.js} +4 -4
  73. package/dist/webdist/assets/{infoDiagram-6WML65LV-CZh4edQp.js → infoDiagram-6WML65LV-BP9JLl_M.js} +1 -1
  74. package/dist/webdist/assets/{ishikawaDiagram-WSZJBQD7-BT7RJUZO.js → ishikawaDiagram-WSZJBQD7-CeBpQALC.js} +1 -1
  75. package/dist/webdist/assets/{journeyDiagram-NVQOT4AX-Brz2ooLj.js → journeyDiagram-NVQOT4AX-Cnn5M1YO.js} +1 -1
  76. package/dist/webdist/assets/{kanban-definition-27J2QSJJ-ByeIutfh.js → kanban-definition-27J2QSJJ-BMnM-8zj.js} +1 -1
  77. package/dist/webdist/assets/{linear-Bfr0xFLl.js → linear-ontMFf7q.js} +1 -1
  78. package/dist/webdist/assets/{lock-CKcOp4XJ.js → lock-CVTYolJH.js} +1 -1
  79. package/dist/webdist/assets/{mermaid.core-D-E5f09M.js → mermaid.core-BX4U-c4C.js} +4 -4
  80. package/dist/webdist/assets/{mindmap-definition-FAOFIHXS-hrzHqptK.js → mindmap-definition-FAOFIHXS-D55lobOz.js} +1 -1
  81. package/dist/webdist/assets/{monitor--WNtubB8.js → monitor-BVyi9riP.js} +1 -1
  82. package/dist/webdist/assets/{pegDiagram-VL7TDLO6-B441EsMI.js → pegDiagram-VL7TDLO6-BE11XRQ7.js} +1 -1
  83. package/dist/webdist/assets/{pencil-DLms_KS_.js → pencil-xiVy9lBH.js} +1 -1
  84. package/dist/webdist/assets/{pieDiagram-7S7Q4E2Y-ByhCEyi1.js → pieDiagram-7S7Q4E2Y-BMHDg8ys.js} +1 -1
  85. package/dist/webdist/assets/{quadrantDiagram-CIZ2JOQS-BoVd-30d.js → quadrantDiagram-CIZ2JOQS-2sqR5qXm.js} +1 -1
  86. package/dist/webdist/assets/{railroadDiagram-AXF67PYL-2uvCDUaS.js → railroadDiagram-AXF67PYL-CrA2ZKhq.js} +1 -1
  87. package/dist/webdist/assets/{refresh-cw-BZK9PNk2.js → refresh-cw-BGipAyiS.js} +1 -1
  88. package/dist/webdist/assets/{remote-failure-BUHwngKj.js → remote-failure-CGk8OyjK.js} +1 -1
  89. package/dist/webdist/assets/{requirementDiagram-LRYGKXZP-BgJIRdwB.js → requirementDiagram-LRYGKXZP-RlYw_SgL.js} +1 -1
  90. package/dist/webdist/assets/{rocket-CZ554uI4.js → rocket-DHnkfnhQ.js} +1 -1
  91. package/dist/webdist/assets/{rotate-ccw-CYnZI5-z.js → rotate-ccw-DmG7PkUG.js} +1 -1
  92. package/dist/webdist/assets/{sankeyDiagram-W5VNT64P-Owz2xIZe.js → sankeyDiagram-W5VNT64P-B61EFr-D.js} +1 -1
  93. package/dist/webdist/assets/{sequenceDiagram-SI44F4Z6-DaoxE-fa.js → sequenceDiagram-SI44F4Z6-Cj4e2tXy.js} +1 -1
  94. package/dist/webdist/assets/{sheet-Df9khmUy.js → sheet-DFCO49jw.js} +1 -1
  95. package/dist/webdist/assets/{sizeCapture-X5ZJPWSS-dcdfbtqP.js → sizeCapture-X5ZJPWSS-CYyUy4Qg.js} +1 -1
  96. package/dist/webdist/assets/{skeleton-Duv5iwwK.js → skeleton-DVrIPwv0.js} +1 -1
  97. package/dist/webdist/assets/{sliders-horizontal-Cr87JkWR.js → sliders-horizontal-DQYu0jQs.js} +1 -1
  98. package/dist/webdist/assets/{sparkles-Cz9OBDET.js → sparkles-DKoUw0Ra.js} +1 -1
  99. package/dist/webdist/assets/{star-DdqpME5N.js → star-EY1hsb1g.js} +1 -1
  100. package/dist/webdist/assets/{stateDiagram-OKZ733FA-CXX12BPj.js → stateDiagram-OKZ733FA-CIAre6fb.js} +1 -1
  101. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-c4H1EbPk.js +1 -0
  102. package/dist/webdist/assets/{swimlanes-SLNWSIFB-fq1Cou-U.js → swimlanes-SLNWSIFB-DGZBf-GQ.js} +2 -2
  103. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-C9AdErpx.js +8 -0
  104. package/dist/webdist/assets/{switch-C6JFP8Mz.js → switch-CXoaYXdG.js} +1 -1
  105. package/dist/webdist/assets/{terminal-BsWKdFvy.js → terminal-BrWVclQ0.js} +1 -1
  106. package/dist/webdist/assets/{timeline-definition-Z64GVDOM-BvUBrPbD.js → timeline-definition-Z64GVDOM-mu5ti0bv.js} +1 -1
  107. package/dist/webdist/assets/{trash-2-B4G2scm5.js → trash-2-WYWL4BUK.js} +1 -1
  108. package/dist/webdist/assets/{vennDiagram-T6HMQDX7-CEeg53T_.js → vennDiagram-T6HMQDX7-OxY1RaKm.js} +1 -1
  109. package/dist/webdist/assets/{wardleyDiagram-T6FBY63Y-C7jkNVGw.js → wardleyDiagram-T6FBY63Y-BtG14vOo.js} +1 -1
  110. package/dist/webdist/assets/{wrench-8U77f_Yu.js → wrench-D_MLSbdw.js} +1 -1
  111. package/dist/webdist/assets/{xychartDiagram-ELKLHX3M-BqzboKBI.js → xychartDiagram-ELKLHX3M-DeNO3ZVS.js} +1 -1
  112. package/dist/webdist/index.html +1 -1
  113. package/package.json +1 -1
  114. package/dist/webdist/assets/CodeComposer-DMDibXma.js +0 -1
  115. package/dist/webdist/assets/HardwareSection-CE799Eq2.js +0 -1
  116. package/dist/webdist/assets/OnboardingScreen-T-PZwwoj.js +0 -1
  117. package/dist/webdist/assets/WorkspaceScreen-B52K9UEq.js +0 -1
  118. package/dist/webdist/assets/channel-BwZvGoK9.js +0 -1
  119. package/dist/webdist/assets/classDiagram-JCYQIIEL-DzGOglmc.js +0 -1
  120. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-DzGOglmc.js +0 -1
  121. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-Cm8sAKH-.js +0 -1
  122. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-BEleuPZP.js +0 -8
package/README.md CHANGED
@@ -443,8 +443,9 @@ connected); **Remove** undoes it.
443
443
 
444
444
  - A **persistent bottom strip** on every screen shows real-time CPU, RAM, GPU and VRAM — values
445
445
  and percentages — pulled from `nvidia-smi`, WDDM counters, `rocm-smi`, AMD sysfs, `ioreg`,
446
- or `/proc` on Linux. Clicking the bar opens detailed gauges and sparklines in Settings → System.
447
- Toggle it off entirely from Settings General.
446
+ or `/proc` on Linux. Clicking the bar opens detailed gauges and sparklines in Settings → System,
447
+ including live **disk I/O** (read/write MB/s) and a **shared/spilled VRAM** figure that shows
448
+ when a discrete GPU has spilled into system memory. Toggle it off entirely from Settings → General.
448
449
  - **Engines → Monitor** puts the live engine log and those same hardware gauges on one
449
450
  always-visible split screen, plus a second, LM Studio-style **developer request log**: every
450
451
  completion the daemon serves — external API clients, Code sessions, in-app Chat — with
@@ -65,7 +65,17 @@ function availableBackends(tag = LLAMA_BUILD) {
65
65
  if (a === "arm64") return [def("cpu", "CPU", `llama-${tag}-bin-win-cpu-arm64.zip`)];
66
66
  return [
67
67
  def("cuda", "CUDA (NVIDIA)", `llama-${tag}-bin-win-cuda-${CUDA_VER}-x64.zip`, `cudart-llama-bin-win-cuda-${CUDA_VER}-x64.zip`),
68
- def("rocm", "ROCm / HIP (AMD Radeon)", `llama-${tag}-bin-win-hip-radeon-x64.zip`),
68
+ // Upstream has renamed this archive at least once (`*-bin-win-hip-radeon-x64.zip`
69
+ // `*-bin-win-rocm-<toolkit-ver>-x64.zip`, GitHub #220) without any deprecation window,
70
+ // so the literal name below is only a fallback label — assetPatterns resolves the
71
+ // real filename from the release's own asset list at download time and survives the
72
+ // next rename too.
73
+ {
74
+ id: "rocm",
75
+ label: "ROCm / HIP (AMD Radeon)",
76
+ assets: [`llama-${tag}-bin-win-hip-radeon-x64.zip`],
77
+ assetPatterns: [/^llama-.+-bin-win-(?:hip-radeon|rocm-[\d.]+)-x64\.zip$/i]
78
+ },
69
79
  def("sycl", "SYCL (Intel)", `llama-${tag}-bin-win-sycl-x64.zip`),
70
80
  def("vulkan", "Vulkan (any GPU)", `llama-${tag}-bin-win-vulkan-x64.zip`),
71
81
  def("cpu", "CPU", `llama-${tag}-bin-win-cpu-x64.zip`)
@@ -236,12 +246,30 @@ async function provisionBackend(enginesRoot, backend, tag, onProgress, signal) {
236
246
  }
237
247
  mkdirSync(destDir, { recursive: true });
238
248
  const parts = backend.assets.length;
249
+ const tmpPaths = [];
239
250
  try {
240
251
  for (let i = 0; i < parts; i++) {
241
- const asset = backend.assets[i];
242
252
  const part = i + 1;
243
- const tmp = join(enginesRoot, asset);
244
- const url = backend.downloadBaseUrl ? `${backend.downloadBaseUrl}/${asset}` : `https://github.com/${backend.repo ?? REPO}/releases/download/${backend.releaseTag ?? tag}/${asset}`;
253
+ const pattern = backend.assetPatterns?.[i];
254
+ let assetName = backend.assets[i];
255
+ let url;
256
+ if (backend.downloadBaseUrl) {
257
+ url = `${backend.downloadBaseUrl}/${assetName}`;
258
+ } else {
259
+ const repo = backend.repo ?? REPO;
260
+ const releaseTag = backend.releaseTag ?? tag;
261
+ if (pattern) {
262
+ const releaseAssets = await releaseAssetsForTag(repo, releaseTag, signal);
263
+ const found = releaseAssets.find((a) => pattern.test(a.name));
264
+ if (!found) throw new Error(`no release asset matching ${pattern} in ${repo}@${releaseTag}`);
265
+ assetName = found.name;
266
+ url = found.browser_download_url;
267
+ } else {
268
+ url = `https://github.com/${repo}/releases/download/${releaseTag}/${assetName}`;
269
+ }
270
+ }
271
+ const tmp = join(enginesRoot, assetName);
272
+ tmpPaths.push(tmp);
245
273
  onProgress?.({ phase: "downloading", pct: 0, part, parts });
246
274
  await downloadFile(url, tmp, (p) => onProgress?.({ ...p, part, parts }), signal);
247
275
  onProgress?.({ phase: "extracting", pct: -1, part, parts });
@@ -249,7 +277,7 @@ async function provisionBackend(enginesRoot, backend, tag, onProgress, signal) {
249
277
  rmSync(tmp, { force: true });
250
278
  }
251
279
  } catch (e) {
252
- for (const asset of backend.assets) rmSync(join(enginesRoot, asset), { force: true });
280
+ for (const tmp of tmpPaths) rmSync(tmp, { force: true });
253
281
  rmSync(destDir, { recursive: true, force: true });
254
282
  throw e;
255
283
  }
@@ -347,6 +375,16 @@ async function latestBuildTagRelease(repo, signal) {
347
375
  }
348
376
  return best;
349
377
  }
378
+ async function releaseAssetsForTag(repo, tag, signal) {
379
+ const res = await fetch(`https://api.github.com/repos/${repo}/releases/tags/${encodeURIComponent(tag)}`, {
380
+ headers: githubHeaders(),
381
+ signal
382
+ });
383
+ if (isRateLimited(res)) throw new GithubRateLimitError(repo);
384
+ if (!res.ok) throw new Error(`could not query ${repo} release ${tag}: HTTP ${res.status}`);
385
+ const data = await res.json();
386
+ return data.assets ?? [];
387
+ }
350
388
  async function latestCommitSha(repo, branch = "", signal) {
351
389
  const ref = branch.trim() ? encodeURIComponent(branch.trim()) : "HEAD";
352
390
  const res = await fetch(`https://api.github.com/repos/${repo}/commits/${ref}`, {
package/dist/cli.js CHANGED
@@ -43,7 +43,7 @@ import {
43
43
  recommendBackendId,
44
44
  reconcileTailscale,
45
45
  setGithubTokenProvider
46
- } from "./chunk-HOKZAC3U.js";
46
+ } from "./chunk-Y3TMLJQD.js";
47
47
 
48
48
  // src/util/hide-console-windows.ts
49
49
  import { ChildProcess } from "child_process";
@@ -22376,6 +22376,67 @@ function mergeUsage(sys, samples) {
22376
22376
  };
22377
22377
  });
22378
22378
  }
22379
+ var WHOLE_DISK_RE = /^(?:sd[a-z]+|vd[a-z]+|xvd[a-z]+|nvme\d+n\d+|mmcblk\d+)$/;
22380
+ function parseDiskstats(raw) {
22381
+ let sectorsRead = 0;
22382
+ let sectorsWritten = 0;
22383
+ let matched = false;
22384
+ for (const line of raw.split("\n")) {
22385
+ const f2 = line.trim().split(/\s+/);
22386
+ if (f2.length < 10) continue;
22387
+ if (!WHOLE_DISK_RE.test(f2[2])) continue;
22388
+ const r = Number(f2[5]);
22389
+ const w = Number(f2[9]);
22390
+ if (!Number.isFinite(r) || !Number.isFinite(w)) continue;
22391
+ sectorsRead += r;
22392
+ sectorsWritten += w;
22393
+ matched = true;
22394
+ }
22395
+ return matched ? { sectorsRead, sectorsWritten } : null;
22396
+ }
22397
+ var SECTOR_BYTES = 512;
22398
+ function diskstatsRate(prev, prevAtMs, cur, curAtMs) {
22399
+ if (!prev || !cur) return null;
22400
+ const elapsedS = (curAtMs - prevAtMs) / 1e3;
22401
+ if (elapsedS <= 0) return null;
22402
+ const readMBps = (cur.sectorsRead - prev.sectorsRead) * SECTOR_BYTES / 1e6 / elapsedS;
22403
+ const writeMBps = (cur.sectorsWritten - prev.sectorsWritten) * SECTOR_BYTES / 1e6 / elapsedS;
22404
+ if (readMBps < 0 || writeMBps < 0) return null;
22405
+ return { readMBps, writeMBps, combined: false };
22406
+ }
22407
+ function parseWindowsDiskSample(line) {
22408
+ let j;
22409
+ try {
22410
+ j = JSON.parse(line);
22411
+ } catch {
22412
+ return null;
22413
+ }
22414
+ if (typeof j.readBps !== "number" || typeof j.writeBps !== "number") return null;
22415
+ return { readMBps: j.readBps / 1e6, writeMBps: j.writeBps / 1e6, combined: false };
22416
+ }
22417
+ var IOSTAT_COLUMNS_PER_DISK = 3;
22418
+ var IOSTAT_MBPS_COLUMN = 2;
22419
+ function parseMacIostat(text) {
22420
+ let newestTotalMBps = null;
22421
+ for (const line of text.split("\n")) {
22422
+ const total = sumDiskThroughput(line);
22423
+ if (total !== null) newestTotalMBps = total;
22424
+ }
22425
+ if (newestTotalMBps === null) return null;
22426
+ return { readMBps: newestTotalMBps, writeMBps: null, combined: true };
22427
+ }
22428
+ function sumDiskThroughput(line) {
22429
+ const trimmed = line.trim();
22430
+ if (!trimmed) return null;
22431
+ const columns = trimmed.split(/\s+/).map(Number);
22432
+ if (columns.length % IOSTAT_COLUMNS_PER_DISK !== 0) return null;
22433
+ if (!columns.every((c) => Number.isFinite(c))) return null;
22434
+ let totalMBps = 0;
22435
+ for (let i = IOSTAT_MBPS_COLUMN; i < columns.length; i += IOSTAT_COLUMNS_PER_DISK) {
22436
+ totalMBps += columns[i];
22437
+ }
22438
+ return totalMBps;
22439
+ }
22379
22440
 
22380
22441
  // src/sysinfo/usage.ts
22381
22442
  var SAMPLE_MS = 1e3;
@@ -22416,6 +22477,61 @@ function createLatchingReader(kind, sample, hooks = {}) {
22416
22477
  }
22417
22478
  };
22418
22479
  }
22480
+ function createStreamingReader(kind, command, args, parseLine) {
22481
+ let child = null;
22482
+ let latest2 = null;
22483
+ let buf = "";
22484
+ let dead = false;
22485
+ return {
22486
+ kind,
22487
+ start() {
22488
+ if (child) return;
22489
+ try {
22490
+ child = spawn8(command, args, {
22491
+ windowsHide: true,
22492
+ stdio: ["ignore", "pipe", "ignore"]
22493
+ });
22494
+ } catch {
22495
+ dead = true;
22496
+ return;
22497
+ }
22498
+ child.stdout?.setEncoding("utf8");
22499
+ child.stdout?.on("data", (chunk) => {
22500
+ buf += chunk;
22501
+ if (buf.length > 1e6) buf = buf.slice(-1e5);
22502
+ for (; ; ) {
22503
+ const nl = buf.indexOf("\n");
22504
+ if (nl < 0) break;
22505
+ const line = buf.slice(0, nl).trim();
22506
+ buf = buf.slice(nl + 1);
22507
+ if (!line) continue;
22508
+ const parsed = parseLine(line);
22509
+ if (parsed !== null) latest2 = parsed;
22510
+ }
22511
+ });
22512
+ child.on("error", () => {
22513
+ dead = true;
22514
+ child = null;
22515
+ });
22516
+ child.on("exit", () => {
22517
+ child = null;
22518
+ });
22519
+ },
22520
+ // Returns null until the first sample lands (~1.65 s for the WDDM counter stream). That is
22521
+ // "not ready", not a failure — which is exactly why this reader is not wrapped in
22522
+ // createLatchingReader: the latch would trip during the normal warm-up.
22523
+ read: async () => dead ? null : latest2,
22524
+ stop() {
22525
+ try {
22526
+ child?.kill();
22527
+ } catch {
22528
+ }
22529
+ child = null;
22530
+ latest2 = null;
22531
+ buf = "";
22532
+ }
22533
+ };
22534
+ }
22419
22535
  function nvidiaReader() {
22420
22536
  return createLatchingReader(
22421
22537
  "nvidia",
@@ -22493,65 +22609,98 @@ var WDDM_STREAM_PS = [
22493
22609
  "}"
22494
22610
  ].join("\n");
22495
22611
  function wddmReader() {
22496
- let child = null;
22497
- let latest2 = null;
22498
- let buf = "";
22612
+ return createStreamingReader(
22613
+ "wddm",
22614
+ "powershell",
22615
+ ["-NoProfile", "-NonInteractive", "-Command", WDDM_STREAM_PS],
22616
+ (line) => {
22617
+ const parsed = parseWddmSample(line);
22618
+ return parsed.length > 0 ? parsed : null;
22619
+ }
22620
+ );
22621
+ }
22622
+ function nullReader() {
22623
+ return { kind: "null", start: () => {
22624
+ }, read: async () => null, stop: () => {
22625
+ } };
22626
+ }
22627
+ var DISK_STREAM_PS = [
22628
+ "$ErrorActionPreference='SilentlyContinue'",
22629
+ "$c=@('\\PhysicalDisk(_Total)\\Disk Read Bytes/sec','\\PhysicalDisk(_Total)\\Disk Write Bytes/sec')",
22630
+ "Get-Counter -Counter $c -SampleInterval 1 -Continuous | ForEach-Object {",
22631
+ "$r=$null;$w=$null",
22632
+ "foreach($s in $_.CounterSamples){",
22633
+ "$p=$s.Path.ToLower()",
22634
+ "if($p -like '*read bytes*'){$r=[double]$s.CookedValue}",
22635
+ "elseif($p -like '*write bytes*'){$w=[double]$s.CookedValue}}",
22636
+ "Write-Output (ConvertTo-Json -Compress -InputObject @{readBps=$r;writeBps=$w})",
22637
+ "}"
22638
+ ].join("\n");
22639
+ function windowsDiskReader() {
22640
+ return createStreamingReader(
22641
+ "windows-disk",
22642
+ "powershell",
22643
+ ["-NoProfile", "-NonInteractive", "-Command", DISK_STREAM_PS],
22644
+ parseWindowsDiskSample
22645
+ );
22646
+ }
22647
+ function linuxDiskReader() {
22648
+ let prev = null;
22649
+ let prevAtMs = 0;
22499
22650
  let dead = false;
22500
22651
  return {
22501
- kind: "wddm",
22652
+ kind: "linux-diskstats",
22502
22653
  start() {
22503
- if (child) return;
22654
+ prev = null;
22655
+ prevAtMs = 0;
22656
+ dead = false;
22657
+ },
22658
+ read: async () => {
22659
+ if (dead) return null;
22504
22660
  try {
22505
- child = spawn8("powershell", ["-NoProfile", "-NonInteractive", "-Command", WDDM_STREAM_PS], {
22506
- windowsHide: true,
22507
- stdio: ["ignore", "pipe", "ignore"]
22508
- });
22661
+ const cur = parseDiskstats(readFileSync15("/proc/diskstats", "utf8"));
22662
+ const now = Date.now();
22663
+ const rate = diskstatsRate(prev, prevAtMs, cur, now);
22664
+ prev = cur;
22665
+ prevAtMs = now;
22666
+ return rate;
22509
22667
  } catch {
22510
22668
  dead = true;
22511
- return;
22669
+ return null;
22512
22670
  }
22513
- child.stdout?.setEncoding("utf8");
22514
- child.stdout?.on("data", (chunk) => {
22515
- buf += chunk;
22516
- if (buf.length > 1e6) buf = buf.slice(-1e5);
22517
- for (; ; ) {
22518
- const nl = buf.indexOf("\n");
22519
- if (nl < 0) break;
22520
- const line = buf.slice(0, nl).trim();
22521
- buf = buf.slice(nl + 1);
22522
- if (!line) continue;
22523
- const parsed = parseWddmSample(line);
22524
- if (parsed.length > 0) latest2 = parsed;
22525
- }
22526
- });
22527
- child.on("error", () => {
22528
- dead = true;
22529
- child = null;
22530
- });
22531
- child.on("exit", () => {
22532
- child = null;
22533
- });
22534
22671
  },
22535
- // Returns null until the first sample lands (~1.65 s). That is "not ready", not a failure —
22536
- // which is exactly why this reader is not wrapped in createLatchingReader: the latch would
22537
- // trip during the normal warm-up.
22538
- read: async () => dead ? null : latest2,
22539
22672
  stop() {
22540
- try {
22541
- child?.kill();
22542
- } catch {
22543
- }
22544
- child = null;
22545
- latest2 = null;
22546
- buf = "";
22673
+ prev = null;
22674
+ prevAtMs = 0;
22547
22675
  }
22548
22676
  };
22549
22677
  }
22550
- function nullReader() {
22678
+ function createLiveIostatParser() {
22679
+ let seenFirstDataRow = false;
22680
+ return (line) => {
22681
+ const sample = parseMacIostat(line);
22682
+ if (!sample) return null;
22683
+ if (!seenFirstDataRow) {
22684
+ seenFirstDataRow = true;
22685
+ return null;
22686
+ }
22687
+ return sample;
22688
+ };
22689
+ }
22690
+ function darwinDiskReader() {
22691
+ return createStreamingReader("darwin-iostat", "iostat", ["-d", "-w", "1"], createLiveIostatParser());
22692
+ }
22693
+ function nullDiskReader() {
22551
22694
  return { kind: "null", start: () => {
22552
22695
  }, read: async () => null, stop: () => {
22553
22696
  } };
22554
22697
  }
22698
+ function pickDiskReader() {
22699
+ if (process.platform === "win32") return windowsDiskReader();
22700
+ if (process.platform === "linux") return linuxDiskReader();
22701
+ if (process.platform === "darwin") return darwinDiskReader();
22702
+ return nullDiskReader();
22703
+ }
22555
22704
  function pickReader(sys) {
22556
22705
  const gpus = sys.gpus ?? [];
22557
22706
  if (gpus.length === 0) return nullReader();
@@ -22563,6 +22712,8 @@ function pickReader(sys) {
22563
22712
  }
22564
22713
  var reader = null;
22565
22714
  var injected = null;
22715
+ var diskReader = null;
22716
+ var injectedDisk = null;
22566
22717
  var timer = null;
22567
22718
  var idleTimer = null;
22568
22719
  var latest = null;
@@ -22574,10 +22725,15 @@ function startLoop() {
22574
22725
  running = true;
22575
22726
  prevCpu = null;
22576
22727
  reader = injected ?? pickReader(getSysInfo());
22728
+ diskReader = injectedDisk ?? pickDiskReader();
22577
22729
  try {
22578
22730
  reader.start();
22579
22731
  } catch {
22580
22732
  }
22733
+ try {
22734
+ diskReader.start();
22735
+ } catch {
22736
+ }
22581
22737
  timer = setInterval(() => void tick2(), SAMPLE_MS);
22582
22738
  timer.unref?.();
22583
22739
  }
@@ -22599,6 +22755,12 @@ async function tick2() {
22599
22755
  } catch {
22600
22756
  samples = null;
22601
22757
  }
22758
+ let disk = null;
22759
+ try {
22760
+ disk = diskReader ? await diskReader.read() : null;
22761
+ } catch {
22762
+ disk = null;
22763
+ }
22602
22764
  latest = {
22603
22765
  cpuPct,
22604
22766
  ram: {
@@ -22606,6 +22768,7 @@ async function tick2() {
22606
22768
  totalMb: Math.round(os2.totalmem() / 1e6)
22607
22769
  },
22608
22770
  gpus: mergeUsage(getSysInfo(), samples),
22771
+ disk,
22609
22772
  sampledAt: Date.now()
22610
22773
  };
22611
22774
  return latest;
@@ -22629,8 +22792,13 @@ function stopUsageMonitor() {
22629
22792
  reader?.stop();
22630
22793
  } catch {
22631
22794
  }
22795
+ try {
22796
+ diskReader?.stop();
22797
+ } catch {
22798
+ }
22632
22799
  }
22633
22800
  reader = null;
22801
+ diskReader = null;
22634
22802
  latest = null;
22635
22803
  prevCpu = null;
22636
22804
  running = false;
@@ -26564,7 +26732,7 @@ function registerRemoteApi(app2, d) {
26564
26732
  if (!provider || !REMOTE_PROVIDERS.includes(provider)) {
26565
26733
  return c.json({ error: { code: "bad_request", message: "Unknown provider." } }, 400);
26566
26734
  }
26567
- const { makeProvider: makeProvider2 } = await import("./factory-7ITNXXOI.js");
26735
+ const { makeProvider: makeProvider2 } = await import("./factory-NOUUQICH.js");
26568
26736
  const state = await makeProvider2(provider, d).preflight();
26569
26737
  if (d.telemetry && (state.kind === "unavailable" || state.kind === "needs-setup")) {
26570
26738
  emit(d.telemetry, remoteAccessPreflightFailed, {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  makeProvider
4
- } from "./chunk-HOKZAC3U.js";
4
+ } from "./chunk-Y3TMLJQD.js";
5
5
  export {
6
6
  makeProvider
7
7
  };
@@ -1 +1 @@
1
- import{j as e}from"./radix-B7FN0WwE.js";import{b as W,u as $,r as b}from"./vendor-C1I6euDx.js";import{u as G,d as H,e as Y,f as J,g as U,a as z,B as C,t as j,c as q,b as h,A as _}from"./index-DWD1Hz6g.js";import{f as V}from"./chat-api-CCZfNFmH.js";import{f as X,a as Z}from"./agent-api-1EptCITO.js";import{P as B}from"./personas-FTKXYi_z.js";import{C as ee}from"./chevron-left-irxTskG3.js";import{R as te}from"./rotate-ccw-CYnZI5-z.js";import{T as se}from"./trash-2-B4G2scm5.js";import{C as ne}from"./chevron-right-BxDhzUZl.js";import"./dropdown-menu-Be7l1fxe.js";const ae=()=>({name:"",description:"",systemPrompt:"",skillIds:[],tools:[]});function oe(s){const d=[],x=new Map;for(const n of s){const a=/^mcp__([^_]+(?:_[^_]+)*)__/.exec(n.name);if(!a){d.push(n);continue}const i=a[1],p=/^\[([^\]]+)\]/.exec(n.description),c=p?p[1]:i.replace(/_/g," ");x.has(i)||x.set(i,{key:i,label:c,tools:[]}),x.get(i).tools.push(n)}return{builtin:d,groups:[...x.values()].sort((n,a)=>n.label.localeCompare(a.label))}}function le(s){return s.replace(/^mcp__[^_]+(?:_[^_]+)*__/,"")}function re(s){return s.replace(/^\[[^\]]+\]\s*/,"")}function D({tool:s,checked:d,onToggle:x}){return e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-[12px]",children:[e.jsx("input",{type:"checkbox",className:"mt-0.5",checked:d,onChange:x}),e.jsxs("span",{className:"flex flex-col",children:[e.jsx("span",{className:"font-mono text-ink",children:le(s.name)}),s.description&&e.jsx("span",{className:"text-faint",children:re(s.description)})]})]})}function ie({group:s,selected:d,onToggleAll:x,onToggleOne:n}){const[a,i]=b.useState(!1),p=s.tools.map(l=>l.name),c=p.filter(l=>d.has(l)).length,o=c===p.length,g=c>0&&!o,u=b.useRef(null);return b.useEffect(()=>{u.current&&(u.current.indeterminate=g)},[g]),e.jsxs("div",{className:"rounded-md border border-border",children:[e.jsxs("div",{className:"flex items-center gap-2 px-2.5 py-2",children:[e.jsx("input",{ref:u,type:"checkbox",checked:o,onChange:()=>x(p,!o)}),e.jsxs("button",{type:"button",onClick:()=>{j("agents","toggle_agent_tool_group"),i(l=>!l)},className:"flex flex-1 items-center gap-1.5 text-left text-[13px] text-ink",children:[e.jsx(ne,{size:12,className:q("shrink-0 text-faint transition-transform",a&&"rotate-90")}),s.label,e.jsxs("span",{className:"text-[11px] text-faint",children:["(",c,"/",p.length,")"]})]})]}),a&&e.jsx("div",{className:"flex flex-col gap-1.5 border-t border-border px-3 py-2 pl-9",children:s.tools.map(l=>e.jsx(D,{tool:l,checked:d.has(l.name),onToggle:()=>n(l.name)},l.name))})]})}function ce({tools:s,selected:d,onChange:x}){const n=new Set(d),{builtin:a,groups:i}=oe(s),p=o=>x(n.has(o)?d.filter(g=>g!==o):[...d,o]),c=(o,g)=>{const u=d.filter(l=>!o.includes(l));x(g?[...u,...o]:u)};return s.length===0?e.jsx("p",{className:"text-[12px] text-faint",children:"No tools available yet."}):e.jsxs("div",{className:"flex flex-col gap-2",children:[a.length>0&&e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:a.map(o=>e.jsx(D,{tool:o,checked:n.has(o.name),onToggle:()=>p(o.name)},o.name))}),i.map(o=>e.jsx(ie,{group:o,selected:n,onToggleAll:c,onToggleOne:p},o.key))]})}function je(){const{agentId:s="new"}=W(),d=$(),x=G(),n=s==="new",a=!n&&B.some(t=>t.id===s),i=a?B.find(t=>t.id===s):void 0,p=H(),c=!n&&!a?(p.data??[]).find(t=>t.id===s):void 0,o=Y(),g=J(),u=U(),l=a?g.data?.[s]:void 0,I=z({queryKey:Z.list(),queryFn:X,staleTime:0}),k=I.data??[],w=z({queryKey:["available-tools"],queryFn:V}),N=w.data??[],[m,f]=b.useState(ae()),[S,T]=b.useState(!1),[A,P]=b.useState(!1),[L,R]=b.useState(!1),[E,Q]=b.useState("skills");n&&!S&&(k.length||N.length)&&(f(t=>({...t,skillIds:k.map(r=>r.id),tools:N.map(r=>r.name)})),T(!0)),!n&&!a&&!S&&c&&(f({name:c.name,description:c.description,systemPrompt:c.systemPrompt,skillIds:c.skillIds,tools:c.tools}),T(!0)),a&&!S&&i&&g.isSuccess&&(k.length||N.length)&&(f({name:l?.name??i.name,description:l?.description??i.description,systemPrompt:l?.systemPrompt??i.systemPrompt,skillIds:l?.skillIds??k.map(t=>t.id),tools:l?.tools??N.map(t=>t.name)}),T(!0));const y=()=>{j("agents","back_to_agents"),d("/customize")},O=t=>f(r=>({...r,skillIds:r.skillIds.includes(t)?r.skillIds.filter(v=>v!==t):[...r.skillIds,t]})),F=()=>{if(!m.name.trim()){h.error("Name is required.");return}P(!0);const t={name:m.name.trim(),description:m.description.trim(),systemPrompt:m.systemPrompt,skillIds:m.skillIds,tools:m.tools};if(a){u.save.mutate({id:s,override:t},{onSuccess:()=>{h.success("Agent saved."),y()},onError:v=>{h.error(v instanceof _?v.message:"Could not save agent."),P(!1)}});return}const r={onSuccess:()=>{x.invalidateQueries({queryKey:["chat-agents"]}),h.success(n?"Agent created.":"Agent saved."),y()},onError:v=>{h.error(v instanceof _?v.message:"Could not save agent."),P(!1)}};n?o.add.mutate(t,r):o.update.mutate({id:s,patch:t},r)},K=()=>{u.reset.mutate(s,{onSuccess:()=>{h.success("Reset to default."),i&&f({name:i.name,description:i.description,systemPrompt:i.systemPrompt,skillIds:k.map(t=>t.id),tools:N.map(t=>t.name)})},onError:t=>h.error(t instanceof _?t.message:"Could not reset agent.")})},M=()=>{o.remove.mutate(s,{onSuccess:()=>{h.success("Agent deleted."),y()},onError:t=>h.error(t instanceof _?t.message:"Could not delete agent.")})};return!n&&!a&&p.isSuccess&&!c?e.jsxs("div",{className:"flex w-full flex-col items-center gap-3 px-8 py-16",children:[e.jsx("p",{className:"text-[14px] text-muted",children:"That agent no longer exists."}),e.jsx(C,{size:"sm",variant:"outline",onClick:y,children:"Back to agents"})]}):e.jsxs("div",{className:"flex w-full max-w-4xl flex-col gap-5 px-4 py-6 md:px-8",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",onClick:y,className:"text-faint hover:text-ink",title:"Back to agents",children:e.jsx(ee,{size:18})}),e.jsx("span",{className:"text-[15px] font-medium text-ink",children:n?"New agent":a?l?"Edit agent (modified built-in)":"Edit agent (built-in)":"Edit agent"}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[a&&e.jsxs(C,{size:"sm",variant:"outline",onClick:()=>{j("agents","reset_agent_to_default"),K()},disabled:u.reset.isPending,children:[e.jsx(te,{size:13})," Reset to default"]}),e.jsx(C,{size:"sm",variant:"outline",onClick:y,children:"Cancel"}),e.jsx(C,{size:"sm",onClick:()=>{j("agents","save_agent"),F()},disabled:A||!m.name.trim(),children:A?"Saving…":"Save"})]})]}),a&&e.jsx("p",{className:"rounded-md border border-border bg-panel px-3 py-2 text-[12px] text-muted",children:"Built-in agents can be edited in place — Reset to default discards your changes and restores TurboLLM's original prompt and access."}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"Name"}),e.jsx("input",{className:"rounded-md border border-border bg-bg px-3 py-1.5 text-[13px] text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"Release Notes Writer",value:m.name,onChange:t=>f(r=>({...r,name:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"Description"}),e.jsx("input",{className:"rounded-md border border-border bg-bg px-3 py-1.5 text-[13px] text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"What this agent is for, in one line",value:m.description,onChange:t=>f(r=>({...r,description:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"System prompt"}),e.jsx("textarea",{className:"min-h-[160px] resize-y rounded-md border border-border bg-bg px-3 py-2 font-mono text-[12px] leading-relaxed text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"You are…",value:m.systemPrompt,onChange:t=>f(r=>({...r,systemPrompt:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-2.5",children:[e.jsx("div",{className:"inline-flex w-fit rounded-md border border-border p-0.5",children:["skills","tools"].map(t=>e.jsx("button",{type:"button",onClick:()=>{j("agents","switch_agent_form_tab"),Q(t)},className:q("rounded px-3 py-1.5 text-[13px] font-medium transition-colors",E===t?"bg-accent/12 text-accent":"text-muted hover:text-ink"),children:t==="skills"?`Skills (${m.skillIds.length})`:`Tools (${m.tools.length})`},t))}),E==="skills"?I.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):k.length===0?e.jsx("p",{className:"text-[12px] text-faint",children:"No skills yet — create one under Customize → Skills."}):e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:k.map(t=>e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-[13px]",children:[e.jsx("input",{type:"checkbox",className:"mt-0.5",checked:m.skillIds.includes(t.id),onChange:()=>O(t.id)}),e.jsxs("span",{className:"flex flex-col",children:[e.jsx("span",{className:"text-ink",children:t.name}),t.description&&e.jsx("span",{className:"text-[12px] text-muted",children:t.description})]})]},t.id))}):w.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):e.jsx(ce,{tools:N,selected:m.tools,onChange:t=>f(r=>({...r,tools:t}))})]}),!n&&!a&&(L?e.jsxs("div",{className:"flex items-center gap-2 self-start rounded-md border border-border bg-panel p-2 text-[12px]",children:[e.jsx("span",{className:"flex-1 text-muted",children:"Delete this agent?"}),e.jsx("button",{type:"button",onClick:()=>{j("agents","delete_agent"),M()},className:"rounded px-2 py-1 text-[color:var(--err)] hover:bg-[color:color-mix(in_srgb,var(--err)_12%,transparent)]",children:"Delete"}),e.jsx("button",{type:"button",onClick:()=>{j("agents","cancel_delete_agent"),R(!1)},className:"rounded px-2 py-1 text-faint hover:text-ink",children:"Cancel"})]}):e.jsxs("button",{type:"button",onClick:()=>R(!0),className:"flex items-center gap-1.5 self-start text-[12px] text-faint hover:text-[color:var(--err)]",children:[e.jsx(se,{size:13})," Delete agent"]}))]})}export{je as AgentEditPage};
1
+ import{j as e}from"./radix-B7FN0WwE.js";import{b as W,u as $,r as b}from"./vendor-C1I6euDx.js";import{u as G,d as H,e as Y,f as J,g as U,a as z,B as C,t as j,c as q,b as h,A as _}from"./index-CfwXVQIu.js";import{f as V}from"./chat-api-BspgdIew.js";import{f as X,a as Z}from"./agent-api-CeGvce9t.js";import{P as B}from"./personas-FTKXYi_z.js";import{C as ee}from"./chevron-left-yPpon0Zo.js";import{R as te}from"./rotate-ccw-DmG7PkUG.js";import{T as se}from"./trash-2-WYWL4BUK.js";import{C as ne}from"./chevron-right-qwzlPkv4.js";import"./dropdown-menu-HI5N3Rmt.js";const ae=()=>({name:"",description:"",systemPrompt:"",skillIds:[],tools:[]});function oe(s){const d=[],x=new Map;for(const n of s){const a=/^mcp__([^_]+(?:_[^_]+)*)__/.exec(n.name);if(!a){d.push(n);continue}const i=a[1],p=/^\[([^\]]+)\]/.exec(n.description),c=p?p[1]:i.replace(/_/g," ");x.has(i)||x.set(i,{key:i,label:c,tools:[]}),x.get(i).tools.push(n)}return{builtin:d,groups:[...x.values()].sort((n,a)=>n.label.localeCompare(a.label))}}function le(s){return s.replace(/^mcp__[^_]+(?:_[^_]+)*__/,"")}function re(s){return s.replace(/^\[[^\]]+\]\s*/,"")}function D({tool:s,checked:d,onToggle:x}){return e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-[12px]",children:[e.jsx("input",{type:"checkbox",className:"mt-0.5",checked:d,onChange:x}),e.jsxs("span",{className:"flex flex-col",children:[e.jsx("span",{className:"font-mono text-ink",children:le(s.name)}),s.description&&e.jsx("span",{className:"text-faint",children:re(s.description)})]})]})}function ie({group:s,selected:d,onToggleAll:x,onToggleOne:n}){const[a,i]=b.useState(!1),p=s.tools.map(l=>l.name),c=p.filter(l=>d.has(l)).length,o=c===p.length,g=c>0&&!o,u=b.useRef(null);return b.useEffect(()=>{u.current&&(u.current.indeterminate=g)},[g]),e.jsxs("div",{className:"rounded-md border border-border",children:[e.jsxs("div",{className:"flex items-center gap-2 px-2.5 py-2",children:[e.jsx("input",{ref:u,type:"checkbox",checked:o,onChange:()=>x(p,!o)}),e.jsxs("button",{type:"button",onClick:()=>{j("agents","toggle_agent_tool_group"),i(l=>!l)},className:"flex flex-1 items-center gap-1.5 text-left text-[13px] text-ink",children:[e.jsx(ne,{size:12,className:q("shrink-0 text-faint transition-transform",a&&"rotate-90")}),s.label,e.jsxs("span",{className:"text-[11px] text-faint",children:["(",c,"/",p.length,")"]})]})]}),a&&e.jsx("div",{className:"flex flex-col gap-1.5 border-t border-border px-3 py-2 pl-9",children:s.tools.map(l=>e.jsx(D,{tool:l,checked:d.has(l.name),onToggle:()=>n(l.name)},l.name))})]})}function ce({tools:s,selected:d,onChange:x}){const n=new Set(d),{builtin:a,groups:i}=oe(s),p=o=>x(n.has(o)?d.filter(g=>g!==o):[...d,o]),c=(o,g)=>{const u=d.filter(l=>!o.includes(l));x(g?[...u,...o]:u)};return s.length===0?e.jsx("p",{className:"text-[12px] text-faint",children:"No tools available yet."}):e.jsxs("div",{className:"flex flex-col gap-2",children:[a.length>0&&e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:a.map(o=>e.jsx(D,{tool:o,checked:n.has(o.name),onToggle:()=>p(o.name)},o.name))}),i.map(o=>e.jsx(ie,{group:o,selected:n,onToggleAll:c,onToggleOne:p},o.key))]})}function je(){const{agentId:s="new"}=W(),d=$(),x=G(),n=s==="new",a=!n&&B.some(t=>t.id===s),i=a?B.find(t=>t.id===s):void 0,p=H(),c=!n&&!a?(p.data??[]).find(t=>t.id===s):void 0,o=Y(),g=J(),u=U(),l=a?g.data?.[s]:void 0,I=z({queryKey:Z.list(),queryFn:X,staleTime:0}),k=I.data??[],w=z({queryKey:["available-tools"],queryFn:V}),N=w.data??[],[m,f]=b.useState(ae()),[S,T]=b.useState(!1),[A,P]=b.useState(!1),[L,R]=b.useState(!1),[E,Q]=b.useState("skills");n&&!S&&(k.length||N.length)&&(f(t=>({...t,skillIds:k.map(r=>r.id),tools:N.map(r=>r.name)})),T(!0)),!n&&!a&&!S&&c&&(f({name:c.name,description:c.description,systemPrompt:c.systemPrompt,skillIds:c.skillIds,tools:c.tools}),T(!0)),a&&!S&&i&&g.isSuccess&&(k.length||N.length)&&(f({name:l?.name??i.name,description:l?.description??i.description,systemPrompt:l?.systemPrompt??i.systemPrompt,skillIds:l?.skillIds??k.map(t=>t.id),tools:l?.tools??N.map(t=>t.name)}),T(!0));const y=()=>{j("agents","back_to_agents"),d("/customize")},O=t=>f(r=>({...r,skillIds:r.skillIds.includes(t)?r.skillIds.filter(v=>v!==t):[...r.skillIds,t]})),F=()=>{if(!m.name.trim()){h.error("Name is required.");return}P(!0);const t={name:m.name.trim(),description:m.description.trim(),systemPrompt:m.systemPrompt,skillIds:m.skillIds,tools:m.tools};if(a){u.save.mutate({id:s,override:t},{onSuccess:()=>{h.success("Agent saved."),y()},onError:v=>{h.error(v instanceof _?v.message:"Could not save agent."),P(!1)}});return}const r={onSuccess:()=>{x.invalidateQueries({queryKey:["chat-agents"]}),h.success(n?"Agent created.":"Agent saved."),y()},onError:v=>{h.error(v instanceof _?v.message:"Could not save agent."),P(!1)}};n?o.add.mutate(t,r):o.update.mutate({id:s,patch:t},r)},K=()=>{u.reset.mutate(s,{onSuccess:()=>{h.success("Reset to default."),i&&f({name:i.name,description:i.description,systemPrompt:i.systemPrompt,skillIds:k.map(t=>t.id),tools:N.map(t=>t.name)})},onError:t=>h.error(t instanceof _?t.message:"Could not reset agent.")})},M=()=>{o.remove.mutate(s,{onSuccess:()=>{h.success("Agent deleted."),y()},onError:t=>h.error(t instanceof _?t.message:"Could not delete agent.")})};return!n&&!a&&p.isSuccess&&!c?e.jsxs("div",{className:"flex w-full flex-col items-center gap-3 px-8 py-16",children:[e.jsx("p",{className:"text-[14px] text-muted",children:"That agent no longer exists."}),e.jsx(C,{size:"sm",variant:"outline",onClick:y,children:"Back to agents"})]}):e.jsxs("div",{className:"flex w-full max-w-4xl flex-col gap-5 px-4 py-6 md:px-8",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",onClick:y,className:"text-faint hover:text-ink",title:"Back to agents",children:e.jsx(ee,{size:18})}),e.jsx("span",{className:"text-[15px] font-medium text-ink",children:n?"New agent":a?l?"Edit agent (modified built-in)":"Edit agent (built-in)":"Edit agent"}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[a&&e.jsxs(C,{size:"sm",variant:"outline",onClick:()=>{j("agents","reset_agent_to_default"),K()},disabled:u.reset.isPending,children:[e.jsx(te,{size:13})," Reset to default"]}),e.jsx(C,{size:"sm",variant:"outline",onClick:y,children:"Cancel"}),e.jsx(C,{size:"sm",onClick:()=>{j("agents","save_agent"),F()},disabled:A||!m.name.trim(),children:A?"Saving…":"Save"})]})]}),a&&e.jsx("p",{className:"rounded-md border border-border bg-panel px-3 py-2 text-[12px] text-muted",children:"Built-in agents can be edited in place — Reset to default discards your changes and restores TurboLLM's original prompt and access."}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"Name"}),e.jsx("input",{className:"rounded-md border border-border bg-bg px-3 py-1.5 text-[13px] text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"Release Notes Writer",value:m.name,onChange:t=>f(r=>({...r,name:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"Description"}),e.jsx("input",{className:"rounded-md border border-border bg-bg px-3 py-1.5 text-[13px] text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"What this agent is for, in one line",value:m.description,onChange:t=>f(r=>({...r,description:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"System prompt"}),e.jsx("textarea",{className:"min-h-[160px] resize-y rounded-md border border-border bg-bg px-3 py-2 font-mono text-[12px] leading-relaxed text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"You are…",value:m.systemPrompt,onChange:t=>f(r=>({...r,systemPrompt:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-2.5",children:[e.jsx("div",{className:"inline-flex w-fit rounded-md border border-border p-0.5",children:["skills","tools"].map(t=>e.jsx("button",{type:"button",onClick:()=>{j("agents","switch_agent_form_tab"),Q(t)},className:q("rounded px-3 py-1.5 text-[13px] font-medium transition-colors",E===t?"bg-accent/12 text-accent":"text-muted hover:text-ink"),children:t==="skills"?`Skills (${m.skillIds.length})`:`Tools (${m.tools.length})`},t))}),E==="skills"?I.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):k.length===0?e.jsx("p",{className:"text-[12px] text-faint",children:"No skills yet — create one under Customize → Skills."}):e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:k.map(t=>e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-[13px]",children:[e.jsx("input",{type:"checkbox",className:"mt-0.5",checked:m.skillIds.includes(t.id),onChange:()=>O(t.id)}),e.jsxs("span",{className:"flex flex-col",children:[e.jsx("span",{className:"text-ink",children:t.name}),t.description&&e.jsx("span",{className:"text-[12px] text-muted",children:t.description})]})]},t.id))}):w.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):e.jsx(ce,{tools:N,selected:m.tools,onChange:t=>f(r=>({...r,tools:t}))})]}),!n&&!a&&(L?e.jsxs("div",{className:"flex items-center gap-2 self-start rounded-md border border-border bg-panel p-2 text-[12px]",children:[e.jsx("span",{className:"flex-1 text-muted",children:"Delete this agent?"}),e.jsx("button",{type:"button",onClick:()=>{j("agents","delete_agent"),M()},className:"rounded px-2 py-1 text-[color:var(--err)] hover:bg-[color:color-mix(in_srgb,var(--err)_12%,transparent)]",children:"Delete"}),e.jsx("button",{type:"button",onClick:()=>{j("agents","cancel_delete_agent"),R(!1)},className:"rounded px-2 py-1 text-faint hover:text-ink",children:"Cancel"})]}):e.jsxs("button",{type:"button",onClick:()=>R(!0),className:"flex items-center gap-1.5 self-start text-[12px] text-faint hover:text-[color:var(--err)]",children:[e.jsx(se,{size:13})," Delete agent"]}))]})}export{je as AgentEditPage};