windows-development-sandbox 0.0.0-stage → 1.1.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 (426) hide show
  1. package/.sandbox-config.example.json +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +94 -2
  4. package/config.example.json +349 -0
  5. package/dist/api.d.ts +31 -0
  6. package/dist/api.js +31 -0
  7. package/dist/bin/agent-sandbox.d.ts +2 -0
  8. package/dist/bin/agent-sandbox.js +3 -0
  9. package/dist/bin/claude-host.d.ts +2 -0
  10. package/dist/bin/claude-host.js +5 -0
  11. package/dist/bin/claude-sbx.d.ts +2 -0
  12. package/dist/bin/claude-sbx.js +3 -0
  13. package/dist/bin/codex-sbx.d.ts +2 -0
  14. package/dist/bin/codex-sbx.js +3 -0
  15. package/dist/bin/gemini-sbx.d.ts +2 -0
  16. package/dist/bin/gemini-sbx.js +3 -0
  17. package/dist/bin/sandbox.d.ts +2 -0
  18. package/dist/bin/sandbox.js +4 -0
  19. package/dist/bin/sbx-hide.d.ts +2 -0
  20. package/dist/bin/sbx-hide.js +3 -0
  21. package/dist/bin/sbx-show.d.ts +2 -0
  22. package/dist/bin/sbx-show.js +3 -0
  23. package/dist/cli/args.d.ts +52 -0
  24. package/dist/cli/args.js +143 -0
  25. package/dist/cli/colors.d.ts +24 -0
  26. package/dist/cli/colors.js +42 -0
  27. package/dist/cli/commands/accounts.d.ts +2 -0
  28. package/dist/cli/commands/accounts.js +52 -0
  29. package/dist/cli/commands/agent-commands.d.ts +6 -0
  30. package/dist/cli/commands/agent-commands.js +61 -0
  31. package/dist/cli/commands/context.d.ts +23 -0
  32. package/dist/cli/commands/context.js +57 -0
  33. package/dist/cli/commands/data/clean.d.ts +15 -0
  34. package/dist/cli/commands/data/clean.js +101 -0
  35. package/dist/cli/commands/data/collect.d.ts +11 -0
  36. package/dist/cli/commands/data/collect.js +54 -0
  37. package/dist/cli/commands/data/index.d.ts +4 -0
  38. package/dist/cli/commands/data/index.js +45 -0
  39. package/dist/cli/commands/data/remove.d.ts +2 -0
  40. package/dist/cli/commands/data/remove.js +30 -0
  41. package/dist/cli/commands/index.d.ts +10 -0
  42. package/dist/cli/commands/index.js +10 -0
  43. package/dist/cli/commands/launch.d.ts +29 -0
  44. package/dist/cli/commands/launch.js +333 -0
  45. package/dist/cli/commands/maintenance.d.ts +8 -0
  46. package/dist/cli/commands/maintenance.js +154 -0
  47. package/dist/cli/commands/project.d.ts +29 -0
  48. package/dist/cli/commands/project.js +63 -0
  49. package/dist/cli/commands/projects.d.ts +14 -0
  50. package/dist/cli/commands/projects.js +146 -0
  51. package/dist/cli/commands/repair/checks.d.ts +2 -0
  52. package/dist/cli/commands/repair/checks.js +170 -0
  53. package/dist/cli/commands/repair/finders.d.ts +30 -0
  54. package/dist/cli/commands/repair/finders.js +108 -0
  55. package/dist/cli/commands/repair/index.d.ts +12 -0
  56. package/dist/cli/commands/repair/index.js +61 -0
  57. package/dist/cli/commands/repair/types.d.ts +26 -0
  58. package/dist/cli/commands/repair/types.js +3 -0
  59. package/dist/cli/commands/restart.d.ts +6 -0
  60. package/dist/cli/commands/restart.js +85 -0
  61. package/dist/cli/commands/sessions.d.ts +12 -0
  62. package/dist/cli/commands/sessions.js +257 -0
  63. package/dist/cli/commands/setup/checks.d.ts +13 -0
  64. package/dist/cli/commands/setup/checks.js +71 -0
  65. package/dist/cli/commands/setup/facts.d.ts +31 -0
  66. package/dist/cli/commands/setup/facts.js +60 -0
  67. package/dist/cli/commands/setup/index.d.ts +2 -0
  68. package/dist/cli/commands/setup/index.js +43 -0
  69. package/dist/cli/commands/user-config.d.ts +8 -0
  70. package/dist/cli/commands/user-config.js +41 -0
  71. package/dist/cli/history.d.ts +11 -0
  72. package/dist/cli/history.js +21 -0
  73. package/dist/cli/index.d.ts +20 -0
  74. package/dist/cli/index.js +121 -0
  75. package/dist/cli/manifest.d.ts +103 -0
  76. package/dist/cli/manifest.js +107 -0
  77. package/dist/cli/menu-multi.d.ts +12 -0
  78. package/dist/cli/menu-multi.js +82 -0
  79. package/dist/cli/menu.d.ts +14 -0
  80. package/dist/cli/menu.js +290 -0
  81. package/dist/cli/progress.d.ts +9 -0
  82. package/dist/cli/progress.js +49 -0
  83. package/dist/cli/settings/edit.d.ts +13 -0
  84. package/dist/cli/settings/edit.js +19 -0
  85. package/dist/cli/settings/index.d.ts +8 -0
  86. package/dist/cli/settings/index.js +131 -0
  87. package/dist/cli/settings/prompts.d.ts +7 -0
  88. package/dist/cli/settings/prompts.js +48 -0
  89. package/dist/cli/settings/schema.d.ts +33 -0
  90. package/dist/cli/settings/schema.js +29 -0
  91. package/dist/cli/validate.d.ts +17 -0
  92. package/dist/cli/validate.js +89 -0
  93. package/dist/core/config.d.ts +17 -0
  94. package/dist/core/config.js +106 -0
  95. package/dist/core/detect-databases.d.ts +15 -0
  96. package/dist/core/detect-databases.js +147 -0
  97. package/dist/core/detect-pwsh.d.ts +18 -0
  98. package/dist/core/detect-pwsh.js +111 -0
  99. package/dist/core/detect-toolchains.d.ts +30 -0
  100. package/dist/core/detect-toolchains.js +58 -0
  101. package/dist/core/disk.d.ts +16 -0
  102. package/dist/core/disk.js +55 -0
  103. package/dist/core/local-config.d.ts +20 -0
  104. package/dist/core/local-config.js +77 -0
  105. package/dist/core/project-policy.d.ts +15 -0
  106. package/dist/core/project-policy.js +35 -0
  107. package/dist/core/prompt.d.ts +4 -0
  108. package/dist/core/prompt.js +15 -0
  109. package/dist/core/safe-paths.d.ts +4 -0
  110. package/dist/core/safe-paths.js +37 -0
  111. package/dist/core/schema/common.d.ts +17 -0
  112. package/dist/core/schema/common.js +15 -0
  113. package/dist/core/schema/config.d.ts +594 -0
  114. package/dist/core/schema/config.js +63 -0
  115. package/dist/core/schema/databases.d.ts +33 -0
  116. package/dist/core/schema/databases.js +35 -0
  117. package/dist/core/schema/harness.d.ts +12 -0
  118. package/dist/core/schema/harness.js +17 -0
  119. package/dist/core/schema/json-schema.d.ts +5 -0
  120. package/dist/core/schema/json-schema.js +25 -0
  121. package/dist/core/schema/profile.d.ts +27 -0
  122. package/dist/core/schema/profile.js +29 -0
  123. package/dist/core/schema/projects.d.ts +9 -0
  124. package/dist/core/schema/projects.js +11 -0
  125. package/dist/core/schema/sandbox.d.ts +50 -0
  126. package/dist/core/schema/sandbox.js +36 -0
  127. package/dist/core/schema/toolchains.d.ts +93 -0
  128. package/dist/core/schema/toolchains.js +83 -0
  129. package/dist/core/schema.d.ts +6 -0
  130. package/dist/core/schema.js +8 -0
  131. package/dist/core/types.d.ts +190 -0
  132. package/dist/core/types.js +1 -0
  133. package/dist/core/util.d.ts +60 -0
  134. package/dist/core/util.js +154 -0
  135. package/dist/core/workspace.d.ts +18 -0
  136. package/dist/core/workspace.js +128 -0
  137. package/dist/guest/boot-env.d.ts +4 -0
  138. package/dist/guest/boot-env.js +25 -0
  139. package/dist/guest/cmdline.d.ts +12 -0
  140. package/dist/guest/cmdline.js +23 -0
  141. package/dist/guest/daemon/exec.d.ts +5 -0
  142. package/dist/guest/daemon/exec.js +32 -0
  143. package/dist/guest/daemon/project.d.ts +14 -0
  144. package/dist/guest/daemon/project.js +132 -0
  145. package/dist/guest/daemon/session.d.ts +13 -0
  146. package/dist/guest/daemon/session.js +139 -0
  147. package/dist/guest/daemon/shutdown.d.ts +1 -0
  148. package/dist/guest/daemon/shutdown.js +21 -0
  149. package/dist/guest/daemon/state.d.ts +17 -0
  150. package/dist/guest/daemon/state.js +31 -0
  151. package/dist/guest/daemon.d.ts +1 -0
  152. package/dist/guest/daemon.js +53 -0
  153. package/dist/guest/db.d.ts +1 -0
  154. package/dist/guest/db.js +75 -0
  155. package/dist/guest/env.d.ts +51 -0
  156. package/dist/guest/env.js +101 -0
  157. package/dist/guest/gitguard.d.ts +7 -0
  158. package/dist/guest/gitguard.js +60 -0
  159. package/dist/guest/gitrules.d.ts +2 -0
  160. package/dist/guest/gitrules.js +11 -0
  161. package/dist/guest/guide.d.ts +16 -0
  162. package/dist/guest/guide.js +69 -0
  163. package/dist/guest/helpers.d.ts +3 -0
  164. package/dist/guest/helpers.js +26 -0
  165. package/dist/guest/main.d.ts +1 -0
  166. package/dist/guest/main.js +130 -0
  167. package/dist/guest/ports.d.ts +6 -0
  168. package/dist/guest/ports.js +22 -0
  169. package/dist/guest/project-context.d.ts +7 -0
  170. package/dist/guest/project-context.js +10 -0
  171. package/dist/guest/project-env.d.ts +20 -0
  172. package/dist/guest/project-env.js +20 -0
  173. package/dist/guest/project-status.d.ts +5 -0
  174. package/dist/guest/project-status.js +17 -0
  175. package/dist/guest/ptyhost.d.ts +22 -0
  176. package/dist/guest/ptyhost.js +36 -0
  177. package/dist/guest/setup/agents.d.ts +11 -0
  178. package/dist/guest/setup/agents.js +87 -0
  179. package/dist/guest/setup/claude.d.ts +21 -0
  180. package/dist/guest/setup/claude.js +146 -0
  181. package/dist/guest/setup/environment.d.ts +16 -0
  182. package/dist/guest/setup/environment.js +69 -0
  183. package/dist/guest/setup/hooks.d.ts +9 -0
  184. package/dist/guest/setup/hooks.js +50 -0
  185. package/dist/guest/setup/network.d.ts +10 -0
  186. package/dist/guest/setup/network.js +99 -0
  187. package/dist/guest/setup/policy.d.ts +3 -0
  188. package/dist/guest/setup/policy.js +18 -0
  189. package/dist/guest/setup/user.d.ts +7 -0
  190. package/dist/guest/setup/user.js +47 -0
  191. package/dist/guest/toolchains/catalogue.d.ts +55 -0
  192. package/dist/guest/toolchains/catalogue.js +31 -0
  193. package/dist/guest/toolchains/cli.d.ts +10 -0
  194. package/dist/guest/toolchains/cli.js +72 -0
  195. package/dist/guest/toolchains/common.d.ts +54 -0
  196. package/dist/guest/toolchains/common.js +147 -0
  197. package/dist/guest/toolchains/databases/dynamodb.d.ts +8 -0
  198. package/dist/guest/toolchains/databases/dynamodb.js +52 -0
  199. package/dist/guest/toolchains/databases/index.d.ts +6 -0
  200. package/dist/guest/toolchains/databases/index.js +62 -0
  201. package/dist/guest/toolchains/databases/mongodb.d.ts +3 -0
  202. package/dist/guest/toolchains/databases/mongodb.js +31 -0
  203. package/dist/guest/toolchains/databases/mysql.d.ts +3 -0
  204. package/dist/guest/toolchains/databases/mysql.js +38 -0
  205. package/dist/guest/toolchains/databases/postgres.d.ts +5 -0
  206. package/dist/guest/toolchains/databases/postgres.js +38 -0
  207. package/dist/guest/toolchains/databases/redis.d.ts +3 -0
  208. package/dist/guest/toolchains/databases/redis.js +16 -0
  209. package/dist/guest/toolchains/databases/server.d.ts +14 -0
  210. package/dist/guest/toolchains/databases/server.js +52 -0
  211. package/dist/guest/toolchains/git.d.ts +3 -0
  212. package/dist/guest/toolchains/git.js +121 -0
  213. package/dist/guest/toolchains/go.d.ts +3 -0
  214. package/dist/guest/toolchains/go.js +33 -0
  215. package/dist/guest/toolchains/index.d.ts +17 -0
  216. package/dist/guest/toolchains/index.js +80 -0
  217. package/dist/guest/toolchains/java.d.ts +8 -0
  218. package/dist/guest/toolchains/java.js +96 -0
  219. package/dist/guest/toolchains/leftovers.d.ts +2 -0
  220. package/dist/guest/toolchains/leftovers.js +26 -0
  221. package/dist/guest/toolchains/managers.d.ts +16 -0
  222. package/dist/guest/toolchains/managers.js +84 -0
  223. package/dist/guest/toolchains/native/binstall.d.ts +7 -0
  224. package/dist/guest/toolchains/native/binstall.js +52 -0
  225. package/dist/guest/toolchains/native/cpp.d.ts +4 -0
  226. package/dist/guest/toolchains/native/cpp.js +38 -0
  227. package/dist/guest/toolchains/native/dotnet.d.ts +4 -0
  228. package/dist/guest/toolchains/native/dotnet.js +103 -0
  229. package/dist/guest/toolchains/native/mesa.d.ts +7 -0
  230. package/dist/guest/toolchains/native/mesa.js +46 -0
  231. package/dist/guest/toolchains/native/msvc/environment.d.ts +16 -0
  232. package/dist/guest/toolchains/native/msvc/environment.js +57 -0
  233. package/dist/guest/toolchains/native/msvc/index.d.ts +6 -0
  234. package/dist/guest/toolchains/native/msvc/index.js +48 -0
  235. package/dist/guest/toolchains/native/msvc/packages.d.ts +6 -0
  236. package/dist/guest/toolchains/native/msvc/packages.js +156 -0
  237. package/dist/guest/toolchains/native/msvc/tree.d.ts +15 -0
  238. package/dist/guest/toolchains/native/msvc/tree.js +21 -0
  239. package/dist/guest/toolchains/native/rust.d.ts +3 -0
  240. package/dist/guest/toolchains/native/rust.js +45 -0
  241. package/dist/guest/toolchains/node.d.ts +3 -0
  242. package/dist/guest/toolchains/node.js +152 -0
  243. package/dist/guest/toolchains/plan.d.ts +22 -0
  244. package/dist/guest/toolchains/plan.js +96 -0
  245. package/dist/guest/toolchains/pwsh.d.ts +4 -0
  246. package/dist/guest/toolchains/pwsh.js +14 -0
  247. package/dist/guest/toolchains/python.d.ts +3 -0
  248. package/dist/guest/toolchains/python.js +54 -0
  249. package/dist/guest/toolchains/runtimes.d.ts +19 -0
  250. package/dist/guest/toolchains/runtimes.js +38 -0
  251. package/dist/guest/toolchains/scripting/php.d.ts +3 -0
  252. package/dist/guest/toolchains/scripting/php.js +71 -0
  253. package/dist/guest/toolchains/scripting/ruby.d.ts +3 -0
  254. package/dist/guest/toolchains/scripting/ruby.js +47 -0
  255. package/dist/guest/toolchains/scripting/vcruntime.d.ts +7 -0
  256. package/dist/guest/toolchains/scripting/vcruntime.js +45 -0
  257. package/dist/guest/toolchains/versions.d.ts +47 -0
  258. package/dist/guest/toolchains/versions.js +77 -0
  259. package/dist/guest/toolchains/vscode.d.ts +2 -0
  260. package/dist/guest/toolchains/vscode.js +53 -0
  261. package/dist/guest/view.d.ts +1 -0
  262. package/dist/guest/view.js +42 -0
  263. package/dist/host/accounts.d.ts +32 -0
  264. package/dist/host/accounts.js +128 -0
  265. package/dist/host/agent-commands.d.ts +25 -0
  266. package/dist/host/agent-commands.js +145 -0
  267. package/dist/host/attach.d.ts +17 -0
  268. package/dist/host/attach.js +69 -0
  269. package/dist/host/channel.d.ts +38 -0
  270. package/dist/host/channel.js +162 -0
  271. package/dist/host/claude-profile.d.ts +15 -0
  272. package/dist/host/claude-profile.js +107 -0
  273. package/dist/host/cleanup.d.ts +23 -0
  274. package/dist/host/cleanup.js +57 -0
  275. package/dist/host/database-plan.d.ts +12 -0
  276. package/dist/host/database-plan.js +52 -0
  277. package/dist/host/generate.d.ts +7 -0
  278. package/dist/host/generate.js +98 -0
  279. package/dist/host/join.d.ts +28 -0
  280. package/dist/host/join.js +76 -0
  281. package/dist/host/launch/mappings.d.ts +3 -0
  282. package/dist/host/launch/mappings.js +50 -0
  283. package/dist/host/launch/projects.d.ts +15 -0
  284. package/dist/host/launch/projects.js +56 -0
  285. package/dist/host/launch/stage.d.ts +11 -0
  286. package/dist/host/launch/stage.js +66 -0
  287. package/dist/host/launch/wsb.d.ts +10 -0
  288. package/dist/host/launch/wsb.js +34 -0
  289. package/dist/host/pc-scan.d.ts +6 -0
  290. package/dist/host/pc-scan.js +37 -0
  291. package/dist/host/personalize.d.ts +10 -0
  292. package/dist/host/personalize.js +97 -0
  293. package/dist/host/platform.d.ts +19 -0
  294. package/dist/host/platform.js +126 -0
  295. package/dist/host/project-scan.d.ts +7 -0
  296. package/dist/host/project-scan.js +89 -0
  297. package/dist/host/projects.d.ts +100 -0
  298. package/dist/host/projects.js +147 -0
  299. package/dist/host/repo-guard.d.ts +36 -0
  300. package/dist/host/repo-guard.js +219 -0
  301. package/dist/host/secrets.d.ts +14 -0
  302. package/dist/host/secrets.js +133 -0
  303. package/dist/host/terminal.d.ts +32 -0
  304. package/dist/host/terminal.js +130 -0
  305. package/dist/host/test-guard.d.ts +6 -0
  306. package/dist/host/test-guard.js +15 -0
  307. package/dist/host/window.d.ts +4 -0
  308. package/dist/host/window.js +72 -0
  309. package/dist/host/wsb.d.ts +37 -0
  310. package/dist/host/wsb.js +101 -0
  311. package/dist/runtime/daemon.js +28494 -0
  312. package/dist/runtime/db.js +26387 -0
  313. package/dist/runtime/gitguard.js +84 -0
  314. package/dist/runtime/main.js +28622 -0
  315. package/dist/runtime/view.js +25841 -0
  316. package/dist/selftest/accounts.test.d.ts +2 -0
  317. package/dist/selftest/accounts.test.js +44 -0
  318. package/dist/selftest/agent-commands.test.d.ts +2 -0
  319. package/dist/selftest/agent-commands.test.js +47 -0
  320. package/dist/selftest/channel.test.d.ts +2 -0
  321. package/dist/selftest/channel.test.js +37 -0
  322. package/dist/selftest/cli.test.d.ts +2 -0
  323. package/dist/selftest/cli.test.js +118 -0
  324. package/dist/selftest/cmdline.test.d.ts +2 -0
  325. package/dist/selftest/cmdline.test.js +45 -0
  326. package/dist/selftest/config.test.d.ts +2 -0
  327. package/dist/selftest/config.test.js +38 -0
  328. package/dist/selftest/data.test.d.ts +2 -0
  329. package/dist/selftest/data.test.js +80 -0
  330. package/dist/selftest/detect.test.d.ts +2 -0
  331. package/dist/selftest/detect.test.js +58 -0
  332. package/dist/selftest/fixtures.d.ts +272 -0
  333. package/dist/selftest/fixtures.js +80 -0
  334. package/dist/selftest/generate.test.d.ts +2 -0
  335. package/dist/selftest/generate.test.js +63 -0
  336. package/dist/selftest/git-access.test.d.ts +2 -0
  337. package/dist/selftest/git-access.test.js +26 -0
  338. package/dist/selftest/guest-boot.test.d.ts +2 -0
  339. package/dist/selftest/guest-boot.test.js +76 -0
  340. package/dist/selftest/harness.d.ts +51 -0
  341. package/dist/selftest/harness.js +77 -0
  342. package/dist/selftest/host-sim.test.d.ts +2 -0
  343. package/dist/selftest/host-sim.test.js +93 -0
  344. package/dist/selftest/hostile-input.test.d.ts +2 -0
  345. package/dist/selftest/hostile-input.test.js +54 -0
  346. package/dist/selftest/index.d.ts +8 -0
  347. package/dist/selftest/index.js +155 -0
  348. package/dist/selftest/links.test.d.ts +2 -0
  349. package/dist/selftest/links.test.js +50 -0
  350. package/dist/selftest/live-daemon.test.d.ts +2 -0
  351. package/dist/selftest/live-daemon.test.js +91 -0
  352. package/dist/selftest/live-git.test.d.ts +2 -0
  353. package/dist/selftest/live-git.test.js +60 -0
  354. package/dist/selftest/live-projects.test.d.ts +2 -0
  355. package/dist/selftest/live-projects.test.js +127 -0
  356. package/dist/selftest/live.d.ts +65 -0
  357. package/dist/selftest/live.js +109 -0
  358. package/dist/selftest/local-config.test.d.ts +2 -0
  359. package/dist/selftest/local-config.test.js +107 -0
  360. package/dist/selftest/mirror.test.d.ts +2 -0
  361. package/dist/selftest/mirror.test.js +101 -0
  362. package/dist/selftest/network.test.d.ts +2 -0
  363. package/dist/selftest/network.test.js +28 -0
  364. package/dist/selftest/personalization.test.d.ts +2 -0
  365. package/dist/selftest/personalization.test.js +53 -0
  366. package/dist/selftest/projects.test.d.ts +2 -0
  367. package/dist/selftest/projects.test.js +254 -0
  368. package/dist/selftest/repair.test.d.ts +2 -0
  369. package/dist/selftest/repair.test.js +42 -0
  370. package/dist/selftest/repo-guard.test.d.ts +2 -0
  371. package/dist/selftest/repo-guard.test.js +63 -0
  372. package/dist/selftest/secrets.test.d.ts +2 -0
  373. package/dist/selftest/secrets.test.js +71 -0
  374. package/dist/selftest/setup.test.d.ts +2 -0
  375. package/dist/selftest/setup.test.js +46 -0
  376. package/dist/selftest/suite.d.ts +13 -0
  377. package/dist/selftest/suite.js +1 -0
  378. package/dist/selftest/sync.test.d.ts +2 -0
  379. package/dist/selftest/sync.test.js +94 -0
  380. package/dist/selftest/test-guard.test.d.ts +2 -0
  381. package/dist/selftest/test-guard.test.js +49 -0
  382. package/dist/selftest/toolchains.test.d.ts +2 -0
  383. package/dist/selftest/toolchains.test.js +103 -0
  384. package/dist/selftest/workspace.test.d.ts +2 -0
  385. package/dist/selftest/workspace.test.js +53 -0
  386. package/dist/shared/download.d.ts +60 -0
  387. package/dist/shared/download.js +215 -0
  388. package/dist/shared/guest-paths.d.ts +30 -0
  389. package/dist/shared/guest-paths.js +61 -0
  390. package/dist/shared/netrules.d.ts +18 -0
  391. package/dist/shared/netrules.js +98 -0
  392. package/dist/shared/paths.d.ts +14 -0
  393. package/dist/shared/paths.js +28 -0
  394. package/dist/shared/projects.d.ts +53 -0
  395. package/dist/shared/projects.js +67 -0
  396. package/dist/shared/pty-client.d.ts +86 -0
  397. package/dist/shared/pty-client.js +227 -0
  398. package/dist/shared/rundir.d.ts +39 -0
  399. package/dist/shared/rundir.js +94 -0
  400. package/dist/shared/safe-remove.d.ts +10 -0
  401. package/dist/shared/safe-remove.js +66 -0
  402. package/dist/shared/schema.d.ts +527 -0
  403. package/dist/shared/schema.js +90 -0
  404. package/dist/shared/system.d.ts +15 -0
  405. package/dist/shared/system.js +19 -0
  406. package/dist/shared/test-guard.d.ts +4 -0
  407. package/dist/shared/test-guard.js +37 -0
  408. package/dist/sync/claude-mem.d.ts +8 -0
  409. package/dist/sync/claude-mem.js +79 -0
  410. package/dist/sync/history.d.ts +41 -0
  411. package/dist/sync/history.js +161 -0
  412. package/dist/sync/watcher.d.ts +21 -0
  413. package/dist/sync/watcher.js +135 -0
  414. package/hooks/post-agent/README.txt +1 -0
  415. package/hooks/pre-provision/README.txt +1 -0
  416. package/package.json +91 -4
  417. package/sandbox/bootstrap.ps1 +258 -0
  418. package/sandbox/cpucap.ps1 +51 -0
  419. package/sandbox/gitshim.cs +35 -0
  420. package/sandbox/logon.cmd +18 -0
  421. package/sandbox/openssl.cs +42 -0
  422. package/sandbox/ptyhost.cs +614 -0
  423. package/sandbox/trust.cmd +35 -0
  424. package/sandbox/vswhere.cs +83 -0
  425. package/schemas/config.schema.json +1161 -0
  426. package/schemas/sandbox-config.schema.json +968 -0
@@ -0,0 +1,19 @@
1
+ import type { Config, HostProbe } from '../core/types.js';
2
+ /** What can be copied from this PC instead of downloaded inside the sandbox. */
3
+ export declare const probeHost: (config: Config, harnessName: string) => HostProbe;
4
+ /**
5
+ * Running INSIDE a Windows Sandbox this tool started (its launch folder and data folder are mapped in): then the CLI
6
+ * talks to the sandbox it is in, through C:\\AgentData and loopback, instead of looking for one on a PC.
7
+ */
8
+ export declare const insideSandbox: () => boolean;
9
+ export declare const GUEST_DATA_DIR = "C:\\AgentData";
10
+ export declare const isSandboxRunning: () => boolean;
11
+ export declare const sandboxFeatureInstalled: () => boolean;
12
+ export declare const assertCanLaunch: () => void;
13
+ /** cmd.exe expands %VAR% and ^ even inside quotes, and a quote ends them: such a path could run something else. */
14
+ export declare const assertCmdSafePath: (file: string) => void;
15
+ export declare const startSandbox: (wsbPath: string) => void;
16
+ /** Runs a detached copy of this CLI (used for the background history/claude-mem sync watcher). */
17
+ export declare const spawnDetached: (entry: string, args: string[]) => void;
18
+ export declare const hostClaude: (storageRoot: string, personal: boolean, args: string[]) => number;
19
+ export declare const doctorRows: (config: Config, harnessName: string, storageRoot: string, configPath: string | null) => [string, string][];
@@ -0,0 +1,126 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { spawn, spawnSync } from 'node:child_process';
5
+ import { SYSTEM } from '../shared/system.js';
6
+ import { refuseInSelfTest } from './test-guard.js';
7
+ import { commandsDir, realAgent } from './agent-commands.js';
8
+ import { dirExists, ensureDir, fail, fileExists, findOnPath, homeDir, isWin, realPath } from '../core/util.js';
9
+ const findHarnessExe = (config, harnessName) => {
10
+ const harness = config.harnesses[harnessName];
11
+ if (!harness?.hostExecutable)
12
+ return null;
13
+ const explicit = harness.hostDir && harness.hostDir !== 'auto' ? path.join(harness.hostDir, harness.hostExecutable) : null;
14
+ const found = explicit
15
+ ? (fileExists(explicit) ? explicit : null)
16
+ : findOnPath([harness.hostExecutable]) ?? [path.join(homeDir(), '.local', 'bin', harness.hostExecutable)].find(fileExists) ?? null;
17
+ if (!found)
18
+ return null;
19
+ const real = realPath(found);
20
+ return { dir: path.dirname(real), file: path.basename(real) };
21
+ };
22
+ /** Git for Windows root (the folder with cmd\git.exe and bin\bash.exe), from git on PATH. */
23
+ const findGitRoot = () => {
24
+ const git = findOnPath(['git.exe']);
25
+ if (!git)
26
+ return null;
27
+ const root = path.resolve(path.dirname(realPath(git)), '..');
28
+ return fileExists(path.join(root, 'bin', 'bash.exe')) ? root : null;
29
+ };
30
+ /** What can be copied from this PC instead of downloaded inside the sandbox. */
31
+ export const probeHost = (config, harnessName) => {
32
+ const nodeDir = isWin ? path.dirname(process.execPath) : null;
33
+ const copy = config.provisioning.copyFromHost;
34
+ const nvmHome = process.env.NVM_HOME;
35
+ const nvmDir = copy && nvmHome && dirExists(nvmHome) ? realPath(nvmHome) : null;
36
+ const hasNode = (dir) => fileExists(path.join(dir, 'node.exe')) && fileExists(path.join(dir, 'node_modules', 'npm', 'bin', 'npm-cli.js'));
37
+ // One source for Node: nvm's copy of this version when there is one, otherwise the Node folder itself.
38
+ const nvmNode = Boolean(nvmDir && hasNode(path.join(nvmDir, process.version)));
39
+ return {
40
+ nodeDir: copy && !nvmNode && nodeDir && hasNode(nodeDir) ? realPath(nodeDir) : null,
41
+ harnessExe: copy ? findHarnessExe(config, harnessName) : null,
42
+ gitDir: copy && config.provisioning.git.enabled ? findGitRoot() : null,
43
+ nvmDir,
44
+ hostNodeVersion: process.version,
45
+ nvmNode,
46
+ volta: Boolean(process.env.VOLTA_HOME),
47
+ pyenv: Boolean(process.env.PYENV ?? process.env.PYENV_ROOT ?? process.env.PYENV_HOME),
48
+ };
49
+ };
50
+ const SANDBOX_PROCESSES = ['WindowsSandboxClient.exe', 'WindowsSandboxRemoteSession.exe', 'WindowsSandbox.exe'];
51
+ /**
52
+ * Running INSIDE a Windows Sandbox this tool started (its launch folder and data folder are mapped in): then the CLI
53
+ * talks to the sandbox it is in, through C:\\AgentData and loopback, instead of looking for one on a PC.
54
+ */
55
+ export const insideSandbox = () => isWin && !process.env.AGENT_SANDBOX_HOST_ONLY && fs.existsSync('C:\\AgentLaunch\\session.json') && fs.existsSync('C:\\AgentData\\run');
56
+ export const GUEST_DATA_DIR = 'C:\\AgentData';
57
+ export const isSandboxRunning = () => {
58
+ if (!isWin)
59
+ return false;
60
+ if (insideSandbox())
61
+ return true;
62
+ const result = spawnSync(SYSTEM.tasklist(), ['/NH', '/FO', 'CSV'], { encoding: 'utf8', windowsHide: true });
63
+ const out = (result.stdout ?? '').toLowerCase();
64
+ return SANDBOX_PROCESSES.some((image) => out.includes('"' + image.toLowerCase() + '"'));
65
+ };
66
+ export const sandboxFeatureInstalled = () => isWin && fileExists(path.join(process.env.WINDIR ?? 'C:\\Windows', 'System32', 'WindowsSandbox.exe'));
67
+ export const assertCanLaunch = () => {
68
+ if (!isWin)
69
+ fail('Windows Sandbox only runs on Windows.', 'Use sandbox generate to only write the files.');
70
+ if (!sandboxFeatureInstalled())
71
+ fail('Windows Sandbox is not enabled on this PC.', 'Run in an admin PowerShell, then reboot: Enable-WindowsOptionalFeature -Online -FeatureName Containers-DisposableClientVM -All (needs Windows Pro, Enterprise or Education)');
72
+ if (isSandboxRunning())
73
+ fail('A Windows Sandbox is already running (Windows allows one at a time).', 'Attach to it with sandbox claude -t, show it with sbx-show, or shut it down with sandbox stop.');
74
+ };
75
+ /** cmd.exe expands %VAR% and ^ even inside quotes, and a quote ends them: such a path could run something else. */
76
+ export const assertCmdSafePath = (file) => {
77
+ if (/[%"^\r\n]/.test(file))
78
+ fail('The storage folder path has a character that cannot be started safely: ' + file, 'Set storage.root to a folder without % " ^ in its path.');
79
+ };
80
+ export const startSandbox = (wsbPath) => {
81
+ refuseInSelfTest('start Windows Sandbox');
82
+ assertCmdSafePath(wsbPath);
83
+ const result = spawnSync(SYSTEM.cmd(), ['/d', '/c', 'start', '""', '"' + wsbPath + '"'], { stdio: 'inherit', windowsVerbatimArguments: true });
84
+ if (result.error)
85
+ throw result.error;
86
+ };
87
+ /** Runs a detached copy of this CLI (used for the background history/claude-mem sync watcher). */
88
+ export const spawnDetached = (entry, args) => {
89
+ refuseInSelfTest('start background programs');
90
+ // cwd = the install folder: the caller's folder is the workspace, which the sandbox can write.
91
+ spawn(process.execPath, [entry, ...args], { cwd: path.dirname(entry), detached: true, stdio: 'ignore', windowsHide: true }).unref();
92
+ };
93
+ export const hostClaude = (storageRoot, personal, args) => {
94
+ refuseInSelfTest('run Claude Code on this PC');
95
+ // Never this tool's own forwarding command (agentCommands), which would start a sandbox instead.
96
+ const exe = realAgent('claude', commandsDir(storageRoot));
97
+ if (!exe)
98
+ fail('Claude Code is not installed on this PC (no claude.exe or claude.cmd on PATH).', 'Install it: npm install -g @anthropic-ai/claude-code');
99
+ const env = { ...process.env };
100
+ if (!personal) {
101
+ const profile = path.join(storageRoot, 'host', 'claude');
102
+ ensureDir(profile);
103
+ env.CLAUDE_CONFIG_DIR = profile;
104
+ console.warn('Host Claude is NOT sandboxed. Using separate profile: ' + profile + ' (pass --personal to use your normal one).');
105
+ }
106
+ const result = exe.toLowerCase().endsWith('.cmd') ? spawnSync(SYSTEM.cmd(), ['/d', '/c', exe, ...args], { stdio: 'inherit', env }) : spawnSync(exe, args, { stdio: 'inherit', env });
107
+ if (result.error)
108
+ throw result.error;
109
+ return result.status ?? 1;
110
+ };
111
+ export const doctorRows = (config, harnessName, storageRoot, configPath) => {
112
+ const probe = probeHost(config, harnessName);
113
+ return [
114
+ ['Config file', configPath ?? '(none; built-in defaults; create one with: sandbox config init)'],
115
+ ['Windows', isWin ? 'yes' : 'NO (launch needs Windows)'],
116
+ ['Windows Sandbox feature', sandboxFeatureInstalled() ? 'enabled' : 'NOT enabled'],
117
+ ['Sandbox running', isSandboxRunning() ? 'YES' : 'no'],
118
+ ['Free host RAM (MB)', String(Math.floor(os.freemem() / 1048576))],
119
+ ['Provisioning', config.provisioning.copyFromHost ? 'copy from this PC' + (config.provisioning.fallbackToInstall ? ', fall back to download' : ', no fallback') : 'download inside sandbox'],
120
+ ['Host Node (runner)', probe.nvmNode ? 'nvm ' + probe.hostNodeVersion : probe.nodeDir ?? '(none; will download)'],
121
+ ['Host nvm versions', probe.nvmDir ?? '(no NVM_HOME; versions will be downloaded)'],
122
+ ['Host ' + harnessName, probe.harnessExe ? path.join(probe.harnessExe.dir, probe.harnessExe.file) : '(none; will npm install)'],
123
+ ['Host Git for Windows', probe.gitDir ?? '(none with bash; PortableGit will be downloaded)'],
124
+ ['Storage root', storageRoot + (dirExists(storageRoot) ? '' : ' (will be created)')],
125
+ ];
126
+ };
@@ -0,0 +1,7 @@
1
+ import { type ProjectFile } from '../core/detect-databases.js';
2
+ /** Manifest-type files in the project, up to 3 folders deep. Links are not followed (the workspace may be guest-written). */
3
+ export declare const readProjectFiles: (root: string, depth?: number) => ProjectFile[];
4
+ /** File names in the project and its direct sub-folders ("api/go.mod"), for toolchain detection. No links followed. */
5
+ export declare const projectEntries: (root: string) => string[];
6
+ /** Scripts in the project root or one folder down that set up MSVC (vcvars*.bat, vswhere): read with bounded effort. */
7
+ export declare const msvcHint: (root: string) => string | undefined;
@@ -0,0 +1,89 @@
1
+ // Reads a project the way detect-databases.ts and detect-toolchains.ts need it (only manifest/config files, bounded).
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { INTERESTING_FILE } from '../core/detect-databases.js';
5
+ const SKIP = /^(node_modules|\.git|\.hg|\.svn|vendor|target|bin|obj|dist|build|out|\.next|\.nuxt|\.venv|venv|env|__pycache__|\.gradle|\.idea|\.vs|coverage|packages)$/i;
6
+ const MAX_FILES = 400;
7
+ const MAX_BYTES = 256 * 1024;
8
+ const MAX_FOLDERS = 2000;
9
+ /** Reads a file through one handle, only if that handle is a regular file of at most MAX_BYTES. */
10
+ const readSmallFile = (file) => {
11
+ let fd = null;
12
+ try {
13
+ fd = fs.openSync(file, 'r');
14
+ const stat = fs.fstatSync(fd);
15
+ if (!stat.isFile() || stat.size > MAX_BYTES)
16
+ return null;
17
+ const buffer = Buffer.alloc(stat.size);
18
+ fs.readSync(fd, buffer, 0, stat.size, 0);
19
+ return buffer.toString('utf8');
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ finally {
25
+ if (fd !== null)
26
+ fs.closeSync(fd);
27
+ }
28
+ };
29
+ /** Manifest-type files in the project, up to 3 folders deep. Links are not followed (the workspace may be guest-written). */
30
+ export const readProjectFiles = (root, depth = 3) => {
31
+ const files = [];
32
+ let folders = 0;
33
+ const walk = (dir, level) => {
34
+ if (++folders > MAX_FOLDERS)
35
+ return;
36
+ let entries;
37
+ try {
38
+ entries = fs.readdirSync(dir, { withFileTypes: true });
39
+ }
40
+ catch {
41
+ return;
42
+ }
43
+ for (const entry of entries) {
44
+ if (files.length >= MAX_FILES)
45
+ return;
46
+ const full = path.join(dir, entry.name);
47
+ if (entry.isFile() && INTERESTING_FILE.test(entry.name)) {
48
+ const text = readSmallFile(full);
49
+ if (text !== null)
50
+ files.push({ path: path.relative(root, full), text });
51
+ }
52
+ else if (entry.isDirectory() && level < depth && !SKIP.test(entry.name))
53
+ walk(full, level + 1);
54
+ }
55
+ };
56
+ walk(root, 0);
57
+ return files;
58
+ };
59
+ /** File names in the project and its direct sub-folders ("api/go.mod"), for toolchain detection. No links followed. */
60
+ export const projectEntries = (root) => {
61
+ const list = (dir) => { try {
62
+ return fs.readdirSync(dir, { withFileTypes: true }).slice(0, 2000);
63
+ }
64
+ catch {
65
+ return [];
66
+ } };
67
+ const top = list(root);
68
+ const below = top.filter((d) => d.isDirectory() && !d.name.startsWith('.') && !SKIP.test(d.name)).slice(0, 200)
69
+ .flatMap((d) => list(path.join(root, d.name)).filter((f) => f.isFile()).map((f) => d.name + '/' + f.name));
70
+ return [...top.filter((d) => d.isFile()).map((d) => d.name), ...below];
71
+ };
72
+ /** Scripts in the project root or one folder down that set up MSVC (vcvars*.bat, vswhere): read with bounded effort. */
73
+ export const msvcHint = (root) => {
74
+ const scripts = projectEntries(root).filter((e) => /\.(ps1|cmd|bat|psm1)$/i.test(e)).slice(0, 60);
75
+ for (const rel of scripts) {
76
+ let text = '';
77
+ try {
78
+ const file = path.join(root, rel);
79
+ if (fs.statSync(file).size <= 256 * 1024)
80
+ text = fs.readFileSync(file, 'utf8');
81
+ }
82
+ catch {
83
+ continue;
84
+ }
85
+ if (/vcvars(all|64|32)?\.bat|vswhere(\.exe)?/i.test(text))
86
+ return rel + ' sets up MSVC';
87
+ }
88
+ return undefined;
89
+ };
@@ -0,0 +1,100 @@
1
+ import { z } from 'zod';
2
+ import { PROJECTS_GUEST, type ProjectEntry, type RootMapping } from '../shared/projects.js';
3
+ import { type Wsb } from './wsb.js';
4
+ export { PROJECTS_GUEST };
5
+ export type { ProjectEntry };
6
+ declare const Entry: z.ZodObject<{
7
+ name: z.ZodString;
8
+ host: z.ZodString;
9
+ guest: z.ZodString;
10
+ primary: z.ZodBoolean;
11
+ mechanism: z.ZodEnum<{
12
+ root: "root";
13
+ launch: "launch";
14
+ boot: "boot";
15
+ wsb: "wsb";
16
+ }>;
17
+ registeredAt: z.ZodString;
18
+ }, z.core.$strict>;
19
+ declare const Registry: z.ZodObject<{
20
+ launchId: z.ZodString;
21
+ protections: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
22
+ roots: z.ZodArray<z.ZodObject<{
23
+ host: z.ZodString;
24
+ guest: z.ZodString;
25
+ }, z.core.$strict>>;
26
+ projects: z.ZodArray<z.ZodObject<{
27
+ name: z.ZodString;
28
+ host: z.ZodString;
29
+ guest: z.ZodString;
30
+ primary: z.ZodBoolean;
31
+ mechanism: z.ZodEnum<{
32
+ root: "root";
33
+ launch: "launch";
34
+ boot: "boot";
35
+ wsb: "wsb";
36
+ }>;
37
+ registeredAt: z.ZodString;
38
+ }, z.core.$strict>>;
39
+ }, z.core.$strict>;
40
+ export type RegistryEntry = z.output<typeof Entry>;
41
+ export type ProjectRegistry = z.output<typeof Registry>;
42
+ export declare const readRegistry: (storageRoot: string) => ProjectRegistry | null;
43
+ /** At launch: the launch folder, the projects mapped with it, and the roots. */
44
+ export declare const startRegistry: (storageRoot: string, o: {
45
+ launchId: string;
46
+ protections: ProjectRegistry["protections"];
47
+ primary: RootMapping;
48
+ roots: RootMapping[];
49
+ boot: RootMapping[];
50
+ }) => RegistryEntry;
51
+ /** Why a folder cannot join the running sandbox without a restart (the caller offers one). */
52
+ export declare class NeedsRestart extends Error {
53
+ readonly hostDir: string;
54
+ readonly reason: string;
55
+ constructor(hostDir: string, reason: string);
56
+ }
57
+ export interface ProjectMapper {
58
+ /** The projects of the running sandbox (the launch folder first). */
59
+ list(): RegistryEntry[];
60
+ /** Makes a folder of this PC a project of the running sandbox; throws NeedsRestart when that needs a restart. */
61
+ register(hostDir: string): RegistryEntry;
62
+ /** Forgets a project (never the launch folder). Its folder stays visible until the next start if it is mapped. */
63
+ unregister(name: string): void;
64
+ }
65
+ export interface MapperOptions {
66
+ storageRoot: string;
67
+ packageRoot: string;
68
+ wsbShare: boolean;
69
+ detect?: () => Wsb | null;
70
+ }
71
+ /** Roots first (instant), then `wsb share` where the Windows Sandbox CLI exists, else NeedsRestart. */
72
+ export declare const projectMapper: (o: MapperOptions) => ProjectMapper;
73
+ /** Which project of the running sandbox a folder on this PC is in, and where that folder is inside. */
74
+ export interface ProjectHere {
75
+ project: RegistryEntry;
76
+ guestDir: string;
77
+ }
78
+ export declare const projectHere: (storageRoot: string, hostDir: string) => ProjectHere | null;
79
+ /** The running sandbox's root containing this folder, if any. */
80
+ export declare const rootHere: (storageRoot: string, hostDir: string) => RootMapping | null;
81
+ declare const Known: z.ZodObject<{
82
+ projects: z.ZodArray<z.ZodObject<{
83
+ host: z.ZodString;
84
+ lastUsed: z.ZodString;
85
+ }, z.core.$strict>>;
86
+ }, z.core.$strict>;
87
+ export type KnownProject = z.output<typeof Known>['projects'][number];
88
+ export declare const readKnown: (storageRoot: string) => KnownProject[];
89
+ export declare const rememberProject: (storageRoot: string, hostDir: string) => void;
90
+ export declare const forgetProject: (storageRoot: string, hostDir: string) => boolean;
91
+ /**
92
+ * projects.all: the known projects mapped at boot on their own (existing folders, not excluded, not the launch folder,
93
+ * not inside it or a root, which already show them). Pure apart from checking that the folders exist.
94
+ */
95
+ export declare const allProjectsToMap: (known: string[], o: {
96
+ primary: string;
97
+ roots: string[];
98
+ exclude: string[];
99
+ exists?: (p: string) => boolean;
100
+ }) => string[];
@@ -0,0 +1,147 @@
1
+ // The projects of the running sandbox, and how another folder joins it (shared/projects.ts explains the ways in).
2
+ // Two host-only files under the storage folder, never in the data folder the sandbox can write:
3
+ // - run\projects.json: the running sandbox's projects, roots and machine-wide protections (written at launch, then
4
+ // as folders join);
5
+ // - known-projects.json: every folder this tool has started a project in (for projects.all and `sandbox projects`).
6
+ // Everything about HOW a folder becomes visible is behind ProjectMapper, so the mechanisms can change independently.
7
+ import path from 'node:path';
8
+ import { z } from 'zod';
9
+ import { assertSafeWorkspace } from '../core/safe-paths.js';
10
+ import { dirExists, fail } from '../core/util.js';
11
+ import { Id } from '../shared/schema.js';
12
+ import { readValid, writeJsonAtomic } from '../shared/rundir.js';
13
+ import { guestDirFor, hubName, isWithin, PROJECTS_GUEST, projectForHostDir } from '../shared/projects.js';
14
+ import { detectWsb, runningSandboxId, shareFolder } from './wsb.js';
15
+ export { PROJECTS_GUEST };
16
+ const AbsolutePath = z.string().max(1024).refine((p) => path.isAbsolute(p), 'must be an absolute path');
17
+ const Entry = z.strictObject({
18
+ name: Id, host: AbsolutePath, guest: z.string().max(1024), primary: z.boolean(),
19
+ mechanism: z.enum(['launch', 'root', 'boot', 'wsb']), registeredAt: z.string().max(64),
20
+ });
21
+ const Registry = z.strictObject({
22
+ launchId: z.string().max(64),
23
+ /** The running sandbox's protections (core/project-policy.ts), fixed at boot. */
24
+ protections: z.record(z.string(), z.union([z.boolean(), z.string()])),
25
+ roots: z.array(z.strictObject({ host: AbsolutePath, guest: z.string().max(1024) })).max(64),
26
+ projects: z.array(Entry).max(1024),
27
+ });
28
+ const registryFile = (storageRoot) => path.join(storageRoot, 'run', 'projects.json');
29
+ export const readRegistry = (storageRoot) => readValid(Registry, registryFile(storageRoot));
30
+ const saveRegistry = (storageRoot, registry) => writeJsonAtomic(registryFile(storageRoot), registry);
31
+ /** At launch: the launch folder, the projects mapped with it, and the roots. */
32
+ export const startRegistry = (storageRoot, o) => {
33
+ const at = new Date().toISOString();
34
+ const primary = { name: hubName(o.primary.host, []), host: o.primary.host, guest: o.primary.guest, primary: true, mechanism: 'launch', registeredAt: at };
35
+ const names = [primary.name];
36
+ const boot = o.boot.map((b) => { const name = hubName(b.host, names); names.push(name); return { name, host: b.host, guest: b.guest, primary: false, mechanism: 'boot', registeredAt: at }; });
37
+ saveRegistry(storageRoot, { launchId: o.launchId, protections: o.protections, roots: o.roots, projects: [primary, ...boot] });
38
+ return primary;
39
+ };
40
+ /** Why a folder cannot join the running sandbox without a restart (the caller offers one). */
41
+ export class NeedsRestart extends Error {
42
+ hostDir;
43
+ reason;
44
+ constructor(hostDir, reason) {
45
+ super(reason);
46
+ this.hostDir = hostDir;
47
+ this.reason = reason;
48
+ }
49
+ }
50
+ /** Roots first (instant), then `wsb share` where the Windows Sandbox CLI exists, else NeedsRestart. */
51
+ export const projectMapper = (o) => {
52
+ const registry = () => readRegistry(o.storageRoot) ?? fail('The running sandbox was started by an older version, so it cannot take another folder.', 'Stop it (sandbox stop) and start it again.');
53
+ const add = (reg, host, guest, mechanism, name) => {
54
+ const entry = { name, host, guest, primary: false, mechanism, registeredAt: new Date().toISOString() };
55
+ // Re-read right before writing: another terminal may have registered something meanwhile.
56
+ const latest = readRegistry(o.storageRoot) ?? reg;
57
+ const same = latest.projects.find((p) => p.host.toLowerCase() === host.toLowerCase());
58
+ if (same)
59
+ return same;
60
+ saveRegistry(o.storageRoot, { ...latest, projects: [...latest.projects, entry] });
61
+ return entry;
62
+ };
63
+ return {
64
+ list: () => readRegistry(o.storageRoot)?.projects ?? [],
65
+ register: (hostDir) => {
66
+ const host = path.resolve(hostDir);
67
+ const reg = registry();
68
+ const known = reg.projects.find((p) => p.host.toLowerCase() === host.toLowerCase());
69
+ if (known)
70
+ return known;
71
+ assertSafeWorkspace(host, o.packageRoot, o.storageRoot);
72
+ if (!dirExists(host))
73
+ fail('The folder does not exist: ' + host);
74
+ const name = hubName(host, reg.projects.map((p) => p.name));
75
+ // Inside a root: visible already (also a project created after the sandbox started).
76
+ const root = projectForHostDir(reg.roots, host);
77
+ if (root)
78
+ return add(reg, host, guestDirFor(root, host), 'root', name);
79
+ if (!o.wsbShare)
80
+ throw new NeedsRestart(host, 'it is not inside a project root (projects.roots), and adding folders with wsb share is off (projects.wsbShare)');
81
+ const wsb = (o.detect ?? detectWsb)();
82
+ if (!wsb?.has('share'))
83
+ throw new NeedsRestart(host, 'it is not inside a project root (projects.roots), and this Windows has no Windows Sandbox command line (wsb share needs Windows 11 24H2+ with the updated Windows Sandbox)');
84
+ const sandbox = runningSandboxId(wsb);
85
+ if (!sandbox.id)
86
+ throw new NeedsRestart(host, 'wsb share could not find the running sandbox: ' + sandbox.error);
87
+ const guest = path.win32.join(PROJECTS_GUEST, name);
88
+ const shared = shareFolder(wsb, sandbox.id, host, guest);
89
+ if (!shared.ok)
90
+ throw new NeedsRestart(host, 'wsb share failed (untested on this Windows): ' + shared.error);
91
+ return add(reg, host, guest, 'wsb', name);
92
+ },
93
+ unregister: (name) => {
94
+ const reg = registry();
95
+ const entry = reg.projects.find((p) => p.name.toLowerCase() === name.toLowerCase());
96
+ if (!entry)
97
+ fail('No project "' + name + '" in the running sandbox.', 'sandbox projects lists them.');
98
+ if (entry.primary)
99
+ fail(entry.host + ' is the folder the sandbox started from; it stays until the sandbox stops.');
100
+ saveRegistry(o.storageRoot, { ...reg, projects: reg.projects.filter((p) => p !== entry) });
101
+ },
102
+ };
103
+ };
104
+ export const projectHere = (storageRoot, hostDir) => {
105
+ const project = projectForHostDir(readRegistry(storageRoot)?.projects ?? [], hostDir);
106
+ return project ? { project, guestDir: guestDirFor(project, hostDir) } : null;
107
+ };
108
+ /** The running sandbox's root containing this folder, if any. */
109
+ export const rootHere = (storageRoot, hostDir) => projectForHostDir(readRegistry(storageRoot)?.roots ?? [], hostDir);
110
+ // ---- known projects (every folder a project was started in) ------------------------------------------------------
111
+ const Known = z.strictObject({ projects: z.array(z.strictObject({ host: AbsolutePath, lastUsed: z.string().max(64) })).max(2000) });
112
+ const knownFile = (storageRoot) => path.join(storageRoot, 'known-projects.json');
113
+ export const readKnown = (storageRoot) => readValid(Known, knownFile(storageRoot))?.projects ?? [];
114
+ export const rememberProject = (storageRoot, hostDir) => {
115
+ const host = path.resolve(hostDir);
116
+ const rest = readKnown(storageRoot).filter((p) => p.host.toLowerCase() !== host.toLowerCase());
117
+ try {
118
+ writeJsonAtomic(knownFile(storageRoot), { projects: [{ host, lastUsed: new Date().toISOString() }, ...rest].slice(0, 2000) });
119
+ }
120
+ catch { /* a convenience list */ }
121
+ };
122
+ export const forgetProject = (storageRoot, hostDir) => {
123
+ const host = path.resolve(hostDir);
124
+ const all = readKnown(storageRoot);
125
+ const rest = all.filter((p) => p.host.toLowerCase() !== host.toLowerCase());
126
+ if (rest.length !== all.length)
127
+ writeJsonAtomic(knownFile(storageRoot), { projects: rest });
128
+ return rest.length !== all.length;
129
+ };
130
+ /**
131
+ * projects.all: the known projects mapped at boot on their own (existing folders, not excluded, not the launch folder,
132
+ * not inside it or a root, which already show them). Pure apart from checking that the folders exist.
133
+ */
134
+ export const allProjectsToMap = (known, o) => {
135
+ const exists = o.exists ?? dirExists;
136
+ const out = [];
137
+ for (const host of known.map((k) => path.resolve(k))) {
138
+ if (o.exclude.some((e) => isWithin(path.resolve(e), host)))
139
+ continue;
140
+ if (isWithin(o.primary, host) || o.roots.some((r) => isWithin(r, host)))
141
+ continue;
142
+ if (out.some((x) => isWithin(x, host) || isWithin(host, x)) || !exists(host))
143
+ continue;
144
+ out.push(host);
145
+ }
146
+ return out;
147
+ };
@@ -0,0 +1,36 @@
1
+ export interface RepoSnapshot {
2
+ gitDir: boolean;
3
+ config: string[];
4
+ hooks: Record<string, string>;
5
+ redirects: string[];
6
+ commands: Record<string, string>;
7
+ }
8
+ export interface RepoFinding {
9
+ kind: 'hook' | 'config' | 'git' | 'command';
10
+ detail: string;
11
+ }
12
+ export declare const snapshotRepo: (workspace: string) => RepoSnapshot;
13
+ /**
14
+ * Compares the workspace with its pre-launch snapshot and neutralises anything new that would execute on this PC.
15
+ * Returns what was found (and fixed). Never touches what was already there before the sandbox ran.
16
+ */
17
+ export declare const guardRepo: (workspace: string, before: RepoSnapshot) => RepoFinding[];
18
+ /**
19
+ * At launch: every folder the sandbox will be able to write. The launch folder, projects mapped with it and every
20
+ * project already inside a project root are snapshotted as they are now, before the sandbox can touch them.
21
+ */
22
+ export declare const saveRepoSnapshot: (dataPath: string, workspace: string, more?: string[], roots?: string[]) => void;
23
+ /**
24
+ * A project that joins the running sandbox: snapshotted before its first session, then guarded like the launch
25
+ * folder. A project already guarded keeps its first snapshot (what was there before the sandbox could touch it).
26
+ */
27
+ export declare const addRepoSnapshot: (dataPath: string, workspace: string, o?: {
28
+ empty?: boolean;
29
+ }) => void;
30
+ /** The folders being guarded (for status). */
31
+ export declare const guardedProjects: (dataPath: string) => string[];
32
+ /** Re-checks every project of the current/last launch; findings are kept in a host-only file for `status`. Returns the new ones. */
33
+ export declare const checkRepo: (dataPath: string) => RepoFinding[];
34
+ export declare const repoFindings: (dataPath: string) => (RepoFinding & {
35
+ at?: string;
36
+ })[];