wherdr 1.3.3 → 2.0.0

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 (252) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/BDNMzG2s.js +1 -0
  3. package/.output/public/_nuxt/BETID3_E.js +1 -0
  4. package/.output/public/_nuxt/BHenDMeH.js +1 -0
  5. package/.output/public/_nuxt/BYZVrreW.js +1 -0
  6. package/.output/public/_nuxt/BhgehRdJ.js +1 -0
  7. package/.output/public/_nuxt/{yzABg5xl.js → Bpoxvzh6.js} +1 -1
  8. package/.output/public/_nuxt/BtH82ZuZ.js +9 -0
  9. package/.output/public/_nuxt/C25ROUa9.js +3 -0
  10. package/.output/public/_nuxt/C3Bkn4ac.js +62 -0
  11. package/.output/public/_nuxt/CDWjMk9C.js +2 -0
  12. package/.output/public/_nuxt/{Ci8N4mWR.js → CXJnLmWv.js} +1 -1
  13. package/.output/public/_nuxt/CuUQ4mEf.js +1 -0
  14. package/.output/public/_nuxt/DFGEl0v2.js +23 -0
  15. package/.output/public/_nuxt/{CKhgznq4.js → DFmgQVme.js} +42 -39
  16. package/.output/public/_nuxt/DZGKxROq.js +6 -0
  17. package/.output/public/_nuxt/DmkWvmnE.js +2 -0
  18. package/.output/public/_nuxt/DrKKeFFE.js +31 -0
  19. package/.output/public/_nuxt/DyfFwwGq.js +1 -0
  20. package/.output/public/_nuxt/FaNto0ga.js +105 -0
  21. package/.output/public/_nuxt/NIF0VwHk.js +25 -0
  22. package/.output/public/_nuxt/R0Y4VoeX.js +1 -0
  23. package/.output/public/_nuxt/board.CEEcFc6M.css +1 -0
  24. package/.output/public/_nuxt/builds/latest.json +1 -1
  25. package/.output/public/_nuxt/builds/meta/0b28b3e9-664e-4347-a35b-afb0a711d5c5.json +1 -0
  26. package/.output/public/_nuxt/entry.CKoXcwRa.css +2 -0
  27. package/.output/public/_nuxt/pdf.min.t82Z80JU.mjs +28 -0
  28. package/.output/public/_nuxt/pdf.worker.min.wgc6bjNh.mjs +28 -0
  29. package/.output/public/_nuxt/settings.Cdb21nNw.css +1 -0
  30. package/.output/public/sw.js +1 -1
  31. package/.output/server/chunks/_/branding.mjs +1 -1
  32. package/.output/server/chunks/_/changes.mjs +4 -4
  33. package/.output/server/chunks/_/fileDownload.mjs +278 -0
  34. package/.output/server/chunks/_/files.mjs +60 -20
  35. package/.output/server/chunks/_/machineOrder.mjs +1 -1
  36. package/.output/server/chunks/_/onboarding.mjs +1 -1
  37. package/.output/server/chunks/_/package.mjs +11 -3
  38. package/.output/server/chunks/_/plugins.mjs +92 -122
  39. package/.output/server/chunks/_/restart.mjs +1 -1
  40. package/.output/server/chunks/_/selfupdate.mjs +1 -1
  41. package/.output/server/chunks/_/settingstabs.mjs +36 -0
  42. package/.output/server/chunks/_/updates.mjs +1 -1
  43. package/.output/server/chunks/_/worktrees.mjs +1 -1
  44. package/.output/server/chunks/_/ws.mjs +43 -6
  45. package/.output/server/chunks/nitro/nitro.mjs +14126 -10238
  46. package/.output/server/chunks/raw/check-doc-links.mjs +5 -0
  47. package/.output/server/chunks/raw/check-leaks.mjs +1 -1
  48. package/.output/server/chunks/raw/check-release-notes.mjs +5 -0
  49. package/.output/server/chunks/raw/herdr-plugin.mjs +1 -1
  50. package/.output/server/chunks/raw/install-claude-statusline.mjs +1 -1
  51. package/.output/server/chunks/raw/prerelease-summary.mjs +5 -0
  52. package/.output/server/chunks/raw/prerelease.mjs +7 -0
  53. package/.output/server/chunks/raw/reveal.mjs +1 -1
  54. package/.output/server/chunks/raw/test-affected.mjs +5 -0
  55. package/.output/server/chunks/routes/api/_..._.mjs +6 -5
  56. package/.output/server/chunks/routes/api/agents.post.mjs +6 -5
  57. package/.output/server/chunks/routes/api/ask-tab.post.mjs +6 -5
  58. package/.output/server/chunks/routes/api/attach.post.mjs +6 -5
  59. package/.output/server/chunks/routes/api/auth/disable.post.mjs +6 -5
  60. package/.output/server/chunks/routes/api/auth/lock-all.post.mjs +6 -5
  61. package/.output/server/chunks/routes/api/auth/lock.post.mjs +6 -5
  62. package/.output/server/chunks/routes/api/auth/login/options.post.mjs +6 -5
  63. package/.output/server/chunks/routes/api/auth/login/verify.post.mjs +6 -5
  64. package/.output/server/chunks/routes/api/auth/max-session.post.mjs +6 -5
  65. package/.output/server/chunks/routes/api/auth/register/options.post.mjs +6 -5
  66. package/.output/server/chunks/routes/api/auth/register/verify.post.mjs +6 -5
  67. package/.output/server/chunks/routes/api/auth/status.get.mjs +6 -5
  68. package/.output/server/chunks/routes/api/changes.get.mjs +7 -6
  69. package/.output/server/chunks/routes/api/chat/image.get.mjs +7 -6
  70. package/.output/server/chunks/routes/api/chat.get.mjs +44 -11
  71. package/.output/server/chunks/routes/api/choose.post.mjs +44 -30
  72. package/.output/server/chunks/routes/api/claude-setup.post.mjs +42 -0
  73. package/.output/server/chunks/routes/api/claude-statusline.post.mjs +7 -6
  74. package/.output/server/chunks/routes/api/clear-queued-input.post.mjs +42 -0
  75. package/.output/server/chunks/routes/api/close/status.get.mjs +7 -6
  76. package/.output/server/chunks/routes/api/close.post.mjs +6 -5
  77. package/.output/server/chunks/routes/api/codex-update.post.mjs +7 -6
  78. package/.output/server/chunks/routes/api/commands.get.mjs +9 -7
  79. package/.output/server/chunks/routes/api/config.get.mjs +10 -13
  80. package/.output/server/chunks/routes/api/dirs.get.mjs +7 -6
  81. package/.output/server/chunks/routes/api/dismiss-stopped.post.mjs +7 -6
  82. package/.output/server/chunks/routes/api/dismiss.post.mjs +7 -6
  83. package/.output/server/chunks/routes/api/effort.post.mjs +7 -6
  84. package/.output/server/chunks/routes/api/efforts.get.mjs +7 -6
  85. package/.output/server/chunks/routes/api/file.post.mjs +7 -6
  86. package/.output/server/chunks/routes/api/files/download.get.mjs +12 -24
  87. package/.output/server/chunks/routes/api/files/download.head.mjs +41 -0
  88. package/.output/server/chunks/routes/api/files/read.get.mjs +8 -7
  89. package/.output/server/chunks/routes/api/files.get.mjs +7 -6
  90. package/.output/server/chunks/routes/api/health.get.mjs +6 -5
  91. package/.output/server/chunks/routes/api/input.post.mjs +33 -15
  92. package/.output/server/chunks/routes/api/interrupt.post.mjs +24 -21
  93. package/.output/server/chunks/routes/api/isgit.get.mjs +8 -8
  94. package/.output/server/chunks/routes/api/machine/awake.get.mjs +7 -6
  95. package/.output/server/chunks/routes/api/machine/awake.post.mjs +7 -6
  96. package/.output/server/chunks/routes/api/machine/order.get.mjs +6 -5
  97. package/.output/server/chunks/routes/api/machine/order.post.mjs +6 -5
  98. package/.output/server/chunks/routes/api/machine/reconnect.post.mjs +40 -0
  99. package/.output/server/chunks/routes/api/machine/rename.post.mjs +7 -6
  100. package/.output/server/chunks/routes/api/machine/status.post.mjs +39 -0
  101. package/.output/server/chunks/routes/api/menu-left.post.mjs +40 -0
  102. package/.output/server/chunks/routes/api/menu.post.mjs +10 -6
  103. package/.output/server/chunks/routes/api/model.post.mjs +7 -6
  104. package/.output/server/chunks/routes/api/models.get.mjs +7 -6
  105. package/.output/server/chunks/routes/api/nav.post.mjs +40 -26
  106. package/.output/server/chunks/routes/api/onboarding.get.mjs +6 -5
  107. package/.output/server/chunks/routes/api/onboarding.post.mjs +6 -5
  108. package/.output/server/chunks/routes/api/phone.get.mjs +8 -10
  109. package/.output/server/chunks/routes/api/phone.post.mjs +8 -10
  110. package/.output/server/chunks/routes/api/plugins/actions.get.mjs +6 -8
  111. package/.output/server/chunks/routes/api/plugins/invoke.post.mjs +6 -8
  112. package/.output/server/chunks/routes/api/plugins/projects.get.mjs +10 -8
  113. package/.output/server/chunks/routes/api/plugins/projects.post.mjs +11 -7
  114. package/.output/server/chunks/routes/api/prompt.post.mjs +22 -13
  115. package/.output/server/chunks/routes/api/push/quiet.post.mjs +7 -6
  116. package/.output/server/chunks/routes/api/push/subscribe.post.mjs +7 -7
  117. package/.output/server/chunks/routes/api/push/test.post.mjs +7 -6
  118. package/.output/server/chunks/routes/api/push/unsubscribe.post.mjs +7 -6
  119. package/.output/server/chunks/routes/api/quotas.get.mjs +7 -6
  120. package/.output/server/chunks/routes/api/rename.post.mjs +6 -5
  121. package/.output/server/chunks/routes/api/requeue.post.mjs +7 -6
  122. package/.output/server/chunks/routes/api/restart.get.mjs +6 -5
  123. package/.output/server/chunks/routes/api/restart.post.mjs +6 -5
  124. package/.output/server/chunks/routes/api/reveal.post.mjs +91 -8
  125. package/.output/server/chunks/routes/api/screen-key.post.mjs +19 -15
  126. package/.output/server/chunks/routes/api/screen.get.mjs +8 -40
  127. package/.output/server/chunks/routes/api/search.get.mjs +7 -6
  128. package/.output/server/chunks/routes/api/seen.post.mjs +7 -6
  129. package/.output/server/chunks/routes/api/sessions.get.mjs +7 -6
  130. package/.output/server/chunks/routes/api/sessions.post.mjs +7 -6
  131. package/.output/server/chunks/routes/api/settings-tab.post.mjs +90 -0
  132. package/.output/server/chunks/routes/api/{plugins/thread-limits.get.mjs → settings.get.mjs} +10 -9
  133. package/.output/server/chunks/routes/api/settings.post.mjs +40 -0
  134. package/.output/server/chunks/routes/api/space.post.mjs +34 -18
  135. package/.output/server/chunks/routes/api/state.get.mjs +7 -6
  136. package/.output/server/chunks/routes/api/tasks/action.post.mjs +39 -0
  137. package/.output/server/chunks/routes/api/{plugins/profiles.get.mjs → tasks/add.post.mjs} +12 -14
  138. package/.output/server/chunks/routes/api/tasks/after.post.mjs +39 -0
  139. package/.output/server/chunks/routes/api/tasks/approve.post.mjs +39 -0
  140. package/.output/server/chunks/routes/api/{project/report.get.mjs → tasks/archived.get.mjs} +12 -13
  141. package/.output/server/chunks/routes/api/{gitroot.get.mjs → tasks/autopilot.get.mjs} +13 -14
  142. package/.output/server/chunks/routes/api/tasks/autopilot.post.mjs +39 -0
  143. package/.output/server/chunks/routes/api/{index.get.mjs → tasks/board-settings.get.mjs} +12 -13
  144. package/.output/server/chunks/routes/api/tasks/board-settings.post.mjs +39 -0
  145. package/.output/server/chunks/routes/api/tasks/coordinator.get.mjs +40 -0
  146. package/.output/server/chunks/routes/api/tasks/coordinator.post.mjs +39 -0
  147. package/.output/server/chunks/routes/api/tasks/details.get.mjs +40 -0
  148. package/.output/server/chunks/routes/api/tasks/limit.post.mjs +39 -0
  149. package/.output/server/chunks/routes/api/tasks/links.get.mjs +39 -0
  150. package/.output/server/chunks/routes/api/tasks/models.get.mjs +40 -0
  151. package/.output/server/chunks/routes/api/tasks/pick.post.mjs +39 -0
  152. package/.output/server/chunks/routes/api/tasks/question.post.mjs +39 -0
  153. package/.output/server/chunks/routes/api/tasks/scheduled.get.mjs +40 -0
  154. package/.output/server/chunks/routes/api/{project → tasks}/settings.get.mjs +10 -11
  155. package/.output/server/chunks/routes/api/tasks/start.get.mjs +40 -0
  156. package/.output/server/chunks/routes/api/tasks/tell.post.mjs +39 -0
  157. package/.output/server/chunks/routes/api/tasks.get.mjs +39 -0
  158. package/.output/server/chunks/routes/api/unqueue.post.mjs +7 -6
  159. package/.output/server/chunks/routes/api/update/status.get.mjs +6 -5
  160. package/.output/server/chunks/routes/api/update.get.mjs +8 -10
  161. package/.output/server/chunks/routes/api/update.post.mjs +8 -10
  162. package/.output/server/chunks/routes/api/upload.post.mjs +7 -6
  163. package/.output/server/chunks/routes/api/worktrees/remove.post.mjs +6 -5
  164. package/.output/server/chunks/routes/api/worktrees.get.mjs +6 -5
  165. package/.output/server/chunks/routes/favicon.ico.get.mjs +6 -5
  166. package/.output/server/chunks/routes/icons/_name_.get.mjs +7 -6
  167. package/.output/server/chunks/routes/renderer.mjs +8 -7
  168. package/.output/server/chunks/routes/uploads/_...name_.get.mjs +7 -6
  169. package/.output/server/chunks/routes/ws/_..._.mjs +7 -6
  170. package/.output/server/chunks/routes/ws/events.mjs +9 -7
  171. package/.output/server/chunks/routes/ws/term.mjs +7 -6
  172. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  173. package/.output/server/index.mjs +7 -6
  174. package/.output/server/package.json +1 -1
  175. package/README.md +44 -1424
  176. package/bin/lib/commands.mjs +44 -9
  177. package/bin/lib/panel.mjs +3 -11
  178. package/bin/lib/service.mjs +41 -2
  179. package/bin/lib/skill.mjs +1 -1
  180. package/bin/lib/tailnet.d.mts +6 -3
  181. package/bin/lib/tailnet.mjs +70 -32
  182. package/bin/lib/userpath.d.mts +14 -0
  183. package/bin/lib/userpath.mjs +142 -0
  184. package/docs/README.md +58 -0
  185. package/docs/RELEASING.md +174 -0
  186. package/docs/board.md +164 -0
  187. package/docs/command.md +58 -0
  188. package/docs/configuration.md +39 -0
  189. package/docs/conversation.md +132 -0
  190. package/docs/development.md +38 -0
  191. package/docs/devices.md +58 -0
  192. package/docs/files.md +29 -0
  193. package/docs/herdr-projects-1x.md +278 -0
  194. package/docs/home.md +52 -0
  195. package/docs/installation.md +174 -0
  196. package/docs/machines.md +69 -0
  197. package/docs/migrate-from-1.x-docker.md +160 -0
  198. package/docs/networks.md +154 -0
  199. package/docs/notifications.md +83 -0
  200. package/docs/overview.md +71 -0
  201. package/docs/phone.md +26 -0
  202. package/docs/plugins.md +109 -0
  203. package/docs/quick-start.md +89 -0
  204. package/docs/quotas.md +65 -0
  205. package/docs/release-notes-2.0.0.md +84 -0
  206. package/docs/security.md +117 -0
  207. package/docs/terminal.md +15 -0
  208. package/docs/troubleshooting.md +45 -0
  209. package/package.json +11 -3
  210. package/skills/wherdr/SKILL.md +24 -167
  211. package/.output/public/_nuxt/B4Yk2tB1.js +0 -23
  212. package/.output/public/_nuxt/BBw_0a4M.js +0 -6
  213. package/.output/public/_nuxt/BSy6OCIY.js +0 -1
  214. package/.output/public/_nuxt/BX5PM2JQ.js +0 -1
  215. package/.output/public/_nuxt/BgPDnf2S.js +0 -1
  216. package/.output/public/_nuxt/BkOxQzbS.js +0 -2
  217. package/.output/public/_nuxt/CP8o925U.js +0 -1
  218. package/.output/public/_nuxt/CWwyK2XK.js +0 -2
  219. package/.output/public/_nuxt/CkbmecwS.js +0 -1
  220. package/.output/public/_nuxt/Cr3SrGky.js +0 -1
  221. package/.output/public/_nuxt/DAg9fiVh.js +0 -89
  222. package/.output/public/_nuxt/DT8qZ0Wv.js +0 -1
  223. package/.output/public/_nuxt/DaaJIRB3.js +0 -1
  224. package/.output/public/_nuxt/DcJi16XA.js +0 -1
  225. package/.output/public/_nuxt/SiL1FJ5s.js +0 -3
  226. package/.output/public/_nuxt/VpjCgSXu.js +0 -36
  227. package/.output/public/_nuxt/builds/meta/c735b6c0-1bd0-47d7-a208-d310f0a06287.json +0 -1
  228. package/.output/public/_nuxt/dPxB2L94.js +0 -89
  229. package/.output/public/_nuxt/entry.CGWKmYU3.css +0 -2
  230. package/.output/public/_nuxt/xYX85SPI.js +0 -1
  231. package/.output/server/chunks/_/pluginPolicy.mjs +0 -93
  232. package/.output/server/chunks/_/projectBoard.mjs +0 -366
  233. package/.output/server/chunks/_/projectDocs.mjs +0 -106
  234. package/.output/server/chunks/_/projectInbox.mjs +0 -135
  235. package/.output/server/chunks/_/projectThreads.mjs +0 -46
  236. package/.output/server/chunks/_/projectThreads2.mjs +0 -61
  237. package/.output/server/chunks/_/projectsActions.mjs +0 -143
  238. package/.output/server/chunks/_/projectsPlugin.mjs +0 -56
  239. package/.output/server/chunks/_/reveal.mjs +0 -115
  240. package/.output/server/chunks/raw/dev.wherdr.open.mjs +0 -7
  241. package/.output/server/chunks/raw/docker-entrypoint.mjs +0 -7
  242. package/.output/server/chunks/raw/install-host-open.mjs +0 -7
  243. package/.output/server/chunks/raw/wherdr-open.mjs +0 -7
  244. package/.output/server/chunks/routes/api/board.get.mjs +0 -147
  245. package/.output/server/chunks/routes/api/plugins/thread-limits.post.mjs +0 -45
  246. package/.output/server/chunks/routes/api/project/inbox.get.mjs +0 -43
  247. package/.output/server/chunks/routes/api/project/inbox.post.mjs +0 -43
  248. package/.output/server/chunks/routes/api/project/memory.get.mjs +0 -42
  249. package/.output/server/chunks/routes/api/project/routines.get.mjs +0 -43
  250. package/.output/server/chunks/routes/api/project/thread.get.mjs +0 -44
  251. package/.output/server/chunks/routes/api/project/thread.post.mjs +0 -45
  252. package/bin/install-docker-skill.sh +0 -20
@@ -0,0 +1 @@
1
+ .notification-level[data-v-aa9b4e30]{flex-direction:column;gap:6px;min-width:0;display:flex}.notification-level select[data-v-aa9b4e30]{border:1px solid var(--line);background:var(--bg);max-width:100%;min-height:44px;color:var(--text);font:inherit;border-radius:0;padding:8px}.notification-level-hint[data-v-aa9b4e30]{color:var(--muted);font-size:12px}.notification-customize summary[data-v-aa9b4e30]{cursor:pointer;min-height:36px;color:var(--muted);align-items:center;gap:4px;font-size:13px;list-style:none;display:flex}.notification-customize summary[data-v-aa9b4e30]::-webkit-details-marker{display:none}.notification-chev[data-v-aa9b4e30]{transition:transform .15s}.notification-customize[open] .notification-chev[data-v-aa9b4e30]{transform:rotate(90deg)}.notification-events[data-v-aa9b4e30]{flex-wrap:wrap;gap:4px 18px;display:flex}.notification-events label[data-v-aa9b4e30]{align-items:center;gap:6px;min-height:44px;display:flex}.notification-events input[data-v-aa9b4e30]{accent-color:var(--accent)}.notification-rules .settings-toggle[data-v-aeafb17e]{gap:16px}.notification-rules .settings-toggle>span[data-v-aeafb17e]{flex:1;min-width:0}.notification-default[data-v-aeafb17e]>.notification-level{margin-bottom:8px}.notification-help[data-v-aeafb17e]{margin:8px 0 0;font-size:12px}.notification-rule[data-v-aeafb17e]{border:1px solid var(--line);flex-direction:column;gap:10px;min-width:0;margin:12px 0;padding:14px;display:flex}.notification-rule-head b[data-v-aeafb17e],.notification-rule-head small[data-v-aeafb17e]{overflow-wrap:anywhere;display:block}.notification-rule-head small[data-v-aeafb17e]{color:var(--muted);font:11px var(--mono);margin-bottom:4px}.notification-rule-head .notification-diff[data-v-aeafb17e]{font:12px var(--sans,inherit);margin:4px 0 0}.notification-rule .settings-action small[data-v-aeafb17e]{margin-left:auto;padding-left:8px;font-size:11px}.notification-add[data-v-aeafb17e]{margin-top:12px}.notification-picker[data-v-aeafb17e]{border:1px solid var(--line);flex-direction:column;gap:12px;margin-top:8px;padding:12px;display:flex}.notification-picker-group[data-v-aeafb17e]{flex-direction:column;gap:4px;display:flex}.notification-picker-group>small[data-v-aeafb17e]{color:var(--muted);font:11px var(--mono)}.notification-reset[data-v-aeafb17e]{margin-top:16px}
@@ -15,7 +15,7 @@
15
15
  var sw = self;
16
16
  var CACHE = "wherdr-v1";
17
17
  var NETWORK_WAIT_MS = 3e3;
18
- var PRECACHE = ["/", ...[{"revision":"e6a852ba6e2a724d2255af526cb04083","url":"manifest.webmanifest"},{"revision":"b1a14fab8c06784649bf26c636747a86","url":"manifest-en.webmanifest"},{"revision":null,"url":"_nuxt/yzABg5xl.js"},{"revision":null,"url":"_nuxt/xYX85SPI.js"},{"revision":null,"url":"_nuxt/wherdr-symbols.C1LsPKmg.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-powerline.B_kAMxXr.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-octicons.Hl4VEx8m.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-material-4.CO_PudDR.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-material-3.8xz7iX-Y.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-material-2.C_flbBWO.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-material-1.BdvqkCqW.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-extension.Dai_ky39.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-devicons.ZMSFX1sW.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-codicons.CtEsfSAf.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-awesome.DQ3_iAfa.woff2"},{"revision":null,"url":"_nuxt/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2"},{"revision":null,"url":"_nuxt/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2"},{"revision":null,"url":"_nuxt/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2"},{"revision":null,"url":"_nuxt/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2"},{"revision":null,"url":"_nuxt/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2"},{"revision":null,"url":"_nuxt/inter-vietnamese-wght-normal.CBcvBZtf.woff2"},{"revision":null,"url":"_nuxt/inter-latin-wght-normal.Dx4kXJAl.woff2"},{"revision":null,"url":"_nuxt/inter-latin-ext-wght-normal.DO1Apj_S.woff2"},{"revision":null,"url":"_nuxt/inter-greek-wght-normal.CkhJZR-_.woff2"},{"revision":null,"url":"_nuxt/inter-greek-ext-wght-normal.DlzME5K_.woff2"},{"revision":null,"url":"_nuxt/inter-cyrillic-wght-normal.DqGufNeO.woff2"},{"revision":null,"url":"_nuxt/inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2"},{"revision":null,"url":"_nuxt/hePW80VL.js"},{"revision":null,"url":"_nuxt/error-500.Bwd7zAaE.css"},{"revision":null,"url":"_nuxt/error-404.Bb87HomL.css"},{"revision":null,"url":"_nuxt/entry.CGWKmYU3.css"},{"revision":null,"url":"_nuxt/dPxB2L94.js"},{"revision":null,"url":"_nuxt/archivo-vietnamese-wght-normal.XAtsl5Q_.woff2"},{"revision":null,"url":"_nuxt/archivo-latin-wght-normal.E0tuGl4L.woff2"},{"revision":null,"url":"_nuxt/archivo-latin-ext-wght-normal.C4zznr8T.woff2"},{"revision":null,"url":"_nuxt/VpjCgSXu.js"},{"revision":null,"url":"_nuxt/SiL1FJ5s.js"},{"revision":null,"url":"_nuxt/DcJi16XA.js"},{"revision":null,"url":"_nuxt/DaaJIRB3.js"},{"revision":null,"url":"_nuxt/DT8qZ0Wv.js"},{"revision":null,"url":"_nuxt/DAg9fiVh.js"},{"revision":null,"url":"_nuxt/Cr3SrGky.js"},{"revision":null,"url":"_nuxt/CkbmecwS.js"},{"revision":null,"url":"_nuxt/Ci8N4mWR.js"},{"revision":null,"url":"_nuxt/CWwyK2XK.js"},{"revision":null,"url":"_nuxt/CP8o925U.js"},{"revision":null,"url":"_nuxt/CKhgznq4.js"},{"revision":null,"url":"_nuxt/BkOxQzbS.js"},{"revision":null,"url":"_nuxt/BgPDnf2S.js"},{"revision":null,"url":"_nuxt/Bd17z0YL.js"},{"revision":null,"url":"_nuxt/BX5PM2JQ.js"},{"revision":null,"url":"_nuxt/BSy6OCIY.js"},{"revision":null,"url":"_nuxt/BBw_0a4M.js"},{"revision":null,"url":"_nuxt/B4Yk2tB1.js"},{"revision":null,"url":"_nuxt/AgentView.DzFWBd2A.css"},{"revision":"f0fc32f393fea2b75a91e3f10a5be779","url":"_nuxt/builds/latest.json"},{"revision":null,"url":"_nuxt/builds/meta/c735b6c0-1bd0-47d7-a208-d310f0a06287.json"}].map((e) => "/" + (typeof e === "string" ? e : e.url).replace(/^\//, ""))];
18
+ var PRECACHE = ["/", ...[{"revision":"e6a852ba6e2a724d2255af526cb04083","url":"manifest.webmanifest"},{"revision":"b1a14fab8c06784649bf26c636747a86","url":"manifest-en.webmanifest"},{"revision":null,"url":"_nuxt/wherdr-symbols.C1LsPKmg.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-powerline.B_kAMxXr.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-octicons.Hl4VEx8m.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-material-4.CO_PudDR.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-material-3.8xz7iX-Y.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-material-2.C_flbBWO.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-material-1.BdvqkCqW.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-extension.Dai_ky39.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-devicons.ZMSFX1sW.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-codicons.CtEsfSAf.woff2"},{"revision":null,"url":"_nuxt/wherdr-nerd-awesome.DQ3_iAfa.woff2"},{"revision":null,"url":"_nuxt/settings.Cdb21nNw.css"},{"revision":null,"url":"_nuxt/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2"},{"revision":null,"url":"_nuxt/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2"},{"revision":null,"url":"_nuxt/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2"},{"revision":null,"url":"_nuxt/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2"},{"revision":null,"url":"_nuxt/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2"},{"revision":null,"url":"_nuxt/inter-vietnamese-wght-normal.CBcvBZtf.woff2"},{"revision":null,"url":"_nuxt/inter-latin-wght-normal.Dx4kXJAl.woff2"},{"revision":null,"url":"_nuxt/inter-latin-ext-wght-normal.DO1Apj_S.woff2"},{"revision":null,"url":"_nuxt/inter-greek-wght-normal.CkhJZR-_.woff2"},{"revision":null,"url":"_nuxt/inter-greek-ext-wght-normal.DlzME5K_.woff2"},{"revision":null,"url":"_nuxt/inter-cyrillic-wght-normal.DqGufNeO.woff2"},{"revision":null,"url":"_nuxt/inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2"},{"revision":null,"url":"_nuxt/hePW80VL.js"},{"revision":null,"url":"_nuxt/error-500.Bwd7zAaE.css"},{"revision":null,"url":"_nuxt/error-404.Bb87HomL.css"},{"revision":null,"url":"_nuxt/entry.CKoXcwRa.css"},{"revision":null,"url":"_nuxt/board.CEEcFc6M.css"},{"revision":null,"url":"_nuxt/archivo-vietnamese-wght-normal.XAtsl5Q_.woff2"},{"revision":null,"url":"_nuxt/archivo-latin-wght-normal.E0tuGl4L.woff2"},{"revision":null,"url":"_nuxt/archivo-latin-ext-wght-normal.C4zznr8T.woff2"},{"revision":null,"url":"_nuxt/R0Y4VoeX.js"},{"revision":null,"url":"_nuxt/NIF0VwHk.js"},{"revision":null,"url":"_nuxt/FaNto0ga.js"},{"revision":null,"url":"_nuxt/DyfFwwGq.js"},{"revision":null,"url":"_nuxt/DrKKeFFE.js"},{"revision":null,"url":"_nuxt/DmkWvmnE.js"},{"revision":null,"url":"_nuxt/DZGKxROq.js"},{"revision":null,"url":"_nuxt/DFmgQVme.js"},{"revision":null,"url":"_nuxt/DFGEl0v2.js"},{"revision":null,"url":"_nuxt/CuUQ4mEf.js"},{"revision":null,"url":"_nuxt/CXJnLmWv.js"},{"revision":null,"url":"_nuxt/CDWjMk9C.js"},{"revision":null,"url":"_nuxt/C3Bkn4ac.js"},{"revision":null,"url":"_nuxt/C25ROUa9.js"},{"revision":null,"url":"_nuxt/BtH82ZuZ.js"},{"revision":null,"url":"_nuxt/Bpoxvzh6.js"},{"revision":null,"url":"_nuxt/BhgehRdJ.js"},{"revision":null,"url":"_nuxt/Bd17z0YL.js"},{"revision":null,"url":"_nuxt/BYZVrreW.js"},{"revision":null,"url":"_nuxt/BHenDMeH.js"},{"revision":null,"url":"_nuxt/BETID3_E.js"},{"revision":null,"url":"_nuxt/BDNMzG2s.js"},{"revision":null,"url":"_nuxt/AgentView.DzFWBd2A.css"},{"revision":"cd669ad19a6e6aac95c99782fbde9967","url":"_nuxt/builds/latest.json"},{"revision":null,"url":"_nuxt/builds/meta/0b28b3e9-664e-4347-a35b-afb0a711d5c5.json"}].map((e) => "/" + (typeof e === "string" ? e : e.url).replace(/^\//, ""))];
19
19
  sw.addEventListener("install", (e) => {
20
20
  e.waitUntil((async () => {
21
21
  const c = await caches.open(CACHE);
@@ -1,4 +1,4 @@
1
- import { s as sendError, bJ as useStorage, aC as setResponseHeader } from '../nitro/nitro.mjs';
1
+ import { s as sendError, cd as useStorage, aw as setResponseHeader } from '../nitro/nitro.mjs';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
 
@@ -55,7 +55,7 @@ function parseNumstat(raw) {
55
55
  }
56
56
  return stats;
57
57
  }
58
- function runner(m) {
58
+ function runner(m, signal) {
59
59
  const remoteExec = m.exec;
60
60
  if (remoteExec) return async (script, args, timeout = 12e3) => {
61
61
  const r = await remoteExec(script, args, { timeoutMs: timeout });
@@ -63,7 +63,7 @@ function runner(m) {
63
63
  return r.stdout;
64
64
  };
65
65
  return (script, args, timeout = 12e3) => new Promise((resolve, reject) => {
66
- execFile("sh", ["-c", script, "sh", ...args], { timeout, encoding: "buffer", maxBuffer: 512 * 1024 }, (err, out, stderr) => {
66
+ execFile("sh", ["-c", script, "sh", ...args], { timeout, encoding: "buffer", maxBuffer: 512 * 1024, signal }, (err, out, stderr) => {
67
67
  if (err) reject(new Error(String(stderr || err.message).trim()));
68
68
  else resolve(out);
69
69
  });
@@ -72,8 +72,8 @@ function runner(m) {
72
72
  const git = "git --no-optional-locks -c core.fsmonitor=false -c core.hooksPath=/dev/null -c core.quotePath=false -c diff.external=";
73
73
  const generated = /(^|\/)(?:dist|build|generated|coverage|node_modules|\.nuxt)\/|(^|\/)(?:package-lock\.json|pnpm-lock\.yaml|yarn\.lock|Cargo\.lock|composer\.lock|Gemfile\.lock|.*\.min\.(?:js|css)|.*\.map|.*\.generated\.[^/]+)$/i;
74
74
  const emptySet = () => ({ files: [], truncated: false, count: 0 });
75
- async function gitToplevel(m, cwd) {
76
- const out = await runner(m)(`cd "$1" 2>/dev/null && ${git} rev-parse --show-toplevel 2>/dev/null || true`, [cwd]).catch(() => Buffer.alloc(0));
75
+ async function gitToplevel(m, cwd, signal) {
76
+ const out = await runner(m, signal)(`cd "$1" 2>/dev/null && ${git} rev-parse --show-toplevel 2>/dev/null || true`, [cwd]).catch(() => Buffer.alloc(0));
77
77
  return out.toString("utf8").trim();
78
78
  }
79
79
  async function readChangeStatus(m, cwd) {
@@ -0,0 +1,278 @@
1
+ import { H as HerdrError, a as defineApi, i as getQuery, f as findPane, m as machineFor, aw as setResponseHeader, ax as getRequestHeader, ay as setResponseStatus } from '../nitro/nitro.mjs';
2
+ import { w as writtenTarget, c as cleanRelative, r as rootOf, i as isVideo, O as OPEN_FILE, V as VIDEO_HEAD, s as shellError, v as videoType, a as readWrittenBytes, b as readFileBytes, d as isPdf, e as attachmentHeader } from './files.mjs';
3
+ import { spawn } from 'node:child_process';
4
+ import crypto from 'node:crypto';
5
+ import path from 'node:path';
6
+ import { Readable } from 'node:stream';
7
+
8
+ const VIDEO_BLOCK = 64 * 1024;
9
+ const OPEN_TIMEOUT_MS = 15e3;
10
+ const STREAM_SCRIPT = `${OPEN_FILE}
11
+ m=$(meta) || exit 4
12
+ echo "$(date +%s) $m"
13
+ dd bs=${VIDEO_HEAD} count=1 <&3 2>/dev/null
14
+ read skip count || exit 0
15
+ [ "$count" -gt 0 ] 2>/dev/null || exit 0
16
+ exec dd bs=${VIDEO_BLOCK} skip="$skip" count="$count" <&3 2>/dev/null`;
17
+ function parseRange(header, size) {
18
+ var _a;
19
+ if (header === void 0) return { kind: "full" };
20
+ const m = /^bytes[ \t]*=[ \t]*(.*)$/i.exec(header.trim());
21
+ if (!m) return { kind: "full" };
22
+ const specs = m[1].split(",").map((x) => x.trim()).filter(Boolean);
23
+ if (!specs.length) return { kind: "full" };
24
+ const parsed = [];
25
+ for (const spec of specs) {
26
+ const r = /^(\d*)-(\d*)$/.exec(spec);
27
+ if (!r || !r[1] && !r[2]) return { kind: "full" };
28
+ if (!r[1]) parsed.push({ suffix: Number(r[2]) });
29
+ else {
30
+ const first = Number(r[1]);
31
+ const last = r[2] ? Number(r[2]) : void 0;
32
+ if (last !== void 0 && last < first) return { kind: "full" };
33
+ parsed.push({ first, last });
34
+ }
35
+ }
36
+ for (const p of parsed) {
37
+ if (p.suffix !== void 0) {
38
+ if (p.suffix > 0 && size > 0) return { kind: "part", start: Math.max(0, size - p.suffix), end: size - 1 };
39
+ } else if (p.first < size) {
40
+ return { kind: "part", start: p.first, end: Math.min((_a = p.last) != null ? _a : size - 1, size - 1) };
41
+ }
42
+ }
43
+ return { kind: "none" };
44
+ }
45
+ function answer(v, req) {
46
+ let range = req.method === "HEAD" ? void 0 : req.range;
47
+ if (range !== void 0 && req.ifRange !== void 0 && (req.ifRange.trim() !== v.etag || v.etag.startsWith("W/"))) range = void 0;
48
+ const r = parseRange(range, v.size);
49
+ if (r.kind === "none") return { status: 416, start: 0, len: 0, contentRange: `bytes */${v.size}` };
50
+ if (r.kind === "full") return { status: 200, start: 0, len: v.size };
51
+ return { status: 206, start: r.start, len: r.end - r.start + 1, contentRange: `bytes ${r.start}-${r.end}/${v.size}` };
52
+ }
53
+ function videoEtag(meta) {
54
+ var _a;
55
+ const frac = ((_a = /\.(\d+)/.exec(meta.version)) == null ? void 0 : _a[1]) || "";
56
+ const strong = /[1-9]/.test(frac) && meta.now - meta.mtime >= 2;
57
+ const hash = crypto.createHash("sha1").update(`${meta.ino}|${meta.size}|${meta.version}`).digest("hex").slice(0, 20);
58
+ return `${strong ? "" : "W/"}"${hash}"`;
59
+ }
60
+ function cutOnError(res, body) {
61
+ body.once("error", () => res.destroy());
62
+ return body;
63
+ }
64
+ function readPlan(start, len, head) {
65
+ const fromHead = start < head ? Math.min(len, head - start) : 0;
66
+ const rest = len - fromHead;
67
+ if (rest <= 0) return { fromHead, skip: 0, count: 0, drop: 0 };
68
+ const at = start + fromHead - head;
69
+ const skip = Math.floor(at / VIDEO_BLOCK);
70
+ const drop = at - skip * VIDEO_BLOCK;
71
+ return { fromHead, skip, count: Math.ceil((drop + rest) / VIDEO_BLOCK), drop };
72
+ }
73
+ function spawnScript(m, args) {
74
+ var _a;
75
+ if (!m.exec) {
76
+ return spawn("sh", ["-c", STREAM_SCRIPT, "sh", ...args], { stdio: ["pipe", "pipe", "pipe"], detached: true });
77
+ }
78
+ const child = (_a = m.spawnShell) == null ? void 0 : _a.call(m, STREAM_SCRIPT, args);
79
+ if (!child) throw new HerdrError("unreachable", "Machine unreachable");
80
+ return child;
81
+ }
82
+ function kill(child, local) {
83
+ if (child.exitCode !== null || child.signalCode !== null) return;
84
+ try {
85
+ if (local && child.pid) process.kill(-child.pid, "SIGKILL");
86
+ else child.kill("SIGKILL");
87
+ } catch {
88
+ }
89
+ }
90
+ const closedError = () => new HerdrError("closed", "Request closed");
91
+ async function openAt(m, root, rel, signal) {
92
+ if (signal == null ? void 0 : signal.aborted) throw closedError();
93
+ const child = spawnScript(m, [root, rel]);
94
+ const done = new Promise((resolve) => {
95
+ child.on("close", () => resolve());
96
+ child.on("error", () => resolve());
97
+ });
98
+ const local = !m.exec;
99
+ const close = () => kill(child, local);
100
+ child.stdin.on("error", () => {
101
+ });
102
+ let buf = Buffer.alloc(0);
103
+ let stderr = "";
104
+ child.stderr.on("data", (b) => {
105
+ if (stderr.length < 4e3) stderr += b.toString("utf8");
106
+ });
107
+ const opened = await new Promise((resolve, reject) => {
108
+ const timer = setTimeout(() => {
109
+ close();
110
+ reject(new HerdrError("timeout", "The folder took too long to read"));
111
+ }, OPEN_TIMEOUT_MS);
112
+ const onAbort = () => done2(() => {
113
+ close();
114
+ reject(closedError());
115
+ });
116
+ signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
117
+ const done2 = (f) => {
118
+ clearTimeout(timer);
119
+ signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
120
+ child.stdout.off("data", onData);
121
+ child.off("close", onClose);
122
+ child.off("error", onError);
123
+ f();
124
+ };
125
+ const onData = (b) => {
126
+ buf = Buffer.concat([buf, b]);
127
+ const nl = buf.indexOf(10);
128
+ if (nl < 0) return;
129
+ const [now = "0", ino = "0", size = "0", mtime = "0", ...version] = buf.subarray(0, nl).toString("utf8").trim().split(/\s+/);
130
+ const n = Number(size) || 0;
131
+ const headLen = Math.min(VIDEO_HEAD, n);
132
+ if (buf.length - nl - 1 < headLen) return;
133
+ child.stdout.pause();
134
+ const head = buf.subarray(nl + 1, nl + 1 + headLen);
135
+ done2(() => resolve({ now: Number(now) || 0, ino, size: n, mtime: Number(mtime) || 0, version: version.join(" "), head }));
136
+ };
137
+ const onClose = (code) => done2(() => reject(code === 0 ? new HerdrError("not_found", "File not found") : shellError(m, code, stderr)));
138
+ const onError = () => done2(() => reject(new HerdrError("unreachable", "Machine unreachable")));
139
+ child.stdout.on("data", onData);
140
+ child.on("close", onClose);
141
+ child.on("error", onError);
142
+ });
143
+ const name = path.posix.basename(rel);
144
+ if (!isVideo(name, opened.head)) {
145
+ close();
146
+ throw new HerdrError("not_video", "Not a video");
147
+ }
148
+ let reading = false;
149
+ return {
150
+ name,
151
+ size: opened.size,
152
+ mtime: opened.mtime,
153
+ etag: videoEtag(opened),
154
+ close,
155
+ done,
156
+ read(start, len) {
157
+ if (reading) throw new Error("read once");
158
+ reading = true;
159
+ const plan = readPlan(start, len, opened.head.length);
160
+ child.stdin.end(`${plan.skip} ${plan.count}
161
+ `);
162
+ const out = child.stdout;
163
+ async function* bytes() {
164
+ let left = len;
165
+ try {
166
+ if (plan.fromHead) {
167
+ yield opened.head.subarray(start, start + plan.fromHead);
168
+ left -= plan.fromHead;
169
+ }
170
+ let drop = plan.drop;
171
+ for await (const chunk of out) {
172
+ if (left <= 0) break;
173
+ let c = chunk;
174
+ if (drop) {
175
+ const n = Math.min(drop, c.length);
176
+ c = c.subarray(n);
177
+ drop -= n;
178
+ }
179
+ if (!c.length) continue;
180
+ if (c.length > left) c = c.subarray(0, left);
181
+ left -= c.length;
182
+ yield c;
183
+ if (left <= 0) break;
184
+ }
185
+ if (left > 0) throw new HerdrError("truncated", "The file shrank while being read");
186
+ } finally {
187
+ close();
188
+ }
189
+ }
190
+ return Readable.from(bytes(), { objectMode: false });
191
+ }
192
+ };
193
+ }
194
+ function untilClosed(p, signal) {
195
+ if (!signal) return p;
196
+ if (signal.aborted) return Promise.reject(closedError());
197
+ return new Promise((resolve, reject) => {
198
+ const onAbort = () => reject(closedError());
199
+ signal.addEventListener("abort", onAbort, { once: true });
200
+ p.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
201
+ });
202
+ }
203
+ async function openVideo(m, cwd, rel, signal) {
204
+ if (signal == null ? void 0 : signal.aborted) throw closedError();
205
+ const p = cleanRelative(rel);
206
+ if (!p) throw new HerdrError("not_file", "Not a file");
207
+ const root = await untilClosed(rootOf(m, cwd, signal), signal);
208
+ if (signal == null ? void 0 : signal.aborted) throw closedError();
209
+ return openAt(m, root, p, signal);
210
+ }
211
+ async function openWrittenVideo(m, cwd, written, signal) {
212
+ const t = writtenTarget(m, cwd, written);
213
+ return openAt(m, t.root, t.rel, signal);
214
+ }
215
+
216
+ async function serveVideo(event, p, q, type) {
217
+ const m = machineFor(p.machine);
218
+ const res = event.node.res;
219
+ const closed = new AbortController();
220
+ res.once("close", () => closed.abort());
221
+ if (res.destroyed) closed.abort();
222
+ const v = q.from === "chat" ? await openWrittenVideo(m, p.cwd, q.path, closed.signal) : await openVideo(m, p.cwd, q.path, closed.signal);
223
+ if (closed.signal.aborted) {
224
+ v.close();
225
+ return "";
226
+ }
227
+ closed.signal.addEventListener("abort", v.close, { once: true });
228
+ try {
229
+ setResponseHeader(event, "x-content-type-options", "nosniff");
230
+ setResponseHeader(event, "accept-ranges", "bytes");
231
+ setResponseHeader(event, "content-security-policy", "default-src 'none'; media-src 'self'; frame-ancestors 'self'");
232
+ setResponseHeader(event, "etag", v.etag);
233
+ setResponseHeader(event, "last-modified", new Date(v.mtime * 1e3).toUTCString());
234
+ const a = answer(v, { method: event.method, range: getRequestHeader(event, "range"), ifRange: getRequestHeader(event, "if-range") });
235
+ setResponseStatus(event, a.status);
236
+ if (a.contentRange) setResponseHeader(event, "content-range", a.contentRange);
237
+ if (a.status === 416) {
238
+ v.close();
239
+ setResponseHeader(event, "content-type", "text/plain");
240
+ return "";
241
+ }
242
+ setResponseHeader(event, "content-type", type);
243
+ setResponseHeader(event, "content-disposition", attachmentHeader(v.name, "inline"));
244
+ setResponseHeader(event, "content-length", a.len);
245
+ if (event.method === "HEAD" || !a.len) {
246
+ v.close();
247
+ return "";
248
+ }
249
+ return cutOnError(res, v.read(a.start, a.len));
250
+ } catch (e) {
251
+ v.close();
252
+ throw e;
253
+ }
254
+ }
255
+ const fileDownload = defineApi(async (event) => {
256
+ const q = getQuery(event);
257
+ const p = findPane(String(q.pane || ""));
258
+ if (!p) throw new HerdrError("bad_pane", "Pane not found");
259
+ if (q.from !== "chat" && !p.cwd) throw new HerdrError("bad_cwd", "This agent\u2019s folder is unknown");
260
+ const video = q.inline === "1" ? videoType(String(q.path || "")) : void 0;
261
+ if (video) return serveVideo(event, p, q, video);
262
+ const f = q.from === "chat" ? await readWrittenBytes(machineFor(p.machine), p.cwd, q.path) : await readFileBytes(machineFor(p.machine), p.cwd, q.path);
263
+ setResponseHeader(event, "x-content-type-options", "nosniff");
264
+ if (q.inline === "1" && isPdf(f.name, f.body)) {
265
+ setResponseHeader(event, "content-type", "application/pdf");
266
+ setResponseHeader(event, "content-disposition", attachmentHeader(f.name, "inline"));
267
+ setResponseHeader(event, "content-security-policy", "default-src 'none'; object-src 'self'; frame-ancestors 'self'");
268
+ setResponseHeader(event, "cache-control", "private, no-store");
269
+ return f.body;
270
+ }
271
+ setResponseHeader(event, "content-type", "application/octet-stream");
272
+ setResponseHeader(event, "content-disposition", attachmentHeader(f.name));
273
+ setResponseHeader(event, "content-security-policy", "default-src 'none'; sandbox");
274
+ return f.body;
275
+ });
276
+
277
+ export { fileDownload as f };
278
+ //# sourceMappingURL=fileDownload.mjs.map
@@ -19,6 +19,18 @@ const IMAGE_TYPES = {
19
19
  ico: "image/x-icon",
20
20
  svg: "image/svg+xml"
21
21
  };
22
+ const PDF_HEAD = 1024;
23
+ const isPdf = (name, head) => path.posix.extname(name).toLowerCase() === ".pdf" && head.subarray(0, PDF_HEAD).includes("%PDF-");
24
+ const VIDEO_TYPES = { mp4: "video/mp4", m4v: "video/mp4", mov: "video/quicktime", webm: "video/webm" };
25
+ const VIDEO_HEAD = 12;
26
+ const MP4_BOXES = /* @__PURE__ */ new Set(["ftyp", "moov", "mdat", "wide", "free", "skip", "pnot"]);
27
+ const videoType = (name) => VIDEO_TYPES[path.posix.extname(name).slice(1).toLowerCase()];
28
+ function isVideo(name, head) {
29
+ const type = videoType(name);
30
+ if (!type || head.length < 8) return false;
31
+ if (type === "video/webm") return head.readUInt32BE(0) === 440786851;
32
+ return MP4_BOXES.has(head.subarray(4, 8).toString("latin1"));
33
+ }
22
34
  const RESOLVE = `root=$(cd "$1" 2>/dev/null && pwd -P) || { echo "folder not found" >&2; exit 3; }
23
35
  under() { case "$1/" in "\${root%/}/"*) return 0 ;; esac; return 1; }`;
24
36
  const LIST_SCRIPT = `${RESOLVE}
@@ -29,7 +41,10 @@ else
29
41
  under "$dir" || { echo "outside" >&2; exit 5; }
30
42
  fi
31
43
  cd "$dir" || exit 4
32
- [ -r . ] || { echo "permission denied" >&2; exit 7; }
44
+ e=$(LC_ALL=C ls -A 2>&1 >/dev/null) || {
45
+ case "$e" in *"not permitted"*) [ "$(uname -s)" = Darwin ] && exit 8 ;; esac
46
+ echo "permission denied" >&2; exit 7
47
+ }
33
48
  printf '%s\\0%s\\0' "$root" "$dir"
34
49
  max=$3; n=0
35
50
  set --
@@ -47,7 +62,7 @@ printf '=\\0'
47
62
  [ "$#" -gt 0 ] || exit 0
48
63
  if stat -f %z / >/dev/null 2>&1; then stat -f %z -- "$@"; else stat -c %s -- "$@"; fi 2>/dev/null
49
64
  exit 0`;
50
- const READ_SCRIPT = `${RESOLVE}
65
+ const OPEN_FILE = `${RESOLVE}
51
66
  case "$2" in */*) d=\${2%/*} ;; *) d=. ;; esac
52
67
  b=\${2##*/}
53
68
  dir=$(cd "$root" && cd -- "./$d" 2>/dev/null && pwd -P) || { echo "not found" >&2; exit 4; }
@@ -64,10 +79,23 @@ done
64
79
  under "$f" || { echo "outside" >&2; exit 5; }
65
80
  [ -f "$f" ] || { echo "not a file" >&2; exit 6; }
66
81
  [ -r "$f" ] || { echo "permission denied" >&2; exit 7; }
67
- s=$(wc -c < "$f") || exit 4
82
+ command exec 3< "$f" || { echo "permission denied" >&2; exit 7; }
83
+ # "<inode> <size> <mtime> <version>" of the opened file, from its metadata:
84
+ # never a read (BusyBox's wc -c reads every byte). <version>: modification
85
+ # and change times to the nanosecond (GNU/BusyBox, then BSD). Without the
86
+ # descriptor's metadata, the path's, with no <version>: never a strong ETag.
87
+ meta() {
88
+ stat -L -c '%i %s %Y %y %z' /dev/fd/3 2>/dev/null || stat -L -f '%i %z %m %Fm %Fc' /dev/fd/3 2>/dev/null ||
89
+ stat -L -c '%i %s %Y' "$f" 2>/dev/null || stat -L -f '%i %z %m' "$f" 2>/dev/null || echo "0 $(wc -c < "$f") 0"
90
+ }`;
91
+ const READ_SCRIPT = `${OPEN_FILE}
92
+ m=$(meta) || exit 4
93
+ s=\${m#* }; s=$((\${s%% *}))
68
94
  echo $s
69
- [ -n "$4" ] && [ $(($s)) -ge "$3" ] && exit 0
70
- head -c "$3" < "$f"`;
95
+ [ -n "$4" ] && [ "$s" -ge "$3" ] && exit 0
96
+ head -c "$3" <&3`;
97
+ const MACOS_SSH_DENIED = "macOS blocks access to this folder. On the Mac: System Settings \u203A General \u203A Sharing \u203A Remote Login \u24D8 \u203A \u201CAllow full disk access for remote users\u201D.";
98
+ const MACOS_LOCAL_DENIED = "macOS blocks access to this folder. Allow the app that runs wherdr in System Settings \u203A Privacy & Security \u203A Full Disk Access.";
71
99
  function executor(m, { timeoutMs = 15e3, maxBytes = IMAGE_BYTES } = {}) {
72
100
  const remote = m.exec;
73
101
  if (remote) return (script, args) => remote(script, args, { timeoutMs });
@@ -82,14 +110,19 @@ function executor(m, { timeoutMs = 15e3, maxBytes = IMAGE_BYTES } = {}) {
82
110
  async function run(m, script, args, opts) {
83
111
  const r = await executor(m, opts)(script, args);
84
112
  if (r.code === 0) return r.stdout;
85
- if (r.code === 3) throw new HerdrError("bad_cwd", "This agent\u2019s folder is unknown");
86
- if (r.code === 4) throw new HerdrError("not_found", "File not found");
87
- if (r.code === 5) throw new HerdrError("outside", "Outside the project folder");
88
- if (r.code === 6) throw new HerdrError("not_file", "Not a file");
89
- if (r.code === 7) throw new HerdrError("denied", "Permission denied");
90
- if (r.code === 124) throw new HerdrError("timeout", "The folder took too long to read");
91
- if (r.code === 255 || r.code === null) throw new HerdrError("unreachable", "Machine unreachable");
92
- throw new HerdrError("remote", r.stderr.trim().split("\n").pop() || `code ${r.code}`);
113
+ throw shellError(m, r.code, r.stderr);
114
+ }
115
+ function shellError(m, code, stderr) {
116
+ const r = { code, stderr };
117
+ if (r.code === 3) return new HerdrError("bad_cwd", "This agent\u2019s folder is unknown");
118
+ if (r.code === 4) return new HerdrError("not_found", "File not found");
119
+ if (r.code === 5) return new HerdrError("outside", "Outside the project folder");
120
+ if (r.code === 6) return new HerdrError("not_file", "Not a file");
121
+ if (r.code === 7) return new HerdrError("denied", "Permission denied");
122
+ if (r.code === 8) return new HerdrError("denied", m.exec ? MACOS_SSH_DENIED : MACOS_LOCAL_DENIED);
123
+ if (r.code === 124) return new HerdrError("timeout", "The folder took too long to read");
124
+ if (r.code === 255 || r.code === null) return new HerdrError("unreachable", "Machine unreachable");
125
+ return new HerdrError("remote", r.stderr.trim().split("\n").pop() || `code ${r.code}`);
93
126
  }
94
127
  function cleanRelative(p) {
95
128
  const raw = String(p != null ? p : "").replace(/\\/g, "/");
@@ -126,8 +159,8 @@ function parseListing(raw) {
126
159
  entries.sort((a, b) => Number(b.kind === "dir") - Number(a.kind === "dir") || a.name.localeCompare(b.name, void 0, { numeric: true, sensitivity: "base" }));
127
160
  return { root, dir, entries, truncated };
128
161
  }
129
- async function rootOf(m, cwd) {
130
- return await gitToplevel(m, cwd) || cwd;
162
+ async function rootOf(m, cwd, signal) {
163
+ return await gitToplevel(m, cwd, signal) || cwd;
131
164
  }
132
165
  async function listFiles(m, cwd, rel, opts = {}) {
133
166
  var _a, _b;
@@ -160,8 +193,15 @@ async function readHead(m, root, rel, max, opts) {
160
193
  return { size: Number(out.subarray(0, nl).toString("utf8")) || 0, body: out.subarray(nl + 1) };
161
194
  }
162
195
  async function previewAt(m, root, rel, shown) {
163
- const mime = IMAGE_TYPES[path.posix.extname(rel).slice(1).toLowerCase()];
164
- const { size, body } = await readHead(m, root, rel, mime ? IMAGE_BYTES + 1 : TEXT_BYTES + 1);
196
+ const ext = path.posix.extname(rel).slice(1).toLowerCase();
197
+ const mime = IMAGE_TYPES[ext];
198
+ const video = VIDEO_TYPES[ext];
199
+ const { size, body } = await readHead(m, root, rel, mime ? IMAGE_BYTES + 1 : ext === "pdf" ? PDF_HEAD : video ? VIDEO_HEAD : TEXT_BYTES + 1);
200
+ if (video) return { path: shown, size, kind: isVideo(rel, body) ? "video" : "binary", truncated: false };
201
+ if (ext === "pdf") {
202
+ if (!isPdf(rel, body)) return { path: shown, size, kind: "binary", truncated: false };
203
+ return { path: shown, size, kind: size > DOWNLOAD_BYTES ? "large" : "pdf", truncated: false };
204
+ }
165
205
  if (mime) {
166
206
  if (size > IMAGE_BYTES) return { path: shown, size, kind: "large", truncated: true };
167
207
  return { path: shown, size, kind: "image", dataUrl: `data:${mime};base64,${body.toString("base64")}`, truncated: false };
@@ -194,11 +234,11 @@ async function readWrittenBytes(m, cwd, written) {
194
234
  const t = writtenTarget(m, cwd, written);
195
235
  return bytesAt(m, t.root, t.rel);
196
236
  }
197
- function attachmentHeader(name) {
237
+ function attachmentHeader(name, type = "attachment") {
198
238
  const ascii = name.replace(/[^\x20-\x7e]|["\\]/g, "_") || "download";
199
239
  const utf8 = encodeURIComponent(name).replace(/['()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
200
- return `attachment; filename="${ascii}"; filename*=UTF-8''${utf8}`;
240
+ return `${type}; filename="${ascii}"; filename*=UTF-8''${utf8}`;
201
241
  }
202
242
 
203
- export { readFileBytes as a, attachmentHeader as b, readWrittenPreview as c, readFilePreview as d, listFiles as l, readWrittenBytes as r };
243
+ export { OPEN_FILE as O, VIDEO_HEAD as V, readWrittenBytes as a, readFileBytes as b, cleanRelative as c, isPdf as d, attachmentHeader as e, readWrittenPreview as f, readFilePreview as g, isVideo as i, listFiles as l, rootOf as r, shellError as s, videoType as v, writtenTarget as w };
204
244
  //# sourceMappingURL=files.mjs.map
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { aL as baseMachines, aM as DATA_DIR } from '../nitro/nitro.mjs';
4
+ import { aG as baseMachines, aH as DATA_DIR } from '../nitro/nitro.mjs';
5
5
 
6
6
  function cleanMachineOrder(value, known) {
7
7
  if (!Array.isArray(value)) return [];
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { aW as HOST_LABEL, aM as DATA_DIR } from '../nitro/nitro.mjs';
3
+ import { aW as HOST_LABEL, aH as DATA_DIR } from '../nitro/nitro.mjs';
4
4
 
5
5
  const ONBOARDING_FILE = path.join(DATA_DIR, "onboarding.json");
6
6
  function readOnboarding(file = ONBOARDING_FILE, host = HOST_LABEL) {
@@ -1,5 +1,5 @@
1
1
  var name = "wherdr";
2
- var version = "1.3.3";
2
+ var version = "2.0.0";
3
3
  var license = "MIT";
4
4
  var type = "module";
5
5
  var description = "Unofficial mobile web client (PWA) to drive the coding agents running in Herdr";
@@ -25,7 +25,8 @@ var files = [
25
25
  ".output",
26
26
  "!.output/**/*.map",
27
27
  "bin",
28
- "skills/wherdr"
28
+ "skills/wherdr",
29
+ "docs/*.md"
29
30
  ];
30
31
  var engines = {
31
32
  node: ">=22"
@@ -38,10 +39,15 @@ var scripts = {
38
39
  typecheck: "nuxt typecheck",
39
40
  test: "vitest run",
40
41
  "test:e2e": "playwright test",
42
+ "shots:readme": "node tools/readme-shots/capture.mjs",
43
+ "test:e2e:shots": "SHOTS=${SHOTS:-.shots} playwright test tests/e2e/question-reply.spec.ts --grep screenshot:",
44
+ "test:e2e:stability": "playwright test menu-responsiveness codex-self-update quote-mode onboarding-tailnet --grep \"MCP arrow paints|a new Codex restarts|the former per-device values|a quoted question keeps|#/setup[?]step=security opens|a direct Security link\"",
41
45
  prepare: "nuxt prepare",
42
46
  prepack: "nuxt build && node scripts/pack-output.mjs",
47
+ "check:docs": "node scripts/check-doc-links.mjs",
43
48
  "check:leaks": "node scripts/check-leaks.mjs",
44
- "hooks:install": "git config core.hooksPath .githooks"
49
+ "hooks:install": "git config core.hooksPath .githooks",
50
+ "test:affected": "node scripts/test-affected.mjs"
45
51
  };
46
52
  var dependencies = {
47
53
  "qrcode-terminal": "^0.12.0"
@@ -59,6 +65,7 @@ var devDependencies = {
59
65
  "@types/node": "^22.0.0",
60
66
  "@types/web-push": "^3.6.4",
61
67
  "@vite-pwa/nuxt": "^1.1.1",
68
+ "@vue/reactivity": "^3.5.43",
62
69
  "@vue/test-utils": "^2.5.1",
63
70
  "@xterm/addon-fit": "^0.10.0",
64
71
  "@xterm/addon-webgl": "^0.18.0",
@@ -67,6 +74,7 @@ var devDependencies = {
67
74
  "happy-dom": "^20.14.5",
68
75
  marked: "^15.0.12",
69
76
  nuxt: "^4.5.2",
77
+ "pdfjs-dist": "5.4.624",
70
78
  tailwindcss: "^4.3.3",
71
79
  typescript: "~5.9.3",
72
80
  vitest: "^4.1.11",