turbollm 1.6.1 → 1.6.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 (104) hide show
  1. package/LICENSE.md +105 -105
  2. package/README.md +7 -4
  3. package/bin/turbollm.mjs +25 -25
  4. package/dist/cli.js +194 -41
  5. package/dist/webdist/assets/{AgentsScreen-Bm0dlNUs.js → AgentsScreen-BviDj463.js} +1 -1
  6. package/dist/webdist/assets/ChatScreen-4a_6ZX6c.js +29 -0
  7. package/dist/webdist/assets/CustomizeScreen-BhZJK7xv.js +4 -0
  8. package/dist/webdist/assets/{DeveloperScreen-EeXXJhPl.js → DeveloperScreen-8CVekggw.js} +1 -1
  9. package/dist/webdist/assets/EnginesScreen-zHLzht8k.js +7 -0
  10. package/dist/webdist/assets/ModelDetailDialog-DjMSf0rz.js +29 -0
  11. package/dist/webdist/assets/{ModelDirs-ChNMfQlk.js → ModelDirs-CIOcl5qu.js} +1 -1
  12. package/dist/webdist/assets/ModelsScreen-v7kDcWmr.js +2 -0
  13. package/dist/webdist/assets/{SettingsScreen-fyDtvMAN.js → SettingsScreen-DnSgBps7.js} +1 -1
  14. package/dist/webdist/assets/alert-dialog-93rFXd1_.js +1 -0
  15. package/dist/webdist/assets/{arc-CuIEySlm.js → arc-BFc9YP9w.js} +1 -1
  16. package/dist/webdist/assets/{architectureDiagram-3BPJPVTR-CDtTHNKE.js → architectureDiagram-3BPJPVTR-Bd6WFbHz.js} +1 -1
  17. package/dist/webdist/assets/{arrow-left-BhWtMEXH.js → arrow-left--NjoPnor.js} +1 -1
  18. package/dist/webdist/assets/{blockDiagram-GPEHLZMM--Dy7JNXf.js → blockDiagram-GPEHLZMM-Dupawk92.js} +1 -1
  19. package/dist/webdist/assets/{c4Diagram-AAUBKEIU-XVnczljG.js → c4Diagram-AAUBKEIU-BMhAUE8i.js} +1 -1
  20. package/dist/webdist/assets/channel-BCSKocRg.js +1 -0
  21. package/dist/webdist/assets/check-Bu2UFiB0.js +1 -0
  22. package/dist/webdist/assets/chevron-right-kiIQKgde.js +1 -0
  23. package/dist/webdist/assets/{chunk-2J33WTMH-C077hTl3.js → chunk-2J33WTMH-BhxySqcq.js} +1 -1
  24. package/dist/webdist/assets/{chunk-4BX2VUAB-DKdVCoaf.js → chunk-4BX2VUAB-B-UGkx88.js} +1 -1
  25. package/dist/webdist/assets/{chunk-55IACEB6-COscQ2lU.js → chunk-55IACEB6-BDvjmk8T.js} +1 -1
  26. package/dist/webdist/assets/{chunk-727SXJPM-DWN7NXCr.js → chunk-727SXJPM-BhyFFQxZ.js} +1 -1
  27. package/dist/webdist/assets/{chunk-AQP2D5EJ-DunZhDts.js → chunk-AQP2D5EJ-VTSW3fZJ.js} +1 -1
  28. package/dist/webdist/assets/{chunk-FMBD7UC4-Cs40cRbK.js → chunk-FMBD7UC4-QKx1b_-m.js} +1 -1
  29. package/dist/webdist/assets/{chunk-ND2GUHAM-DpXYV_RZ.js → chunk-ND2GUHAM-DZANzpY0.js} +1 -1
  30. package/dist/webdist/assets/{chunk-QZHKN3VN-D6BC_875.js → chunk-QZHKN3VN-DVZIy115.js} +1 -1
  31. package/dist/webdist/assets/circle-check-C4aACGyb.js +1 -0
  32. package/dist/webdist/assets/circle-x-koFsrlGA.js +1 -0
  33. package/dist/webdist/assets/classDiagram-4FO5ZUOK-B_Eb_jRj.js +1 -0
  34. package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-B_Eb_jRj.js +1 -0
  35. package/dist/webdist/assets/common-CQVogVIs.js +1 -0
  36. package/dist/webdist/assets/{copy-button-BDBGYJyK.js → copy-button-3_2Us2zb.js} +1 -1
  37. package/dist/webdist/assets/{cose-bilkent-S5V4N54A-CBdxwvXL.js → cose-bilkent-S5V4N54A-Ci07N3_4.js} +1 -1
  38. package/dist/webdist/assets/{dagre-BM42HDAG--TuZmFxK.js → dagre-BM42HDAG-45qc0phu.js} +1 -1
  39. package/dist/webdist/assets/{diagram-2AECGRRQ-CBd1wCAj.js → diagram-2AECGRRQ-DA3u3hzE.js} +1 -1
  40. package/dist/webdist/assets/{diagram-5GNKFQAL-CGhx3UWE.js → diagram-5GNKFQAL-B3wpvPKp.js} +1 -1
  41. package/dist/webdist/assets/{diagram-KO2AKTUF-Cao3Duro.js → diagram-KO2AKTUF-h1qR3ckq.js} +1 -1
  42. package/dist/webdist/assets/{diagram-LMA3HP47-WjRqqdMT.js → diagram-LMA3HP47-B3uU2roT.js} +1 -1
  43. package/dist/webdist/assets/{diagram-OG6HWLK6-2ox056u5.js → diagram-OG6HWLK6-CibVtZrO.js} +1 -1
  44. package/dist/webdist/assets/dialog-Dn3dxmMP.js +1 -0
  45. package/dist/webdist/assets/{erDiagram-TEJ5UH35-ArZ5ZZJa.js → erDiagram-TEJ5UH35-VsHZBAOZ.js} +1 -1
  46. package/dist/webdist/assets/{flowDiagram-I6XJVG4X-B9tLKPOZ.js → flowDiagram-I6XJVG4X-DhYah8sF.js} +1 -1
  47. package/dist/webdist/assets/{ganttDiagram-6RSMTGT7-C-N7wsLt.js → ganttDiagram-6RSMTGT7-RPkNEJnH.js} +1 -1
  48. package/dist/webdist/assets/{gitGraphDiagram-PVQCEYII-WMWkUM9v.js → gitGraphDiagram-PVQCEYII-JknfsYQp.js} +1 -1
  49. package/dist/webdist/assets/index-5NYGYU_t.css +1 -0
  50. package/dist/webdist/assets/{index-BEuak5p5.js → index-K2ZQBdky.js} +4 -4
  51. package/dist/webdist/assets/{infoDiagram-5YYISTIA-cGx1kqp-.js → infoDiagram-5YYISTIA-BeGMPySd.js} +1 -1
  52. package/dist/webdist/assets/{ishikawaDiagram-YF4QCWOH-CKuSQqaZ.js → ishikawaDiagram-YF4QCWOH-D38Q1-tz.js} +1 -1
  53. package/dist/webdist/assets/{journeyDiagram-JHISSGLW-3nxSzaVj.js → journeyDiagram-JHISSGLW-CG8TFzp6.js} +1 -1
  54. package/dist/webdist/assets/{kanban-definition-UN3LZRKU-_hSS8ZRB.js → kanban-definition-UN3LZRKU-CNgUZ1rd.js} +1 -1
  55. package/dist/webdist/assets/{linear-DcWs5d6j.js → linear-DYIxmEeo.js} +1 -1
  56. package/dist/webdist/assets/{mermaid.core-vZsS4NJL.js → mermaid.core-CZhJJFjL.js} +4 -4
  57. package/dist/webdist/assets/{mindmap-definition-RKZ34NQL-DB5Mtp7f.js → mindmap-definition-RKZ34NQL-BIVYSbvh.js} +1 -1
  58. package/dist/webdist/assets/pencil-iVnKKeCp.js +1 -0
  59. package/dist/webdist/assets/{personas-DdUgL1dH.js → personas-DslX_qdt.js} +4 -4
  60. package/dist/webdist/assets/{pieDiagram-4H26LBE5-C1qmat-q.js → pieDiagram-4H26LBE5-CU9qALXo.js} +1 -1
  61. package/dist/webdist/assets/plus-mSm32jpN.js +1 -0
  62. package/dist/webdist/assets/{quadrantDiagram-W4KKPZXB-Boa-e85b.js → quadrantDiagram-W4KKPZXB-AE50YmvR.js} +1 -1
  63. package/dist/webdist/assets/{radix-4XwKfE88.js → radix-9WP-OkMY.js} +2 -2
  64. package/dist/webdist/assets/refresh-cw-C04dn1r1.js +1 -0
  65. package/dist/webdist/assets/{requirementDiagram-4Y6WPE33-Bmp1KNz5.js → requirementDiagram-4Y6WPE33-Crymka5P.js} +1 -1
  66. package/dist/webdist/assets/{sankeyDiagram-5OEKKPKP-BW5ZiXqU.js → sankeyDiagram-5OEKKPKP-DRviwCen.js} +1 -1
  67. package/dist/webdist/assets/save-BT2nzRB6.js +1 -0
  68. package/dist/webdist/assets/{sequenceDiagram-3UESZ5HK-Dqsa-4BM.js → sequenceDiagram-3UESZ5HK-DuBllsfJ.js} +1 -1
  69. package/dist/webdist/assets/skeleton-BfMJjCGZ.js +1 -0
  70. package/dist/webdist/assets/{stateDiagram-AJRCARHV-BBfHSXy1.js → stateDiagram-AJRCARHV-Cj4BwRLl.js} +1 -1
  71. package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-Y25sKBZm.js +1 -0
  72. package/dist/webdist/assets/{timeline-definition-PNZ67QCA-BHarWHkU.js → timeline-definition-PNZ67QCA-BWnH2-RY.js} +1 -1
  73. package/dist/webdist/assets/trash-2-Ce39UFy5.js +1 -0
  74. package/dist/webdist/assets/{vendor-CKtmMAvG.js → vendor-W5GIuFcv.js} +1 -1
  75. package/dist/webdist/assets/{vennDiagram-CIIHVFJN-DTvjLJ1x.js → vennDiagram-CIIHVFJN-GgdSx9c7.js} +1 -1
  76. package/dist/webdist/assets/{wardley-L42UT6IY-DOFy2Cyi.js → wardley-L42UT6IY-C9XKbMb6.js} +1 -1
  77. package/dist/webdist/assets/{wardleyDiagram-YWT4CUSO-FMOMz9fW.js → wardleyDiagram-YWT4CUSO-ZxceNtWm.js} +1 -1
  78. package/dist/webdist/assets/{wrench-C8ZOI3oB.js → wrench-Ceqe74n2.js} +1 -1
  79. package/dist/webdist/assets/{xychartDiagram-2RQKCTM6-pxISvXSk.js → xychartDiagram-2RQKCTM6-C-mAbbHW.js} +1 -1
  80. package/dist/webdist/favicon.svg +4 -4
  81. package/dist/webdist/index.html +20 -20
  82. package/package.json +1 -1
  83. package/dist/webdist/assets/ChatScreen-De7mfm87.js +0 -57
  84. package/dist/webdist/assets/CustomizeScreen-BhJkwqO1.js +0 -4
  85. package/dist/webdist/assets/EnginesScreen-4MCxOhkl.js +0 -7
  86. package/dist/webdist/assets/ModelDetailDialog-BhySVphP.js +0 -1
  87. package/dist/webdist/assets/ModelsScreen-DSZhXs2J.js +0 -1
  88. package/dist/webdist/assets/channel-C4W_mju9.js +0 -1
  89. package/dist/webdist/assets/check-BJnna3cY.js +0 -1
  90. package/dist/webdist/assets/chevron-right-DJQHNjeM.js +0 -1
  91. package/dist/webdist/assets/circle-check-CYzq3xdq.js +0 -1
  92. package/dist/webdist/assets/circle-x-A-lKHO2r.js +0 -1
  93. package/dist/webdist/assets/classDiagram-4FO5ZUOK-CcUXUVK5.js +0 -1
  94. package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-CcUXUVK5.js +0 -1
  95. package/dist/webdist/assets/common-Bs-nRFXO.js +0 -1
  96. package/dist/webdist/assets/dialog-CxAGijbe.js +0 -1
  97. package/dist/webdist/assets/index-CJj8sGhF.css +0 -1
  98. package/dist/webdist/assets/pencil-BC_D38u5.js +0 -1
  99. package/dist/webdist/assets/plus-CYdaHYzw.js +0 -1
  100. package/dist/webdist/assets/refresh-cw-CAf-srhC.js +0 -1
  101. package/dist/webdist/assets/save-CuovAu9V.js +0 -1
  102. package/dist/webdist/assets/skeleton-sJWGKoPW.js +0 -1
  103. package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-DHCBzQwe.js +0 -1
  104. package/dist/webdist/assets/trash-2-BxB6A4uU.js +0 -1
package/LICENSE.md CHANGED
@@ -1,105 +1,105 @@
1
- # Functional Source License, Version 1.1, ALv2 Future License
2
-
3
- ## Abbreviation
4
-
5
- FSL-1.1-ALv2
6
-
7
- ## Notice
8
-
9
- Copyright 2026 Mohit Soni
10
-
11
- ## Terms and Conditions
12
-
13
- ### Licensor ("We")
14
-
15
- The party offering the Software under these Terms and Conditions.
16
-
17
- ### The Software
18
-
19
- The "Software" is each version of the software that we make available under
20
- these Terms and Conditions, as indicated by our inclusion of these Terms and
21
- Conditions with the Software.
22
-
23
- ### License Grant
24
-
25
- Subject to your compliance with this License Grant and the Patents,
26
- Redistribution and Trademark clauses below, we hereby grant you the right to
27
- use, copy, modify, create derivative works, publicly perform, publicly display
28
- and redistribute the Software for any Permitted Purpose identified below.
29
-
30
- ### Permitted Purpose
31
-
32
- A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
- means making the Software available to others in a commercial product or
34
- service that:
35
-
36
- 1. substitutes for the Software;
37
-
38
- 2. substitutes for any other product or service we offer using the Software
39
- that exists as of the date we make the Software available; or
40
-
41
- 3. offers the same or substantially similar functionality as the Software.
42
-
43
- Permitted Purposes specifically include using the Software:
44
-
45
- 1. for your internal use and access;
46
-
47
- 2. for non-commercial education;
48
-
49
- 3. for non-commercial research; and
50
-
51
- 4. in connection with professional services that you provide to a licensee
52
- using the Software in accordance with these Terms and Conditions.
53
-
54
- ### Patents
55
-
56
- To the extent your use for a Permitted Purpose would necessarily infringe our
57
- patents, the license grant above includes a license under our patents. If you
58
- make a claim against any party that the Software infringes or contributes to
59
- the infringement of any patent, then your patent license to the Software ends
60
- immediately.
61
-
62
- ### Redistribution
63
-
64
- The Terms and Conditions apply to all copies, modifications and derivatives of
65
- the Software.
66
-
67
- If you redistribute any copies, modifications or derivatives of the Software,
68
- you must include a copy of or a link to these Terms and Conditions and not
69
- remove any copyright notices provided in or with the Software.
70
-
71
- ### Disclaimer
72
-
73
- THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
- IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
- PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
-
77
- IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
- SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
- EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
-
81
- ### Trademarks
82
-
83
- Except for displaying the License Details and identifying us as the origin of
84
- the Software, you have no right under these Terms and Conditions to use our
85
- trademarks, trade names, service marks or product names.
86
-
87
- ## Grant of Future License
88
-
89
- We hereby irrevocably grant you an additional license to use the Software under
90
- the Apache License, Version 2.0 that is effective on the second anniversary of
91
- the date we make the Software available. On or after that date, you may use the
92
- Software under the Apache License, Version 2.0, in which case the following
93
- will apply:
94
-
95
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
- this file except in compliance with the License.
97
-
98
- You may obtain a copy of the License at
99
-
100
- http://www.apache.org/licenses/LICENSE-2.0
101
-
102
- Unless required by applicable law or agreed to in writing, software distributed
103
- under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
- CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
- specific language governing permissions and limitations under the License.
1
+ # Functional Source License, Version 1.1, ALv2 Future License
2
+
3
+ ## Abbreviation
4
+
5
+ FSL-1.1-ALv2
6
+
7
+ ## Notice
8
+
9
+ Copyright 2026 Mohit Soni
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the Apache License, Version 2.0 that is effective on the second anniversary of
91
+ the date we make the Software available. On or after that date, you may use the
92
+ Software under the Apache License, Version 2.0, in which case the following
93
+ will apply:
94
+
95
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
+ this file except in compliance with the License.
97
+
98
+ You may obtain a copy of the License at
99
+
100
+ http://www.apache.org/licenses/LICENSE-2.0
101
+
102
+ Unless required by applicable law or agreed to in writing, software distributed
103
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
+ specific language governing permissions and limitations under the License.
package/README.md CHANGED
@@ -136,9 +136,10 @@ the detail:
136
136
  - **Use the folders you already have.** Point TurboLLM at any directory of GGUFs — your
137
137
  existing LM Studio / Ollama / manual downloads — **no re-downloading.** It parses GGUF
138
138
  metadata (arch, params, quant, context, vision) for every file.
139
- - **Browse & download from Hugging Face**, in-app: search, see the file tree, pick a quant,
140
- and download with **resume + SHA-256 verification**. Gated models (Llama, Gemma) work via
141
- your own HF token, which **never leaves your machine**.
139
+ - **Browse & download from Hugging Face**, in-app: a live, sortable list (trending / downloads
140
+ / likes / recently updated / newest) alongside a permanent detail pane — pick a quant, read
141
+ the **rendered model card**, and download with **resume + SHA-256 verification**. Gated
142
+ models (Llama, Gemma) work via your own HF token, which **never leaves your machine**.
142
143
  - **Import from any URL** — not just Hugging Face. Paste a direct `.gguf` link (model-author
143
144
  sites, mirrors, private servers); it disk-space-checks and downloads through the same manager.
144
145
  - **Quant recommendation per GPU** and a **VRAM-fit verdict** so you pick a quant that
@@ -319,7 +320,9 @@ the engine as a swappable component.
319
320
  support are hidden; ones it adds (e.g. low-bit KV cache, NextN) light up.
320
321
 
321
322
  No prebuilt for your OS? The **build-from-source guide** checks your toolchain (git / CMake /
322
- CUDA / MSVC), hands you the exact build commands, then drops you into the folder scan above.
323
+ CUDA / a compiler — MSVC on Windows, gcc/clang on Linux), hands you the exact build commands
324
+ (or a 1-click **"Build it for me"** on Windows and Linux), then drops you into the folder scan
325
+ above.
323
326
 
324
327
  **Auto-provisioned default.** Don't want to fetch anything? On first run TurboLLM downloads
325
328
  the right upstream prebuilt for your GPU automatically — and a **backend picker** lets you
package/bin/turbollm.mjs CHANGED
@@ -1,25 +1,25 @@
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+).
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')
package/dist/cli.js CHANGED
@@ -1427,7 +1427,12 @@ function readinessTimeoutMs(kind) {
1427
1427
  return kind === "vllm" || kind === "sglang" ? 6e5 : 12e4;
1428
1428
  }
1429
1429
  function pyEngineEnv(kind, dataDir, binPath) {
1430
- if (kind !== "mlx" && kind !== "vllm" && kind !== "sglang") return void 0;
1430
+ if (kind !== "mlx" && kind !== "vllm" && kind !== "sglang") {
1431
+ if (process.platform === "win32") return void 0;
1432
+ const dir = dirname2(binPath);
1433
+ const existing = process.env.LD_LIBRARY_PATH;
1434
+ return { ...process.env, LD_LIBRARY_PATH: existing ? `${dir}:${existing}` : dir };
1435
+ }
1431
1436
  const hfHome = join9(dataDir, "hf-cache");
1432
1437
  const hubCache = join9(hfHome, "hub");
1433
1438
  mkdirSync6(hubCache, { recursive: true });
@@ -4148,6 +4153,28 @@ var HfError = class extends Error {
4148
4153
  }
4149
4154
  code;
4150
4155
  };
4156
+ var SORT_PARAM = {
4157
+ trending: "trendingScore",
4158
+ downloads: "downloads",
4159
+ likes: "likes",
4160
+ modified: "lastModified",
4161
+ created: "createdAt"
4162
+ };
4163
+ function libraryFilterFor(engineKind) {
4164
+ if (engineKind === "mlx") return "filter=mlx&";
4165
+ if (engineKind === "vllm") return "";
4166
+ return "filter=gguf&";
4167
+ }
4168
+ function toSearchItem(m) {
4169
+ return {
4170
+ repo: m.id ?? m.modelId ?? "",
4171
+ downloads: m.downloads ?? 0,
4172
+ likes: m.likes ?? 0,
4173
+ updatedAt: m.lastModified ?? m.createdAt ?? "",
4174
+ gated: m.gated === true || m.gated === "auto" || m.gated === "manual",
4175
+ tags: Array.isArray(m.tags) ? m.tags : []
4176
+ };
4177
+ }
4151
4178
  var SPLIT_RE2 = /^(.*)-(\d{5})-of-(\d{5})\.gguf$/i;
4152
4179
  var HfClient = class {
4153
4180
  constructor(tokenFn, version2) {
@@ -4157,24 +4184,26 @@ var HfClient = class {
4157
4184
  tokenFn;
4158
4185
  version;
4159
4186
  cache = /* @__PURE__ */ new Map();
4160
- /** Search repos (spec 10 §2). Returns up to 30 rows sorted by downloads.
4161
- * Format filter adapts to the active engine kind:
4162
- * - llama-server / TurboQuant filter=gguf
4163
- * - mlx → filter=mlx (HF library tag)
4164
- * - vllm → no format filter (searches all HF repos) */
4165
- async searchModels(query, engineKind) {
4187
+ /** Search repos by text (spec 10 §2). Returns up to 30 rows. `sort` defaults to HF's own
4188
+ * relevance ranking ('best-match' omits `sort=` entirely, a genuinely different order
4189
+ * from `sort=downloads`, not just an alias for it). Format filter adapts to the active
4190
+ * engine kind (never hardcoded to GGUF) — see {@link libraryFilterFor}. */
4191
+ async searchModels(query, engineKind, sort = "best-match") {
4166
4192
  const q = query.trim();
4167
- const formatFilter = engineKind === "mlx" ? "&filter=mlx" : engineKind === "vllm" ? "" : "&filter=gguf";
4168
- const url = `${BASE}/api/models?search=${encodeURIComponent(q)}${formatFilter}&sort=downloads&direction=-1&limit=30&full=false`;
4193
+ const sortParam = sort === "best-match" ? "" : `sort=${SORT_PARAM[sort]}&direction=-1&`;
4194
+ const url = `${BASE}/api/models?search=${encodeURIComponent(q)}&${libraryFilterFor(engineKind)}${sortParam}limit=30&full=false`;
4169
4195
  const raw = await this.getJson(url);
4170
- return raw.map((m) => ({
4171
- repo: m.id ?? m.modelId ?? "",
4172
- downloads: m.downloads ?? 0,
4173
- likes: m.likes ?? 0,
4174
- updatedAt: m.lastModified ?? m.createdAt ?? "",
4175
- gated: m.gated === true || m.gated === "auto" || m.gated === "manual",
4176
- tags: Array.isArray(m.tags) ? m.tags : []
4177
- }));
4196
+ return raw.map(toSearchItem);
4197
+ }
4198
+ /** Browse repos with no search term (spec 10 §7 rewrite) — the live equivalent of
4199
+ * https://huggingface.co/models?library=gguf&sort=trending, replacing what used to be a
4200
+ * hardcoded "Featured" list. 'best-match' has no meaning without a query, so it falls
4201
+ * back to 'trending'. Format filter adapts to the active engine kind, same as search. */
4202
+ async browseModels(sort, engineKind, limit = 30) {
4203
+ const effective = sort === "best-match" ? "trending" : sort;
4204
+ const url = `${BASE}/api/models?${libraryFilterFor(engineKind)}sort=${SORT_PARAM[effective]}&direction=-1&limit=${limit}&full=false`;
4205
+ const raw = await this.getJson(url);
4206
+ return raw.map(toSearchItem);
4178
4207
  }
4179
4208
  /** Repo detail (spec 10 §3): card data + the GGUF file tree, with split parts
4180
4209
  * grouped and quant/mmproj detected per file. */
@@ -9123,6 +9152,36 @@ var ALL = [
9123
9152
  // install endpoint of its own.
9124
9153
  installEndpoint: ""
9125
9154
  },
9155
+ {
9156
+ // Upstream publishes NO Linux CUDA prebuilt (download.ts availableBackends() — Linux
9157
+ // NVIDIA users get Vulkan from the main llama.cpp entry above). Now that the guided
9158
+ // build (ADR-100/build-runner.ts) runs on Linux too, offer official llama.cpp + CUDA
9159
+ // there as its own "build from source" card — same guided-build flow as ik_llama.cpp/
9160
+ // TurboQuant below, just pointed at the official repo. Windows/macOS never see this
9161
+ // (platforms:['linux']): Windows already gets a CUDA prebuilt, and macOS has no CUDA.
9162
+ id: "llama.cpp-cuda-linux",
9163
+ name: "llama.cpp (CUDA)",
9164
+ kind: "llama-server",
9165
+ description: "Official llama.cpp compiled with CUDA for NVIDIA GPUs on Linux \u2014 no prebuilt is published upstream, so this uses the guided in-app build.",
9166
+ provision: "github-release",
9167
+ homepage: "https://github.com/ggml-org/llama.cpp",
9168
+ repo: "ggml-org/llama.cpp",
9169
+ platforms: ["linux"],
9170
+ support: "experimental",
9171
+ installEndpoint: "",
9172
+ note: "Builds the official repo with -DGGML_CUDA=ON and bundles its CUDA runtime libraries next to the binary, so it runs standalone. Manages like any other engine afterward (rebuild on a newer commit, disable, delete).",
9173
+ variants: [
9174
+ {
9175
+ id: "llama.cpp-cuda-source",
9176
+ label: "CUDA (NVIDIA) \u2014 build from source",
9177
+ repo: "ggml-org/llama.cpp",
9178
+ requires: { platform: ["linux"], gpuVendor: ["nvidia"] },
9179
+ stability: "experimental",
9180
+ speed: "fast",
9181
+ hasPrebuilt: false
9182
+ }
9183
+ ]
9184
+ },
9126
9185
  {
9127
9186
  id: "vllm",
9128
9187
  name: "vLLM",
@@ -9377,7 +9436,8 @@ var INSTALL_URLS = {
9377
9436
  cmake: "https://cmake.org/download/",
9378
9437
  cuda: "https://developer.nvidia.com/cuda-downloads",
9379
9438
  // The "Desktop development with C++" workload from the VS Build Tools installer.
9380
- msvc: "https://visualstudio.microsoft.com/downloads/"
9439
+ msvc: "https://visualstudio.microsoft.com/downloads/",
9440
+ gcc: "https://gcc.gnu.org/install/"
9381
9441
  };
9382
9442
  async function runVersion(cmd, args, env) {
9383
9443
  const { stdout, stderr } = await execFileP5(cmd, args, {
@@ -9400,6 +9460,10 @@ function parseNvccVersion(out) {
9400
9460
  const m = out.match(/release\s+([\d.]+)/i);
9401
9461
  return m ? m[1] : "";
9402
9462
  }
9463
+ function parseCompilerVersion(out) {
9464
+ const m = out.match(/(?:g\+\+|gcc|clang(?:\+\+)?)[^\d]*(\d+(?:\.\d+)*)/i);
9465
+ return m ? m[1] : "";
9466
+ }
9403
9467
  async function checkGit(env) {
9404
9468
  let found = false;
9405
9469
  let version2;
@@ -9461,13 +9525,30 @@ async function checkMsvc(env) {
9461
9525
  installUrl: INSTALL_URLS.msvc
9462
9526
  };
9463
9527
  }
9528
+ async function checkGcc(env) {
9529
+ let found = false;
9530
+ let version2;
9531
+ try {
9532
+ version2 = parseCompilerVersion(await runVersion("g++", ["--version"], env)) || void 0;
9533
+ found = true;
9534
+ } catch {
9535
+ try {
9536
+ version2 = parseCompilerVersion(await runVersion("clang++", ["--version"], env)) || void 0;
9537
+ found = true;
9538
+ } catch {
9539
+ found = false;
9540
+ }
9541
+ }
9542
+ return { id: "gcc", name: "C++ compiler (g++/clang++)", found, version: version2, installUrl: INSTALL_URLS.gcc };
9543
+ }
9464
9544
  async function checkBuildPrereqs(toolchainDirs = []) {
9465
- if (process.platform !== "win32") {
9466
- return { supported: false, tools: [] };
9545
+ const platform = process.platform;
9546
+ if (platform !== "win32" && platform !== "linux") {
9547
+ return { supported: false, os: "other", tools: [] };
9467
9548
  }
9468
9549
  const env = buildEnv(toolchainDirs);
9469
- const tools = await Promise.all([checkGit(env), checkCmake(env), checkCuda(env), checkMsvc(env)]);
9470
- return { supported: true, tools };
9550
+ const tools = platform === "win32" ? await Promise.all([checkGit(env), checkCmake(env), checkCuda(env), checkMsvc(env)]) : await Promise.all([checkGit(env), checkCmake(env), checkCuda(env), checkGcc(env)]);
9551
+ return { supported: true, os: platform === "win32" ? "windows" : "linux", tools };
9471
9552
  }
9472
9553
 
9473
9554
  // src/engines/build-runner.ts
@@ -9497,8 +9578,9 @@ function sourceBuildDirOf(binPath, enginesRoot) {
9497
9578
  if (!m) return null;
9498
9579
  return join19(enginesRoot, "build", m[1]);
9499
9580
  }
9500
- function pickGenerator(hasNinja) {
9501
- return hasNinja ? "Ninja" : "NMake Makefiles";
9581
+ function pickGenerator(hasNinja, isWindows) {
9582
+ if (hasNinja) return "Ninja";
9583
+ return isWindows ? "NMake Makefiles" : "Unix Makefiles";
9502
9584
  }
9503
9585
  var CMAKE_CONFIGURE_ARGS = ["-DGGML_CUDA=ON", "-DCMAKE_BUILD_TYPE=Release"];
9504
9586
  function vcvarsBatch(vcvars, cmakeArgs) {
@@ -9573,6 +9655,56 @@ function copyCudaRuntimeDlls(env, destDir, log) {
9573
9655
  if (copied > 0) log(`Bundled ${copied} CUDA runtime DLL(s) next to the binary so the engine is self-contained.`);
9574
9656
  return copied;
9575
9657
  }
9658
+ var CUDA_RUNTIME_SO_PREFIXES = ["libcudart.so", "libcublas.so", "libcublasLt.so", "libnvrtc.so", "libnvrtc-builtins.so", "libnvJitLink.so"];
9659
+ function cudaSoSourceDirs(env) {
9660
+ const key = Object.keys(env).find((k) => k.toLowerCase() === "path") ?? "PATH";
9661
+ const pathDirs = (env[key] ?? "").split(delimiter2).filter(Boolean);
9662
+ const nvccDir = pathDirs.find((dir) => {
9663
+ try {
9664
+ return existsSync17(join19(dir, "nvcc"));
9665
+ } catch {
9666
+ return false;
9667
+ }
9668
+ });
9669
+ if (!nvccDir) return [];
9670
+ const toolkitRoot = dirname6(nvccDir);
9671
+ return [join19(toolkitRoot, "lib64"), join19(toolkitRoot, "lib"), join19(toolkitRoot, "targets", "x86_64-linux", "lib")].filter((d) => {
9672
+ try {
9673
+ return existsSync17(d);
9674
+ } catch {
9675
+ return false;
9676
+ }
9677
+ });
9678
+ }
9679
+ function copyCudaRuntimeLibs(env, destDir, log) {
9680
+ const sources = cudaSoSourceDirs(env);
9681
+ if (sources.length === 0) {
9682
+ log("Note: could not find the CUDA toolkit shared libraries to bundle \u2014 the engine may need LD_LIBRARY_PATH set to run.");
9683
+ return 0;
9684
+ }
9685
+ const seen = /* @__PURE__ */ new Set();
9686
+ let copied = 0;
9687
+ for (const dir of sources) {
9688
+ let names;
9689
+ try {
9690
+ names = readdirSync5(dir);
9691
+ } catch {
9692
+ continue;
9693
+ }
9694
+ for (const name of names) {
9695
+ if (seen.has(name)) continue;
9696
+ if (!CUDA_RUNTIME_SO_PREFIXES.some((p) => name.startsWith(p))) continue;
9697
+ try {
9698
+ copyFileSync(join19(dir, name), join19(destDir, name));
9699
+ seen.add(name);
9700
+ copied++;
9701
+ } catch {
9702
+ }
9703
+ }
9704
+ }
9705
+ if (copied > 0) log(`Bundled ${copied} CUDA runtime librar${copied === 1 ? "y" : "ies"} next to the binary so the engine is self-contained.`);
9706
+ return copied;
9707
+ }
9576
9708
  async function findVcvarsall() {
9577
9709
  try {
9578
9710
  const programFilesX86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
@@ -9691,10 +9823,11 @@ function neutralizeGratuitousAsm(srcDir, log) {
9691
9823
  }
9692
9824
  }
9693
9825
  async function runBuild(req, hooks, signal) {
9826
+ const isWindows = process.platform === "win32";
9694
9827
  const env = { ...buildEnv(req.toolchainDirs), GIT_TERMINAL_PROMPT: "0", GCM_INTERACTIVE: "never" };
9695
9828
  hooks.phase("preparing");
9696
9829
  const prereqs = await checkBuildPrereqs(req.toolchainDirs);
9697
- if (!prereqs.supported) throw new Error("In-app build is currently Windows + CUDA only.");
9830
+ if (!prereqs.supported) throw new Error("In-app build is currently Windows or Linux (with CUDA) only.");
9698
9831
  const missing = prereqs.tools.filter((t) => (t.id === "git" || t.id === "cmake" || t.id === "cuda") && !t.found);
9699
9832
  if (missing.length > 0) {
9700
9833
  const names = missing.map((t) => t.name).join(", ");
@@ -9702,10 +9835,17 @@ async function runBuild(req, hooks, signal) {
9702
9835
  `Missing build prerequisite(s): ${names}. Install them, or \u2014 if they live in a conda env / custom path \u2014 add that folder under Build environment so TurboLLM can find them.`
9703
9836
  );
9704
9837
  }
9705
- const vcvars = await findVcvarsall();
9706
- if (!vcvars) {
9838
+ let vcvars = null;
9839
+ if (isWindows) {
9840
+ vcvars = await findVcvarsall();
9841
+ if (!vcvars) {
9842
+ throw new Error(
9843
+ 'Could not locate the Visual Studio C++ build environment (vcvarsall.bat). Install the "Desktop development with C++" workload from the Visual Studio Build Tools.'
9844
+ );
9845
+ }
9846
+ } else if (!prereqs.tools.some((t) => t.id === "gcc" && t.found)) {
9707
9847
  throw new Error(
9708
- 'Could not locate the Visual Studio C++ build environment (vcvarsall.bat). Install the "Desktop development with C++" workload from the Visual Studio Build Tools.'
9848
+ "Could not find a C++ compiler. Install one (e.g. `sudo apt install build-essential` on Debian/Ubuntu) and retry."
9709
9849
  );
9710
9850
  }
9711
9851
  const buildRoot = join19(req.enginesRoot, "build", buildDirName(req.repoUrl, req.branch));
@@ -9721,24 +9861,35 @@ async function runBuild(req, hooks, signal) {
9721
9861
  const commit = (await runStep("git", ["-C", srcDir, "rev-parse", "HEAD"], { env, signal, onLine: () => {
9722
9862
  } })).trim();
9723
9863
  neutralizeGratuitousAsm(srcDir, hooks.log);
9724
- const generator = pickGenerator(onPath(env, "ninja.exe"));
9864
+ const generator = pickGenerator(onPath(env, isWindows ? "ninja.exe" : "ninja"), isWindows);
9725
9865
  hooks.log(
9726
- generator === "Ninja" ? "Using the Ninja generator (drives nvcc directly \u2014 no Visual Studio CUDA integration needed)." : "Ninja not found on PATH \u2014 using the NMake generator (works, but single-threaded and slower; add a folder containing ninja.exe under Build environment for much faster builds)."
9866
+ generator === "Ninja" ? "Using the Ninja generator (drives nvcc directly \u2014 no Visual Studio CUDA integration needed)." : isWindows ? "Ninja not found on PATH \u2014 using the NMake generator (works, but single-threaded and slower; add a folder containing ninja.exe under Build environment for much faster builds)." : "Ninja not found on PATH \u2014 using Unix Makefiles (works, but single-threaded and slower; add a folder containing ninja under Build environment for much faster builds)."
9727
9867
  );
9728
9868
  hooks.phase("configuring");
9729
- const configureBat = join19(buildRoot, "_tllm_configure.bat");
9730
- writeFileSync8(configureBat, vcvarsBatch(vcvars, ["-G", generator, "-B", buildSubdir, "-S", srcDir, ...CMAKE_CONFIGURE_ARGS]));
9731
- await runStep("cmd.exe", ["/c", configureBat], { cwd: buildRoot, env, signal, onLine: hooks.log });
9869
+ const configureArgs = ["-G", generator, "-B", buildSubdir, "-S", srcDir, ...CMAKE_CONFIGURE_ARGS];
9870
+ if (isWindows) {
9871
+ const configureBat = join19(buildRoot, "_tllm_configure.bat");
9872
+ writeFileSync8(configureBat, vcvarsBatch(vcvars, configureArgs));
9873
+ await runStep("cmd.exe", ["/c", configureBat], { cwd: buildRoot, env, signal, onLine: hooks.log });
9874
+ } else {
9875
+ await runStep("cmake", configureArgs, { cwd: buildRoot, env, signal, onLine: hooks.log });
9876
+ }
9732
9877
  hooks.phase("compiling");
9733
- const compileBat = join19(buildRoot, "_tllm_build.bat");
9734
- writeFileSync8(compileBat, vcvarsBatch(vcvars, ["--build", buildSubdir, "-j", "--target", "llama-server"]));
9735
- await runStep("cmd.exe", ["/c", compileBat], { cwd: buildRoot, env, signal, onLine: hooks.log });
9878
+ const compileArgs = ["--build", buildSubdir, "-j", "--target", "llama-server"];
9879
+ if (isWindows) {
9880
+ const compileBat = join19(buildRoot, "_tllm_build.bat");
9881
+ writeFileSync8(compileBat, vcvarsBatch(vcvars, compileArgs));
9882
+ await runStep("cmd.exe", ["/c", compileBat], { cwd: buildRoot, env, signal, onLine: hooks.log });
9883
+ } else {
9884
+ await runStep("cmake", compileArgs, { cwd: buildRoot, env, signal, onLine: hooks.log });
9885
+ }
9736
9886
  hooks.phase("registering");
9737
9887
  const binPath = resolveServerBinary(buildSubdir) ?? resolveServerBinary(buildRoot);
9738
9888
  if (!binPath) {
9739
9889
  throw new Error("Build finished but no llama-server binary was found in the output \u2014 see the log above.");
9740
9890
  }
9741
- copyCudaRuntimeDlls(env, dirname6(binPath), hooks.log);
9891
+ if (isWindows) copyCudaRuntimeDlls(env, dirname6(binPath), hooks.log);
9892
+ else copyCudaRuntimeLibs(env, dirname6(binPath), hooks.log);
9742
9893
  return { binPath, commit, buildRoot };
9743
9894
  }
9744
9895
 
@@ -10353,8 +10504,8 @@ function registerApi(app2, d) {
10353
10504
  app2.post("/api/v1/build/run", async (c) => {
10354
10505
  if (!isLocalRequest(c, d))
10355
10506
  return err2(c, 403, "forbidden", "Building an engine is only available on the machine running TurboLLM.");
10356
- if (process.platform !== "win32")
10357
- return err2(c, 409, "unsupported_platform", "In-app build is currently Windows + CUDA only.");
10507
+ if (process.platform !== "win32" && process.platform !== "linux")
10508
+ return err2(c, 409, "unsupported_platform", "In-app build is currently Windows or Linux (with CUDA) only.");
10358
10509
  const b = await body2(c);
10359
10510
  const repoUrl = (b.repoUrl ?? "").trim();
10360
10511
  if (!/^https?:\/\//i.test(repoUrl))
@@ -11270,11 +11421,13 @@ function registerApi(app2, d) {
11270
11421
  });
11271
11422
  return c.json(modelDirsPayload(d));
11272
11423
  });
11424
+ const SORT_OPTIONS = ["best-match", "trending", "downloads", "likes", "modified", "created"];
11273
11425
  app2.get("/api/v1/hf/search", async (c) => {
11274
11426
  const q = (c.req.query("q") ?? "").trim();
11275
- if (!q) return c.json({ results: [] });
11427
+ const rawSort = c.req.query("sort") ?? "";
11428
+ const sort = SORT_OPTIONS.includes(rawSort) ? rawSort : "best-match";
11276
11429
  try {
11277
- const results = await d.hf.searchModels(q, d.registry.active()?.kind);
11430
+ const results = q ? await d.hf.searchModels(q, d.registry.active()?.kind, sort) : await d.hf.browseModels(sort, d.registry.active()?.kind);
11278
11431
  const withLocal = results.map((r) => ({ ...r, localCount: localCountFor(d, r.repo) }));
11279
11432
  return c.json({ results: withLocal });
11280
11433
  } catch (e) {