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,29 @@
1
+ /** optional()/default() wrappers hide the real type. */
2
+ export const unwrap = (s) => (['optional', 'default', 'nullable'].includes(s._zod.def.type) && s._zod.def.innerType ? unwrap(s._zod.def.innerType) : s);
3
+ export const kind = (s) => unwrap(s)._zod.def.type;
4
+ export const isSection = (s) => kind(s) === 'object' && Boolean(unwrap(s).shape);
5
+ /** Settings not worth editing here (the schema link). */
6
+ const HIDDEN = new Set(['$schema']);
7
+ /** The settings one level below a section (or the top level), in schema order. */
8
+ export const childrenOf = (schema) => Object.entries(unwrap(schema).shape ?? {}).filter(([name]) => !HIDDEN.has(name));
9
+ /** The description, which `.partial()` and `.optional()` wrappers may carry on the inner schema instead. */
10
+ export const describeSetting = (s) => s.description ?? unwrap(s).description;
11
+ /** Every setting that is edited with a prompt of its own (everything that is not a section), with its path. */
12
+ export const leavesOf = (schema, key = []) => childrenOf(schema).flatMap(([name, child]) => (isSection(child) ? leavesOf(child, [...key, name]) : [{ key: [...key, name], schema: child }]));
13
+ /** Which prompt edits this setting. Lists of objects and maps (mappings, harnesses, environment) fall back to JSON. */
14
+ export const promptKind = (schema) => {
15
+ const s = unwrap(schema);
16
+ const type = s._zod.def.type;
17
+ if (type === 'boolean' || type === 'enum' || type === 'union' || type === 'number' || type === 'string')
18
+ return type;
19
+ if (type === 'array' && s._zod.def.element && kind(s._zod.def.element) === 'string')
20
+ return 'string-list';
21
+ return 'json';
22
+ };
23
+ const JSON_EXAMPLES = {
24
+ harnesses: '{"mytool": {"npmPackage": "my-cli", "npmBin": "my-cli", "arguments": [], "environment": {}}}',
25
+ mappings: '[{"host": "C:\\\\data", "guest": "C:\\\\Data", "readOnly": true}]',
26
+ environment: '{"NPM_CONFIG_REGISTRY": "https://registry.example.com"}',
27
+ };
28
+ /** A one-line example of the JSON a setting expects, shown in its prompt. */
29
+ export const jsonExample = (key, schema) => JSON_EXAMPLES[key[key.length - 1]] ?? (unwrap(schema)._zod.def.type === 'array' ? '["value", ...]' : '{"name": "value"}');
@@ -0,0 +1,17 @@
1
+ import type { Context } from './commands/context.js';
2
+ /** Edit distance, for "did you mean". */
3
+ export declare const distance: (a: string, b: string) => number;
4
+ /** The closest of `choices` to `input`, when it is close enough to be a typo. */
5
+ export declare const closest: (input: string, choices: readonly string[]) => string | undefined;
6
+ /** "Unknown agent "cluade". Did you mean claude?" with the valid values as the fix. */
7
+ export declare const unknownValue: (what: string, input: string, choices: readonly string[], howToList: string) => never;
8
+ /** Node: 22, 22.1, v22.1.0, lts, lts/*, lts/iron, latest, current, node. */
9
+ export declare const validNodeSpec: (spec: string) => boolean;
10
+ /** Python 3: 3, 3.12, 3.12.4. */
11
+ export declare const validPythonSpec: (spec: string) => boolean;
12
+ export declare const checkHarness: (name: string | undefined, harnesses: string[]) => void;
13
+ export declare const PROJECT_ACTIONS: readonly ["list", "choose", "add", "remove", "include", "exclude", "all", "roots"];
14
+ /** `sandbox projects <action> [value] [folder]`: the action, then what it needs. Pure (no file checks). */
15
+ export declare const validateProjectsArgs: (args: string[]) => void;
16
+ /** Fails with what is wrong and what is valid, before anything is started. */
17
+ export declare const validateOptions: (ctx: Context) => void;
@@ -0,0 +1,89 @@
1
+ // Checks what the user typed before anything starts, so a typo fails at once with the list of valid values
2
+ // instead of halfway into a sandbox boot. Pure helpers first, then validateOptions (the one call from the dispatcher).
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { DATABASES } from '../core/detect-databases.js';
6
+ import { fail } from '../core/util.js';
7
+ import { listAccounts } from '../host/accounts.js';
8
+ /** Edit distance, for "did you mean". */
9
+ export const distance = (a, b) => {
10
+ let row = Array.from({ length: b.length + 1 }, (_, i) => i);
11
+ for (let i = 1; i <= a.length; i++) {
12
+ const next = [i];
13
+ for (let j = 1; j <= b.length; j++)
14
+ next[j] = Math.min(row[j] + 1, next[j - 1] + 1, row[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
15
+ row = next;
16
+ }
17
+ return row[b.length];
18
+ };
19
+ /** The closest of `choices` to `input`, when it is close enough to be a typo. */
20
+ export const closest = (input, choices) => {
21
+ const best = choices.map((c) => ({ c, d: distance(input.toLowerCase(), c.toLowerCase()) })).sort((x, y) => x.d - y.d)[0];
22
+ return best && best.d <= Math.max(2, Math.floor(input.length / 3)) ? best.c : undefined;
23
+ };
24
+ /** "Unknown agent "cluade". Did you mean claude?" with the valid values as the fix. */
25
+ export const unknownValue = (what, input, choices, howToList) => {
26
+ const hint = closest(input, choices);
27
+ return fail('Unknown ' + what + ' "' + input + '".' + (hint ? ' Did you mean ' + hint + '?' : ''), (choices.length ? 'Choose one of: ' + choices.join(', ') + '. ' : '') + howToList);
28
+ };
29
+ /** Node: 22, 22.1, v22.1.0, lts, lts/*, lts/iron, latest, current, node. */
30
+ export const validNodeSpec = (spec) => /^(v?\d+(\.\d+){0,2}|node|latest|current|stable|lts(\/(\*|[a-z]+))?)$/i.test(spec.trim());
31
+ /** Python 3: 3, 3.12, 3.12.4. */
32
+ export const validPythonSpec = (spec) => /^v?3(\.\d+){0,2}$/.test(spec.trim());
33
+ export const checkHarness = (name, harnesses) => {
34
+ if (name !== undefined && !harnesses.includes(name))
35
+ unknownValue('agent', name, harnesses, 'Add your own under "harnesses" in your settings (sandbox config).');
36
+ };
37
+ /** Commands that read these options; checked only for them (restart/doctor take --harness too). */
38
+ const LAUNCHING = new Set(['launch', 'generate', 'host-claude']);
39
+ export const PROJECT_ACTIONS = ['list', 'choose', 'add', 'remove', 'include', 'exclude', 'all', 'roots'];
40
+ /** `sandbox projects <action> [value] [folder]`: the action, then what it needs. Pure (no file checks). */
41
+ export const validateProjectsArgs = (args) => {
42
+ const [action = 'list', value, folder] = args;
43
+ if (!PROJECT_ACTIONS.includes(action))
44
+ unknownValue('projects action', action, PROJECT_ACTIONS, 'sandbox projects with no action lists your projects.');
45
+ if (['add', 'remove', 'include', 'exclude'].includes(action) && !value)
46
+ fail('Which folder?', 'Usage: sandbox projects ' + action + ' <folder> (. = this folder)');
47
+ if (action === 'all' && value !== undefined && !['on', 'off'].includes(value))
48
+ unknownValue('value for projects all', value, ['on', 'off'], 'sandbox projects all on|off');
49
+ if (action === 'roots' && value !== undefined && !['list', 'add', 'remove'].includes(value))
50
+ unknownValue('projects roots action', value, ['list', 'add', 'remove'], 'sandbox projects roots add|remove <folder>');
51
+ if (action === 'roots' && (value === 'add' || value === 'remove') && !folder)
52
+ fail('Which folder?', 'Usage: sandbox projects roots ' + value + ' <folder>');
53
+ };
54
+ /** Fails with what is wrong and what is valid, before anything is started. */
55
+ export const validateOptions = (ctx) => {
56
+ const o = ctx.options;
57
+ const harnesses = Object.keys(ctx.loaded.config.harnesses);
58
+ if (['launch', 'generate', 'restart', 'doctor'].includes(o.command))
59
+ checkHarness(o.harness, harnesses);
60
+ if (o.command === 'projects')
61
+ validateProjectsArgs(o.positionals);
62
+ if (!LAUNCHING.has(o.command))
63
+ return;
64
+ if (o.node !== undefined && !validNodeSpec(o.node))
65
+ fail('"' + o.node + '" is not a Node version.', 'Use a number like 22 or 22.11.0, or lts, latest.');
66
+ if (o.python !== undefined && !validPythonSpec(o.python))
67
+ fail('"' + o.python + '" is not a Python 3 version.', 'Use 3, 3.12 or 3.12.4.');
68
+ for (const db of o.databases.flatMap((d) => d.split(',')).map((d) => d.trim()).filter(Boolean)) {
69
+ if (!DATABASES.includes(db))
70
+ unknownValue('database', db, DATABASES, 'Repeat --database for several.');
71
+ }
72
+ if (o.account !== undefined) {
73
+ const names = listAccounts(ctx.storageRoot, ctx.dataPath).map((a) => a.name);
74
+ if (!names.includes(o.account))
75
+ unknownValue('account', o.account, names, names.length ? 'See them with: sandbox account list' : 'None saved yet: sign in inside the sandbox, then run sandbox account save <name>.');
76
+ }
77
+ for (const s of o.sessions) {
78
+ checkHarness(s.harness, harnesses);
79
+ if (!fs.existsSync(s.folder) || !fs.statSync(s.folder).isDirectory())
80
+ fail('The folder ' + s.folder + ' (--session ' + s.harness + '@...) does not exist.', 'Check the path after the @.');
81
+ }
82
+ if (o.sessions.length && (o.harness !== undefined || o.workspace !== undefined))
83
+ fail('--session names the agent and folder of each session, so --harness and --workspace do not apply.', 'Use only --session <agent>@<folder> (repeatable).');
84
+ if (o.workspace !== undefined && !fs.existsSync(path.resolve(o.workspace)))
85
+ fail('The folder ' + path.resolve(o.workspace) + ' does not exist.', 'Check the --workspace path (or leave it out to use the current folder).');
86
+ for (const script of o.scripts)
87
+ if (!fs.existsSync(path.resolve(script)))
88
+ fail('The script ' + path.resolve(script) + ' does not exist.', 'Check the --script path.');
89
+ };
@@ -0,0 +1,17 @@
1
+ import type { Config, LoadedConfig } from './types.js';
2
+ export declare const DEFAULTS: Config;
3
+ /** Per-user folder for config and hooks. Survives reinstalling the npm package. */
4
+ export declare const userDir: () => string;
5
+ export declare const userConfigPath: () => string;
6
+ /** Deep merge where arrays (and anything that is not a plain object) replace instead of merging element by element. */
7
+ export declare const mergeConfig: <T>(base: T, extra: unknown) => T;
8
+ /** Validates a full config; throws one readable error listing every problem. */
9
+ export declare const validateConfig: (config: unknown, source: string) => Config;
10
+ /**
11
+ * Lookup order: --config, %AGENT_SANDBOX_CONFIG%, ~/.agent-sandbox/config.json, built-in defaults.
12
+ * Whatever file is found (JSON with comments) is merged over the defaults, so it only needs the keys you change.
13
+ */
14
+ export declare const loadConfig: (explicitPath?: string) => LoadedConfig;
15
+ export declare const assertNoGuestOverlap: (mappings: {
16
+ guest: string;
17
+ }[]) => void;
@@ -0,0 +1,106 @@
1
+ // Built-in defaults and loading the user config (~/.agent-sandbox/config.json). Shapes live in schema.ts.
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import _ from 'lodash';
5
+ import { Config as ConfigSchema, describeIssues } from './schema.js';
6
+ import { fail, homeDir, readJsonc } from './util.js';
7
+ export const DEFAULTS = {
8
+ defaultHarness: 'claude',
9
+ guestWorkspace: 'auto',
10
+ readOnly: false,
11
+ mappings: [],
12
+ sandbox: { memoryMb: 'auto', maxMemoryMb: 32768, maxMemoryPercent: 80, cpuLimit: 80, reserveHostMb: 8192, vGpu: false, networking: true, clipboard: true, audioInput: false, videoInput: false, printerRedirection: false, protectedClient: true, headless: false },
13
+ storage: { root: '%LOCALAPPDATA%\\AgentSandbox', persistAgentState: true, dataName: 'default' },
14
+ network: { blockPrivateRanges: true },
15
+ provisioning: { copyFromHost: true, fallbackToInstall: true, refresh: false, git: { enabled: true, access: 'full' }, terminal: { enabled: true } },
16
+ downloads: { requireChecksum: false },
17
+ toolchains: {
18
+ node: { version: 'host', extraVersions: [], corepack: true, volta: 'auto', globalPackages: [] },
19
+ python: { enabled: 'auto', version: '3', python2: true, pyenv: 'auto', tools: [] },
20
+ rust: { enabled: 'auto', toolchain: 'stable', host: 'auto', components: [], targets: [], crates: [], targetDir: 'separate' },
21
+ msvc: { enabled: 'auto', acceptLicense: false, msvcVersion: 'latest', sdkVersion: 'latest' },
22
+ cpp: { enabled: 'auto', flexBison: true },
23
+ dotnet: { enabled: 'auto', channels: ['LTS'], tools: [], workloads: [], frameworkTargets: ['net48', 'net472'], netfx35: false },
24
+ // Bigger downloads only for projects that use them.
25
+ go: { enabled: 'auto', version: 'stable', tools: [] },
26
+ java: { enabled: 'auto', version: 'lts', maven: true, gradle: true },
27
+ ruby: { enabled: 'auto', version: '3', gems: [] },
28
+ php: { enabled: 'auto', version: '8', composer: true },
29
+ deno: { enabled: 'auto' },
30
+ pwsh: { enabled: 'auto' },
31
+ cli: { gh: 'auto', zstd: false, openssl: 'auto' },
32
+ bun: { enabled: true },
33
+ uv: { enabled: true },
34
+ vcRuntime: { enabled: false },
35
+ mesa: { enabled: false, vulkan: false },
36
+ vscode: { enabled: true },
37
+ environment: {},
38
+ },
39
+ databases: {
40
+ postgres: { enabled: 'auto', version: 'latest', port: 5432 },
41
+ mysql: { enabled: 'auto', version: 'lts', port: 3306 },
42
+ mongodb: { enabled: 'auto', version: 'latest', port: 27017 },
43
+ redis: { enabled: 'auto', port: 6379 },
44
+ dynamodb: { enabled: 'auto', port: 8000, adminPort: 8001, admin: true },
45
+ sqlserver: { enabled: 'auto' },
46
+ },
47
+ attach: { enabled: true, reuseSession: true, auto: false, autoHide: false },
48
+ agentCommands: { enabled: false, agents: 'auto' },
49
+ secrets: { strip: true, allow: [], patterns: [], warnFiles: true },
50
+ personalization: { enabled: true },
51
+ claudeProfile: { enabled: true, hostDir: 'auto', include: ['settings.json', 'CLAUDE.md', 'commands', 'agents', 'skills', 'plugins'], globalStateFile: 'auto', copyCredentials: false, overwrite: true, syncHistory: true, syncClaudeMem: true },
52
+ harnesses: {
53
+ claude: { hostExecutable: 'claude.exe', hostDir: 'auto', npmPackage: '@anthropic-ai/claude-code@latest', npmBin: 'claude', arguments: [], environment: { DISABLE_AUTOUPDATER: '1' }, resumeArguments: ['--continue'] },
54
+ codex: { npmPackage: '@openai/codex@latest', npmBin: 'codex', arguments: [], environment: {}, resumeArguments: ['resume', '--last'] },
55
+ gemini: { npmPackage: '@google/gemini-cli@latest', npmBin: 'gemini', arguments: [], environment: {}, resumeArguments: ['--resume'] },
56
+ // Not tested by us; installed from each project's official npm / PyPI package.
57
+ opencode: { npmPackage: 'opencode-ai@latest', npmBin: 'opencode', arguments: [], environment: {}, resumeArguments: ['--continue'] },
58
+ qwen: { npmPackage: '@qwen-code/qwen-code@latest', npmBin: 'qwen', arguments: [], environment: {}, resumeArguments: ['--continue'] },
59
+ crush: { npmPackage: '@charmland/crush@latest', npmBin: 'crush', arguments: [], environment: {}, resumeArguments: ['--continue'] },
60
+ copilot: { npmPackage: '@github/copilot@latest', npmBin: 'copilot', arguments: [], environment: {}, resumeArguments: ['--continue'] },
61
+ kilo: { npmPackage: '@kilocode/cli@latest', npmBin: 'kilo', arguments: [], environment: {}, resumeArguments: ['--continue'] },
62
+ amp: { npmPackage: '@ampcode/cli@latest', npmBin: 'amp', arguments: [], environment: {} },
63
+ cline: { npmPackage: 'cline@latest', npmBin: 'cline', arguments: [], environment: {} },
64
+ continue: { npmPackage: '@continuedev/cli@latest', npmBin: 'cn', arguments: [], environment: {}, resumeArguments: ['--resume'] },
65
+ kimi: { npmPackage: '@moonshot-ai/kimi-code@latest', npmBin: 'kimi', arguments: [], environment: {}, resumeArguments: ['-c'] },
66
+ // DeepSeek has no official coding CLI; these two community agents are built for it.
67
+ reasonix: { npmPackage: 'reasonix@latest', npmBin: 'reasonix', arguments: [], environment: {} },
68
+ deepseek: { npmPackage: 'codewhale@latest', npmBin: 'codewhale', arguments: [], environment: {} },
69
+ aider: { uvPackage: 'aider-chat', uvBin: 'aider', arguments: [], environment: {}, resumeArguments: ['--restore-chat-history'] },
70
+ },
71
+ hooks: { failFast: false },
72
+ projects: { all: false, exclude: [], roots: [], askToAddRoot: true, declinedRoots: [], wsbShare: true },
73
+ };
74
+ /** Per-user folder for config and hooks. Survives reinstalling the npm package. */
75
+ export const userDir = () => process.env.AGENT_SANDBOX_HOME ?? path.join(homeDir(), '.agent-sandbox');
76
+ export const userConfigPath = () => path.join(userDir(), 'config.json');
77
+ /** Deep merge where arrays (and anything that is not a plain object) replace instead of merging element by element. */
78
+ export const mergeConfig = (base, extra) => _.mergeWith(_.cloneDeep(base), extra, (_target, source) => (Array.isArray(source) ? source : undefined));
79
+ /** Validates a full config; throws one readable error listing every problem. */
80
+ export const validateConfig = (config, source) => {
81
+ const parsed = ConfigSchema.safeParse(config);
82
+ if (!parsed.success)
83
+ fail(source + ' is not valid:\n - ' + describeIssues(parsed.error).join('\n - '));
84
+ return parsed.data;
85
+ };
86
+ /**
87
+ * Lookup order: --config, %AGENT_SANDBOX_CONFIG%, ~/.agent-sandbox/config.json, built-in defaults.
88
+ * Whatever file is found (JSON with comments) is merged over the defaults, so it only needs the keys you change.
89
+ */
90
+ export const loadConfig = (explicitPath) => {
91
+ const requested = explicitPath ?? process.env.AGENT_SANDBOX_CONFIG;
92
+ const full = path.resolve(requested ?? userConfigPath());
93
+ if (!fs.existsSync(full)) {
94
+ if (requested)
95
+ fail('Config file not found: ' + full, 'Check the --config path or AGENT_SANDBOX_CONFIG, or create one with: sandbox config init');
96
+ return { config: structuredClone(DEFAULTS), configPath: null, base: userDir() };
97
+ }
98
+ return { config: validateConfig(mergeConfig(DEFAULTS, readJsonc(full)), full), configPath: full, base: path.dirname(full) };
99
+ };
100
+ export const assertNoGuestOverlap = (mappings) => {
101
+ const normal = mappings.map((m) => m.guest.replace(/\\+$/, '').toLowerCase());
102
+ normal.forEach((a, i) => normal.slice(i + 1).forEach((b, j) => {
103
+ if (a === b || a.startsWith(b + '\\') || b.startsWith(a + '\\'))
104
+ fail('Two folders map to overlapping places in the sandbox: ' + mappings[i].guest + ' and ' + mappings[i + 1 + j].guest + '.', 'Give each mapping its own guest folder (one must not be inside the other).');
105
+ }));
106
+ };
@@ -0,0 +1,15 @@
1
+ export declare const DATABASES: readonly ["postgres", "mysql", "sqlserver", "mongodb", "redis", "dynamodb"];
2
+ export type Database = (typeof DATABASES)[number];
3
+ export interface ProjectFile {
4
+ path: string;
5
+ text: string;
6
+ }
7
+ /** Files worth reading, by name (lower case). Everything else is ignored, so a scan stays fast on big repos. */
8
+ export declare const INTERESTING_FILE: RegExp;
9
+ export interface Detection {
10
+ database: Database;
11
+ reasons: string[];
12
+ }
13
+ export declare const detectDatabases: (input: ProjectFile[], hostHas?: Database[] | (() => Database[])) => Detection[];
14
+ /** Windows service names of databases installed on this PC (from `sc query`), e.g. postgresql-x64-16, MySQL80. */
15
+ export declare const databasesFromServices: (serviceNames: string[]) => Database[];
@@ -0,0 +1,147 @@
1
+ // Which databases a project needs, worked out from its files: compose files, dependency manifests of every ecosystem,
2
+ // ORM schemas, connection strings and .env templates. Pure (file contents in, verdicts out), so the host can run it at
3
+ // launch and the tests can feed it fixtures.
4
+ export const DATABASES = ['postgres', 'mysql', 'sqlserver', 'mongodb', 'redis', 'dynamodb'];
5
+ /** Files worth reading, by name (lower case). Everything else is ignored, so a scan stays fast on big repos. */
6
+ export const INTERESTING_FILE = /^(package\.json|requirements[\w.-]{0,40}\.txt|pyproject\.toml|pipfile|setup\.py|setup\.cfg|gemfile|go\.mod|cargo\.toml|composer\.json|pom\.xml|build\.gradle(\.kts)?|[\w.-]+\.(cs|fs|vb)proj|directory\.packages\.props|packages\.config|schema\.prisma|(docker-)?compose[\w.-]{0,40}\.ya?ml|\.env(\.[\w.-]+)?|appsettings[\w.-]{0,40}\.json|database\.yml|application[\w.-]{0,40}\.(properties|ya?ml)|knexfile\.[jt]s|ormconfig\.(json|[jt]s)|drizzle\.config\.[jt]s|alembic\.ini|settings\.py|mix\.exs|deno\.json|serverless\.ya?ml|template\.ya?ml|samconfig\.toml|[\w.-]+\.tf|cdk\.json)$/i;
7
+ const manifests = /^(package\.json|deno\.json)$/i;
8
+ const python = /^(requirements[\w.-]{0,40}\.txt|pyproject\.toml|pipfile|setup\.py|setup\.cfg)$/i;
9
+ const dotnet = /\.(cs|fs|vb)proj$|^directory\.packages\.props$|^packages\.config$/i;
10
+ const jvm = /^(pom\.xml|build\.gradle(\.kts)?)$/i;
11
+ const compose = /^(docker-)?compose[\w.-]{0,40}\.ya?ml$/i;
12
+ const config = /^(\.env(\.[\w.-]+)?|appsettings[\w.-]{0,40}\.json|database\.yml|application[\w.-]{0,40}\.(properties|ya?ml)|knexfile\.[jt]s|ormconfig\.(json|[jt]s)|drizzle\.config\.[jt]s|alembic\.ini|settings\.py)$/i;
13
+ const infra = /^(serverless\.ya?ml|template\.ya?ml|[\w.-]+\.tf)$/i;
14
+ const dep = (names) => new RegExp('["\'\\s/=]?(' + names + ')["\'\\s@=<>~^:,\\]\\n]', 'i');
15
+ const RULES = {
16
+ postgres: [
17
+ [compose, /image:\s*["']?[\w./-]{0,80}(postgres|postgis|timescaledb|supabase\/postgres|pgvector)[\w.-]{0,40}(:|\s|["']|$)/im, 'a compose service runs Postgres'],
18
+ [manifests, dep('pg|postgres|pg-promise|@neondatabase/serverless|@vercel/postgres|slonik|postgres-js|@electric-sql/pglite'), 'a Postgres driver in package.json'],
19
+ [python, dep('psycopg2?(-binary)?|psycopg\\[[\\w,]+\\]|asyncpg|pg8000|django\\.db\\.backends\\.postgresql'), 'a Postgres driver in the Python dependencies'],
20
+ [/^gemfile$/i, /gem\s+["']pg["']/, 'the pg gem'],
21
+ [/^go\.mod$/i, /github\.com\/(jackc\/pgx|lib\/pq)/, 'a Postgres driver in go.mod'],
22
+ [/^cargo\.toml$/i, /tokio-postgres|postgres\s*=|sqlx[^\n]{0,200}postgres|diesel[^\n]{0,200}postgres|sea-orm[^\n]{0,200}postgres/i, 'a Postgres driver in Cargo.toml'],
23
+ [dotnet, /Npgsql/i, 'Npgsql in a .NET project'],
24
+ [jvm, /org\.postgresql|postgresql:postgresql|r2dbc-postgresql/i, 'the Postgres JDBC driver'],
25
+ [/^composer\.json$/i, /ext-pgsql|ext-pdo_pgsql/i, 'the PHP Postgres extension'],
26
+ [/^mix\.exs$/i, /:postgrex/, 'Postgrex'],
27
+ [/^schema\.prisma$/i, /provider\s*=\s*"(postgresql|postgres|cockroachdb)"/, 'Prisma uses PostgreSQL'],
28
+ [config, /postgres(ql)?(\+\w+)?:\/\/|DB_CONNECTION\s*=\s*pgsql|adapter:\s*postgres|\bHost=[^;\s]{1,200};\s*(Port=\d{1,5};\s*)?Database=|jdbc:postgresql:/i, 'a Postgres connection string'],
29
+ ],
30
+ mysql: [
31
+ [compose, /image:\s*["']?[\w./-]{0,80}(mysql|mariadb|percona)[\w.-]{0,40}(:|\s|["']|$)/im, 'a compose service runs MySQL / MariaDB'],
32
+ [manifests, dep('mysql2?|mariadb|@planetscale/database'), 'a MySQL driver in package.json'],
33
+ [python, dep('pymysql|mysqlclient|mysql-connector-python|aiomysql|asyncmy|mariadb'), 'a MySQL driver in the Python dependencies'],
34
+ [/^gemfile$/i, /gem\s+["'](mysql2|trilogy)["']/, 'a MySQL gem'],
35
+ [/^go\.mod$/i, /github\.com\/go-sql-driver\/mysql/, 'the MySQL driver in go.mod'],
36
+ [/^cargo\.toml$/i, /mysql_async|mysql\s*=|sqlx[^\n]{0,200}mysql|diesel[^\n]{0,200}mysql/i, 'a MySQL driver in Cargo.toml'],
37
+ [dotnet, /MySqlConnector|MySql\.Data|Pomelo\.EntityFrameworkCore\.MySql/i, 'a MySQL driver in a .NET project'],
38
+ [jvm, /mysql-connector|mariadb-java-client|com\.mysql/i, 'the MySQL JDBC driver'],
39
+ [/^composer\.json$/i, /ext-mysqli|ext-pdo_mysql/i, 'the PHP MySQL extension'],
40
+ [/^mix\.exs$/i, /:myxql/, 'MyXQL'],
41
+ [/^schema\.prisma$/i, /provider\s*=\s*"mysql"/, 'Prisma uses MySQL'],
42
+ [config, /(mysql|mariadb)(\+\w+)?:\/\/|DB_CONNECTION\s*=\s*(mysql|mariadb)|adapter:\s*(mysql2|trilogy)|jdbc:(mysql|mariadb):/i, 'a MySQL connection string'],
43
+ ],
44
+ sqlserver: [
45
+ [compose, /image:\s*["']?(mcr\.microsoft\.com\/(mssql|azure-sql-edge)|[\w./-]{0,80}mssql)[\w./:-]{0,80}/im, 'a compose service runs SQL Server'],
46
+ [manifests, dep('mssql|tedious|msnodesqlv8'), 'a SQL Server driver in package.json'],
47
+ [python, dep('pyodbc|pymssql|aioodbc|mssql-django'), 'a SQL Server driver in the Python dependencies'],
48
+ [/^go\.mod$/i, /(denisenkom|microsoft)\/go-mssqldb/, 'the SQL Server driver in go.mod'],
49
+ [/^cargo\.toml$/i, /tiberius|sqlx[^\n]{0,200}mssql/i, 'a SQL Server driver in Cargo.toml'],
50
+ [dotnet, /Microsoft\.Data\.SqlClient|System\.Data\.SqlClient|EntityFrameworkCore\.SqlServer|Dapper\.SqlBuilder|LocalDb/i, 'SQL Server in a .NET project'],
51
+ [jvm, /mssql-jdbc|com\.microsoft\.sqlserver/i, 'the SQL Server JDBC driver'],
52
+ [/^composer\.json$/i, /ext-sqlsrv|ext-pdo_sqlsrv/i, 'the PHP SQL Server extension'],
53
+ [/^schema\.prisma$/i, /provider\s*=\s*"sqlserver"/, 'Prisma uses SQL Server'],
54
+ [config, /\(localdb\)|mssql(\+\w+)?:\/\/|sqlserver:\/\/|DB_CONNECTION\s*=\s*sqlsrv|jdbc:sqlserver:|Initial Catalog=|Trusted_Connection=|TrustServerCertificate=|Integrated Security=/i, 'a SQL Server connection string'],
55
+ ],
56
+ mongodb: [
57
+ [compose, /image:\s*["']?[\w./-]{0,80}mongo(db)?[\w.-]{0,40}(:|\s|["']|$)/im, 'a compose service runs MongoDB'],
58
+ [manifests, dep('mongodb|mongoose|@typegoose/typegoose|mongodb-memory-server'), 'a MongoDB driver in package.json'],
59
+ [python, dep('pymongo|motor|mongoengine|beanie|djongo'), 'a MongoDB driver in the Python dependencies'],
60
+ [/^gemfile$/i, /gem\s+["'](mongoid|mongo)["']/, 'a MongoDB gem'],
61
+ [/^go\.mod$/i, /go\.mongodb\.org\/mongo-driver/, 'the MongoDB driver in go.mod'],
62
+ [/^cargo\.toml$/i, /^\s*mongodb\s*=/m, 'the MongoDB crate'],
63
+ [dotnet, /MongoDB\.Driver|MongoDB\.EntityFrameworkCore/i, 'the MongoDB driver in a .NET project'],
64
+ [jvm, /mongodb-driver|spring-boot-starter-data-mongodb/i, 'the MongoDB Java driver'],
65
+ [/^schema\.prisma$/i, /provider\s*=\s*"mongodb"/, 'Prisma uses MongoDB'],
66
+ [config, /mongodb(\+srv)?:\/\//i, 'a MongoDB connection string'],
67
+ ],
68
+ dynamodb: [
69
+ [compose, /image:\s*["']?(amazon\/dynamodb-local|[\w./-]{0,80}dynamodb-local|instructure\/dynamo-local-admin)[\w.:-]{0,40}/im, 'a compose service runs DynamoDB Local'],
70
+ [manifests, dep('@aws-sdk/client-dynamodb|@aws-sdk/lib-dynamodb|dynamoose|electrodb|dynamodb-toolbox|@typedorm/core|dynamodb-onetable'), 'a DynamoDB client in package.json'],
71
+ [python, dep('pynamodb|boto3-stubs\\[[^\\]]{0,80}dynamodb[^\\]]{0,80}\\]|types-aiobotocore-dynamodb|mypy-boto3-dynamodb|dynamorm'), 'a DynamoDB client in the Python dependencies'],
72
+ [/^gemfile$/i, /gem\s+["'](aws-sdk-dynamodb|dynamoid|aws-record)["']/, 'a DynamoDB gem'],
73
+ [/^go\.mod$/i, /aws-sdk-go-v2\/service\/dynamodb|github\.com\/guregu\/dynamo/, 'a DynamoDB client in go.mod'],
74
+ [/^cargo\.toml$/i, /^\s*(aws-sdk-dynamodb|serde_dynamo|modyne)\s*=/m, 'a DynamoDB crate'],
75
+ [dotnet, /AWSSDK\.DynamoDBv2/i, 'AWSSDK.DynamoDBv2 in a .NET project'],
76
+ [jvm, /software\.amazon\.awssdk[^\n]{0,200}dynamodb|aws-java-sdk-dynamodb|dynamodb-enhanced/i, 'the DynamoDB Java SDK'],
77
+ [infra, /AWS::DynamoDB::(Global)?Table|aws_dynamodb_table/, 'a DynamoDB table in the infrastructure code'],
78
+ [config, /AWS_ENDPOINT_URL_DYNAMODB|DYNAMO(DB)?_(ENDPOINT|URL|TABLE)|dynamodb\.[\w-]+\.amazonaws\.com|localhost:8000/i, 'DynamoDB settings in the config'],
79
+ ],
80
+ redis: [
81
+ [compose, /image:\s*["']?[\w./-]{0,80}(redis|valkey|keydb|dragonfly)[\w.-]{0,40}(:|\s|["']|$)/im, 'a compose service runs Redis'],
82
+ [manifests, dep('redis|ioredis|bullmq|bull|@upstash/redis|connect-redis|rate-limit-redis'), 'a Redis client in package.json'],
83
+ [python, dep('redis|aioredis|rq|celery\\[redis\\]|django-redis|arq'), 'a Redis client in the Python dependencies'],
84
+ [/^gemfile$/i, /gem\s+["'](redis|sidekiq|resque)["']/, 'a Redis gem'],
85
+ [/^go\.mod$/i, /github\.com\/(redis\/go-redis|go-redis\/redis|gomodule\/redigo)/, 'a Redis client in go.mod'],
86
+ [/^cargo\.toml$/i, /^\s*(redis|deadpool-redis|bb8-redis)\s*=/m, 'a Redis crate'],
87
+ [dotnet, /StackExchange\.Redis|Microsoft\.Extensions\.Caching\.StackExchangeRedis/i, 'StackExchange.Redis in a .NET project'],
88
+ [jvm, /jedis|lettuce-core|spring-boot-starter-data-redis|redisson/i, 'a Redis Java client'],
89
+ [/^composer\.json$/i, /predis\/predis|ext-redis/i, 'a PHP Redis client'],
90
+ [config, /rediss?:\/\/|REDIS_(URL|HOST)\s*=|CACHE_DRIVER\s*=\s*redis/i, 'a Redis connection string'],
91
+ ],
92
+ };
93
+ /** Libraries that talk to "a SQL database" without saying which: then this PC's own database decides (see below). */
94
+ const GENERIC_SQL = [
95
+ [manifests, dep('knex|sequelize|typeorm|drizzle-orm|kysely|@mikro-orm/core|objection|prisma'), 'an SQL ORM'],
96
+ [python, dep('sqlalchemy|django|peewee|tortoise-orm|sqlmodel|alembic'), 'an SQL ORM'],
97
+ [dotnet, /Microsoft\.EntityFrameworkCore(?!\.(Sqlite|InMemory))|Dapper/i, 'Entity Framework / Dapper'],
98
+ [/^gemfile$/i, /gem\s+["'](rails|activerecord|sequel)["']/, 'ActiveRecord'],
99
+ [jvm, /spring-boot-starter-data-jpa|hibernate-core|jooq/i, 'JPA / Hibernate'],
100
+ [/^go\.mod$/i, /gorm\.io\/gorm|entgo\.io\/ent|github\.com\/jmoiron\/sqlx/, 'an SQL ORM'],
101
+ [/^cargo\.toml$/i, /^\s*(sqlx|diesel|sea-orm)\s*=/m, 'an SQL ORM'],
102
+ [/^composer\.json$/i, /laravel\/framework|doctrine\/orm/i, 'Laravel / Doctrine'],
103
+ ];
104
+ const fileName = (p) => p.split(/[\\/]/).pop() ?? p;
105
+ const SQL = ['postgres', 'mysql', 'sqlserver'];
106
+ /**
107
+ * The databases a project needs, each with the evidence ("compose.yaml: a compose service runs Postgres"). `hostHas` is
108
+ * what this PC has installed: when the project only shows a database-agnostic ORM, the SQL database you use here is
109
+ * taken (Postgres first if several), so an ORM project still gets a database.
110
+ */
111
+ /** Longest line and file looked at: bounded work per file whatever a (sandbox-written) file contains. */
112
+ const MAX_LINE = 1000;
113
+ const MAX_TEXT = 256 * 1024;
114
+ const bounded = (text) => text.slice(0, MAX_TEXT).split('\n').filter((line) => line.length <= MAX_LINE).join('\n');
115
+ export const detectDatabases = (input, hostHas = []) => {
116
+ const files = input.map((f) => ({ path: f.path, text: bounded(f.text) }));
117
+ const found = new Map();
118
+ const add = (db, reason) => { const list = found.get(db) ?? []; if (!list.includes(reason))
119
+ list.push(reason); found.set(db, list); };
120
+ for (const file of files) {
121
+ const name = fileName(file.path);
122
+ for (const db of DATABASES)
123
+ for (const [test, pattern, reason] of RULES[db])
124
+ if (test.test(name) && pattern.test(file.text))
125
+ add(db, file.path + ': ' + reason);
126
+ }
127
+ if (!SQL.some((db) => found.has(db))) {
128
+ const orm = files.flatMap((file) => GENERIC_SQL.filter(([test, pattern]) => test.test(fileName(file.path)) && pattern.test(file.text)).map(([, , reason]) => file.path + ': ' + reason));
129
+ const host = orm.length ? (typeof hostHas === 'function' ? hostHas() : hostHas) : [];
130
+ const mine = SQL.find((db) => host.includes(db));
131
+ if (orm.length && mine)
132
+ add(mine, orm[0] + ', and this PC has ' + mine + ' installed');
133
+ }
134
+ return DATABASES.filter((db) => found.has(db)).map((database) => ({ database, reasons: found.get(database) }));
135
+ };
136
+ /** Windows service names of databases installed on this PC (from `sc query`), e.g. postgresql-x64-16, MySQL80. */
137
+ export const databasesFromServices = (serviceNames) => {
138
+ const has = (r) => serviceNames.some((s) => r.test(s));
139
+ return DATABASES.filter((db) => ({
140
+ postgres: has(/^postgresql/i),
141
+ mysql: has(/^(mysql|mariadb)/i),
142
+ sqlserver: has(/^(MSSQLSERVER|MSSQL\$|SQLServer)/i),
143
+ mongodb: has(/^mongodb/i),
144
+ redis: has(/^(redis|memurai)/i),
145
+ dynamodb: false,
146
+ })[db]);
147
+ };
@@ -0,0 +1,18 @@
1
+ import type { ProjectFile } from './detect-databases.js';
2
+ /** Scripts looked at: the workspace root and one folder down, at most this many, only their start. */
3
+ export declare const PWSH_MAX_SCRIPTS = 40;
4
+ export declare const PWSH_MAX_BYTES: number;
5
+ /** The first script that needs PowerShell 7 and why ("moh.ps1: #Requires -Version 7"), or null. */
6
+ export declare const usesPwsh: (files: readonly ProjectFile[]) => string | null;
7
+ /** *.ps1 / *.psm1 / *.psd1 in the workspace root and its direct sub-folders (root first), capped. Links are skipped. */
8
+ export declare const readPwshScripts: (root: string) => ProjectFile[];
9
+ /** PowerShell 7 installed on this PC (the MSI's folder, or a pwsh.exe on PATH other than a Store alias). */
10
+ export declare const pcHasPwsh: (env?: NodeJS.ProcessEnv, exists?: (p: string) => boolean) => boolean;
11
+ /**
12
+ * The decision for toolchains.pwsh.enabled: true/false are kept; "auto" is on when a script needs PowerShell 7, or, in
13
+ * a folder that is no project yet (`fresh`), when this PC has it.
14
+ */
15
+ export declare const decidePwsh: (setting: boolean | "auto", scripts: readonly ProjectFile[], fresh: boolean, pcHas: boolean) => {
16
+ on: boolean;
17
+ reason: string;
18
+ };
@@ -0,0 +1,111 @@
1
+ // Does a project need PowerShell 7 (pwsh)? Windows PowerShell 5.1 ships with Windows, so a plain *.ps1 says nothing;
2
+ // a script that asks for 7 (#Requires -Version 7 / -PSEdition Core) or tells you to run it with `pwsh` does.
3
+ // usesPwsh is pure; readPwshScripts reads a bounded sample of the workspace (no links followed, files and bytes capped).
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ /** Scripts looked at: the workspace root and one folder down, at most this many, only their start. */
7
+ export const PWSH_MAX_SCRIPTS = 40;
8
+ export const PWSH_MAX_BYTES = 64 * 1024;
9
+ const MAX_LINES = 400;
10
+ const MAX_LINE = 400;
11
+ const SKIP = /^(node_modules|\.git|vendor|target|bin|obj|dist|build|out|\.venv|venv|packages)$/i;
12
+ /** Why one line asks for PowerShell 7, or null. Plain string work per line (no regex that can backtrack). */
13
+ const pwshLine = (raw) => {
14
+ const line = raw.trimStart().slice(0, MAX_LINE).toLowerCase();
15
+ if (line.startsWith('#requires')) {
16
+ const words = line.slice('#requires'.length).split(/\s+/).filter(Boolean);
17
+ const after = (flag) => words[words.indexOf(flag) + 1];
18
+ const version = words.includes('-version') ? Number.parseInt(after('-version') ?? '', 10) : NaN;
19
+ if (version >= 7)
20
+ return '#Requires -Version ' + version;
21
+ if (words.includes('-psedition') && after('-psedition') === 'core')
22
+ return '#Requires -PSEdition Core';
23
+ return null;
24
+ }
25
+ // "Usage: pwsh scripts/build.ps1", "& pwsh -File x.ps1", "pwsh.exe -NoProfile ...": the word pwsh, then an option
26
+ // or a script (so prose like "works in pwsh too" does not count).
27
+ // At most a few occurrences per line, each looking at a short window: linear in the (capped) input.
28
+ for (let at = line.indexOf('pwsh'), n = 0; at !== -1 && n < 4; at = line.indexOf('pwsh', at + 4), n++) {
29
+ const end = at + (line.startsWith('pwsh.exe', at) ? 8 : 4);
30
+ if (at > 0 && /[\w.$-]/.test(line[at - 1]))
31
+ continue;
32
+ if (line[end] !== ' ' && line[end] !== '\t')
33
+ continue;
34
+ const next = line.slice(end, end + 80).trimStart().split(/\s/, 1)[0] ?? '';
35
+ if (next.startsWith('-') || next.includes('.ps1'))
36
+ return 'pwsh usage';
37
+ }
38
+ return null;
39
+ };
40
+ /** The first script that needs PowerShell 7 and why ("moh.ps1: #Requires -Version 7"), or null. */
41
+ export const usesPwsh = (files) => {
42
+ for (const file of files.slice(0, PWSH_MAX_SCRIPTS)) {
43
+ if (!/\.ps[dm]?1$/i.test(file.path))
44
+ continue;
45
+ const lines = file.text.slice(0, PWSH_MAX_BYTES).split(/\r?\n/, MAX_LINES);
46
+ for (const line of lines) {
47
+ const why = pwshLine(line);
48
+ if (why)
49
+ return file.path.replace(/\\/g, '/') + ': ' + why;
50
+ }
51
+ }
52
+ return null;
53
+ };
54
+ /** The start of a file, through one handle, only when that handle is a regular file. */
55
+ const readStart = (file) => {
56
+ let fd = null;
57
+ try {
58
+ fd = fs.openSync(file, 'r');
59
+ const stat = fs.fstatSync(fd);
60
+ if (!stat.isFile())
61
+ return null;
62
+ const buffer = Buffer.alloc(Math.min(stat.size, PWSH_MAX_BYTES));
63
+ const read = fs.readSync(fd, buffer, 0, buffer.length, 0);
64
+ return buffer.subarray(0, read).toString('utf8');
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ finally {
70
+ if (fd !== null)
71
+ fs.closeSync(fd);
72
+ }
73
+ };
74
+ /** *.ps1 / *.psm1 / *.psd1 in the workspace root and its direct sub-folders (root first), capped. Links are skipped. */
75
+ export const readPwshScripts = (root) => {
76
+ const list = (dir) => { try {
77
+ return fs.readdirSync(dir, { withFileTypes: true }).slice(0, 2000);
78
+ }
79
+ catch {
80
+ return [];
81
+ } };
82
+ const isScript = (d) => d.isFile() && /\.ps[dm]?1$/i.test(d.name);
83
+ const top = list(root);
84
+ const names = [
85
+ ...top.filter(isScript).map((d) => d.name),
86
+ ...top.filter((d) => d.isDirectory() && !d.name.startsWith('.') && !SKIP.test(d.name)).slice(0, 200)
87
+ .flatMap((d) => list(path.join(root, d.name)).filter(isScript).map((f) => d.name + '/' + f.name)),
88
+ ].slice(0, PWSH_MAX_SCRIPTS);
89
+ return names.flatMap((name) => { const text = readStart(path.join(root, name)); return text === null ? [] : [{ path: name, text }]; });
90
+ };
91
+ /** PowerShell 7 installed on this PC (the MSI's folder, or a pwsh.exe on PATH other than a Store alias). */
92
+ export const pcHasPwsh = (env = process.env, exists = fs.existsSync) => {
93
+ const programFiles = env.ProgramFiles ?? 'C:\\Program Files';
94
+ if (exists(path.win32.join(programFiles, 'PowerShell', '7', 'pwsh.exe')))
95
+ return true;
96
+ return (env.PATH ?? env.Path ?? '').split(';').some((d) => d && !/WindowsApps/i.test(d) && exists(path.win32.join(d, 'pwsh.exe')));
97
+ };
98
+ /**
99
+ * The decision for toolchains.pwsh.enabled: true/false are kept; "auto" is on when a script needs PowerShell 7, or, in
100
+ * a folder that is no project yet (`fresh`), when this PC has it.
101
+ */
102
+ export const decidePwsh = (setting, scripts, fresh, pcHas) => {
103
+ if (setting !== 'auto')
104
+ return { on: setting, reason: setting ? 'enabled in config' : 'disabled in config' };
105
+ const why = usesPwsh(scripts);
106
+ if (why)
107
+ return { on: true, reason: why };
108
+ if (fresh && pcHas)
109
+ return { on: true, reason: 'installed on this PC (new folder)' };
110
+ return { on: false, reason: 'no script needs PowerShell 7' };
111
+ };
@@ -0,0 +1,30 @@
1
+ import type { Toolchains } from './types.js';
2
+ /** Files that show a project uses a language (looked for in the workspace and one folder down). */
3
+ export declare const MARKERS: {
4
+ readonly python: readonly ["pyproject.toml", "requirements.txt", "setup.py", "setup.cfg", "Pipfile", "uv.lock", "poetry.lock", ".python-version", "*.py", "*.ipynb"];
5
+ readonly rust: readonly ["Cargo.toml", "rust-toolchain", "rust-toolchain.toml"];
6
+ readonly msvc: readonly ["*.vcxproj", "CMakePresets.json", "CMakeUserPresets.json"];
7
+ readonly cpp: readonly ["CMakeLists.txt", "Makefile", "meson.build", "premake5.lua", "Cargo.toml", "*.vcxproj", "*.c", "*.cpp", "*.cc", "*.h", "*.hpp"];
8
+ readonly dotnet: readonly ["*.sln", "*.slnx", "*.csproj", "*.fsproj", "*.vbproj", "global.json", "*.cs"];
9
+ readonly go: readonly ["go.mod", "go.work", "*.go"];
10
+ readonly java: readonly ["pom.xml", "build.gradle", "build.gradle.kts", "settings.gradle", "settings.gradle.kts", "mvnw", "gradlew", ".java-version", ".sdkmanrc", "*.java"];
11
+ readonly ruby: readonly ["Gemfile", "*.gemspec", ".ruby-version", "*.rb"];
12
+ readonly php: readonly ["composer.json", "artisan", ".php-version", "*.php"];
13
+ readonly deno: readonly ["deno.json", "deno.jsonc", "deno.lock"];
14
+ readonly pwsh: readonly [];
15
+ };
16
+ export type AutoToolchain = keyof typeof MARKERS;
17
+ export declare const AUTO_TOOLCHAINS: AutoToolchain[];
18
+ export interface ToolchainDecision {
19
+ on: boolean;
20
+ reason: string;
21
+ }
22
+ /**
23
+ * The decision per toolchain. true/false are kept; "auto" is on when the project has one of its marker files, or, in
24
+ * a folder that is no project yet, when this PC has the language installed. Rust needs a linker (MSVC or C/C++).
25
+ * hints: reasons found by reading files (a script that calls vcvars/vswhere) or about this PC ("builds Rust with MSVC"),
26
+ * which turn an "auto" toolchain on like a marker file does.
27
+ */
28
+ export declare const decideToolchains: (settings: Toolchains, entries: string[], pcHas: AutoToolchain[], hints?: Partial<Record<AutoToolchain, string>>) => Record<AutoToolchain, ToolchainDecision>;
29
+ /** The settings with every "auto" replaced by the decision (what the sandbox receives). */
30
+ export declare const resolveToolchains: (settings: Toolchains, decisions: Record<AutoToolchain, ToolchainDecision>) => Toolchains;