turbollm 1.8.5 → 1.8.6

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 (101) hide show
  1. package/dist/cli.js +105 -17
  2. package/dist/webdist/assets/{AgentEditPage-VoVmMCf1.js → AgentEditPage-BaaqMpWR.js} +1 -1
  3. package/dist/webdist/assets/{ChatScreen-DHGEKPZr.js → ChatScreen-C2DYwxeR.js} +1 -1
  4. package/dist/webdist/assets/{CodeComposer-Cxhvsus4.js → CodeComposer-BBE_Hp0Q.js} +1 -1
  5. package/dist/webdist/assets/{CodeHomeScreen-BHIrDU_t.js → CodeHomeScreen-B_rbjGaw.js} +1 -1
  6. package/dist/webdist/assets/{CodeSessionScreen-CqogdVEN.js → CodeSessionScreen-DJJY5EKZ.js} +1 -1
  7. package/dist/webdist/assets/{CustomizeScreen-B4XGEyxA.js → CustomizeScreen-ClXS3xOu.js} +1 -1
  8. package/dist/webdist/assets/{DeveloperScreen-jGamwaJG.js → DeveloperScreen-X2uqzXVK.js} +1 -1
  9. package/dist/webdist/assets/EnginesScreen-jM6G9Lnt.js +7 -0
  10. package/dist/webdist/assets/{FsBrowser-5VN4Yj8z.js → FsBrowser-CWzT3VbL.js} +1 -1
  11. package/dist/webdist/assets/{ModelLoadMenu-CgM5a39X.js → ModelLoadMenu-UGUkfjbF.js} +1 -1
  12. package/dist/webdist/assets/{ModelsScreen-GUtj_sux.js → ModelsScreen-D0-Onb6V.js} +1 -1
  13. package/dist/webdist/assets/{SettingsScreen-D65xd3_e.js → SettingsScreen-C-k9Yc55.js} +1 -1
  14. package/dist/webdist/assets/{SkillEditPage-CkKqavr8.js → SkillEditPage-DVIYJU7N.js} +1 -1
  15. package/dist/webdist/assets/{TokensScreen-CCS_y7DZ.js → TokensScreen-DC4sSZK8.js} +1 -1
  16. package/dist/webdist/assets/{ToolApprovalBar-CRZPKrcR.js → ToolApprovalBar-BYyXPiNP.js} +3 -3
  17. package/dist/webdist/assets/WorkspaceScreen-DJr_KuyC.js +1 -0
  18. package/dist/webdist/assets/{agent-api-BZQuCIAd.js → agent-api-DBuqrdZq.js} +1 -1
  19. package/dist/webdist/assets/{arc-CG_F6y0n.js → arc-Banj5wBf.js} +1 -1
  20. package/dist/webdist/assets/{architectureDiagram-3BPJPVTR-bK0viBCO.js → architectureDiagram-3BPJPVTR-D-VtkgYv.js} +1 -1
  21. package/dist/webdist/assets/{arrow-left-Cxqlqe4Q.js → arrow-left-C1r8Dr2d.js} +1 -1
  22. package/dist/webdist/assets/{badge-D1brk9rd.js → badge-DMOKG62I.js} +1 -1
  23. package/dist/webdist/assets/{blockDiagram-GPEHLZMM-DqMi7LYs.js → blockDiagram-GPEHLZMM-nvbn1Awx.js} +1 -1
  24. package/dist/webdist/assets/{bot-CldCBtRY.js → bot-CTxax61P.js} +1 -1
  25. package/dist/webdist/assets/{c4Diagram-AAUBKEIU-D5JOtr9l.js → c4Diagram-AAUBKEIU-DoG1JXd6.js} +1 -1
  26. package/dist/webdist/assets/channel-g0-qHfup.js +1 -0
  27. package/dist/webdist/assets/{chat-api-uAJNrEFg.js → chat-api-B81lfnq0.js} +1 -1
  28. package/dist/webdist/assets/{chat-queries-OevUA_jH.js → chat-queries-BcaqUVgR.js} +1 -1
  29. package/dist/webdist/assets/check-BQ18Nt2_.js +1 -0
  30. package/dist/webdist/assets/{chevron-left-Dv-zay0l.js → chevron-left-BdgNx91c.js} +1 -1
  31. package/dist/webdist/assets/{chevron-right-DvvJS6ye.js → chevron-right-BXxjw90s.js} +1 -1
  32. package/dist/webdist/assets/{chunk-2J33WTMH-D5FvNAKn.js → chunk-2J33WTMH-CI01KUY5.js} +1 -1
  33. package/dist/webdist/assets/{chunk-4BX2VUAB-PiXdGtQT.js → chunk-4BX2VUAB-CT4Q6KgA.js} +1 -1
  34. package/dist/webdist/assets/{chunk-55IACEB6-BcFnIoE2.js → chunk-55IACEB6-DVqUTluK.js} +1 -1
  35. package/dist/webdist/assets/{chunk-727SXJPM-BigbNnpE.js → chunk-727SXJPM-2pMnnV6j.js} +1 -1
  36. package/dist/webdist/assets/{chunk-AQP2D5EJ-ksTbyzzH.js → chunk-AQP2D5EJ-q_bI8ZG1.js} +1 -1
  37. package/dist/webdist/assets/{chunk-FMBD7UC4-DpDAzpmq.js → chunk-FMBD7UC4-B8gQv0l1.js} +1 -1
  38. package/dist/webdist/assets/{chunk-ND2GUHAM-Ch7eIfE0.js → chunk-ND2GUHAM-DJx_4zvu.js} +1 -1
  39. package/dist/webdist/assets/{chunk-QZHKN3VN-DMDG8lEf.js → chunk-QZHKN3VN-CrAA0uxl.js} +1 -1
  40. package/dist/webdist/assets/{circle-check-BFtGWNjh.js → circle-check-CzXTbeIt.js} +1 -1
  41. package/dist/webdist/assets/{circle-x-BmwEPZU0.js → circle-x-CfrulclP.js} +1 -1
  42. package/dist/webdist/assets/classDiagram-4FO5ZUOK-B09K5xH-.js +1 -0
  43. package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-B09K5xH-.js +1 -0
  44. package/dist/webdist/assets/{common-BEcCBxuG.js → common-DAcb-w9o.js} +1 -1
  45. package/dist/webdist/assets/{copy-button-B3sedfsF.js → copy-button-CE2-6pHL.js} +1 -1
  46. package/dist/webdist/assets/{cose-bilkent-S5V4N54A-BBGTUfOp.js → cose-bilkent-S5V4N54A-EGQLoy7D.js} +1 -1
  47. package/dist/webdist/assets/{dagre-BM42HDAG-D8W6jcq_.js → dagre-BM42HDAG-DC_RQ1B0.js} +1 -1
  48. package/dist/webdist/assets/{diagram-2AECGRRQ-CvCrWf_H.js → diagram-2AECGRRQ-cZcCJYfi.js} +1 -1
  49. package/dist/webdist/assets/{diagram-5GNKFQAL-DZS4yZU1.js → diagram-5GNKFQAL-Cb-jxgLV.js} +1 -1
  50. package/dist/webdist/assets/{diagram-KO2AKTUF-BlKSql5d.js → diagram-KO2AKTUF-D4INKoTb.js} +1 -1
  51. package/dist/webdist/assets/{diagram-LMA3HP47-CKo-tRYQ.js → diagram-LMA3HP47-CZBo_NP5.js} +1 -1
  52. package/dist/webdist/assets/{diagram-OG6HWLK6-NSePJGx1.js → diagram-OG6HWLK6-Dmb2yOZ2.js} +1 -1
  53. package/dist/webdist/assets/{dialog-B-GLhgc2.js → dialog-BKdq0aeC.js} +1 -1
  54. package/dist/webdist/assets/{erDiagram-TEJ5UH35-haPVT0D3.js → erDiagram-TEJ5UH35-_ekw2dYE.js} +1 -1
  55. package/dist/webdist/assets/{external-link-UbaLGQ_h.js → external-link-DJyx1xu4.js} +1 -1
  56. package/dist/webdist/assets/{flowDiagram-I6XJVG4X-BzKZFBHV.js → flowDiagram-I6XJVG4X-BKFCSX9M.js} +1 -1
  57. package/dist/webdist/assets/{ganttDiagram-6RSMTGT7-CCmAecLV.js → ganttDiagram-6RSMTGT7-Bun-N5iU.js} +1 -1
  58. package/dist/webdist/assets/{git-branch-Bj6Xfs8n.js → git-branch-DWvtYq2n.js} +1 -1
  59. package/dist/webdist/assets/{gitGraphDiagram-PVQCEYII-OD-Aumfw.js → gitGraphDiagram-PVQCEYII-DP97jy0N.js} +1 -1
  60. package/dist/webdist/assets/{index-D4oBHgyO.js → index-v0Tdes8H.js} +2 -2
  61. package/dist/webdist/assets/{infoDiagram-5YYISTIA-CXiblcgy.js → infoDiagram-5YYISTIA-XNpJszfx.js} +1 -1
  62. package/dist/webdist/assets/{ishikawaDiagram-YF4QCWOH-C8sCKBhs.js → ishikawaDiagram-YF4QCWOH-Ct7Jx-R0.js} +1 -1
  63. package/dist/webdist/assets/{journeyDiagram-JHISSGLW-B3be8ACK.js → journeyDiagram-JHISSGLW-CyHwpNbR.js} +1 -1
  64. package/dist/webdist/assets/{kanban-definition-UN3LZRKU-BbfHizAI.js → kanban-definition-UN3LZRKU-BlIiwFL_.js} +1 -1
  65. package/dist/webdist/assets/{layers-BqbkDoHi.js → layers-C5s0VHiR.js} +1 -1
  66. package/dist/webdist/assets/{linear-C0lkBXID.js → linear-BHBdNjY-.js} +1 -1
  67. package/dist/webdist/assets/{mermaid.core-CW2TnRwR.js → mermaid.core-DJ7y5RnJ.js} +4 -4
  68. package/dist/webdist/assets/{mindmap-definition-RKZ34NQL-h-ro0B1A.js → mindmap-definition-RKZ34NQL-hhkBvUUD.js} +1 -1
  69. package/dist/webdist/assets/{pencil-BJsQ5uv5.js → pencil-CJGwma8c.js} +1 -1
  70. package/dist/webdist/assets/{pieDiagram-4H26LBE5-DEGupnzV.js → pieDiagram-4H26LBE5-TIZ5Ty6J.js} +1 -1
  71. package/dist/webdist/assets/{plus-BESpOgWu.js → plus-88_2XyV5.js} +1 -1
  72. package/dist/webdist/assets/{quadrantDiagram-W4KKPZXB-CMkivigQ.js → quadrantDiagram-W4KKPZXB-DYHxb7at.js} +1 -1
  73. package/dist/webdist/assets/{refresh-cw-CuuCQSpX.js → refresh-cw-MdqFeESZ.js} +1 -1
  74. package/dist/webdist/assets/{requirementDiagram-4Y6WPE33-DyChhWBw.js → requirementDiagram-4Y6WPE33-qnClMgKa.js} +1 -1
  75. package/dist/webdist/assets/{rotate-ccw-D99lmEA-.js → rotate-ccw-c1dWBxKq.js} +1 -1
  76. package/dist/webdist/assets/{sankeyDiagram-5OEKKPKP-BDPQ7Ai5.js → sankeyDiagram-5OEKKPKP-BG_kgFTc.js} +1 -1
  77. package/dist/webdist/assets/{sequenceDiagram-3UESZ5HK-C_jdr66e.js → sequenceDiagram-3UESZ5HK-D6qrIrDg.js} +1 -1
  78. package/dist/webdist/assets/{skeleton-nGnGDZ2Z.js → skeleton-Br4uEDd5.js} +1 -1
  79. package/dist/webdist/assets/{sliders-horizontal-BXU5PC3A.js → sliders-horizontal-Cy_WWOJ2.js} +1 -1
  80. package/dist/webdist/assets/{star-BGgeiEjL.js → star-C-2hCQLL.js} +1 -1
  81. package/dist/webdist/assets/{stateDiagram-AJRCARHV-CwtPbKxE.js → stateDiagram-AJRCARHV-BHad4Ojy.js} +1 -1
  82. package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-BDM3H2wn.js +1 -0
  83. package/dist/webdist/assets/{switch-BQT_NipX.js → switch-CMtwRt96.js} +1 -1
  84. package/dist/webdist/assets/{terminal-CrCLNyjB.js → terminal-BtT1uKGg.js} +1 -1
  85. package/dist/webdist/assets/{timeline-definition-PNZ67QCA-B1bN1YFW.js → timeline-definition-PNZ67QCA-B4rUcQHc.js} +1 -1
  86. package/dist/webdist/assets/{trash-2-CuUIi8kE.js → trash-2-Pyx2qefh.js} +1 -1
  87. package/dist/webdist/assets/{useIsDesktop-BwBLPtTS.js → useIsDesktop-Cm4AYq5A.js} +1 -1
  88. package/dist/webdist/assets/{vennDiagram-CIIHVFJN-B23LrfT3.js → vennDiagram-CIIHVFJN-Xc9rC-NG.js} +1 -1
  89. package/dist/webdist/assets/{wardley-L42UT6IY-Bkk_DpTu.js → wardley-L42UT6IY-lxhSG_a5.js} +1 -1
  90. package/dist/webdist/assets/{wardleyDiagram-YWT4CUSO-Di9GYhE4.js → wardleyDiagram-YWT4CUSO-cPWAssfx.js} +1 -1
  91. package/dist/webdist/assets/{wrench-CUU3qZM0.js → wrench-A33IdAiw.js} +1 -1
  92. package/dist/webdist/assets/{xychartDiagram-2RQKCTM6-BF1BnBYj.js → xychartDiagram-2RQKCTM6-CKEYbcW3.js} +1 -1
  93. package/dist/webdist/index.html +1 -1
  94. package/package.json +1 -1
  95. package/dist/webdist/assets/EnginesScreen-BRkOTacr.js +0 -7
  96. package/dist/webdist/assets/WorkspaceScreen-D060hDIn.js +0 -1
  97. package/dist/webdist/assets/channel-C-X5wnqi.js +0 -1
  98. package/dist/webdist/assets/check-r_BeDgvE.js +0 -1
  99. package/dist/webdist/assets/classDiagram-4FO5ZUOK-Dw2O5mDo.js +0 -1
  100. package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-Dw2O5mDo.js +0 -1
  101. package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-DlCLpW5_.js +0 -1
package/dist/cli.js CHANGED
@@ -2310,6 +2310,7 @@ function trimLen(s, n) {
2310
2310
 
2311
2311
  // src/engines/build-runner.ts
2312
2312
  import { execFile as execFile9, spawn as spawn2 } from "child_process";
2313
+ import { createHash as createHash2 } from "crypto";
2313
2314
  import { copyFileSync, existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync3, readdirSync as readdirSync4, rmSync as rmSync6, writeFileSync as writeFileSync4 } from "fs";
2314
2315
  import { delimiter as delimiter2, dirname as dirname5, join as join12 } from "path";
2315
2316
  import { promisify as promisify7 } from "util";
@@ -2533,8 +2534,8 @@ function sameRepo(a, b) {
2533
2534
  function normRepoUrl(s) {
2534
2535
  return (s ?? "").trim().toLowerCase().replace(/^https?:\/\//, "").replace(/^github\.com\//, "").replace(/\.git$/, "").replace(/\/+$/, "");
2535
2536
  }
2536
- function sourceBuildBinary(enginesRoot, repoUrl, branch) {
2537
- const root = join12(enginesRoot, "build", buildDirName(repoUrl, branch));
2537
+ function sourceBuildBinary(enginesRoot, repoUrl, branch, commit) {
2538
+ const root = join12(enginesRoot, "build", buildDirName(repoUrl, branch, commit));
2538
2539
  return resolveServerBinary(join12(root, "build")) ?? resolveServerBinary(root);
2539
2540
  }
2540
2541
  function sourceBuildDirOf(binPath, enginesRoot) {
@@ -2553,6 +2554,20 @@ function notCmakeProjectError(hasCMakeLists) {
2553
2554
  if (hasCMakeLists) return null;
2554
2555
  return "This repository doesn't look like a llama.cpp-based (CMake) project \u2014 no CMakeLists.txt was found at its root. 1-click build currently only supports llama.cpp-family engines built with CMake. If this project exposes a llama-server-compatible binary some other way, add it as a custom engine by pointing TurboLLM directly at that binary instead of building from source.";
2555
2556
  }
2557
+ function missingPatchShaError(patchUrl, patchSha256) {
2558
+ if (!(patchUrl ?? "").trim()) return null;
2559
+ if ((patchSha256 ?? "").trim()) return null;
2560
+ return "Refusing to apply a build patch with no pinned SHA-256 checksum \u2014 a patch may only be applied when its exact downloaded bytes can be verified against a known hash.";
2561
+ }
2562
+ function sha256Hex(bytes) {
2563
+ return createHash2("sha256").update(bytes).digest("hex");
2564
+ }
2565
+ function patchChecksumMismatchError(expectedSha256, actualSha256) {
2566
+ const want = expectedSha256.trim().toLowerCase();
2567
+ const got = actualSha256.trim().toLowerCase();
2568
+ if (want === got) return null;
2569
+ return `The downloaded patch did not match its pinned SHA-256 checksum (expected ${want}, got ${got}). TurboLLM refused to apply an unverified patch \u2014 the remote file may have changed or been tampered with. The build was stopped before any patch was applied.`;
2570
+ }
2556
2571
  function vcvarsBatch(vcvars, cmakeArgs) {
2557
2572
  const quoted = cmakeArgs.map((a) => /[\s"]/.test(a) ? `"${a}"` : a).join(" ");
2558
2573
  return [
@@ -2830,17 +2845,44 @@ async function runBuild(req, hooks, signal) {
2830
2845
  if (pinnedCommit) {
2831
2846
  mkdirSync7(srcDir, { recursive: true });
2832
2847
  await runStep("git", ["init"], { cwd: srcDir, env, signal, onLine: hooks.log });
2848
+ if (isWindows) await runStep("git", ["config", "core.longpaths", "true"], { cwd: srcDir, env, signal, onLine: hooks.log });
2833
2849
  await runStep("git", ["remote", "add", "origin", req.repoUrl], { cwd: srcDir, env, signal, onLine: hooks.log });
2834
2850
  await runStep("git", ["fetch", "--depth", "1", "origin", pinnedCommit], { cwd: srcDir, env, signal, onLine: hooks.log });
2835
2851
  await runStep("git", ["checkout", "FETCH_HEAD"], { cwd: srcDir, env, signal, onLine: hooks.log });
2836
2852
  } else {
2837
- const cloneArgs = ["clone", "--depth", "1"];
2853
+ const cloneArgs = isWindows ? ["-c", "core.longpaths=true", "clone", "--depth", "1"] : ["clone", "--depth", "1"];
2838
2854
  if ((req.branch ?? "").trim()) cloneArgs.push("--branch", req.branch.trim());
2839
2855
  cloneArgs.push(req.repoUrl, srcDir);
2840
2856
  await runStep("git", cloneArgs, { env, signal, onLine: hooks.log });
2841
2857
  }
2842
2858
  const commit = (await runStep("git", ["-C", srcDir, "rev-parse", "HEAD"], { env, signal, onLine: () => {
2843
2859
  } })).trim();
2860
+ const patchUrl = (req.patchUrl ?? "").trim();
2861
+ if (patchUrl) {
2862
+ const expectedSha = (req.patchSha256 ?? "").trim();
2863
+ const guard = missingPatchShaError(patchUrl, expectedSha);
2864
+ if (guard) throw new Error(guard);
2865
+ hooks.log(`Downloading build patch from ${patchUrl} \u2026`);
2866
+ const res = await fetch(patchUrl, { signal });
2867
+ if (!res.ok) throw new Error(`Failed to download the build patch (HTTP ${res.status} ${res.statusText}) from ${patchUrl}.`);
2868
+ const patchBytes = Buffer.from(await res.arrayBuffer());
2869
+ const actualSha = sha256Hex(patchBytes);
2870
+ const mismatch = patchChecksumMismatchError(expectedSha, actualSha);
2871
+ if (mismatch) throw new Error(mismatch);
2872
+ const patchFile = join12(buildRoot, "_tllm_patch.diff");
2873
+ writeFileSync4(patchFile, patchBytes);
2874
+ hooks.log(`Patch verified against its pinned checksum (sha256 ${actualSha.slice(0, 12)}\u2026).`);
2875
+ try {
2876
+ await runStep("git", ["-C", srcDir, "apply", "--check", patchFile], { env, signal, onLine: hooks.log });
2877
+ } catch (e) {
2878
+ if (e?.name === "AbortError") throw e;
2879
+ throw new Error(
2880
+ "The verified patch failed to apply against the checked-out commit (most likely it has drifted from the commit it was authored against, but see the underlying error below for the exact cause). " + (e instanceof Error ? e.message : String(e))
2881
+ );
2882
+ }
2883
+ await runStep("git", ["-C", srcDir, "apply", patchFile], { env, signal, onLine: hooks.log });
2884
+ hooks.log(`Applied verified patch (sha256 ${actualSha.slice(0, 12)}\u2026) on top of ${commit.slice(0, 8)}.`);
2885
+ }
2844
2886
  const notCmake = notCmakeProjectError(existsSync13(join12(srcDir, "CMakeLists.txt")));
2845
2887
  if (notCmake) throw new Error(notCmake);
2846
2888
  neutralizeGratuitousAsm(srcDir, hooks.log);
@@ -2931,6 +2973,7 @@ var Registry = class {
2931
2973
  const sourceRepo = source?.sourceRepo?.trim() || void 0;
2932
2974
  const sourceBranch = source?.sourceBranch?.trim() || void 0;
2933
2975
  const sourceCommit = source?.sourceCommit?.trim() || void 0;
2976
+ const sourcePatchUrl = source?.sourcePatchUrl?.trim() || void 0;
2934
2977
  const eng = {
2935
2978
  id: randomUUID2(),
2936
2979
  name: finalName,
@@ -2941,7 +2984,8 @@ var Registry = class {
2941
2984
  addedAt: (/* @__PURE__ */ new Date()).toISOString(),
2942
2985
  ...sourceRepo ? { sourceRepo } : {},
2943
2986
  ...sourceBranch ? { sourceBranch } : {},
2944
- ...sourceCommit ? { sourceCommit } : {}
2987
+ ...sourceCommit ? { sourceCommit } : {},
2988
+ ...sourcePatchUrl ? { sourcePatchUrl } : {}
2945
2989
  };
2946
2990
  this.store.update((c) => {
2947
2991
  if (this.nameClash(c.engines, finalName)) throw new NameTakenError();
@@ -4695,7 +4739,7 @@ function seedDefaultModelDir(store2, scanner2) {
4695
4739
  }
4696
4740
 
4697
4741
  // src/models/hashes.ts
4698
- import { createHash as createHash2 } from "crypto";
4742
+ import { createHash as createHash3 } from "crypto";
4699
4743
  import { createReadStream, mkdirSync as mkdirSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "fs";
4700
4744
  import { join as join16 } from "path";
4701
4745
  var HashStore = class {
@@ -4722,7 +4766,7 @@ var HashStore = class {
4722
4766
  }
4723
4767
  compute(path, size, mtime) {
4724
4768
  return new Promise((resolve5) => {
4725
- const hash = createHash2("sha256");
4769
+ const hash = createHash3("sha256");
4726
4770
  const rs = createReadStream(path);
4727
4771
  rs.on("error", () => resolve5());
4728
4772
  rs.on("data", (c) => hash.update(c));
@@ -6640,7 +6684,7 @@ function dirOf(p) {
6640
6684
  }
6641
6685
 
6642
6686
  // src/downloads/downloads.ts
6643
- import { createHash as createHash3 } from "crypto";
6687
+ import { createHash as createHash4 } from "crypto";
6644
6688
  import {
6645
6689
  createWriteStream as createWriteStream3,
6646
6690
  existsSync as existsSync17,
@@ -6920,7 +6964,7 @@ var DownloadManager = class {
6920
6964
  const clen = Number(res.headers.get("content-length") ?? 0);
6921
6965
  if (clen > 0) rec.total = resuming ? startAt + clen : clen;
6922
6966
  if (clen > 0) this.assertDisk(dirname7(part), clen);
6923
- const hash = rec.sha256 ? createHash3("sha256") : null;
6967
+ const hash = rec.sha256 ? createHash4("sha256") : null;
6924
6968
  const verifyHash = hash !== null && startAt === 0;
6925
6969
  let lastTick = Date.now();
6926
6970
  let lastBytes = startAt;
@@ -12386,11 +12430,11 @@ async function autoTitleFromConversation(d, convId) {
12386
12430
  }
12387
12431
 
12388
12432
  // src/auth.ts
12389
- import { createHash as createHash4, randomBytes, randomUUID as randomUUID6 } from "crypto";
12433
+ import { createHash as createHash5, randomBytes, randomUUID as randomUUID6 } from "crypto";
12390
12434
  import { getConnInfo } from "@hono/node-server/conninfo";
12391
12435
  var LOOPBACK = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "::ffff:127.0.0.1"]);
12392
12436
  function hashKey(raw) {
12393
- return createHash4("sha256").update(raw).digest("hex");
12437
+ return createHash5("sha256").update(raw).digest("hex");
12394
12438
  }
12395
12439
  function generateApiKey() {
12396
12440
  const charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -12398,7 +12442,7 @@ function generateApiKey() {
12398
12442
  let key = "";
12399
12443
  for (let i = 0; i < 40; i++) key += charset[buf[i] % 62];
12400
12444
  const full = `tllm-${key}`;
12401
- const hash = createHash4("sha256").update(full).digest("hex");
12445
+ const hash = createHash5("sha256").update(full).digest("hex");
12402
12446
  return { full, hash, prefix: full.slice(0, 12) };
12403
12447
  }
12404
12448
  function provisionTunnelApiKey(d) {
@@ -12901,6 +12945,38 @@ var ALL = [
12901
12945
  hasPrebuilt: false
12902
12946
  }
12903
12947
  ]
12948
+ },
12949
+ {
12950
+ id: "solar-open2",
12951
+ name: "Solar Open 2 (patched llama.cpp)",
12952
+ kind: "llama-server",
12953
+ description: "Upstage's Solar Open 2 (250B-A15B MoE) isn't in mainline llama.cpp yet \u2014 this builds official llama.cpp at a pinned commit with a community patch that adds the solar_open2 architecture, then runs it on the standard llama-server path.",
12954
+ provision: "github-release",
12955
+ // Builds the OFFICIAL llama.cpp repo (like the prism/beellama build-from-source cards, no
12956
+ // real github-release asset is resolved) — pinned to the exact commit the patch was authored
12957
+ // against, then the checksum-verified patch is applied before compiling. The patch is an
12958
+ // INDEPENDENT community diff, NOT reviewed or endorsed by Upstage or upstream llama.cpp — same
12959
+ // fork-provenance honesty as the prism/beellama entries above (Honesty rule at the top).
12960
+ homepage: "https://github.com/ggml-org/llama.cpp",
12961
+ repo: "ggml-org/llama.cpp",
12962
+ sourceCommit: "846e991ec3c7ccec49112ff2c5b00b710e5f551d",
12963
+ patchUrl: "https://huggingface.co/prometheusAIR/Solar-Open2-250B-GGUF/resolve/main/solar_open2-llama.cpp.patch",
12964
+ patchSha256: "998a9cef479d3b01f25e473793890b05b887a8ce85563431b3b053b14bb21fa8",
12965
+ platforms: ["win32", "darwin", "linux"],
12966
+ support: "experimental",
12967
+ installEndpoint: "",
12968
+ note: "Unofficial: applies an independent community patch (not affiliated with or reviewed by Upstage or upstream llama.cpp) on top of a pinned llama.cpp commit, verified against a pinned SHA-256 before it is applied. This is a 250B-total / ~15B-active MoE \u2014 the upstream port was tested on workstation-class hardware (128GB DDR5 + a 96GB RTX PRO 6000), not a typical consumer box; GGUF quants run ~89 GiB (Q2_K) to 191 GiB (Q6_K), with IQ4_XS (~127 GiB) recommended. Two known quirks on this arch: pass -ub 512 or -ub 4096 (a batch size of -ub 2048 crashes with a CUDA illegal-memory-access), and add --no-mmap for any CPU-offloaded setup (mmap page-faulting collapses throughput ~10x on this port).",
12969
+ variants: [
12970
+ {
12971
+ id: "solar-open2-source",
12972
+ label: "Build from source (patched)",
12973
+ repo: "ggml-org/llama.cpp",
12974
+ requires: {},
12975
+ stability: "experimental",
12976
+ speed: "baseline",
12977
+ hasPrebuilt: false
12978
+ }
12979
+ ]
12904
12980
  }
12905
12981
  ];
12906
12982
  function catalogForPlatform(platform = process.platform) {
@@ -13520,9 +13596,11 @@ function registerApi(app2, d) {
13520
13596
  installed2 = existsSync22(llamafileBinPath(enginesRoot));
13521
13597
  enabled = regEngines.some((x) => x.kind === "llamafile");
13522
13598
  }
13523
- const srcEng = regEngines.find((x) => sameRepo(x.sourceRepo, e.homepage));
13599
+ const srcEng = regEngines.find(
13600
+ (x) => sameRepo(x.sourceRepo, e.homepage) && (x.sourceCommit ?? "") === (e.sourceCommit ?? "") && (x.sourcePatchUrl ?? "") === (e.patchUrl ?? "")
13601
+ );
13524
13602
  let sourceBinPath = srcEng?.binPath;
13525
- if (!srcEng) sourceBinPath = sourceBuildBinary(enginesRoot, e.homepage) ?? void 0;
13603
+ if (!srcEng) sourceBinPath = sourceBuildBinary(enginesRoot, e.homepage, void 0, e.sourceCommit) ?? void 0;
13526
13604
  const sourceBuilt = !!srcEng || !!sourceBinPath;
13527
13605
  if (srcEng) {
13528
13606
  installed2 = true;
@@ -13567,6 +13645,14 @@ function registerApi(app2, d) {
13567
13645
  const commit = (b.commit ?? "").trim() || void 0;
13568
13646
  if (commit && !/^[0-9a-f]{7,40}$/i.test(commit))
13569
13647
  return err2(c, 400, "invalid_config_value", "commit must be a hex SHA (7-40 chars).");
13648
+ const patchUrl = (b.patchUrl ?? "").trim() || void 0;
13649
+ const patchSha256 = (b.patchSha256 ?? "").trim() || void 0;
13650
+ if (!!patchUrl !== !!patchSha256)
13651
+ return err2(c, 400, "invalid_config_value", "patchUrl and patchSha256 must be provided together \u2014 a patch may only be applied with a pinned checksum.");
13652
+ if (patchUrl && !/^https?:\/\//i.test(patchUrl))
13653
+ return err2(c, 400, "invalid_config_value", "patchUrl must be an http(s) URL.");
13654
+ if (patchSha256 && !/^[0-9a-f]{64}$/i.test(patchSha256))
13655
+ return err2(c, 400, "invalid_config_value", "patchSha256 must be a 64-char hex SHA-256.");
13570
13656
  const busy = engineWorkBusy(d);
13571
13657
  if (busy) return err2(c, 409, "engine_already_running", busy);
13572
13658
  const name = (b.name ?? "").trim() || void 0;
@@ -13581,7 +13667,7 @@ function registerApi(app2, d) {
13581
13667
  let out;
13582
13668
  try {
13583
13669
  out = await runBuild(
13584
- { repoUrl, branch, commit, enginesRoot, toolchainDirs },
13670
+ { repoUrl, branch, commit, patchUrl, patchSha256, enginesRoot, toolchainDirs },
13585
13671
  { phase: (p) => d.build.phase(p), log: (line) => d.build.log(line) },
13586
13672
  ac.signal
13587
13673
  );
@@ -13616,11 +13702,12 @@ function registerApi(app2, d) {
13616
13702
  const eng = (await d.registry.add(prior?.name ?? name ?? "", out.binPath, {
13617
13703
  sourceRepo: repoUrl,
13618
13704
  sourceBranch: branch,
13619
- sourceCommit: commit
13705
+ sourceCommit: commit,
13706
+ sourcePatchUrl: patchUrl
13620
13707
  })).engine;
13621
13708
  d.registry.activate(eng.id);
13622
13709
  if (!isCatalogRepo(repoUrl)) {
13623
- d.registry.recordCustomSource({ name: eng.name, binPath: eng.binPath, kind: eng.kind, sourceRepo: repoUrl, sourceBranch: branch, sourceCommit: commit });
13710
+ d.registry.recordCustomSource({ name: eng.name, binPath: eng.binPath, kind: eng.kind, sourceRepo: repoUrl, sourceBranch: branch, sourceCommit: commit, sourcePatchUrl: patchUrl });
13624
13711
  }
13625
13712
  d.build.log(`Registered "${eng.name}" \u2014 built from ${out.commit.slice(0, 8)}.`);
13626
13713
  d.build.done();
@@ -13893,7 +13980,8 @@ function registerApi(app2, d) {
13893
13980
  kind: eng.kind,
13894
13981
  sourceRepo: eng.sourceRepo,
13895
13982
  sourceBranch: eng.sourceBranch,
13896
- sourceCommit: eng.sourceCommit
13983
+ sourceCommit: eng.sourceCommit,
13984
+ sourcePatchUrl: eng.sourcePatchUrl
13897
13985
  });
13898
13986
  }
13899
13987
  d.registry.remove(id);
@@ -1 +1 @@
1
- import{j as e}from"./radix-C-sz7VcM.js";import{u as M,b as W,r as b}from"./vendor-BFom-Mq6.js";import{u as $,b as G,c as H,d as Y,e as J,a as E,B as y,f as B,t as h,A as C}from"./index-D4oBHgyO.js";import{f as U}from"./chat-api-uAJNrEFg.js";import{f as V,a as X}from"./agent-api-BZQuCIAd.js";import{P as z}from"./personas-fIGMukzj.js";import{C as Z}from"./chevron-left-Dv-zay0l.js";import{R as ee}from"./rotate-ccw-D99lmEA-.js";import{T as te}from"./trash-2-CuUIi8kE.js";import{C as se}from"./chevron-right-DvvJS6ye.js";const ne=()=>({name:"",description:"",systemPrompt:"",skillIds:[],tools:[]});function oe(s){const d=[],x=new Map;for(const n of s){const o=/^mcp__([^_]+(?:_[^_]+)*)__/.exec(n.name);if(!o){d.push(n);continue}const i=o[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,o)=>n.label.localeCompare(o.label))}}function ae(s){return s.replace(/^mcp__[^_]+(?:_[^_]+)*__/,"")}function le(s){return s.replace(/^\[[^\]]+\]\s*/,"")}function q({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:ae(s.name)}),s.description&&e.jsx("span",{className:"text-faint",children:le(s.description)})]})]})}function re({group:s,selected:d,onToggleAll:x,onToggleOne:n}){const[o,i]=b.useState(!1),p=s.tools.map(l=>l.name),c=p.filter(l=>d.has(l)).length,a=c===p.length,f=c>0&&!a,u=b.useRef(null);return b.useEffect(()=>{u.current&&(u.current.indeterminate=f)},[f]),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:a,onChange:()=>x(p,!a)}),e.jsxs("button",{type:"button",onClick:()=>i(l=>!l),className:"flex flex-1 items-center gap-1.5 text-left text-[13px] text-ink",children:[e.jsx(se,{size:12,className:B("shrink-0 text-faint transition-transform",o&&"rotate-90")}),s.label,e.jsxs("span",{className:"text-[11px] text-faint",children:["(",c,"/",p.length,")"]})]})]}),o&&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(q,{tool:l,checked:d.has(l.name),onToggle:()=>n(l.name)},l.name))})]})}function ie({tools:s,selected:d,onChange:x}){const n=new Set(d),{builtin:o,groups:i}=oe(s),p=a=>x(n.has(a)?d.filter(f=>f!==a):[...d,a]),c=(a,f)=>{const u=d.filter(l=>!a.includes(l));x(f?[...u,...a]: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:[o.length>0&&e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:o.map(a=>e.jsx(q,{tool:a,checked:n.has(a.name),onToggle:()=>p(a.name)},a.name))}),i.map(a=>e.jsx(re,{group:a,selected:n,onToggleAll:c,onToggleOne:p},a.key))]})}function ke(){const{agentId:s="new"}=M(),d=W(),x=$(),n=s==="new",o=!n&&z.some(t=>t.id===s),i=o?z.find(t=>t.id===s):void 0,p=G(),c=!n&&!o?(p.data??[]).find(t=>t.id===s):void 0,a=H(),f=Y(),u=J(),l=o?f.data?.[s]:void 0,_=E({queryKey:X.list(),queryFn:V,staleTime:0}),k=_.data??[],I=E({queryKey:["available-tools"],queryFn:U}),j=I.data??[],[m,g]=b.useState(ne()),[S,T]=b.useState(!1),[A,P]=b.useState(!1),[D,w]=b.useState(!1),[R,L]=b.useState("skills");n&&!S&&(k.length||j.length)&&(g(t=>({...t,skillIds:k.map(r=>r.id),tools:j.map(r=>r.name)})),T(!0)),!n&&!o&&!S&&c&&(g({name:c.name,description:c.description,systemPrompt:c.systemPrompt,skillIds:c.skillIds,tools:c.tools}),T(!0)),o&&!S&&i&&f.isSuccess&&(k.length||j.length)&&(g({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??j.map(t=>t.name)}),T(!0));const N=()=>d("/customize"),Q=t=>g(r=>({...r,skillIds:r.skillIds.includes(t)?r.skillIds.filter(v=>v!==t):[...r.skillIds,t]})),O=()=>{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(o){u.save.mutate({id:s,override:t},{onSuccess:()=>{h.success("Agent saved."),N()},onError:v=>{h.error(v instanceof C?v.message:"Could not save agent."),P(!1)}});return}const r={onSuccess:()=>{x.invalidateQueries({queryKey:["chat-agents"]}),h.success(n?"Agent created.":"Agent saved."),N()},onError:v=>{h.error(v instanceof C?v.message:"Could not save agent."),P(!1)}};n?a.add.mutate(t,r):a.update.mutate({id:s,patch:t},r)},F=()=>{u.reset.mutate(s,{onSuccess:()=>{h.success("Reset to default."),i&&g({name:i.name,description:i.description,systemPrompt:i.systemPrompt,skillIds:k.map(t=>t.id),tools:j.map(t=>t.name)})},onError:t=>h.error(t instanceof C?t.message:"Could not reset agent.")})},K=()=>{a.remove.mutate(s,{onSuccess:()=>{h.success("Agent deleted."),N()},onError:t=>h.error(t instanceof C?t.message:"Could not delete agent.")})};return!n&&!o&&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(y,{size:"sm",variant:"outline",onClick:N,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:N,className:"text-faint hover:text-ink",title:"Back to agents",children:e.jsx(Z,{size:18})}),e.jsx("span",{className:"text-[15px] font-medium text-ink",children:n?"New agent":o?l?"Edit agent (modified built-in)":"Edit agent (built-in)":"Edit agent"}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[o&&e.jsxs(y,{size:"sm",variant:"outline",onClick:F,disabled:u.reset.isPending,children:[e.jsx(ee,{size:13})," Reset to default"]}),e.jsx(y,{size:"sm",variant:"outline",onClick:N,children:"Cancel"}),e.jsx(y,{size:"sm",onClick:O,disabled:A||!m.name.trim(),children:A?"Saving…":"Save"})]})]}),o&&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=>g(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=>g(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=>g(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:()=>L(t),className:B("rounded px-3 py-1.5 text-[13px] font-medium transition-colors",R===t?"bg-accent/12 text-accent":"text-muted hover:text-ink"),children:t==="skills"?`Skills (${m.skillIds.length})`:`Tools (${m.tools.length})`},t))}),R==="skills"?_.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:()=>Q(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))}):I.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):e.jsx(ie,{tools:j,selected:m.tools,onChange:t=>g(r=>({...r,tools:t}))})]}),!n&&!o&&(D?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:K,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:()=>w(!1),className:"rounded px-2 py-1 text-faint hover:text-ink",children:"Cancel"})]}):e.jsxs("button",{type:"button",onClick:()=>w(!0),className:"flex items-center gap-1.5 self-start text-[12px] text-faint hover:text-[color:var(--err)]",children:[e.jsx(te,{size:13})," Delete agent"]}))]})}export{ke as AgentEditPage};
1
+ import{j as e}from"./radix-C-sz7VcM.js";import{u as M,b as W,r as b}from"./vendor-BFom-Mq6.js";import{u as $,b as G,c as H,d as Y,e as J,a as E,B as y,f as B,t as h,A as C}from"./index-v0Tdes8H.js";import{f as U}from"./chat-api-B81lfnq0.js";import{f as V,a as X}from"./agent-api-DBuqrdZq.js";import{P as z}from"./personas-fIGMukzj.js";import{C as Z}from"./chevron-left-BdgNx91c.js";import{R as ee}from"./rotate-ccw-c1dWBxKq.js";import{T as te}from"./trash-2-Pyx2qefh.js";import{C as se}from"./chevron-right-BXxjw90s.js";const ne=()=>({name:"",description:"",systemPrompt:"",skillIds:[],tools:[]});function oe(s){const d=[],x=new Map;for(const n of s){const o=/^mcp__([^_]+(?:_[^_]+)*)__/.exec(n.name);if(!o){d.push(n);continue}const i=o[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,o)=>n.label.localeCompare(o.label))}}function ae(s){return s.replace(/^mcp__[^_]+(?:_[^_]+)*__/,"")}function le(s){return s.replace(/^\[[^\]]+\]\s*/,"")}function q({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:ae(s.name)}),s.description&&e.jsx("span",{className:"text-faint",children:le(s.description)})]})]})}function re({group:s,selected:d,onToggleAll:x,onToggleOne:n}){const[o,i]=b.useState(!1),p=s.tools.map(l=>l.name),c=p.filter(l=>d.has(l)).length,a=c===p.length,f=c>0&&!a,u=b.useRef(null);return b.useEffect(()=>{u.current&&(u.current.indeterminate=f)},[f]),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:a,onChange:()=>x(p,!a)}),e.jsxs("button",{type:"button",onClick:()=>i(l=>!l),className:"flex flex-1 items-center gap-1.5 text-left text-[13px] text-ink",children:[e.jsx(se,{size:12,className:B("shrink-0 text-faint transition-transform",o&&"rotate-90")}),s.label,e.jsxs("span",{className:"text-[11px] text-faint",children:["(",c,"/",p.length,")"]})]})]}),o&&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(q,{tool:l,checked:d.has(l.name),onToggle:()=>n(l.name)},l.name))})]})}function ie({tools:s,selected:d,onChange:x}){const n=new Set(d),{builtin:o,groups:i}=oe(s),p=a=>x(n.has(a)?d.filter(f=>f!==a):[...d,a]),c=(a,f)=>{const u=d.filter(l=>!a.includes(l));x(f?[...u,...a]: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:[o.length>0&&e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:o.map(a=>e.jsx(q,{tool:a,checked:n.has(a.name),onToggle:()=>p(a.name)},a.name))}),i.map(a=>e.jsx(re,{group:a,selected:n,onToggleAll:c,onToggleOne:p},a.key))]})}function ke(){const{agentId:s="new"}=M(),d=W(),x=$(),n=s==="new",o=!n&&z.some(t=>t.id===s),i=o?z.find(t=>t.id===s):void 0,p=G(),c=!n&&!o?(p.data??[]).find(t=>t.id===s):void 0,a=H(),f=Y(),u=J(),l=o?f.data?.[s]:void 0,_=E({queryKey:X.list(),queryFn:V,staleTime:0}),k=_.data??[],I=E({queryKey:["available-tools"],queryFn:U}),j=I.data??[],[m,g]=b.useState(ne()),[S,T]=b.useState(!1),[A,P]=b.useState(!1),[D,w]=b.useState(!1),[R,L]=b.useState("skills");n&&!S&&(k.length||j.length)&&(g(t=>({...t,skillIds:k.map(r=>r.id),tools:j.map(r=>r.name)})),T(!0)),!n&&!o&&!S&&c&&(g({name:c.name,description:c.description,systemPrompt:c.systemPrompt,skillIds:c.skillIds,tools:c.tools}),T(!0)),o&&!S&&i&&f.isSuccess&&(k.length||j.length)&&(g({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??j.map(t=>t.name)}),T(!0));const N=()=>d("/customize"),Q=t=>g(r=>({...r,skillIds:r.skillIds.includes(t)?r.skillIds.filter(v=>v!==t):[...r.skillIds,t]})),O=()=>{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(o){u.save.mutate({id:s,override:t},{onSuccess:()=>{h.success("Agent saved."),N()},onError:v=>{h.error(v instanceof C?v.message:"Could not save agent."),P(!1)}});return}const r={onSuccess:()=>{x.invalidateQueries({queryKey:["chat-agents"]}),h.success(n?"Agent created.":"Agent saved."),N()},onError:v=>{h.error(v instanceof C?v.message:"Could not save agent."),P(!1)}};n?a.add.mutate(t,r):a.update.mutate({id:s,patch:t},r)},F=()=>{u.reset.mutate(s,{onSuccess:()=>{h.success("Reset to default."),i&&g({name:i.name,description:i.description,systemPrompt:i.systemPrompt,skillIds:k.map(t=>t.id),tools:j.map(t=>t.name)})},onError:t=>h.error(t instanceof C?t.message:"Could not reset agent.")})},K=()=>{a.remove.mutate(s,{onSuccess:()=>{h.success("Agent deleted."),N()},onError:t=>h.error(t instanceof C?t.message:"Could not delete agent.")})};return!n&&!o&&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(y,{size:"sm",variant:"outline",onClick:N,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:N,className:"text-faint hover:text-ink",title:"Back to agents",children:e.jsx(Z,{size:18})}),e.jsx("span",{className:"text-[15px] font-medium text-ink",children:n?"New agent":o?l?"Edit agent (modified built-in)":"Edit agent (built-in)":"Edit agent"}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[o&&e.jsxs(y,{size:"sm",variant:"outline",onClick:F,disabled:u.reset.isPending,children:[e.jsx(ee,{size:13})," Reset to default"]}),e.jsx(y,{size:"sm",variant:"outline",onClick:N,children:"Cancel"}),e.jsx(y,{size:"sm",onClick:O,disabled:A||!m.name.trim(),children:A?"Saving…":"Save"})]})]}),o&&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=>g(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=>g(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=>g(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:()=>L(t),className:B("rounded px-3 py-1.5 text-[13px] font-medium transition-colors",R===t?"bg-accent/12 text-accent":"text-muted hover:text-ink"),children:t==="skills"?`Skills (${m.skillIds.length})`:`Tools (${m.tools.length})`},t))}),R==="skills"?_.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:()=>Q(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))}):I.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):e.jsx(ie,{tools:j,selected:m.tools,onChange:t=>g(r=>({...r,tools:t}))})]}),!n&&!o&&(D?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:K,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:()=>w(!1),className:"rounded px-2 py-1 text-faint hover:text-ink",children:"Cancel"})]}):e.jsxs("button",{type:"button",onClick:()=>w(!0),className:"flex items-center gap-1.5 self-start text-[12px] text-faint hover:text-[color:var(--err)]",children:[e.jsx(te,{size:13})," Delete agent"]}))]})}export{ke as AgentEditPage};