turbollm 1.7.1 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +3 -3
  2. package/bin/turbollm.mjs +29 -25
  3. package/dist/cli.js +98 -13
  4. package/dist/webdist/assets/{AgentsScreen-BToQ_CZg.js → AgentsScreen-sMeMB3IQ.js} +1 -1
  5. package/dist/webdist/assets/{ChatScreen-B4T7fIcx.js → ChatScreen-rXB7PrWJ.js} +1 -1
  6. package/dist/webdist/assets/{CustomizeScreen-IL-QlVq2.js → CustomizeScreen-BBwvtk28.js} +1 -1
  7. package/dist/webdist/assets/DeveloperScreen-fXV-qXB5.js +1 -0
  8. package/dist/webdist/assets/{EnginesScreen-GZYaJJNx.js → EnginesScreen-CrmYzhio.js} +1 -1
  9. package/dist/webdist/assets/{MessageBubble-DG7ZWPCw.js → MessageBubble-COuZ8jTd.js} +3 -3
  10. package/dist/webdist/assets/{ModelDetailDialog-DhCCmMnp.js → ModelDetailDialog-Dlt5uF3h.js} +1 -1
  11. package/dist/webdist/assets/{ModelDirs-D0d7xetP.js → ModelDirs-BYN-DmHL.js} +1 -1
  12. package/dist/webdist/assets/{ModelsScreen-Bl0OP-BY.js → ModelsScreen-DncNvsj6.js} +1 -1
  13. package/dist/webdist/assets/{SettingsScreen-DXy_TCXo.js → SettingsScreen-DXX3r4Ep.js} +1 -1
  14. package/dist/webdist/assets/{arc-DVrcAJc9.js → arc-BrQAHE5c.js} +1 -1
  15. package/dist/webdist/assets/{architectureDiagram-3BPJPVTR-BaL05OA8.js → architectureDiagram-3BPJPVTR-DzOwDk0E.js} +1 -1
  16. package/dist/webdist/assets/{arrow-left-nmoUPZoB.js → arrow-left-Dp4XRnbs.js} +1 -1
  17. package/dist/webdist/assets/{blockDiagram-GPEHLZMM-D8aCVMG0.js → blockDiagram-GPEHLZMM-Cbs2lNCh.js} +1 -1
  18. package/dist/webdist/assets/{c4Diagram-AAUBKEIU-Bpj96pxf.js → c4Diagram-AAUBKEIU-BAull9Yv.js} +1 -1
  19. package/dist/webdist/assets/channel-Bt5-ol5R.js +1 -0
  20. package/dist/webdist/assets/check-jMeH6YsH.js +1 -0
  21. package/dist/webdist/assets/{chevron-down-DgTSOyZG.js → chevron-down-C5ZMFCtb.js} +1 -1
  22. package/dist/webdist/assets/{chevron-right-BshRZEvM.js → chevron-right-DNVnXbZ1.js} +1 -1
  23. package/dist/webdist/assets/{chunk-2J33WTMH-DA6mFoN-.js → chunk-2J33WTMH-B38k4sJL.js} +1 -1
  24. package/dist/webdist/assets/{chunk-4BX2VUAB-B_fmKUNu.js → chunk-4BX2VUAB-VxAkYvb7.js} +1 -1
  25. package/dist/webdist/assets/{chunk-55IACEB6-3cWMWgYr.js → chunk-55IACEB6-CAz9ZWyR.js} +1 -1
  26. package/dist/webdist/assets/{chunk-727SXJPM-Cwb5Sv7F.js → chunk-727SXJPM-CvLX5ghS.js} +1 -1
  27. package/dist/webdist/assets/{chunk-AQP2D5EJ-7QIg1x7-.js → chunk-AQP2D5EJ-CZ0fsnc1.js} +1 -1
  28. package/dist/webdist/assets/{chunk-FMBD7UC4-D_Qfl5Jc.js → chunk-FMBD7UC4-tjHz_yw8.js} +1 -1
  29. package/dist/webdist/assets/{chunk-ND2GUHAM-pgqeq7NP.js → chunk-ND2GUHAM-DVSh5E5_.js} +1 -1
  30. package/dist/webdist/assets/{chunk-QZHKN3VN-EUqDaxxx.js → chunk-QZHKN3VN-D1rUM2SU.js} +1 -1
  31. package/dist/webdist/assets/{circle-check-Dey3SdiG.js → circle-check-qnghY_qF.js} +1 -1
  32. package/dist/webdist/assets/{circle-x-M54_eiYo.js → circle-x-FM28MwOL.js} +1 -1
  33. package/dist/webdist/assets/classDiagram-4FO5ZUOK-jfnUpxOr.js +1 -0
  34. package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-jfnUpxOr.js +1 -0
  35. package/dist/webdist/assets/{common-Dn21s6g5.js → common-BD4Wa3KL.js} +1 -1
  36. package/dist/webdist/assets/{copy-button-D6JkFOO9.js → copy-button-DypRNkqI.js} +1 -1
  37. package/dist/webdist/assets/{cose-bilkent-S5V4N54A-BzxdTTj-.js → cose-bilkent-S5V4N54A-DIUqY7o2.js} +1 -1
  38. package/dist/webdist/assets/{dagre-BM42HDAG-YQn0mFsV.js → dagre-BM42HDAG-BzTcsgZ1.js} +1 -1
  39. package/dist/webdist/assets/{diagram-2AECGRRQ-DtSRGaVH.js → diagram-2AECGRRQ-DanHH-W_.js} +1 -1
  40. package/dist/webdist/assets/{diagram-5GNKFQAL-Dko3hF44.js → diagram-5GNKFQAL-DQ5sWHUL.js} +1 -1
  41. package/dist/webdist/assets/{diagram-KO2AKTUF-CQAm-tYF.js → diagram-KO2AKTUF-Jqr_pLwu.js} +1 -1
  42. package/dist/webdist/assets/{diagram-LMA3HP47-gz5BqFhM.js → diagram-LMA3HP47-BZ89-cp0.js} +1 -1
  43. package/dist/webdist/assets/{diagram-OG6HWLK6-BqsSoNIn.js → diagram-OG6HWLK6-cidBc5qa.js} +1 -1
  44. package/dist/webdist/assets/{dialog-B_Yd5di3.js → dialog-3hyZ9j4e.js} +1 -1
  45. package/dist/webdist/assets/{erDiagram-TEJ5UH35-D8rPsHw-.js → erDiagram-TEJ5UH35-DEAKZN7b.js} +1 -1
  46. package/dist/webdist/assets/{flowDiagram-I6XJVG4X-DhGWyp50.js → flowDiagram-I6XJVG4X-Cyx8gMzN.js} +1 -1
  47. package/dist/webdist/assets/{ganttDiagram-6RSMTGT7-WEinw7mP.js → ganttDiagram-6RSMTGT7-CqXYW44d.js} +1 -1
  48. package/dist/webdist/assets/{gitGraphDiagram-PVQCEYII-BJ-BzBFO.js → gitGraphDiagram-PVQCEYII-0dv_zKYA.js} +1 -1
  49. package/dist/webdist/assets/{index-C-xjjrht.js → index-CriwC5VH.js} +2 -2
  50. package/dist/webdist/assets/{infoDiagram-5YYISTIA-BA9oHMe2.js → infoDiagram-5YYISTIA-PxeM6E3u.js} +1 -1
  51. package/dist/webdist/assets/{ishikawaDiagram-YF4QCWOH-BJ5McdEJ.js → ishikawaDiagram-YF4QCWOH-BnNdTjj1.js} +1 -1
  52. package/dist/webdist/assets/{journeyDiagram-JHISSGLW-Bu6WJyQy.js → journeyDiagram-JHISSGLW-D3AHUGxz.js} +1 -1
  53. package/dist/webdist/assets/{kanban-definition-UN3LZRKU-C_Y8cJ9D.js → kanban-definition-UN3LZRKU-YARl6SUt.js} +1 -1
  54. package/dist/webdist/assets/{linear-BssoHTW-.js → linear-CMEhaWGh.js} +1 -1
  55. package/dist/webdist/assets/{mermaid.core-C331Qhyf.js → mermaid.core-Dfl2pPvv.js} +4 -4
  56. package/dist/webdist/assets/{mindmap-definition-RKZ34NQL-B6NCYWu3.js → mindmap-definition-RKZ34NQL-BojWC6jk.js} +1 -1
  57. package/dist/webdist/assets/{pencil-bwNY7waZ.js → pencil-CS33zp9q.js} +1 -1
  58. package/dist/webdist/assets/{personas-C_q63e_2.js → personas-CzcXp8zg.js} +1 -1
  59. package/dist/webdist/assets/{pieDiagram-4H26LBE5-CV23vNlv.js → pieDiagram-4H26LBE5-cjsdMtJJ.js} +1 -1
  60. package/dist/webdist/assets/{plus-12BmUfjg.js → plus-BO3vGy6f.js} +1 -1
  61. package/dist/webdist/assets/{quadrantDiagram-W4KKPZXB-DxWTWFL7.js → quadrantDiagram-W4KKPZXB-DYVcgQuL.js} +1 -1
  62. package/dist/webdist/assets/{refresh-cw-Cl7RshCH.js → refresh-cw-Cco9RapO.js} +1 -1
  63. package/dist/webdist/assets/{requirementDiagram-4Y6WPE33-DRRulwpq.js → requirementDiagram-4Y6WPE33-Dkj58nhB.js} +1 -1
  64. package/dist/webdist/assets/{sankeyDiagram-5OEKKPKP-BTBSg_uE.js → sankeyDiagram-5OEKKPKP-l3GwUuNl.js} +1 -1
  65. package/dist/webdist/assets/{save-YXge1rTt.js → save-CSISNMk8.js} +1 -1
  66. package/dist/webdist/assets/{sequenceDiagram-3UESZ5HK-HiTl9dyH.js → sequenceDiagram-3UESZ5HK-CWj1Dplo.js} +1 -1
  67. package/dist/webdist/assets/{skeleton-BMhnZFjx.js → skeleton-CBRf-twG.js} +1 -1
  68. package/dist/webdist/assets/{stateDiagram-AJRCARHV-SGw6a8ke.js → stateDiagram-AJRCARHV-zbnPRcoE.js} +1 -1
  69. package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-Ukx8AVKZ.js +1 -0
  70. package/dist/webdist/assets/{timeline-definition-PNZ67QCA-B_X3zBz0.js → timeline-definition-PNZ67QCA-C_zAo1WZ.js} +1 -1
  71. package/dist/webdist/assets/{trash-2-BNQkpp4n.js → trash-2-DJmVqx0w.js} +1 -1
  72. package/dist/webdist/assets/{vennDiagram-CIIHVFJN-C8ibsbKD.js → vennDiagram-CIIHVFJN-DxfcocQu.js} +1 -1
  73. package/dist/webdist/assets/{vram-D4ttIJVy.js → vram-Dn53zt7R.js} +1 -1
  74. package/dist/webdist/assets/{wardley-L42UT6IY-ClFBGt2Y.js → wardley-L42UT6IY-BnZ8BinJ.js} +1 -1
  75. package/dist/webdist/assets/{wardleyDiagram-YWT4CUSO-1iaMKpVQ.js → wardleyDiagram-YWT4CUSO-DMk9z7hr.js} +1 -1
  76. package/dist/webdist/assets/{wrench-Chhk_zTw.js → wrench-Di5WLTz2.js} +1 -1
  77. package/dist/webdist/assets/{xychartDiagram-2RQKCTM6-FIIVikoF.js → xychartDiagram-2RQKCTM6-BUtTPXPF.js} +1 -1
  78. package/dist/webdist/index.html +1 -1
  79. package/package.json +2 -2
  80. package/dist/webdist/assets/DeveloperScreen-DN-FWjXV.js +0 -1
  81. package/dist/webdist/assets/channel-M9YFYffr.js +0 -1
  82. package/dist/webdist/assets/check-CD6cKVwJ.js +0 -1
  83. package/dist/webdist/assets/classDiagram-4FO5ZUOK-BtQ5UIn2.js +0 -1
  84. package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-BtQ5UIn2.js +0 -1
  85. package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-C7Pv9LnA.js +0 -1
package/README.md CHANGED
@@ -446,7 +446,7 @@ Use `--config <file>` to point at an alternate config (its directory becomes the
446
446
 
447
447
  ## Requirements
448
448
 
449
- - **Node.js 22 or newer** — enforced at startup with a clear message. <https://nodejs.org>
449
+ - **Node.js 22.13.0 or newer** — enforced at startup with a clear message. <https://nodejs.org>
450
450
  - **Windows, macOS, or Linux.**
451
451
  - A GPU is recommended but **not required** — a CPU build is provisioned as a fallback.
452
452
  - On Windows, the first time the auto-downloaded `llama-server` runs, SmartScreen/Defender may
@@ -492,7 +492,7 @@ Prefer Open WebUI's chat breadth? It works great pointed at TurboLLM's OpenAI en
492
492
 
493
493
  ## Troubleshooting
494
494
 
495
- - **`TurboLLM requires Node.js 22 or newer`** — upgrade Node: <https://nodejs.org>.
495
+ - **`TurboLLM requires Node.js 22.13.0 or newer`** — upgrade Node: <https://nodejs.org>.
496
496
  - **Model won't load / OOM** — pick a smaller quant (the VRAM verdict warns you), lower GPU
497
497
  offload, or close other GPU apps. Failures surface in the Engines screen with the engine log.
498
498
  - **Windows Defender / SmartScreen prompt** — that's the upstream `llama-server` binary on
@@ -519,7 +519,7 @@ node dist/cli.js --port 6996
519
519
  Frontend hot-reload: `cd web && npm run dev` (proxies `/api` and `/v1` to the daemon on
520
520
  :6996).
521
521
 
522
- **Stack:** Node ≥22 · TypeScript · Hono · `node:sqlite` · tsup — and a React 19 + Tailwind v4 +
522
+ **Stack:** Node ≥22.13 · TypeScript · Hono · `node:sqlite` · tsup — and a React 19 + Tailwind v4 +
523
523
  shadcn/ui frontend. One TypeScript codebase, shipped as an npm package.
524
524
 
525
525
  ---
package/bin/turbollm.mjs CHANGED
@@ -1,25 +1,29 @@
1
- #!/usr/bin/env node
2
- // Hand-written launcher shim — NOT bundled by tsup. It runs before the bundled
3
- // daemon (dist/cli.js) loads, so it can do two things that must happen before
4
- // node:sqlite is imported (the bundle hoists that import, emitting an experimental
5
- // warning that PowerShell renders as a scary red error block on every run):
6
- // 1. Guard the Node version with a friendly message (node:sqlite needs Node 22+).
7
- // 2. Register a 'warning' filter that swallows the node:sqlite experimental notice
8
- // while still printing every other warning.
9
- // Then it hands off to the real CLI via dynamic import (same process; argv intact).
10
- const major = Number(process.versions.node.split('.')[0])
11
- if (major < 22) {
12
- process.stderr.write(
13
- `TurboLLM requires Node.js 22 or newer.\n` +
14
- `You are running Node.js ${process.versions.node}.\n` +
15
- `Please upgrade: https://nodejs.org\n`,
16
- )
17
- process.exit(1)
18
- }
19
-
20
- process.on('warning', (w) => {
21
- if (w.name === 'ExperimentalWarning' && /SQLite/i.test(w.message)) return
22
- process.stderr.write(`${w.stack ?? `${w.name}: ${w.message}`}\n`)
23
- })
24
-
25
- await import('../dist/cli.js')
1
+ #!/usr/bin/env node
2
+ // Hand-written launcher shim — NOT bundled by tsup. It runs before the bundled
3
+ // daemon (dist/cli.js) loads, so it can do two things that must happen before
4
+ // node:sqlite is imported (the bundle hoists that import, emitting an experimental
5
+ // warning that PowerShell renders as a scary red error block on every run):
6
+ // 1. Guard the Node version with a friendly message (node:sqlite needs Node 22.13+
7
+ // that's when node:sqlite became available WITHOUT the --experimental-sqlite flag;
8
+ // on 22.5.0-22.12.x it's registered only behind that flag, so importing it bare
9
+ // throws ERR_UNKNOWN_BUILTIN_MODULE: "No such built-in module: node:sqlite"
10
+ // (GitHub #40) even though `node -v` reports 22.x).
11
+ // 2. Register a 'warning' filter that swallows the node:sqlite experimental notice
12
+ // while still printing every other warning.
13
+ // Then it hands off to the real CLI via dynamic import (same process; argv intact).
14
+ const [major, minor] = process.versions.node.split('.').map(Number)
15
+ if (major < 22 || (major === 22 && minor < 13)) {
16
+ process.stderr.write(
17
+ `TurboLLM requires Node.js 22.13.0 or newer (needs node:sqlite unflagged).\n` +
18
+ `You are running Node.js ${process.versions.node}.\n` +
19
+ `Please upgrade: https://nodejs.org\n`,
20
+ )
21
+ process.exit(1)
22
+ }
23
+
24
+ process.on('warning', (w) => {
25
+ if (w.name === 'ExperimentalWarning' && /SQLite/i.test(w.message)) return
26
+ process.stderr.write(`${w.stack ?? `${w.name}: ${w.message}`}\n`)
27
+ })
28
+
29
+ await import('../dist/cli.js')
package/dist/cli.js CHANGED
@@ -1946,7 +1946,7 @@ async function probe(bin) {
1946
1946
  const m = RE_VERSION.exec(combined);
1947
1947
  let version2 = m ? m[1].trim() : trimLen(firstNonEmptyLine(v.out), 100);
1948
1948
  if (!version2) version2 = "unknown";
1949
- const flags = [...new Set(h.out.match(RE_FLAG) ?? [])].sort();
1949
+ const flags = extractFlags(h.out);
1950
1950
  const kvTypes = flags.includes("--cache-type-k") ? [...KNOWN_KV] : ["f16"];
1951
1951
  if (combined.toLowerCase().includes("turbo")) kvTypes.push("turbo2", "turbo3", "turbo4");
1952
1952
  const ENUM_RE = /--spec-type\s+(\[[^\]\n]+\]|[a-z][a-z0-9_-]*(?:[,|][a-z0-9_-]+)+)/gi;
@@ -1982,6 +1982,14 @@ function detectFormat(bin) {
1982
1982
  function osLabel(fmt) {
1983
1983
  return fmt === "pe" ? "Windows" : fmt === "macho" ? "macOS" : "Linux";
1984
1984
  }
1985
+ function extractFlags(helpText) {
1986
+ const flagSet = /* @__PURE__ */ new Set();
1987
+ for (const line of helpText.split("\n")) {
1988
+ if (/\bhas been removed\b/i.test(line)) continue;
1989
+ for (const f of line.match(RE_FLAG) ?? []) flagSet.add(f);
1990
+ }
1991
+ return [...flagSet].sort();
1992
+ }
1985
1993
  function firstNonEmptyLine(s) {
1986
1994
  for (const ln of s.split("\n")) {
1987
1995
  const t = ln.trim();
@@ -2264,9 +2272,8 @@ var Registry = class {
2264
2272
  * e.g. one with `--spec-type` but no captured `spec-type:<value>` entries, so
2265
2273
  * NextN/MTP gating has the data it needs without a manual re-probe. */
2266
2274
  async ensureProbed() {
2267
- const stale = (e) => e.capabilities.flags.includes("--spec-type") && !e.capabilities.flags.some((f) => f.startsWith("spec-type:"));
2268
2275
  for (const e of this.list().engines) {
2269
- if (e.version && !stale(e)) continue;
2276
+ if (e.version && !isStaleCapabilities(e.capabilities.flags)) continue;
2270
2277
  try {
2271
2278
  await this.reprobe(e.id);
2272
2279
  } catch {
@@ -2274,6 +2281,11 @@ var Registry = class {
2274
2281
  }
2275
2282
  }
2276
2283
  };
2284
+ function isStaleCapabilities(flags) {
2285
+ if (flags.includes("--spec-type") && !flags.some((f) => f.startsWith("spec-type:"))) return true;
2286
+ if (["--draft-max", "--draft-min", "--draft", "--draft-n", "--draft-n-min"].some((f) => flags.includes(f))) return true;
2287
+ return false;
2288
+ }
2277
2289
 
2278
2290
  // src/engines/provision-state.ts
2279
2291
  var ProvisionState = class {
@@ -3900,9 +3912,12 @@ function profileToArgs(p, m, caps, cores = 0) {
3900
3912
  if (specType) a.push("--spec-type", "mtp");
3901
3913
  a.push("--mtp-head", p.mtpHeadPath);
3902
3914
  specActive = true;
3903
- } else if (p.speculative === "nextn" && specType && has("--model-draft")) {
3915
+ } else if (p.speculative === "nextn" && specType) {
3904
3916
  const nextnVal = ["nextn", "draft-mtp"].find((v) => specAccepts(v));
3905
- if (nextnVal) {
3917
+ if (nextnVal === "draft-mtp") {
3918
+ a.push("--spec-type", nextnVal);
3919
+ specActive = true;
3920
+ } else if (nextnVal === "nextn" && has("--model-draft")) {
3906
3921
  a.push("--spec-type", nextnVal, "--model-draft", m.path);
3907
3922
  specActive = true;
3908
3923
  }
@@ -3911,8 +3926,12 @@ function profileToArgs(p, m, caps, cores = 0) {
3911
3926
  a.push("--model-draft", p.draftModelPath);
3912
3927
  specActive = true;
3913
3928
  }
3914
- if (specActive && has("--draft-max")) a.push("--draft-max", String(p.draftMax ?? 16));
3915
- if (specActive && has("--draft-min")) a.push("--draft-min", String(p.draftMin ?? 1));
3929
+ if (specActive) {
3930
+ if (has("--draft-max")) a.push("--draft-max", String(p.draftMax ?? 16));
3931
+ else if (has("--spec-draft-n-max")) a.push("--spec-draft-n-max", String(p.draftMax ?? 16));
3932
+ if (has("--draft-min")) a.push("--draft-min", String(p.draftMin ?? 1));
3933
+ else if (has("--spec-draft-n-min")) a.push("--spec-draft-n-min", String(p.draftMin ?? 1));
3934
+ }
3916
3935
  if (p.sampling.temp !== 0.8 && has("--temp")) a.push("--temp", String(p.sampling.temp));
3917
3936
  if (p.sampling.topP !== 0.95 && has("--top-p")) a.push("--top-p", String(p.sampling.topP));
3918
3937
  if (p.sampling.topK !== 40 && has("--top-k")) a.push("--top-k", String(p.sampling.topK));
@@ -5396,7 +5415,7 @@ var BenchRunner = class {
5396
5415
  const saved = getModelProfile(this.store.snapshot(), modelKey, active?.id ?? "*");
5397
5416
  const defaults = this.store.snapshot().modelDefaults;
5398
5417
  const resolved = resolveProfile(entry, sys, saved, base2, defaults);
5399
- const baseProfile = { ...resolved, speculative: "off", mtpHeadPath: "", draftModelPath: "" };
5418
+ const baseProfile = resolved;
5400
5419
  const headroomMb = this.store.snapshot().vramHeadroomMb;
5401
5420
  const results = [];
5402
5421
  let best = null;
@@ -12356,6 +12375,7 @@ function registerApi(app2, d) {
12356
12375
  const base2 = `http://${host2}:${port2}`;
12357
12376
  const ms = d.manager.status();
12358
12377
  const modelName = ms.state === "running" ? ms.model?.name ?? "local" : "local";
12378
+ const modelKey = ms.state === "running" ? ms.model?.key ?? modelName : modelName;
12359
12379
  let apiKey = "not-needed-on-localhost";
12360
12380
  if (lanBind) {
12361
12381
  const keyName = `cli-${cli}`;
@@ -12374,7 +12394,7 @@ function registerApi(app2, d) {
12374
12394
  });
12375
12395
  apiKey = full;
12376
12396
  }
12377
- return c.json(buildConnectSnippets(cli, base2, apiKey, modelName));
12397
+ return c.json(buildConnectSnippets(cli, base2, apiKey, modelName, modelKey));
12378
12398
  });
12379
12399
  }
12380
12400
  function overlayModel(e, d, lastTpsMap) {
@@ -12613,7 +12633,7 @@ function getLanIp() {
12613
12633
  }
12614
12634
  return "127.0.0.1";
12615
12635
  }
12616
- function buildConnectSnippets(cli, base2, apiKey, modelName) {
12636
+ function buildConnectSnippets(cli, base2, apiKey, modelName, modelKey = modelName) {
12617
12637
  switch (cli) {
12618
12638
  case "claude-code":
12619
12639
  return {
@@ -12642,6 +12662,11 @@ function buildConnectSnippets(cli, base2, apiKey, modelName) {
12642
12662
  cli,
12643
12663
  title: "opencode",
12644
12664
  steps: [
12665
+ {
12666
+ label: "Quickest \u2014 one command (ships with TurboLLM)",
12667
+ snippet: `turbollm launch opencode`,
12668
+ lang: "bash"
12669
+ },
12645
12670
  {
12646
12671
  label: "Merge into ~/.config/opencode/opencode.json",
12647
12672
  snippet: JSON.stringify(
@@ -12669,6 +12694,11 @@ function buildConnectSnippets(cli, base2, apiKey, modelName) {
12669
12694
  cli,
12670
12695
  title: "Kilo Code",
12671
12696
  steps: [
12697
+ {
12698
+ label: "Quickest \u2014 one command (ships with TurboLLM)",
12699
+ snippet: `turbollm launch kilo`,
12700
+ lang: "bash"
12701
+ },
12672
12702
  {
12673
12703
  label: "Add to ~/.config/kilo/kilo.jsonc providers array",
12674
12704
  snippet: JSON.stringify(
@@ -12687,6 +12717,61 @@ function buildConnectSnippets(cli, base2, apiKey, modelName) {
12687
12717
  }
12688
12718
  ]
12689
12719
  };
12720
+ case "openclaw":
12721
+ return {
12722
+ cli,
12723
+ title: "openclaw",
12724
+ steps: [
12725
+ {
12726
+ label: "Quickest \u2014 one command (ships with TurboLLM)",
12727
+ snippet: `turbollm launch openclaw`,
12728
+ lang: "bash"
12729
+ },
12730
+ {
12731
+ label: "Merge into ~/.config/openclaw/openclaw.json",
12732
+ snippet: JSON.stringify(
12733
+ {
12734
+ models: {
12735
+ providers: {
12736
+ turbollm: {
12737
+ baseUrl: `${base2}/v1`,
12738
+ apiKey: apiKey !== "not-needed-on-localhost" ? apiKey : "not-required",
12739
+ api: "openai-completions",
12740
+ models: [{ id: modelKey, name: modelName }]
12741
+ }
12742
+ }
12743
+ },
12744
+ agents: { defaults: { model: { primary: `turbollm/${modelKey}` } } }
12745
+ },
12746
+ null,
12747
+ 2
12748
+ ),
12749
+ lang: "json"
12750
+ }
12751
+ ]
12752
+ };
12753
+ case "hermes":
12754
+ return {
12755
+ cli,
12756
+ title: "Hermes Agent",
12757
+ steps: [
12758
+ {
12759
+ label: "Quickest \u2014 one command (ships with TurboLLM)",
12760
+ snippet: `turbollm launch hermes`,
12761
+ lang: "bash"
12762
+ },
12763
+ {
12764
+ label: "PowerShell",
12765
+ snippet: `hermes config set model.provider custom; hermes config set model.base_url ${base2}/v1; hermes config set model.default "${modelKey}"`,
12766
+ lang: "powershell"
12767
+ },
12768
+ {
12769
+ label: "bash / zsh",
12770
+ snippet: `hermes config set model.provider custom && hermes config set model.base_url ${base2}/v1 && hermes config set model.default "${modelKey}"`,
12771
+ lang: "bash"
12772
+ }
12773
+ ]
12774
+ };
12690
12775
  case "qwen":
12691
12776
  return {
12692
12777
  cli,
@@ -13661,10 +13746,10 @@ try {
13661
13746
  version = JSON.parse(readFileSync12(pkgPath, "utf8")).version ?? version;
13662
13747
  } catch {
13663
13748
  }
13664
- var nodeMajor = Number(process.versions.node.split(".")[0]);
13665
- if (nodeMajor < 22) {
13749
+ var [nodeMajor, nodeMinor] = process.versions.node.split(".").map(Number);
13750
+ if (nodeMajor < 22 || nodeMajor === 22 && nodeMinor < 13) {
13666
13751
  process.stderr.write(
13667
- `TurboLLM requires Node.js 22 or newer.
13752
+ `TurboLLM requires Node.js 22.13.0 or newer.
13668
13753
  You are running Node.js ${process.versions.node}.
13669
13754
  Please upgrade: https://nodejs.org
13670
13755
  `
@@ -1,2 +1,2 @@
1
- import{j as e}from"./radix-BY-fjzwm.js";import{r as u}from"./vendor-W5GIuFcv.js";import{c as w,d as k,A as T,u as v,L as h,e as S,a as b,f as C,g as q,X as A}from"./index-C-xjjrht.js";import{P as N}from"./plus-12BmUfjg.js";import{C as y}from"./circle-x-M54_eiYo.js";import{C as O}from"./circle-check-Dey3SdiG.js";import{W as E}from"./wrench-Chhk_zTw.js";const _=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}]],D=w("circle-dot",_);const L=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 6v6l4 2",key:"mmk7yg"}]],P=w("clock",L),p={all:["agent-runs"],list:()=>[...p.all,"list"],detail:t=>[...p.all,"detail",t]};async function g(t,a){const l={Accept:"application/json",...k(),...a?.headers??{}},i=await fetch(t,{...a,headers:l});if(i.status===204)return;const r=await i.text(),o=r?JSON.parse(r):void 0;if(!i.ok){const d=o;throw new T(d?.error?.code??"http_error",d?.error?.message??`Request failed with status ${i.status}.`,i.status)}return o}async function $(){return g("/api/v1/agents/runs")}async function I(t){return g(`/api/v1/agents/runs/${t}`)}async function Q(t){return g("/api/v1/agents/runs",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}async function K(t){await g(`/api/v1/agents/runs/${t}`,{method:"DELETE"})}async function*F(t,a=0,l){const i=`/api/v1/agents/runs/${t}/stream?fromSeq=${a}`,r=await fetch(i,{headers:{Accept:"text/event-stream",...k()},signal:l});if(!r.ok||!r.body)throw new Error(`Stream error: ${r.status}`);const o=r.body.getReader(),d=new TextDecoder;let m="";try{for(;;){const{done:s,value:x}=await o.read();if(s)break;m+=d.decode(x,{stream:!0});const c=m.split(`
1
+ import{j as e}from"./radix-BY-fjzwm.js";import{r as u}from"./vendor-W5GIuFcv.js";import{c as w,d as k,A as T,u as v,L as h,e as S,a as b,f as C,g as q,X as A}from"./index-CriwC5VH.js";import{P as N}from"./plus-BO3vGy6f.js";import{C as y}from"./circle-x-FM28MwOL.js";import{C as O}from"./circle-check-qnghY_qF.js";import{W as E}from"./wrench-Di5WLTz2.js";const _=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}]],D=w("circle-dot",_);const L=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 6v6l4 2",key:"mmk7yg"}]],P=w("clock",L),p={all:["agent-runs"],list:()=>[...p.all,"list"],detail:t=>[...p.all,"detail",t]};async function g(t,a){const l={Accept:"application/json",...k(),...a?.headers??{}},i=await fetch(t,{...a,headers:l});if(i.status===204)return;const r=await i.text(),o=r?JSON.parse(r):void 0;if(!i.ok){const d=o;throw new T(d?.error?.code??"http_error",d?.error?.message??`Request failed with status ${i.status}.`,i.status)}return o}async function $(){return g("/api/v1/agents/runs")}async function I(t){return g(`/api/v1/agents/runs/${t}`)}async function Q(t){return g("/api/v1/agents/runs",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}async function K(t){await g(`/api/v1/agents/runs/${t}`,{method:"DELETE"})}async function*F(t,a=0,l){const i=`/api/v1/agents/runs/${t}/stream?fromSeq=${a}`,r=await fetch(i,{headers:{Accept:"text/event-stream",...k()},signal:l});if(!r.ok||!r.body)throw new Error(`Stream error: ${r.status}`);const o=r.body.getReader(),d=new TextDecoder;let m="";try{for(;;){const{done:s,value:x}=await o.read();if(s)break;m+=d.decode(x,{stream:!0});const c=m.split(`
2
2
  `);m=c.pop()??"";let n="message";for(const f of c){if(f.startsWith("event: ")){n=f.slice(7).trim();continue}if(f.startsWith("data: ")){const j=f.slice(6).trim();if(j==="[DONE]")return;try{const R=JSON.parse(j);if(yield{event:n,data:R},n==="done"||n==="error")return}catch{}n="message"}}}}finally{o.cancel()}}const J={queued:e.jsx(P,{size:12}),running:e.jsx(h,{size:12,className:"animate-spin"}),done:e.jsx(O,{size:12}),failed:e.jsx(y,{size:12}),cancelled:e.jsx(y,{size:12}),interrupted:e.jsx(y,{size:12})},M={queued:"text-muted",running:"text-accent",done:"text-green-500",failed:"text-red-500",cancelled:"text-muted",interrupted:"text-orange-500"};function z({status:t}){return e.jsxs("span",{className:b("flex items-center gap-1 text-[11px] capitalize",M[t]),children:[J[t],t]})}function W(t){const a=Date.now()-new Date(t).getTime();return a<6e4?"just now":a<36e5?`${Math.floor(a/6e4)}m ago`:a<864e5?`${Math.floor(a/36e5)}h ago`:new Date(t).toLocaleDateString()}const U=[{id:"web_search",label:"Web search",hint:"Search the web (needs a provider configured in Settings)"},{id:"fetch_url",label:"Fetch URL",hint:"Read the contents of a web page"},{id:"run_code",label:"Run code",hint:"Execute JS in a sandbox — no mid-run confirmation, opt in only if you trust the task"}];function B({onClose:t,onCreated:a}){const[l,i]=u.useState(""),[r,o]=u.useState(""),[d,m]=u.useState({web_search:!0,fetch_url:!0,run_code:!1}),s=C(),x=n=>m(f=>({...f,[n]:!f[n]})),c=q({mutationFn:()=>Q({title:l.slice(0,60)||"Agent run",systemPrompt:r||void 0,userMessage:l,allowedTools:Object.entries(d).filter(([,n])=>n).map(([n])=>n)}),onSuccess:n=>{s.invalidateQueries({queryKey:p.list()}),a(n.id),t()}});return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/40",onClick:t,children:e.jsxs("div",{className:"w-full max-w-lg rounded-xl border border-border bg-panel p-5 shadow-xl",onClick:n=>n.stopPropagation(),children:[e.jsxs("div",{className:"mb-4 flex items-center justify-between",children:[e.jsx("h2",{className:"text-[15px] font-semibold",children:"New agent run"}),e.jsx("button",{type:"button",onClick:t,className:"text-faint hover:text-ink",children:e.jsx(A,{size:16})})]}),e.jsx("label",{className:"mb-1 block text-[12px] text-muted",children:"Task"}),e.jsx("textarea",{autoFocus:!0,value:l,onChange:n=>i(n.target.value),placeholder:"Describe what the agent should do…",rows:4,className:"mb-3 w-full resize-none rounded-lg border border-border bg-input px-3 py-2 text-[13px] text-ink placeholder:text-faint focus:border-accent focus:outline-none"}),e.jsxs("label",{className:"mb-1 block text-[12px] text-muted",children:["System prompt ",e.jsx("span",{className:"text-faint",children:"(optional)"})]}),e.jsx("textarea",{value:r,onChange:n=>o(n.target.value),placeholder:"You are a helpful assistant…",rows:2,className:"mb-4 w-full resize-none rounded-lg border border-border bg-input px-3 py-2 text-[13px] text-ink placeholder:text-faint focus:border-accent focus:outline-none"}),e.jsx("label",{className:"mb-1.5 block text-[12px] text-muted",children:"Tools"}),e.jsx("div",{className:"mb-4 space-y-1.5",children:U.map(n=>e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 rounded-lg border border-border px-2.5 py-2 hover:bg-panel-2",children:[e.jsx("input",{type:"checkbox",checked:d[n.id],onChange:()=>x(n.id),className:"mt-0.5 accent-[var(--accent)]"}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-[13px] font-medium text-ink",children:n.label}),e.jsx("span",{className:"block text-[11px] leading-snug text-faint",children:n.hint})]})]},n.id))}),e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx("button",{type:"button",onClick:t,className:"rounded-lg px-3 py-1.5 text-[13px] text-muted hover:text-ink",children:"Cancel"}),e.jsxs("button",{type:"button",disabled:!l.trim()||c.isPending,onClick:()=>c.mutate(),className:"flex items-center gap-1.5 rounded-lg bg-accent px-3 py-1.5 text-[13px] font-medium text-white disabled:opacity-50",children:[c.isPending?e.jsx(h,{size:13,className:"animate-spin"}):e.jsx(S,{size:13}),"Run agent"]})]}),c.isError&&e.jsx("p",{className:"mt-2 text-[12px]",style:{color:"var(--err)"},children:c.error.message})]})})}function X({call:t}){const[a,l]=u.useState(!1),i=typeof t.args?.query=="string"?t.args.query:typeof t.args?.url=="string"?t.args.url:JSON.stringify(t.args??{});return e.jsxs("div",{className:"w-full max-w-[85%] rounded-lg border border-border bg-panel px-2.5 py-1.5 text-[12px]",children:[e.jsxs("button",{type:"button",onClick:()=>l(r=>!r),className:"flex w-full items-center gap-1.5 text-left text-muted hover:text-ink",children:[e.jsx(E,{size:12,className:"shrink-0 text-accent"}),e.jsx("span",{className:"font-medium text-ink",children:t.name}),e.jsx("span",{className:"truncate text-faint",children:i})]}),a&&e.jsx("pre",{className:"mt-1.5 max-h-48 overflow-auto whitespace-pre-wrap break-words rounded bg-panel-2 p-2 text-[11px] text-muted",children:t.result})]})}function H({run:t}){const a=C(),l=u.useRef(null),[i,r]=u.useState(""),o=u.useRef(null),d=q({mutationFn:()=>K(t.id),onSuccess:()=>{a.invalidateQueries({queryKey:p.list()})}});u.useEffect(()=>{if(t.status!=="running"&&t.status!=="queued")return;const s=new AbortController;l.current=s;let x="";return(async()=>{try{for await(const c of F(t.id,0,s.signal))if(c.event==="delta")x+=c.data.delta,r(x);else if(c.event==="done"||c.event==="error"){r(""),a.invalidateQueries({queryKey:p.detail(t.id)}),a.invalidateQueries({queryKey:p.list()});break}}catch{}})(),()=>{s.abort(),l.current=null}},[t.id,t.status,a]),u.useEffect(()=>{o.current?.scrollIntoView({behavior:"smooth"})},[i,t.messages?.length]);const m=t.messages??[];return e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-border px-4 py-2.5",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[14px] font-medium text-ink",children:t.title}),e.jsx(z,{status:t.status})]}),(t.status==="running"||t.status==="queued")&&e.jsx("button",{type:"button",onClick:()=>d.mutate(),className:"rounded-lg border border-border px-3 py-1 text-[12px] text-muted transition-colors hover:border-red-400 hover:text-red-500",children:d.isPending?e.jsx(h,{size:12,className:"inline animate-spin"}):"Cancel"})]}),e.jsxs("div",{className:"flex-1 space-y-3 overflow-y-auto p-4",children:[m.map(s=>e.jsxs("div",{className:b("flex flex-col gap-1.5",s.role==="user"?"items-end":"items-start"),children:[s.toolCalls?.map(x=>e.jsx(X,{call:x},x.id)),(s.content||s.role==="user"||t.status==="running")&&e.jsx("div",{className:b("max-w-[85%] rounded-xl px-3 py-2 text-[13px] leading-relaxed",s.role==="user"?"bg-accent/15 text-ink":"bg-panel-2 text-ink"),children:e.jsx("p",{className:"whitespace-pre-wrap break-words",children:s.content||(s.role==="assistant"&&t.status==="running"?"…":"")})})]},s.id)),i&&e.jsx("div",{className:"flex gap-2",children:e.jsx("div",{className:"max-w-[85%] rounded-xl bg-panel-2 px-3 py-2 text-[13px] leading-relaxed text-ink",children:e.jsx("p",{className:"whitespace-pre-wrap break-words",children:i})})}),t.error&&e.jsxs("div",{className:"rounded-lg bg-red-500/10 px-3 py-2 text-[12px] text-red-500",children:["Error: ",t.error]}),e.jsx("div",{ref:o})]})]})}function ne(){const[t,a]=u.useState(null),[l,i]=u.useState(!1),r=v({queryKey:p.list(),queryFn:$,refetchInterval:s=>(s.state.data??[]).some(n=>n.status==="queued"||n.status==="running")?3e3:!1}),o=v({queryKey:p.detail(t??""),queryFn:()=>I(t),enabled:!!t,refetchInterval:s=>{const x=s.state.data;return x?.status==="queued"||x?.status==="running"?5e3:!1}}),d=r.data??[],m=o.data;return e.jsxs("div",{className:"flex h-full",children:[e.jsxs("div",{className:"flex w-64 shrink-0 flex-col border-r border-border",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-border px-3 py-2.5",children:[e.jsx("span",{className:"text-[13px] font-semibold text-ink",children:"Agents"}),e.jsxs("button",{type:"button",title:"New agent run",onClick:()=>i(!0),className:"flex items-center gap-1 rounded-lg bg-accent px-2 py-1 text-[11px] font-medium text-white transition-opacity hover:opacity-90",children:[e.jsx(N,{size:11})," New"]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[r.isLoading&&e.jsx("div",{className:"flex h-20 items-center justify-center",children:e.jsx(h,{size:16,className:"animate-spin text-faint"})}),d.length===0&&!r.isLoading&&e.jsxs("div",{className:"px-4 py-8 text-center",children:[e.jsx(S,{size:28,className:"mx-auto mb-2 text-faint"}),e.jsx("p",{className:"text-[12px] text-muted",children:"No agent runs yet."}),e.jsx("p",{className:"mt-0.5 text-[11px] text-faint",children:"Click “New” to start one."})]}),d.map(s=>e.jsxs("button",{type:"button",onClick:()=>a(s.id),className:b("w-full border-b border-border px-3 py-2.5 text-left transition-colors hover:bg-panel-2",t===s.id&&"bg-panel-2"),children:[e.jsx("p",{className:"mb-0.5 truncate text-[13px] font-medium text-ink",children:s.title}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(z,{status:s.status}),e.jsx("span",{className:"text-[10px] text-faint",children:W(s.createdAt)})]})]},s.id))]})]}),e.jsx("div",{className:"flex min-w-0 flex-1 flex-col",children:t?o.isLoading?e.jsx("div",{className:"flex h-full items-center justify-center",children:e.jsx(h,{size:20,className:"animate-spin text-faint"})}):m?e.jsx(H,{run:m}):null:e.jsxs("div",{className:"flex h-full flex-col items-center justify-center text-center",children:[e.jsx(D,{size:32,className:"mb-3 text-faint"}),e.jsx("p",{className:"text-[14px] font-medium text-ink",children:"Select a run"}),e.jsx("p",{className:"mt-1 text-[12px] text-muted",children:"or create a new agent run to get started"}),e.jsxs("button",{type:"button",onClick:()=>i(!0),className:"mt-4 flex items-center gap-1.5 rounded-lg bg-accent px-3 py-1.5 text-[13px] font-medium text-white hover:opacity-90",children:[e.jsx(N,{size:13})," New agent run"]})]})}),l&&e.jsx(B,{onClose:()=>i(!1),onCreated:s=>{a(s),r.refetch()}})]})}export{ne as AgentsScreen};