windows-development-sandbox 1.0.5 → 1.4.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 (453) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -8
  3. package/config.example.json +55 -5
  4. package/dist/api.js +2 -1
  5. package/dist/cli/args.d.ts +23 -0
  6. package/dist/cli/args.js +38 -4
  7. package/dist/cli/colors.d.ts +24 -0
  8. package/dist/cli/colors.js +42 -0
  9. package/dist/cli/commands/accounts.js +2 -2
  10. package/dist/cli/commands/agent-commands.d.ts +6 -0
  11. package/dist/cli/commands/agent-commands.js +61 -0
  12. package/dist/cli/commands/context.d.ts +2 -0
  13. package/dist/cli/commands/context.js +5 -1
  14. package/dist/cli/commands/data/clean.d.ts +15 -0
  15. package/dist/cli/commands/data/clean.js +106 -0
  16. package/dist/cli/commands/data/collect.d.ts +11 -0
  17. package/dist/cli/commands/data/collect.js +54 -0
  18. package/dist/cli/commands/data/index.d.ts +4 -0
  19. package/dist/cli/commands/data/index.js +45 -0
  20. package/dist/cli/commands/data/remove.d.ts +2 -0
  21. package/dist/cli/commands/data/remove.js +30 -0
  22. package/dist/cli/commands/index.d.ts +6 -4
  23. package/dist/cli/commands/index.js +6 -4
  24. package/dist/cli/commands/launch.d.ts +26 -2
  25. package/dist/cli/commands/launch.js +256 -42
  26. package/dist/cli/commands/maintenance.d.ts +2 -0
  27. package/dist/cli/commands/maintenance.js +67 -5
  28. package/dist/cli/commands/project.d.ts +29 -0
  29. package/dist/cli/commands/project.js +63 -0
  30. package/dist/cli/commands/projects.d.ts +14 -0
  31. package/dist/cli/commands/projects.js +146 -0
  32. package/dist/cli/commands/repair/checks.d.ts +2 -0
  33. package/dist/cli/commands/{repair.js → repair/checks.js} +19 -181
  34. package/dist/cli/commands/{repair.d.ts → repair/finders.d.ts} +0 -29
  35. package/dist/cli/commands/repair/finders.js +108 -0
  36. package/dist/cli/commands/repair/index.d.ts +12 -0
  37. package/dist/cli/commands/repair/index.js +61 -0
  38. package/dist/cli/commands/repair/types.d.ts +26 -0
  39. package/dist/cli/commands/repair/types.js +3 -0
  40. package/dist/cli/commands/restart.d.ts +6 -0
  41. package/dist/cli/commands/restart.js +85 -0
  42. package/dist/cli/commands/sessions.d.ts +2 -1
  43. package/dist/cli/commands/sessions.js +189 -45
  44. package/dist/cli/commands/setup/checks.d.ts +13 -0
  45. package/dist/cli/commands/setup/checks.js +71 -0
  46. package/dist/cli/commands/{setup.d.ts → setup/facts.d.ts} +1 -15
  47. package/dist/cli/commands/setup/facts.js +60 -0
  48. package/dist/cli/commands/setup/index.d.ts +2 -0
  49. package/dist/cli/commands/setup/index.js +43 -0
  50. package/dist/cli/commands/user-config.d.ts +8 -0
  51. package/dist/cli/commands/user-config.js +41 -0
  52. package/dist/cli/history.d.ts +11 -0
  53. package/dist/cli/history.js +21 -0
  54. package/dist/cli/index.d.ts +7 -1
  55. package/dist/cli/index.js +42 -15
  56. package/dist/cli/manifest.d.ts +8 -0
  57. package/dist/cli/manifest.js +40 -15
  58. package/dist/cli/menu/apps.d.ts +21 -0
  59. package/dist/cli/menu/apps.js +122 -0
  60. package/dist/cli/menu/command-form.d.ts +28 -0
  61. package/dist/cli/menu/command-form.js +219 -0
  62. package/dist/cli/menu/index.d.ts +26 -0
  63. package/dist/cli/menu/index.js +180 -0
  64. package/dist/cli/menu/settings/categories.d.ts +9 -0
  65. package/dist/cli/menu/settings/categories.js +28 -0
  66. package/dist/cli/menu/settings/config-file.d.ts +40 -0
  67. package/dist/cli/menu/settings/config-file.js +71 -0
  68. package/dist/cli/menu/settings/editors.d.ts +30 -0
  69. package/dist/cli/menu/settings/editors.js +305 -0
  70. package/dist/cli/menu/settings/index.d.ts +32 -0
  71. package/dist/cli/menu/settings/index.js +136 -0
  72. package/dist/cli/menu/settings/schema-node.d.ts +62 -0
  73. package/dist/cli/menu/settings/schema-node.js +104 -0
  74. package/dist/cli/menu/several.d.ts +20 -0
  75. package/dist/cli/menu/several.js +102 -0
  76. package/dist/cli/progress.d.ts +9 -0
  77. package/dist/cli/progress.js +49 -0
  78. package/dist/cli/tui/app.d.ts +39 -0
  79. package/dist/cli/tui/app.js +52 -0
  80. package/dist/cli/tui/dialogs.d.ts +57 -0
  81. package/dist/cli/tui/dialogs.js +162 -0
  82. package/dist/cli/tui/frame.d.ts +18 -0
  83. package/dist/cli/tui/frame.js +27 -0
  84. package/dist/cli/tui/index.d.ts +7 -0
  85. package/dist/cli/tui/index.js +8 -0
  86. package/dist/cli/tui/list-screen.d.ts +101 -0
  87. package/dist/cli/tui/list-screen.js +299 -0
  88. package/dist/cli/tui/terminal.d.ts +37 -0
  89. package/dist/cli/tui/terminal.js +89 -0
  90. package/dist/cli/tui/text.d.ts +20 -0
  91. package/dist/cli/tui/text.js +105 -0
  92. package/dist/cli/tui/theme.d.ts +45 -0
  93. package/dist/cli/tui/theme.js +30 -0
  94. package/dist/cli/validate.d.ts +17 -0
  95. package/dist/cli/validate.js +89 -0
  96. package/dist/core/config.js +12 -6
  97. package/dist/core/disk.d.ts +16 -0
  98. package/dist/core/disk.js +55 -0
  99. package/dist/core/local-config.d.ts +23 -0
  100. package/dist/core/local-config.js +79 -7
  101. package/dist/core/project-policy.d.ts +15 -0
  102. package/dist/core/project-policy.js +35 -0
  103. package/dist/core/prompt.d.ts +4 -0
  104. package/dist/core/prompt.js +15 -0
  105. package/dist/core/safe-paths.d.ts +4 -0
  106. package/dist/core/safe-paths.js +37 -0
  107. package/dist/core/schema/apps.d.ts +40 -0
  108. package/dist/core/schema/apps.js +27 -0
  109. package/dist/core/schema/common.d.ts +17 -0
  110. package/dist/core/schema/common.js +15 -0
  111. package/dist/core/schema/config.d.ts +659 -0
  112. package/dist/core/schema/config.js +75 -0
  113. package/dist/core/schema/databases.d.ts +33 -0
  114. package/dist/core/schema/databases.js +35 -0
  115. package/dist/core/schema/harness.d.ts +12 -0
  116. package/dist/core/schema/harness.js +17 -0
  117. package/dist/core/schema/json-schema.d.ts +5 -0
  118. package/dist/core/schema/json-schema.js +25 -0
  119. package/dist/core/schema/profile.d.ts +32 -0
  120. package/dist/core/schema/profile.js +31 -0
  121. package/dist/core/schema/projects.d.ts +9 -0
  122. package/dist/core/schema/projects.js +11 -0
  123. package/dist/core/schema/sandbox.d.ts +78 -0
  124. package/dist/core/schema/sandbox.js +64 -0
  125. package/dist/core/schema/toolchains.d.ts +96 -0
  126. package/dist/core/schema/toolchains.js +88 -0
  127. package/dist/core/schema.d.ts +6 -604
  128. package/dist/core/schema.js +8 -264
  129. package/dist/core/types.d.ts +35 -1
  130. package/dist/core/util.d.ts +9 -0
  131. package/dist/core/util.js +14 -3
  132. package/dist/core/workspace.d.ts +0 -5
  133. package/dist/core/workspace.js +33 -50
  134. package/dist/guest/apps/index.d.ts +10 -0
  135. package/dist/guest/apps/index.js +206 -0
  136. package/dist/guest/apps/resolvers.d.ts +8 -0
  137. package/dist/guest/apps/resolvers.js +90 -0
  138. package/dist/guest/audit-parse.d.ts +7 -0
  139. package/dist/guest/audit-parse.js +24 -0
  140. package/dist/guest/audit.d.ts +4 -0
  141. package/dist/guest/audit.js +47 -0
  142. package/dist/guest/boot-env.d.ts +4 -0
  143. package/dist/guest/boot-env.js +25 -0
  144. package/dist/guest/cmdline.d.ts +12 -0
  145. package/dist/guest/cmdline.js +23 -0
  146. package/dist/guest/daemon/exec.d.ts +5 -0
  147. package/dist/guest/daemon/exec.js +32 -0
  148. package/dist/guest/daemon/project.d.ts +14 -0
  149. package/dist/guest/daemon/project.js +132 -0
  150. package/dist/guest/daemon/relays.d.ts +1 -0
  151. package/dist/guest/daemon/relays.js +18 -0
  152. package/dist/guest/daemon/session.d.ts +13 -0
  153. package/dist/guest/daemon/session.js +139 -0
  154. package/dist/guest/daemon/shutdown.d.ts +1 -0
  155. package/dist/guest/daemon/shutdown.js +21 -0
  156. package/dist/guest/daemon/state.d.ts +17 -0
  157. package/dist/guest/daemon/state.js +31 -0
  158. package/dist/guest/daemon.js +12 -141
  159. package/dist/guest/db.js +18 -3
  160. package/dist/guest/env.d.ts +3 -0
  161. package/dist/guest/env.js +7 -3
  162. package/dist/guest/guide.d.ts +6 -2
  163. package/dist/guest/guide.js +5 -4
  164. package/dist/guest/helpers.d.ts +3 -0
  165. package/dist/guest/helpers.js +26 -0
  166. package/dist/guest/main.js +31 -8
  167. package/dist/guest/netproxy.d.ts +1 -0
  168. package/dist/guest/netproxy.js +100 -0
  169. package/dist/guest/ports.d.ts +6 -0
  170. package/dist/guest/ports.js +22 -0
  171. package/dist/guest/project-context.d.ts +7 -0
  172. package/dist/guest/project-context.js +10 -0
  173. package/dist/guest/project-env.d.ts +20 -0
  174. package/dist/guest/project-env.js +20 -0
  175. package/dist/guest/project-status.d.ts +5 -0
  176. package/dist/guest/project-status.js +17 -0
  177. package/dist/guest/ptyhost.d.ts +0 -18
  178. package/dist/guest/ptyhost.js +17 -65
  179. package/dist/guest/setup/agents.d.ts +5 -2
  180. package/dist/guest/setup/agents.js +22 -8
  181. package/dist/guest/setup/claude.d.ts +0 -4
  182. package/dist/guest/setup/claude.js +59 -5
  183. package/dist/guest/setup/environment.d.ts +13 -3
  184. package/dist/guest/setup/environment.js +14 -10
  185. package/dist/guest/setup/hooks.d.ts +9 -1
  186. package/dist/guest/setup/hooks.js +28 -14
  187. package/dist/guest/setup/network.d.ts +9 -0
  188. package/dist/guest/setup/network.js +97 -4
  189. package/dist/guest/setup/user.js +4 -0
  190. package/dist/guest/toolchains/catalogue.d.ts +4 -0
  191. package/dist/guest/toolchains/catalogue.js +2 -2
  192. package/dist/guest/toolchains/cli.js +25 -17
  193. package/dist/guest/toolchains/common.d.ts +18 -1
  194. package/dist/guest/toolchains/common.js +34 -11
  195. package/dist/guest/toolchains/databases/dynamodb.d.ts +8 -0
  196. package/dist/guest/toolchains/databases/dynamodb.js +52 -0
  197. package/dist/guest/toolchains/{databases.d.ts → databases/index.d.ts} +2 -3
  198. package/dist/guest/toolchains/databases/index.js +62 -0
  199. package/dist/guest/toolchains/databases/mongodb.d.ts +3 -0
  200. package/dist/guest/toolchains/databases/mongodb.js +31 -0
  201. package/dist/guest/toolchains/databases/mysql.d.ts +3 -0
  202. package/dist/guest/toolchains/databases/mysql.js +38 -0
  203. package/dist/guest/toolchains/databases/postgres.d.ts +5 -0
  204. package/dist/guest/toolchains/databases/postgres.js +38 -0
  205. package/dist/guest/toolchains/databases/redis.d.ts +3 -0
  206. package/dist/guest/toolchains/databases/redis.js +16 -0
  207. package/dist/guest/toolchains/databases/server.d.ts +14 -0
  208. package/dist/guest/toolchains/databases/server.js +52 -0
  209. package/dist/guest/toolchains/git.js +25 -16
  210. package/dist/guest/toolchains/go.js +1 -1
  211. package/dist/guest/toolchains/index.d.ts +13 -9
  212. package/dist/guest/toolchains/index.js +40 -82
  213. package/dist/guest/toolchains/java.js +5 -5
  214. package/dist/guest/toolchains/leftovers.d.ts +2 -0
  215. package/dist/guest/toolchains/leftovers.js +26 -0
  216. package/dist/guest/toolchains/managers.js +12 -10
  217. package/dist/guest/toolchains/{binstall.js → native/binstall.js} +6 -9
  218. package/dist/guest/toolchains/native/cpp.d.ts +4 -0
  219. package/dist/guest/toolchains/native/cpp.js +38 -0
  220. package/dist/guest/toolchains/native/dotnet.d.ts +4 -0
  221. package/dist/guest/toolchains/native/dotnet.js +103 -0
  222. package/dist/guest/toolchains/native/mesa.d.ts +7 -0
  223. package/dist/guest/toolchains/native/mesa.js +56 -0
  224. package/dist/guest/toolchains/native/msvc/environment.d.ts +16 -0
  225. package/dist/guest/toolchains/native/msvc/environment.js +57 -0
  226. package/dist/guest/toolchains/native/msvc/index.d.ts +6 -0
  227. package/dist/guest/toolchains/native/msvc/index.js +48 -0
  228. package/dist/guest/toolchains/native/msvc/packages.d.ts +6 -0
  229. package/dist/guest/toolchains/native/msvc/packages.js +156 -0
  230. package/dist/guest/toolchains/native/msvc/tree.d.ts +15 -0
  231. package/dist/guest/toolchains/native/msvc/tree.js +21 -0
  232. package/dist/guest/toolchains/native/rust.d.ts +3 -0
  233. package/dist/guest/toolchains/native/rust.js +45 -0
  234. package/dist/guest/toolchains/node.js +26 -6
  235. package/dist/guest/toolchains/plan.d.ts +24 -0
  236. package/dist/guest/toolchains/plan.js +140 -0
  237. package/dist/guest/toolchains/pwsh.js +1 -1
  238. package/dist/guest/toolchains/python.js +43 -12
  239. package/dist/guest/toolchains/runtimes.d.ts +2 -0
  240. package/dist/guest/toolchains/runtimes.js +6 -8
  241. package/dist/guest/toolchains/scripting/php.d.ts +3 -0
  242. package/dist/guest/toolchains/scripting/php.js +71 -0
  243. package/dist/guest/toolchains/scripting/ruby.d.ts +3 -0
  244. package/dist/guest/toolchains/scripting/ruby.js +47 -0
  245. package/dist/guest/toolchains/scripting/vcruntime.d.ts +7 -0
  246. package/dist/guest/toolchains/scripting/vcruntime.js +45 -0
  247. package/dist/guest/toolchains/vscode-profile.d.ts +30 -0
  248. package/dist/guest/toolchains/vscode-profile.js +69 -0
  249. package/dist/guest/toolchains/vscode.d.ts +17 -0
  250. package/dist/guest/toolchains/vscode.js +87 -1
  251. package/dist/guest/view.js +21 -1
  252. package/dist/host/accounts.js +14 -5
  253. package/dist/host/agent-commands.d.ts +25 -0
  254. package/dist/host/agent-commands.js +145 -0
  255. package/dist/host/attach.d.ts +17 -0
  256. package/dist/host/attach.js +70 -0
  257. package/dist/host/audit/collect.d.ts +34 -0
  258. package/dist/host/audit/collect.js +126 -0
  259. package/dist/host/audit/log.d.ts +46 -0
  260. package/dist/host/audit/log.js +143 -0
  261. package/dist/host/channel.d.ts +23 -22
  262. package/dist/host/channel.js +66 -84
  263. package/dist/host/claude-profile.js +7 -3
  264. package/dist/host/cleanup.js +2 -11
  265. package/dist/host/database-plan.d.ts +12 -0
  266. package/dist/host/database-plan.js +52 -0
  267. package/dist/host/generate.d.ts +10 -12
  268. package/dist/host/generate.js +58 -135
  269. package/dist/host/join.d.ts +28 -0
  270. package/dist/host/join.js +76 -0
  271. package/dist/host/launch/mappings.d.ts +3 -0
  272. package/dist/host/launch/mappings.js +54 -0
  273. package/dist/host/launch/projects.d.ts +15 -0
  274. package/dist/host/launch/projects.js +56 -0
  275. package/dist/host/launch/stage.d.ts +11 -0
  276. package/dist/host/launch/stage.js +66 -0
  277. package/dist/host/launch/wsb.d.ts +10 -0
  278. package/dist/host/launch/wsb.js +34 -0
  279. package/dist/host/motw.d.ts +17 -0
  280. package/dist/host/motw.js +74 -0
  281. package/dist/host/pc-scan.d.ts +6 -0
  282. package/dist/host/pc-scan.js +37 -0
  283. package/dist/host/platform.d.ts +2 -0
  284. package/dist/host/platform.js +16 -1
  285. package/dist/host/port-forward.d.ts +8 -0
  286. package/dist/host/port-forward.js +37 -0
  287. package/dist/host/project-scan.d.ts +1 -17
  288. package/dist/host/project-scan.js +2 -86
  289. package/dist/host/projects.d.ts +100 -0
  290. package/dist/host/projects.js +147 -0
  291. package/dist/host/repo-guard.d.ts +25 -5
  292. package/dist/host/repo-guard.js +242 -23
  293. package/dist/host/stops.d.ts +67 -0
  294. package/dist/host/stops.js +126 -0
  295. package/dist/host/terminal.d.ts +8 -0
  296. package/dist/host/terminal.js +48 -1
  297. package/dist/host/test-guard.d.ts +6 -0
  298. package/dist/host/test-guard.js +15 -0
  299. package/dist/host/window.js +7 -3
  300. package/dist/host/workspace-view/index.d.ts +20 -0
  301. package/dist/host/workspace-view/index.js +53 -0
  302. package/dist/host/workspace-view/rules.d.ts +26 -0
  303. package/dist/host/workspace-view/rules.js +93 -0
  304. package/dist/host/workspace-view/view.d.ts +50 -0
  305. package/dist/host/workspace-view/view.js +281 -0
  306. package/dist/host/wsb.d.ts +37 -0
  307. package/dist/host/wsb.js +101 -0
  308. package/dist/runtime/daemon.js +11791 -2821
  309. package/dist/runtime/db.js +6585 -466
  310. package/dist/runtime/main.js +10238 -1724
  311. package/dist/runtime/netproxy.js +25936 -0
  312. package/dist/runtime/view.js +6183 -59
  313. package/dist/selftest/accounts.test.d.ts +2 -0
  314. package/dist/selftest/accounts.test.js +44 -0
  315. package/dist/selftest/agent-commands.test.d.ts +2 -0
  316. package/dist/selftest/agent-commands.test.js +47 -0
  317. package/dist/selftest/audit.test.d.ts +2 -0
  318. package/dist/selftest/audit.test.js +57 -0
  319. package/dist/selftest/channel.test.d.ts +2 -0
  320. package/dist/selftest/channel.test.js +44 -0
  321. package/dist/selftest/cli.test.d.ts +2 -2
  322. package/dist/selftest/cli.test.js +145 -27
  323. package/dist/selftest/cmdline.test.d.ts +2 -0
  324. package/dist/selftest/cmdline.test.js +45 -0
  325. package/dist/selftest/config.test.d.ts +2 -3
  326. package/dist/selftest/config.test.js +36 -72
  327. package/dist/selftest/data.test.d.ts +2 -2
  328. package/dist/selftest/data.test.js +77 -70
  329. package/dist/selftest/detect.test.d.ts +2 -2
  330. package/dist/selftest/detect.test.js +54 -38
  331. package/dist/selftest/fixtures.d.ts +89 -4
  332. package/dist/selftest/fixtures.js +43 -24
  333. package/dist/selftest/generate.test.d.ts +2 -0
  334. package/dist/selftest/generate.test.js +68 -0
  335. package/dist/selftest/git-access.test.d.ts +2 -0
  336. package/dist/selftest/git-access.test.js +26 -0
  337. package/dist/selftest/guest-boot.test.d.ts +2 -0
  338. package/dist/selftest/guest-boot.test.js +76 -0
  339. package/dist/selftest/harness.d.ts +44 -7
  340. package/dist/selftest/harness.js +62 -21
  341. package/dist/selftest/host-sim.test.d.ts +2 -0
  342. package/dist/selftest/host-sim.test.js +93 -0
  343. package/dist/selftest/hostile-input.test.d.ts +2 -0
  344. package/dist/selftest/hostile-input.test.js +54 -0
  345. package/dist/selftest/index.d.ts +8 -1
  346. package/dist/selftest/index.js +137 -35
  347. package/dist/selftest/links.test.d.ts +2 -0
  348. package/dist/selftest/links.test.js +50 -0
  349. package/dist/selftest/live-daemon.test.d.ts +2 -0
  350. package/dist/selftest/live-daemon.test.js +91 -0
  351. package/dist/selftest/live-git.test.d.ts +2 -0
  352. package/dist/selftest/live-git.test.js +60 -0
  353. package/dist/selftest/live-network.test.d.ts +2 -0
  354. package/dist/selftest/live-network.test.js +63 -0
  355. package/dist/selftest/live-projects.test.d.ts +2 -0
  356. package/dist/selftest/live-projects.test.js +127 -0
  357. package/dist/selftest/live.d.ts +65 -0
  358. package/dist/selftest/live.js +109 -0
  359. package/dist/selftest/local-config.test.d.ts +2 -0
  360. package/dist/selftest/local-config.test.js +120 -0
  361. package/dist/selftest/mirror.test.d.ts +2 -3
  362. package/dist/selftest/mirror.test.js +92 -65
  363. package/dist/selftest/network.test.d.ts +2 -0
  364. package/dist/selftest/network.test.js +40 -0
  365. package/dist/selftest/personalization.test.d.ts +2 -0
  366. package/dist/selftest/personalization.test.js +53 -0
  367. package/dist/selftest/projects.test.d.ts +2 -0
  368. package/dist/selftest/projects.test.js +254 -0
  369. package/dist/selftest/repair.test.d.ts +2 -0
  370. package/dist/selftest/repair.test.js +42 -0
  371. package/dist/selftest/repo-guard.test.d.ts +2 -0
  372. package/dist/selftest/repo-guard.test.js +121 -0
  373. package/dist/selftest/secrets.test.d.ts +2 -0
  374. package/dist/selftest/secrets.test.js +71 -0
  375. package/dist/selftest/setup.test.d.ts +2 -2
  376. package/dist/selftest/setup.test.js +45 -22
  377. package/dist/selftest/suite.d.ts +13 -0
  378. package/dist/selftest/suite.js +1 -0
  379. package/dist/selftest/sync.test.d.ts +2 -3
  380. package/dist/selftest/sync.test.js +130 -78
  381. package/dist/selftest/test-guard.test.d.ts +2 -0
  382. package/dist/selftest/test-guard.test.js +49 -0
  383. package/dist/selftest/toolchains.test.d.ts +2 -0
  384. package/dist/selftest/toolchains.test.js +133 -0
  385. package/dist/selftest/workspace-view.test.d.ts +2 -0
  386. package/dist/selftest/workspace-view.test.js +89 -0
  387. package/dist/selftest/workspace.test.d.ts +2 -0
  388. package/dist/selftest/workspace.test.js +53 -0
  389. package/dist/shared/apps.d.ts +49 -0
  390. package/dist/shared/apps.js +114 -0
  391. package/dist/shared/download.d.ts +3 -1
  392. package/dist/shared/download.js +19 -4
  393. package/dist/shared/netpolicy.d.ts +27 -0
  394. package/dist/shared/netpolicy.js +51 -0
  395. package/dist/shared/paths.d.ts +5 -0
  396. package/dist/shared/paths.js +6 -0
  397. package/dist/shared/projects.d.ts +53 -0
  398. package/dist/shared/projects.js +67 -0
  399. package/dist/shared/pty-client.d.ts +9 -4
  400. package/dist/shared/pty-client.js +139 -17
  401. package/dist/shared/rundir.d.ts +12 -1
  402. package/dist/shared/rundir.js +14 -4
  403. package/dist/shared/safe-remove.js +11 -0
  404. package/dist/shared/schema.d.ts +453 -0
  405. package/dist/shared/schema.js +43 -2
  406. package/dist/shared/system.d.ts +1 -0
  407. package/dist/shared/system.js +1 -0
  408. package/dist/shared/test-guard.d.ts +4 -0
  409. package/dist/shared/test-guard.js +37 -0
  410. package/dist/sync/claude-mem.js +6 -3
  411. package/dist/sync/history.d.ts +29 -12
  412. package/dist/sync/history.js +72 -25
  413. package/dist/sync/watcher.d.ts +8 -0
  414. package/dist/sync/watcher.js +99 -8
  415. package/package.json +7 -6
  416. package/sandbox/bootstrap.ps1 +258 -258
  417. package/sandbox/cargoshim.cs +56 -0
  418. package/sandbox/cpucap.cs +33 -0
  419. package/sandbox/cpucap.ps1 +20 -0
  420. package/sandbox/logon.cmd +24 -16
  421. package/sandbox/memlog.ps1 +34 -0
  422. package/sandbox/openssl.cs +42 -0
  423. package/sandbox/pagefile.cs +31 -0
  424. package/sandbox/pagefile.ps1 +21 -0
  425. package/sandbox/ptyhost.cs +120 -11
  426. package/sandbox/trust.cmd +35 -35
  427. package/schemas/config.schema.json +403 -3
  428. package/schemas/sandbox-config.schema.json +143 -13
  429. package/dist/cli/commands/data.d.ts +0 -46
  430. package/dist/cli/commands/data.js +0 -249
  431. package/dist/cli/commands/setup.js +0 -152
  432. package/dist/cli/menu.d.ts +0 -22
  433. package/dist/cli/menu.js +0 -187
  434. package/dist/cli/settings.d.ts +0 -11
  435. package/dist/cli/settings.js +0 -156
  436. package/dist/guest/toolchains/databases.js +0 -226
  437. package/dist/guest/toolchains/msvc.d.ts +0 -10
  438. package/dist/guest/toolchains/msvc.js +0 -216
  439. package/dist/guest/toolchains/native.d.ts +0 -12
  440. package/dist/guest/toolchains/native.js +0 -220
  441. package/dist/guest/toolchains/scripting.d.ts +0 -10
  442. package/dist/guest/toolchains/scripting.js +0 -137
  443. package/dist/selftest/guest.test.d.ts +0 -3
  444. package/dist/selftest/guest.test.js +0 -61
  445. package/dist/selftest/helpers.test.d.ts +0 -2
  446. package/dist/selftest/helpers.test.js +0 -125
  447. package/dist/selftest/host.test.d.ts +0 -2
  448. package/dist/selftest/host.test.js +0 -71
  449. package/dist/selftest/live.test.d.ts +0 -7
  450. package/dist/selftest/live.test.js +0 -127
  451. package/dist/selftest/security.test.d.ts +0 -3
  452. package/dist/selftest/security.test.js +0 -143
  453. /package/dist/guest/toolchains/{binstall.d.ts → native/binstall.d.ts} +0 -0
@@ -0,0 +1,299 @@
1
+ import { Text } from './text.js';
2
+ import { Theme } from './theme.js';
3
+ export class ListScreen {
4
+ o;
5
+ category = 0;
6
+ focus = 'list';
7
+ cursor = 0;
8
+ offset = 0;
9
+ query = '';
10
+ searching = false;
11
+ notice;
12
+ checked;
13
+ constructor(o) {
14
+ this.o = o;
15
+ this.notice = o.notice;
16
+ this.checked = new Set(o.items.flatMap((item, i) => (item.checked ? [i] : [])));
17
+ const start = o.startAt === undefined ? -1 : o.items.findIndex((item) => item.value === o.startAt);
18
+ const startCategory = start >= 0 ? o.items[start].category : o.startCategory;
19
+ if (o.categories && startCategory)
20
+ this.category = Math.max(0, o.categories.findIndex((c) => c.id === startCategory));
21
+ if (start >= 0)
22
+ this.cursor = Math.max(0, this.visible().indexOf(start));
23
+ }
24
+ /** Indexes of the entries shown now: all matches of the search, else the current category's, else all. */
25
+ visible() {
26
+ const all = this.o.items.map((_, i) => i);
27
+ if (this.query.trim()) {
28
+ const words = this.query.toLowerCase().split(/\s+/).filter(Boolean);
29
+ const label = (id) => this.o.categories?.find((c) => c.id === id)?.label ?? '';
30
+ return all.filter((i) => {
31
+ const it = this.o.items[i];
32
+ const hay = [it.label, Text.strip(it.hint ?? ''), it.description, it.keywords, it.section, label(it.category)].join(' ').toLowerCase();
33
+ return words.every((w) => hay.includes(w));
34
+ });
35
+ }
36
+ const cat = this.o.categories?.[this.category];
37
+ return cat ? all.filter((i) => this.o.items[i].category === cat.id) : all;
38
+ }
39
+ rows(visible) {
40
+ const rows = [];
41
+ let section;
42
+ const searchAll = Boolean(this.query.trim() && this.o.categories);
43
+ for (const index of visible) {
44
+ const it = this.o.items[index];
45
+ const heading = searchAll ? [this.o.categories?.find((c) => c.id === it.category)?.label, it.section].filter(Boolean).join(' › ') : it.section;
46
+ if (heading && heading !== section)
47
+ rows.push({ kind: 'section', text: heading });
48
+ section = heading;
49
+ rows.push({ kind: 'item', index });
50
+ }
51
+ return rows;
52
+ }
53
+ render(size) {
54
+ const visible = this.visible();
55
+ this.cursor = Math.min(this.cursor, Math.max(0, visible.length - 1));
56
+ const sideWidth = this.o.categories ? Math.min(32, Math.max(...this.o.categories.map((c) => Text.width(c.label))) + 7) : 0;
57
+ const rest = size.width - 1 - (sideWidth ? sideWidth + 3 : 0);
58
+ const detailsRight = rest >= 100;
59
+ const detailsWidth = detailsRight ? Math.min(52, Math.floor(rest * 0.38)) : rest;
60
+ const listWidth = detailsRight ? rest - detailsWidth - 3 : rest;
61
+ const top = [];
62
+ if (this.o.tabs)
63
+ top.push(' ' + this.o.tabs.items.map((tab, i) => (i === this.o.tabs.active ? tab.paint(' ' + tab.badge + ' ' + tab.label + ' ') : Theme.muted(' ' + tab.label + ' '))).join(' ') + Theme.muted(' tab switches'), '');
64
+ const intro = typeof this.o.intro === 'string' ? [this.o.intro] : this.o.intro ?? [];
65
+ for (const line of intro)
66
+ top.push(...Text.wrap(line, size.width - 3).map((l) => ' ' + Theme.muted(l)));
67
+ if (this.searching || this.query)
68
+ top.push(' ' + Theme.accent(Theme.glyph.search) + ' ' + this.query + (this.searching ? Theme.accent('▏') : '') + Theme.muted(' ' + visible.length + ' match' + (visible.length === 1 ? '' : 'es')));
69
+ if (top.length)
70
+ top.push('');
71
+ const details = this.detailsLines(visible[this.cursor], detailsWidth);
72
+ const bottomDetails = !detailsRight && size.height - top.length >= 14 ? details.slice(0, 6) : [];
73
+ const rows = this.rows(visible);
74
+ const room = size.height - top.length - (bottomDetails.length ? bottomDetails.length + 1 : 0);
75
+ // A list longer than the room keeps one row for "▲ / ▼ more".
76
+ const listHeight = rows.length > room ? room - 1 : room;
77
+ const cursorRow = rows.findIndex((r) => r.kind === 'item' && r.index === visible[this.cursor]);
78
+ if (cursorRow >= 0) {
79
+ // Keep the heading above the first entry in view, and the cursor inside the window.
80
+ const want = cursorRow > 0 && rows[cursorRow - 1].kind === 'section' ? cursorRow - 1 : cursorRow;
81
+ if (want < this.offset)
82
+ this.offset = want;
83
+ if (cursorRow >= this.offset + listHeight)
84
+ this.offset = cursorRow - listHeight + 1;
85
+ }
86
+ this.offset = Math.max(0, Math.min(this.offset, Math.max(0, rows.length - listHeight)));
87
+ const listLines = rows.slice(this.offset, this.offset + listHeight).map((row) => this.rowLine(row, visible, listWidth));
88
+ if (!visible.length)
89
+ listLines.push('', ' ' + Theme.muted(this.query ? 'Nothing matches "' + this.query + '".' : this.o.empty ?? 'Nothing here yet.'));
90
+ if (rows.length > listHeight) {
91
+ const above = this.offset;
92
+ const below = rows.length - this.offset - listHeight;
93
+ listLines.push(Theme.muted(' ' + (above > 0 ? '▲ ' + above + ' above' : '') + (above > 0 && below > 0 ? ' ' : '') + (below > 0 ? '▼ ' + below + ' more' : '')));
94
+ }
95
+ const sideLines = this.sideLines(sideWidth);
96
+ const body = [...top];
97
+ const height = Math.max(listLines.length, detailsRight ? details.length : 0, sideLines.length);
98
+ for (let i = 0; i < Math.min(height, size.height - top.length); i++) {
99
+ const side = sideWidth ? Text.fit(sideLines[i] ?? '', sideWidth) + ' ' + Theme.dim(Theme.glyph.vline) + ' ' : '';
100
+ const main = Text.fit(listLines[i] ?? '', listWidth);
101
+ const right = detailsRight ? ' ' + Theme.dim(Theme.glyph.vline) + ' ' + (details[i] ?? '') : '';
102
+ body.push(side + main + right);
103
+ }
104
+ if (bottomDetails.length) {
105
+ // The details sit at the bottom, whatever the length of the list.
106
+ while (body.length < size.height - bottomDetails.length - 1)
107
+ body.push(sideWidth ? Text.fit(sideLines[body.length - top.length] ?? '', sideWidth) + ' ' + Theme.dim(Theme.glyph.vline) : '');
108
+ body.push(Theme.dim(' ' + Theme.glyph.line.repeat(size.width - 3)), ...bottomDetails.map((l) => ' ' + l));
109
+ }
110
+ return { path: this.o.path, status: this.o.status, body, keys: this.keys(), notice: this.notice };
111
+ }
112
+ rowLine(row, visible, width) {
113
+ if (row.kind === 'section')
114
+ return ' ' + Theme.accentBold(row.text);
115
+ const it = this.o.items[row.index];
116
+ const selected = visible[this.cursor] === row.index;
117
+ const box = this.o.multi ? (this.checked.has(row.index) ? Theme.ok(Theme.glyph.checked) : Theme.muted(Theme.glyph.unchecked)) + ' ' : '';
118
+ const icon = it.icon ? it.icon + ' ' : '';
119
+ const hint = it.hint ?? '';
120
+ const hintWidth = Math.min(Text.width(hint), Math.floor(width * 0.5));
121
+ const labelWidth = width - 4 - Text.width(box) - Text.width(icon) - (hintWidth ? hintWidth + 2 : 0);
122
+ const label = it.disabled ? Theme.muted(it.label) : it.label;
123
+ const line = (selected ? Theme.glyph.pointer : ' ') + ' ' + box + icon + Text.fit(label, labelWidth) + (hintWidth ? ' ' + Text.fit(hint, hintWidth, 'right') : '') + ' ';
124
+ if (!selected)
125
+ return ' ' + line;
126
+ return this.focus === 'list' ? ' ' + Theme.selected(Text.strip(line)) : ' ' + Theme.accent(Text.strip(line));
127
+ }
128
+ sideLines(width) {
129
+ if (!this.o.categories)
130
+ return [];
131
+ return this.o.categories.map((cat, i) => {
132
+ const count = this.o.items.filter((it) => it.category === cat.id).length;
133
+ const text = ' ' + Text.fit(cat.label, width - 6) + ' ' + Text.fit(String(count), 3, 'right') + ' ';
134
+ if (i !== this.category)
135
+ return Theme.muted(text);
136
+ return this.focus === 'side' ? Theme.selected(text) : Theme.accentBold(text);
137
+ });
138
+ }
139
+ detailsLines(index, width) {
140
+ const w = Math.max(10, width - 1);
141
+ if (this.focus === 'side' && this.o.categories) {
142
+ const cat = this.o.categories[this.category];
143
+ return [Theme.bold(cat.label), ...(cat.description ? Text.wrap(cat.description, w).map((l) => Theme.muted(l)) : [])];
144
+ }
145
+ if (index === undefined)
146
+ return [];
147
+ const it = this.o.items[index];
148
+ return [
149
+ Theme.bold(Text.truncate(it.label, w)),
150
+ ...(it.description ? Text.wrap(it.description, w).map((l) => Theme.muted(l)) : []),
151
+ ...(it.details?.length ? ['', ...it.details.flatMap((d) => Text.wrap(d, w))] : []),
152
+ ...(it.disabled ? ['', Theme.warn(it.disabled)] : []),
153
+ ];
154
+ }
155
+ keys() {
156
+ if (this.searching)
157
+ return [['type', 'to search'], ['↑↓', 'move'], ['↵', this.o.multi ? 'done' : 'open'], ['esc', 'clear search']];
158
+ return [
159
+ ['↑↓', 'move'],
160
+ ...(this.o.tabs ? [['tab', 'switch ' + this.o.tabs.items.map((t) => t.label.toLowerCase()).join(' / ')]] : []),
161
+ ...(this.o.categories ? [['←→', 'categories']] : []),
162
+ ...(this.o.multi ? [['space', 'tick'], ['a', 'tick all shown'], ['↵', 'done']] : [['↵', 'open']]),
163
+ ['/', 'search'],
164
+ ...(this.o.actions ?? []).map((a) => [a.key, a.label]),
165
+ ['esc', this.o.escapeLabel ?? 'back'],
166
+ ];
167
+ }
168
+ /** Programmatic notice (e.g. "Saved") shown until the next key. */
169
+ setNotice(text) { this.notice = text; }
170
+ handle(key) {
171
+ const visible = this.visible();
172
+ const current = visible[this.cursor];
173
+ this.notice = undefined;
174
+ const move = (by) => { this.cursor = Math.max(0, Math.min(visible.length - 1, this.cursor + by)); };
175
+ if (key.name === 'up') {
176
+ if (this.focus === 'side')
177
+ this.switchCategory(-1);
178
+ else
179
+ move(-1);
180
+ return;
181
+ }
182
+ if (key.name === 'down') {
183
+ if (this.focus === 'side')
184
+ this.switchCategory(1);
185
+ else
186
+ move(1);
187
+ return;
188
+ }
189
+ if (key.name === 'pageup') {
190
+ move(-10);
191
+ return;
192
+ }
193
+ if (key.name === 'pagedown') {
194
+ move(10);
195
+ return;
196
+ }
197
+ if (key.name === 'home') {
198
+ this.cursor = 0;
199
+ return;
200
+ }
201
+ if (key.name === 'end') {
202
+ this.cursor = visible.length - 1;
203
+ return;
204
+ }
205
+ if (this.searching) {
206
+ if (key.name === 'escape') {
207
+ this.searching = false;
208
+ this.query = '';
209
+ this.cursor = 0;
210
+ return;
211
+ }
212
+ if (key.name === 'backspace') {
213
+ if (this.query)
214
+ this.query = this.query.slice(0, -1);
215
+ else
216
+ this.searching = false;
217
+ this.cursor = 0;
218
+ return;
219
+ }
220
+ // In a tick list, space always ticks (even while searching).
221
+ if (key.name !== 'return' && key.text && !(this.o.multi && key.name === 'space')) {
222
+ this.query += key.text;
223
+ this.cursor = 0;
224
+ return;
225
+ }
226
+ }
227
+ if (this.o.tabs && key.name === 'tab') {
228
+ const n = this.o.tabs.items.length;
229
+ return { done: { kind: 'tab', index: (this.o.tabs.active + (key.shift ? n - 1 : 1)) % n } };
230
+ }
231
+ if (this.o.categories && !this.query) {
232
+ if (key.name === 'left' && this.focus === 'list') {
233
+ this.focus = 'side';
234
+ return;
235
+ }
236
+ if ((key.name === 'right' || key.name === 'return') && this.focus === 'side') {
237
+ this.focus = 'list';
238
+ return;
239
+ }
240
+ }
241
+ if (key.name === 'escape' || (key.name === 'backspace' && !this.searching)) {
242
+ if (this.query) {
243
+ this.query = '';
244
+ this.cursor = 0;
245
+ return;
246
+ }
247
+ return { done: { kind: 'back' } };
248
+ }
249
+ if (key.text === '/' || (key.name === 'f' && key.ctrl)) {
250
+ this.searching = true;
251
+ this.focus = 'list';
252
+ return;
253
+ }
254
+ if (this.o.multi) {
255
+ if (key.name === 'space' && current !== undefined) {
256
+ this.toggle(current);
257
+ return;
258
+ }
259
+ if (key.text === 'a') {
260
+ const all = visible.filter((i) => !this.o.items[i].disabled);
261
+ const tick = all.some((i) => !this.checked.has(i));
262
+ all.forEach((i) => (tick ? this.checked.add(i) : this.checked.delete(i)));
263
+ return;
264
+ }
265
+ if (key.name === 'return')
266
+ return { done: { kind: 'multi', values: this.o.items.filter((_, i) => this.checked.has(i)).map((it) => it.value) } };
267
+ }
268
+ if ((key.name === 'return' || key.name === 'right' || (key.name === 'space' && !this.searching)) && current !== undefined && !this.o.multi) {
269
+ const it = this.o.items[current];
270
+ if (it.disabled) {
271
+ this.notice = Theme.warn(it.disabled);
272
+ return;
273
+ }
274
+ return { done: { kind: 'pick', value: it.value } };
275
+ }
276
+ const action = !this.searching && key.text ? this.o.actions?.find((a) => a.key === key.text) : undefined;
277
+ if (action)
278
+ return { done: { kind: 'action', key: action.key, value: current === undefined ? undefined : this.o.items[current].value } };
279
+ return;
280
+ }
281
+ toggle(index) {
282
+ if (this.o.items[index].disabled) {
283
+ this.notice = Theme.warn(this.o.items[index].disabled);
284
+ return;
285
+ }
286
+ if (this.checked.has(index))
287
+ this.checked.delete(index);
288
+ else
289
+ this.checked.add(index);
290
+ }
291
+ switchCategory(by) {
292
+ const count = this.o.categories?.length ?? 0;
293
+ if (!count)
294
+ return;
295
+ this.category = (this.category + by + count) % count;
296
+ this.cursor = 0;
297
+ this.offset = 0;
298
+ }
299
+ }
@@ -0,0 +1,37 @@
1
+ /** One key press: `name` for special keys (up, return, escape, f1 ...), `text` for something typed. */
2
+ export interface Key {
3
+ name: string;
4
+ text: string;
5
+ ctrl: boolean;
6
+ meta: boolean;
7
+ shift: boolean;
8
+ }
9
+ /** Ctrl+C: leave the menu at once (callers let it propagate to the top). */
10
+ export declare class ExitRequested extends Error {
11
+ constructor();
12
+ }
13
+ export declare class Terminal {
14
+ private readonly stdin;
15
+ private readonly stdout;
16
+ private active;
17
+ private frame;
18
+ private queue;
19
+ private waiting;
20
+ private resizeHandler;
21
+ private readonly onKeypress;
22
+ private readonly onResize;
23
+ constructor(stdin?: NodeJS.ReadStream, stdout?: NodeJS.WriteStream);
24
+ get width(): number;
25
+ get height(): number;
26
+ /** Called after the window was resized (the screen draws itself again). */
27
+ onResized(handler: (() => void) | null): void;
28
+ start(): void;
29
+ /** Gives the terminal back exactly as it was (also on errors: callers use try/finally). */
30
+ stop(): void;
31
+ get running(): boolean;
32
+ /** Draws a whole screen: `lines` are cut to the width and padded to the height; unchanged rows are not rewritten. */
33
+ render(lines: string[]): void;
34
+ /** The next key press. Ctrl+C rejects with ExitRequested. */
35
+ key(): Promise<Key>;
36
+ private push;
37
+ }
@@ -0,0 +1,89 @@
1
+ // The terminal while the menu owns it: the alternate screen (your scrollback stays as it was), raw keys, a cursor that
2
+ // is hidden, and redraws that only rewrite the rows that changed (no flicker). suspend() hands the terminal back for
3
+ // a command's own output; resume() takes it again.
4
+ import readline from 'node:readline';
5
+ import { Text } from './text.js';
6
+ /** Ctrl+C: leave the menu at once (callers let it propagate to the top). */
7
+ export class ExitRequested extends Error {
8
+ constructor() { super('Ctrl+C'); this.name = 'ExitPromptError'; }
9
+ }
10
+ export class Terminal {
11
+ stdin;
12
+ stdout;
13
+ active = false;
14
+ frame = [];
15
+ queue = [];
16
+ waiting = null;
17
+ resizeHandler = null;
18
+ onKeypress = (str, key) => this.push(str, key);
19
+ onResize = () => { this.frame = []; this.resizeHandler?.(); };
20
+ constructor(stdin = process.stdin, stdout = process.stdout) {
21
+ this.stdin = stdin;
22
+ this.stdout = stdout;
23
+ }
24
+ get width() { return Math.max(40, this.stdout.columns ?? 80); }
25
+ get height() { return Math.max(12, this.stdout.rows ?? 30); }
26
+ /** Called after the window was resized (the screen draws itself again). */
27
+ onResized(handler) { this.resizeHandler = handler; }
28
+ start() {
29
+ if (this.active)
30
+ return;
31
+ this.active = true;
32
+ this.frame = [];
33
+ readline.emitKeypressEvents(this.stdin);
34
+ if (this.stdin.isTTY)
35
+ this.stdin.setRawMode(true);
36
+ this.stdin.on('keypress', this.onKeypress);
37
+ this.stdin.resume();
38
+ this.stdout.on('resize', this.onResize);
39
+ this.stdout.write('\x1b[?1049h\x1b[?25l\x1b[H\x1b[2J');
40
+ }
41
+ /** Gives the terminal back exactly as it was (also on errors: callers use try/finally). */
42
+ stop() {
43
+ if (!this.active)
44
+ return;
45
+ this.active = false;
46
+ this.stdin.off('keypress', this.onKeypress);
47
+ this.stdout.off('resize', this.onResize);
48
+ if (this.stdin.isTTY)
49
+ this.stdin.setRawMode(false);
50
+ this.stdin.pause();
51
+ this.queue = [];
52
+ this.stdout.write('\x1b[0m\x1b[?25h\x1b[?1049l');
53
+ }
54
+ get running() { return this.active; }
55
+ /** Draws a whole screen: `lines` are cut to the width and padded to the height; unchanged rows are not rewritten. */
56
+ render(lines) {
57
+ const { width, height } = this;
58
+ // One column is left free: writing the last column can scroll older consoles.
59
+ const rows = Array.from({ length: height }, (_, i) => Text.fit(lines[i] ?? '', width - 1));
60
+ let out = '';
61
+ rows.forEach((row, i) => { if (this.frame[i] !== row)
62
+ out += '\x1b[' + (i + 1) + ';1H' + row + '\x1b[0m'; });
63
+ if (this.frame.length !== rows.length)
64
+ out = '\x1b[H\x1b[2J' + rows.map((r, i) => '\x1b[' + (i + 1) + ';1H' + r + '\x1b[0m').join('');
65
+ this.frame = rows;
66
+ if (out)
67
+ this.stdout.write(out);
68
+ }
69
+ /** The next key press. Ctrl+C rejects with ExitRequested. */
70
+ key() {
71
+ const next = this.queue.shift();
72
+ if (next)
73
+ return next.ctrl && next.name === 'c' ? Promise.reject(new ExitRequested()) : Promise.resolve(next);
74
+ return new Promise((resolve, reject) => { this.waiting = { resolve, reject }; });
75
+ }
76
+ push(str, key) {
77
+ const event = { name: key?.name ?? '', text: str && !key?.ctrl && !key?.meta && str.length >= 1 && str >= ' ' && str !== '\x7f' ? str : '', ctrl: Boolean(key?.ctrl), meta: Boolean(key?.meta), shift: Boolean(key?.shift) };
78
+ const waiting = this.waiting;
79
+ if (!waiting) {
80
+ this.queue.push(event);
81
+ return;
82
+ }
83
+ this.waiting = null;
84
+ if (event.ctrl && event.name === 'c')
85
+ waiting.reject(new ExitRequested());
86
+ else
87
+ waiting.resolve(event);
88
+ }
89
+ }
@@ -0,0 +1,20 @@
1
+ export declare class Text {
2
+ /** Removes colour and cursor codes. */
3
+ static strip(text: string): string;
4
+ /** Columns one character takes: 2 for East Asian wide characters and most emoji, 0 for combining marks. */
5
+ static charWidth(code: number): number;
6
+ /** Columns `text` takes on screen. */
7
+ static width(text: string): number;
8
+ /**
9
+ * The first `max` columns of `text`, keeping colour codes (and closing them), with an ellipsis when something was cut.
10
+ */
11
+ static truncate(text: string, max: number, ellipsis?: string): string;
12
+ /** `text` cut or padded with spaces to exactly `width` columns. */
13
+ static fit(text: string, width: number, align?: 'left' | 'right'): string;
14
+ /** Cuts the middle out of a long path so both ends stay readable (plain text). */
15
+ static middle(text: string, max: number): string;
16
+ /** Word-wraps plain text to `width` columns (long words are split); keeps the text's own line breaks. */
17
+ static wrap(text: string, width: number): string[];
18
+ /** "memoryMb" -> "Memory MB", "vGpu" -> "V GPU": a readable label from a setting's key. */
19
+ static humanize(key: string): string;
20
+ }
@@ -0,0 +1,105 @@
1
+ // Measuring and laying out terminal text that may hold colour codes: visible width, padding, cutting and wrapping.
2
+ // Pure (tested), so every screen lines up the same way.
3
+ const ANSI = /\x1b\[[0-9;?]*[A-Za-z]/g;
4
+ export class Text {
5
+ /** Removes colour and cursor codes. */
6
+ static strip(text) {
7
+ return text.replace(ANSI, '');
8
+ }
9
+ /** Columns one character takes: 2 for East Asian wide characters and most emoji, 0 for combining marks. */
10
+ static charWidth(code) {
11
+ if (code < 32 || (code >= 0x7f && code < 0xa0))
12
+ return 0;
13
+ if ((code >= 0x300 && code <= 0x36f) || (code >= 0x200b && code <= 0x200f) || code === 0xfe0f)
14
+ return 0;
15
+ const wide = (code >= 0x1100 && code <= 0x115f) || (code >= 0x2e80 && code <= 0xa4cf) || (code >= 0xac00 && code <= 0xd7a3)
16
+ || (code >= 0xf900 && code <= 0xfaff) || (code >= 0xfe30 && code <= 0xfe4f) || (code >= 0xff00 && code <= 0xff60)
17
+ || (code >= 0xffe0 && code <= 0xffe6) || (code >= 0x1f300 && code <= 0x1faff) || (code >= 0x20000 && code <= 0x3fffd);
18
+ return wide ? 2 : 1;
19
+ }
20
+ /** Columns `text` takes on screen. */
21
+ static width(text) {
22
+ let width = 0;
23
+ for (const ch of Text.strip(text))
24
+ width += Text.charWidth(ch.codePointAt(0));
25
+ return width;
26
+ }
27
+ /**
28
+ * The first `max` columns of `text`, keeping colour codes (and closing them), with an ellipsis when something was cut.
29
+ */
30
+ static truncate(text, max, ellipsis = '…') {
31
+ if (max <= 0)
32
+ return '';
33
+ if (Text.width(text) <= max)
34
+ return text;
35
+ const room = max - Text.width(ellipsis);
36
+ let out = '';
37
+ let used = 0;
38
+ let coloured = false;
39
+ for (let i = 0; i < text.length;) {
40
+ const code = /^\x1b\[[0-9;?]*[A-Za-z]/.exec(text.slice(i));
41
+ if (code) {
42
+ out += code[0];
43
+ coloured = code[0] !== '\x1b[0m';
44
+ i += code[0].length;
45
+ continue;
46
+ }
47
+ const ch = String.fromCodePoint(text.codePointAt(i));
48
+ const w = Text.charWidth(ch.codePointAt(0));
49
+ if (used + w > room)
50
+ break;
51
+ out += ch;
52
+ used += w;
53
+ i += ch.length;
54
+ }
55
+ return out + (coloured ? '\x1b[0m' : '') + ellipsis;
56
+ }
57
+ /** `text` cut or padded with spaces to exactly `width` columns. */
58
+ static fit(text, width, align = 'left') {
59
+ const cut = Text.truncate(text, width);
60
+ const gap = ' '.repeat(Math.max(0, width - Text.width(cut)));
61
+ return align === 'left' ? cut + gap : gap + cut;
62
+ }
63
+ /** Cuts the middle out of a long path so both ends stay readable (plain text). */
64
+ static middle(text, max) {
65
+ if (max < 5 || text.length <= max)
66
+ return text;
67
+ const keep = max - 1;
68
+ const head = Math.ceil(keep / 2);
69
+ return text.slice(0, head) + '…' + text.slice(text.length - (keep - head));
70
+ }
71
+ /** Word-wraps plain text to `width` columns (long words are split); keeps the text's own line breaks. */
72
+ static wrap(text, width) {
73
+ const lines = [];
74
+ for (const paragraph of text.split(/\r?\n/)) {
75
+ let line = '';
76
+ for (const word of paragraph.split(/ +/)) {
77
+ let rest = word;
78
+ while (Text.width(rest) > width) {
79
+ if (line) {
80
+ lines.push(line);
81
+ line = '';
82
+ }
83
+ lines.push(rest.slice(0, width));
84
+ rest = rest.slice(width);
85
+ }
86
+ if (!line)
87
+ line = rest;
88
+ else if (Text.width(line) + 1 + Text.width(rest) <= width)
89
+ line += ' ' + rest;
90
+ else {
91
+ lines.push(line);
92
+ line = rest;
93
+ }
94
+ }
95
+ lines.push(line);
96
+ }
97
+ return lines;
98
+ }
99
+ /** "memoryMb" -> "Memory MB", "vGpu" -> "V GPU": a readable label from a setting's key. */
100
+ static humanize(key) {
101
+ const words = key.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ').split(' ').filter(Boolean);
102
+ const upper = new Set(['mb', 'gb', 'cpu', 'gpu', 'jdk', 'sdk', 'id', 'url', 'ui', 'npm', 'msvc', 'uv', 'api', 'ssh', 'vm', 'io']);
103
+ return words.map((w, i) => (upper.has(w.toLowerCase()) ? w.toUpperCase() : i === 0 ? w[0].toUpperCase() + w.slice(1) : w.toLowerCase())).join(' ');
104
+ }
105
+ }
@@ -0,0 +1,45 @@
1
+ export declare class Theme {
2
+ /** Colour is decided once per run: the menu only runs in a terminal. */
3
+ static readonly colour: boolean;
4
+ static readonly bold: (text: string) => string;
5
+ static readonly dim: (text: string) => string;
6
+ static readonly italic: (text: string) => string;
7
+ static readonly accent: (text: string) => string;
8
+ static readonly accentBold: (t: string) => string;
9
+ static readonly ok: (text: string) => string;
10
+ static readonly warn: (text: string) => string;
11
+ static readonly error: (text: string) => string;
12
+ static readonly muted: (text: string) => string;
13
+ static readonly changed: (text: string) => string;
14
+ /** The highlighted row: a soft background bar across the whole width. */
15
+ static readonly selected: (t: string) => string;
16
+ /** The header bar. */
17
+ static readonly bar: (t: string) => string;
18
+ /** The two settings scopes: your own (blue) and the project's (purple). */
19
+ static readonly scopeGlobal: (t: string) => string;
20
+ static readonly scopeProject: (t: string) => string;
21
+ static readonly project: (text: string) => string;
22
+ static readonly key: (t: string) => string;
23
+ static readonly glyph: {
24
+ pointer: string;
25
+ bullet: string;
26
+ on: string;
27
+ off: string;
28
+ checked: string;
29
+ unchecked: string;
30
+ dot: string;
31
+ arrow: string;
32
+ back: string;
33
+ more: string;
34
+ folder: string;
35
+ open: string;
36
+ line: string;
37
+ vline: string;
38
+ search: string;
39
+ changed: string;
40
+ lock: string;
41
+ ok: string;
42
+ cross: string;
43
+ star: string;
44
+ };
45
+ }
@@ -0,0 +1,30 @@
1
+ // The look of every screen: colours (off with NO_COLOR, like the rest of the CLI) and the line-drawing characters.
2
+ import { colorEnabled } from '../colors.js';
3
+ const sgr = (open, close = '0') => (text) => (Theme.colour ? '\x1b[' + open + 'm' + text + '\x1b[' + close + 'm' : text);
4
+ export class Theme {
5
+ /** Colour is decided once per run: the menu only runs in a terminal. */
6
+ static colour = colorEnabled(process.env, Boolean(process.stdout.isTTY));
7
+ static bold = sgr('1', '22');
8
+ static dim = sgr('2', '22');
9
+ static italic = sgr('3', '23');
10
+ static accent = sgr('38;5;75', '39');
11
+ static accentBold = (t) => Theme.bold(Theme.accent(t));
12
+ static ok = sgr('38;5;78', '39');
13
+ static warn = sgr('38;5;214', '39');
14
+ static error = sgr('38;5;203', '39');
15
+ static muted = sgr('38;5;245', '39');
16
+ static changed = sgr('38;5;221', '39');
17
+ /** The highlighted row: a soft background bar across the whole width. */
18
+ static selected = (t) => (Theme.colour ? '\x1b[48;5;24m\x1b[97m' + t.replace(/\x1b\[0m/g, '\x1b[0m\x1b[48;5;24m\x1b[97m') + '\x1b[0m' : t);
19
+ /** The header bar. */
20
+ static bar = (t) => (Theme.colour ? '\x1b[48;5;236m\x1b[97m' + t.replace(/\x1b\[0m/g, '\x1b[0m\x1b[48;5;236m\x1b[97m') + '\x1b[0m' : t);
21
+ /** The two settings scopes: your own (blue) and the project's (purple). */
22
+ static scopeGlobal = (t) => (Theme.colour ? '\x1b[48;5;25m\x1b[97m\x1b[1m' + t + '\x1b[0m' : '[' + t + ']');
23
+ static scopeProject = (t) => (Theme.colour ? '\x1b[48;5;91m\x1b[97m\x1b[1m' + t + '\x1b[0m' : '[' + t + ']');
24
+ static project = sgr('38;5;177', '39');
25
+ static key = (t) => (Theme.colour ? '\x1b[48;5;238m\x1b[97m ' + t + ' \x1b[0m' : '[' + t + ']');
26
+ static glyph = {
27
+ pointer: '›', bullet: '•', on: '●', off: '○', checked: '◉', unchecked: '◯', dot: '·', arrow: '→', back: '←', more: '…',
28
+ folder: '▸', open: '▾', line: '─', vline: '│', search: '⌕', changed: '✎', lock: '⚿', ok: '✔', cross: '✘', star: '★',
29
+ };
30
+ }
@@ -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;