windows-development-sandbox 1.5.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (709) hide show
  1. package/README.md +1 -0
  2. package/config.example.json +27 -1
  3. package/dist/app/context.d.ts +8 -0
  4. package/dist/app/context.js +12 -0
  5. package/dist/app/features/defs.d.ts +322 -0
  6. package/dist/app/features/defs.js +28 -0
  7. package/dist/app/features/sandbox/index.d.ts +2 -0
  8. package/dist/app/features/sandbox/index.js +3 -0
  9. package/dist/app/features/sandbox/sandbox.def.d.ts +193 -0
  10. package/dist/app/features/sandbox/sandbox.def.js +245 -0
  11. package/dist/app/features/sandbox/sandbox.run.d.ts +72 -0
  12. package/dist/app/features/sandbox/sandbox.run.js +98 -0
  13. package/dist/app/features/sessions/index.d.ts +2 -0
  14. package/dist/app/features/sessions/index.js +3 -0
  15. package/dist/app/features/sessions/sessions.def.d.ts +141 -0
  16. package/dist/app/features/sessions/sessions.def.js +176 -0
  17. package/dist/app/features/sessions/sessions.run.d.ts +39 -0
  18. package/dist/app/features/sessions/sessions.run.js +58 -0
  19. package/dist/{cli/menu/settings/categories.d.ts → app/features/settings/categories.def.d.ts} +4 -0
  20. package/dist/{cli/menu/settings/categories.js → app/features/settings/categories.def.js} +40 -46
  21. package/dist/app/features/settings/index.d.ts +5 -0
  22. package/dist/app/features/settings/index.js +6 -0
  23. package/dist/{cli/menu/settings/config-file.d.ts → app/features/settings/settings-file.d.ts} +1 -1
  24. package/dist/{cli/menu/settings/config-file.js → app/features/settings/settings-file.js} +1 -1
  25. package/dist/app/features/settings/settings-rows.d.ts +35 -0
  26. package/dist/app/features/settings/settings-rows.js +94 -0
  27. package/dist/app/features/settings/settings.def.d.ts +157 -0
  28. package/dist/app/features/settings/settings.def.js +179 -0
  29. package/dist/app/features/settings/settings.run.d.ts +67 -0
  30. package/dist/app/features/settings/settings.run.js +84 -0
  31. package/dist/app/kernel/define.d.ts +143 -0
  32. package/dist/app/kernel/define.js +42 -0
  33. package/dist/app/kernel/errors.d.ts +34 -0
  34. package/dist/app/kernel/errors.js +45 -0
  35. package/dist/app/kernel/fields.d.ts +70 -0
  36. package/dist/app/kernel/fields.js +243 -0
  37. package/dist/app/kernel/index.d.ts +8 -0
  38. package/dist/app/kernel/index.js +10 -0
  39. package/dist/app/kernel/io.d.ts +193 -0
  40. package/dist/app/kernel/io.js +126 -0
  41. package/dist/app/kernel/rpc.d.ts +156 -0
  42. package/dist/app/kernel/rpc.js +47 -0
  43. package/dist/{cli/menu/settings → app/kernel}/schema-node.d.ts +9 -0
  44. package/dist/{cli/menu/settings → app/kernel}/schema-node.js +26 -0
  45. package/dist/app/kernel/text.d.ts +6 -0
  46. package/dist/app/kernel/text.js +57 -0
  47. package/dist/app/kernel/view.d.ts +146 -0
  48. package/dist/app/kernel/view.js +28 -0
  49. package/dist/app/registry.d.ts +10 -0
  50. package/dist/app/registry.js +50 -0
  51. package/dist/cli/args.d.ts +18 -2
  52. package/dist/cli/args.js +101 -24
  53. package/dist/cli/commands/accounts.js +45 -17
  54. package/dist/cli/commands/context.d.ts +2 -0
  55. package/dist/cli/commands/context.js +9 -2
  56. package/dist/cli/commands/data/clean.js +32 -9
  57. package/dist/cli/commands/engine.d.ts +2 -0
  58. package/dist/cli/commands/engine.js +60 -0
  59. package/dist/cli/commands/index.d.ts +2 -1
  60. package/dist/cli/commands/index.js +2 -1
  61. package/dist/cli/commands/launch/add-root.d.ts +3 -2
  62. package/dist/cli/commands/launch/add-root.js +11 -10
  63. package/dist/cli/commands/launch/launch.js +102 -9
  64. package/dist/cli/commands/launch/prepare.js +6 -4
  65. package/dist/cli/commands/launch/running.js +2 -1
  66. package/dist/cli/commands/launch/summary.d.ts +2 -0
  67. package/dist/cli/commands/maintenance/audit.js +1 -1
  68. package/dist/cli/commands/maintenance/clean.d.ts +1 -1
  69. package/dist/cli/commands/maintenance/clean.js +17 -3
  70. package/dist/cli/commands/maintenance/config-share.d.ts +12 -0
  71. package/dist/cli/commands/maintenance/config-share.js +80 -0
  72. package/dist/cli/commands/maintenance/config.d.ts +1 -1
  73. package/dist/cli/commands/maintenance/config.js +38 -10
  74. package/dist/cli/commands/maintenance/doctor.d.ts +1 -1
  75. package/dist/cli/commands/maintenance/doctor.js +2 -4
  76. package/dist/cli/commands/maintenance/logs.js +14 -0
  77. package/dist/cli/commands/maintenance/migrate.d.ts +2 -1
  78. package/dist/cli/commands/maintenance/migrate.js +19 -4
  79. package/dist/cli/commands/maintenance/sync.js +2 -0
  80. package/dist/cli/commands/maintenance/update.d.ts +2 -0
  81. package/dist/cli/commands/maintenance/update.js +27 -4
  82. package/dist/cli/commands/projects/here.js +12 -7
  83. package/dist/cli/commands/projects/projects.js +26 -17
  84. package/dist/cli/commands/registry.js +10 -7
  85. package/dist/cli/commands/repair/checks/agents.d.ts +2 -0
  86. package/dist/cli/commands/repair/checks/agents.js +70 -0
  87. package/dist/cli/commands/repair/checks/common.d.ts +8 -0
  88. package/dist/cli/commands/repair/checks/common.js +22 -0
  89. package/dist/cli/commands/repair/checks/contained.d.ts +2 -0
  90. package/dist/cli/commands/repair/checks/contained.js +139 -0
  91. package/dist/cli/commands/repair/checks/data.d.ts +2 -0
  92. package/dist/cli/commands/repair/checks/data.js +241 -0
  93. package/dist/cli/commands/repair/checks/hcs.d.ts +7 -0
  94. package/dist/cli/commands/repair/checks/hcs.js +28 -0
  95. package/dist/cli/commands/repair/checks/index.d.ts +2 -0
  96. package/dist/cli/commands/repair/checks/index.js +24 -0
  97. package/dist/cli/commands/repair/checks/install.d.ts +5 -0
  98. package/dist/cli/commands/repair/checks/install.js +318 -0
  99. package/dist/cli/commands/repair/checks/machine.d.ts +2 -0
  100. package/dist/cli/commands/repair/checks/machine.js +232 -0
  101. package/dist/cli/commands/repair/checks/network.d.ts +6 -0
  102. package/dist/cli/commands/repair/checks/network.js +60 -0
  103. package/dist/cli/commands/repair/checks/pc.d.ts +4 -0
  104. package/dist/cli/commands/repair/checks/pc.js +86 -0
  105. package/dist/cli/commands/repair/checks/sandbox.d.ts +2 -0
  106. package/dist/cli/commands/repair/checks/sandbox.js +282 -0
  107. package/dist/cli/commands/repair/checks/settings.d.ts +2 -0
  108. package/dist/cli/commands/repair/checks/settings.js +169 -0
  109. package/dist/cli/commands/repair/checks/vpn.d.ts +2 -0
  110. package/dist/cli/commands/repair/checks/vpn.js +78 -0
  111. package/dist/cli/commands/repair/engine.d.ts +32 -0
  112. package/dist/cli/commands/repair/engine.js +127 -0
  113. package/dist/cli/commands/repair/env.d.ts +7 -0
  114. package/dist/cli/commands/repair/env.js +50 -0
  115. package/dist/cli/commands/repair/index.d.ts +1 -9
  116. package/dist/cli/commands/repair/index.js +2 -54
  117. package/dist/cli/commands/repair/log.d.ts +17 -0
  118. package/dist/cli/commands/repair/log.js +82 -0
  119. package/dist/cli/commands/repair/printer.d.ts +32 -0
  120. package/dist/cli/commands/repair/printer.js +132 -0
  121. package/dist/cli/commands/repair/run.d.ts +33 -0
  122. package/dist/cli/commands/repair/run.js +133 -0
  123. package/dist/cli/commands/repair/types.d.ts +97 -9
  124. package/dist/cli/commands/repair/types.js +11 -7
  125. package/dist/cli/commands/resume.js +2 -2
  126. package/dist/cli/commands/sessions/index.d.ts +0 -4
  127. package/dist/cli/commands/sessions/index.js +3 -7
  128. package/dist/cli/commands/setup/index.d.ts +5 -0
  129. package/dist/cli/commands/setup/index.js +25 -1
  130. package/dist/cli/commands/shared-use.d.ts +5 -2
  131. package/dist/cli/commands/shared-use.js +11 -8
  132. package/dist/cli/commands/storage/contained.d.ts +3 -0
  133. package/dist/cli/commands/storage/contained.js +179 -0
  134. package/dist/cli/commands/storage/index.d.ts +2 -0
  135. package/dist/cli/commands/storage/index.js +2 -0
  136. package/dist/cli/commands/storage/offer.d.ts +3 -0
  137. package/dist/cli/commands/storage/offer.js +91 -0
  138. package/dist/cli/commands/storage/storage.d.ts +8 -0
  139. package/dist/cli/commands/storage/storage.js +179 -0
  140. package/dist/cli/commands/user-config.js +2 -2
  141. package/dist/cli/commands/vpn.d.ts +4 -0
  142. package/dist/cli/commands/vpn.js +91 -0
  143. package/dist/cli/commands/web.d.ts +4 -0
  144. package/dist/cli/commands/web.js +97 -0
  145. package/dist/cli/history.js +1 -1
  146. package/dist/cli/index.js +48 -4
  147. package/dist/cli/manifest.d.ts +339 -97
  148. package/dist/cli/manifest.js +222 -67
  149. package/dist/cli/menu/add-agent.d.ts +47 -0
  150. package/dist/cli/menu/add-agent.js +168 -0
  151. package/dist/cli/menu/apps.d.ts +38 -3
  152. package/dist/cli/menu/apps.js +80 -5
  153. package/dist/cli/menu/command-fields.d.ts +18 -0
  154. package/dist/cli/menu/command-fields.js +61 -0
  155. package/dist/cli/menu/command-form.d.ts +22 -0
  156. package/dist/cli/menu/command-form.js +169 -46
  157. package/dist/cli/menu/data-folder.d.ts +18 -0
  158. package/dist/cli/menu/data-folder.js +99 -0
  159. package/dist/cli/menu/io-menu.d.ts +29 -0
  160. package/dist/cli/menu/io-menu.js +126 -0
  161. package/dist/cli/menu/live.d.ts +27 -0
  162. package/dist/cli/menu/live.js +69 -0
  163. package/dist/cli/menu/memory.d.ts +19 -0
  164. package/dist/cli/menu/memory.js +53 -0
  165. package/dist/cli/menu/menu.d.ts +11 -2
  166. package/dist/cli/menu/menu.js +36 -15
  167. package/dist/cli/menu/pages/accounts-page.js +55 -24
  168. package/dist/cli/menu/pages/agents-page.d.ts +68 -0
  169. package/dist/cli/menu/pages/agents-page.js +345 -0
  170. package/dist/cli/menu/pages/apps-page.d.ts +3 -1
  171. package/dist/cli/menu/pages/apps-page.js +20 -4
  172. package/dist/cli/menu/pages/list-page.d.ts +43 -3
  173. package/dist/cli/menu/pages/list-page.js +146 -12
  174. package/dist/cli/menu/pages/maintenance-page.d.ts +9 -5
  175. package/dist/cli/menu/pages/maintenance-page.js +172 -85
  176. package/dist/cli/menu/pages/sandbox-page.d.ts +7 -6
  177. package/dist/cli/menu/pages/sandbox-page.js +117 -120
  178. package/dist/cli/menu/pages/scopes.d.ts +1 -1
  179. package/dist/cli/menu/pages/sessions-page.d.ts +6 -8
  180. package/dist/cli/menu/pages/sessions-page.js +22 -75
  181. package/dist/cli/menu/pages/settings-page.d.ts +10 -14
  182. package/dist/cli/menu/pages/settings-page.js +95 -102
  183. package/dist/cli/menu/render-view.d.ts +28 -0
  184. package/dist/cli/menu/render-view.js +112 -0
  185. package/dist/cli/menu/settings/ask-path.d.ts +14 -0
  186. package/dist/cli/menu/settings/ask-path.js +14 -0
  187. package/dist/cli/menu/settings/collections/collection-editor.d.ts +8 -2
  188. package/dist/cli/menu/settings/collections/collection-editor.js +12 -8
  189. package/dist/cli/menu/settings/collections/map-editor.js +5 -1
  190. package/dist/cli/menu/settings/collections/object-list-editor.js +2 -2
  191. package/dist/cli/menu/settings/collections/object-map-editor.js +2 -2
  192. package/dist/cli/menu/settings/collections/string-list-editor.d.ts +10 -1
  193. package/dist/cli/menu/settings/collections/string-list-editor.js +23 -0
  194. package/dist/cli/menu/settings/draft.d.ts +1 -1
  195. package/dist/cli/menu/settings/format.d.ts +1 -3
  196. package/dist/cli/menu/settings/format.js +6 -36
  197. package/dist/cli/menu/settings/index.d.ts +1 -3
  198. package/dist/cli/menu/settings/index.js +3 -3
  199. package/dist/cli/menu/settings/object-editor.d.ts +6 -2
  200. package/dist/cli/menu/settings/object-editor.js +15 -4
  201. package/dist/cli/menu/settings/share.d.ts +36 -0
  202. package/dist/cli/menu/settings/share.js +131 -0
  203. package/dist/cli/menu/settings/value-editor.d.ts +10 -1
  204. package/dist/cli/menu/settings/value-editor.js +99 -63
  205. package/dist/cli/menu/several.js +7 -5
  206. package/dist/cli/menu/share-settings.d.ts +21 -0
  207. package/dist/cli/menu/share-settings.js +112 -0
  208. package/dist/cli/menu/shell.d.ts +53 -10
  209. package/dist/cli/menu/shell.js +115 -10
  210. package/dist/cli/menu/views.d.ts +7 -0
  211. package/dist/cli/menu/views.js +11 -0
  212. package/dist/cli/menu/vpn-login.d.ts +16 -0
  213. package/dist/cli/menu/vpn-login.js +74 -0
  214. package/dist/cli/operations/handler.d.ts +6 -0
  215. package/dist/cli/operations/handler.js +61 -0
  216. package/dist/cli/operations/index.d.ts +4 -0
  217. package/dist/cli/operations/index.js +5 -0
  218. package/dist/cli/operations/input.d.ts +6 -0
  219. package/dist/cli/operations/input.js +37 -0
  220. package/dist/cli/operations/io-cli.d.ts +7 -0
  221. package/dist/cli/operations/io-cli.js +62 -0
  222. package/dist/cli/operations/spec.d.ts +18 -0
  223. package/dist/cli/operations/spec.js +108 -0
  224. package/dist/cli/output/colors.d.ts +2 -2
  225. package/dist/cli/output/colors.js +2 -11
  226. package/dist/cli/output/index.d.ts +1 -0
  227. package/dist/cli/output/index.js +1 -0
  228. package/dist/cli/output/print.d.ts +5 -1
  229. package/dist/cli/output/print.js +15 -4
  230. package/dist/cli/output/progress.d.ts +15 -0
  231. package/dist/cli/output/progress.js +44 -0
  232. package/dist/cli/output/render-view.d.ts +4 -0
  233. package/dist/cli/output/render-view.js +63 -0
  234. package/dist/cli/services/accounts-service.d.ts +2 -0
  235. package/dist/cli/services/accounts-service.js +2 -2
  236. package/dist/cli/services/agent-commands-service.d.ts +2 -0
  237. package/dist/cli/services/agent-commands-service.js +11 -2
  238. package/dist/cli/services/health-service.d.ts +0 -6
  239. package/dist/cli/services/health-service.js +5 -42
  240. package/dist/cli/services/index.d.ts +3 -1
  241. package/dist/cli/services/index.js +3 -1
  242. package/dist/cli/services/logs-service.js +4 -3
  243. package/dist/cli/services/migrate-service.js +1 -1
  244. package/dist/cli/services/update-service.d.ts +2 -0
  245. package/dist/cli/services/update-service.js +13 -6
  246. package/dist/cli/services/vpn-service.d.ts +28 -0
  247. package/dist/cli/services/vpn-service.js +46 -0
  248. package/dist/cli/services/web-service.d.ts +22 -0
  249. package/dist/cli/services/web-service.js +111 -0
  250. package/dist/cli/tui/app.d.ts +12 -4
  251. package/dist/cli/tui/app.js +38 -9
  252. package/dist/cli/tui/dialogs/path-listing.d.ts +43 -0
  253. package/dist/cli/tui/dialogs/path-listing.js +127 -0
  254. package/dist/cli/tui/dialogs/path-picker.d.ts +67 -0
  255. package/dist/cli/tui/dialogs/path-picker.js +423 -0
  256. package/dist/cli/tui/dialogs/text-screen.d.ts +6 -0
  257. package/dist/cli/tui/dialogs/text-screen.js +10 -3
  258. package/dist/cli/tui/frame.d.ts +7 -10
  259. package/dist/cli/tui/frame.js +19 -10
  260. package/dist/cli/tui/index.d.ts +4 -3
  261. package/dist/cli/tui/index.js +2 -1
  262. package/dist/cli/tui/list/list-screen.d.ts +28 -2
  263. package/dist/cli/tui/list/list-screen.js +130 -66
  264. package/dist/cli/tui/list/list-types.d.ts +10 -4
  265. package/dist/cli/tui/nav.d.ts +29 -0
  266. package/dist/cli/tui/nav.js +67 -0
  267. package/dist/cli/tui/terminal.d.ts +7 -0
  268. package/dist/cli/tui/terminal.js +30 -10
  269. package/dist/cli/validate.d.ts +1 -1
  270. package/dist/cli/validate.js +3 -3
  271. package/dist/cli/version.d.ts +2 -0
  272. package/dist/cli/version.js +11 -0
  273. package/dist/core/config/defaults.js +13 -1
  274. package/dist/core/config/loader.js +12 -2
  275. package/dist/core/local-config/overrides.js +1 -0
  276. package/dist/core/prompt.d.ts +19 -0
  277. package/dist/core/prompt.js +43 -3
  278. package/dist/core/schema/common.d.ts +6 -0
  279. package/dist/core/schema/common.js +8 -0
  280. package/dist/core/schema/config.d.ts +36 -0
  281. package/dist/core/schema/config.js +26 -2
  282. package/dist/core/schema/harness.d.ts +2 -0
  283. package/dist/core/schema/harness.js +13 -2
  284. package/dist/core/schema/index.d.ts +3 -1
  285. package/dist/core/schema/index.js +3 -1
  286. package/dist/core/schema/profile.d.ts +1 -0
  287. package/dist/core/schema/profile.js +3 -0
  288. package/dist/core/schema/redact.d.ts +13 -0
  289. package/dist/core/schema/redact.js +75 -0
  290. package/dist/core/schema/sandbox.d.ts +6 -0
  291. package/dist/core/schema/sandbox.js +21 -3
  292. package/dist/core/schema/vpn.d.ts +18 -0
  293. package/dist/core/schema/vpn.js +22 -0
  294. package/dist/core/schema/web.d.ts +6 -0
  295. package/dist/core/schema/web.js +14 -0
  296. package/dist/core/types.d.ts +44 -0
  297. package/dist/core/util/fs.d.ts +2 -0
  298. package/dist/core/util/fs.js +9 -0
  299. package/dist/core/util/index.d.ts +1 -1
  300. package/dist/core/util/index.js +1 -1
  301. package/dist/guest/agents/agent-files.d.ts +54 -0
  302. package/dist/guest/agents/agent-files.js +67 -0
  303. package/dist/guest/agents/agent-installer.js +2 -9
  304. package/dist/guest/agents/local-state.d.ts +14 -0
  305. package/dist/guest/agents/local-state.js +218 -0
  306. package/dist/guest/agents/sbx-agent.d.ts +2 -0
  307. package/dist/guest/agents/sbx-agent.js +35 -0
  308. package/dist/guest/boot/boot.d.ts +4 -0
  309. package/dist/guest/boot/boot.js +51 -11
  310. package/dist/guest/daemon/daemon.js +8 -1
  311. package/dist/guest/daemon/exec.js +2 -1
  312. package/dist/guest/daemon/idle-shutdown.js +2 -0
  313. package/dist/guest/daemon/sessions.d.ts +5 -0
  314. package/dist/guest/daemon/sessions.js +20 -3
  315. package/dist/guest/entries/agent.d.ts +1 -0
  316. package/dist/guest/entries/agent.js +10 -0
  317. package/dist/guest/entries/daemon.js +5 -0
  318. package/dist/guest/governor/decide.d.ts +61 -0
  319. package/dist/guest/governor/decide.js +182 -0
  320. package/dist/guest/governor/governor.d.ts +42 -0
  321. package/dist/guest/governor/governor.js +214 -0
  322. package/dist/guest/governor/index.d.ts +2 -0
  323. package/dist/guest/governor/index.js +2 -0
  324. package/dist/guest/runtime/csc.d.ts +2 -0
  325. package/dist/guest/runtime/csc.js +2 -0
  326. package/dist/guest/runtime/secrets.d.ts +12 -0
  327. package/dist/guest/runtime/secrets.js +63 -0
  328. package/dist/guest/sessions/viewer.js +3 -1
  329. package/dist/guest/setup/claude-profile.d.ts +2 -1
  330. package/dist/guest/setup/claude-profile.js +12 -1
  331. package/dist/guest/setup/environment.d.ts +6 -0
  332. package/dist/guest/setup/environment.js +56 -6
  333. package/dist/guest/setup/path-plan.d.ts +32 -0
  334. package/dist/guest/setup/path-plan.js +67 -0
  335. package/dist/guest/setup/shell-path.d.ts +1 -0
  336. package/dist/guest/setup/shell-path.js +22 -0
  337. package/dist/guest/toolchains/languages/python.js +1 -1
  338. package/dist/guest/toolchains/native/rust-extras.js +4 -2
  339. package/dist/guest/toolchains/runtimes.js +2 -2
  340. package/dist/guest/vpn/index.d.ts +1 -0
  341. package/dist/guest/vpn/index.js +1 -0
  342. package/dist/guest/vpn/openvpn.d.ts +9 -0
  343. package/dist/guest/vpn/openvpn.js +47 -0
  344. package/dist/guest/vpn/tunnel.d.ts +17 -0
  345. package/dist/guest/vpn/tunnel.js +78 -0
  346. package/dist/guest/vpn/vpn.d.ts +6 -0
  347. package/dist/guest/vpn/vpn.js +174 -0
  348. package/dist/guest/vpn/wireguard.d.ts +32 -0
  349. package/dist/guest/vpn/wireguard.js +132 -0
  350. package/dist/host/agent-commands/commands.d.ts +4 -0
  351. package/dist/host/agent-commands/commands.js +31 -7
  352. package/dist/host/audit/log.d.ts +1 -1
  353. package/dist/host/channel/attach.d.ts +6 -2
  354. package/dist/host/channel/attach.js +6 -3
  355. package/dist/host/channel/channel.d.ts +9 -0
  356. package/dist/host/channel/channel.js +30 -2
  357. package/dist/host/engines/engine.d.ts +12 -0
  358. package/dist/host/engines/engine.js +1 -0
  359. package/dist/host/engines/hcs/check.d.ts +25 -0
  360. package/dist/host/engines/hcs/check.js +95 -0
  361. package/dist/host/engines/hcs/documents.d.ts +44 -0
  362. package/dist/host/engines/hcs/documents.js +155 -0
  363. package/dist/host/engines/hcs/engine.d.ts +39 -0
  364. package/dist/host/engines/hcs/engine.js +171 -0
  365. package/dist/host/engines/hcs/helper.d.ts +43 -0
  366. package/dist/host/engines/hcs/helper.js +173 -0
  367. package/dist/host/engines/hcs/images.d.ts +37 -0
  368. package/dist/host/engines/hcs/images.js +152 -0
  369. package/dist/host/engines/index.d.ts +7 -0
  370. package/dist/host/engines/index.js +5 -0
  371. package/dist/host/engines/registry.d.ts +16 -0
  372. package/dist/host/engines/registry.js +30 -0
  373. package/dist/host/engines/types.d.ts +58 -0
  374. package/dist/host/engines/types.js +1 -0
  375. package/dist/host/engines/windows-sandbox/engine.d.ts +16 -0
  376. package/dist/host/engines/windows-sandbox/engine.js +63 -0
  377. package/dist/host/engines/windows-sandbox/wsb-text.d.ts +2 -0
  378. package/dist/host/engines/windows-sandbox/wsb-text.js +29 -0
  379. package/dist/host/health/acl-read.d.ts +17 -0
  380. package/dist/host/health/acl-read.js +45 -0
  381. package/dist/host/health/config-backup.d.ts +11 -0
  382. package/dist/host/health/config-backup.js +73 -0
  383. package/dist/host/health/index.d.ts +6 -0
  384. package/dist/host/health/index.js +7 -0
  385. package/dist/host/health/install-state.d.ts +33 -0
  386. package/dist/host/health/install-state.js +110 -0
  387. package/dist/host/health/path-copies.d.ts +32 -0
  388. package/dist/host/health/path-copies.js +82 -0
  389. package/dist/host/health/stale.d.ts +45 -0
  390. package/dist/host/health/stale.js +120 -0
  391. package/dist/host/health/system.d.ts +37 -0
  392. package/dist/host/health/system.js +87 -0
  393. package/dist/host/install/copies.d.ts +13 -0
  394. package/dist/host/install/copies.js +63 -0
  395. package/dist/host/install/index.d.ts +1 -0
  396. package/dist/host/install/index.js +1 -0
  397. package/dist/host/launch/generate.d.ts +5 -1
  398. package/dist/host/launch/generate.js +73 -7
  399. package/dist/host/launch/index.d.ts +3 -1
  400. package/dist/host/launch/index.js +3 -1
  401. package/dist/host/launch/launch-plan.d.ts +13 -0
  402. package/dist/host/launch/launch-plan.js +26 -0
  403. package/dist/host/launch/mappings.js +2 -1
  404. package/dist/host/launch/risk-notes.d.ts +10 -0
  405. package/dist/host/launch/risk-notes.js +18 -0
  406. package/dist/host/launch/session-file.d.ts +2 -0
  407. package/dist/host/launch/session-file.js +11 -2
  408. package/dist/host/launch/stage.js +1 -1
  409. package/dist/host/launch/wsb-file.d.ts +28 -4
  410. package/dist/host/launch/wsb-file.js +61 -42
  411. package/dist/host/life/crash-report.d.ts +27 -1
  412. package/dist/host/life/crash-report.js +173 -7
  413. package/dist/host/life/host-memory.d.ts +40 -0
  414. package/dist/host/life/host-memory.js +137 -0
  415. package/dist/host/life/index.d.ts +2 -0
  416. package/dist/host/life/index.js +2 -0
  417. package/dist/host/life/stop-events.d.ts +2 -0
  418. package/dist/host/life/stop-events.js +20 -3
  419. package/dist/host/life/stop-warning.js +1 -1
  420. package/dist/host/life/watchdog.d.ts +54 -0
  421. package/dist/host/life/watchdog.js +108 -0
  422. package/dist/host/migrate/backup.js +3 -0
  423. package/dist/host/migrate/migrations/config-file.d.ts +2 -0
  424. package/dist/host/migrate/migrations/config-file.js +7 -0
  425. package/dist/host/migrate/migrations/follow-machine-storage.js +9 -1
  426. package/dist/host/migrate/migrations/pin-storage-root.d.ts +4 -0
  427. package/dist/host/migrate/migrations/pin-storage-root.js +46 -0
  428. package/dist/host/migrate/migrations/unpin-config-defaults.js +4 -1
  429. package/dist/host/migrate/registry.js +2 -1
  430. package/dist/host/native.d.ts +3 -2
  431. package/dist/host/native.js +22 -3
  432. package/dist/host/profile/accounts.d.ts +25 -1
  433. package/dist/host/profile/accounts.js +96 -13
  434. package/dist/host/profile/agent-accounts.d.ts +5 -1
  435. package/dist/host/profile/agent-accounts.js +35 -5
  436. package/dist/host/profile/claude-login.js +3 -2
  437. package/dist/host/profile/index.d.ts +2 -1
  438. package/dist/host/profile/index.js +1 -0
  439. package/dist/host/profile/plugin-share.d.ts +26 -0
  440. package/dist/host/profile/plugin-share.js +146 -0
  441. package/dist/host/projects/join.d.ts +7 -1
  442. package/dist/host/projects/join.js +21 -4
  443. package/dist/host/projects/registry.d.ts +16 -10
  444. package/dist/host/projects/registry.js +74 -6
  445. package/dist/host/sandbox/contained-deps.d.ts +2 -0
  446. package/dist/host/sandbox/contained-deps.js +17 -0
  447. package/dist/host/sandbox/index.d.ts +2 -0
  448. package/dist/host/sandbox/index.js +2 -0
  449. package/dist/host/sandbox/platform.d.ts +4 -0
  450. package/dist/host/sandbox/platform.js +23 -4
  451. package/dist/host/sandbox/tasklist.d.ts +13 -0
  452. package/dist/host/sandbox/tasklist.js +47 -0
  453. package/dist/host/secrets/index.d.ts +2 -0
  454. package/dist/host/secrets/index.js +2 -0
  455. package/dist/host/secrets/launch-secrets.d.ts +17 -0
  456. package/dist/host/secrets/launch-secrets.js +94 -0
  457. package/dist/host/secrets/secret-store.d.ts +25 -0
  458. package/dist/host/secrets/secret-store.js +89 -0
  459. package/dist/host/sharing/acl.d.ts +16 -2
  460. package/dist/host/sharing/acl.js +35 -10
  461. package/dist/host/sharing/current.js +8 -3
  462. package/dist/host/sharing/doctor.d.ts +2 -0
  463. package/dist/host/sharing/doctor.js +44 -0
  464. package/dist/host/sharing/group-access.d.ts +6 -0
  465. package/dist/host/sharing/group-access.js +24 -0
  466. package/dist/host/sharing/index.d.ts +2 -1
  467. package/dist/host/sharing/index.js +2 -1
  468. package/dist/host/sharing/lifecycle.d.ts +8 -2
  469. package/dist/host/sharing/lifecycle.js +16 -7
  470. package/dist/host/storage/cleanup.d.ts +2 -0
  471. package/dist/host/storage/cleanup.js +2 -1
  472. package/dist/host/storage/contained/check.d.ts +9 -0
  473. package/dist/host/storage/contained/check.js +37 -0
  474. package/dist/host/storage/contained/contained-storage.d.ts +66 -0
  475. package/dist/host/storage/contained/contained-storage.js +168 -0
  476. package/dist/host/storage/contained/disk-port.d.ts +43 -0
  477. package/dist/host/storage/contained/disk-port.js +122 -0
  478. package/dist/host/storage/contained/index.d.ts +9 -0
  479. package/dist/host/storage/contained/index.js +8 -0
  480. package/dist/host/storage/contained/layout.d.ts +28 -0
  481. package/dist/host/storage/contained/layout.js +45 -0
  482. package/dist/host/storage/contained/resolve.d.ts +4 -0
  483. package/dist/host/storage/contained/resolve.js +30 -0
  484. package/dist/host/storage/contained/setting.d.ts +1 -0
  485. package/dist/host/storage/contained/setting.js +5 -0
  486. package/dist/host/storage/contained/state.d.ts +89 -0
  487. package/dist/host/storage/contained/state.js +166 -0
  488. package/dist/host/storage/contained/transfer.d.ts +24 -0
  489. package/dist/host/storage/contained/transfer.js +121 -0
  490. package/dist/host/storage/history.d.ts +21 -0
  491. package/dist/host/storage/history.js +49 -0
  492. package/dist/host/storage/index.d.ts +6 -0
  493. package/dist/host/storage/index.js +6 -0
  494. package/dist/host/storage/move.d.ts +95 -0
  495. package/dist/host/storage/move.js +384 -0
  496. package/dist/host/storage/offer.d.ts +11 -0
  497. package/dist/host/storage/offer.js +36 -0
  498. package/dist/host/storage/providers/contained.d.ts +15 -0
  499. package/dist/host/storage/providers/contained.js +39 -0
  500. package/dist/host/storage/providers/folder.d.ts +12 -0
  501. package/dist/host/storage/providers/folder.js +20 -0
  502. package/dist/host/storage/providers/index.d.ts +4 -0
  503. package/dist/host/storage/providers/index.js +3 -0
  504. package/dist/host/storage/providers/registry.d.ts +9 -0
  505. package/dist/host/storage/providers/registry.js +14 -0
  506. package/dist/host/storage/providers/types.d.ts +33 -0
  507. package/dist/host/storage/providers/types.js +1 -0
  508. package/dist/host/storage/root.d.ts +18 -0
  509. package/dist/host/storage/root.js +77 -0
  510. package/dist/host/tools/conpty.js +3 -2
  511. package/dist/host/tools/windows-terminal.d.ts +2 -0
  512. package/dist/host/tools/windows-terminal.js +31 -12
  513. package/dist/host/update/index.d.ts +1 -1
  514. package/dist/host/update/index.js +1 -1
  515. package/dist/host/update/notice.d.ts +2 -0
  516. package/dist/host/update/notice.js +13 -1
  517. package/dist/host/update/update-state.d.ts +6 -0
  518. package/dist/host/update/update-state.js +2 -0
  519. package/dist/host/update/updater.d.ts +19 -0
  520. package/dist/host/update/updater.js +88 -12
  521. package/dist/host/vpn/index.d.ts +4 -0
  522. package/dist/host/vpn/index.js +4 -0
  523. package/dist/host/vpn/login.d.ts +24 -0
  524. package/dist/host/vpn/login.js +79 -0
  525. package/dist/host/vpn/nordvpn.d.ts +21 -0
  526. package/dist/host/vpn/nordvpn.js +77 -0
  527. package/dist/host/vpn/prepare.d.ts +19 -0
  528. package/dist/host/vpn/prepare.js +138 -0
  529. package/dist/host/vpn/status.d.ts +12 -0
  530. package/dist/host/vpn/status.js +53 -0
  531. package/dist/host/web/auth.d.ts +38 -0
  532. package/dist/host/web/auth.js +96 -0
  533. package/dist/host/web/backend.d.ts +14 -0
  534. package/dist/host/web/backend.js +1 -0
  535. package/dist/host/web/bridge.d.ts +27 -0
  536. package/dist/host/web/bridge.js +144 -0
  537. package/dist/host/web/browser.d.ts +3 -0
  538. package/dist/host/web/browser.js +23 -0
  539. package/dist/host/web/control.d.ts +17 -0
  540. package/dist/host/web/control.js +67 -0
  541. package/dist/host/web/index.d.ts +10 -0
  542. package/dist/host/web/index.js +9 -0
  543. package/dist/host/web/rpc.d.ts +24 -0
  544. package/dist/host/web/rpc.js +149 -0
  545. package/dist/host/web/runner.d.ts +16 -0
  546. package/dist/host/web/runner.js +44 -0
  547. package/dist/host/web/server.d.ts +47 -0
  548. package/dist/host/web/server.js +238 -0
  549. package/dist/host/web/state.d.ts +20 -0
  550. package/dist/host/web/state.js +41 -0
  551. package/dist/host/web/static-files.d.ts +13 -0
  552. package/dist/host/web/static-files.js +57 -0
  553. package/dist/runtime/agent.js +27675 -0
  554. package/dist/runtime/daemon.js +1950 -1122
  555. package/dist/runtime/db.js +302 -111
  556. package/dist/runtime/main.js +1560 -275
  557. package/dist/runtime/netproxy.js +168 -8
  558. package/dist/runtime/view.js +186 -13
  559. package/dist/selftest/accounts.test.js +40 -0
  560. package/dist/selftest/agent-paths.test.d.ts +2 -0
  561. package/dist/selftest/agent-paths.test.js +125 -0
  562. package/dist/selftest/app.test.d.ts +2 -0
  563. package/dist/selftest/app.test.js +324 -0
  564. package/dist/selftest/channel.test.js +18 -0
  565. package/dist/selftest/cli.test.js +35 -4
  566. package/dist/selftest/config.test.js +59 -0
  567. package/dist/selftest/contained.test.d.ts +2 -0
  568. package/dist/selftest/contained.test.js +544 -0
  569. package/dist/selftest/credentials.test.d.ts +2 -0
  570. package/dist/selftest/credentials.test.js +198 -0
  571. package/dist/selftest/engine.test.d.ts +2 -0
  572. package/dist/selftest/engine.test.js +127 -0
  573. package/dist/selftest/generate.test.js +1 -1
  574. package/dist/selftest/hcs.test.d.ts +2 -0
  575. package/dist/selftest/hcs.test.js +482 -0
  576. package/dist/selftest/health.test.d.ts +2 -0
  577. package/dist/selftest/health.test.js +470 -0
  578. package/dist/selftest/heavy-load.test.d.ts +2 -0
  579. package/dist/selftest/heavy-load.test.js +329 -0
  580. package/dist/selftest/host-sim.test.js +2 -0
  581. package/dist/selftest/index.js +31 -0
  582. package/dist/selftest/layout.test.js +14 -0
  583. package/dist/selftest/menu-perf.test.d.ts +2 -0
  584. package/dist/selftest/menu-perf.test.js +248 -0
  585. package/dist/selftest/menu-screens.d.ts +7 -0
  586. package/dist/selftest/menu-screens.js +68 -17
  587. package/dist/selftest/menu.test.js +603 -22
  588. package/dist/selftest/migrate.test.js +1 -1
  589. package/dist/selftest/personalization.test.js +3 -1
  590. package/dist/selftest/projects.test.js +39 -1
  591. package/dist/selftest/shared-use.test.js +64 -2
  592. package/dist/selftest/sharing.test.js +50 -1
  593. package/dist/selftest/storage.test.d.ts +2 -0
  594. package/dist/selftest/storage.test.js +363 -0
  595. package/dist/selftest/support/engine-cases.d.ts +8 -0
  596. package/dist/selftest/support/engine-cases.js +65 -0
  597. package/dist/selftest/support/engine-golden.d.ts +3 -0
  598. package/dist/selftest/support/engine-golden.js +66 -0
  599. package/dist/selftest/support/fixtures.d.ts +20 -0
  600. package/dist/selftest/support/hcs-probes.d.ts +17 -0
  601. package/dist/selftest/support/hcs-probes.js +41 -0
  602. package/dist/selftest/support/releases.js +1 -1
  603. package/dist/selftest/toolchains.test.js +21 -0
  604. package/dist/selftest/update-service.test.js +87 -3
  605. package/dist/selftest/vpn.test.d.ts +2 -0
  606. package/dist/selftest/vpn.test.js +412 -0
  607. package/dist/selftest/web.test.d.ts +2 -0
  608. package/dist/selftest/web.test.js +402 -0
  609. package/dist/shared/apps/catalogue.js +31 -0
  610. package/dist/shared/channel/index.d.ts +1 -0
  611. package/dist/shared/channel/index.js +1 -0
  612. package/dist/shared/channel/run-dir.d.ts +9 -1
  613. package/dist/shared/channel/run-dir.js +18 -1
  614. package/dist/shared/channel/schema.d.ts +53 -0
  615. package/dist/shared/channel/schema.js +38 -0
  616. package/dist/shared/channel/secrets.d.ts +29 -0
  617. package/dist/shared/channel/secrets.js +50 -0
  618. package/dist/shared/memory/index.d.ts +1 -0
  619. package/dist/shared/memory/index.js +1 -0
  620. package/dist/shared/memory/policy.d.ts +33 -0
  621. package/dist/shared/memory/policy.js +55 -0
  622. package/dist/shared/pty/output-filter.d.ts +14 -1
  623. package/dist/shared/pty/output-filter.js +22 -4
  624. package/dist/shared/pty/terminal.d.ts +4 -1
  625. package/dist/shared/pty/terminal.js +4 -2
  626. package/dist/shared/system.d.ts +1 -0
  627. package/dist/shared/system.js +1 -0
  628. package/dist/shared/vpn/download.d.ts +29 -0
  629. package/dist/shared/vpn/download.js +30 -0
  630. package/dist/shared/vpn/kill-switch.d.ts +18 -0
  631. package/dist/shared/vpn/kill-switch.js +81 -0
  632. package/dist/shared/vpn/ovpn.d.ts +23 -0
  633. package/dist/shared/vpn/ovpn.js +244 -0
  634. package/dist/shared/vpn/wireguard.d.ts +51 -0
  635. package/dist/shared/vpn/wireguard.js +227 -0
  636. package/dist/shared/web/index.d.ts +1 -0
  637. package/dist/shared/web/index.js +1 -0
  638. package/dist/shared/web/protocol.d.ts +61 -0
  639. package/dist/shared/web/protocol.js +35 -0
  640. package/dist/sync/sync-cycle.js +9 -5
  641. package/dist/sync/sync-state.d.ts +1 -0
  642. package/dist/sync/sync-state.js +1 -0
  643. package/dist/sync/watcher.d.ts +13 -0
  644. package/dist/sync/watcher.js +102 -3
  645. package/dist/web/index.html +14 -0
  646. package/dist/web/main-NRRS5O6Z.js +157 -0
  647. package/dist/web/main-T5DMCHYV.css +1 -0
  648. package/native/csharp/FolderSecurity.cs +29 -0
  649. package/native/csharp/HcsHost/AssemblyInfo.cs +14 -0
  650. package/native/csharp/HcsHost/Guard.cs +100 -0
  651. package/native/csharp/HcsHost/Hcs.cs +256 -0
  652. package/native/csharp/HcsHost/Json.cs +78 -0
  653. package/native/csharp/HcsHost/Program.cs +185 -0
  654. package/native/csharp/HcsHost/VirtualDisk.cs +95 -0
  655. package/native/csharp/HostTools/AssemblyInfo.cs +14 -0
  656. package/native/csharp/HostTools/MemoryStatus.cs +107 -0
  657. package/native/csharp/HostTools/Program.cs +58 -17
  658. package/native/scripts/check-contained.ps1 +28 -0
  659. package/native/scripts/contained-common.ps1 +241 -0
  660. package/native/scripts/dismount-contained.ps1 +66 -0
  661. package/native/scripts/memory-status.ps1 +34 -0
  662. package/native/scripts/mount-contained.ps1 +139 -0
  663. package/native/scripts/protect-data.ps1 +29 -0
  664. package/native/scripts/read-folder-sddl.ps1 +10 -0
  665. package/native/scripts/run-elevated.ps1 +17 -4
  666. package/native/scripts/set-folder-access.ps1 +49 -7
  667. package/native/scripts/stop-events.ps1 +23 -8
  668. package/node_modules/ws/LICENSE +20 -0
  669. package/node_modules/ws/README.md +548 -0
  670. package/node_modules/ws/browser.js +8 -0
  671. package/node_modules/ws/index.js +22 -0
  672. package/node_modules/ws/lib/buffer-util.js +131 -0
  673. package/node_modules/ws/lib/constants.js +19 -0
  674. package/node_modules/ws/lib/event-target.js +292 -0
  675. package/node_modules/ws/lib/extension.js +203 -0
  676. package/node_modules/ws/lib/limiter.js +55 -0
  677. package/node_modules/ws/lib/permessage-deflate.js +530 -0
  678. package/node_modules/ws/lib/receiver.js +743 -0
  679. package/node_modules/ws/lib/sender.js +607 -0
  680. package/node_modules/ws/lib/stream.js +161 -0
  681. package/node_modules/ws/lib/subprotocol.js +62 -0
  682. package/node_modules/ws/lib/validation.js +152 -0
  683. package/node_modules/ws/lib/websocket-server.js +562 -0
  684. package/node_modules/ws/lib/websocket.js +1421 -0
  685. package/node_modules/ws/package.json +74 -0
  686. package/node_modules/ws/wrapper.mjs +21 -0
  687. package/package.json +22 -5
  688. package/sandbox/csharp/EnvBroadcast.cs +33 -0
  689. package/sandbox/csharp/MemGov.cs +398 -0
  690. package/sandbox/csharp/PathSync.cs +90 -0
  691. package/sandbox/csharp/PtyHost.cs +111 -5
  692. package/sandbox/scripts/install-shell-path.ps1 +73 -0
  693. package/sandbox/scripts/set-machine-environment.ps1 +37 -4
  694. package/schemas/config.schema.json +136 -7
  695. package/schemas/sandbox-config.schema.json +17 -4
  696. package/dist/cli/commands/repair/checks.d.ts +0 -2
  697. package/dist/cli/commands/repair/checks.js +0 -246
  698. package/dist/cli/commands/sessions/control.d.ts +0 -4
  699. package/dist/cli/commands/sessions/control.js +0 -66
  700. package/dist/cli/commands/sessions/list.d.ts +0 -2
  701. package/dist/cli/commands/sessions/list.js +0 -45
  702. package/dist/cli/commands/sessions/status.d.ts +0 -2
  703. package/dist/cli/commands/sessions/status.js +0 -93
  704. package/dist/cli/commands/sessions/window.d.ts +0 -3
  705. package/dist/cli/commands/sessions/window.js +0 -18
  706. package/dist/cli/menu/pages/start-page.d.ts +0 -43
  707. package/dist/cli/menu/pages/start-page.js +0 -192
  708. package/dist/cli/tui/tab-bar.d.ts +0 -9
  709. package/dist/cli/tui/tab-bar.js +0 -33
@@ -1,5 +1,7 @@
1
1
  // Several Claude logins for the sandbox. Each account is a saved copy of Claude's .credentials.json plus the
2
- // `oauthAccount` block of .claude.json, kept in host-only storage (<storage>\accounts, never mapped into a sandbox).
2
+ // `oauthAccount` block of .claude.json, kept in host-only storage (<storage>\accounts, never mapped into a sandbox)
3
+ // and encrypted with Windows DPAPI (host/secrets): only the name, e-mail and date are readable in the file. Accounts
4
+ // saved before that were plain; they are encrypted the first time they are read.
3
5
  // Switching writes them into the sandbox's persistent Claude state; when the sandbox is running the agent is then
4
6
  // restarted in place with --continue so the conversation carries on.
5
7
  import fs from 'node:fs';
@@ -8,8 +10,10 @@ import { z } from 'zod';
8
10
  import { isSafeFileName } from '../../shared/paths/index.js';
9
11
  import { JsonFile } from '../../shared/io/index.js';
10
12
  import { storageOf } from '../storage/index.js';
11
- import { fail, fileExists } from '../../core/util/index.js';
12
- import { clearAccountCaches, emailOf, MAX_STATE_BYTES, readLogin, readUntrusted, sandboxLogin, writeSandboxJson, } from './claude-login.js';
13
+ import { errMsg, fail, fileExists } from '../../core/util/index.js';
14
+ import { SecretStore } from '../secrets/index.js';
15
+ import { PluginShare } from './plugin-share.js';
16
+ import { clearAccountCaches, emailOf, MAX_STATE_BYTES, readLogin, sandboxClaudeDir, readUntrusted, sandboxLogin, writeSandboxJson, } from './claude-login.js';
13
17
  const NAME = /^[A-Za-z0-9_-]{1,40}$/;
14
18
  const AccountSchema = z.object({
15
19
  name: z.string().regex(NAME),
@@ -22,6 +26,15 @@ const IndexSchema = z.object({
22
26
  default: z.string().regex(NAME).optional(),
23
27
  active: z.record(z.string().max(200), z.string().regex(NAME)).optional(),
24
28
  });
29
+ /** On disk: the readable details and the sealed login ({ credentials, oauthAccount }). */
30
+ const SealedSchema = z.object({
31
+ name: z.string().regex(NAME),
32
+ savedAt: z.string().max(64),
33
+ email: z.string().max(200).nullable(),
34
+ sealed: z.string().max(200000),
35
+ });
36
+ const StoredSchema = z.union([SealedSchema, AccountSchema]);
37
+ const isSealed = (s) => 'sealed' in s;
25
38
  export function accountsDir(storageRoot) {
26
39
  return path.join(storageRoot, 'accounts');
27
40
  }
@@ -51,19 +64,87 @@ function assertName(name) {
51
64
  /** The saved Claude logins under <storage>\accounts, and which one each sandbox data folder uses. */
52
65
  export class AccountStore {
53
66
  storageRoot;
54
- constructor(storageRoot) {
67
+ sharePlugins;
68
+ secrets;
69
+ /** What the last activate() did with the shared plugins (a problem there never stops the switch). */
70
+ pluginNote = null;
71
+ /** @param sharePlugins claudeProfile.sharePluginsAcrossAccounts: carry Claude plugins to the account switched to */
72
+ constructor(storageRoot, sharePlugins = false, secrets = SecretStore.standard()) {
55
73
  this.storageRoot = storageRoot;
74
+ this.sharePlugins = sharePlugins;
75
+ this.secrets = secrets;
76
+ }
77
+ /** With the setting on: refreshes the shared plugin set from this data set, or fills this data set from it. */
78
+ syncPlugins(dataPath) {
79
+ this.shareStep(dataPath, sandboxClaudeDir(dataPath));
80
+ }
81
+ shareStep(dataPath, claudeDir) {
82
+ this.pluginNote = null;
83
+ if (!this.sharePlugins)
84
+ return;
85
+ try {
86
+ const result = PluginShare.in(this.storageRoot).sync(dataPath, claudeDir);
87
+ if (result === 'restored')
88
+ this.pluginNote = 'Claude plugins were copied in from your other accounts.';
89
+ }
90
+ catch (e) {
91
+ this.pluginNote = 'Claude plugins were not copied: ' + errMsg(e);
92
+ }
56
93
  }
57
94
  file(name) {
58
- return new JsonFile(AccountSchema, path.join(accountsDir(this.storageRoot), name + '.json'));
95
+ return new JsonFile(StoredSchema, path.join(accountsDir(this.storageRoot), name + '.json'));
96
+ }
97
+ seal(account) {
98
+ const { name, savedAt, email, credentials, oauthAccount } = account;
99
+ return { name, savedAt, email, sealed: this.secrets.sealJson({ credentials, oauthAccount }) };
59
100
  }
60
101
  store(name, login) {
61
102
  const account = { name, savedAt: new Date().toISOString(), email: emailOf(login.oauthAccount), ...login };
62
- this.file(name).write(account);
103
+ this.file(name).write(this.seal(account));
63
104
  return account;
64
105
  }
106
+ /** The saved account's name, date and e-mail (nothing is decrypted). */
107
+ meta(name) {
108
+ const stored = validName(name) ? this.file(name).read() : null;
109
+ return stored ? { name: stored.name, savedAt: stored.savedAt, email: stored.email } : null;
110
+ }
111
+ /**
112
+ * The saved account with its login decrypted. A plain file from an older version is encrypted on the spot (it stays
113
+ * readable when that fails).
114
+ */
65
115
  read(name) {
66
- return validName(name) ? this.file(name).read() : null;
116
+ const stored = validName(name) ? this.file(name).read() : null;
117
+ if (!stored)
118
+ return null;
119
+ if (isSealed(stored)) {
120
+ const login = this.secrets.openJson(stored.sealed);
121
+ return { name: stored.name, savedAt: stored.savedAt, email: stored.email, ...login };
122
+ }
123
+ try {
124
+ this.file(name).write(this.seal(stored));
125
+ }
126
+ catch {
127
+ // Could not encrypt now (DPAPI unavailable): the old plain file stays and is tried again next time.
128
+ }
129
+ return stored;
130
+ }
131
+ /** Encrypts every account still saved as plain text (older versions); returns how many it did. */
132
+ sealLegacy() {
133
+ const dir = accountsDir(this.storageRoot);
134
+ if (!fs.existsSync(dir))
135
+ return 0;
136
+ let done = 0;
137
+ for (const f of fs.readdirSync(dir).filter((x) => x.endsWith('.json') && x !== 'index.json')) {
138
+ const name = f.slice(0, -5);
139
+ const stored = validName(name) ? this.file(name).read() : null;
140
+ if (!stored || isSealed(stored))
141
+ continue;
142
+ this.read(name);
143
+ const after = this.file(name).read();
144
+ if (after && isSealed(after))
145
+ done++;
146
+ }
147
+ return done;
67
148
  }
68
149
  defaultName() {
69
150
  return readIndex(this.storageRoot).default ?? null;
@@ -76,12 +157,13 @@ export class AccountStore {
76
157
  const dir = accountsDir(this.storageRoot);
77
158
  if (!fs.existsSync(dir))
78
159
  return [];
160
+ this.sealLegacy();
79
161
  const def = this.defaultName();
80
162
  const active = this.activeFor(dataPath);
81
163
  return fs
82
164
  .readdirSync(dir)
83
165
  .filter((f) => f.endsWith('.json') && f !== 'index.json')
84
- .map((f) => this.read(f.slice(0, -5)))
166
+ .map((f) => this.meta(f.slice(0, -5)))
85
167
  .filter((a) => a !== null)
86
168
  .map((a) => ({
87
169
  name: a.name,
@@ -114,7 +196,7 @@ export class AccountStore {
114
196
  .join(', ') || 'none yet; save one with sandbox account save <name>'));
115
197
  const { claudeDir, globalStateFile } = sandboxLogin(dataPath);
116
198
  const outgoing = this.activeFor(dataPath);
117
- if (outgoing && outgoing !== name && this.read(outgoing) && fileExists(path.join(claudeDir, '.credentials.json'))) {
199
+ if (outgoing && outgoing !== name && this.meta(outgoing) && fileExists(path.join(claudeDir, '.credentials.json'))) {
118
200
  try {
119
201
  this.store(outgoing, readLogin(claudeDir, globalStateFile));
120
202
  }
@@ -128,20 +210,21 @@ export class AccountStore {
128
210
  const state = readUntrusted(globalStateFile, MAX_STATE_BYTES);
129
211
  if (account.oauthAccount && (state || !fileExists(globalStateFile)))
130
212
  writeSandboxJson(globalStateFile, { ...(state ?? {}), oauthAccount: account.oauthAccount });
213
+ this.shareStep(dataPath, claudeDir);
131
214
  setActive(dataPath, name);
132
215
  return account;
133
216
  }
134
217
  setDefault(name) {
135
- if (name !== null && !this.read(name))
218
+ if (name !== null && !this.meta(name))
136
219
  fail('Unknown account "' + name + '".', 'See your accounts with: sandbox account list');
137
220
  updateIndex(this.storageRoot, (i) => ({ ...i, default: name ?? undefined }));
138
221
  }
139
222
  rename(name, to) {
140
223
  assertName(to);
141
224
  const account = this.read(name) ?? fail('Unknown account "' + name + '".', 'See your accounts with: sandbox account list');
142
- if (this.read(to))
225
+ if (this.meta(to))
143
226
  fail('There is an account "' + to + '" already.', 'Pick another name.');
144
- this.file(to).write({ ...account, name: to });
227
+ this.file(to).write(this.seal({ ...account, name: to }));
145
228
  fs.rmSync(this.file(name).file);
146
229
  updateIndex(this.storageRoot, (i) => ({
147
230
  ...i,
@@ -150,7 +233,7 @@ export class AccountStore {
150
233
  }));
151
234
  }
152
235
  remove(name) {
153
- if (!this.read(name))
236
+ if (!this.meta(name))
154
237
  fail('Unknown account "' + name + '".', 'See your accounts with: sandbox account list');
155
238
  fs.rmSync(this.file(name).file);
156
239
  if (this.defaultName() === name)
@@ -1,12 +1,16 @@
1
+ import { SecretStore } from '../secrets/index.js';
1
2
  import { type AccountRow } from './accounts.js';
2
3
  export declare class AgentAccountStore {
3
4
  private readonly storageRoot;
4
5
  private readonly agent;
5
6
  private readonly loginFiles;
7
+ private readonly secrets;
6
8
  /**
7
9
  * @param loginFiles files of the login, relative to the folder they are read from and written to
8
10
  */
9
- constructor(storageRoot: string, agent: string, loginFiles: readonly string[]);
11
+ constructor(storageRoot: string, agent: string, loginFiles: readonly string[], secrets?: SecretStore);
12
+ /** Encrypts the plain login files of every account saved by an older version. */
13
+ sealLegacy(): void;
10
14
  private get dir();
11
15
  private folder;
12
16
  private index;
@@ -1,11 +1,14 @@
1
1
  // Saved logins for agents other than Claude: <storage>\accounts\<agent>\<name>\ holds a copy of the agent's login files
2
- // (the harness `home.loginFiles`) and meta.json. Host-only storage, never mapped into a sandbox; switching copies the
3
- // files into the sandbox's persistent state. Claude keeps its own older layout (accounts.ts).
2
+ // (the harness `home.loginFiles`, each one encrypted with Windows DPAPI as <file>.sealed) and meta.json. Host-only
3
+ // storage, never mapped into a sandbox; switching decrypts the files into the sandbox's persistent state. Copies saved
4
+ // by older versions were plain: they are encrypted the next time the accounts are listed or one is switched to.
5
+ // Claude keeps its own older layout (accounts.ts).
4
6
  import fs from 'node:fs';
5
7
  import path from 'node:path';
6
8
  import { z } from 'zod';
7
9
  import { JsonFile } from '../../shared/io/index.js';
8
10
  import { isSafeFileName } from '../../shared/paths/index.js';
11
+ import { SecretStore } from '../secrets/index.js';
9
12
  import { assertNoLinks, ensureDir, fail, isLink } from '../../core/util/index.js';
10
13
  import { accountsDir } from './accounts.js';
11
14
  const NAME = /^[A-Za-z0-9_-]{1,40}$/;
@@ -27,13 +30,36 @@ export class AgentAccountStore {
27
30
  storageRoot;
28
31
  agent;
29
32
  loginFiles;
33
+ secrets;
30
34
  /**
31
35
  * @param loginFiles files of the login, relative to the folder they are read from and written to
32
36
  */
33
- constructor(storageRoot, agent, loginFiles) {
37
+ constructor(storageRoot, agent, loginFiles, secrets = SecretStore.standard()) {
34
38
  this.storageRoot = storageRoot;
35
39
  this.agent = agent;
36
40
  this.loginFiles = loginFiles;
41
+ this.secrets = secrets;
42
+ }
43
+ /** Encrypts the plain login files of every account saved by an older version. */
44
+ sealLegacy() {
45
+ if (!fs.existsSync(this.dir))
46
+ return;
47
+ for (const d of fs.readdirSync(this.dir, { withFileTypes: true })) {
48
+ if (!d.isDirectory() || d.isSymbolicLink() || !validName(d.name))
49
+ continue;
50
+ for (const f of this.loginFiles) {
51
+ const plain = path.join(this.folder(d.name), ...f.split(/[\\/]/));
52
+ if (!fs.existsSync(plain) || isLink(plain))
53
+ continue;
54
+ try {
55
+ fs.writeFileSync(plain + '.sealed', this.secrets.sealBytes(fs.readFileSync(plain)));
56
+ fs.rmSync(plain);
57
+ }
58
+ catch {
59
+ // Could not encrypt now: the plain copy stays readable and is tried again next time.
60
+ }
61
+ }
62
+ }
37
63
  }
38
64
  get dir() {
39
65
  return path.join(accountsDir(this.storageRoot), this.agent);
@@ -66,6 +92,7 @@ export class AgentAccountStore {
66
92
  list(dataPath) {
67
93
  if (!fs.existsSync(this.dir))
68
94
  return [];
95
+ this.sealLegacy();
69
96
  const def = this.defaultName();
70
97
  const active = this.activeFor(dataPath);
71
98
  return fs
@@ -95,7 +122,7 @@ export class AgentAccountStore {
95
122
  for (const f of found) {
96
123
  const dest = path.join(target, ...f.split(/[\\/]/));
97
124
  ensureDir(path.dirname(dest));
98
- fs.copyFileSync(path.join(from, f), dest);
125
+ fs.writeFileSync(dest + '.sealed', this.secrets.sealBytes(fs.readFileSync(path.join(from, f))));
99
126
  }
100
127
  new JsonFile(MetaSchema, path.join(target, 'meta.json')).write({ name, savedAt: new Date().toISOString() });
101
128
  }
@@ -115,6 +142,7 @@ export class AgentAccountStore {
115
142
  (this.list(dataPath)
116
143
  .map((a) => a.name)
117
144
  .join(', ') || 'none yet'));
145
+ this.sealLegacy();
118
146
  // Tokens rotate while the agent runs: the outgoing account's current files are saved back first.
119
147
  const outgoing = this.activeFor(dataPath);
120
148
  if (outgoing && outgoing !== name && this.meta(outgoing)) {
@@ -133,7 +161,9 @@ export class AgentAccountStore {
133
161
  if (isLink(dest))
134
162
  fs.rmSync(dest);
135
163
  const saved = path.join(this.folder(name), ...f.split(/[\\/]/));
136
- if (fs.existsSync(saved))
164
+ if (fs.existsSync(saved + '.sealed'))
165
+ fs.writeFileSync(dest, this.secrets.openBytes(fs.readFileSync(saved + '.sealed', 'utf8')));
166
+ else if (fs.existsSync(saved))
137
167
  fs.copyFileSync(saved, dest);
138
168
  else
139
169
  fs.rmSync(dest, { force: true });
@@ -3,6 +3,7 @@
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { assertTestWritable } from '../test-guard.js';
6
+ import { hostDataFolder, hostDataRoot } from '../storage/index.js';
6
7
  import { assertNoLinks, fail, fileExists, isLink, removeLink, tryReadJson, writeJson } from '../../core/util/index.js';
7
8
  const MAX_LOGIN_BYTES = 1024 * 1024;
8
9
  /** .claude.json holds per-project state and can be large; still capped so a hostile file cannot exhaust memory. */
@@ -10,7 +11,7 @@ export const MAX_STATE_BYTES = 256 * 1024 * 1024;
10
11
  /** Caches tied to an account (Claude deletes these on /logout). */
11
12
  const ACCOUNT_CACHES = ['remote-settings.json', 'policy-limits.json', 'policy-limits.json.stamp.json'];
12
13
  export function sandboxClaudeDir(dataPath) {
13
- return path.join(dataPath, 'state', 'claude');
14
+ return path.join(hostDataFolder(dataPath, 'state'), 'claude');
14
15
  }
15
16
  export function emailOf(oauthAccount) {
16
17
  const email = oauthAccount?.emailAddress;
@@ -32,7 +33,7 @@ export function readLogin(claudeDir, globalStateFile) {
32
33
  }
33
34
  /** The sandbox's Claude login files (refuses when the data folder holds a link on the way). */
34
35
  export function sandboxLogin(dataPath) {
35
- assertNoLinks(dataPath, sandboxClaudeDir(dataPath));
36
+ assertNoLinks(hostDataRoot(dataPath), sandboxClaudeDir(dataPath));
36
37
  return {
37
38
  claudeDir: sandboxClaudeDir(dataPath),
38
39
  globalStateFile: path.join(sandboxClaudeDir(dataPath), '.claude.json'),
@@ -3,6 +3,7 @@ export { findSecretFiles } from './secret-files.js';
3
3
  export { hostClaudeDir, hostGlobalStateFile, sandboxGlobalState, stageClaudeProfile } from './claude-profile.js';
4
4
  export { capturePersonalization } from './personalize.js';
5
5
  export { toRegFile, type RegValue } from './reg-file.js';
6
- export { AccountStore, accountsDir, type Account, type AccountRow } from './accounts.js';
6
+ export { AccountStore, accountsDir, type Account, type AccountMeta, type AccountRow } from './accounts.js';
7
+ export { PluginShare, PLUGIN_SETTING_KEYS, MAX_PLUGIN_FILES, MAX_PLUGIN_BYTES } from './plugin-share.js';
7
8
  export { AgentAccountStore } from './agent-accounts.js';
8
9
  export { sandboxClaudeDir } from './claude-login.js';
@@ -4,5 +4,6 @@ export { hostClaudeDir, hostGlobalStateFile, sandboxGlobalState, stageClaudeProf
4
4
  export { capturePersonalization } from './personalize.js';
5
5
  export { toRegFile } from './reg-file.js';
6
6
  export { AccountStore, accountsDir } from './accounts.js';
7
+ export { PluginShare, PLUGIN_SETTING_KEYS, MAX_PLUGIN_FILES, MAX_PLUGIN_BYTES } from './plugin-share.js';
7
8
  export { AgentAccountStore } from './agent-accounts.js';
8
9
  export { sandboxClaudeDir } from './claude-login.js';
@@ -0,0 +1,26 @@
1
+ /** The settings.json keys that belong to plugins; nothing else of settings.json is copied. */
2
+ export declare const PLUGIN_SETTING_KEYS: readonly ["enabledPlugins", "extraKnownMarketplaces"];
3
+ export declare const MAX_PLUGIN_FILES = 20000;
4
+ export declare const MAX_PLUGIN_BYTES: number;
5
+ export type PluginShareResult = 'saved' | 'restored' | 'nothing';
6
+ /** Copies a plugins folder: every entry a plain file or folder with a safe name, within the file and size caps. */
7
+ export declare function copyPluginTree(from: string, to: string): void;
8
+ export declare class PluginShare {
9
+ private readonly dir;
10
+ constructor(dir: string);
11
+ /** The shared set kept next to the saved accounts of a storage folder. */
12
+ static in(storageRoot: string): PluginShare;
13
+ /** When a sandbox ends: its plugins refresh the shared set. Never throws; returns the problem, if any. */
14
+ saveQuietly(dataPath: string, claudeDir: string): string | null;
15
+ private get pluginsDir();
16
+ private get settingsFile();
17
+ hasShared(): boolean;
18
+ /** Whether a Claude folder (the sandbox's) has plugins installed. */
19
+ static hasPlugins(claudeDir: string): boolean;
20
+ /** The plugins of a data set's Claude folder become the shared set (replacing the old one). */
21
+ save(dataPath: string, claudeDir: string): void;
22
+ /** The shared set goes into a data set's Claude folder; its own settings win, its other settings are untouched. */
23
+ restore(dataPath: string, claudeDir: string): void;
24
+ /** One step when an account is switched to. */
25
+ sync(dataPath: string, claudeDir: string): PluginShareResult;
26
+ }
@@ -0,0 +1,146 @@
1
+ // Claude plugins carried between sandbox data sets when the account changes (claudeProfile.sharePluginsAcrossAccounts).
2
+ // One plugin set is kept in host-only storage (<storage>\accounts\shared-plugins): the plugins folder plus the plugin
3
+ // keys of settings.json. A data set that has plugins refreshes it; one that has none (a fresh data set) receives it.
4
+ // The sandbox wrote everything it holds: no links, bounded file count and size, nothing is executed, and logins
5
+ // (.credentials.json, .claude.json) never travel with it.
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import { isSafeFileName } from '../../shared/paths/index.js';
9
+ import { safeRemove } from '../../shared/io/index.js';
10
+ import { assertNoLinks, ensureDir, errMsg, fail, fileExists, isLink, removeLink } from '../../core/util/index.js';
11
+ import { assertTestWritable } from '../test-guard.js';
12
+ import { readUntrusted, writeSandboxJson } from './claude-login.js';
13
+ /** The settings.json keys that belong to plugins; nothing else of settings.json is copied. */
14
+ export const PLUGIN_SETTING_KEYS = ['enabledPlugins', 'extraKnownMarketplaces'];
15
+ export const MAX_PLUGIN_FILES = 20000;
16
+ export const MAX_PLUGIN_BYTES = 1024 * 1024 * 1024;
17
+ const MAX_SETTINGS_BYTES = 4 * 1024 * 1024;
18
+ const MAX_DEPTH = 24;
19
+ const INSTALLED = 'installed_plugins.json';
20
+ function isObject(value) {
21
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
22
+ }
23
+ /** Copies a plugins folder: every entry a plain file or folder with a safe name, within the file and size caps. */
24
+ export function copyPluginTree(from, to) {
25
+ let files = 0;
26
+ let bytes = 0;
27
+ const walk = (src, dest, depth) => {
28
+ if (depth > MAX_DEPTH)
29
+ fail('The plugins folder is nested too deeply (' + from + ').', 'Remove the odd folders.');
30
+ ensureDir(dest);
31
+ for (const entry of fs.readdirSync(src)) {
32
+ const file = path.join(src, entry);
33
+ if (!isSafeFileName(entry))
34
+ fail('Plugin file name refused: ' + entry, 'Remove it from ' + from + '.');
35
+ if (isLink(file))
36
+ fail('Refusing to copy plugins: ' + file + ' is a link.', 'Remove the link and try again.');
37
+ const stat = fs.statSync(file);
38
+ if (stat.isDirectory())
39
+ walk(file, path.join(dest, entry), depth + 1);
40
+ else if (stat.isFile()) {
41
+ files++;
42
+ bytes += stat.size;
43
+ if (files > MAX_PLUGIN_FILES || bytes > MAX_PLUGIN_BYTES)
44
+ fail('The plugins are too big to copy between accounts.', 'Remove unused plugins and try again.');
45
+ fs.copyFileSync(file, path.join(dest, entry));
46
+ }
47
+ }
48
+ };
49
+ walk(from, to, 0);
50
+ }
51
+ function pluginSettings(claudeDir) {
52
+ const settings = readUntrusted(path.join(claudeDir, 'settings.json'), MAX_SETTINGS_BYTES);
53
+ const out = {};
54
+ if (isObject(settings))
55
+ for (const key of PLUGIN_SETTING_KEYS)
56
+ if (isObject(settings[key]))
57
+ out[key] = settings[key];
58
+ return out;
59
+ }
60
+ export class PluginShare {
61
+ dir;
62
+ constructor(dir) {
63
+ this.dir = dir;
64
+ }
65
+ /** The shared set kept next to the saved accounts of a storage folder. */
66
+ static in(storageRoot) {
67
+ return new PluginShare(path.join(storageRoot, 'accounts', 'shared-plugins'));
68
+ }
69
+ /** When a sandbox ends: its plugins refresh the shared set. Never throws; returns the problem, if any. */
70
+ saveQuietly(dataPath, claudeDir) {
71
+ try {
72
+ if (PluginShare.hasPlugins(claudeDir))
73
+ this.save(dataPath, claudeDir);
74
+ return null;
75
+ }
76
+ catch (e) {
77
+ return errMsg(e);
78
+ }
79
+ }
80
+ get pluginsDir() {
81
+ return path.join(this.dir, 'plugins');
82
+ }
83
+ get settingsFile() {
84
+ return path.join(this.dir, 'settings.json');
85
+ }
86
+ hasShared() {
87
+ return fileExists(path.join(this.pluginsDir, INSTALLED));
88
+ }
89
+ /** Whether a Claude folder (the sandbox's) has plugins installed. */
90
+ static hasPlugins(claudeDir) {
91
+ const file = path.join(claudeDir, 'plugins', INSTALLED);
92
+ return !isLink(path.join(claudeDir, 'plugins')) && !isLink(file) && fileExists(file);
93
+ }
94
+ /** The plugins of a data set's Claude folder become the shared set (replacing the old one). */
95
+ save(dataPath, claudeDir) {
96
+ assertNoLinks(dataPath, path.join(claudeDir, 'plugins'));
97
+ assertTestWritable(this.dir);
98
+ const tmp = this.pluginsDir + '.new';
99
+ fs.rmSync(tmp, { recursive: true, force: true });
100
+ try {
101
+ copyPluginTree(path.join(claudeDir, 'plugins'), tmp);
102
+ }
103
+ catch (e) {
104
+ fs.rmSync(tmp, { recursive: true, force: true });
105
+ throw e;
106
+ }
107
+ fs.rmSync(this.pluginsDir, { recursive: true, force: true });
108
+ fs.renameSync(tmp, this.pluginsDir);
109
+ writeSandboxJson(this.settingsFile, pluginSettings(claudeDir));
110
+ }
111
+ /** The shared set goes into a data set's Claude folder; its own settings win, its other settings are untouched. */
112
+ restore(dataPath, claudeDir) {
113
+ assertNoLinks(dataPath, claudeDir);
114
+ const target = path.join(claudeDir, 'plugins');
115
+ ensureDir(claudeDir);
116
+ if (isLink(target))
117
+ removeLink(target);
118
+ else
119
+ safeRemove(target, claudeDir);
120
+ copyPluginTree(this.pluginsDir, target);
121
+ const shared = readUntrusted(this.settingsFile, MAX_SETTINGS_BYTES);
122
+ if (!isObject(shared))
123
+ return;
124
+ const file = path.join(claudeDir, 'settings.json');
125
+ const own = readUntrusted(file, MAX_SETTINGS_BYTES);
126
+ if (own !== null && !isObject(own))
127
+ return;
128
+ const merged = { ...(own ?? {}) };
129
+ for (const key of PLUGIN_SETTING_KEYS)
130
+ if (isObject(shared[key]))
131
+ merged[key] = { ...shared[key], ...(isObject(merged[key]) ? merged[key] : {}) };
132
+ writeSandboxJson(file, merged);
133
+ }
134
+ /** One step when an account is switched to. */
135
+ sync(dataPath, claudeDir) {
136
+ if (PluginShare.hasPlugins(claudeDir)) {
137
+ this.save(dataPath, claudeDir);
138
+ return 'saved';
139
+ }
140
+ if (this.hasShared()) {
141
+ this.restore(dataPath, claudeDir);
142
+ return 'restored';
143
+ }
144
+ return 'nothing';
145
+ }
146
+ }
@@ -1,8 +1,14 @@
1
1
  import type { ResolvedRun } from '../../core/types.js';
2
2
  import { type Missing } from '../../core/local-config/index.js';
3
3
  import { type ProjectSpec } from '../../shared/channel/index.js';
4
- import { type RegistryEntry } from './registry.js';
4
+ import { type Registry, type RegistryEntry } from './registry.js';
5
5
  import { type ProjectMapper } from './mapper.js';
6
+ /**
7
+ * The running sandbox's registry. When run\projects.json is missing, cannot be read or belongs to an earlier sandbox
8
+ * (another copy or version of this tool started this one), it is rebuilt from the launch folder, so a folder in one of
9
+ * the sandbox's roots can still join. null: no running sandbox reported a launch, or nothing to rebuild it from.
10
+ */
11
+ export declare function runningRegistry(storageRoot: string, dataPath: string, protections: Registry['protections']): Registry | null;
6
12
  /** The launch folder of the running sandbox (host-only storage; its id comes from the guest, so it is checked). */
7
13
  export declare function runningLaunchPath(storageRoot: string, dataPath: string): string | null;
8
14
  /** What a session or command from this folder needs: where it is inside, and (for another project) its spec. */
@@ -17,12 +17,29 @@ import { RepoGuardStore } from '../guard/index.js';
17
17
  import { ProjectRegistry } from './registry.js';
18
18
  import { NeedsRestart, projectMapper } from './mapper.js';
19
19
  import { KnownProjects } from './known.js';
20
+ /** A launch id as the launch writes it (it comes back from the guest, so it is checked before it names a folder). */
21
+ const LAUNCH_ID = /^\d+-[0-9a-f]{6}$/;
22
+ /**
23
+ * The running sandbox's registry. When run\projects.json is missing, cannot be read or belongs to an earlier sandbox
24
+ * (another copy or version of this tool started this one), it is rebuilt from the launch folder, so a folder in one of
25
+ * the sandbox's roots can still join. null: no running sandbox reported a launch, or nothing to rebuild it from.
26
+ */
27
+ export function runningRegistry(storageRoot, dataPath, protections) {
28
+ const file = new ProjectRegistry(storageRoot);
29
+ const current = file.read();
30
+ const launchId = new RunDir(dataPath).readSandboxStatus()?.launchId;
31
+ if (!launchId || !LAUNCH_ID.test(launchId))
32
+ return current;
33
+ if (current?.launchId === launchId)
34
+ return current;
35
+ const launchPath = path.join(storageRoot, 'launches', launchId);
36
+ assertNoLinks(storageRoot, launchPath);
37
+ return file.rebuild(launchPath, launchId, protections);
38
+ }
20
39
  /** The launch folder of the running sandbox (host-only storage; its id comes from the guest, so it is checked). */
21
40
  export function runningLaunchPath(storageRoot, dataPath) {
22
41
  const launchId = new RunDir(dataPath).readSandboxStatus()?.launchId;
23
- if (!launchId ||
24
- !/^\d+-[0-9a-f]{6}$/.test(launchId) ||
25
- new ProjectRegistry(storageRoot).read()?.launchId !== launchId)
42
+ if (!launchId || !LAUNCH_ID.test(launchId) || new ProjectRegistry(storageRoot).read()?.launchId !== launchId)
26
43
  return null;
27
44
  const launchPath = path.join(storageRoot, 'launches', launchId);
28
45
  assertNoLinks(storageRoot, launchPath);
@@ -54,7 +71,7 @@ export async function joinRunning(o) {
54
71
  if (here?.project.primary)
55
72
  return { ...here, spec: null, run: null, notes: [], missing: null };
56
73
  const registry = registryFile.read() ??
57
- fail('The running sandbox was started by an older version, so it cannot take another folder.', 'Stop it (sandbox stop) and start it again.');
74
+ fail("The record of the running sandbox's projects is missing, and its launch folder could not replace it.", 'Run sandbox doctor (it shows which copy of sandbox runs), or stop the sandbox (sandbox stop) and start it again.');
58
75
  // A folder below a project already in the sandbox uses that project; anything else becomes a project of its own.
59
76
  const root = here?.project.host ?? path.resolve(o.hostDir);
60
77
  const run = await o.resolve(root);
@@ -9,44 +9,44 @@ declare const RegistryEntrySchema: z.ZodObject<{
9
9
  host: z.ZodString;
10
10
  guest: z.ZodString;
11
11
  primary: z.ZodBoolean;
12
- mechanism: z.ZodEnum<{
12
+ mechanism: z.ZodCatch<z.ZodEnum<{
13
13
  root: "root";
14
14
  launch: "launch";
15
15
  boot: "boot";
16
16
  wsb: "wsb";
17
- }>;
17
+ }>>;
18
18
  registeredAt: z.ZodString;
19
- }, z.core.$strict>;
19
+ }, z.core.$strip>;
20
20
  declare const RegistrySchema: z.ZodObject<{
21
21
  launchId: z.ZodString;
22
22
  protections: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
23
23
  roots: z.ZodArray<z.ZodObject<{
24
24
  host: z.ZodString;
25
25
  guest: z.ZodString;
26
- }, z.core.$strict>>;
26
+ }, z.core.$strip>>;
27
27
  projects: z.ZodArray<z.ZodObject<{
28
28
  name: z.ZodString;
29
29
  host: z.ZodString;
30
30
  guest: z.ZodString;
31
31
  primary: z.ZodBoolean;
32
- mechanism: z.ZodEnum<{
32
+ mechanism: z.ZodCatch<z.ZodEnum<{
33
33
  root: "root";
34
34
  launch: "launch";
35
35
  boot: "boot";
36
36
  wsb: "wsb";
37
- }>;
37
+ }>>;
38
38
  registeredAt: z.ZodString;
39
- }, z.core.$strict>>;
39
+ }, z.core.$strip>>;
40
40
  atBoot: z.ZodOptional<z.ZodObject<{
41
41
  memoryMb: z.ZodNullable<z.ZodNumber>;
42
42
  mappings: z.ZodArray<z.ZodObject<{
43
43
  host: z.ZodString;
44
44
  guest: z.ZodString;
45
45
  readOnly: z.ZodBoolean;
46
- }, z.core.$strict>>;
46
+ }, z.core.$strip>>;
47
47
  widened: z.ZodRecord<z.ZodString, z.ZodString>;
48
- }, z.core.$strict>>;
49
- }, z.core.$strict>;
48
+ }, z.core.$strip>>;
49
+ }, z.core.$strip>;
50
50
  export type AtBoot = NonNullable<z.output<typeof RegistrySchema>['atBoot']>;
51
51
  export type RegistryEntry = z.output<typeof RegistryEntrySchema>;
52
52
  export type Registry = z.output<typeof RegistrySchema>;
@@ -79,6 +79,12 @@ export declare class ProjectRegistry {
79
79
  here(hostDir: string): ProjectHere | null;
80
80
  /** The running sandbox's root containing this folder, if any. */
81
81
  rootHere(hostDir: string): RootMapping | null;
82
+ /**
83
+ * The record rebuilt from the running sandbox's launch folder (host-only storage), for when run\projects.json is
84
+ * missing, cannot be read or belongs to an earlier sandbox: the launch folder, and every folder mapped for other
85
+ * projects at boot as a root. Saved and returned; null when the launch folder does not have what it takes.
86
+ */
87
+ rebuild(launchPath: string, launchId: string, protections: Registry['protections']): Registry | null;
82
88
  }
83
89
  /**
84
90
  * The projects of a sandbox another user started and shares: what that user's record lists, in the shape of a registry.