windows-development-sandbox 1.4.1 → 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 (872) hide show
  1. package/config.example.json +3 -1
  2. package/dist/api.js +27 -16
  3. package/dist/cli/args.d.ts +4 -6
  4. package/dist/cli/args.js +67 -34
  5. package/dist/cli/argv.d.ts +9 -0
  6. package/dist/cli/argv.js +22 -0
  7. package/dist/cli/commands/accounts.d.ts +1 -1
  8. package/dist/cli/commands/accounts.js +42 -27
  9. package/dist/cli/commands/agent-commands.d.ts +3 -3
  10. package/dist/cli/commands/agent-commands.js +27 -18
  11. package/dist/cli/commands/context.d.ts +9 -11
  12. package/dist/cli/commands/context.js +35 -32
  13. package/dist/cli/commands/data/clean.d.ts +2 -2
  14. package/dist/cli/commands/data/clean.js +27 -11
  15. package/dist/cli/commands/data/collect.d.ts +6 -3
  16. package/dist/cli/commands/data/collect.js +46 -15
  17. package/dist/cli/commands/data/index.d.ts +2 -2
  18. package/dist/cli/commands/data/index.js +30 -12
  19. package/dist/cli/commands/data/remove.d.ts +1 -1
  20. package/dist/cli/commands/data/remove.js +4 -4
  21. package/dist/cli/commands/index.d.ts +5 -4
  22. package/dist/cli/commands/index.js +5 -4
  23. package/dist/cli/commands/launch/add-root.d.ts +7 -0
  24. package/dist/cli/commands/launch/add-root.js +64 -0
  25. package/dist/cli/commands/launch/boot-progress.d.ts +7 -0
  26. package/dist/cli/commands/launch/boot-progress.js +48 -0
  27. package/dist/cli/commands/launch/boot-wants.d.ts +11 -0
  28. package/dist/cli/commands/launch/boot-wants.js +48 -0
  29. package/dist/cli/commands/launch/first-start.d.ts +10 -0
  30. package/dist/cli/commands/launch/first-start.js +53 -0
  31. package/dist/cli/commands/launch/index.d.ts +6 -0
  32. package/dist/cli/commands/launch/index.js +6 -0
  33. package/dist/cli/commands/launch/launch.d.ts +8 -0
  34. package/dist/cli/commands/launch/launch.js +211 -0
  35. package/dist/cli/commands/launch/prepare.d.ts +23 -0
  36. package/dist/cli/commands/launch/prepare.js +109 -0
  37. package/dist/cli/commands/launch/running.d.ts +45 -0
  38. package/dist/cli/commands/launch/running.js +218 -0
  39. package/dist/cli/commands/launch/summary.d.ts +8 -0
  40. package/dist/cli/commands/launch/summary.js +98 -0
  41. package/dist/cli/commands/maintenance/audit.d.ts +3 -0
  42. package/dist/cli/commands/maintenance/audit.js +58 -0
  43. package/dist/cli/commands/maintenance/clean.d.ts +2 -0
  44. package/dist/cli/commands/maintenance/clean.js +10 -0
  45. package/dist/cli/commands/maintenance/config.d.ts +2 -0
  46. package/dist/cli/commands/maintenance/config.js +145 -0
  47. package/dist/cli/commands/maintenance/doctor.d.ts +2 -0
  48. package/dist/cli/commands/maintenance/doctor.js +52 -0
  49. package/dist/cli/commands/maintenance/host-claude.d.ts +2 -0
  50. package/dist/cli/commands/maintenance/host-claude.js +4 -0
  51. package/dist/cli/commands/maintenance/index.d.ts +8 -0
  52. package/dist/cli/commands/maintenance/index.js +9 -0
  53. package/dist/cli/commands/maintenance/logs.d.ts +2 -0
  54. package/dist/cli/commands/maintenance/logs.js +44 -0
  55. package/dist/cli/commands/maintenance/sync.d.ts +2 -0
  56. package/dist/cli/commands/maintenance/sync.js +12 -0
  57. package/dist/cli/commands/maintenance/watch.d.ts +3 -0
  58. package/dist/cli/commands/maintenance/watch.js +6 -0
  59. package/dist/cli/commands/projects/describe-sessions.d.ts +3 -0
  60. package/dist/cli/commands/projects/describe-sessions.js +15 -0
  61. package/dist/cli/commands/projects/here.d.ts +38 -0
  62. package/dist/cli/commands/projects/here.js +145 -0
  63. package/dist/cli/commands/projects/index.d.ts +4 -0
  64. package/dist/cli/commands/projects/index.js +4 -0
  65. package/dist/cli/commands/projects/projects.d.ts +14 -0
  66. package/dist/cli/commands/projects/projects.js +213 -0
  67. package/dist/cli/commands/projects/restart.d.ts +15 -0
  68. package/dist/cli/commands/projects/restart.js +149 -0
  69. package/dist/cli/commands/registry.d.ts +3 -0
  70. package/dist/cli/commands/registry.js +34 -0
  71. package/dist/cli/commands/repair/checks.js +105 -29
  72. package/dist/cli/commands/repair/finders.d.ts +13 -10
  73. package/dist/cli/commands/repair/finders.js +63 -43
  74. package/dist/cli/commands/repair/index.d.ts +4 -4
  75. package/dist/cli/commands/repair/index.js +47 -21
  76. package/dist/cli/commands/repair/types.d.ts +2 -2
  77. package/dist/cli/commands/repair/types.js +7 -2
  78. package/dist/cli/commands/sessions/attach.d.ts +2 -0
  79. package/dist/cli/commands/sessions/attach.js +45 -0
  80. package/dist/cli/commands/sessions/control.d.ts +4 -0
  81. package/dist/cli/commands/sessions/control.js +62 -0
  82. package/dist/cli/commands/sessions/exec.d.ts +6 -0
  83. package/dist/cli/commands/sessions/exec.js +72 -0
  84. package/dist/cli/commands/sessions/index.d.ts +6 -0
  85. package/dist/cli/commands/sessions/index.js +9 -0
  86. package/dist/cli/commands/sessions/list.d.ts +15 -0
  87. package/dist/cli/commands/sessions/list.js +65 -0
  88. package/dist/cli/commands/sessions/status.d.ts +2 -0
  89. package/dist/cli/commands/sessions/status.js +153 -0
  90. package/dist/cli/commands/sessions/window.d.ts +3 -0
  91. package/dist/cli/commands/sessions/window.js +18 -0
  92. package/dist/cli/commands/setup/checks.d.ts +4 -4
  93. package/dist/cli/commands/setup/checks.js +36 -19
  94. package/dist/cli/commands/setup/facts.d.ts +6 -6
  95. package/dist/cli/commands/setup/facts.js +23 -11
  96. package/dist/cli/commands/setup/index.d.ts +1 -1
  97. package/dist/cli/commands/setup/index.js +25 -12
  98. package/dist/cli/commands/user-config.d.ts +5 -5
  99. package/dist/cli/commands/user-config.js +14 -12
  100. package/dist/cli/history.d.ts +5 -4
  101. package/dist/cli/history.js +23 -11
  102. package/dist/cli/index.d.ts +4 -14
  103. package/dist/cli/index.js +27 -77
  104. package/dist/cli/manifest.d.ts +464 -10
  105. package/dist/cli/manifest.js +327 -53
  106. package/dist/cli/menu/apps.d.ts +7 -5
  107. package/dist/cli/menu/apps.js +64 -16
  108. package/dist/cli/menu/command-fields.d.ts +15 -0
  109. package/dist/cli/menu/command-fields.js +23 -0
  110. package/dist/cli/menu/command-form.d.ts +3 -5
  111. package/dist/cli/menu/command-form.js +116 -48
  112. package/dist/cli/menu/home.d.ts +22 -0
  113. package/dist/cli/menu/home.js +72 -0
  114. package/dist/cli/menu/index.d.ts +2 -24
  115. package/dist/cli/menu/index.js +4 -178
  116. package/dist/cli/menu/menu.d.ts +23 -0
  117. package/dist/cli/menu/menu.js +185 -0
  118. package/dist/cli/menu/settings/categories.d.ts +2 -2
  119. package/dist/cli/menu/settings/categories.js +123 -20
  120. package/dist/cli/menu/settings/collections/collection-editor.d.ts +23 -0
  121. package/dist/cli/menu/settings/collections/collection-editor.js +89 -0
  122. package/dist/cli/menu/settings/collections/map-editor.d.ts +10 -0
  123. package/dist/cli/menu/settings/collections/map-editor.js +34 -0
  124. package/dist/cli/menu/settings/collections/object-list-editor.d.ts +10 -0
  125. package/dist/cli/menu/settings/collections/object-list-editor.js +23 -0
  126. package/dist/cli/menu/settings/collections/object-map-editor.d.ts +10 -0
  127. package/dist/cli/menu/settings/collections/object-map-editor.js +35 -0
  128. package/dist/cli/menu/settings/collections/string-list-editor.d.ts +12 -0
  129. package/dist/cli/menu/settings/collections/string-list-editor.js +39 -0
  130. package/dist/cli/menu/settings/config-file.d.ts +2 -2
  131. package/dist/cli/menu/settings/config-file.js +42 -19
  132. package/dist/cli/menu/settings/editor-actions.d.ts +2 -0
  133. package/dist/cli/menu/settings/editor-actions.js +2 -0
  134. package/dist/cli/menu/settings/format.d.ts +5 -0
  135. package/dist/cli/menu/settings/format.js +39 -0
  136. package/dist/cli/menu/settings/index.d.ts +1 -29
  137. package/dist/cli/menu/settings/index.js +1 -133
  138. package/dist/cli/menu/settings/object-editor.d.ts +12 -0
  139. package/dist/cli/menu/settings/object-editor.js +86 -0
  140. package/dist/cli/menu/settings/schema-node.d.ts +3 -1
  141. package/dist/cli/menu/settings/schema-node.js +71 -24
  142. package/dist/cli/menu/settings/settings-editor.d.ts +30 -0
  143. package/dist/cli/menu/settings/settings-editor.js +176 -0
  144. package/dist/cli/menu/settings/{editors.d.ts → value-editor.d.ts} +2 -13
  145. package/dist/cli/menu/settings/value-editor.js +137 -0
  146. package/dist/cli/menu/several.d.ts +4 -4
  147. package/dist/cli/menu/several.js +61 -20
  148. package/dist/cli/{colors.d.ts → output/colors.d.ts} +8 -8
  149. package/dist/cli/{colors.js → output/colors.js} +32 -14
  150. package/dist/cli/output/index.d.ts +3 -0
  151. package/dist/cli/output/index.js +3 -0
  152. package/dist/cli/output/print.d.ts +5 -0
  153. package/dist/cli/output/print.js +14 -0
  154. package/dist/cli/{progress.d.ts → output/progress.d.ts} +5 -5
  155. package/dist/cli/{progress.js → output/progress.js} +42 -19
  156. package/dist/cli/report.d.ts +2 -0
  157. package/dist/cli/report.js +20 -0
  158. package/dist/cli/tui/app.d.ts +6 -16
  159. package/dist/cli/tui/app.js +28 -8
  160. package/dist/cli/tui/dialogs/confirm-screen.d.ts +20 -0
  161. package/dist/cli/tui/dialogs/confirm-screen.js +50 -0
  162. package/dist/cli/tui/dialogs/message-screen.d.ts +17 -0
  163. package/dist/cli/tui/dialogs/message-screen.js +55 -0
  164. package/dist/cli/tui/dialogs/paragraphs.d.ts +2 -0
  165. package/dist/cli/tui/dialogs/paragraphs.js +5 -0
  166. package/dist/cli/tui/dialogs/text-screen.d.ts +26 -0
  167. package/dist/cli/tui/dialogs/text-screen.js +107 -0
  168. package/dist/cli/tui/frame.js +3 -1
  169. package/dist/cli/tui/index.d.ts +7 -3
  170. package/dist/cli/tui/index.js +4 -2
  171. package/dist/cli/tui/list/list-screen.d.ts +29 -0
  172. package/dist/cli/tui/{list-screen.js → list/list-screen.js} +86 -23
  173. package/dist/cli/tui/{list-screen.d.ts → list/list-types.d.ts} +0 -28
  174. package/dist/cli/tui/screen.d.ts +14 -0
  175. package/dist/cli/tui/terminal.js +34 -10
  176. package/dist/cli/tui/text.d.ts +2 -1
  177. package/dist/cli/tui/text.js +37 -7
  178. package/dist/cli/tui/theme.js +27 -9
  179. package/dist/cli/validate.d.ts +8 -8
  180. package/dist/cli/validate.js +32 -21
  181. package/dist/core/config/defaults.d.ts +2 -0
  182. package/dist/core/config/defaults.js +203 -0
  183. package/dist/core/config/index.d.ts +2 -0
  184. package/dist/core/config/index.js +3 -0
  185. package/dist/core/{config.d.ts → config/loader.d.ts} +1 -2
  186. package/dist/core/config/loader.js +47 -0
  187. package/dist/core/{detect-databases.js → detect/databases.js} +111 -23
  188. package/dist/core/detect/index.d.ts +4 -0
  189. package/dist/core/detect/index.js +4 -0
  190. package/dist/core/{detect-pwsh.d.ts → detect/pwsh.d.ts} +1 -1
  191. package/dist/core/{detect-pwsh.js → detect/pwsh.js} +25 -11
  192. package/dist/core/{detect-toolchains.d.ts → detect/toolchains.d.ts} +1 -1
  193. package/dist/core/{detect-toolchains.js → detect/toolchains.js} +42 -5
  194. package/dist/{guest/toolchains → core/detect}/versions.js +28 -12
  195. package/dist/core/disk.d.ts +2 -0
  196. package/dist/core/disk.js +46 -3
  197. package/dist/core/local-config/boot-wants.d.ts +45 -0
  198. package/dist/core/local-config/boot-wants.js +120 -0
  199. package/dist/core/local-config/file.d.ts +3 -0
  200. package/dist/core/local-config/file.js +16 -0
  201. package/dist/core/local-config/index.d.ts +5 -0
  202. package/dist/core/local-config/index.js +7 -0
  203. package/dist/core/{local-config.d.ts → local-config/overrides.d.ts} +3 -18
  204. package/dist/core/{local-config.js → local-config/overrides.js} +45 -52
  205. package/dist/core/local-config/policy.d.ts +19 -0
  206. package/dist/core/local-config/policy.js +45 -0
  207. package/dist/core/local-config/trust.d.ts +13 -0
  208. package/dist/core/local-config/trust.js +43 -0
  209. package/dist/core/package-info.d.ts +4 -0
  210. package/dist/core/package-info.js +13 -0
  211. package/dist/core/run/guest-workspace.d.ts +23 -0
  212. package/dist/core/run/guest-workspace.js +47 -0
  213. package/dist/core/run/index.d.ts +3 -0
  214. package/dist/core/run/index.js +3 -0
  215. package/dist/core/run/resolve-run.d.ts +3 -0
  216. package/dist/core/run/resolve-run.js +202 -0
  217. package/dist/core/run/versions.d.ts +13 -0
  218. package/dist/core/run/versions.js +65 -0
  219. package/dist/core/safe-paths.js +17 -5
  220. package/dist/core/schema/apps.d.ts +4 -4
  221. package/dist/core/schema/apps.js +55 -21
  222. package/dist/core/schema/common.d.ts +13 -10
  223. package/dist/core/schema/common.js +16 -10
  224. package/dist/core/schema/config.d.ts +15 -10
  225. package/dist/core/schema/config.js +78 -53
  226. package/dist/core/schema/databases.d.ts +4 -3
  227. package/dist/core/schema/databases.js +16 -12
  228. package/dist/core/schema/harness.d.ts +1 -1
  229. package/dist/core/schema/harness.js +17 -7
  230. package/dist/core/schema/index.d.ts +6 -0
  231. package/dist/core/schema/index.js +8 -0
  232. package/dist/core/schema/json-schema.js +10 -5
  233. package/dist/core/schema/profile.d.ts +4 -4
  234. package/dist/core/schema/profile.js +37 -17
  235. package/dist/core/schema/projects.d.ts +1 -1
  236. package/dist/core/schema/projects.js +16 -6
  237. package/dist/core/schema/sandbox.d.ts +11 -11
  238. package/dist/core/schema/sandbox.js +101 -37
  239. package/dist/core/schema/toolchains.d.ts +6 -1
  240. package/dist/core/schema/toolchains.js +84 -34
  241. package/dist/core/types.d.ts +19 -9
  242. package/dist/core/util/errors.d.ts +8 -0
  243. package/dist/core/util/errors.js +14 -0
  244. package/dist/core/util/fs.d.ts +8 -0
  245. package/dist/core/util/fs.js +40 -0
  246. package/dist/core/util/index.d.ts +7 -0
  247. package/dist/core/util/index.js +7 -0
  248. package/dist/core/util/jsonc.d.ts +6 -0
  249. package/dist/core/util/jsonc.js +25 -0
  250. package/dist/core/util/links.d.ts +10 -0
  251. package/dist/core/util/links.js +39 -0
  252. package/dist/core/util/paths.d.ts +7 -0
  253. package/dist/core/util/paths.js +33 -0
  254. package/dist/core/util/process.d.ts +15 -0
  255. package/dist/core/util/process.js +54 -0
  256. package/dist/core/util/text.d.ts +8 -0
  257. package/dist/core/util/text.js +8 -0
  258. package/dist/guest/{setup/agents.js → agents/agent-installer.js} +24 -4
  259. package/dist/guest/apps/after-install.d.ts +3 -0
  260. package/dist/guest/apps/after-install.js +47 -0
  261. package/dist/guest/apps/app-installer.d.ts +22 -0
  262. package/dist/guest/apps/app-installer.js +116 -0
  263. package/dist/guest/apps/find-exe.d.ts +5 -0
  264. package/dist/guest/apps/find-exe.js +41 -0
  265. package/dist/guest/apps/index.d.ts +3 -10
  266. package/dist/guest/apps/index.js +6 -206
  267. package/dist/guest/apps/resolvers.js +37 -9
  268. package/dist/guest/apps/shortcuts.d.ts +6 -0
  269. package/dist/guest/apps/shortcuts.js +28 -0
  270. package/dist/guest/apps/sources.d.ts +4 -0
  271. package/dist/guest/apps/sources.js +17 -0
  272. package/dist/guest/apps/unpack.d.ts +3 -0
  273. package/dist/guest/apps/unpack.js +47 -0
  274. package/dist/guest/{audit-parse.js → audit/parse.js} +39 -3
  275. package/dist/guest/{audit.d.ts → audit/process-audit.d.ts} +3 -1
  276. package/dist/guest/{audit.js → audit/process-audit.js} +33 -8
  277. package/dist/guest/boot/boot-env.d.ts +4 -0
  278. package/dist/guest/{boot-env.js → boot/boot-env.js} +7 -5
  279. package/dist/guest/boot/boot.d.ts +1 -0
  280. package/dist/guest/{main.js → boot/boot.js} +96 -50
  281. package/dist/guest/{guide.js → boot/guide.js} +32 -7
  282. package/dist/guest/{project-env.d.ts → boot/project-env.d.ts} +3 -3
  283. package/dist/guest/{project-env.js → boot/project-env.js} +12 -4
  284. package/dist/guest/boot/project-status.d.ts +5 -0
  285. package/dist/guest/boot/project-status.js +28 -0
  286. package/dist/guest/daemon/daemon.d.ts +1 -0
  287. package/dist/guest/daemon/daemon.js +51 -0
  288. package/dist/guest/daemon/exec.js +18 -6
  289. package/dist/guest/daemon/{shutdown.js → idle-shutdown.js} +5 -4
  290. package/dist/guest/daemon/{project.d.ts → project-provisioner.d.ts} +3 -3
  291. package/dist/guest/daemon/{project.js → project-provisioner.js} +60 -22
  292. package/dist/guest/daemon/relays.js +5 -3
  293. package/dist/guest/daemon/{session.js → sessions.js} +84 -24
  294. package/dist/guest/daemon/state.d.ts +4 -1
  295. package/dist/guest/daemon/state.js +34 -20
  296. package/dist/guest/databases/database-server.d.ts +13 -0
  297. package/dist/guest/databases/database-server.js +35 -0
  298. package/dist/guest/databases/dynamodb.d.ts +12 -0
  299. package/dist/guest/databases/dynamodb.js +81 -0
  300. package/dist/guest/databases/index.d.ts +2 -0
  301. package/dist/guest/databases/index.js +2 -0
  302. package/dist/guest/databases/mongodb.d.ts +7 -0
  303. package/dist/guest/databases/mongodb.js +46 -0
  304. package/dist/guest/databases/mysql.d.ts +7 -0
  305. package/dist/guest/databases/mysql.js +59 -0
  306. package/dist/guest/databases/names.d.ts +5 -0
  307. package/dist/guest/databases/names.js +8 -0
  308. package/dist/guest/databases/postgres.d.ts +9 -0
  309. package/dist/guest/databases/postgres.js +85 -0
  310. package/dist/guest/databases/redis.d.ts +7 -0
  311. package/dist/guest/databases/redis.js +25 -0
  312. package/dist/guest/databases/registry.d.ts +5 -0
  313. package/dist/guest/databases/registry.js +51 -0
  314. package/dist/guest/databases/sbx-db.d.ts +1 -0
  315. package/dist/guest/{db.js → databases/sbx-db.js} +13 -13
  316. package/dist/guest/{toolchains/databases → databases}/server.d.ts +5 -5
  317. package/dist/guest/{toolchains/databases → databases}/server.js +18 -13
  318. package/dist/guest/entries/daemon.js +16 -0
  319. package/dist/guest/entries/db.js +10 -0
  320. package/dist/guest/entries/gitguard.js +20 -0
  321. package/dist/guest/entries/main.d.ts +1 -0
  322. package/dist/guest/entries/main.js +24 -0
  323. package/dist/guest/entries/netproxy.d.ts +1 -0
  324. package/dist/guest/entries/netproxy.js +7 -0
  325. package/dist/guest/entries/view.d.ts +1 -0
  326. package/dist/guest/entries/view.js +11 -0
  327. package/dist/guest/{gitguard.js → git/decision.js} +49 -26
  328. package/dist/guest/network/addresses.d.ts +2 -0
  329. package/dist/guest/network/addresses.js +6 -0
  330. package/dist/guest/{setup/network.d.ts → network/allow-only.d.ts} +0 -10
  331. package/dist/guest/network/allow-only.js +84 -0
  332. package/dist/guest/network/firewall.d.ts +9 -0
  333. package/dist/guest/{setup/network.js → network/firewall.js} +58 -63
  334. package/dist/guest/network/proxy-server.d.ts +2 -0
  335. package/dist/guest/{netproxy.js → network/proxy-server.js} +37 -18
  336. package/dist/guest/{helpers.d.ts → runtime/csc.d.ts} +1 -1
  337. package/dist/guest/{helpers.js → runtime/csc.js} +7 -2
  338. package/dist/guest/runtime/fs.d.ts +2 -0
  339. package/dist/guest/runtime/fs.js +6 -0
  340. package/dist/guest/runtime/log.d.ts +3 -0
  341. package/dist/guest/runtime/log.js +22 -0
  342. package/dist/guest/runtime/paths.d.ts +13 -0
  343. package/dist/guest/runtime/paths.js +14 -0
  344. package/dist/guest/{ports.js → runtime/ports.js} +8 -2
  345. package/dist/guest/runtime/process.d.ts +15 -0
  346. package/dist/guest/runtime/process.js +59 -0
  347. package/dist/guest/{project-context.js → runtime/project-context.js} +1 -1
  348. package/dist/guest/runtime/session.d.ts +5 -0
  349. package/dist/guest/runtime/session.js +10 -0
  350. package/dist/guest/runtime/status.d.ts +7 -0
  351. package/dist/guest/runtime/status.js +57 -0
  352. package/dist/guest/{cmdline.js → sessions/cmdline.js} +10 -4
  353. package/dist/guest/{ptyhost.js → sessions/pty-host.js} +12 -5
  354. package/dist/guest/{view.js → sessions/viewer.js} +8 -11
  355. package/dist/guest/setup/claude-mem.d.ts +10 -0
  356. package/dist/guest/setup/{claude.js → claude-mem.js} +18 -78
  357. package/dist/guest/setup/{claude.d.ts → claude-profile.d.ts} +0 -10
  358. package/dist/guest/setup/claude-profile.js +89 -0
  359. package/dist/guest/setup/desktop.d.ts +2 -0
  360. package/dist/guest/setup/desktop.js +32 -0
  361. package/dist/guest/setup/environment.js +28 -5
  362. package/dist/guest/setup/{user.d.ts → git-identity.d.ts} +0 -2
  363. package/dist/guest/setup/git-identity.js +34 -0
  364. package/dist/guest/{gitrules.d.ts → setup/git-rules.d.ts} +1 -1
  365. package/dist/guest/setup/git-rules.js +50 -0
  366. package/dist/guest/setup/hooks.js +22 -5
  367. package/dist/guest/setup/{policy.js → managed-policy.js} +2 -2
  368. package/dist/guest/toolchains/catalogue.d.ts +4 -4
  369. package/dist/guest/toolchains/catalogue.js +30 -7
  370. package/dist/guest/toolchains/detect.d.ts +12 -0
  371. package/dist/guest/toolchains/detect.js +54 -0
  372. package/dist/guest/toolchains/index.d.ts +3 -17
  373. package/dist/guest/toolchains/index.js +1 -106
  374. package/dist/guest/toolchains/install.d.ts +20 -0
  375. package/dist/guest/toolchains/install.js +29 -0
  376. package/dist/guest/toolchains/languages/go.d.ts +3 -0
  377. package/dist/guest/toolchains/{go.js → languages/go.js} +27 -9
  378. package/dist/guest/toolchains/languages/java.d.ts +8 -0
  379. package/dist/guest/toolchains/{java.js → languages/java.js} +57 -18
  380. package/dist/guest/toolchains/languages/node.d.ts +3 -0
  381. package/dist/guest/toolchains/{node.js → languages/node.js} +51 -18
  382. package/dist/guest/toolchains/languages/php.d.ts +3 -0
  383. package/dist/guest/toolchains/{scripting → languages}/php.js +36 -11
  384. package/dist/guest/toolchains/languages/python-tools.d.ts +3 -0
  385. package/dist/guest/toolchains/languages/python-tools.js +12 -0
  386. package/dist/guest/toolchains/languages/python.d.ts +3 -0
  387. package/dist/guest/toolchains/{python.js → languages/python.js} +29 -16
  388. package/dist/guest/toolchains/languages/ruby.d.ts +3 -0
  389. package/dist/guest/toolchains/{scripting → languages}/ruby.js +28 -10
  390. package/dist/guest/toolchains/leftovers.d.ts +1 -1
  391. package/dist/guest/toolchains/leftovers.js +13 -11
  392. package/dist/guest/toolchains/managers.d.ts +6 -6
  393. package/dist/guest/toolchains/managers.js +38 -17
  394. package/dist/guest/toolchains/native/binstall.d.ts +3 -2
  395. package/dist/guest/toolchains/native/binstall.js +20 -8
  396. package/dist/guest/toolchains/native/cpp.d.ts +2 -2
  397. package/dist/guest/toolchains/native/cpp.js +23 -8
  398. package/dist/guest/toolchains/native/dotnet.d.ts +5 -3
  399. package/dist/guest/toolchains/native/dotnet.js +72 -24
  400. package/dist/guest/toolchains/native/mesa.d.ts +2 -2
  401. package/dist/guest/toolchains/native/mesa.js +27 -10
  402. package/dist/guest/toolchains/native/msvc/environment.d.ts +4 -4
  403. package/dist/guest/toolchains/native/msvc/environment.js +30 -16
  404. package/dist/guest/toolchains/native/msvc/index.d.ts +3 -3
  405. package/dist/guest/toolchains/native/msvc/index.js +10 -8
  406. package/dist/guest/toolchains/native/msvc/packages.d.ts +1 -1
  407. package/dist/guest/toolchains/native/msvc/packages.js +69 -23
  408. package/dist/guest/toolchains/native/msvc/tree.d.ts +6 -6
  409. package/dist/guest/toolchains/native/msvc/tree.js +15 -9
  410. package/dist/guest/toolchains/native/rust-extras.d.ts +23 -0
  411. package/dist/guest/toolchains/native/rust-extras.js +100 -0
  412. package/dist/guest/toolchains/native/rust.d.ts +2 -2
  413. package/dist/guest/toolchains/native/rust.js +41 -10
  414. package/dist/guest/toolchains/{scripting → native}/vcruntime.d.ts +2 -2
  415. package/dist/guest/toolchains/{scripting → native}/vcruntime.js +17 -7
  416. package/dist/guest/toolchains/package-ledger.d.ts +17 -0
  417. package/dist/guest/toolchains/package-ledger.js +54 -0
  418. package/dist/guest/toolchains/plan.d.ts +3 -24
  419. package/dist/guest/toolchains/plan.js +99 -111
  420. package/dist/guest/toolchains/runtimes.d.ts +6 -6
  421. package/dist/guest/toolchains/runtimes.js +31 -13
  422. package/dist/guest/toolchains/scheduler.d.ts +22 -0
  423. package/dist/guest/toolchains/scheduler.js +123 -0
  424. package/dist/guest/toolchains/setup.d.ts +10 -0
  425. package/dist/guest/toolchains/setup.js +22 -0
  426. package/dist/guest/toolchains/state-file.d.ts +3 -0
  427. package/dist/guest/toolchains/state-file.js +10 -0
  428. package/dist/guest/toolchains/step.d.ts +24 -0
  429. package/dist/guest/toolchains/step.js +1 -0
  430. package/dist/guest/toolchains/tool-env.d.ts +12 -0
  431. package/dist/guest/toolchains/tool-env.js +16 -0
  432. package/dist/guest/toolchains/tools/cli.d.ts +10 -0
  433. package/dist/guest/toolchains/{cli.js → tools/cli.js} +35 -15
  434. package/dist/guest/toolchains/tools/git.d.ts +3 -0
  435. package/dist/guest/toolchains/{git.js → tools/git.js} +38 -15
  436. package/dist/guest/toolchains/tools/pwsh.d.ts +4 -0
  437. package/dist/guest/toolchains/{pwsh.js → tools/pwsh.js} +14 -7
  438. package/dist/guest/toolchains/{vscode-profile.d.ts → tools/vscode-profile.d.ts} +6 -6
  439. package/dist/guest/toolchains/{vscode-profile.js → tools/vscode-profile.js} +28 -12
  440. package/dist/guest/toolchains/{vscode.d.ts → tools/vscode.d.ts} +6 -6
  441. package/dist/guest/toolchains/{vscode.js → tools/vscode.js} +67 -21
  442. package/dist/guest/toolchains/version-cache.d.ts +16 -0
  443. package/dist/guest/toolchains/version-cache.js +67 -0
  444. package/dist/host/agent-commands/commands.d.ts +13 -0
  445. package/dist/host/agent-commands/commands.js +33 -0
  446. package/dist/host/agent-commands/forwarders.d.ts +7 -0
  447. package/dist/host/agent-commands/forwarders.js +31 -0
  448. package/dist/host/agent-commands/index.d.ts +4 -0
  449. package/dist/host/agent-commands/index.js +4 -0
  450. package/dist/host/agent-commands/reconcile.d.ts +12 -0
  451. package/dist/host/agent-commands/reconcile.js +69 -0
  452. package/dist/host/agent-commands/user-path.d.ts +2 -0
  453. package/dist/host/agent-commands/user-path.js +33 -0
  454. package/dist/host/audit/collect.d.ts +2 -2
  455. package/dist/host/audit/collect.js +59 -22
  456. package/dist/host/audit/log.d.ts +2 -2
  457. package/dist/host/audit/log.js +24 -8
  458. package/dist/host/{attach.d.ts → channel/attach.d.ts} +2 -2
  459. package/dist/host/{attach.js → channel/attach.js} +33 -15
  460. package/dist/host/channel/channel.d.ts +51 -0
  461. package/dist/host/channel/channel.js +196 -0
  462. package/dist/host/channel/index.d.ts +2 -0
  463. package/dist/host/channel/index.js +2 -0
  464. package/dist/host/guard/agent-files.d.ts +7 -0
  465. package/dist/host/guard/agent-files.js +103 -0
  466. package/dist/host/guard/commands.d.ts +10 -0
  467. package/dist/host/guard/commands.js +123 -0
  468. package/dist/host/guard/file-hash.d.ts +4 -0
  469. package/dist/host/guard/file-hash.js +37 -0
  470. package/dist/host/guard/git-config.d.ts +5 -0
  471. package/dist/host/guard/git-config.js +62 -0
  472. package/dist/host/guard/git-dirs.d.ts +12 -0
  473. package/dist/host/guard/git-dirs.js +53 -0
  474. package/dist/host/guard/index.d.ts +5 -0
  475. package/dist/host/guard/index.js +4 -0
  476. package/dist/host/guard/mark-of-the-web.d.ts +8 -0
  477. package/dist/host/guard/mark-of-the-web.js +74 -0
  478. package/dist/host/guard/nested-repos.d.ts +14 -0
  479. package/dist/host/guard/nested-repos.js +88 -0
  480. package/dist/host/guard/quarantine.d.ts +3 -0
  481. package/dist/host/guard/quarantine.js +24 -0
  482. package/dist/host/guard/repo-guard.d.ts +10 -0
  483. package/dist/host/guard/repo-guard.js +36 -0
  484. package/dist/host/guard/store.d.ts +40 -0
  485. package/dist/host/guard/store.js +145 -0
  486. package/dist/host/guard/types.d.ts +27 -0
  487. package/dist/host/guard/types.js +3 -0
  488. package/dist/host/guard/watch-state.d.ts +9 -0
  489. package/dist/host/guard/watch-state.js +26 -0
  490. package/dist/host/launch/boot-projects.d.ts +17 -0
  491. package/dist/host/launch/{projects.js → boot-projects.js} +22 -13
  492. package/dist/host/{database-plan.d.ts → launch/database-plan.d.ts} +5 -5
  493. package/dist/host/{database-plan.js → launch/database-plan.js} +24 -13
  494. package/dist/host/launch/generate.d.ts +4 -0
  495. package/dist/host/launch/generate.js +77 -0
  496. package/dist/host/launch/index.d.ts +10 -0
  497. package/dist/host/launch/index.js +10 -0
  498. package/dist/host/launch/mappings.d.ts +5 -5
  499. package/dist/host/launch/mappings.js +37 -24
  500. package/dist/host/launch/pc-scan.d.ts +5 -0
  501. package/dist/host/{pc-scan.js → launch/pc-scan.js} +20 -13
  502. package/dist/host/launch/project-scan.d.ts +7 -0
  503. package/dist/host/{project-scan.js → launch/project-scan.js} +29 -21
  504. package/dist/host/launch/session-file.d.ts +23 -0
  505. package/dist/host/launch/session-file.js +73 -0
  506. package/dist/host/launch/stage.d.ts +5 -5
  507. package/dist/host/launch/stage.js +14 -13
  508. package/dist/host/launch/toolchains.d.ts +4 -0
  509. package/dist/host/launch/toolchains.js +11 -0
  510. package/dist/host/launch/{wsb.d.ts → wsb-file.d.ts} +4 -2
  511. package/dist/host/launch/wsb-file.js +56 -0
  512. package/dist/host/life/crash-report.d.ts +8 -0
  513. package/dist/host/life/crash-report.js +87 -0
  514. package/dist/host/life/index.d.ts +6 -0
  515. package/dist/host/life/index.js +6 -0
  516. package/dist/host/life/keep-awake.d.ts +10 -0
  517. package/dist/host/life/keep-awake.js +29 -0
  518. package/dist/host/life/life-record.d.ts +48 -0
  519. package/dist/host/life/life-record.js +76 -0
  520. package/dist/host/life/stop-events.d.ts +27 -0
  521. package/dist/host/life/stop-events.js +96 -0
  522. package/dist/host/life/stop-warning.d.ts +4 -0
  523. package/dist/host/life/stop-warning.js +25 -0
  524. package/dist/host/life/windows-update.d.ts +3 -0
  525. package/dist/host/life/windows-update.js +11 -0
  526. package/dist/host/native.d.ts +4 -0
  527. package/dist/host/native.js +11 -0
  528. package/dist/host/network/index.d.ts +1 -0
  529. package/dist/host/network/index.js +1 -0
  530. package/dist/host/{port-forward.d.ts → network/port-forward.d.ts} +1 -1
  531. package/dist/host/{port-forward.js → network/port-forward.js} +16 -10
  532. package/dist/host/profile/accounts.d.ts +37 -0
  533. package/dist/host/profile/accounts.js +146 -0
  534. package/dist/host/profile/claude-login.d.ts +22 -0
  535. package/dist/host/profile/claude-login.js +57 -0
  536. package/dist/host/{claude-profile.d.ts → profile/claude-profile.d.ts} +9 -9
  537. package/dist/host/{claude-profile.js → profile/claude-profile.js} +32 -22
  538. package/dist/host/profile/index.d.ts +7 -0
  539. package/dist/host/profile/index.js +7 -0
  540. package/dist/host/profile/personalize.d.ts +2 -0
  541. package/dist/host/profile/personalize.js +127 -0
  542. package/dist/host/profile/reg-file.d.ts +8 -0
  543. package/dist/host/profile/reg-file.js +45 -0
  544. package/dist/host/profile/secret-files.d.ts +2 -0
  545. package/dist/host/profile/secret-files.js +25 -0
  546. package/dist/host/profile/secret-patterns.d.ts +6 -0
  547. package/dist/host/profile/secret-patterns.js +128 -0
  548. package/dist/host/profile/secrets.d.ts +12 -0
  549. package/dist/host/profile/secrets.js +100 -0
  550. package/dist/host/projects/index.d.ts +4 -0
  551. package/dist/host/projects/index.js +4 -0
  552. package/dist/host/{join.d.ts → projects/join.d.ts} +12 -9
  553. package/dist/host/{join.js → projects/join.js} +62 -33
  554. package/dist/host/projects/known.d.ts +28 -0
  555. package/dist/host/projects/known.js +55 -0
  556. package/dist/host/projects/mapper.d.ts +29 -0
  557. package/dist/host/projects/mapper.js +88 -0
  558. package/dist/host/projects/registry.d.ts +83 -0
  559. package/dist/host/projects/registry.js +136 -0
  560. package/dist/host/sandbox/doctor.d.ts +2 -0
  561. package/dist/host/sandbox/doctor.js +42 -0
  562. package/dist/host/sandbox/host-claude.d.ts +1 -0
  563. package/dist/host/sandbox/host-claude.js +26 -0
  564. package/dist/host/sandbox/index.d.ts +6 -0
  565. package/dist/host/sandbox/index.js +6 -0
  566. package/dist/host/{platform.d.ts → sandbox/platform.d.ts} +0 -5
  567. package/dist/host/sandbox/platform.js +60 -0
  568. package/dist/host/sandbox/probe.d.ts +3 -0
  569. package/dist/host/sandbox/probe.js +47 -0
  570. package/dist/host/{window.js → sandbox/window.js} +7 -5
  571. package/dist/host/{wsb.js → sandbox/wsb-cli.js} +31 -8
  572. package/dist/host/{cleanup.js → storage/cleanup.js} +27 -12
  573. package/dist/host/storage/index.d.ts +2 -0
  574. package/dist/host/storage/index.js +2 -0
  575. package/dist/host/storage/state-files.d.ts +4 -0
  576. package/dist/host/storage/state-files.js +10 -0
  577. package/dist/host/test-guard.js +1 -1
  578. package/dist/host/tools/conpty.d.ts +8 -0
  579. package/dist/host/tools/conpty.js +58 -0
  580. package/dist/host/tools/index.d.ts +2 -0
  581. package/dist/host/tools/index.js +2 -0
  582. package/dist/host/{terminal.d.ts → tools/windows-terminal.d.ts} +2 -10
  583. package/dist/host/{terminal.js → tools/windows-terminal.js} +33 -57
  584. package/dist/host/workspace-view/active-views.d.ts +3 -0
  585. package/dist/host/workspace-view/active-views.js +22 -0
  586. package/dist/host/workspace-view/index.d.ts +2 -18
  587. package/dist/host/workspace-view/index.js +2 -49
  588. package/dist/host/workspace-view/plan.d.ts +16 -0
  589. package/dist/host/workspace-view/plan.js +50 -0
  590. package/dist/host/workspace-view/rules.js +10 -3
  591. package/dist/host/workspace-view/view-state.d.ts +10 -0
  592. package/dist/host/workspace-view/view-state.js +31 -0
  593. package/dist/host/workspace-view/view.d.ts +1 -0
  594. package/dist/host/workspace-view/view.js +51 -55
  595. package/dist/runtime/daemon.js +4220 -1968
  596. package/dist/runtime/db.js +2134 -849
  597. package/dist/runtime/gitguard.js +29 -11
  598. package/dist/runtime/main.js +4687 -2243
  599. package/dist/runtime/netproxy.js +1644 -420
  600. package/dist/runtime/view.js +1356 -428
  601. package/dist/selftest/accounts.test.d.ts +1 -1
  602. package/dist/selftest/accounts.test.js +20 -17
  603. package/dist/selftest/agent-commands.test.d.ts +1 -1
  604. package/dist/selftest/agent-commands.test.js +9 -5
  605. package/dist/selftest/audit.test.d.ts +1 -1
  606. package/dist/selftest/audit.test.js +46 -13
  607. package/dist/selftest/channel.test.d.ts +1 -1
  608. package/dist/selftest/channel.test.js +63 -16
  609. package/dist/selftest/cli.test.d.ts +1 -1
  610. package/dist/selftest/cli.test.js +68 -16
  611. package/dist/selftest/cmdline.test.d.ts +1 -1
  612. package/dist/selftest/cmdline.test.js +36 -7
  613. package/dist/selftest/config.test.d.ts +1 -1
  614. package/dist/selftest/config.test.js +12 -5
  615. package/dist/selftest/data.test.d.ts +1 -1
  616. package/dist/selftest/data.test.js +35 -6
  617. package/dist/selftest/detect.test.d.ts +1 -1
  618. package/dist/selftest/detect.test.js +22 -9
  619. package/dist/selftest/generate.test.d.ts +1 -1
  620. package/dist/selftest/generate.test.js +33 -9
  621. package/dist/selftest/git-access.test.d.ts +1 -1
  622. package/dist/selftest/git-access.test.js +42 -4
  623. package/dist/selftest/guest-boot.test.d.ts +1 -1
  624. package/dist/selftest/guest-boot.test.js +25 -7
  625. package/dist/selftest/host-sim.test.d.ts +1 -1
  626. package/dist/selftest/host-sim.test.js +27 -3
  627. package/dist/selftest/hostile-input.test.d.ts +1 -1
  628. package/dist/selftest/hostile-input.test.js +5 -5
  629. package/dist/selftest/index.d.ts +1 -1
  630. package/dist/selftest/index.js +72 -16
  631. package/dist/selftest/layout.test.d.ts +2 -0
  632. package/dist/selftest/layout.test.js +131 -0
  633. package/dist/selftest/links.test.d.ts +1 -1
  634. package/dist/selftest/links.test.js +16 -11
  635. package/dist/selftest/live-daemon.test.d.ts +1 -1
  636. package/dist/selftest/live-daemon.test.js +20 -8
  637. package/dist/selftest/live-git.test.d.ts +1 -1
  638. package/dist/selftest/live-git.test.js +13 -4
  639. package/dist/selftest/live-network.test.d.ts +1 -1
  640. package/dist/selftest/live-network.test.js +24 -9
  641. package/dist/selftest/live-projects.test.d.ts +1 -1
  642. package/dist/selftest/live-projects.test.js +47 -20
  643. package/dist/selftest/live-terminal.test.d.ts +1 -1
  644. package/dist/selftest/live-terminal.test.js +41 -15
  645. package/dist/selftest/local-config.test.d.ts +1 -1
  646. package/dist/selftest/local-config.test.js +64 -16
  647. package/dist/selftest/mirror.test.d.ts +1 -1
  648. package/dist/selftest/mirror.test.js +102 -32
  649. package/dist/selftest/network.test.d.ts +1 -1
  650. package/dist/selftest/network.test.js +17 -8
  651. package/dist/selftest/personalization.test.d.ts +1 -1
  652. package/dist/selftest/personalization.test.js +12 -5
  653. package/dist/selftest/projects.test.d.ts +1 -1
  654. package/dist/selftest/projects.test.js +280 -85
  655. package/dist/selftest/repair.test.d.ts +1 -1
  656. package/dist/selftest/repair.test.js +17 -5
  657. package/dist/selftest/repo-guard.test.d.ts +1 -1
  658. package/dist/selftest/repo-guard.test.js +21 -20
  659. package/dist/selftest/secrets.test.d.ts +1 -1
  660. package/dist/selftest/secrets.test.js +57 -13
  661. package/dist/selftest/setup.test.d.ts +1 -1
  662. package/dist/selftest/setup.test.js +25 -5
  663. package/dist/selftest/{fixtures.d.ts → support/fixtures.d.ts} +5 -3
  664. package/dist/selftest/{fixtures.js → support/fixtures.js} +95 -17
  665. package/dist/selftest/{harness.js → support/harness.js} +24 -7
  666. package/dist/selftest/{live.d.ts → support/live.d.ts} +2 -2
  667. package/dist/selftest/{live.js → support/live.js} +34 -10
  668. package/dist/selftest/support/suite.js +1 -0
  669. package/dist/selftest/sync.test.d.ts +1 -1
  670. package/dist/selftest/sync.test.js +64 -26
  671. package/dist/selftest/test-guard.test.d.ts +1 -1
  672. package/dist/selftest/test-guard.test.js +43 -15
  673. package/dist/selftest/toolchains.test.d.ts +1 -1
  674. package/dist/selftest/toolchains.test.js +135 -36
  675. package/dist/selftest/workspace-view.test.d.ts +1 -1
  676. package/dist/selftest/workspace-view.test.js +48 -11
  677. package/dist/selftest/workspace.test.d.ts +1 -1
  678. package/dist/selftest/workspace.test.js +13 -4
  679. package/dist/shared/{apps.d.ts → apps/catalogue.d.ts} +1 -11
  680. package/dist/shared/apps/catalogue.js +768 -0
  681. package/dist/shared/apps/index.d.ts +2 -0
  682. package/dist/shared/apps/index.js +2 -0
  683. package/dist/shared/apps/selection.d.ts +11 -0
  684. package/dist/shared/apps/selection.js +40 -0
  685. package/dist/shared/channel/index.d.ts +2 -0
  686. package/dist/shared/channel/index.js +2 -0
  687. package/dist/shared/channel/run-dir.d.ts +30 -0
  688. package/dist/shared/channel/run-dir.js +84 -0
  689. package/dist/shared/{schema.d.ts → channel/schema.d.ts} +38 -21
  690. package/dist/shared/{schema.js → channel/schema.js} +62 -35
  691. package/dist/shared/download/archive.d.ts +13 -0
  692. package/dist/shared/download/archive.js +57 -0
  693. package/dist/shared/download/downloader.d.ts +35 -0
  694. package/dist/shared/download/downloader.js +110 -0
  695. package/dist/shared/download/github.d.ts +16 -0
  696. package/dist/shared/download/github.js +74 -0
  697. package/dist/shared/download/http.d.ts +5 -0
  698. package/dist/shared/download/http.js +30 -0
  699. package/dist/shared/download/index.d.ts +5 -0
  700. package/dist/shared/download/index.js +5 -0
  701. package/dist/shared/download/spawn.d.ts +2 -0
  702. package/dist/shared/download/spawn.js +7 -0
  703. package/dist/shared/io/index.d.ts +3 -0
  704. package/dist/shared/io/index.js +3 -0
  705. package/dist/shared/io/json-file.d.ts +10 -0
  706. package/dist/shared/io/json-file.js +21 -0
  707. package/dist/shared/io/json.d.ts +13 -0
  708. package/dist/shared/io/json.js +49 -0
  709. package/dist/shared/{safe-remove.js → io/safe-remove.js} +32 -7
  710. package/dist/shared/{netrules.js → network/firewall-rules.js} +36 -5
  711. package/dist/shared/network/index.d.ts +2 -0
  712. package/dist/shared/network/index.js +2 -0
  713. package/dist/shared/{netpolicy.js → network/policy.js} +66 -11
  714. package/dist/shared/{paths.js → paths/claude-paths.js} +12 -2
  715. package/dist/shared/{guest-paths.d.ts → paths/guest-paths.d.ts} +6 -12
  716. package/dist/shared/{guest-paths.js → paths/guest-paths.js} +53 -36
  717. package/dist/shared/paths/index.d.ts +3 -0
  718. package/dist/shared/paths/index.js +3 -0
  719. package/dist/shared/{projects.js → paths/projects.js} +13 -3
  720. package/dist/shared/pty/client.d.ts +21 -0
  721. package/dist/shared/pty/client.js +79 -0
  722. package/dist/shared/{console-input.js → pty/console-input.js} +26 -6
  723. package/dist/shared/pty/index.d.ts +6 -0
  724. package/dist/shared/pty/index.js +6 -0
  725. package/dist/shared/pty/input-joiner.d.ts +15 -0
  726. package/dist/shared/pty/input-joiner.js +44 -0
  727. package/dist/shared/pty/output-filter.d.ts +13 -0
  728. package/dist/shared/pty/output-filter.js +140 -0
  729. package/dist/shared/pty/protocol.d.ts +36 -0
  730. package/dist/shared/pty/protocol.js +60 -0
  731. package/dist/shared/pty/terminal.d.ts +24 -0
  732. package/dist/shared/pty/terminal.js +147 -0
  733. package/dist/shared/test-guard.js +3 -1
  734. package/dist/sync/claude-mem.d.ts +1 -1
  735. package/dist/sync/claude-mem.js +9 -4
  736. package/dist/sync/history.d.ts +1 -29
  737. package/dist/sync/history.js +57 -45
  738. package/dist/sync/index.d.ts +5 -0
  739. package/dist/sync/index.js +5 -0
  740. package/dist/sync/sync-cycle.d.ts +18 -0
  741. package/dist/sync/sync-cycle.js +85 -0
  742. package/dist/sync/sync-state.d.ts +32 -0
  743. package/dist/sync/sync-state.js +37 -0
  744. package/dist/sync/watcher.d.ts +0 -18
  745. package/dist/sync/watcher.js +66 -100
  746. package/native/keep-awake.ps1 +8 -0
  747. package/native/power.cs +23 -0
  748. package/native/stop-events.ps1 +38 -0
  749. package/package.json +11 -3
  750. package/sandbox/linkgate.cs +98 -0
  751. package/sandbox/memlog.ps1 +15 -6
  752. package/schemas/config.schema.json +34 -1
  753. package/schemas/sandbox-config.schema.json +34 -1
  754. package/dist/cli/boot-progress.d.ts +0 -22
  755. package/dist/cli/boot-progress.js +0 -59
  756. package/dist/cli/commands/launch.d.ts +0 -32
  757. package/dist/cli/commands/launch.js +0 -421
  758. package/dist/cli/commands/maintenance.d.ts +0 -10
  759. package/dist/cli/commands/maintenance.js +0 -220
  760. package/dist/cli/commands/project.d.ts +0 -33
  761. package/dist/cli/commands/project.js +0 -102
  762. package/dist/cli/commands/projects.d.ts +0 -14
  763. package/dist/cli/commands/projects.js +0 -146
  764. package/dist/cli/commands/restart.d.ts +0 -6
  765. package/dist/cli/commands/restart.js +0 -95
  766. package/dist/cli/commands/sessions.d.ts +0 -12
  767. package/dist/cli/commands/sessions.js +0 -258
  768. package/dist/cli/menu/settings/editors.js +0 -305
  769. package/dist/cli/tui/dialogs.d.ts +0 -57
  770. package/dist/cli/tui/dialogs.js +0 -162
  771. package/dist/core/config.js +0 -109
  772. package/dist/core/project-policy.d.ts +0 -62
  773. package/dist/core/project-policy.js +0 -121
  774. package/dist/core/schema.d.ts +0 -6
  775. package/dist/core/schema.js +0 -8
  776. package/dist/core/util.d.ts +0 -62
  777. package/dist/core/util.js +0 -156
  778. package/dist/core/workspace.d.ts +0 -35
  779. package/dist/core/workspace.js +0 -206
  780. package/dist/guest/boot-env.d.ts +0 -4
  781. package/dist/guest/daemon.js +0 -57
  782. package/dist/guest/env.d.ts +0 -56
  783. package/dist/guest/env.js +0 -115
  784. package/dist/guest/gitrules.js +0 -11
  785. package/dist/guest/project-status.d.ts +0 -5
  786. package/dist/guest/project-status.js +0 -17
  787. package/dist/guest/setup/user.js +0 -51
  788. package/dist/guest/toolchains/cli.d.ts +0 -10
  789. package/dist/guest/toolchains/common.d.ts +0 -54
  790. package/dist/guest/toolchains/common.js +0 -147
  791. package/dist/guest/toolchains/databases/dynamodb.d.ts +0 -8
  792. package/dist/guest/toolchains/databases/dynamodb.js +0 -52
  793. package/dist/guest/toolchains/databases/index.d.ts +0 -6
  794. package/dist/guest/toolchains/databases/index.js +0 -62
  795. package/dist/guest/toolchains/databases/mongodb.d.ts +0 -3
  796. package/dist/guest/toolchains/databases/mongodb.js +0 -31
  797. package/dist/guest/toolchains/databases/mysql.d.ts +0 -3
  798. package/dist/guest/toolchains/databases/mysql.js +0 -38
  799. package/dist/guest/toolchains/databases/postgres.d.ts +0 -5
  800. package/dist/guest/toolchains/databases/postgres.js +0 -38
  801. package/dist/guest/toolchains/databases/redis.d.ts +0 -3
  802. package/dist/guest/toolchains/databases/redis.js +0 -16
  803. package/dist/guest/toolchains/git.d.ts +0 -3
  804. package/dist/guest/toolchains/go.d.ts +0 -3
  805. package/dist/guest/toolchains/java.d.ts +0 -8
  806. package/dist/guest/toolchains/node.d.ts +0 -3
  807. package/dist/guest/toolchains/pwsh.d.ts +0 -4
  808. package/dist/guest/toolchains/python.d.ts +0 -3
  809. package/dist/guest/toolchains/scripting/php.d.ts +0 -3
  810. package/dist/guest/toolchains/scripting/ruby.d.ts +0 -3
  811. package/dist/host/accounts.d.ts +0 -32
  812. package/dist/host/accounts.js +0 -128
  813. package/dist/host/agent-commands.d.ts +0 -25
  814. package/dist/host/agent-commands.js +0 -145
  815. package/dist/host/channel.d.ts +0 -38
  816. package/dist/host/channel.js +0 -163
  817. package/dist/host/generate.d.ts +0 -13
  818. package/dist/host/generate.js +0 -115
  819. package/dist/host/launch/projects.d.ts +0 -17
  820. package/dist/host/launch/wsb.js +0 -34
  821. package/dist/host/motw.d.ts +0 -17
  822. package/dist/host/motw.js +0 -74
  823. package/dist/host/pc-scan.d.ts +0 -6
  824. package/dist/host/personalize.d.ts +0 -10
  825. package/dist/host/personalize.js +0 -97
  826. package/dist/host/platform.js +0 -129
  827. package/dist/host/project-scan.d.ts +0 -7
  828. package/dist/host/projects.d.ts +0 -123
  829. package/dist/host/projects.js +0 -196
  830. package/dist/host/repo-guard.d.ts +0 -43
  831. package/dist/host/repo-guard.js +0 -347
  832. package/dist/host/secrets.d.ts +0 -14
  833. package/dist/host/secrets.js +0 -133
  834. package/dist/host/stops.d.ts +0 -67
  835. package/dist/host/stops.js +0 -126
  836. package/dist/shared/apps.js +0 -114
  837. package/dist/shared/download.d.ts +0 -63
  838. package/dist/shared/download.js +0 -238
  839. package/dist/shared/pty-client.d.ts +0 -108
  840. package/dist/shared/pty-client.js +0 -406
  841. package/dist/shared/rundir.d.ts +0 -41
  842. package/dist/shared/rundir.js +0 -96
  843. /package/dist/{guest/daemon.d.ts → cli/tui/list/list-types.js} +0 -0
  844. /package/dist/{guest/db.d.ts → cli/tui/screen.js} +0 -0
  845. /package/dist/core/{detect-databases.d.ts → detect/databases.d.ts} +0 -0
  846. /package/dist/{guest/toolchains → core/detect}/versions.d.ts +0 -0
  847. /package/dist/guest/{setup/agents.d.ts → agents/agent-installer.d.ts} +0 -0
  848. /package/dist/guest/{audit-parse.d.ts → audit/parse.d.ts} +0 -0
  849. /package/dist/guest/{guide.d.ts → boot/guide.d.ts} +0 -0
  850. /package/dist/guest/daemon/{shutdown.d.ts → idle-shutdown.d.ts} +0 -0
  851. /package/dist/guest/daemon/{session.d.ts → sessions.d.ts} +0 -0
  852. /package/dist/guest/{main.d.ts → entries/daemon.d.ts} +0 -0
  853. /package/dist/guest/{netproxy.d.ts → entries/db.d.ts} +0 -0
  854. /package/dist/{selftest/suite.js → guest/entries/gitguard.d.ts} +0 -0
  855. /package/dist/guest/{gitguard.d.ts → git/decision.d.ts} +0 -0
  856. /package/dist/guest/{ports.d.ts → runtime/ports.d.ts} +0 -0
  857. /package/dist/guest/{project-context.d.ts → runtime/project-context.d.ts} +0 -0
  858. /package/dist/guest/{cmdline.d.ts → sessions/cmdline.d.ts} +0 -0
  859. /package/dist/guest/{ptyhost.d.ts → sessions/pty-host.d.ts} +0 -0
  860. /package/dist/guest/{view.d.ts → sessions/viewer.d.ts} +0 -0
  861. /package/dist/guest/setup/{policy.d.ts → managed-policy.d.ts} +0 -0
  862. /package/dist/host/{window.d.ts → sandbox/window.d.ts} +0 -0
  863. /package/dist/host/{wsb.d.ts → sandbox/wsb-cli.d.ts} +0 -0
  864. /package/dist/host/{cleanup.d.ts → storage/cleanup.d.ts} +0 -0
  865. /package/dist/selftest/{harness.d.ts → support/harness.d.ts} +0 -0
  866. /package/dist/selftest/{suite.d.ts → support/suite.d.ts} +0 -0
  867. /package/dist/shared/{safe-remove.d.ts → io/safe-remove.d.ts} +0 -0
  868. /package/dist/shared/{netrules.d.ts → network/firewall-rules.d.ts} +0 -0
  869. /package/dist/shared/{netpolicy.d.ts → network/policy.d.ts} +0 -0
  870. /package/dist/shared/{paths.d.ts → paths/claude-paths.d.ts} +0 -0
  871. /package/dist/shared/{projects.d.ts → paths/projects.d.ts} +0 -0
  872. /package/dist/shared/{console-input.d.ts → pty/console-input.d.ts} +0 -0
@@ -3,34 +3,37 @@
3
3
  // environment, history sync and the repo guard for every project. Offline: temp folders only.
4
4
  import fs from 'node:fs';
5
5
  import path from 'node:path';
6
- import { LocalOverrides } from '../core/schema.js';
7
- import { checkJoin, describeMissing, missingAtBoot, missingTip, nothingMissing, protectionsOf } from '../core/project-policy.js';
8
- import { allowStorePath, saveAllowed } from '../core/local-config.js';
9
- import { sessionsFirstIn } from '../host/channel.js';
10
- import { buildWsb } from '../host/launch/wsb.js';
11
- import { projectSpec, joinRunning } from '../host/join.js';
12
- import { allProjectsToMap, forgetProject, NeedsRestart, parseWsbBoot, projectHere, projectMapper, readKnown, readRegistry, rememberProject, startRegistry } from '../host/projects.js';
13
- import { checkRepo, saveRepoSnapshot } from '../host/repo-guard.js';
14
- import { findWsb, parseCommands, parseIp, parseList, parseVersion } from '../host/wsb.js';
15
- import { baseEnvFor } from '../guest/project-env.js';
16
- import { guestDirFor, hostDirFor, hubName, insideProjects, isBelow, isWithin, planProjectMappings, projectForGuestDir, projectForHostDir, PROJECTS_GUEST, rootGuestDir } from '../shared/projects.js';
17
- import { GuestRequest, ProjectSpec } from '../shared/schema.js';
18
- import { projectFolderName } from '../shared/paths.js';
19
- import { syncHistoryOut } from '../sync/history.js';
6
+ import { LocalOverridesSchema } from '../core/schema/index.js';
7
+ import { allowStorePath, checkJoin, describeMissing, missingAtBoot, missingTip, nothingMissing, protectionsOf, saveAllowed, } from '../core/local-config/index.js';
8
+ import { sessionsFirstIn } from '../host/channel/index.js';
9
+ import { buildWsb } from '../host/launch/index.js';
10
+ import { projectSpec, joinRunning } from '../host/projects/index.js';
11
+ import { allProjectsToMap, KnownProjects } from '../host/projects/index.js';
12
+ import { NeedsRestart, projectMapper } from '../host/projects/index.js';
13
+ import { parseWsbBoot, ProjectRegistry } from '../host/projects/index.js';
14
+ import { RepoGuardStore } from '../host/guard/index.js';
15
+ import { findWsb, parseCommands, parseIp, parseList, parseVersion } from '../host/sandbox/index.js';
16
+ import { baseEnvFor } from '../guest/boot/project-env.js';
17
+ import { guestDirFor, hostDirFor, hubName, insideProjects, isBelow, isWithin, planProjectMappings, projectForGuestDir, projectForHostDir, PROJECTS_GUEST, rootGuestDir, } from '../shared/paths/index.js';
18
+ import { GuestRequestSchema, ProjectSpecSchema } from '../shared/channel/index.js';
19
+ import { projectFolderName } from '../shared/paths/index.js';
20
+ import { syncHistoryOut } from '../sync/index.js';
20
21
  import { validateOptions, validateProjectsArgs } from '../cli/validate.js';
21
22
  import { parseCli, parseSessionWant } from '../cli/args.js';
22
23
  import { candidateFolders, severalAgentsArgv } from '../cli/menu/index.js';
23
- import { generateSandbox } from '../host/generate.js';
24
+ import { generateSandbox } from '../host/launch/index.js';
24
25
  import { askedWhen } from '../cli/manifest.js';
25
- import { describeSessions } from '../cli/commands/restart.js';
26
+ import { describeSessions } from '../cli/commands/projects/index.js';
26
27
  /** The error `fn` throws, or null. */
27
- const caught = (fn) => { try {
28
- fn();
29
- return null;
30
- }
31
- catch (e) {
32
- return e;
33
- } };
28
+ const caught = (fn) => {
29
+ try {
30
+ fn();
31
+ return null;
32
+ }
33
+ catch (e) {
34
+ return e;
35
+ }
36
+ };
34
37
  export const projectsSuite = {
35
38
  name: 'projects',
36
39
  title: 'several projects in one sandbox (paths, joining, policy, specs, --session)',
@@ -42,7 +45,10 @@ export const projectsSuite = {
42
45
  t.equal(hubName('F:\\Code\\api', ['API', 'api-2']), 'api-3', 'project ids are unique (case-insensitive)');
43
46
  t.equal(hubName('F:\\Code\\...', []), 'project', 'project ids are never empty');
44
47
  t.equal(hubName('F:\\' + 'x'.repeat(80), []).length, 48, 'project ids are capped at 48 characters');
45
- const projects = [{ host: 'F:\\Code', guest: 'C:\\Projects\\Code' }, { host: 'F:\\Code\\api', guest: 'C:\\Projects\\api' }];
48
+ const projects = [
49
+ { host: 'F:\\Code', guest: 'C:\\Projects\\Code' },
50
+ { host: 'F:\\Code\\api', guest: 'C:\\Projects\\api' },
51
+ ];
46
52
  t.equal(projectForHostDir(projects, 'f:\\code\\api\\src')?.guest, 'C:\\Projects\\api', 'the most specific mapped folder wins');
47
53
  t.equal(projectForHostDir(projects, 'F:\\Code\\web')?.guest, 'C:\\Projects\\Code', 'a folder inside a mapped folder belongs to it');
48
54
  t.equal(projectForHostDir(projects, 'F:\\Other'), null, 'unrelated folders belong to no project');
@@ -59,9 +65,9 @@ export const projectsSuite = {
59
65
  const plan = planProjectMappings(['F:\\Code', 'E:\\Work\\Code', 'C:\\Users\\me\\src'], ['D:\\x\\api', 'D:\\y\\api'], false);
60
66
  t.equal(plan.roots.map((r) => r.guest), ['C:\\Projects\\Code', 'C:\\Projects\\Code-2', 'C:\\Projects\\src'], 'roots get unique C:\\Projects\\<name> folders');
61
67
  t.equal(plan.projects.map((p) => p.guest), ['C:\\Workspace\\api', 'C:\\Workspace\\api-2'], 'projects mapped on their own get unique C:\\Workspace\\<name> folders (where they are as the launch folder)');
62
- t.equal(planProjectMappings([], ['D:\\x\\app'], false, ['C:\\Workspace\\app']).projects[0].guest, 'C:\\Workspace\\app-2', 'a project mapped on its own never lands on the launch folder\'s place');
68
+ t.equal(planProjectMappings([], ['D:\\x\\app'], false, ['C:\\Workspace\\app']).projects[0].guest, 'C:\\Workspace\\app-2', "a project mapped on its own never lands on the launch folder's place");
63
69
  t.equal(planProjectMappings(['F:\\Code'], ['D:\\x\\api'], true).projects[0].guest, 'D:\\x\\api', 'with "mirror" a project mapped on its own appears at its PC path, as it would as the launch folder');
64
- t.equal(rootGuestDir(['F:\\Code'], false, 'F:\\Code\\web\\src'), 'C:\\Projects\\Code\\web\\src', 'a folder inside a root is placed under the root\'s guest folder');
70
+ t.equal(rootGuestDir(['F:\\Code'], false, 'F:\\Code\\web\\src'), 'C:\\Projects\\Code\\web\\src', "a folder inside a root is placed under the root's guest folder");
65
71
  t.equal(rootGuestDir(['F:\\Code'], false, 'F:\\Other'), null, 'a folder in no root has no root place');
66
72
  const mirror = planProjectMappings(['F:\\Code', 'C:\\Users\\me\\src'], [], true);
67
73
  t.equal(mirror.roots.map((r) => r.guest), ['F:\\Code', 'C:\\Projects\\src'], 'with "mirror" a root appears at its PC path when the sandbox can show it there (C:\\Users\\... cannot)');
@@ -69,18 +75,21 @@ export const projectsSuite = {
69
75
  const base = protectionsOf(f.baseConfig);
70
76
  const same = checkJoin(base, base);
71
77
  t.equal({ stricter: same.stricter, looser: same.looser }, { stricter: [], looser: [] }, 'the same settings join without notes');
72
- const readonlyGit = protectionsOf({ ...f.baseConfig, provisioning: { ...f.baseConfig.provisioning, git: { ...f.baseConfig.provisioning.git, access: 'readonly' } } });
78
+ const readonlyGit = protectionsOf({
79
+ ...f.baseConfig,
80
+ provisioning: { ...f.baseConfig.provisioning, git: { ...f.baseConfig.provisioning.git, access: 'readonly' } },
81
+ });
73
82
  t.check(checkJoin(base, readonlyGit).stricter.some((s) => s.startsWith('provisioning.git.access')), 'a project needing stricter git access than the running sandbox is refused (git access is machine-wide)');
74
83
  const loosening = checkJoin(readonlyGit, base);
75
84
  t.equal(loosening.stricter.length, 0, 'a project asking for less git access is not refused...');
76
- t.check(loosening.looser.some((s) => s.includes('provisioning.git.access stays "readonly"')), '... it gets the sandbox\'s stricter value, with a note: never loosened', JSON.stringify(loosening.looser));
85
+ t.check(loosening.looser.some((s) => s.includes('provisioning.git.access stays "readonly"')), "... it gets the sandbox's stricter value, with a note: never loosened", JSON.stringify(loosening.looser));
77
86
  const offline = protectionsOf({ ...f.baseConfig, sandbox: { ...f.baseConfig.sandbox, networking: false } });
78
87
  t.check(checkJoin(base, offline).stricter.some((s) => s.startsWith('sandbox.networking')), 'networking off is stricter than a sandbox with networking');
79
88
  t.check(checkJoin(offline, base).looser.some((s) => s.startsWith('sandbox.networking')), 'networking on is looser than an offline sandbox');
80
89
  const readOnly = protectionsOf({ ...f.baseConfig, readOnly: true });
81
90
  t.check(checkJoin(readOnly, readOnly).stricter.some((s) => s.startsWith('readOnly')), 'a read-only project cannot join (other projects are mapped read/write), even when the launch folder was read-only');
82
- t.check(!LocalOverrides.safeParse({ projects: { roots: ['C:\\'] } }).success, 'a project\'s .sandbox-config.json can never set projects.roots (they map folders of this PC)');
83
- t.check(!LocalOverrides.safeParse({ projects: { all: true } }).success, 'a project\'s .sandbox-config.json can never set projects.all');
91
+ t.check(!LocalOverridesSchema.safeParse({ projects: { roots: ['C:\\'] } }).success, "a project's .sandbox-config.json can never set projects.roots (they map folders of this PC)");
92
+ t.check(!LocalOverridesSchema.safeParse({ projects: { all: true } }).success, "a project's .sandbox-config.json can never set projects.all");
84
93
  // A project file that loosens git access is clamped by keepStrictest first, then joins without being refused.
85
94
  const strictUser = structuredClone(f.baseConfig);
86
95
  strictUser.provisioning.git.access = 'readonly';
@@ -99,24 +108,35 @@ export const projectsSuite = {
99
108
  const root = t.at('proj-root');
100
109
  const inRoot = t.dir('proj-root', 'web');
101
110
  const outside = t.dir('proj-outside');
102
- const primary = startRegistry(storage, { launchId: '1700000000000-abcdef', protections: base, primary: { host: f.workA, guest: 'C:\\Workspace\\work-a' }, roots: [{ host: root, guest: 'C:\\Projects\\proj-root' }], boot: [{ host: f.workB, guest: 'C:\\Projects\\work-b' }] });
103
- const registry = readRegistry(storage);
111
+ const primary = new ProjectRegistry(storage).start({
112
+ launchId: '1700000000000-abcdef',
113
+ protections: base,
114
+ primary: { host: f.workA, guest: 'C:\\Workspace\\work-a' },
115
+ roots: [{ host: root, guest: 'C:\\Projects\\proj-root' }],
116
+ boot: [{ host: f.workB, guest: 'C:\\Projects\\work-b' }],
117
+ });
118
+ const registry = new ProjectRegistry(storage).read();
104
119
  t.check(primary.primary, 'at launch the launch folder is the primary project');
105
120
  t.equal(registry?.projects.length, 2, 'at launch the registry holds the launch folder and the projects mapped with it');
106
121
  t.equal({ mechanism: registry?.projects[1].mechanism, name: registry?.projects[1].name }, { mechanism: 'boot', name: 'work-b' }, 'a project mapped at boot is registered by its mechanism and name');
107
- t.equal(projectHere(storage, path.join(f.workA, 'src'))?.guestDir, 'C:\\Workspace\\work-a\\src', 'projectHere: a folder inside the launch folder');
108
- t.equal(projectHere(storage, f.workB)?.project.mechanism, 'boot', 'projectHere: a project mapped at boot');
109
- t.equal(projectHere(storage, outside), null, 'projectHere: a folder in no project');
122
+ t.equal(new ProjectRegistry(storage).here(path.join(f.workA, 'src'))?.guestDir, 'C:\\Workspace\\work-a\\src', 'projectHere: a folder inside the launch folder');
123
+ t.equal(new ProjectRegistry(storage).here(f.workB)?.project.mechanism, 'boot', 'projectHere: a project mapped at boot');
124
+ t.equal(new ProjectRegistry(storage).here(outside), null, 'projectHere: a folder in no project');
110
125
  const noWsb = projectMapper({ storageRoot: storage, packageRoot: f.install, wsbShare: true, detect: () => null });
111
126
  const web = noWsb.register(inRoot);
112
127
  t.equal({ mechanism: web.mechanism, guest: web.guest }, { mechanism: 'root', guest: 'C:\\Projects\\proj-root\\web' }, 'a folder inside a root joins at once (also one created after boot)');
113
128
  t.equal(noWsb.register(inRoot).name, web.name, 'registering the same folder again gives the same project');
114
- t.equal(readRegistry(storage)?.projects.filter((p) => p.host === inRoot).length, 1, 'a folder is registered once');
129
+ t.equal(new ProjectRegistry(storage).read()?.projects.filter((p) => p.host === inRoot).length, 1, 'a folder is registered once');
115
130
  const needs = caught(() => noWsb.register(outside));
116
131
  t.check(needs instanceof NeedsRestart && needs.reason.includes('wsb share needs Windows 11 24H2'), 'a folder outside every root without the Windows Sandbox CLI needs a restart (and says why)');
117
132
  const shareOff = caught(() => projectMapper({ storageRoot: storage, packageRoot: f.install, wsbShare: false }).register(outside));
118
133
  t.check(shareOff instanceof NeedsRestart && shareOff.reason.includes('projects.wsbShare'), 'projects.wsbShare off goes straight to the restart offer');
119
- const fakeWsb = { exe: t.at('no-such-wsb.exe'), version: '0.1.0', commands: ['share', 'list'], has: (c) => c === 'share' || c === 'list' };
134
+ const fakeWsb = {
135
+ exe: t.at('no-such-wsb.exe'),
136
+ version: '0.1.0',
137
+ commands: ['share', 'list'],
138
+ has: (c) => c === 'share' || c === 'list',
139
+ };
120
140
  const listFails = caught(() => projectMapper({ storageRoot: storage, packageRoot: f.install, wsbShare: true, detect: () => fakeWsb }).register(outside));
121
141
  t.check(listFails instanceof NeedsRestart && listFails.reason.includes('wsb share could not find the running sandbox'), 'when wsb cannot tell which sandbox is ours, it falls back to the restart offer with the reason');
122
142
  await t.throws(() => noWsb.register(storage), 'cannot be the workspace', 'joining uses the launch-folder safety checks: not the storage folder');
@@ -128,17 +148,40 @@ export const projectsSuite = {
128
148
  const webRun = await f.run({ cwd: inRoot, trustConfig: true });
129
149
  const joined = await join(inRoot, resolveFor(webRun));
130
150
  t.equal(joined.spec?.workspace, 'C:\\Projects\\proj-root\\web', 'joining a project builds a spec with its guest folder...');
131
- t.check(ProjectSpec.safeParse(joined.spec).success && joined.spec?.harnesses.claude !== undefined, '... that is valid and carries the agent');
132
- t.check(readKnown(storage).some((k) => k.host === inRoot), 'joined projects are remembered (projects.all, sandbox projects)');
151
+ t.check(ProjectSpecSchema.safeParse(joined.spec).success && joined.spec?.harnesses.claude !== undefined, '... that is valid and carries the agent');
152
+ t.check(new KnownProjects(storage).list().some((k) => k.host === inRoot), 'joined projects are remembered (projects.all, sandbox projects)');
133
153
  const launchFolder = await join(path.join(f.workA, 'sub'), () => Promise.reject(new Error('must not resolve')));
134
154
  t.equal(launchFolder.spec, null, 'the launch folder (and below) needs no spec: its sessions use the boot environment');
135
- await t.throws(() => join(tightDir, resolveFor(tight)), 'stricter protection than the running sandbox', 'a project whose .sandbox-config.json tightens git access beyond the running sandbox is refused, with the reason');
136
- t.check(readRegistry(storage)?.projects.every((p) => p.host !== tightDir) === true, 'a refused project is not registered');
155
+ await t.throws(() => join(tightDir, resolveFor(tight)), 'stricter than the running sandbox', 'a project whose .sandbox-config.json tightens git access beyond the running sandbox is refused without your consent, with the reason');
156
+ t.check(new ProjectRegistry(storage).read()?.projects.every((p) => p.host !== tightDir) === true, 'a refused project is not registered');
157
+ let asked = [];
158
+ const agreed = await t.thrownMessage(() => joinRunning({
159
+ storageRoot: storage,
160
+ dataPath: data,
161
+ packageRoot: f.install,
162
+ hostDir: tightDir,
163
+ wsbShare: false,
164
+ resolve: resolveFor(tight),
165
+ acceptStricter: async (_name, stricter) => {
166
+ asked = stricter;
167
+ return true;
168
+ },
169
+ }));
170
+ t.check(asked.some((s) => s.startsWith('provisioning.git.access')) &&
171
+ !agreed.includes('stricter than the running sandbox'), 'with your consent it is not refused for its stricter settings (it goes on to joining: here a restart, as its folder is outside every root)', agreed);
137
172
  const outsideRun = await f.run({ cwd: outside });
138
173
  await t.throws(() => join(outside, resolveFor(outsideRun)), 'projects.wsbShare', 'a folder that cannot be shown lets NeedsRestart reach the caller');
139
174
  t.section('projects: the spec and request the guest gets');
140
175
  const spec = projectSpec(webRun, web, false);
141
- const sessionRequest = (extra) => GuestRequest.safeParse({ kind: 'session', id: 'r1', harness: 'claude', args: [], cwd: spec.workspace, createdAt: new Date().toISOString(), ...extra });
176
+ const sessionRequest = (extra) => GuestRequestSchema.safeParse({
177
+ kind: 'session',
178
+ id: 'r1',
179
+ harness: 'claude',
180
+ args: [],
181
+ cwd: spec.workspace,
182
+ createdAt: new Date().toISOString(),
183
+ ...extra,
184
+ });
142
185
  t.check(sessionRequest({ project: spec }).success, 'a session request carries a project spec');
143
186
  t.check(sessionRequest({ project: spec, harnessSpec: f.baseConfig.harnesses.codex }).success, 'a session request carries an agent definition');
144
187
  t.check(!sessionRequest({ project: { ...spec, name: '..\\evil' } }).success, 'specs are validated: project ids are file-name safe');
@@ -147,24 +190,36 @@ export const projectsSuite = {
147
190
  t.check(!sessionRequest({ project: { ...spec, databases: manyDatabases } }).success, 'specs are validated: lists are capped');
148
191
  const manyAgents = Object.fromEntries(Array.from({ length: 9 }, (_, i) => ['a' + i, f.baseConfig.harnesses.codex]));
149
192
  t.check(!sessionRequest({ project: { ...spec, harnesses: manyAgents } }).success, 'at most 8 agent definitions in one spec');
150
- t.check(GuestRequest.safeParse({ kind: 'project', id: 'p1', project: spec, createdAt: 'x' }).success, '"project" requests (set up without an agent) carry a spec');
151
- t.check(!GuestRequest.safeParse({ kind: 'project', id: 'p1', createdAt: 'x' }).success, '"project" requests need a spec');
152
- t.check(GuestRequest.safeParse({ kind: 'restart', id: 'x', harness: null, cwd: 'C:\\Projects\\a', createdAt: 'x' }).success, 'restart can be scoped to one project\'s folder');
153
- t.check(GuestRequest.safeParse({ kind: 'restart', id: 'x', harness: null, createdAt: 'x' }).success, 'restart still works without a folder');
193
+ t.check(GuestRequestSchema.safeParse({ kind: 'project', id: 'p1', project: spec, createdAt: 'x' }).success, '"project" requests (set up without an agent) carry a spec');
194
+ t.check(!GuestRequestSchema.safeParse({ kind: 'project', id: 'p1', createdAt: 'x' }).success, '"project" requests need a spec');
195
+ t.check(GuestRequestSchema.safeParse({ kind: 'restart', id: 'x', harness: null, cwd: 'C:\\Projects\\a', createdAt: 'x' })
196
+ .success, "restart can be scoped to one project's folder");
197
+ t.check(GuestRequestSchema.safeParse({ kind: 'restart', id: 'x', harness: null, createdAt: 'x' }).success, 'restart still works without a folder');
154
198
  t.section('projects: which projects are mapped at boot');
155
- const toMap = allProjectsToMap(['C:\\a', 'C:\\a\\b', 'C:\\work-a\\x', 'C:\\r\\p', 'C:\\ex\\y', 'C:\\gone'], { primary: 'C:\\work-a', roots: ['C:\\r'], exclude: ['C:\\ex'], exists: (p) => p !== 'C:\\gone' });
156
- t.equal(toMap, ['C:\\a'], 'projects.all: known projects except excluded, missing, nested, the launch folder\'s and the roots\'');
199
+ const toMap = allProjectsToMap(['C:\\a', 'C:\\a\\b', 'C:\\work-a\\x', 'C:\\r\\p', 'C:\\ex\\y', 'C:\\gone'], {
200
+ primary: 'C:\\work-a',
201
+ roots: ['C:\\r'],
202
+ exclude: ['C:\\ex'],
203
+ exists: (p) => p !== 'C:\\gone',
204
+ });
205
+ t.equal(toMap, ['C:\\a'], "projects.all: known projects except excluded, missing, nested, the launch folder's and the roots'");
157
206
  const rootConfig = structuredClone(f.baseConfig);
158
207
  rootConfig.projects = { ...rootConfig.projects, roots: [root, t.at('no-such-root')], all: true };
159
- rememberProject(f.baseConfig.storage.root, outside);
208
+ new KnownProjects(f.baseConfig.storage.root).remember(outside);
160
209
  const gen = f.generate(await f.run({}, rootConfig));
161
210
  const session = f.readJson(gen.sessionPath);
162
211
  const wsb = fs.readFileSync(gen.wsbPath, 'utf8');
163
212
  t.equal(gen.projects.roots.map((r) => r.guest), ['C:\\Projects\\proj-root'], 'roots are mapped as C:\\Projects\\<name>');
164
213
  t.check(gen.projects.notes.some((n) => n.includes('no-such-root')), 'a missing root is skipped with a note', JSON.stringify(gen.projects.notes));
165
214
  t.check(gen.projects.projects.some((p) => p.host === outside), 'projects.all maps the known projects too');
166
- t.includes(wsb, '<HostFolder>' + root + '</HostFolder><SandboxFolder>C:\\Projects\\proj-root</SandboxFolder><ReadOnly>false</ReadOnly>', 'roots are mapped read/write in the .wsb');
167
- t.equal({ projectsDir: session.projectsDir, roots: session.roots, projectId: session.projectId }, { projectsDir: PROJECTS_GUEST, roots: ['C:\\Projects\\proj-root', 'C:\\Workspace\\proj-outside'], projectId: 'work-a' }, 'session.json tells the guest where other projects can be');
215
+ t.includes(wsb, '<HostFolder>' +
216
+ root +
217
+ '</HostFolder><SandboxFolder>C:\\Projects\\proj-root</SandboxFolder><ReadOnly>false</ReadOnly>', 'roots are mapped read/write in the .wsb');
218
+ t.equal({ projectsDir: session.projectsDir, roots: session.roots, projectId: session.projectId }, {
219
+ projectsDir: PROJECTS_GUEST,
220
+ roots: ['C:\\Projects\\proj-root', 'C:\\Workspace\\proj-outside'],
221
+ projectId: 'work-a',
222
+ }, 'session.json tells the guest where other projects can be');
168
223
  // The same project is at the same place whether it started the sandbox or joined one another project started.
169
224
  const fromRoot = f.generate(await f.run({ cwd: inRoot }, rootConfig));
170
225
  const joinedAt = guestDirFor(gen.projects.roots[0], inRoot);
@@ -184,8 +239,8 @@ export const projectsSuite = {
184
239
  const badRoot = structuredClone(f.baseConfig);
185
240
  badRoot.projects = { ...badRoot.projects, roots: [f.baseConfig.storage.root] };
186
241
  await t.throws(async () => f.generate(await f.run({}, badRoot)), 'projects.roots', 'a root that would expose the storage folder is refused');
187
- t.check(forgetProject(f.baseConfig.storage.root, outside), '`sandbox projects remove` forgets a project...');
188
- t.check(!readKnown(f.baseConfig.storage.root).some((k) => k.host === outside), '... so it is no longer known (its folder is untouched)');
242
+ t.check(new KnownProjects(f.baseConfig.storage.root).forget(outside), '`sandbox projects remove` forgets a project...');
243
+ t.check(!new KnownProjects(f.baseConfig.storage.root).list().some((k) => k.host === outside), '... so it is no longer known (its folder is untouched)');
189
244
  t.includes(buildWsb(f.baseConfig, 4096, []), '<MappedFolders></MappedFolders>', 'no projects: nothing extra mapped');
190
245
  t.section('projects: repo guard for every project the sandbox can write');
191
246
  const guardData = t.at('guard-data');
@@ -193,13 +248,13 @@ export const projectsSuite = {
193
248
  const old = path.join(rootG, 'old');
194
249
  t.write(path.join(old, '.git', 'hooks', 'pre-commit'), 'mine');
195
250
  t.write(path.join(old, '.git', 'config'), '[core]\n\tbare = false\n');
196
- saveRepoSnapshot(guardData, f.workA, [], [rootG]);
251
+ new RepoGuardStore(guardData).save(f.workA, [], [rootG]);
197
252
  t.write(path.join(old, '.git', 'hooks', 'post-checkout'), 'planted');
198
253
  const fresh = path.join(rootG, 'created-later');
199
254
  t.write(path.join(fresh, '.git', 'hooks', 'pre-push'), 'planted');
200
255
  t.write(path.join(fresh, '.git', 'config'), '[core]\n\tfsmonitor = evil.exe\n\tbare = false\n');
201
256
  t.write(path.join(fresh, 'node.exe'), 'planted');
202
- const found = checkRepo(guardData);
257
+ const found = new RepoGuardStore(guardData).check();
203
258
  t.check(fs.existsSync(path.join(old, '.git', 'hooks', 'pre-commit')), 'a hook that was there before the sandbox ran stays');
204
259
  t.check(!fs.existsSync(path.join(old, '.git', 'hooks', 'post-checkout')), 'a hook added inside the sandbox to a project in a root is quarantined');
205
260
  t.check(!fs.existsSync(path.join(fresh, '.git', 'hooks', 'pre-push')), 'a project that appeared in a root after the start has its planted hooks removed');
@@ -211,17 +266,61 @@ export const projectsSuite = {
211
266
  const guestClaude = t.at('hist-guest');
212
267
  const bHost = t.at('hist-b');
213
268
  t.write(path.join(guestClaude, 'projects', projectFolderName('C:\\Projects\\hist-b'), 's.jsonl'), JSON.stringify({ cwd: 'C:\\Projects\\hist-b\\src' }) + '\n');
214
- syncHistoryOut({ hostClaudeDir: hostClaude, guestClaudeDir: guestClaude, hostWorkspace: f.workA, guestWorkspace: 'C:\\Workspace\\work-a', extra: [{ hostWorkspace: bHost, guestWorkspace: 'C:\\Projects\\hist-b' }] });
269
+ syncHistoryOut({
270
+ hostClaudeDir: hostClaude,
271
+ guestClaudeDir: guestClaude,
272
+ hostWorkspace: f.workA,
273
+ guestWorkspace: 'C:\\Workspace\\work-a',
274
+ extra: [{ hostWorkspace: bHost, guestWorkspace: 'C:\\Projects\\hist-b' }],
275
+ });
215
276
  const back = path.join(hostClaude, 'projects', projectFolderName(bHost), 's.jsonl');
216
- t.check(fs.existsSync(back), 'a joined project\'s history goes back to ITS folder on this PC');
217
- t.includes(fs.existsSync(back) ? fs.readFileSync(back, 'utf8') : '', JSON.stringify(bHost + '\\src').slice(1, -1), 'a joined project\'s history paths are translated');
218
- const env = baseEnvFor({ basePath: 'C:\\Windows', toolVars: ['NVM_HOME', 'CARGO_HOME'], steps: {}, summary: [], lan: 'blocked' }, { Path: 'C:\\tools\\a;C:\\Windows', NVM_HOME: 'x', CARGO_HOME: 'y', CARGO_TARGET_DIR: 'C:\\Workspace\\a\\target', AGENT_WORKSPACE: 'C:\\Workspace\\a', TEMP: 'C:\\t' });
219
- t.equal({ PATH: env.PATH, Path: env.Path, NVM_HOME: env.NVM_HOME, CARGO_TARGET_DIR: env.CARGO_TARGET_DIR, AGENT_WORKSPACE: env.AGENT_WORKSPACE, TEMP: env.TEMP }, { PATH: 'C:\\Windows', Path: undefined, NVM_HOME: undefined, CARGO_TARGET_DIR: undefined, AGENT_WORKSPACE: undefined, TEMP: 'C:\\t' }, 'a joined project starts from the boot\'s base environment: none of the first project\'s tools, workspace or target folder');
277
+ t.check(fs.existsSync(back), "a joined project's history goes back to ITS folder on this PC");
278
+ t.includes(fs.existsSync(back) ? fs.readFileSync(back, 'utf8') : '', JSON.stringify(bHost + '\\src').slice(1, -1), "a joined project's history paths are translated");
279
+ const env = baseEnvFor({ basePath: 'C:\\Windows', toolVars: ['NVM_HOME', 'CARGO_HOME'], steps: {}, summary: [], lan: 'blocked' }, {
280
+ Path: 'C:\\tools\\a;C:\\Windows',
281
+ NVM_HOME: 'x',
282
+ CARGO_HOME: 'y',
283
+ CARGO_TARGET_DIR: 'C:\\Workspace\\a\\target',
284
+ AGENT_WORKSPACE: 'C:\\Workspace\\a',
285
+ TEMP: 'C:\\t',
286
+ });
287
+ t.equal({
288
+ PATH: env.PATH,
289
+ Path: env.Path,
290
+ NVM_HOME: env.NVM_HOME,
291
+ CARGO_TARGET_DIR: env.CARGO_TARGET_DIR,
292
+ AGENT_WORKSPACE: env.AGENT_WORKSPACE,
293
+ TEMP: env.TEMP,
294
+ }, {
295
+ PATH: 'C:\\Windows',
296
+ Path: undefined,
297
+ NVM_HOME: undefined,
298
+ CARGO_TARGET_DIR: undefined,
299
+ AGENT_WORKSPACE: undefined,
300
+ TEMP: 'C:\\t',
301
+ }, "a joined project starts from the boot's base environment: none of the first project's tools, workspace or target folder");
220
302
  t.section('projects: commands');
221
- const status = (id, cwd, startedAt) => ({ id, launchId: 'l', harness: 'claude', cwd, phase: 'running', message: '', updatedAt: startedAt, startedAt });
222
- const sessions = [status('a1', 'C:\\Workspace\\a', '1'), status('b1', 'C:\\Projects\\b', '2'), status('a2', 'C:\\Workspace\\a\\x', '3'), status('b2', 'C:\\Projects\\b\\y', '4')];
223
- t.equal(sessionsFirstIn(sessions, 'C:\\Projects\\b').map((x) => x.id), ['b2', 'b1', 'a2', 'a1'], 'attach and sessions put this project\'s sessions first, newest first');
224
- t.equal(describeSessions([{ harness: 'claude', cwd: 'C:\\Workspace\\api', project: 'api' }, { harness: 'codex', cwd: 'C:\\Projects\\web' }]), '2 sessions (claude in api, codex in web)', 'the restart offer lists the sessions that would end');
303
+ const status = (id, cwd, startedAt) => ({
304
+ id,
305
+ launchId: 'l',
306
+ harness: 'claude',
307
+ cwd,
308
+ phase: 'running',
309
+ message: '',
310
+ updatedAt: startedAt,
311
+ startedAt,
312
+ });
313
+ const sessions = [
314
+ status('a1', 'C:\\Workspace\\a', '1'),
315
+ status('b1', 'C:\\Projects\\b', '2'),
316
+ status('a2', 'C:\\Workspace\\a\\x', '3'),
317
+ status('b2', 'C:\\Projects\\b\\y', '4'),
318
+ ];
319
+ t.equal(sessionsFirstIn(sessions, 'C:\\Projects\\b').map((x) => x.id), ['b2', 'b1', 'a2', 'a1'], "attach and sessions put this project's sessions first, newest first");
320
+ t.equal(describeSessions([
321
+ { harness: 'claude', cwd: 'C:\\Workspace\\api', project: 'api' },
322
+ { harness: 'codex', cwd: 'C:\\Projects\\web' },
323
+ ]), '2 sessions (claude in api, codex in web)', 'the restart offer lists the sessions that would end');
225
324
  await t.throws(() => validateProjectsArgs(['bogus']), 'projects action', '`sandbox projects` rejects an unknown action');
226
325
  await t.throws(() => validateProjectsArgs(['add']), 'Which folder', '`sandbox projects add` needs a folder');
227
326
  await t.throws(() => validateProjectsArgs(['all', 'maybe']), 'on', '`sandbox projects all` needs on or off');
@@ -229,7 +328,10 @@ export const projectsSuite = {
229
328
  validateProjectsArgs([]);
230
329
  validateProjectsArgs(['roots']);
231
330
  validateProjectsArgs(['all', 'on']);
232
- t.check(askedWhen(['add', 'remove'], 'add') && !askedWhen(['add'], 'list') && askedWhen(undefined, 'x') && askedWhen('save', 'save'), 'the menu asks an argument only for the actions it belongs to');
331
+ t.check(askedWhen(['add', 'remove'], 'add') &&
332
+ !askedWhen(['add'], 'list') &&
333
+ askedWhen(undefined, 'x') &&
334
+ askedWhen('save', 'save'), 'the menu asks an argument only for the actions it belongs to');
233
335
  t.section('projects: several sessions at once (--session agent@folder)');
234
336
  const want = parseSessionWant('claude@C:\\code\\a@b', 'C:\\here');
235
337
  t.equal({ harness: want.harness, folder: want.folder }, { harness: 'claude', folder: 'C:\\code\\a@b' }, '--session: the first @ splits agent from folder');
@@ -237,21 +339,63 @@ export const projectsSuite = {
237
339
  t.equal(parseSessionWant('gemini@sub', 'C:\\here').folder, 'C:\\here\\sub', '--session: relative folders become absolute');
238
340
  await t.throws(() => parseSessionWant('@C:\\x'), 'names no agent', '--session without an agent is refused');
239
341
  const own = parseSessionWant('codex@C:\\code\\web|--model o3 "two words"', 'C:\\here');
240
- t.equal({ harness: own.harness, folder: own.folder, args: own.args }, { harness: 'codex', folder: 'C:\\code\\web', args: ['--model', 'o3', 'two words'] }, '--session: after | come that agent\'s own arguments (quotes keep words together)');
342
+ t.equal({ harness: own.harness, folder: own.folder, args: own.args }, { harness: 'codex', folder: 'C:\\code\\web', args: ['--model', 'o3', 'two words'] }, "--session: after | come that agent's own arguments (quotes keep words together)");
241
343
  t.equal(parseSessionWant('claude@C:\\x').args, undefined, '--session: no | means no own arguments');
242
- const both = parseCli(['launch', '--session', 'claude@C:\\a|--continue', '--session', 'codex@C:\\b', '--', '--verbose']);
344
+ const both = parseCli([
345
+ 'launch',
346
+ '--session',
347
+ 'claude@C:\\a|--continue',
348
+ '--session',
349
+ 'codex@C:\\b',
350
+ '--',
351
+ '--verbose',
352
+ ]);
243
353
  t.equal(both.passthrough, ['--verbose'], 'arguments after -- go to every session...');
244
354
  t.equal(both.sessions.map((s) => s.args ?? []), [['--continue'], []], '... arguments after | only to that one');
245
- const multi = parseCli(['launch', '--session', 'claude@' + f.workA, '--session', 'codex@' + f.workB, '--session', 'claude@' + f.workB, '-t', '--', '--continue']);
246
- t.equal({ command: multi.command, sessions: multi.sessions.length, terminal: multi.terminal, second: multi.sessions[1].harness, passthrough: multi.passthrough }, { command: 'launch', sessions: 3, terminal: true, second: 'codex', passthrough: ['--continue'] }, 'several --session options parse in order, with -t and agent arguments');
247
- const validationContext = (options) => ({ packageRoot: f.install, entry: '', options, loaded: { config: f.baseConfig, configPath: null, base: t.temp }, storageRoot: f.baseConfig.storage.root, dataPath: t.at('vdata') });
355
+ const multi = parseCli([
356
+ 'launch',
357
+ '--session',
358
+ 'claude@' + f.workA,
359
+ '--session',
360
+ 'codex@' + f.workB,
361
+ '--session',
362
+ 'claude@' + f.workB,
363
+ '-t',
364
+ '--',
365
+ '--continue',
366
+ ]);
367
+ t.equal({
368
+ command: multi.command,
369
+ sessions: multi.sessions.length,
370
+ terminal: multi.terminal,
371
+ second: multi.sessions[1].harness,
372
+ passthrough: multi.passthrough,
373
+ }, { command: 'launch', sessions: 3, terminal: true, second: 'codex', passthrough: ['--continue'] }, 'several --session options parse in order, with -t and agent arguments');
374
+ const validationContext = (options) => ({
375
+ packageRoot: f.install,
376
+ entry: '',
377
+ options,
378
+ loaded: { config: f.baseConfig, configPath: null, base: t.temp },
379
+ storageRoot: f.baseConfig.storage.root,
380
+ dataPath: t.at('vdata'),
381
+ });
248
382
  await t.throws(() => validateOptions(validationContext(parseCli(['launch', '--session', 'claud@' + f.workA]))), 'Did you mean', 'an unknown agent in --session suggests the closest one');
249
383
  await t.throws(() => validateOptions(validationContext(parseCli(['launch', '--session', 'claude@' + t.at('nope')]))), 'does not exist', 'a missing --session folder is refused before anything starts');
250
384
  await t.throws(() => validateOptions(validationContext(parseCli(['launch', '--session', 'claude@' + f.workA, '--harness', 'codex']))), 'do not apply', '--session cannot be mixed with --harness/--workspace');
251
385
  validateOptions(validationContext(multi));
252
- t.equal(severalAgentsArgv([{ harness: 'claude', folder: 'C:\\a' }, { harness: 'codex', folder: 'C:\\b c' }], { headless: true, attachFirst: true }).join(' '), 'launch --session claude@C:\\a --session codex@C:\\b c --headless -t', 'the menu builds the same command line (so repeat-last works)');
386
+ t.equal(severalAgentsArgv([
387
+ { harness: 'claude', folder: 'C:\\a' },
388
+ { harness: 'codex', folder: 'C:\\b c' },
389
+ ], { headless: true, attachFirst: true }).join(' '), 'launch --session claude@C:\\a --session codex@C:\\b c --headless -t', 'the menu builds the same command line (so repeat-last works)');
253
390
  t.equal(candidateFolders(validationContext(parseCli(['launch'])), f.workA)[0], path.resolve(f.workA), 'the menu offers this folder first, then known projects and the folders in your roots');
254
- const multiGen = generateSandbox({ packageRoot: t.packageRoot, run: await f.run(), harnessArgs: [], probe: f.probe, extraProjects: [f.workB, path.join(f.workA, 'sub'), f.workB], autoSession: false });
391
+ const multiGen = generateSandbox({
392
+ packageRoot: t.packageRoot,
393
+ run: await f.run(),
394
+ harnessArgs: [],
395
+ probe: f.probe,
396
+ extraProjects: [f.workB, path.join(f.workA, 'sub'), f.workB],
397
+ autoSession: false,
398
+ });
255
399
  const multiSession = f.readJson(multiGen.sessionPath);
256
400
  const multiWsb = fs.readFileSync(multiGen.wsbPath, 'utf8');
257
401
  t.equal(multiGen.projects.projects.map((p) => p.guest), ['C:\\Workspace\\work-b'], 'a multi-project launch maps every other project once (folders inside the launch folder and duplicates need nothing)');
@@ -261,20 +405,36 @@ export const projectsSuite = {
261
405
  // A games project: its approved file asks for vGPU (you allowed it for this project) and maps a folder of its own.
262
406
  const games = t.dir('proj-games');
263
407
  t.dir('proj-games', 'assets');
264
- f.writeLocal(games, { sandbox: { vGpu: true }, mappings: [{ host: 'assets', guest: 'F:\\GameAssets', readOnly: true }] });
408
+ f.writeLocal(games, {
409
+ sandbox: { vGpu: true },
410
+ mappings: [{ host: 'assets', guest: 'F:\\GameAssets', readOnly: true }],
411
+ });
265
412
  saveAllowed(allowStorePath(f.baseConfig.storage.root), path.join(games, '.sandbox-config.json'), 'sandbox.vGpu', true, true);
266
413
  const gamesRun = await f.run({ cwd: games, trustConfig: true });
267
414
  t.equal(gamesRun.config.sandbox.vGpu, true, 'the vGPU you allowed for the project is in its effective config');
268
415
  const launchedRun = await f.run();
269
- const runningBoot = { memoryMb: 8192, mappings: [{ host: f.workA, guest: 'C:\\Workspace\\work-a', readOnly: false }] };
416
+ const runningBoot = {
417
+ memoryMb: 8192,
418
+ mappings: [{ host: f.workA, guest: 'C:\\Workspace\\work-a', readOnly: false }],
419
+ };
270
420
  const wanted = missingAtBoot(protectionsOf(launchedRun.config), runningBoot, gamesRun.config, fs.existsSync);
271
- t.equal({ settings: wanted.settings, memoryMb: wanted.memoryMb, mappings: wanted.mappings.map((m) => m.guest) }, { settings: ['sandbox.vGpu'], memoryMb: null, mappings: ['F:\\GameAssets'] }, 'missingAtBoot: vGPU and the project\'s folder are missing from a sandbox started without them (the missing optional mapping is no wish)');
272
- const mappedMirror = missingAtBoot(protectionsOf(gamesRun.config), { memoryMb: 8192, mappings: [{ host: path.join(games, 'assets'), guest: 'C:\\Mirror\\F\\GameAssets', readOnly: true }] }, gamesRun.config, fs.existsSync);
421
+ t.equal({ settings: wanted.settings, memoryMb: wanted.memoryMb, mappings: wanted.mappings.map((m) => m.guest) }, { settings: ['sandbox.vGpu'], memoryMb: null, mappings: ['F:\\GameAssets'] }, "missingAtBoot: vGPU and the project's folder are missing from a sandbox started without them (the missing optional mapping is no wish)");
422
+ const mappedMirror = missingAtBoot(protectionsOf(gamesRun.config), {
423
+ memoryMb: 8192,
424
+ mappings: [{ host: path.join(games, 'assets'), guest: 'C:\\Mirror\\F\\GameAssets', readOnly: true }],
425
+ }, gamesRun.config, fs.existsSync);
273
426
  t.check(nothingMissing(mappedMirror), 'missingAtBoot: nothing missing when the sandbox has vGPU and the folder (F:\\x is C:\\Mirror\\F\\x in the .wsb)', JSON.stringify(mappedMirror));
274
427
  const bigger = structuredClone(launchedRun.config);
275
428
  bigger.sandbox.memoryMb = 16384;
276
429
  t.equal(missingAtBoot(protectionsOf(launchedRun.config), runningBoot, bigger).memoryMb, 16384, 'missingAtBoot: a larger fixed memory size is missing too');
277
- const twoFolders = { settings: ['sandbox.vGpu'], memoryMb: null, mappings: [{ host: 'C:\\Steam\\common', guest: 'C:\\Steam', readOnly: true }, { host: 'F:\\SteamLibrary', guest: 'F:\\SteamLibrary', readOnly: true }] };
430
+ const twoFolders = {
431
+ settings: ['sandbox.vGpu'],
432
+ memoryMb: null,
433
+ mappings: [
434
+ { host: 'C:\\Steam\\common', guest: 'C:\\Steam', readOnly: true },
435
+ { host: 'F:\\SteamLibrary', guest: 'F:\\SteamLibrary', readOnly: true },
436
+ ],
437
+ };
278
438
  t.equal(describeMissing('mw2-agent', twoFolders), 'mw2-agent wants vGPU and 2 folders (C:\\Steam\\common, F:\\SteamLibrary), but this sandbox started without them.', 'the message names each missing item');
279
439
  t.equal(missingTip(twoFolders), 'Set sandbox.vGpu (or the mappings) in your own settings to have them in every sandbox.', 'the tip names the settings');
280
440
  t.equal(describeMissing('api', { settings: ['sandbox.vGpu'], memoryMb: null, mappings: [] }), 'api wants vGPU, but this sandbox started without it.', 'one item reads naturally');
@@ -285,25 +445,60 @@ export const projectsSuite = {
285
445
  // joinRunning asks before anything is registered: restart (NeedsRestart with what is missing), or continue without.
286
446
  const storage2 = t.dir('proj-storage2');
287
447
  const data2 = t.dir('proj-storage2', 'data', 'testdata');
288
- startRegistry(storage2, { launchId: '1700000000001-abcdef', protections: protectionsOf(launchedRun.config), primary: { host: f.workA, guest: 'C:\\Workspace\\work-a' }, roots: [{ host: path.dirname(games), guest: 'C:\\Projects\\temp' }], boot: [], atBoot: { ...runningBoot, widened: {} } });
289
- const joinGames = (choice) => joinRunning({ storageRoot: storage2, dataPath: data2, packageRoot: f.install, hostDir: games, wsbShare: false, resolve: resolveFor(gamesRun), decide: async () => choice });
448
+ new ProjectRegistry(storage2).start({
449
+ launchId: '1700000000001-abcdef',
450
+ protections: protectionsOf(launchedRun.config),
451
+ primary: { host: f.workA, guest: 'C:\\Workspace\\work-a' },
452
+ roots: [{ host: path.dirname(games), guest: 'C:\\Projects\\temp' }],
453
+ boot: [],
454
+ atBoot: { ...runningBoot, widened: {} },
455
+ });
456
+ const joinGames = (choice) => joinRunning({
457
+ storageRoot: storage2,
458
+ dataPath: data2,
459
+ packageRoot: f.install,
460
+ hostDir: games,
461
+ wsbShare: false,
462
+ resolve: resolveFor(gamesRun),
463
+ decide: async () => choice,
464
+ });
290
465
  const restartFor = await joinGames('restart').then(() => null, (e) => e);
291
- t.check(restartFor instanceof NeedsRestart && restartFor.missing?.settings.includes('sandbox.vGpu') === true && restartFor.missing.mappings.length === 1, 'choosing "Restart with them" hands the restart offer what is missing');
466
+ t.check(restartFor instanceof NeedsRestart &&
467
+ restartFor.missing?.settings.includes('sandbox.vGpu') === true &&
468
+ restartFor.missing.mappings.length === 1, 'choosing "Restart with them" hands the restart offer what is missing');
292
469
  await t.throws(() => joinGames('cancel'), 'Cancelled', '"Cancel" stops with a short line');
293
- t.check(!readRegistry(storage2)?.projects.some((p) => p.host === games), 'neither registers the project');
470
+ t.check(!new ProjectRegistry(storage2).read()?.projects.some((p) => p.host === games), 'neither registers the project');
294
471
  const continued = await joinGames('continue');
295
472
  t.equal(continued.missing?.settings, ['sandbox.vGpu'], '"Continue anyway" joins without them and says what is missing');
296
473
  // The restart that adds it (and any launch with it mapped at boot) boots with the union.
297
- const unionGen = generateSandbox({ packageRoot: t.packageRoot, run: launchedRun, harnessArgs: [], probe: f.probe, extraProjects: [games], autoSession: false, bootWants: { projects: [{ name: 'proj-games', config: gamesRun.config }], keepOff: [] } });
474
+ const unionGen = generateSandbox({
475
+ packageRoot: t.packageRoot,
476
+ run: launchedRun,
477
+ harnessArgs: [],
478
+ probe: f.probe,
479
+ extraProjects: [games],
480
+ autoSession: false,
481
+ bootWants: { projects: [{ name: 'proj-games', config: gamesRun.config }], keepOff: [] },
482
+ });
298
483
  const unionWsb = fs.readFileSync(unionGen.wsbPath, 'utf8');
299
484
  t.includes(unionWsb, '<vGPU>Enable</vGPU>', 'the restart plan: vGPU on because the added project asks for it (and you allowed it)');
300
- t.includes(unionWsb, '<HostFolder>' + path.join(games, 'assets') + '</HostFolder><SandboxFolder>C:\\Mirror\\F\\GameAssets</SandboxFolder><ReadOnly>true</ReadOnly>', 'the restart plan: the added project\'s mapping is mapped');
485
+ t.includes(unionWsb, '<HostFolder>' +
486
+ path.join(games, 'assets') +
487
+ '</HostFolder><SandboxFolder>C:\\Mirror\\F\\GameAssets</SandboxFolder><ReadOnly>true</ReadOnly>', "the restart plan: the added project's mapping is mapped");
301
488
  t.includes(unionWsb, '<HostFolder>' + games + '</HostFolder><SandboxFolder>C:\\Workspace\\proj-games</SandboxFolder>', 'the restart plan: the added project itself is mapped (where it is as the launch folder)');
302
489
  t.equal(unionGen.widened, { 'sandbox.vGpu': 'proj-games' }, 'the registry learns which boot setting was turned on for which project');
303
490
  t.check(unionGen.projects.notes.some((n) => n.startsWith('vGPU is on in this sandbox')), 'the launch says vGPU is on for every project and why', JSON.stringify(unionGen.projects.notes));
304
491
  t.check(nothingMissing(missingAtBoot(protectionsOf(unionGen.bootConfig), { memoryMb: unionGen.memoryMb, mappings: unionGen.mappings }, gamesRun.config, fs.existsSync)), 'after that restart the project joins with nothing missing');
305
- const keptOff = generateSandbox({ packageRoot: t.packageRoot, run: launchedRun, harnessArgs: [], probe: f.probe, extraProjects: [games], autoSession: false, bootWants: { projects: [{ name: 'proj-games', config: gamesRun.config }], keepOff: ['sandbox.vGpu'] } });
306
- t.includes(fs.readFileSync(keptOff.wsbPath, 'utf8'), '<vGPU>Disable</vGPU>', 'a device the launch folder\'s own file switched off stays off');
492
+ const keptOff = generateSandbox({
493
+ packageRoot: t.packageRoot,
494
+ run: launchedRun,
495
+ harnessArgs: [],
496
+ probe: f.probe,
497
+ extraProjects: [games],
498
+ autoSession: false,
499
+ bootWants: { projects: [{ name: 'proj-games', config: gamesRun.config }], keepOff: ['sandbox.vGpu'] },
500
+ });
501
+ t.includes(fs.readFileSync(keptOff.wsbPath, 'utf8'), '<vGPU>Disable</vGPU>', "a device the launch folder's own file switched off stays off");
307
502
  t.includes(fs.readFileSync(f.generate(launchedRun).wsbPath, 'utf8'), '<vGPU>Disable</vGPU>', 'without other projects nothing changes');
308
503
  t.section('projects: wsb (Windows Sandbox command line) adapter');
309
504
  t.equal([parseVersion('Windows Sandbox CLI version 0.4.1.0\n'), parseVersion('nothing')], ['0.4.1.0', null], 'wsb --version');
@@ -1,2 +1,2 @@
1
- import type { Suite } from './suite.js';
1
+ import type { Suite } from './support/suite.js';
2
2
  export declare const repairSuite: Suite;
@@ -1,6 +1,6 @@
1
1
  // `sandbox repair`: finding half-installed toolchains, interrupted downloads, stale pid files and broken state.
2
2
  import path from 'node:path';
3
- import { deadPidFiles, findHalfInstalled, findStagingLeftovers, globalPackages, resolvedVersionsValid } from '../cli/commands/repair/finders.js';
3
+ import { deadPidFiles, findHalfInstalled, findStagingLeftovers, globalPackages, resolvedVersionsValid, } from '../cli/commands/repair/finders.js';
4
4
  export const repairSuite = {
5
5
  name: 'repair',
6
6
  title: 'repair detection (half-installed tools, leftovers, stale pids)',
@@ -20,10 +20,20 @@ export const repairSuite = {
20
20
  t.dir('repair', 'tools', 'go', '1.24.0.staging-ab12cd');
21
21
  t.dir('repair', 'tools', 'node-staging');
22
22
  t.dir('repair', 'tools', 'rust.staging-0f');
23
- const half = findHalfInstalled(tools).map((h) => path.relative(tools, h.path)).sort();
24
- const expectedHalf = [path.join('go', '1.22.8'), path.join('java', 'jdk-17'), 'dotnet', 'nvm', path.join('nvm', 'v20.18.0')].sort();
23
+ const half = findHalfInstalled(tools)
24
+ .map((h) => path.relative(tools, h.path))
25
+ .sort();
26
+ const expectedHalf = [
27
+ path.join('go', '1.22.8'),
28
+ path.join('java', 'jdk-17'),
29
+ 'dotnet',
30
+ 'nvm',
31
+ path.join('nvm', 'v20.18.0'),
32
+ ].sort();
25
33
  t.equal(half, expectedHalf, 'half-installed toolchains are folders without their program');
26
- const leftovers = findStagingLeftovers(tools).map((p) => path.relative(tools, p)).sort();
34
+ const leftovers = findStagingLeftovers(tools)
35
+ .map((p) => path.relative(tools, p))
36
+ .sort();
27
37
  t.equal(leftovers, [path.join('go', '1.24.0.staging-ab12cd'), 'node-staging', 'rust.staging-0f'].sort(), 'interrupted downloads are found in tools and one level down');
28
38
  t.section('state files');
29
39
  t.check(resolvedVersionsValid('{"go":"1.23.2"}') && resolvedVersionsValid('{}'), 'resolved-versions.json: a JSON object is valid (a byte-order mark is fine)');
@@ -36,7 +46,9 @@ export const repairSuite = {
36
46
  t.write(path.join(run, 'watcher-other.pid'), String(process.pid));
37
47
  t.write(path.join(run, 'watcher-junk.pid'), 'not a pid');
38
48
  t.write(path.join(run, 'hidden-windows.json'), '[]');
39
- const dead = deadPidFiles(run, (pid) => pid === process.pid).map((file) => path.basename(file)).sort();
49
+ const dead = deadPidFiles(run, (pid) => pid === process.pid)
50
+ .map((file) => path.basename(file))
51
+ .sort();
40
52
  t.equal(dead, ['watcher-default.pid', 'watcher-junk.pid'], 'stale watcher pid files (dead process or junk) are found; a live one is kept');
41
53
  },
42
54
  };
@@ -1,2 +1,2 @@
1
- import type { Suite } from './suite.js';
1
+ import type { Suite } from './support/suite.js';
2
2
  export declare const repoGuardSuite: Suite;