windows-development-sandbox 1.4.0 → 1.4.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 (877) hide show
  1. package/.sandbox-config.example.json +2 -1
  2. package/config.example.json +4 -1
  3. package/dist/api.js +27 -16
  4. package/dist/cli/args.d.ts +4 -6
  5. package/dist/cli/args.js +67 -34
  6. package/dist/cli/argv.d.ts +9 -0
  7. package/dist/cli/argv.js +22 -0
  8. package/dist/cli/commands/accounts.d.ts +1 -1
  9. package/dist/cli/commands/accounts.js +42 -27
  10. package/dist/cli/commands/agent-commands.d.ts +3 -3
  11. package/dist/cli/commands/agent-commands.js +27 -18
  12. package/dist/cli/commands/context.d.ts +9 -11
  13. package/dist/cli/commands/context.js +35 -32
  14. package/dist/cli/commands/data/clean.d.ts +2 -2
  15. package/dist/cli/commands/data/clean.js +27 -11
  16. package/dist/cli/commands/data/collect.d.ts +6 -3
  17. package/dist/cli/commands/data/collect.js +46 -15
  18. package/dist/cli/commands/data/index.d.ts +2 -2
  19. package/dist/cli/commands/data/index.js +30 -12
  20. package/dist/cli/commands/data/remove.d.ts +1 -1
  21. package/dist/cli/commands/data/remove.js +4 -4
  22. package/dist/cli/commands/index.d.ts +5 -4
  23. package/dist/cli/commands/index.js +5 -4
  24. package/dist/cli/commands/launch/add-root.d.ts +7 -0
  25. package/dist/cli/commands/launch/add-root.js +64 -0
  26. package/dist/cli/commands/launch/boot-progress.d.ts +7 -0
  27. package/dist/cli/commands/launch/boot-progress.js +48 -0
  28. package/dist/cli/commands/launch/boot-wants.d.ts +11 -0
  29. package/dist/cli/commands/launch/boot-wants.js +48 -0
  30. package/dist/cli/commands/launch/first-start.d.ts +10 -0
  31. package/dist/cli/commands/launch/first-start.js +53 -0
  32. package/dist/cli/commands/launch/index.d.ts +6 -0
  33. package/dist/cli/commands/launch/index.js +6 -0
  34. package/dist/cli/commands/launch/launch.d.ts +8 -0
  35. package/dist/cli/commands/launch/launch.js +211 -0
  36. package/dist/cli/commands/launch/prepare.d.ts +23 -0
  37. package/dist/cli/commands/launch/prepare.js +109 -0
  38. package/dist/cli/commands/launch/running.d.ts +45 -0
  39. package/dist/cli/commands/launch/running.js +218 -0
  40. package/dist/cli/commands/launch/summary.d.ts +8 -0
  41. package/dist/cli/commands/launch/summary.js +98 -0
  42. package/dist/cli/commands/maintenance/audit.d.ts +3 -0
  43. package/dist/cli/commands/maintenance/audit.js +58 -0
  44. package/dist/cli/commands/maintenance/clean.d.ts +2 -0
  45. package/dist/cli/commands/maintenance/clean.js +10 -0
  46. package/dist/cli/commands/maintenance/config.d.ts +2 -0
  47. package/dist/cli/commands/maintenance/config.js +145 -0
  48. package/dist/cli/commands/maintenance/doctor.d.ts +2 -0
  49. package/dist/cli/commands/maintenance/doctor.js +52 -0
  50. package/dist/cli/commands/maintenance/host-claude.d.ts +2 -0
  51. package/dist/cli/commands/maintenance/host-claude.js +4 -0
  52. package/dist/cli/commands/maintenance/index.d.ts +8 -0
  53. package/dist/cli/commands/maintenance/index.js +9 -0
  54. package/dist/cli/commands/maintenance/logs.d.ts +2 -0
  55. package/dist/cli/commands/maintenance/logs.js +44 -0
  56. package/dist/cli/commands/maintenance/sync.d.ts +2 -0
  57. package/dist/cli/commands/maintenance/sync.js +12 -0
  58. package/dist/cli/commands/maintenance/watch.d.ts +3 -0
  59. package/dist/cli/commands/maintenance/watch.js +6 -0
  60. package/dist/cli/commands/projects/describe-sessions.d.ts +3 -0
  61. package/dist/cli/commands/projects/describe-sessions.js +15 -0
  62. package/dist/cli/commands/projects/here.d.ts +38 -0
  63. package/dist/cli/commands/projects/here.js +145 -0
  64. package/dist/cli/commands/projects/index.d.ts +4 -0
  65. package/dist/cli/commands/projects/index.js +4 -0
  66. package/dist/cli/commands/projects/projects.d.ts +14 -0
  67. package/dist/cli/commands/projects/projects.js +213 -0
  68. package/dist/cli/commands/projects/restart.d.ts +15 -0
  69. package/dist/cli/commands/projects/restart.js +149 -0
  70. package/dist/cli/commands/registry.d.ts +3 -0
  71. package/dist/cli/commands/registry.js +34 -0
  72. package/dist/cli/commands/repair/checks.js +105 -29
  73. package/dist/cli/commands/repair/finders.d.ts +13 -10
  74. package/dist/cli/commands/repair/finders.js +63 -43
  75. package/dist/cli/commands/repair/index.d.ts +4 -4
  76. package/dist/cli/commands/repair/index.js +47 -21
  77. package/dist/cli/commands/repair/types.d.ts +2 -2
  78. package/dist/cli/commands/repair/types.js +7 -2
  79. package/dist/cli/commands/sessions/attach.d.ts +2 -0
  80. package/dist/cli/commands/sessions/attach.js +45 -0
  81. package/dist/cli/commands/sessions/control.d.ts +4 -0
  82. package/dist/cli/commands/sessions/control.js +62 -0
  83. package/dist/cli/commands/sessions/exec.d.ts +6 -0
  84. package/dist/cli/commands/sessions/exec.js +72 -0
  85. package/dist/cli/commands/sessions/index.d.ts +6 -0
  86. package/dist/cli/commands/sessions/index.js +9 -0
  87. package/dist/cli/commands/sessions/list.d.ts +15 -0
  88. package/dist/cli/commands/sessions/list.js +65 -0
  89. package/dist/cli/commands/sessions/status.d.ts +2 -0
  90. package/dist/cli/commands/sessions/status.js +153 -0
  91. package/dist/cli/commands/sessions/window.d.ts +3 -0
  92. package/dist/cli/commands/sessions/window.js +18 -0
  93. package/dist/cli/commands/setup/checks.d.ts +4 -4
  94. package/dist/cli/commands/setup/checks.js +36 -19
  95. package/dist/cli/commands/setup/facts.d.ts +6 -6
  96. package/dist/cli/commands/setup/facts.js +23 -11
  97. package/dist/cli/commands/setup/index.d.ts +1 -1
  98. package/dist/cli/commands/setup/index.js +25 -12
  99. package/dist/cli/commands/user-config.d.ts +5 -5
  100. package/dist/cli/commands/user-config.js +14 -12
  101. package/dist/cli/history.d.ts +5 -4
  102. package/dist/cli/history.js +23 -11
  103. package/dist/cli/index.d.ts +4 -14
  104. package/dist/cli/index.js +27 -77
  105. package/dist/cli/manifest.d.ts +464 -10
  106. package/dist/cli/manifest.js +328 -54
  107. package/dist/cli/menu/apps.d.ts +7 -5
  108. package/dist/cli/menu/apps.js +64 -16
  109. package/dist/cli/menu/command-fields.d.ts +15 -0
  110. package/dist/cli/menu/command-fields.js +23 -0
  111. package/dist/cli/menu/command-form.d.ts +3 -5
  112. package/dist/cli/menu/command-form.js +116 -48
  113. package/dist/cli/menu/home.d.ts +22 -0
  114. package/dist/cli/menu/home.js +72 -0
  115. package/dist/cli/menu/index.d.ts +2 -24
  116. package/dist/cli/menu/index.js +4 -178
  117. package/dist/cli/menu/menu.d.ts +23 -0
  118. package/dist/cli/menu/menu.js +185 -0
  119. package/dist/cli/menu/settings/categories.d.ts +2 -2
  120. package/dist/cli/menu/settings/categories.js +123 -20
  121. package/dist/cli/menu/settings/collections/collection-editor.d.ts +23 -0
  122. package/dist/cli/menu/settings/collections/collection-editor.js +89 -0
  123. package/dist/cli/menu/settings/collections/map-editor.d.ts +10 -0
  124. package/dist/cli/menu/settings/collections/map-editor.js +34 -0
  125. package/dist/cli/menu/settings/collections/object-list-editor.d.ts +10 -0
  126. package/dist/cli/menu/settings/collections/object-list-editor.js +23 -0
  127. package/dist/cli/menu/settings/collections/object-map-editor.d.ts +10 -0
  128. package/dist/cli/menu/settings/collections/object-map-editor.js +35 -0
  129. package/dist/cli/menu/settings/collections/string-list-editor.d.ts +12 -0
  130. package/dist/cli/menu/settings/collections/string-list-editor.js +39 -0
  131. package/dist/cli/menu/settings/config-file.d.ts +2 -2
  132. package/dist/cli/menu/settings/config-file.js +42 -19
  133. package/dist/cli/menu/settings/editor-actions.d.ts +2 -0
  134. package/dist/cli/menu/settings/editor-actions.js +2 -0
  135. package/dist/cli/menu/settings/format.d.ts +5 -0
  136. package/dist/cli/menu/settings/format.js +39 -0
  137. package/dist/cli/menu/settings/index.d.ts +1 -29
  138. package/dist/cli/menu/settings/index.js +1 -133
  139. package/dist/cli/menu/settings/object-editor.d.ts +12 -0
  140. package/dist/cli/menu/settings/object-editor.js +86 -0
  141. package/dist/cli/menu/settings/schema-node.d.ts +3 -1
  142. package/dist/cli/menu/settings/schema-node.js +71 -24
  143. package/dist/cli/menu/settings/settings-editor.d.ts +30 -0
  144. package/dist/cli/menu/settings/settings-editor.js +176 -0
  145. package/dist/cli/menu/settings/{editors.d.ts → value-editor.d.ts} +2 -13
  146. package/dist/cli/menu/settings/value-editor.js +137 -0
  147. package/dist/cli/menu/several.d.ts +4 -4
  148. package/dist/cli/menu/several.js +61 -20
  149. package/dist/cli/{colors.d.ts → output/colors.d.ts} +8 -8
  150. package/dist/cli/{colors.js → output/colors.js} +32 -14
  151. package/dist/cli/output/index.d.ts +3 -0
  152. package/dist/cli/output/index.js +3 -0
  153. package/dist/cli/output/print.d.ts +5 -0
  154. package/dist/cli/output/print.js +14 -0
  155. package/dist/cli/output/progress.d.ts +24 -0
  156. package/dist/cli/output/progress.js +124 -0
  157. package/dist/cli/report.d.ts +2 -0
  158. package/dist/cli/report.js +20 -0
  159. package/dist/cli/tui/app.d.ts +6 -16
  160. package/dist/cli/tui/app.js +28 -8
  161. package/dist/cli/tui/dialogs/confirm-screen.d.ts +20 -0
  162. package/dist/cli/tui/dialogs/confirm-screen.js +50 -0
  163. package/dist/cli/tui/dialogs/message-screen.d.ts +17 -0
  164. package/dist/cli/tui/dialogs/message-screen.js +55 -0
  165. package/dist/cli/tui/dialogs/paragraphs.d.ts +2 -0
  166. package/dist/cli/tui/dialogs/paragraphs.js +5 -0
  167. package/dist/cli/tui/dialogs/text-screen.d.ts +26 -0
  168. package/dist/cli/tui/dialogs/text-screen.js +107 -0
  169. package/dist/cli/tui/frame.js +3 -1
  170. package/dist/cli/tui/index.d.ts +7 -3
  171. package/dist/cli/tui/index.js +4 -2
  172. package/dist/cli/tui/list/list-screen.d.ts +29 -0
  173. package/dist/cli/tui/{list-screen.js → list/list-screen.js} +86 -23
  174. package/dist/cli/tui/{list-screen.d.ts → list/list-types.d.ts} +0 -28
  175. package/dist/cli/tui/screen.d.ts +14 -0
  176. package/dist/cli/tui/terminal.js +34 -10
  177. package/dist/cli/tui/text.d.ts +2 -1
  178. package/dist/cli/tui/text.js +37 -7
  179. package/dist/cli/tui/theme.js +27 -9
  180. package/dist/cli/validate.d.ts +8 -8
  181. package/dist/cli/validate.js +32 -21
  182. package/dist/core/config/defaults.d.ts +2 -0
  183. package/dist/core/config/defaults.js +203 -0
  184. package/dist/core/config/index.d.ts +2 -0
  185. package/dist/core/config/index.js +3 -0
  186. package/dist/core/{config.d.ts → config/loader.d.ts} +1 -2
  187. package/dist/core/config/loader.js +47 -0
  188. package/dist/core/{detect-databases.js → detect/databases.js} +111 -23
  189. package/dist/core/detect/index.d.ts +4 -0
  190. package/dist/core/detect/index.js +4 -0
  191. package/dist/core/{detect-pwsh.d.ts → detect/pwsh.d.ts} +1 -1
  192. package/dist/core/{detect-pwsh.js → detect/pwsh.js} +25 -11
  193. package/dist/core/{detect-toolchains.d.ts → detect/toolchains.d.ts} +1 -1
  194. package/dist/core/{detect-toolchains.js → detect/toolchains.js} +42 -5
  195. package/dist/{guest/toolchains → core/detect}/versions.js +28 -12
  196. package/dist/core/disk.d.ts +2 -0
  197. package/dist/core/disk.js +46 -3
  198. package/dist/core/local-config/boot-wants.d.ts +45 -0
  199. package/dist/core/local-config/boot-wants.js +120 -0
  200. package/dist/core/local-config/file.d.ts +3 -0
  201. package/dist/core/local-config/file.js +16 -0
  202. package/dist/core/local-config/index.d.ts +5 -0
  203. package/dist/core/local-config/index.js +7 -0
  204. package/dist/core/{local-config.d.ts → local-config/overrides.d.ts} +11 -11
  205. package/dist/core/{local-config.js → local-config/overrides.js} +53 -54
  206. package/dist/core/{project-policy.d.ts → local-config/policy.d.ts} +7 -3
  207. package/dist/core/{project-policy.js → local-config/policy.js} +16 -6
  208. package/dist/core/local-config/trust.d.ts +13 -0
  209. package/dist/core/local-config/trust.js +43 -0
  210. package/dist/core/package-info.d.ts +4 -0
  211. package/dist/core/package-info.js +13 -0
  212. package/dist/core/run/guest-workspace.d.ts +23 -0
  213. package/dist/core/run/guest-workspace.js +47 -0
  214. package/dist/core/run/index.d.ts +3 -0
  215. package/dist/core/run/index.js +3 -0
  216. package/dist/core/run/resolve-run.d.ts +3 -0
  217. package/dist/core/run/resolve-run.js +202 -0
  218. package/dist/core/run/versions.d.ts +13 -0
  219. package/dist/core/run/versions.js +65 -0
  220. package/dist/core/safe-paths.js +17 -5
  221. package/dist/core/schema/apps.d.ts +4 -4
  222. package/dist/core/schema/apps.js +55 -21
  223. package/dist/core/schema/common.d.ts +13 -10
  224. package/dist/core/schema/common.js +16 -10
  225. package/dist/core/schema/config.d.ts +18 -12
  226. package/dist/core/schema/config.js +78 -53
  227. package/dist/core/schema/databases.d.ts +4 -3
  228. package/dist/core/schema/databases.js +16 -12
  229. package/dist/core/schema/harness.d.ts +1 -1
  230. package/dist/core/schema/harness.js +17 -7
  231. package/dist/core/schema/index.d.ts +6 -0
  232. package/dist/core/schema/index.js +8 -0
  233. package/dist/core/schema/json-schema.js +10 -5
  234. package/dist/core/schema/profile.d.ts +4 -4
  235. package/dist/core/schema/profile.js +37 -17
  236. package/dist/core/schema/projects.d.ts +2 -1
  237. package/dist/core/schema/projects.js +16 -5
  238. package/dist/core/schema/sandbox.d.ts +12 -12
  239. package/dist/core/schema/sandbox.js +101 -37
  240. package/dist/core/schema/toolchains.d.ts +6 -1
  241. package/dist/core/schema/toolchains.js +84 -34
  242. package/dist/core/types.d.ts +36 -9
  243. package/dist/core/util/errors.d.ts +8 -0
  244. package/dist/core/util/errors.js +14 -0
  245. package/dist/core/util/fs.d.ts +8 -0
  246. package/dist/core/util/fs.js +40 -0
  247. package/dist/core/util/index.d.ts +7 -0
  248. package/dist/core/util/index.js +7 -0
  249. package/dist/core/util/jsonc.d.ts +6 -0
  250. package/dist/core/util/jsonc.js +25 -0
  251. package/dist/core/util/links.d.ts +10 -0
  252. package/dist/core/util/links.js +39 -0
  253. package/dist/core/util/paths.d.ts +7 -0
  254. package/dist/core/util/paths.js +33 -0
  255. package/dist/core/util/process.d.ts +15 -0
  256. package/dist/core/util/process.js +54 -0
  257. package/dist/core/util/text.d.ts +8 -0
  258. package/dist/core/util/text.js +8 -0
  259. package/dist/guest/{setup/agents.js → agents/agent-installer.js} +24 -4
  260. package/dist/guest/apps/after-install.d.ts +3 -0
  261. package/dist/guest/apps/after-install.js +47 -0
  262. package/dist/guest/apps/app-installer.d.ts +22 -0
  263. package/dist/guest/apps/app-installer.js +116 -0
  264. package/dist/guest/apps/find-exe.d.ts +5 -0
  265. package/dist/guest/apps/find-exe.js +41 -0
  266. package/dist/guest/apps/index.d.ts +3 -10
  267. package/dist/guest/apps/index.js +6 -206
  268. package/dist/guest/apps/resolvers.js +37 -9
  269. package/dist/guest/apps/shortcuts.d.ts +6 -0
  270. package/dist/guest/apps/shortcuts.js +28 -0
  271. package/dist/guest/apps/sources.d.ts +4 -0
  272. package/dist/guest/apps/sources.js +17 -0
  273. package/dist/guest/apps/unpack.d.ts +3 -0
  274. package/dist/guest/apps/unpack.js +47 -0
  275. package/dist/guest/{audit-parse.js → audit/parse.js} +39 -3
  276. package/dist/guest/{audit.d.ts → audit/process-audit.d.ts} +3 -1
  277. package/dist/guest/{audit.js → audit/process-audit.js} +33 -8
  278. package/dist/guest/boot/boot-env.d.ts +4 -0
  279. package/dist/guest/{boot-env.js → boot/boot-env.js} +7 -5
  280. package/dist/guest/boot/boot.d.ts +1 -0
  281. package/dist/guest/{main.js → boot/boot.js} +100 -50
  282. package/dist/guest/{guide.js → boot/guide.js} +32 -7
  283. package/dist/guest/{project-env.d.ts → boot/project-env.d.ts} +3 -3
  284. package/dist/guest/{project-env.js → boot/project-env.js} +12 -4
  285. package/dist/guest/boot/project-status.d.ts +5 -0
  286. package/dist/guest/boot/project-status.js +28 -0
  287. package/dist/guest/daemon/daemon.d.ts +1 -0
  288. package/dist/guest/daemon/daemon.js +51 -0
  289. package/dist/guest/daemon/exec.js +18 -6
  290. package/dist/guest/daemon/{shutdown.js → idle-shutdown.js} +5 -4
  291. package/dist/guest/daemon/{project.d.ts → project-provisioner.d.ts} +3 -3
  292. package/dist/guest/daemon/{project.js → project-provisioner.js} +60 -22
  293. package/dist/guest/daemon/relays.js +5 -3
  294. package/dist/guest/daemon/{session.js → sessions.js} +84 -24
  295. package/dist/guest/daemon/state.d.ts +4 -1
  296. package/dist/guest/daemon/state.js +34 -20
  297. package/dist/guest/databases/database-server.d.ts +13 -0
  298. package/dist/guest/databases/database-server.js +35 -0
  299. package/dist/guest/databases/dynamodb.d.ts +12 -0
  300. package/dist/guest/databases/dynamodb.js +81 -0
  301. package/dist/guest/databases/index.d.ts +2 -0
  302. package/dist/guest/databases/index.js +2 -0
  303. package/dist/guest/databases/mongodb.d.ts +7 -0
  304. package/dist/guest/databases/mongodb.js +46 -0
  305. package/dist/guest/databases/mysql.d.ts +7 -0
  306. package/dist/guest/databases/mysql.js +59 -0
  307. package/dist/guest/databases/names.d.ts +5 -0
  308. package/dist/guest/databases/names.js +8 -0
  309. package/dist/guest/databases/postgres.d.ts +9 -0
  310. package/dist/guest/databases/postgres.js +85 -0
  311. package/dist/guest/databases/redis.d.ts +7 -0
  312. package/dist/guest/databases/redis.js +25 -0
  313. package/dist/guest/databases/registry.d.ts +5 -0
  314. package/dist/guest/databases/registry.js +51 -0
  315. package/dist/guest/databases/sbx-db.d.ts +1 -0
  316. package/dist/guest/{db.js → databases/sbx-db.js} +13 -13
  317. package/dist/guest/{toolchains/databases → databases}/server.d.ts +5 -5
  318. package/dist/guest/{toolchains/databases → databases}/server.js +18 -13
  319. package/dist/guest/entries/daemon.js +16 -0
  320. package/dist/guest/entries/db.js +10 -0
  321. package/dist/guest/entries/gitguard.js +20 -0
  322. package/dist/guest/entries/main.d.ts +1 -0
  323. package/dist/guest/entries/main.js +24 -0
  324. package/dist/guest/entries/netproxy.d.ts +1 -0
  325. package/dist/guest/entries/netproxy.js +7 -0
  326. package/dist/guest/entries/view.d.ts +1 -0
  327. package/dist/guest/entries/view.js +11 -0
  328. package/dist/guest/{gitguard.js → git/decision.js} +49 -26
  329. package/dist/guest/network/addresses.d.ts +2 -0
  330. package/dist/guest/network/addresses.js +6 -0
  331. package/dist/guest/{setup/network.d.ts → network/allow-only.d.ts} +0 -10
  332. package/dist/guest/network/allow-only.js +84 -0
  333. package/dist/guest/network/firewall.d.ts +9 -0
  334. package/dist/guest/{setup/network.js → network/firewall.js} +58 -63
  335. package/dist/guest/network/proxy-server.d.ts +2 -0
  336. package/dist/guest/{netproxy.js → network/proxy-server.js} +37 -18
  337. package/dist/guest/{helpers.d.ts → runtime/csc.d.ts} +1 -1
  338. package/dist/guest/{helpers.js → runtime/csc.js} +7 -2
  339. package/dist/guest/runtime/fs.d.ts +2 -0
  340. package/dist/guest/runtime/fs.js +6 -0
  341. package/dist/guest/runtime/log.d.ts +3 -0
  342. package/dist/guest/runtime/log.js +22 -0
  343. package/dist/guest/runtime/paths.d.ts +13 -0
  344. package/dist/guest/runtime/paths.js +14 -0
  345. package/dist/guest/{ports.js → runtime/ports.js} +8 -2
  346. package/dist/guest/runtime/process.d.ts +15 -0
  347. package/dist/guest/runtime/process.js +59 -0
  348. package/dist/guest/{project-context.js → runtime/project-context.js} +1 -1
  349. package/dist/guest/runtime/session.d.ts +5 -0
  350. package/dist/guest/runtime/session.js +10 -0
  351. package/dist/guest/runtime/status.d.ts +7 -0
  352. package/dist/guest/runtime/status.js +57 -0
  353. package/dist/guest/{cmdline.js → sessions/cmdline.js} +10 -4
  354. package/dist/guest/{ptyhost.js → sessions/pty-host.js} +12 -5
  355. package/dist/guest/{view.js → sessions/viewer.js} +8 -11
  356. package/dist/guest/setup/claude-mem.d.ts +10 -0
  357. package/dist/guest/setup/{claude.js → claude-mem.js} +18 -78
  358. package/dist/guest/setup/{claude.d.ts → claude-profile.d.ts} +0 -10
  359. package/dist/guest/setup/claude-profile.js +89 -0
  360. package/dist/guest/setup/desktop.d.ts +2 -0
  361. package/dist/guest/setup/desktop.js +32 -0
  362. package/dist/guest/setup/environment.js +28 -5
  363. package/dist/guest/setup/{user.d.ts → git-identity.d.ts} +0 -2
  364. package/dist/guest/setup/git-identity.js +34 -0
  365. package/dist/guest/{gitrules.d.ts → setup/git-rules.d.ts} +1 -1
  366. package/dist/guest/setup/git-rules.js +50 -0
  367. package/dist/guest/setup/hooks.js +22 -5
  368. package/dist/guest/setup/{policy.js → managed-policy.js} +2 -2
  369. package/dist/guest/toolchains/catalogue.d.ts +4 -4
  370. package/dist/guest/toolchains/catalogue.js +30 -7
  371. package/dist/guest/toolchains/detect.d.ts +12 -0
  372. package/dist/guest/toolchains/detect.js +54 -0
  373. package/dist/guest/toolchains/index.d.ts +3 -17
  374. package/dist/guest/toolchains/index.js +1 -80
  375. package/dist/guest/toolchains/install.d.ts +20 -0
  376. package/dist/guest/toolchains/install.js +29 -0
  377. package/dist/guest/toolchains/languages/go.d.ts +3 -0
  378. package/dist/guest/toolchains/{go.js → languages/go.js} +27 -9
  379. package/dist/guest/toolchains/languages/java.d.ts +8 -0
  380. package/dist/guest/toolchains/{java.js → languages/java.js} +57 -18
  381. package/dist/guest/toolchains/languages/node.d.ts +3 -0
  382. package/dist/guest/toolchains/{node.js → languages/node.js} +51 -18
  383. package/dist/guest/toolchains/languages/php.d.ts +3 -0
  384. package/dist/guest/toolchains/{scripting → languages}/php.js +36 -11
  385. package/dist/guest/toolchains/languages/python-tools.d.ts +3 -0
  386. package/dist/guest/toolchains/languages/python-tools.js +12 -0
  387. package/dist/guest/toolchains/languages/python.d.ts +3 -0
  388. package/dist/guest/toolchains/{python.js → languages/python.js} +29 -16
  389. package/dist/guest/toolchains/languages/ruby.d.ts +3 -0
  390. package/dist/guest/toolchains/{scripting → languages}/ruby.js +28 -10
  391. package/dist/guest/toolchains/leftovers.d.ts +1 -1
  392. package/dist/guest/toolchains/leftovers.js +13 -11
  393. package/dist/guest/toolchains/managers.d.ts +6 -6
  394. package/dist/guest/toolchains/managers.js +38 -17
  395. package/dist/guest/toolchains/native/binstall.d.ts +3 -2
  396. package/dist/guest/toolchains/native/binstall.js +20 -8
  397. package/dist/guest/toolchains/native/cpp.d.ts +2 -2
  398. package/dist/guest/toolchains/native/cpp.js +23 -8
  399. package/dist/guest/toolchains/native/dotnet.d.ts +5 -3
  400. package/dist/guest/toolchains/native/dotnet.js +72 -24
  401. package/dist/guest/toolchains/native/mesa.d.ts +2 -2
  402. package/dist/guest/toolchains/native/mesa.js +27 -10
  403. package/dist/guest/toolchains/native/msvc/environment.d.ts +4 -4
  404. package/dist/guest/toolchains/native/msvc/environment.js +30 -16
  405. package/dist/guest/toolchains/native/msvc/index.d.ts +3 -3
  406. package/dist/guest/toolchains/native/msvc/index.js +10 -8
  407. package/dist/guest/toolchains/native/msvc/packages.d.ts +1 -1
  408. package/dist/guest/toolchains/native/msvc/packages.js +69 -23
  409. package/dist/guest/toolchains/native/msvc/tree.d.ts +6 -6
  410. package/dist/guest/toolchains/native/msvc/tree.js +15 -9
  411. package/dist/guest/toolchains/native/rust-extras.d.ts +23 -0
  412. package/dist/guest/toolchains/native/rust-extras.js +100 -0
  413. package/dist/guest/toolchains/native/rust.d.ts +2 -2
  414. package/dist/guest/toolchains/native/rust.js +41 -10
  415. package/dist/guest/toolchains/{scripting → native}/vcruntime.d.ts +2 -2
  416. package/dist/guest/toolchains/{scripting → native}/vcruntime.js +17 -7
  417. package/dist/guest/toolchains/package-ledger.d.ts +17 -0
  418. package/dist/guest/toolchains/package-ledger.js +54 -0
  419. package/dist/guest/toolchains/plan.d.ts +3 -24
  420. package/dist/guest/toolchains/plan.js +99 -111
  421. package/dist/guest/toolchains/runtimes.d.ts +6 -6
  422. package/dist/guest/toolchains/runtimes.js +31 -13
  423. package/dist/guest/toolchains/scheduler.d.ts +22 -0
  424. package/dist/guest/toolchains/scheduler.js +123 -0
  425. package/dist/guest/toolchains/setup.d.ts +10 -0
  426. package/dist/guest/toolchains/setup.js +22 -0
  427. package/dist/guest/toolchains/state-file.d.ts +3 -0
  428. package/dist/guest/toolchains/state-file.js +10 -0
  429. package/dist/guest/toolchains/step.d.ts +24 -0
  430. package/dist/guest/toolchains/step.js +1 -0
  431. package/dist/guest/toolchains/tool-env.d.ts +12 -0
  432. package/dist/guest/toolchains/tool-env.js +16 -0
  433. package/dist/guest/toolchains/tools/cli.d.ts +10 -0
  434. package/dist/guest/toolchains/{cli.js → tools/cli.js} +35 -15
  435. package/dist/guest/toolchains/tools/git.d.ts +3 -0
  436. package/dist/guest/toolchains/{git.js → tools/git.js} +38 -15
  437. package/dist/guest/toolchains/tools/pwsh.d.ts +4 -0
  438. package/dist/guest/toolchains/{pwsh.js → tools/pwsh.js} +14 -7
  439. package/dist/guest/toolchains/{vscode-profile.d.ts → tools/vscode-profile.d.ts} +6 -6
  440. package/dist/guest/toolchains/{vscode-profile.js → tools/vscode-profile.js} +28 -12
  441. package/dist/guest/toolchains/{vscode.d.ts → tools/vscode.d.ts} +6 -6
  442. package/dist/guest/toolchains/{vscode.js → tools/vscode.js} +67 -21
  443. package/dist/guest/toolchains/version-cache.d.ts +16 -0
  444. package/dist/guest/toolchains/version-cache.js +67 -0
  445. package/dist/host/agent-commands/commands.d.ts +13 -0
  446. package/dist/host/agent-commands/commands.js +33 -0
  447. package/dist/host/agent-commands/forwarders.d.ts +7 -0
  448. package/dist/host/agent-commands/forwarders.js +31 -0
  449. package/dist/host/agent-commands/index.d.ts +4 -0
  450. package/dist/host/agent-commands/index.js +4 -0
  451. package/dist/host/agent-commands/reconcile.d.ts +12 -0
  452. package/dist/host/agent-commands/reconcile.js +69 -0
  453. package/dist/host/agent-commands/user-path.d.ts +2 -0
  454. package/dist/host/agent-commands/user-path.js +33 -0
  455. package/dist/host/audit/collect.d.ts +2 -2
  456. package/dist/host/audit/collect.js +59 -22
  457. package/dist/host/audit/log.d.ts +2 -2
  458. package/dist/host/audit/log.js +24 -8
  459. package/dist/host/{attach.d.ts → channel/attach.d.ts} +2 -2
  460. package/dist/host/{attach.js → channel/attach.js} +33 -15
  461. package/dist/host/channel/channel.d.ts +51 -0
  462. package/dist/host/channel/channel.js +196 -0
  463. package/dist/host/channel/index.d.ts +2 -0
  464. package/dist/host/channel/index.js +2 -0
  465. package/dist/host/guard/agent-files.d.ts +7 -0
  466. package/dist/host/guard/agent-files.js +103 -0
  467. package/dist/host/guard/commands.d.ts +10 -0
  468. package/dist/host/guard/commands.js +123 -0
  469. package/dist/host/guard/file-hash.d.ts +4 -0
  470. package/dist/host/guard/file-hash.js +37 -0
  471. package/dist/host/guard/git-config.d.ts +5 -0
  472. package/dist/host/guard/git-config.js +62 -0
  473. package/dist/host/guard/git-dirs.d.ts +12 -0
  474. package/dist/host/guard/git-dirs.js +53 -0
  475. package/dist/host/guard/index.d.ts +5 -0
  476. package/dist/host/guard/index.js +4 -0
  477. package/dist/host/guard/mark-of-the-web.d.ts +8 -0
  478. package/dist/host/guard/mark-of-the-web.js +74 -0
  479. package/dist/host/guard/nested-repos.d.ts +14 -0
  480. package/dist/host/guard/nested-repos.js +88 -0
  481. package/dist/host/guard/quarantine.d.ts +3 -0
  482. package/dist/host/guard/quarantine.js +24 -0
  483. package/dist/host/guard/repo-guard.d.ts +10 -0
  484. package/dist/host/guard/repo-guard.js +36 -0
  485. package/dist/host/guard/store.d.ts +40 -0
  486. package/dist/host/guard/store.js +145 -0
  487. package/dist/host/guard/types.d.ts +27 -0
  488. package/dist/host/guard/types.js +3 -0
  489. package/dist/host/guard/watch-state.d.ts +9 -0
  490. package/dist/host/guard/watch-state.js +26 -0
  491. package/dist/host/launch/boot-projects.d.ts +17 -0
  492. package/dist/host/launch/{projects.js → boot-projects.js} +27 -12
  493. package/dist/host/{database-plan.d.ts → launch/database-plan.d.ts} +5 -5
  494. package/dist/host/{database-plan.js → launch/database-plan.js} +24 -13
  495. package/dist/host/launch/generate.d.ts +4 -0
  496. package/dist/host/launch/generate.js +77 -0
  497. package/dist/host/launch/index.d.ts +10 -0
  498. package/dist/host/launch/index.js +10 -0
  499. package/dist/host/launch/mappings.d.ts +7 -2
  500. package/dist/host/launch/mappings.js +83 -24
  501. package/dist/host/launch/pc-scan.d.ts +5 -0
  502. package/dist/host/{pc-scan.js → launch/pc-scan.js} +20 -13
  503. package/dist/host/launch/project-scan.d.ts +7 -0
  504. package/dist/host/{project-scan.js → launch/project-scan.js} +29 -21
  505. package/dist/host/launch/session-file.d.ts +23 -0
  506. package/dist/host/launch/session-file.js +73 -0
  507. package/dist/host/launch/stage.d.ts +5 -5
  508. package/dist/host/launch/stage.js +14 -13
  509. package/dist/host/launch/toolchains.d.ts +4 -0
  510. package/dist/host/launch/toolchains.js +11 -0
  511. package/dist/host/launch/{wsb.d.ts → wsb-file.d.ts} +4 -2
  512. package/dist/host/launch/wsb-file.js +56 -0
  513. package/dist/host/life/crash-report.d.ts +8 -0
  514. package/dist/host/life/crash-report.js +87 -0
  515. package/dist/host/life/index.d.ts +6 -0
  516. package/dist/host/life/index.js +6 -0
  517. package/dist/host/life/keep-awake.d.ts +10 -0
  518. package/dist/host/life/keep-awake.js +29 -0
  519. package/dist/host/life/life-record.d.ts +48 -0
  520. package/dist/host/life/life-record.js +76 -0
  521. package/dist/host/life/stop-events.d.ts +27 -0
  522. package/dist/host/life/stop-events.js +96 -0
  523. package/dist/host/life/stop-warning.d.ts +4 -0
  524. package/dist/host/life/stop-warning.js +25 -0
  525. package/dist/host/life/windows-update.d.ts +3 -0
  526. package/dist/host/life/windows-update.js +11 -0
  527. package/dist/host/native.d.ts +4 -0
  528. package/dist/host/native.js +11 -0
  529. package/dist/host/network/index.d.ts +1 -0
  530. package/dist/host/network/index.js +1 -0
  531. package/dist/host/{port-forward.d.ts → network/port-forward.d.ts} +1 -1
  532. package/dist/host/{port-forward.js → network/port-forward.js} +16 -10
  533. package/dist/host/profile/accounts.d.ts +37 -0
  534. package/dist/host/profile/accounts.js +146 -0
  535. package/dist/host/profile/claude-login.d.ts +22 -0
  536. package/dist/host/profile/claude-login.js +57 -0
  537. package/dist/host/{claude-profile.d.ts → profile/claude-profile.d.ts} +9 -9
  538. package/dist/host/{claude-profile.js → profile/claude-profile.js} +32 -22
  539. package/dist/host/profile/index.d.ts +7 -0
  540. package/dist/host/profile/index.js +7 -0
  541. package/dist/host/profile/personalize.d.ts +2 -0
  542. package/dist/host/profile/personalize.js +127 -0
  543. package/dist/host/profile/reg-file.d.ts +8 -0
  544. package/dist/host/profile/reg-file.js +45 -0
  545. package/dist/host/profile/secret-files.d.ts +2 -0
  546. package/dist/host/profile/secret-files.js +25 -0
  547. package/dist/host/profile/secret-patterns.d.ts +6 -0
  548. package/dist/host/profile/secret-patterns.js +128 -0
  549. package/dist/host/profile/secrets.d.ts +12 -0
  550. package/dist/host/profile/secrets.js +100 -0
  551. package/dist/host/projects/index.d.ts +4 -0
  552. package/dist/host/projects/index.js +4 -0
  553. package/dist/host/projects/join.d.ts +38 -0
  554. package/dist/host/projects/join.js +119 -0
  555. package/dist/host/projects/known.d.ts +28 -0
  556. package/dist/host/projects/known.js +55 -0
  557. package/dist/host/projects/mapper.d.ts +29 -0
  558. package/dist/host/projects/mapper.js +88 -0
  559. package/dist/host/projects/registry.d.ts +83 -0
  560. package/dist/host/projects/registry.js +136 -0
  561. package/dist/host/sandbox/doctor.d.ts +2 -0
  562. package/dist/host/sandbox/doctor.js +42 -0
  563. package/dist/host/sandbox/host-claude.d.ts +1 -0
  564. package/dist/host/sandbox/host-claude.js +26 -0
  565. package/dist/host/sandbox/index.d.ts +6 -0
  566. package/dist/host/sandbox/index.js +6 -0
  567. package/dist/host/{platform.d.ts → sandbox/platform.d.ts} +0 -5
  568. package/dist/host/sandbox/platform.js +60 -0
  569. package/dist/host/sandbox/probe.d.ts +3 -0
  570. package/dist/host/sandbox/probe.js +47 -0
  571. package/dist/host/{window.js → sandbox/window.js} +7 -5
  572. package/dist/host/{wsb.js → sandbox/wsb-cli.js} +31 -8
  573. package/dist/host/{cleanup.js → storage/cleanup.js} +27 -12
  574. package/dist/host/storage/index.d.ts +2 -0
  575. package/dist/host/storage/index.js +2 -0
  576. package/dist/host/storage/state-files.d.ts +4 -0
  577. package/dist/host/storage/state-files.js +10 -0
  578. package/dist/host/test-guard.js +1 -1
  579. package/dist/host/tools/conpty.d.ts +8 -0
  580. package/dist/host/tools/conpty.js +58 -0
  581. package/dist/host/tools/index.d.ts +2 -0
  582. package/dist/host/tools/index.js +2 -0
  583. package/dist/host/{terminal.d.ts → tools/windows-terminal.d.ts} +2 -10
  584. package/dist/host/{terminal.js → tools/windows-terminal.js} +33 -57
  585. package/dist/host/workspace-view/active-views.d.ts +3 -0
  586. package/dist/host/workspace-view/active-views.js +22 -0
  587. package/dist/host/workspace-view/index.d.ts +2 -18
  588. package/dist/host/workspace-view/index.js +2 -49
  589. package/dist/host/workspace-view/plan.d.ts +16 -0
  590. package/dist/host/workspace-view/plan.js +50 -0
  591. package/dist/host/workspace-view/rules.js +10 -3
  592. package/dist/host/workspace-view/view-state.d.ts +10 -0
  593. package/dist/host/workspace-view/view-state.js +31 -0
  594. package/dist/host/workspace-view/view.d.ts +1 -0
  595. package/dist/host/workspace-view/view.js +51 -55
  596. package/dist/runtime/daemon.js +4232 -1918
  597. package/dist/runtime/db.js +2145 -830
  598. package/dist/runtime/gitguard.js +29 -11
  599. package/dist/runtime/main.js +4760 -2155
  600. package/dist/runtime/netproxy.js +1654 -418
  601. package/dist/runtime/view.js +1515 -453
  602. package/dist/selftest/accounts.test.d.ts +1 -1
  603. package/dist/selftest/accounts.test.js +20 -17
  604. package/dist/selftest/agent-commands.test.d.ts +1 -1
  605. package/dist/selftest/agent-commands.test.js +9 -5
  606. package/dist/selftest/audit.test.d.ts +1 -1
  607. package/dist/selftest/audit.test.js +46 -13
  608. package/dist/selftest/channel.test.d.ts +1 -1
  609. package/dist/selftest/channel.test.js +91 -8
  610. package/dist/selftest/cli.test.d.ts +1 -1
  611. package/dist/selftest/cli.test.js +68 -16
  612. package/dist/selftest/cmdline.test.d.ts +1 -1
  613. package/dist/selftest/cmdline.test.js +36 -7
  614. package/dist/selftest/config.test.d.ts +1 -1
  615. package/dist/selftest/config.test.js +12 -5
  616. package/dist/selftest/data.test.d.ts +1 -1
  617. package/dist/selftest/data.test.js +35 -6
  618. package/dist/selftest/detect.test.d.ts +1 -1
  619. package/dist/selftest/detect.test.js +22 -9
  620. package/dist/selftest/generate.test.d.ts +1 -1
  621. package/dist/selftest/generate.test.js +33 -9
  622. package/dist/selftest/git-access.test.d.ts +1 -1
  623. package/dist/selftest/git-access.test.js +42 -4
  624. package/dist/selftest/guest-boot.test.d.ts +1 -1
  625. package/dist/selftest/guest-boot.test.js +25 -7
  626. package/dist/selftest/host-sim.test.d.ts +1 -1
  627. package/dist/selftest/host-sim.test.js +27 -3
  628. package/dist/selftest/hostile-input.test.d.ts +1 -1
  629. package/dist/selftest/hostile-input.test.js +5 -5
  630. package/dist/selftest/index.d.ts +1 -1
  631. package/dist/selftest/index.js +73 -16
  632. package/dist/selftest/layout.test.d.ts +2 -0
  633. package/dist/selftest/layout.test.js +131 -0
  634. package/dist/selftest/links.test.d.ts +1 -1
  635. package/dist/selftest/links.test.js +16 -11
  636. package/dist/selftest/live-daemon.test.d.ts +1 -1
  637. package/dist/selftest/live-daemon.test.js +20 -8
  638. package/dist/selftest/live-git.test.d.ts +1 -1
  639. package/dist/selftest/live-git.test.js +13 -4
  640. package/dist/selftest/live-network.test.d.ts +1 -1
  641. package/dist/selftest/live-network.test.js +24 -9
  642. package/dist/selftest/live-projects.test.d.ts +1 -1
  643. package/dist/selftest/live-projects.test.js +47 -20
  644. package/dist/selftest/live-terminal.test.d.ts +2 -0
  645. package/dist/selftest/live-terminal.test.js +195 -0
  646. package/dist/selftest/local-config.test.d.ts +1 -1
  647. package/dist/selftest/local-config.test.js +88 -15
  648. package/dist/selftest/mirror.test.d.ts +1 -1
  649. package/dist/selftest/mirror.test.js +118 -19
  650. package/dist/selftest/network.test.d.ts +1 -1
  651. package/dist/selftest/network.test.js +17 -8
  652. package/dist/selftest/personalization.test.d.ts +1 -1
  653. package/dist/selftest/personalization.test.js +12 -5
  654. package/dist/selftest/projects.test.d.ts +1 -1
  655. package/dist/selftest/projects.test.js +336 -72
  656. package/dist/selftest/repair.test.d.ts +1 -1
  657. package/dist/selftest/repair.test.js +17 -5
  658. package/dist/selftest/repo-guard.test.d.ts +1 -1
  659. package/dist/selftest/repo-guard.test.js +21 -20
  660. package/dist/selftest/secrets.test.d.ts +1 -1
  661. package/dist/selftest/secrets.test.js +57 -13
  662. package/dist/selftest/setup.test.d.ts +1 -1
  663. package/dist/selftest/setup.test.js +25 -5
  664. package/dist/selftest/{fixtures.d.ts → support/fixtures.d.ts} +7 -4
  665. package/dist/selftest/{fixtures.js → support/fixtures.js} +95 -17
  666. package/dist/selftest/{harness.js → support/harness.js} +24 -7
  667. package/dist/selftest/{live.d.ts → support/live.d.ts} +2 -2
  668. package/dist/selftest/{live.js → support/live.js} +34 -10
  669. package/dist/selftest/support/suite.js +1 -0
  670. package/dist/selftest/sync.test.d.ts +1 -1
  671. package/dist/selftest/sync.test.js +64 -26
  672. package/dist/selftest/test-guard.test.d.ts +1 -1
  673. package/dist/selftest/test-guard.test.js +43 -15
  674. package/dist/selftest/toolchains.test.d.ts +1 -1
  675. package/dist/selftest/toolchains.test.js +135 -36
  676. package/dist/selftest/workspace-view.test.d.ts +1 -1
  677. package/dist/selftest/workspace-view.test.js +48 -11
  678. package/dist/selftest/workspace.test.d.ts +1 -1
  679. package/dist/selftest/workspace.test.js +13 -4
  680. package/dist/shared/{apps.d.ts → apps/catalogue.d.ts} +1 -11
  681. package/dist/shared/apps/catalogue.js +768 -0
  682. package/dist/shared/apps/index.d.ts +2 -0
  683. package/dist/shared/apps/index.js +2 -0
  684. package/dist/shared/apps/selection.d.ts +11 -0
  685. package/dist/shared/apps/selection.js +40 -0
  686. package/dist/shared/channel/index.d.ts +2 -0
  687. package/dist/shared/channel/index.js +2 -0
  688. package/dist/shared/channel/run-dir.d.ts +30 -0
  689. package/dist/shared/channel/run-dir.js +84 -0
  690. package/dist/shared/{schema.d.ts → channel/schema.d.ts} +60 -19
  691. package/dist/shared/channel/schema.js +131 -0
  692. package/dist/shared/download/archive.d.ts +13 -0
  693. package/dist/shared/download/archive.js +57 -0
  694. package/dist/shared/download/downloader.d.ts +35 -0
  695. package/dist/shared/download/downloader.js +110 -0
  696. package/dist/shared/download/github.d.ts +16 -0
  697. package/dist/shared/download/github.js +74 -0
  698. package/dist/shared/download/http.d.ts +5 -0
  699. package/dist/shared/download/http.js +30 -0
  700. package/dist/shared/download/index.d.ts +5 -0
  701. package/dist/shared/download/index.js +5 -0
  702. package/dist/shared/download/spawn.d.ts +2 -0
  703. package/dist/shared/download/spawn.js +7 -0
  704. package/dist/shared/io/index.d.ts +3 -0
  705. package/dist/shared/io/index.js +3 -0
  706. package/dist/shared/io/json-file.d.ts +10 -0
  707. package/dist/shared/io/json-file.js +21 -0
  708. package/dist/shared/io/json.d.ts +13 -0
  709. package/dist/shared/io/json.js +49 -0
  710. package/dist/shared/{safe-remove.js → io/safe-remove.js} +32 -7
  711. package/dist/shared/{netrules.js → network/firewall-rules.js} +36 -5
  712. package/dist/shared/network/index.d.ts +2 -0
  713. package/dist/shared/network/index.js +2 -0
  714. package/dist/shared/{netpolicy.js → network/policy.js} +66 -11
  715. package/dist/shared/{paths.js → paths/claude-paths.js} +12 -2
  716. package/dist/shared/{guest-paths.d.ts → paths/guest-paths.d.ts} +21 -0
  717. package/dist/shared/paths/guest-paths.js +146 -0
  718. package/dist/shared/paths/index.d.ts +3 -0
  719. package/dist/shared/paths/index.js +3 -0
  720. package/dist/shared/{projects.d.ts → paths/projects.d.ts} +27 -4
  721. package/dist/shared/paths/projects.js +136 -0
  722. package/dist/shared/pty/client.d.ts +21 -0
  723. package/dist/shared/pty/client.js +79 -0
  724. package/dist/shared/pty/console-input.d.ts +11 -0
  725. package/dist/shared/pty/console-input.js +81 -0
  726. package/dist/shared/pty/index.d.ts +6 -0
  727. package/dist/shared/pty/index.js +6 -0
  728. package/dist/shared/pty/input-joiner.d.ts +15 -0
  729. package/dist/shared/pty/input-joiner.js +44 -0
  730. package/dist/shared/pty/output-filter.d.ts +13 -0
  731. package/dist/shared/pty/output-filter.js +140 -0
  732. package/dist/shared/pty/protocol.d.ts +36 -0
  733. package/dist/shared/pty/protocol.js +60 -0
  734. package/dist/shared/pty/terminal.d.ts +24 -0
  735. package/dist/shared/pty/terminal.js +147 -0
  736. package/dist/shared/test-guard.js +3 -1
  737. package/dist/sync/claude-mem.d.ts +1 -1
  738. package/dist/sync/claude-mem.js +9 -4
  739. package/dist/sync/history.d.ts +1 -29
  740. package/dist/sync/history.js +57 -45
  741. package/dist/sync/index.d.ts +5 -0
  742. package/dist/sync/index.js +5 -0
  743. package/dist/sync/sync-cycle.d.ts +18 -0
  744. package/dist/sync/sync-cycle.js +85 -0
  745. package/dist/sync/sync-state.d.ts +32 -0
  746. package/dist/sync/sync-state.js +37 -0
  747. package/dist/sync/watcher.d.ts +0 -18
  748. package/dist/sync/watcher.js +66 -100
  749. package/native/keep-awake.ps1 +8 -0
  750. package/native/power.cs +23 -0
  751. package/native/stop-events.ps1 +38 -0
  752. package/package.json +11 -3
  753. package/sandbox/linkgate.cs +98 -0
  754. package/sandbox/memlog.ps1 +15 -6
  755. package/sandbox/ptyhost.cs +60 -3
  756. package/schemas/config.schema.json +48 -1
  757. package/schemas/sandbox-config.schema.json +37 -3
  758. package/dist/cli/commands/launch.d.ts +0 -29
  759. package/dist/cli/commands/launch.js +0 -366
  760. package/dist/cli/commands/maintenance.d.ts +0 -10
  761. package/dist/cli/commands/maintenance.js +0 -187
  762. package/dist/cli/commands/project.d.ts +0 -29
  763. package/dist/cli/commands/project.js +0 -63
  764. package/dist/cli/commands/projects.d.ts +0 -14
  765. package/dist/cli/commands/projects.js +0 -146
  766. package/dist/cli/commands/restart.d.ts +0 -6
  767. package/dist/cli/commands/restart.js +0 -85
  768. package/dist/cli/commands/sessions.d.ts +0 -12
  769. package/dist/cli/commands/sessions.js +0 -257
  770. package/dist/cli/menu/settings/editors.js +0 -305
  771. package/dist/cli/progress.d.ts +0 -9
  772. package/dist/cli/progress.js +0 -49
  773. package/dist/cli/tui/dialogs.d.ts +0 -57
  774. package/dist/cli/tui/dialogs.js +0 -162
  775. package/dist/core/config.js +0 -109
  776. package/dist/core/schema.d.ts +0 -6
  777. package/dist/core/schema.js +0 -8
  778. package/dist/core/util.d.ts +0 -62
  779. package/dist/core/util.js +0 -156
  780. package/dist/core/workspace.d.ts +0 -18
  781. package/dist/core/workspace.js +0 -145
  782. package/dist/guest/boot-env.d.ts +0 -4
  783. package/dist/guest/daemon.js +0 -57
  784. package/dist/guest/env.d.ts +0 -52
  785. package/dist/guest/env.js +0 -103
  786. package/dist/guest/gitrules.js +0 -11
  787. package/dist/guest/project-status.d.ts +0 -5
  788. package/dist/guest/project-status.js +0 -17
  789. package/dist/guest/setup/user.js +0 -51
  790. package/dist/guest/toolchains/cli.d.ts +0 -10
  791. package/dist/guest/toolchains/common.d.ts +0 -54
  792. package/dist/guest/toolchains/common.js +0 -147
  793. package/dist/guest/toolchains/databases/dynamodb.d.ts +0 -8
  794. package/dist/guest/toolchains/databases/dynamodb.js +0 -52
  795. package/dist/guest/toolchains/databases/index.d.ts +0 -6
  796. package/dist/guest/toolchains/databases/index.js +0 -62
  797. package/dist/guest/toolchains/databases/mongodb.d.ts +0 -3
  798. package/dist/guest/toolchains/databases/mongodb.js +0 -31
  799. package/dist/guest/toolchains/databases/mysql.d.ts +0 -3
  800. package/dist/guest/toolchains/databases/mysql.js +0 -38
  801. package/dist/guest/toolchains/databases/postgres.d.ts +0 -5
  802. package/dist/guest/toolchains/databases/postgres.js +0 -38
  803. package/dist/guest/toolchains/databases/redis.d.ts +0 -3
  804. package/dist/guest/toolchains/databases/redis.js +0 -16
  805. package/dist/guest/toolchains/git.d.ts +0 -3
  806. package/dist/guest/toolchains/go.d.ts +0 -3
  807. package/dist/guest/toolchains/java.d.ts +0 -8
  808. package/dist/guest/toolchains/node.d.ts +0 -3
  809. package/dist/guest/toolchains/pwsh.d.ts +0 -4
  810. package/dist/guest/toolchains/python.d.ts +0 -3
  811. package/dist/guest/toolchains/scripting/php.d.ts +0 -3
  812. package/dist/guest/toolchains/scripting/ruby.d.ts +0 -3
  813. package/dist/host/accounts.d.ts +0 -32
  814. package/dist/host/accounts.js +0 -128
  815. package/dist/host/agent-commands.d.ts +0 -25
  816. package/dist/host/agent-commands.js +0 -145
  817. package/dist/host/channel.d.ts +0 -38
  818. package/dist/host/channel.js +0 -162
  819. package/dist/host/generate.d.ts +0 -13
  820. package/dist/host/generate.js +0 -108
  821. package/dist/host/join.d.ts +0 -28
  822. package/dist/host/join.js +0 -76
  823. package/dist/host/launch/projects.d.ts +0 -15
  824. package/dist/host/launch/wsb.js +0 -34
  825. package/dist/host/motw.d.ts +0 -17
  826. package/dist/host/motw.js +0 -74
  827. package/dist/host/pc-scan.d.ts +0 -6
  828. package/dist/host/personalize.d.ts +0 -10
  829. package/dist/host/personalize.js +0 -97
  830. package/dist/host/platform.js +0 -129
  831. package/dist/host/project-scan.d.ts +0 -7
  832. package/dist/host/projects.d.ts +0 -100
  833. package/dist/host/projects.js +0 -147
  834. package/dist/host/repo-guard.d.ts +0 -43
  835. package/dist/host/repo-guard.js +0 -347
  836. package/dist/host/secrets.d.ts +0 -14
  837. package/dist/host/secrets.js +0 -133
  838. package/dist/host/stops.d.ts +0 -67
  839. package/dist/host/stops.js +0 -126
  840. package/dist/shared/apps.js +0 -114
  841. package/dist/shared/download.d.ts +0 -60
  842. package/dist/shared/download.js +0 -215
  843. package/dist/shared/guest-paths.js +0 -61
  844. package/dist/shared/projects.js +0 -67
  845. package/dist/shared/pty-client.d.ts +0 -91
  846. package/dist/shared/pty-client.js +0 -349
  847. package/dist/shared/rundir.d.ts +0 -41
  848. package/dist/shared/rundir.js +0 -96
  849. package/dist/shared/schema.js +0 -92
  850. /package/dist/{guest/daemon.d.ts → cli/tui/list/list-types.js} +0 -0
  851. /package/dist/{guest/db.d.ts → cli/tui/screen.js} +0 -0
  852. /package/dist/core/{detect-databases.d.ts → detect/databases.d.ts} +0 -0
  853. /package/dist/{guest/toolchains → core/detect}/versions.d.ts +0 -0
  854. /package/dist/guest/{setup/agents.d.ts → agents/agent-installer.d.ts} +0 -0
  855. /package/dist/guest/{audit-parse.d.ts → audit/parse.d.ts} +0 -0
  856. /package/dist/guest/{guide.d.ts → boot/guide.d.ts} +0 -0
  857. /package/dist/guest/daemon/{shutdown.d.ts → idle-shutdown.d.ts} +0 -0
  858. /package/dist/guest/daemon/{session.d.ts → sessions.d.ts} +0 -0
  859. /package/dist/guest/{main.d.ts → entries/daemon.d.ts} +0 -0
  860. /package/dist/guest/{netproxy.d.ts → entries/db.d.ts} +0 -0
  861. /package/dist/{selftest/suite.js → guest/entries/gitguard.d.ts} +0 -0
  862. /package/dist/guest/{gitguard.d.ts → git/decision.d.ts} +0 -0
  863. /package/dist/guest/{ports.d.ts → runtime/ports.d.ts} +0 -0
  864. /package/dist/guest/{project-context.d.ts → runtime/project-context.d.ts} +0 -0
  865. /package/dist/guest/{cmdline.d.ts → sessions/cmdline.d.ts} +0 -0
  866. /package/dist/guest/{ptyhost.d.ts → sessions/pty-host.d.ts} +0 -0
  867. /package/dist/guest/{view.d.ts → sessions/viewer.d.ts} +0 -0
  868. /package/dist/guest/setup/{policy.d.ts → managed-policy.d.ts} +0 -0
  869. /package/dist/host/{window.d.ts → sandbox/window.d.ts} +0 -0
  870. /package/dist/host/{wsb.d.ts → sandbox/wsb-cli.d.ts} +0 -0
  871. /package/dist/host/{cleanup.d.ts → storage/cleanup.d.ts} +0 -0
  872. /package/dist/selftest/{harness.d.ts → support/harness.d.ts} +0 -0
  873. /package/dist/selftest/{suite.d.ts → support/suite.d.ts} +0 -0
  874. /package/dist/shared/{safe-remove.d.ts → io/safe-remove.d.ts} +0 -0
  875. /package/dist/shared/{netrules.d.ts → network/firewall-rules.d.ts} +0 -0
  876. /package/dist/shared/{netpolicy.d.ts → network/policy.d.ts} +0 -0
  877. /package/dist/shared/{paths.d.ts → paths/claude-paths.d.ts} +0 -0
@@ -1,126 +0,0 @@
1
- // Why the last sandbox stopped, when nobody stopped it. The background watcher writes a host-only "life" record (when
2
- // the sandbox started, when it was last seen running, how it ended) and keeps this PC awake while it runs
3
- // (sandbox.keepAwake). When the PC restarts, sleeps or crashes, the watcher stops too and the record has no end: the
4
- // next launch reads Windows' System log from that moment on and says what happened, and what keeps it from happening.
5
- import { spawn, spawnSync } from 'node:child_process';
6
- import path from 'node:path';
7
- import { z } from 'zod';
8
- import { SYSTEM } from '../shared/system.js';
9
- import { readValid, writeJsonAtomic } from '../shared/rundir.js';
10
- import { isWin } from '../core/util.js';
11
- import { refuseInSelfTest } from './test-guard.js';
12
- const Iso = z.string().max(40);
13
- const Life = z.object({
14
- started: Iso, lastSeen: Iso, keepAwake: z.boolean(),
15
- ended: z.object({ at: Iso, cause: z.object({ kind: z.enum(['updates', 'restart', 'crash', 'sleep', 'memory', 'sandboxCrash']), at: Iso, text: z.string().max(400) }).nullable() }).optional(),
16
- reported: z.boolean().optional(),
17
- });
18
- const lifeFile = (storageRoot, dataPath) => path.join(storageRoot, 'sync', path.basename(dataPath) + '-life.json');
19
- export const readLife = (storageRoot, dataPath) => readValid(Life, lifeFile(storageRoot, dataPath));
20
- const writeLife = (storageRoot, dataPath, life) => writeJsonAtomic(lifeFile(storageRoot, dataPath), life);
21
- /** At launch: a fresh record (the previous one has been reported by then). */
22
- export const startLife = (storageRoot, dataPath, keepAwake, now = new Date()) => writeLife(storageRoot, dataPath, { started: now.toISOString(), lastSeen: now.toISOString(), keepAwake });
23
- /** Every minute while the sandbox runs. */
24
- export const beatLife = (storageRoot, dataPath, now = new Date()) => {
25
- const life = readLife(storageRoot, dataPath);
26
- if (life && !life.ended)
27
- writeLife(storageRoot, dataPath, { ...life, lastSeen: now.toISOString() });
28
- };
29
- /** The watcher saw the sandbox close while this PC kept running: closed by you (no cause), or by sleep / low memory. */
30
- export const endLife = (storageRoot, dataPath, cause, now = new Date()) => {
31
- const life = readLife(storageRoot, dataPath);
32
- if (life && !life.ended)
33
- writeLife(storageRoot, dataPath, { ...life, ended: { at: now.toISOString(), cause } });
34
- };
35
- const StopEvents = z.array(z.object({ at: Iso, id: z.number().int(), provider: z.string().max(200), process: z.string().max(400).nullable().transform((p) => p ?? '') })).max(100);
36
- const UPDATERS = /^(trustedinstaller|mousocoreworker|musnotification(ux)?|usoclient|wuauclt|tiworker|updateorchestrator)\.exe$/i;
37
- /**
38
- * The first event that ends a running sandbox (pure): Windows inside the sandbox crashing (Hyper-V 18590; `process`
39
- * holds its message with the stop code), a restart or shutdown, a crash or power loss, sleep, low memory. Switching
40
- * user does not end it (seen on 13 Oct 2026: the sandbox ran on after a switch).
41
- */
42
- export const explainStop = (events) => {
43
- const causes = events.flatMap((e) => {
44
- const p = e.provider.toLowerCase();
45
- if (e.id === 1074 && p.includes('user32')) {
46
- const exe = e.process.split(/[\\/]/).pop()?.replace(/\s*\(.*$/, '') ?? '';
47
- return UPDATERS.test(exe)
48
- ? [{ kind: 'updates', at: e.at, text: 'Windows restarted this PC to install updates' }]
49
- : [{ kind: 'restart', at: e.at, text: 'this PC was restarted or shut down' + (exe ? ' (by ' + exe + ')' : '') }];
50
- }
51
- if ((e.id === 41 && p.includes('kernel-power')) || (e.id === 6008 && p.includes('eventlog')))
52
- return [{ kind: 'crash', at: e.at, text: 'Windows stopped unexpectedly (a crash, a power cut, or the power button held down)' }];
53
- if (e.id === 42 && p.includes('kernel-power'))
54
- return [{ kind: 'sleep', at: e.at, text: 'this PC went to sleep or hibernated' }];
55
- if (e.id === 2004 && p.includes('resource-exhaustion'))
56
- return [{ kind: 'memory', at: e.at, text: 'this PC ran out of memory' }];
57
- if (e.id === 18590 && p.includes('hyper-v-worker')) {
58
- const code = /ErrorCode0:\s*(0x[0-9a-f]{1,8})/i.exec(e.process)?.[1];
59
- const sub = /ErrorCode1:\s*(0x[0-9a-f]{1,16})/i.exec(e.process)?.[1];
60
- return [{ kind: 'sandboxCrash', at: e.at, text: 'Windows inside the sandbox crashed' + (code ? ' (stop code ' + code + (sub ? ', ' + sub : '') + ')' : '') }];
61
- }
62
- return [];
63
- });
64
- return causes.sort((a, b) => Date.parse(a.at) - Date.parse(b.at))[0] ?? null;
65
- };
66
- const ADVICE = {
67
- updates: 'Before leaving agents overnight, restart for pending updates first or pause them (Settings > Windows Update > Pause updates).',
68
- restart: 'If that was not you, check Settings > Windows Update and Event Viewer > Windows Logs > System.',
69
- crash: 'Event Viewer > Windows Logs > System has the details; a laptop also needs to stay plugged in.',
70
- sleep: 'sandbox.keepAwake keeps this PC awake while a sandbox runs (closing a laptop lid still sleeps it). Check it is on, and that sleep is not forced by a policy.',
71
- sandboxCrash: 'C:\\AgentData\\logs\\memory-*.log shows what used memory just before. Fewer builds at once inside the sandbox (e.g. cargo build.jobs) makes it less likely.',
72
- memory: 'Give the sandbox less RAM (sandbox.maxMemoryMb, sandbox.reserveHostMb) or run fewer builds at once inside it.',
73
- };
74
- /** System log and Hyper-V events since `since` that can end a sandbox (Windows only; empty when the logs cannot be read). */
75
- export const readStopEvents = (since) => {
76
- if (!isWin)
77
- return [];
78
- refuseInSelfTest('read the Windows event log');
79
- const script = "$ErrorActionPreference='SilentlyContinue'; $t=[datetime]::Parse('" + since.toISOString() + "').ToLocalTime(); $e = Get-WinEvent -FilterHashtable @(@{LogName='System'; Id=1074,6008,41,42,2004; StartTime=$t}, @{LogName='Microsoft-Windows-Hyper-V-Worker-Admin'; Id=18590; StartTime=$t}) -MaxEvents 100 | ForEach-Object { [pscustomobject]@{ at=$_.TimeCreated.ToUniversalTime().ToString('o'); id=$_.Id; provider=$_.ProviderName; process=$(if ($_.Id -eq 1074) { [string]$_.Properties[0].Value } elseif ($_.Id -eq 18590) { ([string]$_.Message).Substring(0, [math]::Min(390, ([string]$_.Message).Length)) } else { '' }) } }; ConvertTo-Json -Compress -InputObject @($e)";
80
- const result = spawnSync(SYSTEM.powershell(), ['-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(script, 'utf16le').toString('base64')], { encoding: 'utf8', windowsHide: true, timeout: 60000 });
81
- try {
82
- return StopEvents.parse(JSON.parse(result.stdout || '[]'));
83
- }
84
- catch {
85
- return [];
86
- }
87
- };
88
- /** Looking back from the last time the sandbox was seen running (a minute between checks, plus margin). */
89
- export const causeSince = (lastSeen) => explainStop(readStopEvents(new Date(Date.parse(lastSeen) - 2 * 60 * 1000)));
90
- const when = (iso) => new Date(iso).toLocaleString(undefined, { weekday: 'short', hour: '2-digit', minute: '2-digit' });
91
- /**
92
- * At launch: one warning when the last sandbox ended without anyone closing it (the PC restarted, crashed, slept or ran
93
- * out of memory), then never again for that run. `watcherAlive` = its watcher is still running (then it did not end).
94
- */
95
- export const lastStopWarning = (storageRoot, dataPath, watcherAlive, find = causeSince) => {
96
- const life = readLife(storageRoot, dataPath);
97
- if (!life || life.reported || watcherAlive)
98
- return null;
99
- writeLife(storageRoot, dataPath, { ...life, reported: true });
100
- if (life.ended && !life.ended.cause)
101
- return null;
102
- const cause = life.ended ? life.ended.cause : find(life.lastSeen);
103
- const what = cause ? cause.text + ' at ' + when(cause.at) + '. ' + ADVICE[cause.kind] : 'this PC stopped (Windows logged no reason). ' + ADVICE.crash;
104
- return 'The last sandbox did not close normally: it was last seen running at ' + when(life.lastSeen) + ', and ' + what + ' Agent conversations are kept: /resume in Claude picks one up.';
105
- };
106
- // ---- Windows Update and keeping awake ----------------------------------------------------------------------------
107
- /** Windows has installed updates and waits to restart: it may do so on its own, outside your active hours. */
108
- export const updateRestartPending = () => isWin && [
109
- 'HKLM\\SOFTWARE\\Microsoft\\WindowsUpdate\\Auto Update\\RebootRequired',
110
- 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending',
111
- ].some((key) => spawnSync(SYSTEM.reg(), ['query', key], { windowsHide: true, stdio: 'ignore', timeout: 15000 }).status === 0);
112
- export const UPDATE_RESTART_WARNING = 'Windows is waiting to restart for updates and may do so on its own (often overnight), which closes the sandbox. Restart first, or pause updates: Settings > Windows Update > Pause updates.';
113
- /**
114
- * sandbox.keepAwake: asks Windows not to sleep while the sandbox runs (as a video player does; the screen may still turn
115
- * off). A small PowerShell holds the request until `ownerPid` exits, so it never outlives the watcher.
116
- */
117
- export const keepAwake = (ownerPid) => {
118
- if (!isWin)
119
- return null;
120
- refuseInSelfTest('keep this PC awake');
121
- const script = "Add-Type -Name Power -Namespace AgentSandbox -MemberDefinition '[DllImport(\"kernel32.dll\")] public static extern uint SetThreadExecutionState(uint f);'; "
122
- + '[void][AgentSandbox.Power]::SetThreadExecutionState([uint32]2147483649); Wait-Process -Id ' + Math.trunc(ownerPid) + ' -ErrorAction SilentlyContinue';
123
- const child = spawn(SYSTEM.powershell(), ['-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(script, 'utf16le').toString('base64')], { stdio: 'ignore', windowsHide: true });
124
- child.on('error', () => undefined);
125
- return child;
126
- };
@@ -1,114 +0,0 @@
1
- export const APP_CATEGORIES = [
2
- { id: 'editors', label: 'Editors & IDEs', description: 'Code and text editors (VS Code is a setting of its own and on by default).' },
3
- { id: 'databases', label: 'Database clients', description: 'GUIs for the databases the sandbox runs (PostgreSQL, MySQL, MongoDB, Redis, SQLite, DynamoDB).' },
4
- { id: 'api', label: 'API clients', description: 'Send HTTP, REST and GraphQL requests to what you are building.' },
5
- { id: 'git', label: 'Git tools', description: 'Git GUIs and terminal UIs. They use the sandbox\'s git, so its git access rules apply.' },
6
- { id: 'utilities', label: 'Utilities', description: 'Archives, comparing files, finding files, process tools, hex editing.' },
7
- { id: 'browsers', label: 'Browsers', description: 'Browsers for testing web apps (Edge is already in Windows).' },
8
- { id: 'gamedev', label: 'Game development', description: 'Engines and editors. They draw with OpenGL on the CPU (Mesa) when the sandbox has no GPU.' },
9
- { id: 'cloud', label: 'Cloud & Kubernetes', description: 'Command-line tools for clouds, Kubernetes and infrastructure as code.' },
10
- { id: 'diagrams', label: 'Diagrams & docs', description: 'Diagrams and document conversion.' },
11
- { id: 'network', label: 'Network & HTTP', description: 'Inspect and test HTTP traffic and APIs.' },
12
- { id: 'cli', label: 'Command-line tools', description: 'Small tools developers reach for: JSON and YAML, search, diff, builds, media, load testing ...' },
13
- ];
14
- const gh = (github, asset) => ({ github, asset });
15
- export const APPS = [
16
- // ---- editors
17
- { id: 'vscode', name: 'Visual Studio Code', category: 'editors', about: 'Code editor with debugging, set up for the sandbox\'s languages.', size: '150 MB', source: { resolve: 'setting' }, exe: 'Code.exe', setting: 'toolchains.vscode.enabled' },
18
- { id: 'windows-terminal', name: 'Windows Terminal', category: 'utilities', about: 'The sandbox window: tabs, panes, PowerShell 7 profile.', size: '40 MB', source: { resolve: 'setting' }, exe: 'WindowsTerminal.exe', setting: 'provisioning.terminal.enabled' },
19
- { id: 'notepadpp', name: 'Notepad++', category: 'editors', about: 'Fast text and code editor.', size: '8 MB', source: gh('notepad-plus-plus/notepad-plus-plus', '^npp\\.[\\d.]+\\.portable\\.x64\\.zip$'), exe: 'notepad++.exe' },
20
- { id: 'sublime', name: 'Sublime Text', category: 'editors', about: 'Fast code editor (paid licence, free to evaluate).', size: '28 MB', source: { resolve: 'sublime' }, exe: 'sublime_text.exe' },
21
- { id: 'neovim', name: 'Neovim', category: 'editors', about: 'Terminal text editor (nvim).', size: '12 MB', source: gh('neovim/neovim', '^nvim-win64\\.zip$'), exe: 'nvim.exe', cli: true },
22
- // ---- database clients
23
- { id: 'dbeaver', name: 'DBeaver Community', category: 'databases', about: 'Universal database client: PostgreSQL, MySQL, SQLite, SQL Server and more.', size: '120 MB', source: gh('dbeaver/dbeaver', '^dbeaver-ce-[\\d.]+-windows-x86_64\\.zip$'), exe: 'dbeaver.exe' },
24
- { id: 'pgadmin', name: 'pgAdmin 4', category: 'databases', about: 'The PostgreSQL admin GUI (from the PostgreSQL binaries zip).', size: '330 MB', source: { resolve: 'pgadmin' }, exe: 'pgAdmin4.exe' },
25
- { id: 'heidisql', name: 'HeidiSQL', category: 'databases', about: 'Light client for MySQL, MariaDB, PostgreSQL and SQL Server.', size: '28 MB', source: gh('HeidiSQL/HeidiSQL', '^HeidiSQL_[\\d.]+_64_Portable\\.zip$'), exe: 'heidisql.exe' },
26
- { id: 'sqlitebrowser', name: 'DB Browser for SQLite', category: 'databases', about: 'Open, browse and edit SQLite files.', size: '21 MB', source: gh('sqlitebrowser/sqlitebrowser', '^DB\\.Browser\\.for\\.SQLite-v?[\\d.]+-win64\\.zip$'), exe: 'DB Browser for SQLite.exe' },
27
- { id: 'compass', name: 'MongoDB Compass', category: 'databases', about: 'The MongoDB GUI.', size: '220 MB', source: gh('mongodb-js/compass', '^mongodb-compass-[\\d.]+-win32-x64\\.zip$'), exe: 'MongoDBCompass.exe' },
28
- { id: 'redisinsight', name: 'Redis Insight', category: 'databases', about: 'The Redis GUI.', size: '110 MB', source: gh('redis/RedisInsight', '^Redis-Insight-win-installer\\.exe$'), unpack: 'nsis', exe: 'Redis Insight.exe', needs: ['7zip'] },
29
- { id: 'dbgate', name: 'DbGate', category: 'databases', about: 'Database manager for SQL and NoSQL databases.', size: '180 MB', source: gh('dbgate/dbgate', '^dbgate-[\\d.]+-win_x64\\.zip$'), exe: 'DbGate.exe' },
30
- { id: 'beekeeper', name: 'Beekeeper Studio', category: 'databases', about: 'SQL editor and database manager.', size: '245 MB', source: gh('beekeeper-studio/beekeeper-studio', '^Beekeeper-Studio-[\\d.]+-portable\\.exe$'), unpack: 'nsis', exe: 'Beekeeper Studio.exe', needs: ['7zip'] },
31
- { id: 'dynamodb-admin', name: 'dynamodb-admin', category: 'databases', about: 'Web GUI for DynamoDB Local: run dynamodb-admin, then open http://localhost:8001.', size: '5 MB', source: { npm: 'dynamodb-admin' }, exe: 'dynamodb-admin.cmd', cli: true },
32
- // ---- API clients
33
- { id: 'bruno', name: 'Bruno', category: 'api', about: 'Offline, git-friendly API client (collections are files in your repo).', size: '175 MB', source: gh('usebruno/bruno', '^bruno_[\\d.]+_x64_win\\.zip$'), exe: 'Bruno.exe' },
34
- { id: 'insomnia', name: 'Insomnia', category: 'api', about: 'REST, GraphQL and gRPC client.', size: '590 MB', source: gh('Kong/insomnia', '^insomnia-[\\d.]+-full\\.nupkg$'), exe: 'Insomnia.exe' },
35
- // ---- git
36
- { id: 'sourcegit', name: 'SourceGit', category: 'git', about: 'Fast open-source Git GUI.', size: '26 MB', source: gh('sourcegit-scm/sourcegit', '^sourcegit_[\\d.]+\\.win-x64\\.zip$'), exe: 'SourceGit.exe' },
37
- { id: 'githubdesktop', name: 'GitHub Desktop', category: 'git', about: 'Simple Git GUI from GitHub. It has its own git, so it needs provisioning.git.access "full".', size: '300 MB', source: gh('desktop/desktop', '^GitHubDesktop-[\\d.]+-x64-full\\.nupkg$'), exe: 'GitHubDesktop.exe', fullGitOnly: true },
38
- { id: 'lazygit', name: 'lazygit', category: 'git', about: 'Git in the terminal.', size: '7 MB', source: gh('jesseduffield/lazygit', '^lazygit_[\\d.]+_windows_x86_64\\.zip$'), exe: 'lazygit.exe', cli: true },
39
- // ---- utilities
40
- { id: '7zip', name: '7-Zip', category: 'utilities', about: 'Archive manager (7z, zip, rar, tar ...). Also unpacks installers for other apps.', size: '2 MB', source: { resolve: '7zip' }, exe: '7zFM.exe' },
41
- { id: 'winmerge', name: 'WinMerge', category: 'utilities', about: 'Compare and merge files and folders.', size: '23 MB', source: gh('WinMerge/winmerge', '^winmerge-[\\d.]+-x64-exe\\.zip$'), exe: 'WinMergeU.exe' },
42
- { id: 'everything', name: 'Everything', category: 'utilities', about: 'Finds files by name instantly.', size: '2 MB', source: { resolve: 'everything' }, exe: 'Everything.exe' },
43
- { id: 'sysinternals', name: 'Sysinternals Suite', category: 'utilities', about: 'Process Explorer, Process Monitor, Autoruns, TCPView and more (on PATH).', size: '200 MB', source: { url: 'https://download.sysinternals.com/files/SysinternalsSuite.zip' }, exe: 'procexp64.exe' },
44
- { id: 'imhex', name: 'ImHex', category: 'utilities', about: 'Hex editor for reverse engineering and binary formats.', size: '80 MB', source: gh('WerWolv/ImHex', '^imhex-[\\d.]+-Windows-Portable-NoGPU-x86_64\\.zip$'), exe: 'imhex-gui.exe' },
45
- // ---- browsers
46
- { id: 'chrome', name: 'Chrome for Testing', category: 'browsers', about: 'Chrome build made for automated tests (with chromedriver on PATH).', size: '170 MB', source: { resolve: 'chrome' }, exe: 'chrome.exe' },
47
- { id: 'firefox', name: 'Firefox', category: 'browsers', about: 'Firefox for testing.', size: '75 MB', source: { resolve: 'firefox' }, unpack: 'nsis', exe: 'firefox.exe', needs: ['7zip'] },
48
- // ---- game development
49
- { id: 'godot', name: 'Godot', category: 'gamedev', about: 'Open-source 2D and 3D game engine.', size: '80 MB', source: gh('godotengine/godot', '^Godot_v[\\d.]+-stable_win64\\.exe\\.zip$'), exe: '/^Godot_v[\\d.]+-stable_win64\\.exe$/', needs: ['mesa'] },
50
- { id: 'blender', name: 'Blender', category: 'gamedev', about: '3D modelling, animation and rendering.', size: '400 MB', source: { resolve: 'blender' }, exe: 'blender.exe', needs: ['mesa'] },
51
- { id: 'love', name: 'LÖVE', category: 'gamedev', about: 'Lua framework for 2D games.', size: '4 MB', source: gh('love2d/love', '^love-[\\d.]+-win64\\.zip$'), exe: 'love.exe', needs: ['mesa'] },
52
- { id: 'defold', name: 'Defold', category: 'gamedev', about: 'Free 2D/3D game engine and editor.', size: '330 MB', source: gh('defold/defold', '^Defold-x86_64-win32\\.zip$'), exe: 'Defold.exe', needs: ['mesa'] },
53
- { id: 'pixelorama', name: 'Pixelorama', category: 'gamedev', about: 'Pixel-art and sprite editor.', size: '40 MB', source: gh('Orama-Interactive/Pixelorama', '^Pixelorama-Windows-64bit\\.zip$'), exe: 'Pixelorama.exe', needs: ['mesa'] },
54
- { id: 'tiled', name: 'Tiled', category: 'gamedev', about: 'Tile map editor.', size: '22 MB', source: gh('mapeditor/tiled', '^Tiled-[\\d.]+_Windows-10\\+_x86_64\\.msi$'), unpack: 'msi', exe: 'tiled.exe' },
55
- // ---- cloud
56
- { id: 'kubectl', name: 'kubectl', category: 'cloud', about: 'Kubernetes command line.', size: '60 MB', source: { resolve: 'kubectl' }, unpack: 'file', exe: 'kubectl.exe', cli: true },
57
- { id: 'helm', name: 'Helm', category: 'cloud', about: 'Kubernetes package manager.', size: '20 MB', source: { resolve: 'helm' }, exe: 'helm.exe', cli: true },
58
- { id: 'k9s', name: 'k9s', category: 'cloud', about: 'Kubernetes cluster UI in the terminal.', size: '40 MB', source: gh('derailed/k9s', '^k9s_Windows_amd64\\.zip$'), exe: 'k9s.exe', cli: true },
59
- { id: 'terraform', name: 'Terraform', category: 'cloud', about: 'Infrastructure as code.', size: '30 MB', source: { resolve: 'terraform' }, exe: 'terraform.exe', cli: true },
60
- { id: 'azure-cli', name: 'Azure CLI', category: 'cloud', about: 'Manage Azure (az).', size: '90 MB', source: { url: 'https://aka.ms/installazurecliwindowszipx64' }, exe: 'az.cmd', cli: true },
61
- { id: 'gcloud', name: 'Google Cloud CLI', category: 'cloud', about: 'Manage Google Cloud (gcloud, gsutil, bq).', size: '120 MB', source: { url: 'https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-windows-x86_64-bundled-python.zip' }, exe: 'gcloud.cmd', cli: true },
62
- { id: 'aws-cli', name: 'AWS CLI', category: 'cloud', about: 'Manage AWS (aws).', size: '50 MB', source: { url: 'https://awscli.amazonaws.com/AWSCLIV2.msi' }, unpack: 'msi', exe: 'aws.exe', cli: true },
63
- // ---- diagrams and docs
64
- { id: 'drawio', name: 'draw.io', category: 'diagrams', about: 'Diagram editor (flowcharts, architecture, UML).', size: '170 MB', source: gh('jgraph/drawio-desktop', '^draw\\.io-[\\d.]+-windows\\.zip$'), exe: 'draw.io.exe' },
65
- { id: 'pandoc', name: 'Pandoc', category: 'diagrams', about: 'Convert documents between Markdown, HTML, Word, PDF ...', size: '35 MB', source: gh('jgm/pandoc', '^pandoc-[\\d.]+-windows-x86_64\\.zip$'), exe: 'pandoc.exe', cli: true },
66
- // ---- network
67
- { id: 'mitmproxy', name: 'mitmproxy', category: 'network', about: 'Intercepting HTTPS proxy (mitmweb opens a web UI).', size: '90 MB', source: { resolve: 'mitmproxy' }, exe: 'mitmweb.exe', cli: true },
68
- { id: 'xh', name: 'xh', category: 'network', about: 'Friendly HTTP requests from the terminal (like HTTPie).', size: '5 MB', source: gh('ducaale/xh', '^xh-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$'), exe: 'xh.exe', cli: true },
69
- { id: 'grpcurl', name: 'grpcurl', category: 'network', about: 'curl for gRPC servers.', size: '10 MB', source: gh('fullstorydev/grpcurl', '^grpcurl_[\\d.]+_windows_x86_64\\.zip$'), exe: 'grpcurl.exe', cli: true },
70
- { id: 'k6', name: 'k6', category: 'network', about: 'Load testing with JavaScript scripts.', size: '30 MB', source: gh('grafana/k6', '^k6-v[\\d.]+-windows-amd64\\.zip$'), exe: 'k6.exe', cli: true },
71
- // ---- command-line tools
72
- { id: 'jq', name: 'jq', category: 'cli', about: 'Query and reshape JSON.', size: '1 MB', source: gh('jqlang/jq', '^jq-windows-amd64\\.exe$'), unpack: 'file', exe: 'jq.exe', cli: true },
73
- { id: 'yq', name: 'yq', category: 'cli', about: 'Query and edit YAML, JSON, XML and TOML.', size: '10 MB', source: gh('mikefarah/yq', '^yq_windows_amd64\\.exe$'), unpack: 'file', exe: 'yq.exe', cli: true },
74
- { id: 'ripgrep', name: 'ripgrep', category: 'cli', about: 'Very fast recursive search (rg).', size: '2 MB', source: gh('BurntSushi/ripgrep', '^ripgrep-[\\d.]+-x86_64-pc-windows-msvc\\.zip$'), exe: 'rg.exe', cli: true },
75
- { id: 'fd', name: 'fd', category: 'cli', about: 'Fast, friendly alternative to find.', size: '2 MB', source: gh('sharkdp/fd', '^fd-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$'), exe: 'fd.exe', cli: true },
76
- { id: 'bat', name: 'bat', category: 'cli', about: 'cat with syntax highlighting and git changes.', size: '3 MB', source: gh('sharkdp/bat', '^bat-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$'), exe: 'bat.exe', cli: true },
77
- { id: 'fzf', name: 'fzf', category: 'cli', about: 'Fuzzy finder for the terminal.', size: '2 MB', source: gh('junegunn/fzf', '^fzf-[\\d.]+-windows_amd64\\.zip$'), exe: 'fzf.exe', cli: true },
78
- { id: 'delta', name: 'delta', category: 'cli', about: 'Readable git diffs with syntax highlighting.', size: '3 MB', source: gh('dandavison/delta', '^delta-[\\d.]+-x86_64-pc-windows-msvc\\.zip$'), exe: 'delta.exe', cli: true },
79
- { id: 'just', name: 'just', category: 'cli', about: 'Command runner (a simpler make for project tasks).', size: '2 MB', source: gh('casey/just', '^just-[\\d.]+-x86_64-pc-windows-msvc\\.zip$'), exe: 'just.exe', cli: true },
80
- { id: 'hyperfine', name: 'hyperfine', category: 'cli', about: 'Benchmark commands.', size: '1 MB', source: gh('sharkdp/hyperfine', '^hyperfine-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$'), exe: 'hyperfine.exe', cli: true },
81
- { id: 'watchexec', name: 'watchexec', category: 'cli', about: 'Run a command when files change.', size: '5 MB', source: gh('watchexec/watchexec', '^watchexec-[\\d.]+-x86_64-pc-windows-msvc\\.zip$'), exe: 'watchexec.exe', cli: true },
82
- { id: 'protoc', name: 'protoc', category: 'cli', about: 'Protocol Buffers compiler.', size: '3 MB', source: gh('protocolbuffers/protobuf', '^protoc-[\\d.]+-win64\\.zip$'), exe: 'protoc.exe', cli: true },
83
- { id: 'ninja', name: 'Ninja', category: 'cli', about: 'Small, fast build system (CMake\'s favourite generator).', size: '1 MB', source: gh('ninja-build/ninja', '^ninja-win\\.zip$'), exe: 'ninja.exe', cli: true },
84
- { id: 'ffmpeg', name: 'FFmpeg', category: 'cli', about: 'Convert and process audio and video.', size: '200 MB', source: gh('BtbN/FFmpeg-Builds', '^ffmpeg-master-latest-win64-gpl\\.zip$'), exe: 'ffmpeg.exe', cli: true },
85
- { id: 'sqlite', name: 'SQLite tools', category: 'cli', about: 'sqlite3 command-line shell.', size: '5 MB', source: { resolve: 'sqlite' }, exe: 'sqlite3.exe', cli: true },
86
- { id: 'shellcheck', name: 'ShellCheck', category: 'cli', about: 'Finds bugs in shell scripts.', size: '10 MB', source: gh('koalaman/shellcheck', '^shellcheck-v[\\d.]+\\.zip$'), exe: 'shellcheck.exe', cli: true },
87
- { id: 'gitleaks', name: 'Gitleaks', category: 'cli', about: 'Finds secrets committed to git.', size: '8 MB', source: gh('gitleaks/gitleaks', '^gitleaks_[\\d.]+_windows_x64\\.zip$'), exe: 'gitleaks.exe', cli: true },
88
- ];
89
- export const appById = (id) => APPS.find((a) => a.id === id);
90
- /** A catalogue `exe` that is a regex ("/.../") matches names with a version in them. */
91
- export const exeMatcher = (exe) => {
92
- const regex = /^\/(.+)\/$/.exec(exe);
93
- if (regex) {
94
- const r = new RegExp(regex[1], 'i');
95
- return (name) => r.test(name);
96
- }
97
- return (name) => name.toLowerCase() === exe.toLowerCase();
98
- };
99
- /** Your own program as a catalogue entry (its folder is apps\custom\<id>). */
100
- const customEntry = (id, app) => ({
101
- id: 'custom/' + id, name: app.name, category: 'utilities', about: 'Your own program.', size: '?',
102
- source: app.github && app.asset ? { github: app.github, asset: app.asset } : { url: app.url },
103
- unpack: app.unpack, exe: app.exe, cli: app.cli,
104
- });
105
- /** The apps to install, in order: 7-Zip first when anything needs it to unpack. */
106
- export const appsToInstall = (apps, gitAccess) => {
107
- const chosen = apps.install.flatMap((id) => { const e = appById(id); return e && !e.setting ? [e] : []; });
108
- const skipped = chosen.filter((e) => e.fullGitOnly && gitAccess !== 'full').map((e) => e.name + ' (needs provisioning.git.access "full")');
109
- const allowed = [...chosen.filter((e) => !(e.fullGitOnly && gitAccess !== 'full')), ...Object.entries(apps.custom).map(([id, app]) => customEntry(id, app))];
110
- const needs7zip = allowed.some((e) => e.needs?.includes('7zip') || e.unpack === 'nsis') && !allowed.some((e) => e.id === '7zip');
111
- return { entries: [...(needs7zip ? [appById('7zip')] : []), ...allowed], skipped };
112
- };
113
- /** Does any chosen app draw with OpenGL (so the Mesa step must run first)? */
114
- export const appsNeedMesa = (apps) => Boolean(apps?.install.some((id) => appById(id)?.needs?.includes('mesa')));
@@ -1,60 +0,0 @@
1
- /**
2
- * A fresh `<destination>.staging-<hex>` folder next to `destination`: fill it, then moveIntoPlace. An interrupted copy
3
- * or extraction leaves only the staging folder (cleanup/repair remove those), never a half-filled destination.
4
- */
5
- export declare const stagingFolder: (destination: string) => string;
6
- /** Replaces `destination` with the finished `work` folder (a folder rename: the destination is never half there). */
7
- export declare const moveIntoPlace: (work: string, destination: string) => void;
8
- /** fetch with retries (the sandbox network can take a few seconds to come up) and a timeout per attempt. */
9
- export declare const fetchRetry: (url: string, init?: RequestInit, attempts?: number, timeoutMs?: number) => Promise<Response>;
10
- /** Small lookups fail fast (2 tries, 20 s each) so an offline boot falls back to cached versions quickly. */
11
- export declare const fetchJson: <T>(url: string) => Promise<T>;
12
- export declare const fetchText: (url: string) => Promise<string>;
13
- /** Expected checksums of a download; any that are given must match. */
14
- export interface Checksums {
15
- sha256?: string | null;
16
- sha512?: string | null;
17
- }
18
- /** downloads.requireChecksum: from then on download() refuses anything it has no expected hash for. The guest sets it from session.json. */
19
- export declare const setChecksumRequired: (on: boolean) => void;
20
- /**
21
- * Streams a download to disk, hashing as it goes: big archives (PostgreSQL is ~330 MB) never sit in memory, and the
22
- * event loop stays free so other toolchains keep downloading meanwhile. A mismatch (or any failure) leaves no file behind.
23
- */
24
- export declare const download: (url: string, destination: string, expected?: string | null | Checksums) => Promise<void>;
25
- /** Runs a program without blocking the event loop (parallel downloads keep going); resolves with its exit code. */
26
- export declare const spawnAsync: (file: string, args: string[], options?: import("node:child_process").SpawnOptions) => Promise<number>;
27
- export interface ReleaseAsset {
28
- url: string;
29
- name: string;
30
- sha256: string | null;
31
- }
32
- /**
33
- * Finds an asset in the latest GitHub release of `repo` (with its published sha256 when available). With
34
- * `searchOlder`, falls back to the newest stable release that still ships a matching asset (projects drop assets).
35
- */
36
- export declare const githubAsset: (repo: string, pattern: RegExp, searchOlder?: boolean) => Promise<ReleaseAsset>;
37
- /** A release's assets from github.com's expanded_assets page (no API rate limit): each download link, then its sha256. */
38
- export declare const parseReleasePage: (html: string) => ReleaseAsset[];
39
- /** The latest release's tag, from github.com's own redirect (no API, no rate limit). */
40
- export declare const latestGithubTag: (repo: string) => Promise<string>;
41
- /** Release tags in the order github.com's /<repo>/releases page lists them (newest first), without duplicates. */
42
- export declare const parseReleaseTags: (html: string, repo: string) => string[];
43
- /**
44
- * Extracts .zip / .nupkg / .7z / .tar.gz with the tar.exe that ships with Windows, falling back to Expand-Archive.
45
- * `members` limits it to those paths inside the archive (e.g. skip pgAdmin in the PostgreSQL zip).
46
- */
47
- export declare const extractArchive: (archive: string, destination: string, members?: string[]) => Promise<void>;
48
- export declare const findFile: (root: string, name: string, maxDepth?: number) => string | null;
49
- /**
50
- * Downloads + extracts into `destination` atomically (staging folder, then rename). With `locate`, only the folder holding
51
- * that file is kept (`up` folders above it, e.g. locate ruby.exe with up 1 keeps the folder around bin).
52
- */
53
- export declare const installArchive: (url: string, destination: string, options?: {
54
- sha256?: string | null;
55
- sha512?: string | null;
56
- locate?: string;
57
- up?: number;
58
- fileName?: string;
59
- members?: string[];
60
- }) => Promise<void>;
@@ -1,215 +0,0 @@
1
- // Download/extract helpers shared by the host (Windows Terminal pre-download) and the guest (toolchains).
2
- // Node built-ins only, so it stays small in both bundles (the CLI and the guest runtime).
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import crypto from 'node:crypto';
6
- import { spawn } from 'node:child_process';
7
- import { Readable, Transform } from 'node:stream';
8
- import { pipeline } from 'node:stream/promises';
9
- import { safeRemove } from './safe-remove.js';
10
- import { SYSTEM } from './system.js';
11
- const USER_AGENT = 'windows-development-sandbox';
12
- /**
13
- * A fresh `<destination>.staging-<hex>` folder next to `destination`: fill it, then moveIntoPlace. An interrupted copy
14
- * or extraction leaves only the staging folder (cleanup/repair remove those), never a half-filled destination.
15
- */
16
- export const stagingFolder = (destination) => destination + '.staging-' + crypto.randomBytes(3).toString('hex');
17
- /** Replaces `destination` with the finished `work` folder (a folder rename: the destination is never half there). */
18
- export const moveIntoPlace = (work, destination) => {
19
- safeRemove(destination, path.dirname(destination));
20
- fs.mkdirSync(path.dirname(destination), { recursive: true });
21
- fs.renameSync(work, destination);
22
- };
23
- /** fetch with retries (the sandbox network can take a few seconds to come up) and a timeout per attempt. */
24
- export const fetchRetry = async (url, init = {}, attempts = 5, timeoutMs = 60000) => {
25
- let last;
26
- for (let i = 1; i <= attempts; i++) {
27
- try {
28
- const response = await fetch(url, { ...init, signal: AbortSignal.timeout(timeoutMs), headers: { 'User-Agent': USER_AGENT, ...(init.headers ?? {}) } });
29
- if (response.ok)
30
- return response;
31
- last = new Error('HTTP ' + response.status + ' for ' + url);
32
- if (response.status === 404)
33
- break;
34
- }
35
- catch (e) {
36
- last = e;
37
- }
38
- if (i < attempts)
39
- await new Promise((r) => setTimeout(r, 3000));
40
- }
41
- throw last instanceof Error ? last : new Error(String(last));
42
- };
43
- /** Small lookups fail fast (2 tries, 20 s each) so an offline boot falls back to cached versions quickly. */
44
- export const fetchJson = async (url) => await (await fetchRetry(url, { headers: { Accept: 'application/json' } }, 2, 20000)).json();
45
- export const fetchText = async (url) => await (await fetchRetry(url)).text();
46
- let checksumRequired = false;
47
- /** downloads.requireChecksum: from then on download() refuses anything it has no expected hash for. The guest sets it from session.json. */
48
- export const setChecksumRequired = (on) => { checksumRequired = on; };
49
- /**
50
- * Streams a download to disk, hashing as it goes: big archives (PostgreSQL is ~330 MB) never sit in memory, and the
51
- * event loop stays free so other toolchains keep downloading meanwhile. A mismatch (or any failure) leaves no file behind.
52
- */
53
- export const download = async (url, destination, expected = null) => {
54
- const sums = typeof expected === 'string' || expected === null ? { sha256: expected } : expected;
55
- if (checksumRequired && !sums.sha256?.trim() && !sums.sha512?.trim()) {
56
- throw new Error('Refusing to download ' + path.basename(destination) + ' (' + url + '): no checksum is published for it, and downloads.requireChecksum is on. Turn that setting off to allow downloads that cannot be verified.');
57
- }
58
- const response = await fetchRetry(url, {}, 3, 20 * 60 * 1000);
59
- if (!response.body)
60
- throw new Error('Empty response for ' + url);
61
- fs.mkdirSync(path.dirname(destination), { recursive: true });
62
- // Only the hashes that will be checked (sha512 of a 330 MB archive is not free).
63
- const checks = ['sha256', 'sha512'].flatMap((kind) => {
64
- const want = sums[kind]?.trim().toLowerCase();
65
- return want ? [{ want, hash: crypto.createHash(kind) }] : [];
66
- });
67
- const tap = new Transform({ transform(chunk, _encoding, done) { for (const c of checks)
68
- c.hash.update(chunk); done(null, chunk); } });
69
- // Written to <destination>.part and moved into place only once complete and verified, so an interrupted download never
70
- // leaves a partial file under the real name.
71
- const partial = destination + '.part';
72
- try {
73
- await pipeline(Readable.fromWeb(response.body), tap, fs.createWriteStream(partial));
74
- if (checks.some((c) => c.hash.digest('hex') !== c.want))
75
- throw new Error('Checksum mismatch for ' + url);
76
- // Mapped folders refuse rename-over, so the old file goes first.
77
- fs.rmSync(destination, { force: true });
78
- fs.renameSync(partial, destination);
79
- }
80
- finally {
81
- fs.rmSync(partial, { force: true });
82
- }
83
- };
84
- /** Runs a program without blocking the event loop (parallel downloads keep going); resolves with its exit code. */
85
- export const spawnAsync = (file, args, options = {}) => new Promise((resolve, reject) => {
86
- const child = spawn(file, args, { stdio: 'ignore', windowsHide: true, ...options });
87
- child.once('error', reject);
88
- child.once('close', (code) => resolve(code ?? -1));
89
- });
90
- const toAsset = (asset) => ({ url: asset.browser_download_url, name: asset.name, sha256: asset.digest?.startsWith('sha256:') ? asset.digest.slice(7) : null });
91
- /**
92
- * Finds an asset in the latest GitHub release of `repo` (with its published sha256 when available). With
93
- * `searchOlder`, falls back to the newest stable release that still ships a matching asset (projects drop assets).
94
- */
95
- export const githubAsset = async (repo, pattern, searchOlder = false) => {
96
- let latest;
97
- try {
98
- latest = await fetchJson('https://api.github.com/repos/' + repo + '/releases/latest');
99
- }
100
- catch (e) {
101
- // The API allows 60 requests an hour per IP without a token; a first boot alone makes a dozen. The release page has
102
- // the same assets and digests and no such limit.
103
- if (!/HTTP (403|429)/.test(e instanceof Error ? e.message : ''))
104
- throw e;
105
- return githubAssetFromPage(repo, pattern, searchOlder);
106
- }
107
- const hit = latest.assets.find((a) => pattern.test(a.name));
108
- if (hit)
109
- return toAsset(hit);
110
- if (searchOlder) {
111
- const releases = await fetchJson('https://api.github.com/repos/' + repo + '/releases?per_page=100');
112
- for (const release of releases.filter((r) => !r.prerelease && !r.draft)) {
113
- const older = release.assets.find((a) => pattern.test(a.name));
114
- if (older)
115
- return toAsset(older);
116
- }
117
- }
118
- throw new Error('No asset matching ' + pattern + ' in the ' + (searchOlder ? 'stable' : 'latest') + ' ' + repo + ' release(s)');
119
- };
120
- /** A release's assets from github.com's expanded_assets page (no API rate limit): each download link, then its sha256. */
121
- export const parseReleasePage = (html) => {
122
- const links = [...html.matchAll(/href="(\/[^"]+\/releases\/download\/[^"]+)"/g)];
123
- return links.map((link, i) => {
124
- const digest = /sha256:([0-9a-f]{64})/.exec(html.slice(link.index, links[i + 1]?.index ?? html.length))?.[1] ?? null;
125
- return { url: 'https://github.com' + link[1], name: decodeURIComponent(link[1].split('/').pop()), sha256: digest };
126
- });
127
- };
128
- /** The latest release's tag, from github.com's own redirect (no API, no rate limit). */
129
- export const latestGithubTag = async (repo) => {
130
- const latest = await fetchRetry('https://github.com/' + repo + '/releases/latest', {}, 2, 20000);
131
- const tag = decodeURIComponent(latest.url.split('/releases/tag/')[1] ?? '');
132
- return tag || Promise.reject(new Error('Could not find the latest release of ' + repo));
133
- };
134
- /** Release tags in the order github.com's /<repo>/releases page lists them (newest first), without duplicates. */
135
- export const parseReleaseTags = (html, repo) => {
136
- const escaped = repo.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&');
137
- const tags = [...html.matchAll(new RegExp('href="/' + escaped + '/releases/tag/([^"?#]+)"', 'gi'))].map((m) => decodeURIComponent(m[1]));
138
- return [...new Set(tags)];
139
- };
140
- /** How many releases the rate-limit fallback looks through for `searchOlder` (one page request each). */
141
- const OLDER_RELEASES = 10;
142
- const githubAssetFromPage = async (repo, pattern, searchOlder) => {
143
- const assetsOf = async (tag) => parseReleasePage(await fetchText('https://github.com/' + repo + '/releases/expanded_assets/' + encodeURIComponent(tag))).find((a) => pattern.test(a.name));
144
- const latest = await latestGithubTag(repo);
145
- const hit = await assetsOf(latest);
146
- if (hit)
147
- return hit;
148
- // nvm-windows' portable zip and winlibs' builds only exist in older releases: walk the release list like the API path does.
149
- if (searchOlder) {
150
- const older = parseReleaseTags(await fetchText('https://github.com/' + repo + '/releases'), repo).filter((t) => t !== latest);
151
- for (const tag of older.slice(0, OLDER_RELEASES)) {
152
- const found = await assetsOf(tag);
153
- if (found)
154
- return found;
155
- }
156
- }
157
- throw new Error('No asset matching ' + pattern + ' in ' + repo + ' ' + latest + (searchOlder ? ' or the releases before it' : ''));
158
- };
159
- /**
160
- * Extracts .zip / .nupkg / .7z / .tar.gz with the tar.exe that ships with Windows, falling back to Expand-Archive.
161
- * `members` limits it to those paths inside the archive (e.g. skip pgAdmin in the PostgreSQL zip).
162
- */
163
- export const extractArchive = async (archive, destination, members = []) => {
164
- fs.mkdirSync(destination, { recursive: true });
165
- let status = await spawnAsync(SYSTEM.tar(), ['-xf', archive, '-C', destination, ...members]);
166
- if (status !== 0 && /\.(zip|nupkg)$/i.test(archive)) {
167
- const zip = archive.endsWith('.zip') ? archive : archive + '.zip';
168
- if (zip !== archive)
169
- fs.copyFileSync(archive, zip);
170
- status = await spawnAsync(SYSTEM.powershell(), ['-NoLogo', '-NoProfile', '-Command', "Expand-Archive -LiteralPath '" + zip.replace(/'/g, "''") + "' -DestinationPath '" + destination.replace(/'/g, "''") + "' -Force"]);
171
- }
172
- if (status !== 0)
173
- throw new Error('Could not extract ' + archive);
174
- };
175
- export const findFile = (root, name, maxDepth = 4) => {
176
- if (maxDepth < 0 || !fs.existsSync(root))
177
- return null;
178
- const entries = fs.readdirSync(root, { withFileTypes: true });
179
- for (const entry of entries)
180
- if (entry.isFile() && entry.name.toLowerCase() === name.toLowerCase())
181
- return path.join(root, entry.name);
182
- for (const entry of entries)
183
- if (entry.isDirectory()) {
184
- const found = findFile(path.join(root, entry.name), name, maxDepth - 1);
185
- if (found)
186
- return found;
187
- }
188
- return null;
189
- };
190
- /**
191
- * Downloads + extracts into `destination` atomically (staging folder, then rename). With `locate`, only the folder holding
192
- * that file is kept (`up` folders above it, e.g. locate ruby.exe with up 1 keeps the folder around bin).
193
- */
194
- export const installArchive = async (url, destination, options = {}) => {
195
- const work = stagingFolder(destination);
196
- try {
197
- const archive = path.join(work, options.fileName ?? path.basename(new URL(url).pathname));
198
- await download(url, archive, { sha256: options.sha256, sha512: options.sha512 });
199
- const extracted = path.join(work, 'x');
200
- await extractArchive(archive, extracted, options.members);
201
- let root = extracted;
202
- if (options.locate) {
203
- const found = findFile(extracted, options.locate);
204
- if (!found)
205
- throw new Error(options.locate + ' not found in ' + url);
206
- root = path.dirname(found);
207
- for (let i = 0; i < (options.up ?? 0) && path.dirname(root).startsWith(extracted); i++)
208
- root = path.dirname(root);
209
- }
210
- moveIntoPlace(root, destination);
211
- }
212
- finally {
213
- safeRemove(work, path.dirname(work));
214
- }
215
- };
@@ -1,61 +0,0 @@
1
- // Guest paths on drive letters other than C:. Windows Sandbox can only map folders onto its own C: drive, so a
2
- // guest path like F:\SteamLibrary\x is mapped to C:\Mirror\F\SteamLibrary\x and, at boot (bootstrap.ps1, before
3
- // anything else uses the workspace), `subst F: C:\Mirror\F` makes it appear at F:\SteamLibrary\x.
4
- // Pure functions only: used by the schema, the host (.wsb, session.json) and history sync.
5
- /** Guest folders no mapping may use: the OS, the sandbox's own folders and the mirror root. */
6
- export const RESERVED_GUEST = /^C:\\(?:Windows|Program Files|Program Files \(x86\)|ProgramData|Users|AgentLaunch|AgentData|HostTools|nvm|Mirror)(?:\\|$)/i;
7
- /** Where folders for other drive letters really live inside the sandbox: C:\Mirror\<letter>. */
8
- export const MIRROR_ROOT = 'C:\\Mirror';
9
- /** Letters a mirrored path may use. Never C: (the sandbox's own disk); A:/B: are left alone (floppy-era tools). */
10
- export const MIRROR_LETTER = /^[D-Z]$/;
11
- const DRIVE_PATH = /^([A-Za-z]):\\(.*)$/;
12
- // No other ':' (alternate data streams), no wildcards or pipes, no control characters, no forward slashes.
13
- const BAD_CHARS = /[<>:"|?*/\x00-\x1f]/;
14
- /** The upper-case drive letter of an absolute guest path (F:\x -> F), or null. */
15
- export const guestDrive = (guest) => DRIVE_PATH.exec(guest)?.[1].toUpperCase() ?? null;
16
- /**
17
- * A folder the sandbox can show a host folder at: C:\<not reserved>\... or <D-Z>:\..., never a drive root,
18
- * no '..' or empty segments, no characters Windows rejects in paths.
19
- */
20
- export const isValidGuestPath = (guest) => {
21
- const m = DRIVE_PATH.exec(guest);
22
- if (!m)
23
- return false;
24
- const letter = m[1].toUpperCase();
25
- const rest = m[2].replace(/\\+$/, '');
26
- if (rest === '' || BAD_CHARS.test(rest))
27
- return false;
28
- if (rest.split('\\').some((segment) => segment === '' || segment === '.' || segment === '..' || /[. ]$/.test(segment)))
29
- return false;
30
- if (letter === 'C')
31
- return !RESERVED_GUEST.test('C:\\' + rest);
32
- return MIRROR_LETTER.test(letter);
33
- };
34
- /** Where a guest path really is inside the sandbox (the .wsb SandboxFolder): C: paths as-is, F:\x -> C:\Mirror\F\x. */
35
- export const sandboxFolder = (guest) => {
36
- const m = DRIVE_PATH.exec(guest);
37
- if (!m || m[1].toUpperCase() === 'C')
38
- return guest;
39
- return MIRROR_ROOT + '\\' + m[1].toUpperCase() + (m[2] ? '\\' + m[2] : '');
40
- };
41
- /** The subst drives the guest must create at boot for these guest paths, one per letter, sorted. */
42
- export const substDrives = (guests) => {
43
- const letters = [...new Set(guests.map(guestDrive).filter((l) => l !== null && l !== 'C'))].sort();
44
- return letters.map((letter) => ({ letter, target: MIRROR_ROOT + '\\' + letter }));
45
- };
46
- /**
47
- * guestWorkspace "mirror": the workspace at the same path as on this PC, so absolute paths (configs, build caches,
48
- * cargo fingerprints, Claude's project folder) match. Falls back to `fallback` (C:\Workspace\<name>) when the host
49
- * path cannot be used inside the sandbox (C:\Users\..., a UNC path, A:/B:, odd characters), with a note saying why.
50
- */
51
- export const planMirrorWorkspace = (workspaceHost, fallback) => {
52
- const host = workspaceHost.replace(/\\+$/, '');
53
- if (isValidGuestPath(host)) {
54
- const letter = guestDrive(host);
55
- return { guest: letter + host.slice(1), note: letter === 'C' ? null : 'guestWorkspace "mirror": ' + host + ' is mapped to ' + sandboxFolder(letter + host.slice(1)) + ' and shown as ' + letter + ': (subst) inside the sandbox.' };
56
- }
57
- const why = !guestDrive(host) ? 'it is not on a drive letter'
58
- : guestDrive(host) === 'C' && RESERVED_GUEST.test(host) ? 'that folder is reserved inside the sandbox (Windows, Program Files, Users, ...)'
59
- : 'the sandbox cannot show a folder at that path';
60
- return { guest: fallback, note: 'guestWorkspace "mirror": ' + host + ' cannot appear at the same path (' + why + '); using ' + fallback + ' instead.' };
61
- };