windows-development-sandbox 1.4.0 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (877) hide show
  1. package/.sandbox-config.example.json +2 -1
  2. package/config.example.json +4 -1
  3. package/dist/api.js +27 -16
  4. package/dist/cli/args.d.ts +4 -6
  5. package/dist/cli/args.js +67 -34
  6. package/dist/cli/argv.d.ts +9 -0
  7. package/dist/cli/argv.js +22 -0
  8. package/dist/cli/commands/accounts.d.ts +1 -1
  9. package/dist/cli/commands/accounts.js +42 -27
  10. package/dist/cli/commands/agent-commands.d.ts +3 -3
  11. package/dist/cli/commands/agent-commands.js +27 -18
  12. package/dist/cli/commands/context.d.ts +9 -11
  13. package/dist/cli/commands/context.js +35 -32
  14. package/dist/cli/commands/data/clean.d.ts +2 -2
  15. package/dist/cli/commands/data/clean.js +27 -11
  16. package/dist/cli/commands/data/collect.d.ts +6 -3
  17. package/dist/cli/commands/data/collect.js +46 -15
  18. package/dist/cli/commands/data/index.d.ts +2 -2
  19. package/dist/cli/commands/data/index.js +30 -12
  20. package/dist/cli/commands/data/remove.d.ts +1 -1
  21. package/dist/cli/commands/data/remove.js +4 -4
  22. package/dist/cli/commands/index.d.ts +5 -4
  23. package/dist/cli/commands/index.js +5 -4
  24. package/dist/cli/commands/launch/add-root.d.ts +7 -0
  25. package/dist/cli/commands/launch/add-root.js +64 -0
  26. package/dist/cli/commands/launch/boot-progress.d.ts +7 -0
  27. package/dist/cli/commands/launch/boot-progress.js +48 -0
  28. package/dist/cli/commands/launch/boot-wants.d.ts +11 -0
  29. package/dist/cli/commands/launch/boot-wants.js +48 -0
  30. package/dist/cli/commands/launch/first-start.d.ts +10 -0
  31. package/dist/cli/commands/launch/first-start.js +53 -0
  32. package/dist/cli/commands/launch/index.d.ts +6 -0
  33. package/dist/cli/commands/launch/index.js +6 -0
  34. package/dist/cli/commands/launch/launch.d.ts +8 -0
  35. package/dist/cli/commands/launch/launch.js +211 -0
  36. package/dist/cli/commands/launch/prepare.d.ts +23 -0
  37. package/dist/cli/commands/launch/prepare.js +109 -0
  38. package/dist/cli/commands/launch/running.d.ts +45 -0
  39. package/dist/cli/commands/launch/running.js +218 -0
  40. package/dist/cli/commands/launch/summary.d.ts +8 -0
  41. package/dist/cli/commands/launch/summary.js +98 -0
  42. package/dist/cli/commands/maintenance/audit.d.ts +3 -0
  43. package/dist/cli/commands/maintenance/audit.js +58 -0
  44. package/dist/cli/commands/maintenance/clean.d.ts +2 -0
  45. package/dist/cli/commands/maintenance/clean.js +10 -0
  46. package/dist/cli/commands/maintenance/config.d.ts +2 -0
  47. package/dist/cli/commands/maintenance/config.js +145 -0
  48. package/dist/cli/commands/maintenance/doctor.d.ts +2 -0
  49. package/dist/cli/commands/maintenance/doctor.js +52 -0
  50. package/dist/cli/commands/maintenance/host-claude.d.ts +2 -0
  51. package/dist/cli/commands/maintenance/host-claude.js +4 -0
  52. package/dist/cli/commands/maintenance/index.d.ts +8 -0
  53. package/dist/cli/commands/maintenance/index.js +9 -0
  54. package/dist/cli/commands/maintenance/logs.d.ts +2 -0
  55. package/dist/cli/commands/maintenance/logs.js +44 -0
  56. package/dist/cli/commands/maintenance/sync.d.ts +2 -0
  57. package/dist/cli/commands/maintenance/sync.js +12 -0
  58. package/dist/cli/commands/maintenance/watch.d.ts +3 -0
  59. package/dist/cli/commands/maintenance/watch.js +6 -0
  60. package/dist/cli/commands/projects/describe-sessions.d.ts +3 -0
  61. package/dist/cli/commands/projects/describe-sessions.js +15 -0
  62. package/dist/cli/commands/projects/here.d.ts +38 -0
  63. package/dist/cli/commands/projects/here.js +145 -0
  64. package/dist/cli/commands/projects/index.d.ts +4 -0
  65. package/dist/cli/commands/projects/index.js +4 -0
  66. package/dist/cli/commands/projects/projects.d.ts +14 -0
  67. package/dist/cli/commands/projects/projects.js +213 -0
  68. package/dist/cli/commands/projects/restart.d.ts +15 -0
  69. package/dist/cli/commands/projects/restart.js +149 -0
  70. package/dist/cli/commands/registry.d.ts +3 -0
  71. package/dist/cli/commands/registry.js +34 -0
  72. package/dist/cli/commands/repair/checks.js +105 -29
  73. package/dist/cli/commands/repair/finders.d.ts +13 -10
  74. package/dist/cli/commands/repair/finders.js +63 -43
  75. package/dist/cli/commands/repair/index.d.ts +4 -4
  76. package/dist/cli/commands/repair/index.js +47 -21
  77. package/dist/cli/commands/repair/types.d.ts +2 -2
  78. package/dist/cli/commands/repair/types.js +7 -2
  79. package/dist/cli/commands/sessions/attach.d.ts +2 -0
  80. package/dist/cli/commands/sessions/attach.js +45 -0
  81. package/dist/cli/commands/sessions/control.d.ts +4 -0
  82. package/dist/cli/commands/sessions/control.js +62 -0
  83. package/dist/cli/commands/sessions/exec.d.ts +6 -0
  84. package/dist/cli/commands/sessions/exec.js +72 -0
  85. package/dist/cli/commands/sessions/index.d.ts +6 -0
  86. package/dist/cli/commands/sessions/index.js +9 -0
  87. package/dist/cli/commands/sessions/list.d.ts +15 -0
  88. package/dist/cli/commands/sessions/list.js +65 -0
  89. package/dist/cli/commands/sessions/status.d.ts +2 -0
  90. package/dist/cli/commands/sessions/status.js +153 -0
  91. package/dist/cli/commands/sessions/window.d.ts +3 -0
  92. package/dist/cli/commands/sessions/window.js +18 -0
  93. package/dist/cli/commands/setup/checks.d.ts +4 -4
  94. package/dist/cli/commands/setup/checks.js +36 -19
  95. package/dist/cli/commands/setup/facts.d.ts +6 -6
  96. package/dist/cli/commands/setup/facts.js +23 -11
  97. package/dist/cli/commands/setup/index.d.ts +1 -1
  98. package/dist/cli/commands/setup/index.js +25 -12
  99. package/dist/cli/commands/user-config.d.ts +5 -5
  100. package/dist/cli/commands/user-config.js +14 -12
  101. package/dist/cli/history.d.ts +5 -4
  102. package/dist/cli/history.js +23 -11
  103. package/dist/cli/index.d.ts +4 -14
  104. package/dist/cli/index.js +27 -77
  105. package/dist/cli/manifest.d.ts +464 -10
  106. package/dist/cli/manifest.js +328 -54
  107. package/dist/cli/menu/apps.d.ts +7 -5
  108. package/dist/cli/menu/apps.js +64 -16
  109. package/dist/cli/menu/command-fields.d.ts +15 -0
  110. package/dist/cli/menu/command-fields.js +23 -0
  111. package/dist/cli/menu/command-form.d.ts +3 -5
  112. package/dist/cli/menu/command-form.js +116 -48
  113. package/dist/cli/menu/home.d.ts +22 -0
  114. package/dist/cli/menu/home.js +72 -0
  115. package/dist/cli/menu/index.d.ts +2 -24
  116. package/dist/cli/menu/index.js +4 -178
  117. package/dist/cli/menu/menu.d.ts +23 -0
  118. package/dist/cli/menu/menu.js +185 -0
  119. package/dist/cli/menu/settings/categories.d.ts +2 -2
  120. package/dist/cli/menu/settings/categories.js +123 -20
  121. package/dist/cli/menu/settings/collections/collection-editor.d.ts +23 -0
  122. package/dist/cli/menu/settings/collections/collection-editor.js +89 -0
  123. package/dist/cli/menu/settings/collections/map-editor.d.ts +10 -0
  124. package/dist/cli/menu/settings/collections/map-editor.js +34 -0
  125. package/dist/cli/menu/settings/collections/object-list-editor.d.ts +10 -0
  126. package/dist/cli/menu/settings/collections/object-list-editor.js +23 -0
  127. package/dist/cli/menu/settings/collections/object-map-editor.d.ts +10 -0
  128. package/dist/cli/menu/settings/collections/object-map-editor.js +35 -0
  129. package/dist/cli/menu/settings/collections/string-list-editor.d.ts +12 -0
  130. package/dist/cli/menu/settings/collections/string-list-editor.js +39 -0
  131. package/dist/cli/menu/settings/config-file.d.ts +2 -2
  132. package/dist/cli/menu/settings/config-file.js +42 -19
  133. package/dist/cli/menu/settings/editor-actions.d.ts +2 -0
  134. package/dist/cli/menu/settings/editor-actions.js +2 -0
  135. package/dist/cli/menu/settings/format.d.ts +5 -0
  136. package/dist/cli/menu/settings/format.js +39 -0
  137. package/dist/cli/menu/settings/index.d.ts +1 -29
  138. package/dist/cli/menu/settings/index.js +1 -133
  139. package/dist/cli/menu/settings/object-editor.d.ts +12 -0
  140. package/dist/cli/menu/settings/object-editor.js +86 -0
  141. package/dist/cli/menu/settings/schema-node.d.ts +3 -1
  142. package/dist/cli/menu/settings/schema-node.js +71 -24
  143. package/dist/cli/menu/settings/settings-editor.d.ts +30 -0
  144. package/dist/cli/menu/settings/settings-editor.js +176 -0
  145. package/dist/cli/menu/settings/{editors.d.ts → value-editor.d.ts} +2 -13
  146. package/dist/cli/menu/settings/value-editor.js +137 -0
  147. package/dist/cli/menu/several.d.ts +4 -4
  148. package/dist/cli/menu/several.js +61 -20
  149. package/dist/cli/{colors.d.ts → output/colors.d.ts} +8 -8
  150. package/dist/cli/{colors.js → output/colors.js} +32 -14
  151. package/dist/cli/output/index.d.ts +3 -0
  152. package/dist/cli/output/index.js +3 -0
  153. package/dist/cli/output/print.d.ts +5 -0
  154. package/dist/cli/output/print.js +14 -0
  155. package/dist/cli/output/progress.d.ts +24 -0
  156. package/dist/cli/output/progress.js +124 -0
  157. package/dist/cli/report.d.ts +2 -0
  158. package/dist/cli/report.js +20 -0
  159. package/dist/cli/tui/app.d.ts +6 -16
  160. package/dist/cli/tui/app.js +28 -8
  161. package/dist/cli/tui/dialogs/confirm-screen.d.ts +20 -0
  162. package/dist/cli/tui/dialogs/confirm-screen.js +50 -0
  163. package/dist/cli/tui/dialogs/message-screen.d.ts +17 -0
  164. package/dist/cli/tui/dialogs/message-screen.js +55 -0
  165. package/dist/cli/tui/dialogs/paragraphs.d.ts +2 -0
  166. package/dist/cli/tui/dialogs/paragraphs.js +5 -0
  167. package/dist/cli/tui/dialogs/text-screen.d.ts +26 -0
  168. package/dist/cli/tui/dialogs/text-screen.js +107 -0
  169. package/dist/cli/tui/frame.js +3 -1
  170. package/dist/cli/tui/index.d.ts +7 -3
  171. package/dist/cli/tui/index.js +4 -2
  172. package/dist/cli/tui/list/list-screen.d.ts +29 -0
  173. package/dist/cli/tui/{list-screen.js → list/list-screen.js} +86 -23
  174. package/dist/cli/tui/{list-screen.d.ts → list/list-types.d.ts} +0 -28
  175. package/dist/cli/tui/screen.d.ts +14 -0
  176. package/dist/cli/tui/terminal.js +34 -10
  177. package/dist/cli/tui/text.d.ts +2 -1
  178. package/dist/cli/tui/text.js +37 -7
  179. package/dist/cli/tui/theme.js +27 -9
  180. package/dist/cli/validate.d.ts +8 -8
  181. package/dist/cli/validate.js +32 -21
  182. package/dist/core/config/defaults.d.ts +2 -0
  183. package/dist/core/config/defaults.js +203 -0
  184. package/dist/core/config/index.d.ts +2 -0
  185. package/dist/core/config/index.js +3 -0
  186. package/dist/core/{config.d.ts → config/loader.d.ts} +1 -2
  187. package/dist/core/config/loader.js +47 -0
  188. package/dist/core/{detect-databases.js → detect/databases.js} +111 -23
  189. package/dist/core/detect/index.d.ts +4 -0
  190. package/dist/core/detect/index.js +4 -0
  191. package/dist/core/{detect-pwsh.d.ts → detect/pwsh.d.ts} +1 -1
  192. package/dist/core/{detect-pwsh.js → detect/pwsh.js} +25 -11
  193. package/dist/core/{detect-toolchains.d.ts → detect/toolchains.d.ts} +1 -1
  194. package/dist/core/{detect-toolchains.js → detect/toolchains.js} +42 -5
  195. package/dist/{guest/toolchains → core/detect}/versions.js +28 -12
  196. package/dist/core/disk.d.ts +2 -0
  197. package/dist/core/disk.js +46 -3
  198. package/dist/core/local-config/boot-wants.d.ts +45 -0
  199. package/dist/core/local-config/boot-wants.js +120 -0
  200. package/dist/core/local-config/file.d.ts +3 -0
  201. package/dist/core/local-config/file.js +16 -0
  202. package/dist/core/local-config/index.d.ts +5 -0
  203. package/dist/core/local-config/index.js +7 -0
  204. package/dist/core/{local-config.d.ts → local-config/overrides.d.ts} +11 -11
  205. package/dist/core/{local-config.js → local-config/overrides.js} +53 -54
  206. package/dist/core/{project-policy.d.ts → local-config/policy.d.ts} +7 -3
  207. package/dist/core/{project-policy.js → local-config/policy.js} +16 -6
  208. package/dist/core/local-config/trust.d.ts +13 -0
  209. package/dist/core/local-config/trust.js +43 -0
  210. package/dist/core/package-info.d.ts +4 -0
  211. package/dist/core/package-info.js +13 -0
  212. package/dist/core/run/guest-workspace.d.ts +23 -0
  213. package/dist/core/run/guest-workspace.js +47 -0
  214. package/dist/core/run/index.d.ts +3 -0
  215. package/dist/core/run/index.js +3 -0
  216. package/dist/core/run/resolve-run.d.ts +3 -0
  217. package/dist/core/run/resolve-run.js +202 -0
  218. package/dist/core/run/versions.d.ts +13 -0
  219. package/dist/core/run/versions.js +65 -0
  220. package/dist/core/safe-paths.js +17 -5
  221. package/dist/core/schema/apps.d.ts +4 -4
  222. package/dist/core/schema/apps.js +55 -21
  223. package/dist/core/schema/common.d.ts +13 -10
  224. package/dist/core/schema/common.js +16 -10
  225. package/dist/core/schema/config.d.ts +18 -12
  226. package/dist/core/schema/config.js +78 -53
  227. package/dist/core/schema/databases.d.ts +4 -3
  228. package/dist/core/schema/databases.js +16 -12
  229. package/dist/core/schema/harness.d.ts +1 -1
  230. package/dist/core/schema/harness.js +17 -7
  231. package/dist/core/schema/index.d.ts +6 -0
  232. package/dist/core/schema/index.js +8 -0
  233. package/dist/core/schema/json-schema.js +10 -5
  234. package/dist/core/schema/profile.d.ts +4 -4
  235. package/dist/core/schema/profile.js +37 -17
  236. package/dist/core/schema/projects.d.ts +2 -1
  237. package/dist/core/schema/projects.js +16 -5
  238. package/dist/core/schema/sandbox.d.ts +12 -12
  239. package/dist/core/schema/sandbox.js +101 -37
  240. package/dist/core/schema/toolchains.d.ts +6 -1
  241. package/dist/core/schema/toolchains.js +84 -34
  242. package/dist/core/types.d.ts +36 -9
  243. package/dist/core/util/errors.d.ts +8 -0
  244. package/dist/core/util/errors.js +14 -0
  245. package/dist/core/util/fs.d.ts +8 -0
  246. package/dist/core/util/fs.js +40 -0
  247. package/dist/core/util/index.d.ts +7 -0
  248. package/dist/core/util/index.js +7 -0
  249. package/dist/core/util/jsonc.d.ts +6 -0
  250. package/dist/core/util/jsonc.js +25 -0
  251. package/dist/core/util/links.d.ts +10 -0
  252. package/dist/core/util/links.js +39 -0
  253. package/dist/core/util/paths.d.ts +7 -0
  254. package/dist/core/util/paths.js +33 -0
  255. package/dist/core/util/process.d.ts +15 -0
  256. package/dist/core/util/process.js +54 -0
  257. package/dist/core/util/text.d.ts +8 -0
  258. package/dist/core/util/text.js +8 -0
  259. package/dist/guest/{setup/agents.js → agents/agent-installer.js} +24 -4
  260. package/dist/guest/apps/after-install.d.ts +3 -0
  261. package/dist/guest/apps/after-install.js +47 -0
  262. package/dist/guest/apps/app-installer.d.ts +22 -0
  263. package/dist/guest/apps/app-installer.js +116 -0
  264. package/dist/guest/apps/find-exe.d.ts +5 -0
  265. package/dist/guest/apps/find-exe.js +41 -0
  266. package/dist/guest/apps/index.d.ts +3 -10
  267. package/dist/guest/apps/index.js +6 -206
  268. package/dist/guest/apps/resolvers.js +37 -9
  269. package/dist/guest/apps/shortcuts.d.ts +6 -0
  270. package/dist/guest/apps/shortcuts.js +28 -0
  271. package/dist/guest/apps/sources.d.ts +4 -0
  272. package/dist/guest/apps/sources.js +17 -0
  273. package/dist/guest/apps/unpack.d.ts +3 -0
  274. package/dist/guest/apps/unpack.js +47 -0
  275. package/dist/guest/{audit-parse.js → audit/parse.js} +39 -3
  276. package/dist/guest/{audit.d.ts → audit/process-audit.d.ts} +3 -1
  277. package/dist/guest/{audit.js → audit/process-audit.js} +33 -8
  278. package/dist/guest/boot/boot-env.d.ts +4 -0
  279. package/dist/guest/{boot-env.js → boot/boot-env.js} +7 -5
  280. package/dist/guest/boot/boot.d.ts +1 -0
  281. package/dist/guest/{main.js → boot/boot.js} +100 -50
  282. package/dist/guest/{guide.js → boot/guide.js} +32 -7
  283. package/dist/guest/{project-env.d.ts → boot/project-env.d.ts} +3 -3
  284. package/dist/guest/{project-env.js → boot/project-env.js} +12 -4
  285. package/dist/guest/boot/project-status.d.ts +5 -0
  286. package/dist/guest/boot/project-status.js +28 -0
  287. package/dist/guest/daemon/daemon.d.ts +1 -0
  288. package/dist/guest/daemon/daemon.js +51 -0
  289. package/dist/guest/daemon/exec.js +18 -6
  290. package/dist/guest/daemon/{shutdown.js → idle-shutdown.js} +5 -4
  291. package/dist/guest/daemon/{project.d.ts → project-provisioner.d.ts} +3 -3
  292. package/dist/guest/daemon/{project.js → project-provisioner.js} +60 -22
  293. package/dist/guest/daemon/relays.js +5 -3
  294. package/dist/guest/daemon/{session.js → sessions.js} +84 -24
  295. package/dist/guest/daemon/state.d.ts +4 -1
  296. package/dist/guest/daemon/state.js +34 -20
  297. package/dist/guest/databases/database-server.d.ts +13 -0
  298. package/dist/guest/databases/database-server.js +35 -0
  299. package/dist/guest/databases/dynamodb.d.ts +12 -0
  300. package/dist/guest/databases/dynamodb.js +81 -0
  301. package/dist/guest/databases/index.d.ts +2 -0
  302. package/dist/guest/databases/index.js +2 -0
  303. package/dist/guest/databases/mongodb.d.ts +7 -0
  304. package/dist/guest/databases/mongodb.js +46 -0
  305. package/dist/guest/databases/mysql.d.ts +7 -0
  306. package/dist/guest/databases/mysql.js +59 -0
  307. package/dist/guest/databases/names.d.ts +5 -0
  308. package/dist/guest/databases/names.js +8 -0
  309. package/dist/guest/databases/postgres.d.ts +9 -0
  310. package/dist/guest/databases/postgres.js +85 -0
  311. package/dist/guest/databases/redis.d.ts +7 -0
  312. package/dist/guest/databases/redis.js +25 -0
  313. package/dist/guest/databases/registry.d.ts +5 -0
  314. package/dist/guest/databases/registry.js +51 -0
  315. package/dist/guest/databases/sbx-db.d.ts +1 -0
  316. package/dist/guest/{db.js → databases/sbx-db.js} +13 -13
  317. package/dist/guest/{toolchains/databases → databases}/server.d.ts +5 -5
  318. package/dist/guest/{toolchains/databases → databases}/server.js +18 -13
  319. package/dist/guest/entries/daemon.js +16 -0
  320. package/dist/guest/entries/db.js +10 -0
  321. package/dist/guest/entries/gitguard.js +20 -0
  322. package/dist/guest/entries/main.d.ts +1 -0
  323. package/dist/guest/entries/main.js +24 -0
  324. package/dist/guest/entries/netproxy.d.ts +1 -0
  325. package/dist/guest/entries/netproxy.js +7 -0
  326. package/dist/guest/entries/view.d.ts +1 -0
  327. package/dist/guest/entries/view.js +11 -0
  328. package/dist/guest/{gitguard.js → git/decision.js} +49 -26
  329. package/dist/guest/network/addresses.d.ts +2 -0
  330. package/dist/guest/network/addresses.js +6 -0
  331. package/dist/guest/{setup/network.d.ts → network/allow-only.d.ts} +0 -10
  332. package/dist/guest/network/allow-only.js +84 -0
  333. package/dist/guest/network/firewall.d.ts +9 -0
  334. package/dist/guest/{setup/network.js → network/firewall.js} +58 -63
  335. package/dist/guest/network/proxy-server.d.ts +2 -0
  336. package/dist/guest/{netproxy.js → network/proxy-server.js} +37 -18
  337. package/dist/guest/{helpers.d.ts → runtime/csc.d.ts} +1 -1
  338. package/dist/guest/{helpers.js → runtime/csc.js} +7 -2
  339. package/dist/guest/runtime/fs.d.ts +2 -0
  340. package/dist/guest/runtime/fs.js +6 -0
  341. package/dist/guest/runtime/log.d.ts +3 -0
  342. package/dist/guest/runtime/log.js +22 -0
  343. package/dist/guest/runtime/paths.d.ts +13 -0
  344. package/dist/guest/runtime/paths.js +14 -0
  345. package/dist/guest/{ports.js → runtime/ports.js} +8 -2
  346. package/dist/guest/runtime/process.d.ts +15 -0
  347. package/dist/guest/runtime/process.js +59 -0
  348. package/dist/guest/{project-context.js → runtime/project-context.js} +1 -1
  349. package/dist/guest/runtime/session.d.ts +5 -0
  350. package/dist/guest/runtime/session.js +10 -0
  351. package/dist/guest/runtime/status.d.ts +7 -0
  352. package/dist/guest/runtime/status.js +57 -0
  353. package/dist/guest/{cmdline.js → sessions/cmdline.js} +10 -4
  354. package/dist/guest/{ptyhost.js → sessions/pty-host.js} +12 -5
  355. package/dist/guest/{view.js → sessions/viewer.js} +8 -11
  356. package/dist/guest/setup/claude-mem.d.ts +10 -0
  357. package/dist/guest/setup/{claude.js → claude-mem.js} +18 -78
  358. package/dist/guest/setup/{claude.d.ts → claude-profile.d.ts} +0 -10
  359. package/dist/guest/setup/claude-profile.js +89 -0
  360. package/dist/guest/setup/desktop.d.ts +2 -0
  361. package/dist/guest/setup/desktop.js +32 -0
  362. package/dist/guest/setup/environment.js +28 -5
  363. package/dist/guest/setup/{user.d.ts → git-identity.d.ts} +0 -2
  364. package/dist/guest/setup/git-identity.js +34 -0
  365. package/dist/guest/{gitrules.d.ts → setup/git-rules.d.ts} +1 -1
  366. package/dist/guest/setup/git-rules.js +50 -0
  367. package/dist/guest/setup/hooks.js +22 -5
  368. package/dist/guest/setup/{policy.js → managed-policy.js} +2 -2
  369. package/dist/guest/toolchains/catalogue.d.ts +4 -4
  370. package/dist/guest/toolchains/catalogue.js +30 -7
  371. package/dist/guest/toolchains/detect.d.ts +12 -0
  372. package/dist/guest/toolchains/detect.js +54 -0
  373. package/dist/guest/toolchains/index.d.ts +3 -17
  374. package/dist/guest/toolchains/index.js +1 -80
  375. package/dist/guest/toolchains/install.d.ts +20 -0
  376. package/dist/guest/toolchains/install.js +29 -0
  377. package/dist/guest/toolchains/languages/go.d.ts +3 -0
  378. package/dist/guest/toolchains/{go.js → languages/go.js} +27 -9
  379. package/dist/guest/toolchains/languages/java.d.ts +8 -0
  380. package/dist/guest/toolchains/{java.js → languages/java.js} +57 -18
  381. package/dist/guest/toolchains/languages/node.d.ts +3 -0
  382. package/dist/guest/toolchains/{node.js → languages/node.js} +51 -18
  383. package/dist/guest/toolchains/languages/php.d.ts +3 -0
  384. package/dist/guest/toolchains/{scripting → languages}/php.js +36 -11
  385. package/dist/guest/toolchains/languages/python-tools.d.ts +3 -0
  386. package/dist/guest/toolchains/languages/python-tools.js +12 -0
  387. package/dist/guest/toolchains/languages/python.d.ts +3 -0
  388. package/dist/guest/toolchains/{python.js → languages/python.js} +29 -16
  389. package/dist/guest/toolchains/languages/ruby.d.ts +3 -0
  390. package/dist/guest/toolchains/{scripting → languages}/ruby.js +28 -10
  391. package/dist/guest/toolchains/leftovers.d.ts +1 -1
  392. package/dist/guest/toolchains/leftovers.js +13 -11
  393. package/dist/guest/toolchains/managers.d.ts +6 -6
  394. package/dist/guest/toolchains/managers.js +38 -17
  395. package/dist/guest/toolchains/native/binstall.d.ts +3 -2
  396. package/dist/guest/toolchains/native/binstall.js +20 -8
  397. package/dist/guest/toolchains/native/cpp.d.ts +2 -2
  398. package/dist/guest/toolchains/native/cpp.js +23 -8
  399. package/dist/guest/toolchains/native/dotnet.d.ts +5 -3
  400. package/dist/guest/toolchains/native/dotnet.js +72 -24
  401. package/dist/guest/toolchains/native/mesa.d.ts +2 -2
  402. package/dist/guest/toolchains/native/mesa.js +27 -10
  403. package/dist/guest/toolchains/native/msvc/environment.d.ts +4 -4
  404. package/dist/guest/toolchains/native/msvc/environment.js +30 -16
  405. package/dist/guest/toolchains/native/msvc/index.d.ts +3 -3
  406. package/dist/guest/toolchains/native/msvc/index.js +10 -8
  407. package/dist/guest/toolchains/native/msvc/packages.d.ts +1 -1
  408. package/dist/guest/toolchains/native/msvc/packages.js +69 -23
  409. package/dist/guest/toolchains/native/msvc/tree.d.ts +6 -6
  410. package/dist/guest/toolchains/native/msvc/tree.js +15 -9
  411. package/dist/guest/toolchains/native/rust-extras.d.ts +23 -0
  412. package/dist/guest/toolchains/native/rust-extras.js +100 -0
  413. package/dist/guest/toolchains/native/rust.d.ts +2 -2
  414. package/dist/guest/toolchains/native/rust.js +41 -10
  415. package/dist/guest/toolchains/{scripting → native}/vcruntime.d.ts +2 -2
  416. package/dist/guest/toolchains/{scripting → native}/vcruntime.js +17 -7
  417. package/dist/guest/toolchains/package-ledger.d.ts +17 -0
  418. package/dist/guest/toolchains/package-ledger.js +54 -0
  419. package/dist/guest/toolchains/plan.d.ts +3 -24
  420. package/dist/guest/toolchains/plan.js +99 -111
  421. package/dist/guest/toolchains/runtimes.d.ts +6 -6
  422. package/dist/guest/toolchains/runtimes.js +31 -13
  423. package/dist/guest/toolchains/scheduler.d.ts +22 -0
  424. package/dist/guest/toolchains/scheduler.js +123 -0
  425. package/dist/guest/toolchains/setup.d.ts +10 -0
  426. package/dist/guest/toolchains/setup.js +22 -0
  427. package/dist/guest/toolchains/state-file.d.ts +3 -0
  428. package/dist/guest/toolchains/state-file.js +10 -0
  429. package/dist/guest/toolchains/step.d.ts +24 -0
  430. package/dist/guest/toolchains/step.js +1 -0
  431. package/dist/guest/toolchains/tool-env.d.ts +12 -0
  432. package/dist/guest/toolchains/tool-env.js +16 -0
  433. package/dist/guest/toolchains/tools/cli.d.ts +10 -0
  434. package/dist/guest/toolchains/{cli.js → tools/cli.js} +35 -15
  435. package/dist/guest/toolchains/tools/git.d.ts +3 -0
  436. package/dist/guest/toolchains/{git.js → tools/git.js} +38 -15
  437. package/dist/guest/toolchains/tools/pwsh.d.ts +4 -0
  438. package/dist/guest/toolchains/{pwsh.js → tools/pwsh.js} +14 -7
  439. package/dist/guest/toolchains/{vscode-profile.d.ts → tools/vscode-profile.d.ts} +6 -6
  440. package/dist/guest/toolchains/{vscode-profile.js → tools/vscode-profile.js} +28 -12
  441. package/dist/guest/toolchains/{vscode.d.ts → tools/vscode.d.ts} +6 -6
  442. package/dist/guest/toolchains/{vscode.js → tools/vscode.js} +67 -21
  443. package/dist/guest/toolchains/version-cache.d.ts +16 -0
  444. package/dist/guest/toolchains/version-cache.js +67 -0
  445. package/dist/host/agent-commands/commands.d.ts +13 -0
  446. package/dist/host/agent-commands/commands.js +33 -0
  447. package/dist/host/agent-commands/forwarders.d.ts +7 -0
  448. package/dist/host/agent-commands/forwarders.js +31 -0
  449. package/dist/host/agent-commands/index.d.ts +4 -0
  450. package/dist/host/agent-commands/index.js +4 -0
  451. package/dist/host/agent-commands/reconcile.d.ts +12 -0
  452. package/dist/host/agent-commands/reconcile.js +69 -0
  453. package/dist/host/agent-commands/user-path.d.ts +2 -0
  454. package/dist/host/agent-commands/user-path.js +33 -0
  455. package/dist/host/audit/collect.d.ts +2 -2
  456. package/dist/host/audit/collect.js +59 -22
  457. package/dist/host/audit/log.d.ts +2 -2
  458. package/dist/host/audit/log.js +24 -8
  459. package/dist/host/{attach.d.ts → channel/attach.d.ts} +2 -2
  460. package/dist/host/{attach.js → channel/attach.js} +33 -15
  461. package/dist/host/channel/channel.d.ts +51 -0
  462. package/dist/host/channel/channel.js +196 -0
  463. package/dist/host/channel/index.d.ts +2 -0
  464. package/dist/host/channel/index.js +2 -0
  465. package/dist/host/guard/agent-files.d.ts +7 -0
  466. package/dist/host/guard/agent-files.js +103 -0
  467. package/dist/host/guard/commands.d.ts +10 -0
  468. package/dist/host/guard/commands.js +123 -0
  469. package/dist/host/guard/file-hash.d.ts +4 -0
  470. package/dist/host/guard/file-hash.js +37 -0
  471. package/dist/host/guard/git-config.d.ts +5 -0
  472. package/dist/host/guard/git-config.js +62 -0
  473. package/dist/host/guard/git-dirs.d.ts +12 -0
  474. package/dist/host/guard/git-dirs.js +53 -0
  475. package/dist/host/guard/index.d.ts +5 -0
  476. package/dist/host/guard/index.js +4 -0
  477. package/dist/host/guard/mark-of-the-web.d.ts +8 -0
  478. package/dist/host/guard/mark-of-the-web.js +74 -0
  479. package/dist/host/guard/nested-repos.d.ts +14 -0
  480. package/dist/host/guard/nested-repos.js +88 -0
  481. package/dist/host/guard/quarantine.d.ts +3 -0
  482. package/dist/host/guard/quarantine.js +24 -0
  483. package/dist/host/guard/repo-guard.d.ts +10 -0
  484. package/dist/host/guard/repo-guard.js +36 -0
  485. package/dist/host/guard/store.d.ts +40 -0
  486. package/dist/host/guard/store.js +145 -0
  487. package/dist/host/guard/types.d.ts +27 -0
  488. package/dist/host/guard/types.js +3 -0
  489. package/dist/host/guard/watch-state.d.ts +9 -0
  490. package/dist/host/guard/watch-state.js +26 -0
  491. package/dist/host/launch/boot-projects.d.ts +17 -0
  492. package/dist/host/launch/{projects.js → boot-projects.js} +27 -12
  493. package/dist/host/{database-plan.d.ts → launch/database-plan.d.ts} +5 -5
  494. package/dist/host/{database-plan.js → launch/database-plan.js} +24 -13
  495. package/dist/host/launch/generate.d.ts +4 -0
  496. package/dist/host/launch/generate.js +77 -0
  497. package/dist/host/launch/index.d.ts +10 -0
  498. package/dist/host/launch/index.js +10 -0
  499. package/dist/host/launch/mappings.d.ts +7 -2
  500. package/dist/host/launch/mappings.js +83 -24
  501. package/dist/host/launch/pc-scan.d.ts +5 -0
  502. package/dist/host/{pc-scan.js → launch/pc-scan.js} +20 -13
  503. package/dist/host/launch/project-scan.d.ts +7 -0
  504. package/dist/host/{project-scan.js → launch/project-scan.js} +29 -21
  505. package/dist/host/launch/session-file.d.ts +23 -0
  506. package/dist/host/launch/session-file.js +73 -0
  507. package/dist/host/launch/stage.d.ts +5 -5
  508. package/dist/host/launch/stage.js +14 -13
  509. package/dist/host/launch/toolchains.d.ts +4 -0
  510. package/dist/host/launch/toolchains.js +11 -0
  511. package/dist/host/launch/{wsb.d.ts → wsb-file.d.ts} +4 -2
  512. package/dist/host/launch/wsb-file.js +56 -0
  513. package/dist/host/life/crash-report.d.ts +8 -0
  514. package/dist/host/life/crash-report.js +87 -0
  515. package/dist/host/life/index.d.ts +6 -0
  516. package/dist/host/life/index.js +6 -0
  517. package/dist/host/life/keep-awake.d.ts +10 -0
  518. package/dist/host/life/keep-awake.js +29 -0
  519. package/dist/host/life/life-record.d.ts +48 -0
  520. package/dist/host/life/life-record.js +76 -0
  521. package/dist/host/life/stop-events.d.ts +27 -0
  522. package/dist/host/life/stop-events.js +96 -0
  523. package/dist/host/life/stop-warning.d.ts +4 -0
  524. package/dist/host/life/stop-warning.js +25 -0
  525. package/dist/host/life/windows-update.d.ts +3 -0
  526. package/dist/host/life/windows-update.js +11 -0
  527. package/dist/host/native.d.ts +4 -0
  528. package/dist/host/native.js +11 -0
  529. package/dist/host/network/index.d.ts +1 -0
  530. package/dist/host/network/index.js +1 -0
  531. package/dist/host/{port-forward.d.ts → network/port-forward.d.ts} +1 -1
  532. package/dist/host/{port-forward.js → network/port-forward.js} +16 -10
  533. package/dist/host/profile/accounts.d.ts +37 -0
  534. package/dist/host/profile/accounts.js +146 -0
  535. package/dist/host/profile/claude-login.d.ts +22 -0
  536. package/dist/host/profile/claude-login.js +57 -0
  537. package/dist/host/{claude-profile.d.ts → profile/claude-profile.d.ts} +9 -9
  538. package/dist/host/{claude-profile.js → profile/claude-profile.js} +32 -22
  539. package/dist/host/profile/index.d.ts +7 -0
  540. package/dist/host/profile/index.js +7 -0
  541. package/dist/host/profile/personalize.d.ts +2 -0
  542. package/dist/host/profile/personalize.js +127 -0
  543. package/dist/host/profile/reg-file.d.ts +8 -0
  544. package/dist/host/profile/reg-file.js +45 -0
  545. package/dist/host/profile/secret-files.d.ts +2 -0
  546. package/dist/host/profile/secret-files.js +25 -0
  547. package/dist/host/profile/secret-patterns.d.ts +6 -0
  548. package/dist/host/profile/secret-patterns.js +128 -0
  549. package/dist/host/profile/secrets.d.ts +12 -0
  550. package/dist/host/profile/secrets.js +100 -0
  551. package/dist/host/projects/index.d.ts +4 -0
  552. package/dist/host/projects/index.js +4 -0
  553. package/dist/host/projects/join.d.ts +38 -0
  554. package/dist/host/projects/join.js +119 -0
  555. package/dist/host/projects/known.d.ts +28 -0
  556. package/dist/host/projects/known.js +55 -0
  557. package/dist/host/projects/mapper.d.ts +29 -0
  558. package/dist/host/projects/mapper.js +88 -0
  559. package/dist/host/projects/registry.d.ts +83 -0
  560. package/dist/host/projects/registry.js +136 -0
  561. package/dist/host/sandbox/doctor.d.ts +2 -0
  562. package/dist/host/sandbox/doctor.js +42 -0
  563. package/dist/host/sandbox/host-claude.d.ts +1 -0
  564. package/dist/host/sandbox/host-claude.js +26 -0
  565. package/dist/host/sandbox/index.d.ts +6 -0
  566. package/dist/host/sandbox/index.js +6 -0
  567. package/dist/host/{platform.d.ts → sandbox/platform.d.ts} +0 -5
  568. package/dist/host/sandbox/platform.js +60 -0
  569. package/dist/host/sandbox/probe.d.ts +3 -0
  570. package/dist/host/sandbox/probe.js +47 -0
  571. package/dist/host/{window.js → sandbox/window.js} +7 -5
  572. package/dist/host/{wsb.js → sandbox/wsb-cli.js} +31 -8
  573. package/dist/host/{cleanup.js → storage/cleanup.js} +27 -12
  574. package/dist/host/storage/index.d.ts +2 -0
  575. package/dist/host/storage/index.js +2 -0
  576. package/dist/host/storage/state-files.d.ts +4 -0
  577. package/dist/host/storage/state-files.js +10 -0
  578. package/dist/host/test-guard.js +1 -1
  579. package/dist/host/tools/conpty.d.ts +8 -0
  580. package/dist/host/tools/conpty.js +58 -0
  581. package/dist/host/tools/index.d.ts +2 -0
  582. package/dist/host/tools/index.js +2 -0
  583. package/dist/host/{terminal.d.ts → tools/windows-terminal.d.ts} +2 -10
  584. package/dist/host/{terminal.js → tools/windows-terminal.js} +33 -57
  585. package/dist/host/workspace-view/active-views.d.ts +3 -0
  586. package/dist/host/workspace-view/active-views.js +22 -0
  587. package/dist/host/workspace-view/index.d.ts +2 -18
  588. package/dist/host/workspace-view/index.js +2 -49
  589. package/dist/host/workspace-view/plan.d.ts +16 -0
  590. package/dist/host/workspace-view/plan.js +50 -0
  591. package/dist/host/workspace-view/rules.js +10 -3
  592. package/dist/host/workspace-view/view-state.d.ts +10 -0
  593. package/dist/host/workspace-view/view-state.js +31 -0
  594. package/dist/host/workspace-view/view.d.ts +1 -0
  595. package/dist/host/workspace-view/view.js +51 -55
  596. package/dist/runtime/daemon.js +4232 -1918
  597. package/dist/runtime/db.js +2145 -830
  598. package/dist/runtime/gitguard.js +29 -11
  599. package/dist/runtime/main.js +4760 -2155
  600. package/dist/runtime/netproxy.js +1654 -418
  601. package/dist/runtime/view.js +1515 -453
  602. package/dist/selftest/accounts.test.d.ts +1 -1
  603. package/dist/selftest/accounts.test.js +20 -17
  604. package/dist/selftest/agent-commands.test.d.ts +1 -1
  605. package/dist/selftest/agent-commands.test.js +9 -5
  606. package/dist/selftest/audit.test.d.ts +1 -1
  607. package/dist/selftest/audit.test.js +46 -13
  608. package/dist/selftest/channel.test.d.ts +1 -1
  609. package/dist/selftest/channel.test.js +91 -8
  610. package/dist/selftest/cli.test.d.ts +1 -1
  611. package/dist/selftest/cli.test.js +68 -16
  612. package/dist/selftest/cmdline.test.d.ts +1 -1
  613. package/dist/selftest/cmdline.test.js +36 -7
  614. package/dist/selftest/config.test.d.ts +1 -1
  615. package/dist/selftest/config.test.js +12 -5
  616. package/dist/selftest/data.test.d.ts +1 -1
  617. package/dist/selftest/data.test.js +35 -6
  618. package/dist/selftest/detect.test.d.ts +1 -1
  619. package/dist/selftest/detect.test.js +22 -9
  620. package/dist/selftest/generate.test.d.ts +1 -1
  621. package/dist/selftest/generate.test.js +33 -9
  622. package/dist/selftest/git-access.test.d.ts +1 -1
  623. package/dist/selftest/git-access.test.js +42 -4
  624. package/dist/selftest/guest-boot.test.d.ts +1 -1
  625. package/dist/selftest/guest-boot.test.js +25 -7
  626. package/dist/selftest/host-sim.test.d.ts +1 -1
  627. package/dist/selftest/host-sim.test.js +27 -3
  628. package/dist/selftest/hostile-input.test.d.ts +1 -1
  629. package/dist/selftest/hostile-input.test.js +5 -5
  630. package/dist/selftest/index.d.ts +1 -1
  631. package/dist/selftest/index.js +73 -16
  632. package/dist/selftest/layout.test.d.ts +2 -0
  633. package/dist/selftest/layout.test.js +131 -0
  634. package/dist/selftest/links.test.d.ts +1 -1
  635. package/dist/selftest/links.test.js +16 -11
  636. package/dist/selftest/live-daemon.test.d.ts +1 -1
  637. package/dist/selftest/live-daemon.test.js +20 -8
  638. package/dist/selftest/live-git.test.d.ts +1 -1
  639. package/dist/selftest/live-git.test.js +13 -4
  640. package/dist/selftest/live-network.test.d.ts +1 -1
  641. package/dist/selftest/live-network.test.js +24 -9
  642. package/dist/selftest/live-projects.test.d.ts +1 -1
  643. package/dist/selftest/live-projects.test.js +47 -20
  644. package/dist/selftest/live-terminal.test.d.ts +2 -0
  645. package/dist/selftest/live-terminal.test.js +195 -0
  646. package/dist/selftest/local-config.test.d.ts +1 -1
  647. package/dist/selftest/local-config.test.js +88 -15
  648. package/dist/selftest/mirror.test.d.ts +1 -1
  649. package/dist/selftest/mirror.test.js +118 -19
  650. package/dist/selftest/network.test.d.ts +1 -1
  651. package/dist/selftest/network.test.js +17 -8
  652. package/dist/selftest/personalization.test.d.ts +1 -1
  653. package/dist/selftest/personalization.test.js +12 -5
  654. package/dist/selftest/projects.test.d.ts +1 -1
  655. package/dist/selftest/projects.test.js +336 -72
  656. package/dist/selftest/repair.test.d.ts +1 -1
  657. package/dist/selftest/repair.test.js +17 -5
  658. package/dist/selftest/repo-guard.test.d.ts +1 -1
  659. package/dist/selftest/repo-guard.test.js +21 -20
  660. package/dist/selftest/secrets.test.d.ts +1 -1
  661. package/dist/selftest/secrets.test.js +57 -13
  662. package/dist/selftest/setup.test.d.ts +1 -1
  663. package/dist/selftest/setup.test.js +25 -5
  664. package/dist/selftest/{fixtures.d.ts → support/fixtures.d.ts} +7 -4
  665. package/dist/selftest/{fixtures.js → support/fixtures.js} +95 -17
  666. package/dist/selftest/{harness.js → support/harness.js} +24 -7
  667. package/dist/selftest/{live.d.ts → support/live.d.ts} +2 -2
  668. package/dist/selftest/{live.js → support/live.js} +34 -10
  669. package/dist/selftest/support/suite.js +1 -0
  670. package/dist/selftest/sync.test.d.ts +1 -1
  671. package/dist/selftest/sync.test.js +64 -26
  672. package/dist/selftest/test-guard.test.d.ts +1 -1
  673. package/dist/selftest/test-guard.test.js +43 -15
  674. package/dist/selftest/toolchains.test.d.ts +1 -1
  675. package/dist/selftest/toolchains.test.js +135 -36
  676. package/dist/selftest/workspace-view.test.d.ts +1 -1
  677. package/dist/selftest/workspace-view.test.js +48 -11
  678. package/dist/selftest/workspace.test.d.ts +1 -1
  679. package/dist/selftest/workspace.test.js +13 -4
  680. package/dist/shared/{apps.d.ts → apps/catalogue.d.ts} +1 -11
  681. package/dist/shared/apps/catalogue.js +768 -0
  682. package/dist/shared/apps/index.d.ts +2 -0
  683. package/dist/shared/apps/index.js +2 -0
  684. package/dist/shared/apps/selection.d.ts +11 -0
  685. package/dist/shared/apps/selection.js +40 -0
  686. package/dist/shared/channel/index.d.ts +2 -0
  687. package/dist/shared/channel/index.js +2 -0
  688. package/dist/shared/channel/run-dir.d.ts +30 -0
  689. package/dist/shared/channel/run-dir.js +84 -0
  690. package/dist/shared/{schema.d.ts → channel/schema.d.ts} +60 -19
  691. package/dist/shared/channel/schema.js +131 -0
  692. package/dist/shared/download/archive.d.ts +13 -0
  693. package/dist/shared/download/archive.js +57 -0
  694. package/dist/shared/download/downloader.d.ts +35 -0
  695. package/dist/shared/download/downloader.js +110 -0
  696. package/dist/shared/download/github.d.ts +16 -0
  697. package/dist/shared/download/github.js +74 -0
  698. package/dist/shared/download/http.d.ts +5 -0
  699. package/dist/shared/download/http.js +30 -0
  700. package/dist/shared/download/index.d.ts +5 -0
  701. package/dist/shared/download/index.js +5 -0
  702. package/dist/shared/download/spawn.d.ts +2 -0
  703. package/dist/shared/download/spawn.js +7 -0
  704. package/dist/shared/io/index.d.ts +3 -0
  705. package/dist/shared/io/index.js +3 -0
  706. package/dist/shared/io/json-file.d.ts +10 -0
  707. package/dist/shared/io/json-file.js +21 -0
  708. package/dist/shared/io/json.d.ts +13 -0
  709. package/dist/shared/io/json.js +49 -0
  710. package/dist/shared/{safe-remove.js → io/safe-remove.js} +32 -7
  711. package/dist/shared/{netrules.js → network/firewall-rules.js} +36 -5
  712. package/dist/shared/network/index.d.ts +2 -0
  713. package/dist/shared/network/index.js +2 -0
  714. package/dist/shared/{netpolicy.js → network/policy.js} +66 -11
  715. package/dist/shared/{paths.js → paths/claude-paths.js} +12 -2
  716. package/dist/shared/{guest-paths.d.ts → paths/guest-paths.d.ts} +21 -0
  717. package/dist/shared/paths/guest-paths.js +146 -0
  718. package/dist/shared/paths/index.d.ts +3 -0
  719. package/dist/shared/paths/index.js +3 -0
  720. package/dist/shared/{projects.d.ts → paths/projects.d.ts} +27 -4
  721. package/dist/shared/paths/projects.js +136 -0
  722. package/dist/shared/pty/client.d.ts +21 -0
  723. package/dist/shared/pty/client.js +79 -0
  724. package/dist/shared/pty/console-input.d.ts +11 -0
  725. package/dist/shared/pty/console-input.js +81 -0
  726. package/dist/shared/pty/index.d.ts +6 -0
  727. package/dist/shared/pty/index.js +6 -0
  728. package/dist/shared/pty/input-joiner.d.ts +15 -0
  729. package/dist/shared/pty/input-joiner.js +44 -0
  730. package/dist/shared/pty/output-filter.d.ts +13 -0
  731. package/dist/shared/pty/output-filter.js +140 -0
  732. package/dist/shared/pty/protocol.d.ts +36 -0
  733. package/dist/shared/pty/protocol.js +60 -0
  734. package/dist/shared/pty/terminal.d.ts +24 -0
  735. package/dist/shared/pty/terminal.js +147 -0
  736. package/dist/shared/test-guard.js +3 -1
  737. package/dist/sync/claude-mem.d.ts +1 -1
  738. package/dist/sync/claude-mem.js +9 -4
  739. package/dist/sync/history.d.ts +1 -29
  740. package/dist/sync/history.js +57 -45
  741. package/dist/sync/index.d.ts +5 -0
  742. package/dist/sync/index.js +5 -0
  743. package/dist/sync/sync-cycle.d.ts +18 -0
  744. package/dist/sync/sync-cycle.js +85 -0
  745. package/dist/sync/sync-state.d.ts +32 -0
  746. package/dist/sync/sync-state.js +37 -0
  747. package/dist/sync/watcher.d.ts +0 -18
  748. package/dist/sync/watcher.js +66 -100
  749. package/native/keep-awake.ps1 +8 -0
  750. package/native/power.cs +23 -0
  751. package/native/stop-events.ps1 +38 -0
  752. package/package.json +11 -3
  753. package/sandbox/linkgate.cs +98 -0
  754. package/sandbox/memlog.ps1 +15 -6
  755. package/sandbox/ptyhost.cs +60 -3
  756. package/schemas/config.schema.json +48 -1
  757. package/schemas/sandbox-config.schema.json +37 -3
  758. package/dist/cli/commands/launch.d.ts +0 -29
  759. package/dist/cli/commands/launch.js +0 -366
  760. package/dist/cli/commands/maintenance.d.ts +0 -10
  761. package/dist/cli/commands/maintenance.js +0 -187
  762. package/dist/cli/commands/project.d.ts +0 -29
  763. package/dist/cli/commands/project.js +0 -63
  764. package/dist/cli/commands/projects.d.ts +0 -14
  765. package/dist/cli/commands/projects.js +0 -146
  766. package/dist/cli/commands/restart.d.ts +0 -6
  767. package/dist/cli/commands/restart.js +0 -85
  768. package/dist/cli/commands/sessions.d.ts +0 -12
  769. package/dist/cli/commands/sessions.js +0 -257
  770. package/dist/cli/menu/settings/editors.js +0 -305
  771. package/dist/cli/progress.d.ts +0 -9
  772. package/dist/cli/progress.js +0 -49
  773. package/dist/cli/tui/dialogs.d.ts +0 -57
  774. package/dist/cli/tui/dialogs.js +0 -162
  775. package/dist/core/config.js +0 -109
  776. package/dist/core/schema.d.ts +0 -6
  777. package/dist/core/schema.js +0 -8
  778. package/dist/core/util.d.ts +0 -62
  779. package/dist/core/util.js +0 -156
  780. package/dist/core/workspace.d.ts +0 -18
  781. package/dist/core/workspace.js +0 -145
  782. package/dist/guest/boot-env.d.ts +0 -4
  783. package/dist/guest/daemon.js +0 -57
  784. package/dist/guest/env.d.ts +0 -52
  785. package/dist/guest/env.js +0 -103
  786. package/dist/guest/gitrules.js +0 -11
  787. package/dist/guest/project-status.d.ts +0 -5
  788. package/dist/guest/project-status.js +0 -17
  789. package/dist/guest/setup/user.js +0 -51
  790. package/dist/guest/toolchains/cli.d.ts +0 -10
  791. package/dist/guest/toolchains/common.d.ts +0 -54
  792. package/dist/guest/toolchains/common.js +0 -147
  793. package/dist/guest/toolchains/databases/dynamodb.d.ts +0 -8
  794. package/dist/guest/toolchains/databases/dynamodb.js +0 -52
  795. package/dist/guest/toolchains/databases/index.d.ts +0 -6
  796. package/dist/guest/toolchains/databases/index.js +0 -62
  797. package/dist/guest/toolchains/databases/mongodb.d.ts +0 -3
  798. package/dist/guest/toolchains/databases/mongodb.js +0 -31
  799. package/dist/guest/toolchains/databases/mysql.d.ts +0 -3
  800. package/dist/guest/toolchains/databases/mysql.js +0 -38
  801. package/dist/guest/toolchains/databases/postgres.d.ts +0 -5
  802. package/dist/guest/toolchains/databases/postgres.js +0 -38
  803. package/dist/guest/toolchains/databases/redis.d.ts +0 -3
  804. package/dist/guest/toolchains/databases/redis.js +0 -16
  805. package/dist/guest/toolchains/git.d.ts +0 -3
  806. package/dist/guest/toolchains/go.d.ts +0 -3
  807. package/dist/guest/toolchains/java.d.ts +0 -8
  808. package/dist/guest/toolchains/node.d.ts +0 -3
  809. package/dist/guest/toolchains/pwsh.d.ts +0 -4
  810. package/dist/guest/toolchains/python.d.ts +0 -3
  811. package/dist/guest/toolchains/scripting/php.d.ts +0 -3
  812. package/dist/guest/toolchains/scripting/ruby.d.ts +0 -3
  813. package/dist/host/accounts.d.ts +0 -32
  814. package/dist/host/accounts.js +0 -128
  815. package/dist/host/agent-commands.d.ts +0 -25
  816. package/dist/host/agent-commands.js +0 -145
  817. package/dist/host/channel.d.ts +0 -38
  818. package/dist/host/channel.js +0 -162
  819. package/dist/host/generate.d.ts +0 -13
  820. package/dist/host/generate.js +0 -108
  821. package/dist/host/join.d.ts +0 -28
  822. package/dist/host/join.js +0 -76
  823. package/dist/host/launch/projects.d.ts +0 -15
  824. package/dist/host/launch/wsb.js +0 -34
  825. package/dist/host/motw.d.ts +0 -17
  826. package/dist/host/motw.js +0 -74
  827. package/dist/host/pc-scan.d.ts +0 -6
  828. package/dist/host/personalize.d.ts +0 -10
  829. package/dist/host/personalize.js +0 -97
  830. package/dist/host/platform.js +0 -129
  831. package/dist/host/project-scan.d.ts +0 -7
  832. package/dist/host/projects.d.ts +0 -100
  833. package/dist/host/projects.js +0 -147
  834. package/dist/host/repo-guard.d.ts +0 -43
  835. package/dist/host/repo-guard.js +0 -347
  836. package/dist/host/secrets.d.ts +0 -14
  837. package/dist/host/secrets.js +0 -133
  838. package/dist/host/stops.d.ts +0 -67
  839. package/dist/host/stops.js +0 -126
  840. package/dist/shared/apps.js +0 -114
  841. package/dist/shared/download.d.ts +0 -60
  842. package/dist/shared/download.js +0 -215
  843. package/dist/shared/guest-paths.js +0 -61
  844. package/dist/shared/projects.js +0 -67
  845. package/dist/shared/pty-client.d.ts +0 -91
  846. package/dist/shared/pty-client.js +0 -349
  847. package/dist/shared/rundir.d.ts +0 -41
  848. package/dist/shared/rundir.js +0 -96
  849. package/dist/shared/schema.js +0 -92
  850. /package/dist/{guest/daemon.d.ts → cli/tui/list/list-types.js} +0 -0
  851. /package/dist/{guest/db.d.ts → cli/tui/screen.js} +0 -0
  852. /package/dist/core/{detect-databases.d.ts → detect/databases.d.ts} +0 -0
  853. /package/dist/{guest/toolchains → core/detect}/versions.d.ts +0 -0
  854. /package/dist/guest/{setup/agents.d.ts → agents/agent-installer.d.ts} +0 -0
  855. /package/dist/guest/{audit-parse.d.ts → audit/parse.d.ts} +0 -0
  856. /package/dist/guest/{guide.d.ts → boot/guide.d.ts} +0 -0
  857. /package/dist/guest/daemon/{shutdown.d.ts → idle-shutdown.d.ts} +0 -0
  858. /package/dist/guest/daemon/{session.d.ts → sessions.d.ts} +0 -0
  859. /package/dist/guest/{main.d.ts → entries/daemon.d.ts} +0 -0
  860. /package/dist/guest/{netproxy.d.ts → entries/db.d.ts} +0 -0
  861. /package/dist/{selftest/suite.js → guest/entries/gitguard.d.ts} +0 -0
  862. /package/dist/guest/{gitguard.d.ts → git/decision.d.ts} +0 -0
  863. /package/dist/guest/{ports.d.ts → runtime/ports.d.ts} +0 -0
  864. /package/dist/guest/{project-context.d.ts → runtime/project-context.d.ts} +0 -0
  865. /package/dist/guest/{cmdline.d.ts → sessions/cmdline.d.ts} +0 -0
  866. /package/dist/guest/{ptyhost.d.ts → sessions/pty-host.d.ts} +0 -0
  867. /package/dist/guest/{view.d.ts → sessions/viewer.d.ts} +0 -0
  868. /package/dist/guest/setup/{policy.d.ts → managed-policy.d.ts} +0 -0
  869. /package/dist/host/{window.d.ts → sandbox/window.d.ts} +0 -0
  870. /package/dist/host/{wsb.d.ts → sandbox/wsb-cli.d.ts} +0 -0
  871. /package/dist/host/{cleanup.d.ts → storage/cleanup.d.ts} +0 -0
  872. /package/dist/selftest/{harness.d.ts → support/harness.d.ts} +0 -0
  873. /package/dist/selftest/{suite.d.ts → support/suite.d.ts} +0 -0
  874. /package/dist/shared/{safe-remove.d.ts → io/safe-remove.d.ts} +0 -0
  875. /package/dist/shared/{netrules.d.ts → network/firewall-rules.d.ts} +0 -0
  876. /package/dist/shared/{netpolicy.d.ts → network/policy.d.ts} +0 -0
  877. /package/dist/shared/{paths.d.ts → paths/claude-paths.d.ts} +0 -0
@@ -0,0 +1,195 @@
1
+ // Live: the terminal path as you use it. An outer ptyhost stands in for Windows Terminal (it hosts the console, like
2
+ // Windows Terminal's own pseudo console) and runs the real viewer/attach client (runTerminalClient), which is attached
3
+ // to an inner ptyhost running a stand-in agent. The agent turns SGR mouse tracking on and echoes every byte it reads.
4
+ // Checks: clicks and the wheel reach the agent, Backspace stays Backspace, a split escape sequence arrives whole,
5
+ // 500 printed lines scroll through as lines (no alternate screen, no scrollback clear), and a viewer that joins after
6
+ // a screen clear still gets mouse tracking.
7
+ import fs from 'node:fs';
8
+ import net from 'node:net';
9
+ import path from 'node:path';
10
+ import { spawn, spawnSync } from 'node:child_process';
11
+ import { pathToFileURL } from 'node:url';
12
+ import { encodeFrame, FrameType } from '../shared/pty/index.js';
13
+ import { CSC, openViewer, tail, WAIT } from './support/live.js';
14
+ /** The stand-in agent: VT input and SGR mouse tracking on, echoes what it reads ("got <1b>[<0;10;5M"). L prints 500 lines, K clears the screen, q quits. */
15
+ const AGENT_CS = String.raw `
16
+ using System;
17
+ using System.Runtime.InteropServices;
18
+ using System.Text;
19
+ static class MouseAgent
20
+ {
21
+ [DllImport("kernel32.dll")] static extern IntPtr GetStdHandle(int n);
22
+ [DllImport("kernel32.dll")] static extern bool GetConsoleMode(IntPtr h, out uint m);
23
+ [DllImport("kernel32.dll")] static extern bool SetConsoleMode(IntPtr h, uint m);
24
+ [DllImport("kernel32.dll")] static extern bool ReadFile(IntPtr h, byte[] b, int n, out int read, IntPtr o);
25
+ static void Say(string s) { Console.Out.Write(s); Console.Out.Flush(); }
26
+ static int Main()
27
+ {
28
+ IntPtr input = GetStdHandle(-10), output = GetStdHandle(-11);
29
+ uint mode;
30
+ GetConsoleMode(output, out mode); SetConsoleMode(output, mode | 4);
31
+ SetConsoleMode(input, 0x200);
32
+ Say("\x1b[?1000h\x1b[?1006hAGENT-READY\r\n");
33
+ var buffer = new byte[512];
34
+ int n;
35
+ while (ReadFile(input, buffer, buffer.Length, out n, IntPtr.Zero) && n > 0)
36
+ {
37
+ var text = new StringBuilder();
38
+ for (int i = 0; i < n; i++) text.Append(buffer[i] < 32 || buffer[i] > 126 ? "<" + buffer[i].ToString("x2") + ">" : ((char)buffer[i]).ToString());
39
+ string got = text.ToString();
40
+ Say("got " + got + "\r\n");
41
+ if (got == "L") { var lines = new StringBuilder(); for (int i = 1; i <= 500; i++) lines.Append("line " + i + "\r\n"); Say(lines.ToString() + "LINES-DONE\r\n"); }
42
+ if (got == "K") Say("\x1b[2J\x1b[HCLEARED\r\n");
43
+ if (got == "q") break;
44
+ }
45
+ // Exits with mouse tracking still on (like a crash): the client must turn it off.
46
+ return 0;
47
+ }
48
+ }
49
+ `;
50
+ const freePort = () => new Promise((resolve, reject) => {
51
+ const server = net.createServer();
52
+ server.on('error', reject);
53
+ server.listen(0, '127.0.0.1', () => {
54
+ const port = server.address().port;
55
+ server.close(() => resolve(port));
56
+ });
57
+ });
58
+ const compile = (source, exe) => {
59
+ const result = spawnSync(CSC, ['/nologo', '/optimize', '/target:exe', '/out:' + exe, source], {
60
+ encoding: 'utf8',
61
+ windowsHide: true,
62
+ });
63
+ return result.status === 0
64
+ ? ''
65
+ : ((result.stdout ?? '') + (result.stderr ?? '')).trim().slice(0, 1500) || 'csc failed';
66
+ };
67
+ /** conpty.dll as a sandbox has it (C:\AgentData\tools\conpty), when this machine has one; else only Windows' own is tested. */
68
+ const conptyDll = () => {
69
+ const dll = path.join(process.env.AGENT_DATA_DIR ?? 'C:\\AgentData', 'tools', 'conpty', 'conpty.dll');
70
+ return fs.existsSync(dll) && fs.existsSync(path.join(path.dirname(dll), 'OpenConsole.exe')) ? dll : null;
71
+ };
72
+ export const liveTerminalSuite = {
73
+ name: 'live-terminal',
74
+ title: 'live: the viewer/attach client in a terminal (mouse clicks and wheel, keys, scrolling lines, late viewers)',
75
+ live: true,
76
+ timeoutMs: 300000,
77
+ run: async (t) => {
78
+ const ptyhost = t.at('ptyhost.exe');
79
+ const agent = t.at('mouse-agent.exe');
80
+ fs.writeFileSync(t.at('mouse-agent.cs'), AGENT_CS);
81
+ const errors = compile(path.join(t.packageRoot, 'sandbox', 'ptyhost.cs'), ptyhost) || compile(t.at('mouse-agent.cs'), agent);
82
+ t.check(!errors, 'ptyhost and the stand-in agent compile', errors);
83
+ if (errors)
84
+ return;
85
+ const client = t.at('client.mjs');
86
+ fs.writeFileSync(client, [
87
+ 'import { connect, runTerminalClient } from ' +
88
+ JSON.stringify(pathToFileURL(path.join(t.packageRoot, 'dist', 'shared', 'pty', 'index.js')).href) +
89
+ ';',
90
+ 'const socket = await connect({ addresses: ["127.0.0.1"], port: Number(process.argv[2]), token: "tok" });',
91
+ 'const result = await runTerminalClient(socket, "tok");',
92
+ 'console.log("CLIENT-DONE " + result.reason);',
93
+ ].join('\n'));
94
+ const dll = conptyDll();
95
+ const kinds = dll ? [dll, null] : [null];
96
+ if (!dll)
97
+ t.skip("conpty.dll not found on this machine: only Windows' own pseudo console is tested");
98
+ for (const kind of kinds) {
99
+ const label = kind ? 'conpty.dll' : "Windows' pseudo console";
100
+ t.section('live terminal (' + label + ')');
101
+ const children = [];
102
+ const viewers = [];
103
+ const start = (port, command, log) => {
104
+ const env = { ...process.env, PTYHOST_BIND: 'loopback' };
105
+ delete env.PTYHOST_CONPTY;
106
+ if (kind)
107
+ env.PTYHOST_CONPTY = kind;
108
+ children.push(spawn(ptyhost, [String(port), 'tok', '100', '30', t.at(log), command], {
109
+ env,
110
+ stdio: 'ignore',
111
+ windowsHide: true,
112
+ }));
113
+ };
114
+ try {
115
+ const innerPort = await freePort();
116
+ start(innerPort, '"' + agent + '"', 'inner-' + kinds.indexOf(kind) + '.log');
117
+ const outerPort = await freePort();
118
+ start(outerPort, '"' + process.execPath + '" "' + client + '" ' + innerPort, 'outer-' + kinds.indexOf(kind) + '.log');
119
+ // The terminal: what it shows is what the client wrote; what it types goes to the client's console.
120
+ const terminal = await openViewer({ addresses: ['127.0.0.1'], port: outerPort, token: 'tok' });
121
+ viewers.push(terminal);
122
+ const screen = () => terminal.output();
123
+ const send = (text) => {
124
+ terminal.socket.write(encodeFrame(FrameType.Input, Buffer.from(text, 'latin1')));
125
+ };
126
+ const ready = await t.waitFor(() => screen().includes('AGENT-READY'), WAIT.screen);
127
+ t.check(Boolean(ready), 'the client shows the agent', 'screen: ' + tail(screen()));
128
+ if (!ready)
129
+ continue;
130
+ // The client switches its console to pass the terminal's input through as it is; until then clicks are lost.
131
+ const click = '\x1b[<0;10;5M\x1b[<0;10;5m';
132
+ const clicked = await t.waitFor(() => {
133
+ if (!screen().includes('got <1b>[<0;10;5M'))
134
+ send(click);
135
+ return screen().includes('got <1b>[<0;10;5M');
136
+ }, WAIT.screen, 1000);
137
+ t.check(Boolean(clicked), 'a mouse click in the terminal reaches the agent (SGR mouse report)', 'screen: ' + tail(screen(), 800));
138
+ const mark = screen().length;
139
+ const after = () => screen().slice(mark);
140
+ send('\x1b[<64;10;5M');
141
+ t.check(Boolean(await t.waitFor(() => after().includes('got <1b>[<64;10;5M'), WAIT.screen)), 'the mouse wheel reaches the agent while it tracks the mouse', 'screen: ' + tail(after(), 800));
142
+ send('\x7f');
143
+ t.check(Boolean(await t.waitFor(() => after().includes('got <7f>'), WAIT.screen)), 'Backspace reaches the agent as DEL (one character, not a word)', 'screen: ' + tail(after(), 800));
144
+ send('\x08');
145
+ t.check(Boolean(await t.waitFor(() => after().includes('got <08>'), WAIT.screen)), 'Ctrl+Backspace reaches the agent as ^H', 'screen: ' + tail(after(), 800));
146
+ send('\x1b[');
147
+ await new Promise((r) => setTimeout(r, 5));
148
+ send('C');
149
+ t.check(Boolean(await t.waitFor(() => after().includes('got <1b>[C'), WAIT.screen)), 'a Right arrow that reaches the client in two pieces arrives whole (no stray "C")', 'screen: ' + tail(after(), 800));
150
+ const before = screen().length;
151
+ send('L');
152
+ const done = await t.waitFor(() => screen().includes('LINES-DONE'), WAIT.screen);
153
+ const printed = screen().slice(before);
154
+ const seen = new Set([...printed.matchAll(/line (\d+)\b/g)].map((m) => Number(m[1])));
155
+ const missing = Array.from({ length: 500 }, (_, i) => i + 1)
156
+ .filter((n) => !seen.has(n))
157
+ .map((n) => 'line ' + n);
158
+ t.check(Boolean(done) && missing.length === 0, 'all 500 printed lines reach the terminal as lines', 'missing: ' + missing.slice(0, 10).join(', ') + '\n' + tail(printed));
159
+ // (The client clears the tab once when it starts; from then on nothing may take the scrollback away.)
160
+ const session = screen().slice(screen().indexOf('AGENT-READY'));
161
+ for (const [sequence, what] of [
162
+ ['\x1b[?1049h', 'alternate screen'],
163
+ ['\x1b[?47h', 'alternate screen (47)'],
164
+ ['\x1b[?1047h', 'alternate screen (1047)'],
165
+ ['\x1b[3J', 'clear scrollback'],
166
+ ]) {
167
+ t.excludes(session, sequence, 'the terminal is never sent ' + what + ' (' + JSON.stringify(sequence) + ')');
168
+ }
169
+ if (kind) {
170
+ // A viewer that joins after the agent cleared its screen: the replay starts at the clear, the modes come first.
171
+ send('K');
172
+ await t.waitFor(() => screen().includes('CLEARED'), WAIT.screen);
173
+ const late = await openViewer({ addresses: ['127.0.0.1'], port: innerPort, token: 'tok' });
174
+ viewers.push(late);
175
+ await t.waitFor(() => late.output().includes('CLEARED'), WAIT.screen);
176
+ const head = late.output().slice(0, late.output().indexOf('CLEARED'));
177
+ t.check(head.includes('\x1b[?1000h') && head.includes('\x1b[?1006h'), "a viewer joining after a screen clear gets the agent's mouse tracking before the replay", 'late viewer: ' + JSON.stringify(late.output().slice(0, 300)));
178
+ late.close();
179
+ }
180
+ send('q');
181
+ const ended = await t.waitFor(() => screen().includes('CLIENT-DONE'), WAIT.exit);
182
+ t.check(Boolean(ended), 'the client ends with the agent', 'screen: ' + tail(screen()));
183
+ if (kind)
184
+ t.includes(screen().slice(screen().lastIndexOf('got q')), '\x1b[?1000l', 'leaving the session turns mouse tracking off in the terminal again');
185
+ }
186
+ finally {
187
+ for (const v of viewers)
188
+ v.close();
189
+ for (const c of children)
190
+ if (c.exitCode === null)
191
+ c.kill();
192
+ }
193
+ }
194
+ },
195
+ };
@@ -1,2 +1,2 @@
1
- import type { Suite } from './suite.js';
1
+ import type { Suite } from './support/suite.js';
2
2
  export declare const localConfigSuite: Suite;
@@ -3,8 +3,8 @@
3
3
  import fs from 'node:fs';
4
4
  import os from 'node:os';
5
5
  import path from 'node:path';
6
- import { download, setChecksumRequired } from '../shared/download.js';
7
- import { allowedAnswer, allowStorePath, saveAllowed } from '../core/local-config.js';
6
+ import { Downloader } from '../shared/download/index.js';
7
+ import { allowedAnswer, allowStorePath, saveAllowed } from '../core/local-config/index.js';
8
8
  export const localConfigSuite = {
9
9
  name: 'local-config',
10
10
  title: '.sandbox-config.json: approval, tighten-only rules, validation',
@@ -14,7 +14,10 @@ export const localConfigSuite = {
14
14
  harness: 'codex',
15
15
  sandbox: { memoryMb: 4096, networking: false, headless: true },
16
16
  toolchains: { node: { version: '18' }, rust: { enabled: false } },
17
- mappings: [{ host: './assets', guest: 'C:\\Assets', readOnly: true }, { host: './data', guest: 'C:\\Data', readOnly: false }],
17
+ mappings: [
18
+ { host: './assets', guest: 'C:\\Assets', readOnly: true },
19
+ { host: './data', guest: 'C:\\Data', readOnly: false },
20
+ ],
18
21
  scripts: ['./setup.mjs'],
19
22
  };
20
23
  f.writeLocal(f.workB, localB);
@@ -30,7 +33,14 @@ export const localConfigSuite = {
30
33
  rustEnabled: approved.config.toolchains.rust.enabled,
31
34
  pythonStillOn: Boolean(approved.config.toolchains.python.enabled),
32
35
  nodeSource: approved.versions.node.source,
33
- }, { harness: 'codex', memoryMb: 4096, headless: true, rustEnabled: false, pythonStillOn: true, nodeSource: '.sandbox-config.json' }, 'approved local settings apply over the defaults (including toolchains and headless)');
36
+ }, {
37
+ harness: 'codex',
38
+ memoryMb: 4096,
39
+ headless: true,
40
+ rustEnabled: false,
41
+ pythonStillOn: true,
42
+ nodeSource: '.sandbox-config.json',
43
+ }, 'approved local settings apply over the defaults (including toolchains and headless)');
34
44
  t.check(approved.config.mappings.some((m) => m.host === path.join(f.workB, 'data') && !m.readOnly), 'relative mapping paths resolve against the folder of .sandbox-config.json', 'mappings: ' + JSON.stringify(approved.config.mappings));
35
45
  t.check(approved.scripts.includes(path.join(f.workB, 'setup.mjs')), 'relative script paths resolve against the folder of .sandbox-config.json', 'scripts: ' + JSON.stringify(approved.scripts));
36
46
  t.equal((await f.run({ cwd: f.workB })).harnessName, 'codex', 'an approval is remembered');
@@ -50,14 +60,53 @@ export const localConfigSuite = {
50
60
  await rejectedBecause({ claudeProfile: { hostDir: 'C:\\x' } }, 'claudeProfile.hostDir is not allowed', 'a project file cannot point at the Claude profile folder');
51
61
  await rejectedBecause({ toolchains: { node: { hostDir: 'x' } } }, 'toolchains.node.hostDir is not allowed', 'a project file cannot point at host tool folders');
52
62
  await rejectedBecause({ sandbox: { memoryMb: 12 } }, 'sandbox.memoryMb:', 'values are type-checked (memory too small)');
53
- await rejectedBecause({ mappings: [{ host: 'x', guest: 'C:\\Windows\\x', readOnly: true }] }, 'reserved or invalid guest path', 'reserved guest paths are rejected');
54
- await rejectedBecause({ mappings: [{ host: '../shared', guest: 'C:\\Shared', readOnly: true }] }, 'only map folders inside the project', 'a project file cannot map folders outside the project');
55
- await rejectedBecause({ mappings: [{ host: '%APPDATA%', guest: 'C:\\Startup', readOnly: false }] }, 'only map folders inside the project', '... not even through environment variables');
56
63
  await rejectedBecause({ provisioning: { git: { access: 'admin' } } }, 'provisioning.git.access:', 'unknown git access modes are rejected');
57
64
  await rejectedBecause('{\n // a comment\n "readOnly": tru\n}', 'line 3', 'broken JSON is reported with its line');
58
65
  await rejectedBecause({ _comment: 'old style' }, '_comment is not allowed', 'unknown keys are rejected');
59
66
  f.writeLocal(dirC, '// comments and trailing commas are fine\n{\n "readOnly": true, /* inline */\n}\n');
60
67
  t.equal((await f.run({ cwd: dirC, trustConfig: true })).config.readOnly, true, '.sandbox-config.json may contain comments and trailing commas');
68
+ t.section('folders outside the project (projects.allowOutsideMappings)');
69
+ const dirD = t.dir('work-d');
70
+ const withOutside = (setting) => ({
71
+ ...f.baseConfig,
72
+ projects: { ...f.baseConfig.projects, allowOutsideMappings: setting },
73
+ });
74
+ const outsideFile = { mappings: [{ host: '../shared', readOnly: true }] };
75
+ f.writeLocal(dirD, outsideFile);
76
+ const notAllowed = await t.thrownMessage(() => f.run({ cwd: dirD, trustConfig: true }, withOutside(false)));
77
+ t.check(notAllowed.includes('outside the project') &&
78
+ notAllowed.includes(f.shared) &&
79
+ notAllowed.includes('projects.allowOutsideMappings'), 'false: refused, naming the folder and the setting that allows it', notAllowed);
80
+ const allowedOutside = await f.run({ cwd: dirD, trustConfig: true }, withOutside(true));
81
+ t.check(allowedOutside.config.mappings.some((m) => m.host === f.shared) &&
82
+ (allowedOutside.outsideMappings ?? []).includes(f.shared), 'true: allowed, and marked as outside the project');
83
+ f.writeLocal(dirD, { ...outsideFile, readOnly: true });
84
+ t.includes(await t.thrownMessage(() => f.run({ cwd: dirD }, withOutside(true))), '(outside the project)', 'true: still listed, flagged, when you approve the file');
85
+ const asking = await t.thrownMessage(() => f.run({ cwd: dirD, trustConfig: true, ask: async () => true, interactive: false }));
86
+ t.check(asking.includes('projects.allowOutsideMappings') && asking.includes('interactive'), '"ask" without a terminal (even with --trust-config): refused, naming the setting and that an interactive launch asks', asking);
87
+ t.includes(await t.thrownMessage(() => f.run({ cwd: dirD, trustConfig: true, ask: async () => false, interactive: true })), 'You did not allow', '"ask": answering no stops the launch');
88
+ const questions = [];
89
+ f.writeLocal(dirD, { ...outsideFile, sandbox: { vGpu: true } });
90
+ const asked = await f.run({
91
+ cwd: dirD,
92
+ trustConfig: true,
93
+ interactive: true,
94
+ ask: async (q) => {
95
+ questions.push(q);
96
+ return true;
97
+ },
98
+ });
99
+ t.check(questions.length === 1 && asked.config.sandbox.vGpu && asked.config.mappings.some((m) => m.host === f.shared), '"ask": the folder and a looser setting (vGPU) are asked together, once', JSON.stringify(questions));
100
+ t.check((await f.run({ cwd: dirD, trustConfig: true, interactive: false })).config.mappings.some((m) => m.host === f.shared), '"ask": the answer is remembered for this project file');
101
+ // What counts as outside is where the folder really is: environment variables are expanded and links followed.
102
+ f.writeLocal(dirD, { mappings: [{ host: '%APPDATA%', readOnly: false }] });
103
+ t.includes(await t.thrownMessage(() => f.run({ cwd: dirD, trustConfig: true }, withOutside(false))), 'outside the project', '%VAR% is expanded before deciding inside or outside');
104
+ fs.symlinkSync(f.shared, path.join(dirD, 'link'), 'junction');
105
+ f.writeLocal(dirD, { mappings: [{ host: './link', readOnly: true }] });
106
+ t.includes(await t.thrownMessage(() => f.run({ cwd: dirD, trustConfig: true }, withOutside(false))), 'outside the project', 'a link inside the project to a folder outside counts as outside');
107
+ fs.rmSync(path.join(dirD, 'link'));
108
+ f.writeLocal(dirD, { mappings: [{ host: './assets', readOnly: true }] });
109
+ t.check((await f.run({ cwd: dirD, trustConfig: true }, withOutside(false))).config.mappings.some((m) => m.host === path.join(dirD, 'assets')), 'a folder inside the project needs no permission');
61
110
  t.section('a project can only tighten protections');
62
111
  // Settings that would loosen a protection are listed before approval, then ignored.
63
112
  f.writeLocal(dirC, {
@@ -87,18 +136,42 @@ export const localConfigSuite = {
87
136
  networking: kept.sandbox.networking,
88
137
  protectedClient: kept.sandbox.protectedClient,
89
138
  copyCredentials: kept.claudeProfile.copyCredentials,
90
- }, { readOnly: true, blockPrivateRanges: true, gitAccess: 'readonly', vGpu: false, clipboard: false, networking: false, protectedClient: true, copyCredentials: false }, 'a project file can never loosen network, git, read-only, GPU, clipboard or login settings');
139
+ }, {
140
+ readOnly: true,
141
+ blockPrivateRanges: true,
142
+ gitAccess: 'readonly',
143
+ vGpu: false,
144
+ clipboard: false,
145
+ networking: false,
146
+ protectedClient: true,
147
+ copyCredentials: false,
148
+ }, 'a project file can never loosen network, git, read-only, GPU, clipboard or login settings');
91
149
  // You allowed one request for this project (asked once at an interactive launch): only that one is let through.
92
150
  const store = allowStorePath(strictUser.storage.root);
93
151
  saveAllowed(store, path.join(dirC, '.sandbox-config.json'), 'sandbox.vGpu', true, true);
94
152
  saveAllowed(store, path.join(dirC, '.sandbox-config.json'), 'sandbox.clipboard', true, false);
95
153
  const allowedRun = await f.run({ cwd: dirC, trustConfig: true }, strictUser);
96
- t.equal({ vGpu: allowedRun.config.sandbox.vGpu, clipboard: allowedRun.config.sandbox.clipboard, networking: allowedRun.config.sandbox.networking }, { vGpu: true, clipboard: false, networking: false }, 'a request you allowed for this project is used; one you declined and the others are not');
97
- t.check(allowedRun.notes.some((n) => n.includes('Allowed for this project: sandbox.vGpu')) && allowedRun.notes.some((n) => n.includes('sandbox.clipboard') && n.includes('You said no')), 'launch says what was allowed and what you declined', allowedRun.notes.join('\n'));
154
+ t.equal({
155
+ vGpu: allowedRun.config.sandbox.vGpu,
156
+ clipboard: allowedRun.config.sandbox.clipboard,
157
+ networking: allowedRun.config.sandbox.networking,
158
+ }, { vGpu: true, clipboard: false, networking: false }, 'a request you allowed for this project is used; one you declined and the others are not');
159
+ t.check(allowedRun.notes.some((n) => n.includes('Allowed for this project: sandbox.vGpu')) &&
160
+ allowedRun.notes.some((n) => n.includes('sandbox.clipboard') && n.includes('You said no')), 'launch says what was allowed and what you declined', allowedRun.notes.join('\n'));
98
161
  t.equal(allowedAnswer(store, path.join(f.workB, '.sandbox-config.json'), 'sandbox.vGpu', true), null, 'an answer is kept per project file');
99
- f.writeLocal(dirC, { readOnly: true, network: { blockPrivateRanges: true }, provisioning: { git: { access: 'none' } }, sandbox: { networking: false, clipboard: false } });
162
+ f.writeLocal(dirC, {
163
+ readOnly: true,
164
+ network: { blockPrivateRanges: true },
165
+ provisioning: { git: { access: 'none' } },
166
+ sandbox: { networking: false, clipboard: false },
167
+ });
100
168
  const tightened = (await f.run({ cwd: dirC, trustConfig: true })).config;
101
- t.equal({ readOnly: tightened.readOnly, gitAccess: tightened.provisioning.git.access, networking: tightened.sandbox.networking, clipboard: tightened.sandbox.clipboard }, { readOnly: true, gitAccess: 'none', networking: false, clipboard: false }, 'a project file can still make things stricter');
169
+ t.equal({
170
+ readOnly: tightened.readOnly,
171
+ gitAccess: tightened.provisioning.git.access,
172
+ networking: tightened.sandbox.networking,
173
+ clipboard: tightened.sandbox.clipboard,
174
+ }, { readOnly: true, gitAccess: 'none', networking: false, clipboard: false }, 'a project file can still make things stricter');
102
175
  t.section('downloads.requireChecksum');
103
176
  f.writeLocal(dirC, { downloads: { requireChecksum: false } });
104
177
  const keptOn = (await f.run({ cwd: dirC, trustConfig: true }, { ...f.baseConfig, downloads: { requireChecksum: true } })).config;
@@ -108,10 +181,10 @@ export const localConfigSuite = {
108
181
  t.equal(turnedOn.downloads.requireChecksum, true, 'a project file can switch the checksum requirement on');
109
182
  t.equal(f.baseConfig.downloads.requireChecksum, false, '(the requirement is off in the defaults)');
110
183
  // With the requirement on, a download without a hash is refused before anything is fetched.
111
- setChecksumRequired(true);
184
+ const strict = new Downloader();
185
+ strict.requireChecksum = true;
112
186
  const target = path.join(os.tmpdir(), 'agent-sandbox-no-such-download.bin');
113
- const refused = await download('http://127.0.0.1:9/tool.zip', target).then(() => '', (e) => e.message);
114
- setChecksumRequired(false);
187
+ const refused = await strict.file('http://127.0.0.1:9/tool.zip', target).then(() => '', (e) => e.message);
115
188
  t.includes(refused, 'requireChecksum', 'a download with no hash is refused when checksums are required');
116
189
  t.includes(refused, 'tool.zip', 'the refusal names the download');
117
190
  t.check(!fs.existsSync(target) && !fs.existsSync(target + '.part'), 'a refused download leaves nothing behind');
@@ -1,2 +1,2 @@
1
- import type { Suite } from './suite.js';
1
+ import type { Suite } from './support/suite.js';
2
2
  export declare const mirrorSuite: Suite;
@@ -1,35 +1,70 @@
1
1
  // Guest paths on other drive letters (C:\Mirror\<letter> + subst) and guestWorkspace "mirror".
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
- import { Config, Mapping } from '../core/schema.js';
4
+ import { ConfigSchema, MappingSchema } from '../core/schema/index.js';
5
5
  import { guestPathFor } from '../cli/commands/context.js';
6
- import { buildWsb } from '../host/launch/wsb.js';
7
- import { guestDrive, isValidGuestPath, planMirrorWorkspace, sandboxFolder, substDrives } from '../shared/guest-paths.js';
8
- import { guestWorkspaceAliases, projectFolderName } from '../shared/paths.js';
9
- import { syncHistoryIn, syncHistoryOut } from '../sync/history.js';
6
+ import { buildWsb } from '../host/launch/index.js';
7
+ import { deriveGuest, guestDrive, isValidGuestPath, planMirrorWorkspace, sandboxFolder, substDrives, } from '../shared/paths/index.js';
8
+ import { guestWorkspaceAliases, projectFolderName } from '../shared/paths/index.js';
9
+ import { syncHistoryIn, syncHistoryOut } from '../sync/index.js';
10
10
  export const mirrorSuite = {
11
11
  name: 'mirror',
12
12
  title: 'guest paths on other drive letters, guestWorkspace "mirror"',
13
13
  run: async (t, f) => {
14
14
  t.section('which guest paths are valid');
15
- const valid = ['C:\\Assets', 'C:\\Workspace\\x', 'F:\\SteamLibrary\\steamapps\\common\\Game', 'f:\\x', 'Z:\\a b\\c (1)'];
15
+ const valid = [
16
+ 'C:\\Assets',
17
+ 'C:\\Workspace\\x',
18
+ 'F:\\SteamLibrary\\steamapps\\common\\Game',
19
+ 'f:\\x',
20
+ 'Z:\\a b\\c (1)',
21
+ ];
16
22
  t.equal(valid.filter((p) => !isValidGuestPath(p)), [], 'guest paths under C:\\ or on D: to Z: are accepted');
17
- const invalid = ['C:\\', 'F:\\', 'F:', 'C:\\Windows\\x', 'C:\\Users\\me', 'c:\\program files\\x', 'C:\\AgentData\\x', 'C:\\Mirror', 'C:\\Mirror\\F\\x', 'A:\\x', 'B:\\x', 'C:\\a\\..\\Windows', 'F:\\a\\..\\b', 'F:\\a:b', 'F:\\a/b', 'F:\\a\\\\b', 'F:\\a.\\b', 'F:\\a|b', 'F:\\a\nb', '\\\\server\\share\\x', 'relative\\x', 'F:x'];
23
+ const invalid = [
24
+ 'C:\\',
25
+ 'F:\\',
26
+ 'F:',
27
+ 'C:\\Windows\\x',
28
+ 'C:\\Users\\me',
29
+ 'c:\\program files\\x',
30
+ 'C:\\AgentData\\x',
31
+ 'C:\\Mirror',
32
+ 'C:\\Mirror\\F\\x',
33
+ 'A:\\x',
34
+ 'B:\\x',
35
+ 'C:\\a\\..\\Windows',
36
+ 'F:\\a\\..\\b',
37
+ 'F:\\a:b',
38
+ 'F:\\a/b',
39
+ 'F:\\a\\\\b',
40
+ 'F:\\a.\\b',
41
+ 'F:\\a|b',
42
+ 'F:\\a\nb',
43
+ '\\\\server\\share\\x',
44
+ 'relative\\x',
45
+ 'F:x',
46
+ ];
18
47
  t.equal(invalid.filter(isValidGuestPath), [], 'drive roots, reserved folders, C:\\Mirror, A:/B:, .., streams, odd characters and UNC paths are refused');
19
- const mappingAccepts = (guest) => Mapping.safeParse({ host: 'E:\\Games', guest, readOnly: true }).success;
20
- t.check(mappingAccepts('F:\\SteamLibrary\\Game') && mappingAccepts('C:\\F'), 'schema: mappings[].guest may be on another drive letter');
21
- t.check(!mappingAccepts('C:\\Mirror\\F\\x') && !mappingAccepts('F:\\'), 'schema: mappings[].guest may never be C:\\Mirror or a drive root');
22
- const workspaceAccepts = (guestWorkspace) => Config.safeParse({ ...f.makeConfig(), guestWorkspace }).success;
48
+ const mappingAccepts = (guest) => MappingSchema.safeParse({ host: 'E:\\Games', guest, readOnly: true }).success;
49
+ t.check(mappingAccepts('F:\\SteamLibrary\\Game') && mappingAccepts('C:\\Windows\\x') && mappingAccepts(undefined), 'schema: any mappings[].guest is accepted, or none (the launch places it; it never fails the config)');
50
+ const workspaceAccepts = (guestWorkspace) => ConfigSchema.safeParse({ ...f.makeConfig(), guestWorkspace }).success;
23
51
  t.check(workspaceAccepts('mirror') && workspaceAccepts('F:\\AgentProjects\\x'), 'schema: guestWorkspace accepts "mirror" and D:-Z: paths');
24
52
  t.check(!workspaceAccepts('C:\\Users\\x'), 'schema: guestWorkspace refuses reserved paths');
25
53
  t.equal([guestDrive('f:\\x'), guestDrive('\\\\s\\x')], ['F', null], 'drive letter of a guest path');
26
54
  t.section('where a drive-letter path really lives');
27
55
  t.equal([sandboxFolder('F:\\SteamLibrary\\Game'), sandboxFolder('f:\\x'), sandboxFolder('C:\\Assets')], ['C:\\Mirror\\F\\SteamLibrary\\Game', 'C:\\Mirror\\F\\x', 'C:\\Assets'], 'F:\\x really lives at C:\\Mirror\\F\\x; C: paths stay as they are');
28
- t.equal(substDrives(['C:\\a', 'G:\\z', 'F:\\x', 'f:\\y']), [{ letter: 'F', target: 'C:\\Mirror\\F' }, { letter: 'G', target: 'C:\\Mirror\\G' }], 'one subst drive per used letter (never C:), sorted');
56
+ t.equal(substDrives(['C:\\a', 'G:\\z', 'F:\\x', 'f:\\y']), [
57
+ { letter: 'F', target: 'C:\\Mirror\\F' },
58
+ { letter: 'G', target: 'C:\\Mirror\\G' },
59
+ ], 'one subst drive per used letter (never C:), sorted');
29
60
  t.equal(guestWorkspaceAliases('F:\\AgentProjects\\mw2'), ['C:\\Mirror\\F\\AgentProjects\\mw2', 'F:\\AgentProjects\\mw2'], 'a mirrored workspace is also known by its real C:\\Mirror path');
30
61
  t.equal(guestWorkspaceAliases('C:\\Workspace\\x').length, 1, 'a C: workspace has no alias');
31
62
  const wsb = buildWsb(f.baseConfig, 4096, [
32
- { host: 'E:\\SteamLibrary\\steamapps\\common\\Game', guest: 'F:\\SteamLibrary\\steamapps\\common\\Game', readOnly: true },
63
+ {
64
+ host: 'E:\\SteamLibrary\\steamapps\\common\\Game',
65
+ guest: 'F:\\SteamLibrary\\steamapps\\common\\Game',
66
+ readOnly: true,
67
+ },
33
68
  { host: 'D:\\Assets', guest: 'C:\\Assets', readOnly: false },
34
69
  ]);
35
70
  t.includes(wsb, '<SandboxFolder>C:\\Mirror\\F\\SteamLibrary\\steamapps\\common\\Game</SandboxFolder>', 'the .wsb maps F:\\ guests under C:\\Mirror\\F');
@@ -55,19 +90,83 @@ export const mirrorSuite = {
55
90
  t.section('generating a sandbox with drive-letter folders');
56
91
  const game = t.dir('steam', 'Game');
57
92
  const base = await f.run();
58
- const run = { ...base, config: { ...base.config, guestWorkspace: 'G:\\Projects\\work-a', mappings: [{ host: game, guest: 'F:\\SteamLibrary\\steamapps\\common\\Game', readOnly: true }] } };
93
+ const run = {
94
+ ...base,
95
+ config: {
96
+ ...base.config,
97
+ guestWorkspace: 'G:\\Projects\\work-a',
98
+ mappings: [{ host: game, guest: 'F:\\SteamLibrary\\steamapps\\common\\Game', readOnly: true }],
99
+ },
100
+ };
59
101
  const generated = f.generate(run);
60
102
  const session = f.readJson(generated.sessionPath);
61
103
  const text = fs.readFileSync(generated.wsbPath, 'utf8');
62
104
  t.equal(session.workspace, 'G:\\Projects\\work-a', 'session.json: the workspace is at its drive-letter path');
63
- t.equal(session.substDrives, [{ letter: 'F', target: 'C:\\Mirror\\F' }, { letter: 'G', target: 'C:\\Mirror\\G' }], 'session.json: subst drives are listed for bootstrap.ps1');
105
+ t.equal(session.substDrives, [
106
+ { letter: 'F', target: 'C:\\Mirror\\F' },
107
+ { letter: 'G', target: 'C:\\Mirror\\G' },
108
+ ], 'session.json: subst drives are listed for bootstrap.ps1');
64
109
  t.includes(text, '<SandboxFolder>C:\\Mirror\\G\\Projects\\work-a</SandboxFolder>', '.wsb: the workspace is under C:\\Mirror');
65
110
  t.includes(text, '<SandboxFolder>C:\\Mirror\\F\\SteamLibrary\\steamapps\\common\\Game</SandboxFolder>', '.wsb: the mapping is under C:\\Mirror');
66
111
  t.equal(f.readJson(f.generate(base).sessionPath).substDrives, [], 'no other drive letters: no subst drives');
67
- const withMapping = (guest) => ({ ...run, config: { ...run.config, mappings: [{ host: game, guest, readOnly: true }] } });
68
- await t.throws(() => f.generate(withMapping('C:\\Mirror\\F\\x')), 'not a usable sandbox folder', 'a mapping straight into C:\\Mirror is refused');
69
- await t.throws(() => f.generate(withMapping('C:\\Windows\\x')), 'not a usable sandbox folder', 'a reserved guest folder is refused by the host too (not only the schema)');
70
- await t.throws(() => f.generate(withMapping('g:\\projects\\work-a\\game')), 'overlapping', 'mappings overlapping on the same mirrored drive are refused');
112
+ t.section('where an extra folder goes: guest left out, or one the sandbox cannot use');
113
+ t.equal([
114
+ deriveGuest('F:\\P\\mw2\\data\\maps', 'F:\\P\\mw2', 'C:\\Workspace\\mw2'),
115
+ deriveGuest('C:\\Steam\\MOHAA', 'F:\\P\\mw2', 'C:\\Workspace\\mw2'),
116
+ deriveGuest('f:\\SteamLibrary\\steamapps\\common\\MW2\\', 'F:\\P\\mw2', 'C:\\Workspace\\mw2'),
117
+ ], ['C:\\Workspace\\mw2\\data\\maps', 'C:\\Steam\\MOHAA', 'F:\\SteamLibrary\\steamapps\\common\\MW2'], 'no guest: inside the project = the same place in it; outside = the same path as on the PC (C: as is, F: through C:\\Mirror\\F + subst)');
118
+ const other = t.dir('steam', 'Other');
119
+ const placed = (mappings) => {
120
+ const g = f.generate({ ...run, config: { ...run.config, mappings } });
121
+ return {
122
+ guests: g.mappings.filter((m) => m.host === game || m.host === other).map((m) => m.guest),
123
+ notes: g.mappingNotes,
124
+ wsb: fs.readFileSync(g.wsbPath, 'utf8'),
125
+ };
126
+ };
127
+ const usable = placed([
128
+ { host: game, guest: 'D:\\Games', readOnly: true },
129
+ { host: game, guest: 'c:/assets/', readOnly: true },
130
+ { host: game, guest: 'C:\\assets', readOnly: true },
131
+ ]);
132
+ t.equal(usable.guests, ['D:\\Games', 'C:\\assets'], 'a usable guest path is used exactly as asked (c:/assets/ tidied); the same folder at the same place is mapped once');
133
+ const refused = await t.thrownMessage(() => placed([
134
+ { host: game, guest: 'C:\\Windows\\foo', readOnly: true },
135
+ { host: game, guest: 'steamapps\\Game', readOnly: true },
136
+ { host: game, guest: 'G:\\Projects\\work-a', readOnly: true },
137
+ { host: game, guest: 'C:\\Assets', readOnly: true },
138
+ { host: other, guest: 'C:\\Assets', readOnly: true },
139
+ ]));
140
+ t.check(refused.includes('4 mapped folders cannot be used'), 'unusable guest paths stop the launch, all named in one message (never moved elsewhere)', refused);
141
+ t.check(refused.includes('C:\\Windows\\foo is a folder the sandbox keeps for itself') &&
142
+ refused.includes('steamapps\\Game is not a full path') &&
143
+ refused.includes('already used by'), '... each with why: reserved, relative, overlapping', refused);
144
+ t.check(refused.includes('Fix: set "guest" to a full path'), '... and the fix', refused);
145
+ t.excludes(refused, 'C:\\Mapped', 'no folder is ever placed under C:\\Mapped');
146
+ const derived = await t.thrownMessage(() => placed([{ host: game, readOnly: true }]));
147
+ t.check(derived === '' || derived.includes('give it a "guest" path'), 'no guest, outside the project: the PC path, or (under C:\\Users, like the temp folder) a message asking for a guest path', derived);
148
+ const inside = t.dir('work-a', 'data');
149
+ const insideRun = await f.run();
150
+ const insideGen = f.generate({
151
+ ...insideRun,
152
+ config: { ...insideRun.config, mappings: [{ host: inside, readOnly: true }] },
153
+ });
154
+ t.check(!insideGen.mappings.some((m) => m.host === inside) &&
155
+ insideGen.mappingNotes.some((n) => n.includes('already in the sandbox at C:\\Workspace\\work-a\\data')), 'no guest, inside the project: already there, no second mapping', insideGen.mappingNotes.join('\n'));
156
+ const missingRequired = await t.thrownMessage(() => f.generate({
157
+ ...run,
158
+ config: {
159
+ ...run.config,
160
+ mappings: [
161
+ { host: t.at('nope-1'), readOnly: true },
162
+ { host: t.at('nope-2'), guest: 'C:\\Windows', readOnly: true },
163
+ ],
164
+ },
165
+ }));
166
+ t.check(missingRequired.includes('2 mapped folders cannot be used') &&
167
+ missingRequired.includes('nope-1') &&
168
+ missingRequired.includes('nope-2') &&
169
+ missingRequired.includes('"optional": true'), 'folders that are not there: one message listing each, with the fix', missingRequired);
71
170
  t.section('exec, attach and history for a mirrored workspace');
72
171
  const workspace = 'F:\\AgentProjects\\mw2-agent';
73
172
  t.equal(guestPathFor(workspace + '\\crates\\engine', workspace, workspace), workspace + '\\crates\\engine', 'a host folder maps to the same guest folder');
@@ -1,2 +1,2 @@
1
- import type { Suite } from './suite.js';
1
+ import type { Suite } from './support/suite.js';
2
2
  export declare const networkSuite: Suite;
@@ -1,6 +1,6 @@
1
- import { isSandboxAddress } from '../host/attach.js';
2
- import { buildFirewallCommands, cidrToRange, ipv4DnsServers, parseDefaultGateways, parseDnsServers, subtractIps } from '../shared/netrules.js';
3
- import { expandAllowList, hostAllowed, withBlockedHosts } from '../shared/netpolicy.js';
1
+ import { isSandboxAddress } from '../host/channel/index.js';
2
+ import { buildFirewallCommands, cidrToRange, ipv4DnsServers, parseDefaultGateways, parseDnsServers, subtractIps, } from '../shared/network/index.js';
3
+ import { expandAllowList, hostAllowed, withBlockedHosts } from '../shared/network/index.js';
4
4
  export const networkSuite = {
5
5
  name: 'network',
6
6
  title: 'firewall maths, gateway/DNS parsing, attach address checks',
@@ -17,19 +17,28 @@ export const networkSuite = {
17
17
  t.equal(ipv4DnsServers(['172.28.80.1', '8.8.8.8:1053', '[::1]:53', 'fe80::1']), ['172.28.80.1', '8.8.8.8'], 'DNS servers from the resolver (any Windows language): IPv4 only, ports dropped');
18
18
  t.section('attach only reaches into the sandbox');
19
19
  const interfaces = {
20
- 'vEthernet (Default Switch)': [{ address: '172.20.0.1', netmask: '255.255.240.0', family: 'IPv4', internal: false, mac: '', cidr: null }],
21
- 'vEthernet (WSL (Hyper-V firewall))': [{ address: '172.30.0.1', netmask: '255.255.240.0', family: 'IPv4', internal: false, mac: '', cidr: null }],
22
- Ethernet: [{ address: '192.168.1.10', netmask: '255.255.255.0', family: 'IPv4', internal: false, mac: '', cidr: null }],
20
+ 'vEthernet (Default Switch)': [
21
+ { address: '172.20.0.1', netmask: '255.255.240.0', family: 'IPv4', internal: false, mac: '', cidr: null },
22
+ ],
23
+ 'vEthernet (WSL (Hyper-V firewall))': [
24
+ { address: '172.30.0.1', netmask: '255.255.240.0', family: 'IPv4', internal: false, mac: '', cidr: null },
25
+ ],
26
+ Ethernet: [
27
+ { address: '192.168.1.10', netmask: '255.255.255.0', family: 'IPv4', internal: false, mac: '', cidr: null },
28
+ ],
23
29
  };
24
30
  t.check(isSandboxAddress('172.20.5.9', interfaces), 'an address in the Hyper-V subnet is the sandbox');
25
31
  t.check(!isSandboxAddress('192.168.1.20', interfaces), 'a LAN address is not');
26
32
  t.check(!isSandboxAddress('172.30.4.4', interfaces), 'an address on the WSL Hyper-V network is not (keystrokes never go to a WSL VM)');
27
33
  t.check(!isSandboxAddress('127.0.0.1', interfaces), 'loopback is not');
28
34
  t.check(!isSandboxAddress('8.8.8.8', interfaces), 'an internet address is not');
29
- t.check(!isSandboxAddress('172.20.0.1', interfaces), 'this PC\'s own address on that subnet is not');
35
+ t.check(!isSandboxAddress('172.20.0.1', interfaces), "this PC's own address on that subnet is not");
30
36
  t.section('network settings');
31
37
  const allow = expandAllowList(['@developer', 'Example.COM', '*.corp.example', 'not a host!']);
32
- t.check(allow.includes('registry.npmjs.org') && allow.includes('api.anthropic.com') && allow.includes('example.com') && !allow.includes('not a host!'), 'allowOnly: @developer expands to registries, GitHub and AI providers; bad entries are dropped');
38
+ t.check(allow.includes('registry.npmjs.org') &&
39
+ allow.includes('api.anthropic.com') &&
40
+ allow.includes('example.com') &&
41
+ !allow.includes('not a host!'), 'allowOnly: @developer expands to registries, GitHub and AI providers; bad entries are dropped');
33
42
  t.equal(['a.corp.example', 'corp.example', 'example.com', 'www.example.com', 'evil-example.com'].map((h) => hostAllowed(h, allow)), [true, false, true, false, false], 'allowOnly: *.x covers subdomains only, a name covers only itself');
34
43
  const hosts = '127.0.0.1 localhost\r\n# mine\r\n';
35
44
  const once = withBlockedHosts(hosts, ['Telemetry.Example.com', '*.bad']);
@@ -1,2 +1,2 @@
1
- import type { Suite } from './suite.js';
1
+ import type { Suite } from './support/suite.js';
2
2
  export declare const personalizationSuite: Suite;