turbollm 1.13.1 → 1.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +9 -2
  2. package/dist/{chunk-TIH3B2GZ.js → chunk-HQ76BEUS.js} +200 -196
  3. package/dist/chunk-Y3TMLJQD.js +1114 -0
  4. package/dist/cli.js +3729 -2958
  5. package/dist/code-routes.js +1 -1
  6. package/dist/code-run-manager.js +1 -1
  7. package/dist/factory-NOUUQICH.js +7 -0
  8. package/dist/webdist/assets/{AgentEditPage-Dym1KyqX.js → AgentEditPage-8XwklBCN.js} +1 -1
  9. package/dist/webdist/assets/{ChatScreen-BcdP2zdp.js → ChatScreen-BG-gWo8i.js} +17 -17
  10. package/dist/webdist/assets/CodeComposer-Bui_gqhF.js +1 -0
  11. package/dist/webdist/assets/CodeHomeScreen-CEaCj3je.js +1 -0
  12. package/dist/webdist/assets/{CodeSessionScreen-BOQ6KoV7.js → CodeSessionScreen-DUTkKMNW.js} +2 -2
  13. package/dist/webdist/assets/CustomizeScreen-ze18T4hb.js +4 -0
  14. package/dist/webdist/assets/{EnginesScreen-DsXKQBdB.js → EnginesScreen-CmJVhifa.js} +10 -10
  15. package/dist/webdist/assets/HardwareSection-63UUvSMO.js +1 -0
  16. package/dist/webdist/assets/{ModelDetailDialog-BXITKheg.js → ModelDetailDialog-C2lnCsw6.js} +1 -1
  17. package/dist/webdist/assets/{ModelLoadMenu-BA07PQdL.js → ModelLoadMenu-D0bpk6p2.js} +1 -1
  18. package/dist/webdist/assets/{ModelsScreen-B9Lfop2U.js → ModelsScreen-DYSvF-AP.js} +2 -2
  19. package/dist/webdist/assets/OnboardingScreen-Bti1XKVZ.js +1 -0
  20. package/dist/webdist/assets/RoutineEditPage-Dytik45T.js +1 -0
  21. package/dist/webdist/assets/RoutinesPanel-CK2_OmGj.js +1 -0
  22. package/dist/webdist/assets/SettingsScreen-qcB-Wlhm.js +2 -0
  23. package/dist/webdist/assets/{SidebarResizeHandle-DVs8SGko.js → SidebarResizeHandle-C6DzzA0i.js} +2 -2
  24. package/dist/webdist/assets/{SkillEditPage-DTIwnb5M.js → SkillEditPage-BoVodeSt.js} +1 -1
  25. package/dist/webdist/assets/{ToolApprovalBar-C1Za_m4h.js → ToolApprovalBar-CkVy2BpV.js} +3 -3
  26. package/dist/webdist/assets/WorkspaceScreen-BzYimITz.js +1 -0
  27. package/dist/webdist/assets/{abnfDiagram-N423BO3Z-CVyB7CsQ.js → abnfDiagram-N423BO3Z-BsFZfp7v.js} +1 -1
  28. package/dist/webdist/assets/{agent-api-mKI2ziy1.js → agent-api-CeGvce9t.js} +1 -1
  29. package/dist/webdist/assets/alert-dialog-Crc_A3Jz.js +1 -0
  30. package/dist/webdist/assets/{arc-vy1HbZG7.js → arc-DBKAh_3p.js} +1 -1
  31. package/dist/webdist/assets/{architectureDiagram-T3A2C74G-CMd1GRSg.js → architectureDiagram-T3A2C74G-DF2Iau9y.js} +1 -1
  32. package/dist/webdist/assets/{blockDiagram-VBNYF7ZC-C0TDSyYW.js → blockDiagram-VBNYF7ZC-EIM7OH8W.js} +1 -1
  33. package/dist/webdist/assets/{c4Diagram-5PPSVZJV-M6Gw1tuY.js → c4Diagram-5PPSVZJV-DfTJQH_y.js} +1 -1
  34. package/dist/webdist/assets/channel-BF2z4CLG.js +1 -0
  35. package/dist/webdist/assets/chat-api-BspgdIew.js +3 -0
  36. package/dist/webdist/assets/chat-queries-dQVxfOyx.js +1 -0
  37. package/dist/webdist/assets/{chevron-down-Cr8PyXv0.js → chevron-down-DNeXZ14t.js} +1 -1
  38. package/dist/webdist/assets/{chevron-left-BWp4EppC.js → chevron-left-yPpon0Zo.js} +1 -1
  39. package/dist/webdist/assets/{chevron-right-BNTB7WiI.js → chevron-right-qwzlPkv4.js} +1 -1
  40. package/dist/webdist/assets/{chunk-2GRJ4B5K-BtJnPm_X.js → chunk-2GRJ4B5K-g8WkdrcJ.js} +1 -1
  41. package/dist/webdist/assets/{chunk-2Q5K7J3B-CUF6QQ1A.js → chunk-2Q5K7J3B-DiSXrpfm.js} +1 -1
  42. package/dist/webdist/assets/{chunk-5RXB4S5H-BtKyDHvg.js → chunk-5RXB4S5H--rX8NQES.js} +1 -1
  43. package/dist/webdist/assets/{chunk-5VM5RSS4-D1I4GKUh.js → chunk-5VM5RSS4-D0bbkNOA.js} +1 -1
  44. package/dist/webdist/assets/{chunk-6Q2QTUOP-CuhRlIbl.js → chunk-6Q2QTUOP-CyjvDHy7.js} +1 -1
  45. package/dist/webdist/assets/{chunk-GF5L2VYU-DXuYLaz3.js → chunk-GF5L2VYU-DBsZFyHH.js} +1 -1
  46. package/dist/webdist/assets/{chunk-JWPE2WC7-CXyw7def.js → chunk-JWPE2WC7-BJX8rZY8.js} +1 -1
  47. package/dist/webdist/assets/{chunk-KBJHAD2P-DTxBuz43.js → chunk-KBJHAD2P-CzHI537O.js} +1 -1
  48. package/dist/webdist/assets/{chunk-RYQCIY6F-CJNSzYoP.js → chunk-RYQCIY6F-DcQ5BoLP.js} +1 -1
  49. package/dist/webdist/assets/{chunk-XXDRQBXY-DEVi8OYy.js → chunk-XXDRQBXY-DwaqNMb3.js} +1 -1
  50. package/dist/webdist/assets/{circle-check-tPHpKH4i.js → circle-check-Brhy4Orf.js} +1 -1
  51. package/dist/webdist/assets/{circle-x-BtZB2fZ7.js → circle-x-BvhAr_O9.js} +1 -1
  52. package/dist/webdist/assets/classDiagram-JCYQIIEL-D-pqoTab.js +1 -0
  53. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-D-pqoTab.js +1 -0
  54. package/dist/webdist/assets/collapsible-Bg5PA5Nz.js +1 -0
  55. package/dist/webdist/assets/{cose-bilkent-JH36ORCC-BFcCFhIi.js → cose-bilkent-JH36ORCC-DT2idxjo.js} +1 -1
  56. package/dist/webdist/assets/{cynefin-VYW2F7L2-BYQiVIyh.js → cynefin-VYW2F7L2-9kVBD_9a.js} +1 -1
  57. package/dist/webdist/assets/{cynefinDiagram-MW4NZA55-BkQKk_25.js → cynefinDiagram-MW4NZA55-CTix7oEO.js} +1 -1
  58. package/dist/webdist/assets/{dagre-VZM6K2ZE-rsfyi456.js → dagre-VZM6K2ZE-DbRB_1Ng.js} +1 -1
  59. package/dist/webdist/assets/{diagram-7IWD3JNH-C0DN8V1H.js → diagram-7IWD3JNH-ClCpikH_.js} +1 -1
  60. package/dist/webdist/assets/{diagram-B4RE2ZJO-VrZw1kLY.js → diagram-B4RE2ZJO-wQlXyd4e.js} +1 -1
  61. package/dist/webdist/assets/{diagram-LBJQPF4R-BcYKBexW.js → diagram-LBJQPF4R-zgM6REwi.js} +1 -1
  62. package/dist/webdist/assets/{diagram-Q27KOJAE-CXS9VQM1.js → diagram-Q27KOJAE-DvIssBlm.js} +1 -1
  63. package/dist/webdist/assets/{diagram-UB23O5K3-o3LA6b9f.js → diagram-UB23O5K3-DdQiF9NE.js} +1 -1
  64. package/dist/webdist/assets/{dropdown-menu-BdlxlOvr.js → dropdown-menu-HI5N3Rmt.js} +1 -1
  65. package/dist/webdist/assets/{ebnfDiagram-BXEA7PRR-CeVCgeJ0.js → ebnfDiagram-BXEA7PRR-CpSxEGTe.js} +1 -1
  66. package/dist/webdist/assets/{erDiagram-JOGREHBK-DNDqb-7g.js → erDiagram-JOGREHBK-BrhRHXD4.js} +1 -1
  67. package/dist/webdist/assets/{file-text-ClQSSMFI.js → file-text-Cx83fgk0.js} +1 -1
  68. package/dist/webdist/assets/{flowDiagram-UKHOOZJN-6Y0STfYO.js → flowDiagram-UKHOOZJN-CIxMbmNO.js} +1 -1
  69. package/dist/webdist/assets/{folder-input-BPVoURwk.js → folder-input-BN5lzecG.js} +1 -1
  70. package/dist/webdist/assets/{folder-plus-C6qdRRE1.js → folder-plus-B-imiY57.js} +1 -1
  71. package/dist/webdist/assets/{ganttDiagram-PKOTCBZU-DEKJRLOu.js → ganttDiagram-PKOTCBZU-CiO9YNNt.js} +1 -1
  72. package/dist/webdist/assets/{git-branch-CGm1i_Eb.js → git-branch-BY-pdlSo.js} +1 -1
  73. package/dist/webdist/assets/{gitGraphDiagram-DS77QQ5N-x2UJFG-U.js → gitGraphDiagram-DS77QQ5N-Dz_fBDX6.js} +1 -1
  74. package/dist/webdist/assets/globe-FB3s-Kjz.js +1 -0
  75. package/dist/webdist/assets/index-A9e9aiYI.css +1 -0
  76. package/dist/webdist/assets/{index-DzbdV438.js → index-Bs1-t0Ft.js} +1 -1
  77. package/dist/webdist/assets/index-CfwXVQIu.js +14 -0
  78. package/dist/webdist/assets/{infoDiagram-6WML65LV-C6C1bGzu.js → infoDiagram-6WML65LV-BP9JLl_M.js} +1 -1
  79. package/dist/webdist/assets/{ishikawaDiagram-WSZJBQD7-CZVmvAx3.js → ishikawaDiagram-WSZJBQD7-CeBpQALC.js} +1 -1
  80. package/dist/webdist/assets/{journeyDiagram-NVQOT4AX-CJ2qLlRG.js → journeyDiagram-NVQOT4AX-Cnn5M1YO.js} +1 -1
  81. package/dist/webdist/assets/{kanban-definition-27J2QSJJ-C1j9o0ks.js → kanban-definition-27J2QSJJ-BMnM-8zj.js} +1 -1
  82. package/dist/webdist/assets/{linear-DXj2WKUc.js → linear-ontMFf7q.js} +1 -1
  83. package/dist/webdist/assets/{lock-BI2ZVie9.js → lock-CVTYolJH.js} +1 -1
  84. package/dist/webdist/assets/{mermaid.core-Zn6MPOtK.js → mermaid.core-BX4U-c4C.js} +4 -4
  85. package/dist/webdist/assets/{mindmap-definition-FAOFIHXS-CDJMKx24.js → mindmap-definition-FAOFIHXS-D55lobOz.js} +1 -1
  86. package/dist/webdist/assets/{monitor-DY9e5ORA.js → monitor-BVyi9riP.js} +1 -1
  87. package/dist/webdist/assets/{pegDiagram-VL7TDLO6-DDIE3L3w.js → pegDiagram-VL7TDLO6-BE11XRQ7.js} +1 -1
  88. package/dist/webdist/assets/{pencil-Db1lkam5.js → pencil-xiVy9lBH.js} +1 -1
  89. package/dist/webdist/assets/{pieDiagram-7S7Q4E2Y-9-_Vzadf.js → pieDiagram-7S7Q4E2Y-BMHDg8ys.js} +1 -1
  90. package/dist/webdist/assets/{quadrantDiagram-CIZ2JOQS-DVFOD-B7.js → quadrantDiagram-CIZ2JOQS-2sqR5qXm.js} +1 -1
  91. package/dist/webdist/assets/radix-B7FN0WwE.js +41 -0
  92. package/dist/webdist/assets/{railroadDiagram-AXF67PYL-DaK1Lf9k.js → railroadDiagram-AXF67PYL-CrA2ZKhq.js} +1 -1
  93. package/dist/webdist/assets/{refresh-cw-ClWNeewb.js → refresh-cw-BGipAyiS.js} +1 -1
  94. package/dist/webdist/assets/{remote-failure-CVQYekAL.js → remote-failure-CGk8OyjK.js} +1 -1
  95. package/dist/webdist/assets/{requirementDiagram-LRYGKXZP-RXJrMu9j.js → requirementDiagram-LRYGKXZP-RlYw_SgL.js} +1 -1
  96. package/dist/webdist/assets/{rocket-BE4Peice.js → rocket-DHnkfnhQ.js} +1 -1
  97. package/dist/webdist/assets/{rotate-ccw-C2s6i5Jp.js → rotate-ccw-DmG7PkUG.js} +1 -1
  98. package/dist/webdist/assets/{sankeyDiagram-W5VNT64P-CFE9sU4S.js → sankeyDiagram-W5VNT64P-B61EFr-D.js} +1 -1
  99. package/dist/webdist/assets/{sequenceDiagram-SI44F4Z6-DZkMg137.js → sequenceDiagram-SI44F4Z6-Cj4e2tXy.js} +1 -1
  100. package/dist/webdist/assets/sheet-DFCO49jw.js +1 -0
  101. package/dist/webdist/assets/{sizeCapture-X5ZJPWSS-NHtmoElu.js → sizeCapture-X5ZJPWSS-CYyUy4Qg.js} +1 -1
  102. package/dist/webdist/assets/{skeleton-CVFgYJeZ.js → skeleton-DVrIPwv0.js} +1 -1
  103. package/dist/webdist/assets/{sliders-horizontal-lnE2U8Ng.js → sliders-horizontal-DQYu0jQs.js} +1 -1
  104. package/dist/webdist/assets/{sparkles-DDdOhO-u.js → sparkles-DKoUw0Ra.js} +1 -1
  105. package/dist/webdist/assets/{star-DK9AFk2h.js → star-EY1hsb1g.js} +1 -1
  106. package/dist/webdist/assets/{stateDiagram-OKZ733FA-qeV-WNNN.js → stateDiagram-OKZ733FA-CIAre6fb.js} +1 -1
  107. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-c4H1EbPk.js +1 -0
  108. package/dist/webdist/assets/{swimlanes-SLNWSIFB-Dn2032Qm.js → swimlanes-SLNWSIFB-DGZBf-GQ.js} +2 -2
  109. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-C9AdErpx.js +8 -0
  110. package/dist/webdist/assets/{switch-C8TDmk4o.js → switch-CXoaYXdG.js} +1 -1
  111. package/dist/webdist/assets/{terminal-B8Cu2_ni.js → terminal-BrWVclQ0.js} +1 -1
  112. package/dist/webdist/assets/{timeline-definition-Z64GVDOM-CeOxLPuW.js → timeline-definition-Z64GVDOM-mu5ti0bv.js} +1 -1
  113. package/dist/webdist/assets/{trash-2-2wk4VHfQ.js → trash-2-WYWL4BUK.js} +1 -1
  114. package/dist/webdist/assets/{vennDiagram-T6HMQDX7-BzQXbsSd.js → vennDiagram-T6HMQDX7-OxY1RaKm.js} +1 -1
  115. package/dist/webdist/assets/{wardleyDiagram-T6FBY63Y-ZnmHNIut.js → wardleyDiagram-T6FBY63Y-BtG14vOo.js} +1 -1
  116. package/dist/webdist/assets/{wrench-Cfgbkzi3.js → wrench-D_MLSbdw.js} +1 -1
  117. package/dist/webdist/assets/{xychartDiagram-ELKLHX3M-ByHBwPv5.js → xychartDiagram-ELKLHX3M-DeNO3ZVS.js} +1 -1
  118. package/dist/webdist/index.html +3 -3
  119. package/package.json +1 -1
  120. package/dist/webdist/assets/CodeComposer-BCxQ5mSO.js +0 -1
  121. package/dist/webdist/assets/CodeHomeScreen-DvHCATzs.js +0 -1
  122. package/dist/webdist/assets/CustomizeScreen-BwMOTrmg.js +0 -4
  123. package/dist/webdist/assets/HardwareSection-DXHuVSsh.js +0 -1
  124. package/dist/webdist/assets/OnboardingScreen-CdCJbHnx.js +0 -1
  125. package/dist/webdist/assets/RoutineEditPage-B-Q_NK95.js +0 -1
  126. package/dist/webdist/assets/RoutinesPanel-DElOj8Dh.js +0 -1
  127. package/dist/webdist/assets/SettingsScreen-CbRWiTC9.js +0 -2
  128. package/dist/webdist/assets/WorkspaceScreen-CjXZkcXT.js +0 -1
  129. package/dist/webdist/assets/alert-dialog-a5ByK8bb.js +0 -1
  130. package/dist/webdist/assets/channel-Co0osRum.js +0 -1
  131. package/dist/webdist/assets/chat-api-u48Gn8_q.js +0 -3
  132. package/dist/webdist/assets/chat-queries-C2eUqnQe.js +0 -1
  133. package/dist/webdist/assets/classDiagram-JCYQIIEL-Cd9CRK17.js +0 -1
  134. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-Cd9CRK17.js +0 -1
  135. package/dist/webdist/assets/collapsible-BEf-vk0G.js +0 -1
  136. package/dist/webdist/assets/common-D2Aax55A.js +0 -1
  137. package/dist/webdist/assets/index-CKu-FGKB.js +0 -14
  138. package/dist/webdist/assets/index-jjD6-DKX.css +0 -1
  139. package/dist/webdist/assets/radix-mRz26PwR.js +0 -41
  140. package/dist/webdist/assets/sheet-65Zlup1V.js +0 -1
  141. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-D8QiIhoF.js +0 -1
  142. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-CtjO7H8G.js +0 -8
package/README.md CHANGED
@@ -299,6 +299,12 @@ the detail:
299
299
  set per link — use models only, run a server, or full control — optionally pinned to specific
300
300
  models, and revocable at any time from the host. Not yet verified against a real two-machine
301
301
  setup, so it stays behind Settings → Experimental.
302
+ - **Remote access** *(experimental, off by default)* — expose TurboLLM to the internet through
303
+ Cloudflare (Quick or Named tunnel), Tailscale (Serve or Funnel), ngrok, or your own reverse
304
+ proxy, from Settings → Network & sharing. Enabling it mints a capability-scoped access token —
305
+ restrict it to chat-only, or also allow loading/unloading models — instead of exposing your
306
+ regular API key, with a live status chip and one-click stop. Not yet verified
307
+ against real Cloudflare/Tailscale/ngrok accounts, so it stays behind Settings → Experimental.
302
308
  - **Thinking-budget control** — a graduated slider, not just on/off: cap reasoning to a specific
303
309
  token count, disable it entirely, or leave it unlimited. Works in Chat and Code alike.
304
310
  - **Reasoning-effort control** for models whose own chat template supports it (e.g. Qwen3.8) —
@@ -437,8 +443,9 @@ connected); **Remove** undoes it.
437
443
 
438
444
  - A **persistent bottom strip** on every screen shows real-time CPU, RAM, GPU and VRAM — values
439
445
  and percentages — pulled from `nvidia-smi`, WDDM counters, `rocm-smi`, AMD sysfs, `ioreg`,
440
- or `/proc` on Linux. Clicking the bar opens detailed gauges and sparklines in Settings → System.
441
- Toggle it off entirely from Settings General.
446
+ or `/proc` on Linux. Clicking the bar opens detailed gauges and sparklines in Settings → System,
447
+ including live **disk I/O** (read/write MB/s) and a **shared/spilled VRAM** figure that shows
448
+ when a discrete GPU has spilled into system memory. Toggle it off entirely from Settings → General.
442
449
  - **Engines → Monitor** puts the live engine log and those same hardware gauges on one
443
450
  always-visible split screen, plus a second, LM Studio-style **developer request log**: every
444
451
  completion the daemon serves — external API clients, Code sessions, in-app Chat — with
@@ -12,11 +12,19 @@ import { EventEmitter as EventEmitter2 } from "events";
12
12
  // src/chat/chat-routes.ts
13
13
  import { streamSSE } from "hono/streaming";
14
14
 
15
+ // src/auth.ts
16
+ import { createHash, randomBytes, randomUUID } from "crypto";
17
+ import { getConnInfo } from "@hono/node-server/conninfo";
18
+
19
+ // src/remote/access-jwt.ts
20
+ import { createPublicKey, createVerify, verify as cryptoVerify } from "crypto";
21
+ var JWKS_TTL_MS = 60 * 6e4;
22
+
15
23
  // src/net.ts
16
24
  import { networkInterfaces } from "os";
17
25
 
18
26
  // src/config/config.ts
19
- import { randomUUID } from "crypto";
27
+ import { randomUUID as randomUUID2 } from "crypto";
20
28
  import { cpSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
21
29
  import { homedir } from "os";
22
30
  import { dirname, join } from "path";
@@ -34,194 +42,6 @@ function parseReasoningEffort(value) {
34
42
  return ALIASES.get(value);
35
43
  }
36
44
 
37
- // src/tools/approval-gate.ts
38
- var pending = /* @__PURE__ */ new Map();
39
- function waitForToolApproval(key, signal) {
40
- return new Promise((resolvePromise) => {
41
- const onAbort = () => {
42
- pending.delete(key);
43
- resolvePromise("deny");
44
- };
45
- const cleanup = () => {
46
- signal.removeEventListener("abort", onAbort);
47
- };
48
- pending.set(key, {
49
- resolve: (decision) => {
50
- cleanup();
51
- resolvePromise(decision);
52
- },
53
- cleanup
54
- });
55
- if (signal.aborted) {
56
- onAbort();
57
- return;
58
- }
59
- signal.addEventListener("abort", onAbort, { once: true });
60
- });
61
- }
62
-
63
- // src/agents/skills.ts
64
- import { join as join2 } from "path";
65
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, rmSync, readdirSync } from "fs";
66
- var BUILTIN_SKILLS = [
67
- {
68
- id: "filesystem",
69
- name: "Filesystem",
70
- description: "Read files, list directories, glob patterns within the agent's workspace.",
71
- instructions: "You can read files and explore directories. Use read_file to read file contents, list_dir to explore, and glob to find files. Always work within your allowed paths.",
72
- tools: ["read_file", "list_dir", "glob"],
73
- builtin: true
74
- },
75
- {
76
- id: "web",
77
- name: "Web",
78
- description: "Search the web and fetch URLs for research.",
79
- instructions: "You can search the web using web_search and fetch URLs with fetch_url. Use these to gather current information and research topics.",
80
- tools: ["web_search", "fetch_url"],
81
- builtin: true
82
- },
83
- {
84
- id: "code",
85
- name: "Code",
86
- description: "Execute code for computation and data processing.",
87
- instructions: "You can run code using run_code. Code execution runs unattended \u2014 ensure your code is correct before running.",
88
- tools: ["run_code"],
89
- builtin: true
90
- },
91
- {
92
- id: "task-tracking",
93
- name: "Task Tracking",
94
- description: "Track progress on a task and declare completion.",
95
- instructions: "You can track your progress with update_doc and declare a task complete with complete_task. Update the working doc regularly to maintain a clear record of what's done and what's left.",
96
- tools: ["update_doc", "complete_task"],
97
- builtin: true
98
- },
99
- {
100
- id: "compose",
101
- name: "Compose",
102
- description: "Delegate work to other agents via call_agent.",
103
- instructions: "You can call other agents using call_agent. Use this to delegate specialized sub-tasks to agents with different capabilities.",
104
- tools: ["call_agent"],
105
- builtin: true
106
- },
107
- {
108
- id: "skill-creator",
109
- name: "Skill Creator",
110
- description: "Save a reusable skill distilled from this conversation.",
111
- instructions: 'Do NOT proactively mention, suggest, or save skills. ONLY when the user EXPLICITLY asks to create or save a skill from this conversation (e.g. "make a skill out of this", "save this as a skill"), call the save_skill tool \u2014 it writes a SKILL.md into the shared library in the background. Never use any external memory, knowledge-graph, or note tool to store skills.',
112
- tools: ["save_skill"],
113
- builtin: true
114
- }
115
- ];
116
- function toSkillMd(skill) {
117
- const fm = [`name: ${skill.name}`, `description: ${oneLine(skill.description)}`];
118
- if (skill.tools.length) fm.push(`tools: ${skill.tools.join(", ")}`);
119
- return `---
120
- ${fm.join("\n")}
121
- ---
122
-
123
- ${skill.instructions.trim()}
124
- `;
125
- }
126
- function fromSkillMd(id, raw) {
127
- const text = raw.replace(/^/, "").replace(/\r\n/g, "\n");
128
- const m = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(text);
129
- if (!m) return null;
130
- const meta = {};
131
- for (const line of m[1].split("\n")) {
132
- const c = line.indexOf(":");
133
- if (c < 0) continue;
134
- meta[line.slice(0, c).trim().toLowerCase()] = unquote(line.slice(c + 1).trim());
135
- }
136
- const name = meta.name?.trim();
137
- const instructions = m[2].trim();
138
- if (!name || !instructions) return null;
139
- const tools = meta.tools ? meta.tools.split(",").map((t) => unquote(t.trim())).filter(Boolean) : [];
140
- return { id, name, description: meta.description ?? "", instructions, tools, builtin: false };
141
- }
142
- function unquote(s) {
143
- return s.replace(/^["']|["']$/g, "").trim();
144
- }
145
- function oneLine(s) {
146
- return s.replace(/\s*\n\s*/g, " ").trim();
147
- }
148
- var SkillStore = class {
149
- constructor(dataDir) {
150
- this.dataDir = dataDir;
151
- }
152
- dataDir;
153
- get skillsDir() {
154
- return join2(this.dataDir, "skills");
155
- }
156
- list() {
157
- const skills = [...BUILTIN_SKILLS];
158
- const idSet = new Set(skills.map((s) => s.id));
159
- if (!existsSync2(this.skillsDir)) return skills;
160
- for (const e of readdirSync(this.skillsDir, { withFileTypes: true })) {
161
- let skill = null;
162
- let id = "";
163
- if (e.isDirectory()) {
164
- id = e.name;
165
- const md = join2(this.skillsDir, e.name, "SKILL.md");
166
- if (existsSync2(md)) skill = this.loadMd(id, md);
167
- } else if (e.isFile() && e.name.endsWith(".json")) {
168
- id = e.name.slice(0, -5);
169
- skill = this.loadJson(join2(this.skillsDir, e.name), id);
170
- }
171
- if (!skill || !id || idSet.has(id)) continue;
172
- idSet.add(id);
173
- skills.push(skill);
174
- }
175
- return skills;
176
- }
177
- /** Only the user-created (non-builtin) skills, for injection + the library UI. */
178
- userSkills() {
179
- return this.list().filter((s) => !s.builtin);
180
- }
181
- get(id) {
182
- return this.list().find((s) => s.id === id);
183
- }
184
- has(id) {
185
- return isValidSkillId(id) && existsSync2(join2(this.skillsDir, id, "SKILL.md"));
186
- }
187
- write(skill) {
188
- if (!isValidSkillId(skill.id)) throw new Error(`Invalid skill id: ${skill.id}`);
189
- const dir = join2(this.skillsDir, skill.id);
190
- mkdirSync2(dir, { recursive: true });
191
- writeFileSync2(join2(dir, "SKILL.md"), toSkillMd(skill), "utf8");
192
- }
193
- delete(id) {
194
- if (!isValidSkillId(id)) return;
195
- rmSync(join2(this.skillsDir, id), { recursive: true, force: true });
196
- const legacy = join2(this.skillsDir, `${id}.json`);
197
- if (existsSync2(legacy)) rmSync(legacy);
198
- }
199
- loadMd(id, path) {
200
- try {
201
- return fromSkillMd(id, readFileSync2(path, "utf8"));
202
- } catch {
203
- return null;
204
- }
205
- }
206
- loadJson(path, id) {
207
- try {
208
- const data = JSON.parse(readFileSync2(path, "utf8"));
209
- if (!data.name || typeof data.name !== "string") return null;
210
- if (!data.instructions || typeof data.instructions !== "string") return null;
211
- return { id, name: data.name, description: data.description || "", instructions: data.instructions, tools: Array.isArray(data.tools) ? data.tools : [], builtin: false };
212
- } catch {
213
- return null;
214
- }
215
- }
216
- };
217
- function isValidSkillId(id) {
218
- return typeof id === "string" && /^[a-z0-9-]{1,64}$/.test(id);
219
- }
220
-
221
- // src/agents/distiller.ts
222
- import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync, existsSync as existsSync3 } from "fs";
223
- import { join as join3 } from "path";
224
-
225
45
  // src/engines/compat.ts
226
46
  var ENGINE_MODEL_ALIAS = "default_model";
227
47
  var RAPID_MLX_MODEL_ALIAS = "default";
@@ -257,7 +77,7 @@ async function proxyStream(remote, path, init, signal, fetchImpl = fetch) {
257
77
  }
258
78
 
259
79
  // src/observability/request-log.ts
260
- import { randomUUID as randomUUID2 } from "crypto";
80
+ import { randomUUID as randomUUID3 } from "crypto";
261
81
  function requestLogConfig(d) {
262
82
  return d.store.snapshot().requestLog ?? { enabled: false, captureBodies: false, maxEntries: 500 };
263
83
  }
@@ -476,9 +296,193 @@ function callChatUpstream(upstream, body, signal, fetchImpl = fetch, d) {
476
296
  );
477
297
  }
478
298
 
479
- // src/auth.ts
480
- import { createHash, randomBytes, randomUUID as randomUUID3 } from "crypto";
481
- import { getConnInfo } from "@hono/node-server/conninfo";
299
+ // src/tools/approval-gate.ts
300
+ var pending = /* @__PURE__ */ new Map();
301
+ function waitForToolApproval(key, signal) {
302
+ return new Promise((resolvePromise) => {
303
+ const onAbort = () => {
304
+ pending.delete(key);
305
+ resolvePromise("deny");
306
+ };
307
+ const cleanup = () => {
308
+ signal.removeEventListener("abort", onAbort);
309
+ };
310
+ pending.set(key, {
311
+ resolve: (decision) => {
312
+ cleanup();
313
+ resolvePromise(decision);
314
+ },
315
+ cleanup
316
+ });
317
+ if (signal.aborted) {
318
+ onAbort();
319
+ return;
320
+ }
321
+ signal.addEventListener("abort", onAbort, { once: true });
322
+ });
323
+ }
324
+
325
+ // src/agents/skills.ts
326
+ import { join as join2 } from "path";
327
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, rmSync, readdirSync } from "fs";
328
+ var BUILTIN_SKILLS = [
329
+ {
330
+ id: "filesystem",
331
+ name: "Filesystem",
332
+ description: "Read files, list directories, glob patterns within the agent's workspace.",
333
+ instructions: "You can read files and explore directories. Use read_file to read file contents, list_dir to explore, and glob to find files. Always work within your allowed paths.",
334
+ tools: ["read_file", "list_dir", "glob"],
335
+ builtin: true
336
+ },
337
+ {
338
+ id: "web",
339
+ name: "Web",
340
+ description: "Search the web and fetch URLs for research.",
341
+ instructions: "You can search the web using web_search and fetch URLs with fetch_url. Use these to gather current information and research topics.",
342
+ tools: ["web_search", "fetch_url"],
343
+ builtin: true
344
+ },
345
+ {
346
+ id: "code",
347
+ name: "Code",
348
+ description: "Execute code for computation and data processing.",
349
+ instructions: "You can run code using run_code. Code execution runs unattended \u2014 ensure your code is correct before running.",
350
+ tools: ["run_code"],
351
+ builtin: true
352
+ },
353
+ {
354
+ id: "task-tracking",
355
+ name: "Task Tracking",
356
+ description: "Track progress on a task and declare completion.",
357
+ instructions: "You can track your progress with update_doc and declare a task complete with complete_task. Update the working doc regularly to maintain a clear record of what's done and what's left.",
358
+ tools: ["update_doc", "complete_task"],
359
+ builtin: true
360
+ },
361
+ {
362
+ id: "compose",
363
+ name: "Compose",
364
+ description: "Delegate work to other agents via call_agent.",
365
+ instructions: "You can call other agents using call_agent. Use this to delegate specialized sub-tasks to agents with different capabilities.",
366
+ tools: ["call_agent"],
367
+ builtin: true
368
+ },
369
+ {
370
+ id: "skill-creator",
371
+ name: "Skill Creator",
372
+ description: "Save a reusable skill distilled from this conversation.",
373
+ instructions: 'Do NOT proactively mention, suggest, or save skills. ONLY when the user EXPLICITLY asks to create or save a skill from this conversation (e.g. "make a skill out of this", "save this as a skill"), call the save_skill tool \u2014 it writes a SKILL.md into the shared library in the background. Never use any external memory, knowledge-graph, or note tool to store skills.',
374
+ tools: ["save_skill"],
375
+ builtin: true
376
+ }
377
+ ];
378
+ function toSkillMd(skill) {
379
+ const fm = [`name: ${skill.name}`, `description: ${oneLine(skill.description)}`];
380
+ if (skill.tools.length) fm.push(`tools: ${skill.tools.join(", ")}`);
381
+ return `---
382
+ ${fm.join("\n")}
383
+ ---
384
+
385
+ ${skill.instructions.trim()}
386
+ `;
387
+ }
388
+ function fromSkillMd(id, raw) {
389
+ const text = raw.replace(/^/, "").replace(/\r\n/g, "\n");
390
+ const m = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(text);
391
+ if (!m) return null;
392
+ const meta = {};
393
+ for (const line of m[1].split("\n")) {
394
+ const c = line.indexOf(":");
395
+ if (c < 0) continue;
396
+ meta[line.slice(0, c).trim().toLowerCase()] = unquote(line.slice(c + 1).trim());
397
+ }
398
+ const name = meta.name?.trim();
399
+ const instructions = m[2].trim();
400
+ if (!name || !instructions) return null;
401
+ const tools = meta.tools ? meta.tools.split(",").map((t) => unquote(t.trim())).filter(Boolean) : [];
402
+ return { id, name, description: meta.description ?? "", instructions, tools, builtin: false };
403
+ }
404
+ function unquote(s) {
405
+ return s.replace(/^["']|["']$/g, "").trim();
406
+ }
407
+ function oneLine(s) {
408
+ return s.replace(/\s*\n\s*/g, " ").trim();
409
+ }
410
+ var SkillStore = class {
411
+ constructor(dataDir) {
412
+ this.dataDir = dataDir;
413
+ }
414
+ dataDir;
415
+ get skillsDir() {
416
+ return join2(this.dataDir, "skills");
417
+ }
418
+ list() {
419
+ const skills = [...BUILTIN_SKILLS];
420
+ const idSet = new Set(skills.map((s) => s.id));
421
+ if (!existsSync2(this.skillsDir)) return skills;
422
+ for (const e of readdirSync(this.skillsDir, { withFileTypes: true })) {
423
+ let skill = null;
424
+ let id = "";
425
+ if (e.isDirectory()) {
426
+ id = e.name;
427
+ const md = join2(this.skillsDir, e.name, "SKILL.md");
428
+ if (existsSync2(md)) skill = this.loadMd(id, md);
429
+ } else if (e.isFile() && e.name.endsWith(".json")) {
430
+ id = e.name.slice(0, -5);
431
+ skill = this.loadJson(join2(this.skillsDir, e.name), id);
432
+ }
433
+ if (!skill || !id || idSet.has(id)) continue;
434
+ idSet.add(id);
435
+ skills.push(skill);
436
+ }
437
+ return skills;
438
+ }
439
+ /** Only the user-created (non-builtin) skills, for injection + the library UI. */
440
+ userSkills() {
441
+ return this.list().filter((s) => !s.builtin);
442
+ }
443
+ get(id) {
444
+ return this.list().find((s) => s.id === id);
445
+ }
446
+ has(id) {
447
+ return isValidSkillId(id) && existsSync2(join2(this.skillsDir, id, "SKILL.md"));
448
+ }
449
+ write(skill) {
450
+ if (!isValidSkillId(skill.id)) throw new Error(`Invalid skill id: ${skill.id}`);
451
+ const dir = join2(this.skillsDir, skill.id);
452
+ mkdirSync2(dir, { recursive: true });
453
+ writeFileSync2(join2(dir, "SKILL.md"), toSkillMd(skill), "utf8");
454
+ }
455
+ delete(id) {
456
+ if (!isValidSkillId(id)) return;
457
+ rmSync(join2(this.skillsDir, id), { recursive: true, force: true });
458
+ const legacy = join2(this.skillsDir, `${id}.json`);
459
+ if (existsSync2(legacy)) rmSync(legacy);
460
+ }
461
+ loadMd(id, path) {
462
+ try {
463
+ return fromSkillMd(id, readFileSync2(path, "utf8"));
464
+ } catch {
465
+ return null;
466
+ }
467
+ }
468
+ loadJson(path, id) {
469
+ try {
470
+ const data = JSON.parse(readFileSync2(path, "utf8"));
471
+ if (!data.name || typeof data.name !== "string") return null;
472
+ if (!data.instructions || typeof data.instructions !== "string") return null;
473
+ return { id, name: data.name, description: data.description || "", instructions: data.instructions, tools: Array.isArray(data.tools) ? data.tools : [], builtin: false };
474
+ } catch {
475
+ return null;
476
+ }
477
+ }
478
+ };
479
+ function isValidSkillId(id) {
480
+ return typeof id === "string" && /^[a-z0-9-]{1,64}$/.test(id);
481
+ }
482
+
483
+ // src/agents/distiller.ts
484
+ import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync, existsSync as existsSync3 } from "fs";
485
+ import { join as join3 } from "path";
482
486
 
483
487
  // src/engines/download.ts
484
488
  import { createWriteStream, existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
@@ -1597,7 +1601,7 @@ import {
1597
1601
  SettingsManager,
1598
1602
  isEditToolResult
1599
1603
  } from "@earendil-works/pi-coding-agent";
1600
- import { estimateTokens, calculateContextTokens } from "@earendil-works/pi-coding-agent";
1604
+ import { estimateTokens as estimateTokens2, calculateContextTokens } from "@earendil-works/pi-coding-agent";
1601
1605
 
1602
1606
  // src/code/robust-bash.ts
1603
1607
  import { access as fsAccess } from "fs/promises";
@@ -3274,12 +3278,12 @@ ${lines.join("\n")}${more}]`
3274
3278
  if (lastUsage) {
3275
3279
  contextUsed = calculateContextTokens(lastUsage);
3276
3280
  for (let i = lastUsageIdx + 1; i < session.messages.length; i++) {
3277
- contextUsed += estimateTokens(session.messages[i]);
3281
+ contextUsed += estimateTokens2(session.messages[i]);
3278
3282
  }
3279
3283
  } else {
3280
3284
  contextUsed = 0;
3281
3285
  for (const m of session.messages) {
3282
- contextUsed += estimateTokens(m);
3286
+ contextUsed += estimateTokens2(m);
3283
3287
  }
3284
3288
  }
3285
3289
  }