windows-development-sandbox 1.5.0 → 1.7.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 (448) hide show
  1. package/README.md +1 -0
  2. package/config.example.json +17 -1
  3. package/dist/cli/args.d.ts +13 -2
  4. package/dist/cli/args.js +95 -24
  5. package/dist/cli/commands/accounts.js +45 -17
  6. package/dist/cli/commands/context.d.ts +2 -0
  7. package/dist/cli/commands/context.js +9 -2
  8. package/dist/cli/commands/data/clean.js +32 -9
  9. package/dist/cli/commands/index.d.ts +1 -0
  10. package/dist/cli/commands/index.js +1 -0
  11. package/dist/cli/commands/launch/add-root.d.ts +3 -2
  12. package/dist/cli/commands/launch/add-root.js +11 -10
  13. package/dist/cli/commands/launch/launch.js +57 -4
  14. package/dist/cli/commands/launch/prepare.js +3 -1
  15. package/dist/cli/commands/maintenance/audit.js +1 -1
  16. package/dist/cli/commands/maintenance/clean.d.ts +1 -1
  17. package/dist/cli/commands/maintenance/clean.js +17 -3
  18. package/dist/cli/commands/maintenance/config.d.ts +1 -1
  19. package/dist/cli/commands/maintenance/config.js +112 -10
  20. package/dist/cli/commands/maintenance/doctor.d.ts +1 -1
  21. package/dist/cli/commands/maintenance/doctor.js +2 -4
  22. package/dist/cli/commands/maintenance/migrate.d.ts +2 -1
  23. package/dist/cli/commands/maintenance/migrate.js +19 -4
  24. package/dist/cli/commands/maintenance/sync.js +2 -0
  25. package/dist/cli/commands/maintenance/update.d.ts +2 -0
  26. package/dist/cli/commands/maintenance/update.js +27 -4
  27. package/dist/cli/commands/projects/here.js +12 -7
  28. package/dist/cli/commands/projects/projects.js +26 -17
  29. package/dist/cli/commands/registry.js +7 -0
  30. package/dist/cli/commands/repair/checks/agents.d.ts +2 -0
  31. package/dist/cli/commands/repair/checks/agents.js +70 -0
  32. package/dist/cli/commands/repair/checks/common.d.ts +8 -0
  33. package/dist/cli/commands/repair/checks/common.js +22 -0
  34. package/dist/cli/commands/repair/checks/data.d.ts +2 -0
  35. package/dist/cli/commands/repair/checks/data.js +241 -0
  36. package/dist/cli/commands/repair/checks/index.d.ts +2 -0
  37. package/dist/cli/commands/repair/checks/index.js +20 -0
  38. package/dist/cli/commands/repair/checks/install.d.ts +5 -0
  39. package/dist/cli/commands/repair/checks/install.js +318 -0
  40. package/dist/cli/commands/repair/checks/machine.d.ts +2 -0
  41. package/dist/cli/commands/repair/checks/machine.js +232 -0
  42. package/dist/cli/commands/repair/checks/network.d.ts +6 -0
  43. package/dist/cli/commands/repair/checks/network.js +60 -0
  44. package/dist/cli/commands/repair/checks/pc.d.ts +4 -0
  45. package/dist/cli/commands/repair/checks/pc.js +55 -0
  46. package/dist/cli/commands/repair/checks/sandbox.d.ts +2 -0
  47. package/dist/cli/commands/repair/checks/sandbox.js +267 -0
  48. package/dist/cli/commands/repair/checks/settings.d.ts +2 -0
  49. package/dist/cli/commands/repair/checks/settings.js +169 -0
  50. package/dist/cli/commands/repair/checks/vpn.d.ts +2 -0
  51. package/dist/cli/commands/repair/checks/vpn.js +53 -0
  52. package/dist/cli/commands/repair/engine.d.ts +32 -0
  53. package/dist/cli/commands/repair/engine.js +127 -0
  54. package/dist/cli/commands/repair/env.d.ts +7 -0
  55. package/dist/cli/commands/repair/env.js +49 -0
  56. package/dist/cli/commands/repair/index.d.ts +1 -9
  57. package/dist/cli/commands/repair/index.js +2 -54
  58. package/dist/cli/commands/repair/log.d.ts +17 -0
  59. package/dist/cli/commands/repair/log.js +82 -0
  60. package/dist/cli/commands/repair/printer.d.ts +32 -0
  61. package/dist/cli/commands/repair/printer.js +132 -0
  62. package/dist/cli/commands/repair/run.d.ts +33 -0
  63. package/dist/cli/commands/repair/run.js +133 -0
  64. package/dist/cli/commands/repair/types.d.ts +97 -9
  65. package/dist/cli/commands/repair/types.js +11 -7
  66. package/dist/cli/commands/resume.js +2 -2
  67. package/dist/cli/commands/sessions/list.js +5 -2
  68. package/dist/cli/commands/sessions/status.d.ts +2 -0
  69. package/dist/cli/commands/sessions/status.js +27 -6
  70. package/dist/cli/commands/setup/index.d.ts +5 -0
  71. package/dist/cli/commands/setup/index.js +25 -1
  72. package/dist/cli/commands/storage/index.d.ts +2 -0
  73. package/dist/cli/commands/storage/index.js +2 -0
  74. package/dist/cli/commands/storage/offer.d.ts +3 -0
  75. package/dist/cli/commands/storage/offer.js +85 -0
  76. package/dist/cli/commands/storage/storage.d.ts +8 -0
  77. package/dist/cli/commands/storage/storage.js +171 -0
  78. package/dist/cli/commands/user-config.js +1 -1
  79. package/dist/cli/commands/vpn.d.ts +4 -0
  80. package/dist/cli/commands/vpn.js +75 -0
  81. package/dist/cli/commands/web.d.ts +4 -0
  82. package/dist/cli/commands/web.js +95 -0
  83. package/dist/cli/history.js +1 -1
  84. package/dist/cli/index.js +46 -3
  85. package/dist/cli/manifest.d.ts +303 -29
  86. package/dist/cli/manifest.js +173 -43
  87. package/dist/cli/menu/add-agent.d.ts +47 -0
  88. package/dist/cli/menu/add-agent.js +168 -0
  89. package/dist/cli/menu/apps.d.ts +31 -2
  90. package/dist/cli/menu/apps.js +44 -5
  91. package/dist/cli/menu/command-fields.d.ts +18 -0
  92. package/dist/cli/menu/command-fields.js +61 -0
  93. package/dist/cli/menu/command-form.d.ts +22 -0
  94. package/dist/cli/menu/command-form.js +169 -46
  95. package/dist/cli/menu/data-folder.d.ts +18 -0
  96. package/dist/cli/menu/data-folder.js +99 -0
  97. package/dist/cli/menu/menu.d.ts +1 -1
  98. package/dist/cli/menu/menu.js +11 -8
  99. package/dist/cli/menu/pages/accounts-page.js +55 -24
  100. package/dist/cli/menu/pages/agents-page.d.ts +66 -0
  101. package/dist/cli/menu/pages/agents-page.js +338 -0
  102. package/dist/cli/menu/pages/apps-page.js +1 -2
  103. package/dist/cli/menu/pages/list-page.d.ts +16 -3
  104. package/dist/cli/menu/pages/list-page.js +40 -8
  105. package/dist/cli/menu/pages/maintenance-page.d.ts +9 -0
  106. package/dist/cli/menu/pages/maintenance-page.js +161 -72
  107. package/dist/cli/menu/pages/sandbox-page.d.ts +3 -0
  108. package/dist/cli/menu/pages/sandbox-page.js +132 -43
  109. package/dist/cli/menu/pages/sessions-page.d.ts +4 -0
  110. package/dist/cli/menu/pages/sessions-page.js +41 -25
  111. package/dist/cli/menu/pages/settings-page.d.ts +8 -4
  112. package/dist/cli/menu/pages/settings-page.js +36 -13
  113. package/dist/cli/menu/settings/categories.d.ts +2 -0
  114. package/dist/cli/menu/settings/categories.js +19 -44
  115. package/dist/cli/menu/settings/collections/collection-editor.d.ts +7 -1
  116. package/dist/cli/menu/settings/collections/collection-editor.js +12 -8
  117. package/dist/cli/menu/settings/collections/map-editor.js +5 -1
  118. package/dist/cli/menu/settings/collections/object-list-editor.js +2 -2
  119. package/dist/cli/menu/settings/collections/object-map-editor.js +2 -2
  120. package/dist/cli/menu/settings/collections/string-list-editor.d.ts +11 -1
  121. package/dist/cli/menu/settings/collections/string-list-editor.js +23 -0
  122. package/dist/cli/menu/settings/index.d.ts +1 -1
  123. package/dist/cli/menu/settings/index.js +1 -1
  124. package/dist/cli/menu/settings/object-editor.d.ts +5 -1
  125. package/dist/cli/menu/settings/object-editor.js +15 -4
  126. package/dist/cli/menu/settings/path-kind.d.ts +20 -0
  127. package/dist/cli/menu/settings/path-kind.js +44 -0
  128. package/dist/cli/menu/settings/schema-node.d.ts +9 -0
  129. package/dist/cli/menu/settings/schema-node.js +26 -0
  130. package/dist/cli/menu/settings/value-editor.d.ts +5 -0
  131. package/dist/cli/menu/settings/value-editor.js +51 -18
  132. package/dist/cli/menu/several.js +7 -5
  133. package/dist/cli/menu/shell.d.ts +37 -10
  134. package/dist/cli/menu/shell.js +90 -10
  135. package/dist/cli/menu/vpn-login.d.ts +16 -0
  136. package/dist/cli/menu/vpn-login.js +66 -0
  137. package/dist/cli/output/print.d.ts +2 -0
  138. package/dist/cli/output/print.js +8 -1
  139. package/dist/cli/services/accounts-service.d.ts +2 -0
  140. package/dist/cli/services/accounts-service.js +2 -2
  141. package/dist/cli/services/health-service.d.ts +0 -6
  142. package/dist/cli/services/health-service.js +5 -42
  143. package/dist/cli/services/index.d.ts +3 -1
  144. package/dist/cli/services/index.js +3 -1
  145. package/dist/cli/services/migrate-service.js +1 -1
  146. package/dist/cli/services/update-service.d.ts +2 -0
  147. package/dist/cli/services/update-service.js +13 -6
  148. package/dist/cli/services/vpn-service.d.ts +28 -0
  149. package/dist/cli/services/vpn-service.js +46 -0
  150. package/dist/cli/services/web-service.d.ts +22 -0
  151. package/dist/cli/services/web-service.js +111 -0
  152. package/dist/cli/tui/app.d.ts +6 -3
  153. package/dist/cli/tui/app.js +12 -5
  154. package/dist/cli/tui/dialogs/path-listing.d.ts +43 -0
  155. package/dist/cli/tui/dialogs/path-listing.js +127 -0
  156. package/dist/cli/tui/dialogs/path-picker.d.ts +67 -0
  157. package/dist/cli/tui/dialogs/path-picker.js +423 -0
  158. package/dist/cli/tui/dialogs/text-screen.d.ts +6 -0
  159. package/dist/cli/tui/dialogs/text-screen.js +10 -3
  160. package/dist/cli/tui/frame.d.ts +7 -10
  161. package/dist/cli/tui/frame.js +19 -10
  162. package/dist/cli/tui/index.d.ts +4 -3
  163. package/dist/cli/tui/index.js +2 -1
  164. package/dist/cli/tui/list/list-screen.d.ts +14 -2
  165. package/dist/cli/tui/list/list-screen.js +68 -32
  166. package/dist/cli/tui/list/list-types.d.ts +8 -4
  167. package/dist/cli/tui/nav.d.ts +29 -0
  168. package/dist/cli/tui/nav.js +67 -0
  169. package/dist/cli/validate.d.ts +1 -1
  170. package/dist/cli/validate.js +3 -3
  171. package/dist/cli/version.d.ts +2 -0
  172. package/dist/cli/version.js +11 -0
  173. package/dist/core/config/defaults.js +5 -1
  174. package/dist/core/config/loader.js +12 -2
  175. package/dist/core/local-config/overrides.js +1 -0
  176. package/dist/core/prompt.d.ts +19 -0
  177. package/dist/core/prompt.js +43 -3
  178. package/dist/core/schema/common.d.ts +6 -0
  179. package/dist/core/schema/common.js +8 -0
  180. package/dist/core/schema/config.d.ts +23 -0
  181. package/dist/core/schema/config.js +10 -1
  182. package/dist/core/schema/harness.d.ts +1 -0
  183. package/dist/core/schema/harness.js +8 -2
  184. package/dist/core/schema/index.d.ts +3 -1
  185. package/dist/core/schema/index.js +3 -1
  186. package/dist/core/schema/profile.d.ts +1 -0
  187. package/dist/core/schema/profile.js +3 -0
  188. package/dist/core/schema/redact.d.ts +13 -0
  189. package/dist/core/schema/redact.js +75 -0
  190. package/dist/core/schema/sandbox.js +1 -0
  191. package/dist/core/schema/vpn.d.ts +17 -0
  192. package/dist/core/schema/vpn.js +22 -0
  193. package/dist/core/schema/web.d.ts +6 -0
  194. package/dist/core/schema/web.js +14 -0
  195. package/dist/core/types.d.ts +26 -0
  196. package/dist/guest/agents/agent-files.d.ts +49 -0
  197. package/dist/guest/agents/agent-files.js +63 -0
  198. package/dist/guest/agents/agent-installer.js +2 -9
  199. package/dist/guest/agents/local-state.d.ts +12 -0
  200. package/dist/guest/agents/local-state.js +198 -0
  201. package/dist/guest/agents/sbx-agent.d.ts +2 -0
  202. package/dist/guest/agents/sbx-agent.js +35 -0
  203. package/dist/guest/boot/boot.d.ts +4 -0
  204. package/dist/guest/boot/boot.js +50 -11
  205. package/dist/guest/daemon/daemon.js +4 -1
  206. package/dist/guest/daemon/exec.js +2 -1
  207. package/dist/guest/daemon/idle-shutdown.js +2 -0
  208. package/dist/guest/daemon/sessions.js +4 -1
  209. package/dist/guest/entries/agent.d.ts +1 -0
  210. package/dist/guest/entries/agent.js +10 -0
  211. package/dist/guest/entries/daemon.js +2 -0
  212. package/dist/guest/runtime/csc.d.ts +1 -0
  213. package/dist/guest/runtime/csc.js +1 -0
  214. package/dist/guest/runtime/secrets.d.ts +12 -0
  215. package/dist/guest/runtime/secrets.js +63 -0
  216. package/dist/guest/setup/claude-profile.d.ts +2 -1
  217. package/dist/guest/setup/claude-profile.js +12 -1
  218. package/dist/guest/setup/environment.d.ts +6 -0
  219. package/dist/guest/setup/environment.js +56 -6
  220. package/dist/guest/setup/path-plan.d.ts +32 -0
  221. package/dist/guest/setup/path-plan.js +67 -0
  222. package/dist/guest/setup/shell-path.d.ts +1 -0
  223. package/dist/guest/setup/shell-path.js +22 -0
  224. package/dist/guest/toolchains/languages/python.js +1 -1
  225. package/dist/guest/toolchains/runtimes.js +2 -2
  226. package/dist/guest/vpn/index.d.ts +1 -0
  227. package/dist/guest/vpn/index.js +1 -0
  228. package/dist/guest/vpn/openvpn.d.ts +9 -0
  229. package/dist/guest/vpn/openvpn.js +47 -0
  230. package/dist/guest/vpn/tunnel.d.ts +17 -0
  231. package/dist/guest/vpn/tunnel.js +78 -0
  232. package/dist/guest/vpn/vpn.d.ts +6 -0
  233. package/dist/guest/vpn/vpn.js +126 -0
  234. package/dist/host/channel/attach.d.ts +3 -1
  235. package/dist/host/channel/attach.js +1 -1
  236. package/dist/host/channel/channel.d.ts +7 -0
  237. package/dist/host/channel/channel.js +26 -2
  238. package/dist/host/health/acl-read.d.ts +17 -0
  239. package/dist/host/health/acl-read.js +45 -0
  240. package/dist/host/health/config-backup.d.ts +11 -0
  241. package/dist/host/health/config-backup.js +73 -0
  242. package/dist/host/health/index.d.ts +6 -0
  243. package/dist/host/health/index.js +7 -0
  244. package/dist/host/health/install-state.d.ts +33 -0
  245. package/dist/host/health/install-state.js +110 -0
  246. package/dist/host/health/path-copies.d.ts +32 -0
  247. package/dist/host/health/path-copies.js +82 -0
  248. package/dist/host/health/stale.d.ts +45 -0
  249. package/dist/host/health/stale.js +120 -0
  250. package/dist/host/health/system.d.ts +37 -0
  251. package/dist/host/health/system.js +87 -0
  252. package/dist/host/install/copies.d.ts +13 -0
  253. package/dist/host/install/copies.js +63 -0
  254. package/dist/host/install/index.d.ts +1 -0
  255. package/dist/host/install/index.js +1 -0
  256. package/dist/host/launch/generate.js +25 -1
  257. package/dist/host/launch/session-file.js +4 -1
  258. package/dist/host/launch/stage.js +1 -1
  259. package/dist/host/migrate/backup.js +3 -0
  260. package/dist/host/migrate/migrations/config-file.d.ts +2 -0
  261. package/dist/host/migrate/migrations/config-file.js +7 -0
  262. package/dist/host/migrate/migrations/follow-machine-storage.js +9 -1
  263. package/dist/host/migrate/migrations/pin-storage-root.d.ts +4 -0
  264. package/dist/host/migrate/migrations/pin-storage-root.js +46 -0
  265. package/dist/host/migrate/migrations/unpin-config-defaults.js +4 -1
  266. package/dist/host/migrate/registry.js +2 -1
  267. package/dist/host/profile/accounts.d.ts +25 -1
  268. package/dist/host/profile/accounts.js +96 -13
  269. package/dist/host/profile/agent-accounts.d.ts +5 -1
  270. package/dist/host/profile/agent-accounts.js +35 -5
  271. package/dist/host/profile/index.d.ts +2 -1
  272. package/dist/host/profile/index.js +1 -0
  273. package/dist/host/profile/plugin-share.d.ts +26 -0
  274. package/dist/host/profile/plugin-share.js +146 -0
  275. package/dist/host/projects/join.d.ts +7 -1
  276. package/dist/host/projects/join.js +21 -4
  277. package/dist/host/projects/registry.d.ts +16 -10
  278. package/dist/host/projects/registry.js +74 -6
  279. package/dist/host/sandbox/platform.d.ts +2 -0
  280. package/dist/host/sandbox/platform.js +21 -2
  281. package/dist/host/secrets/index.d.ts +2 -0
  282. package/dist/host/secrets/index.js +2 -0
  283. package/dist/host/secrets/launch-secrets.d.ts +17 -0
  284. package/dist/host/secrets/launch-secrets.js +93 -0
  285. package/dist/host/secrets/secret-store.d.ts +25 -0
  286. package/dist/host/secrets/secret-store.js +89 -0
  287. package/dist/host/sharing/acl.d.ts +16 -2
  288. package/dist/host/sharing/acl.js +35 -10
  289. package/dist/host/sharing/current.js +11 -2
  290. package/dist/host/sharing/doctor.d.ts +2 -0
  291. package/dist/host/sharing/doctor.js +44 -0
  292. package/dist/host/sharing/group-access.d.ts +6 -0
  293. package/dist/host/sharing/group-access.js +24 -0
  294. package/dist/host/sharing/index.d.ts +2 -1
  295. package/dist/host/sharing/index.js +2 -1
  296. package/dist/host/sharing/lifecycle.d.ts +8 -2
  297. package/dist/host/sharing/lifecycle.js +16 -7
  298. package/dist/host/storage/cleanup.d.ts +2 -0
  299. package/dist/host/storage/cleanup.js +2 -1
  300. package/dist/host/storage/history.d.ts +21 -0
  301. package/dist/host/storage/history.js +49 -0
  302. package/dist/host/storage/index.d.ts +4 -0
  303. package/dist/host/storage/index.js +4 -0
  304. package/dist/host/storage/move.d.ts +95 -0
  305. package/dist/host/storage/move.js +384 -0
  306. package/dist/host/storage/offer.d.ts +11 -0
  307. package/dist/host/storage/offer.js +36 -0
  308. package/dist/host/storage/root.d.ts +18 -0
  309. package/dist/host/storage/root.js +77 -0
  310. package/dist/host/tools/windows-terminal.d.ts +2 -0
  311. package/dist/host/tools/windows-terminal.js +23 -5
  312. package/dist/host/update/index.d.ts +1 -1
  313. package/dist/host/update/index.js +1 -1
  314. package/dist/host/update/notice.d.ts +2 -0
  315. package/dist/host/update/notice.js +13 -1
  316. package/dist/host/update/update-state.d.ts +6 -0
  317. package/dist/host/update/update-state.js +2 -0
  318. package/dist/host/update/updater.d.ts +19 -0
  319. package/dist/host/update/updater.js +88 -12
  320. package/dist/host/vpn/index.d.ts +4 -0
  321. package/dist/host/vpn/index.js +4 -0
  322. package/dist/host/vpn/login.d.ts +24 -0
  323. package/dist/host/vpn/login.js +79 -0
  324. package/dist/host/vpn/nordvpn.d.ts +21 -0
  325. package/dist/host/vpn/nordvpn.js +77 -0
  326. package/dist/host/vpn/prepare.d.ts +17 -0
  327. package/dist/host/vpn/prepare.js +77 -0
  328. package/dist/host/vpn/status.d.ts +12 -0
  329. package/dist/host/vpn/status.js +53 -0
  330. package/dist/host/web/auth.d.ts +38 -0
  331. package/dist/host/web/auth.js +96 -0
  332. package/dist/host/web/backend.d.ts +14 -0
  333. package/dist/host/web/backend.js +1 -0
  334. package/dist/host/web/bridge.d.ts +27 -0
  335. package/dist/host/web/bridge.js +144 -0
  336. package/dist/host/web/browser.d.ts +1 -0
  337. package/dist/host/web/browser.js +10 -0
  338. package/dist/host/web/control.d.ts +17 -0
  339. package/dist/host/web/control.js +67 -0
  340. package/dist/host/web/index.d.ts +9 -0
  341. package/dist/host/web/index.js +8 -0
  342. package/dist/host/web/runner.d.ts +14 -0
  343. package/dist/host/web/runner.js +45 -0
  344. package/dist/host/web/server.d.ts +40 -0
  345. package/dist/host/web/server.js +218 -0
  346. package/dist/host/web/state.d.ts +20 -0
  347. package/dist/host/web/state.js +41 -0
  348. package/dist/host/web/static-files.d.ts +13 -0
  349. package/dist/host/web/static-files.js +57 -0
  350. package/dist/runtime/agent.js +27614 -0
  351. package/dist/runtime/daemon.js +1012 -618
  352. package/dist/runtime/db.js +236 -106
  353. package/dist/runtime/main.js +1093 -250
  354. package/dist/runtime/netproxy.js +102 -3
  355. package/dist/runtime/view.js +102 -3
  356. package/dist/selftest/accounts.test.js +40 -0
  357. package/dist/selftest/agent-paths.test.d.ts +2 -0
  358. package/dist/selftest/agent-paths.test.js +115 -0
  359. package/dist/selftest/channel.test.js +5 -0
  360. package/dist/selftest/cli.test.js +34 -4
  361. package/dist/selftest/credentials.test.d.ts +2 -0
  362. package/dist/selftest/credentials.test.js +198 -0
  363. package/dist/selftest/generate.test.js +1 -1
  364. package/dist/selftest/health.test.d.ts +2 -0
  365. package/dist/selftest/health.test.js +470 -0
  366. package/dist/selftest/host-sim.test.js +2 -0
  367. package/dist/selftest/index.js +19 -0
  368. package/dist/selftest/layout.test.js +2 -0
  369. package/dist/selftest/menu-screens.d.ts +7 -0
  370. package/dist/selftest/menu-screens.js +65 -16
  371. package/dist/selftest/menu.test.js +574 -21
  372. package/dist/selftest/migrate.test.js +1 -1
  373. package/dist/selftest/personalization.test.js +3 -1
  374. package/dist/selftest/projects.test.js +39 -1
  375. package/dist/selftest/shared-use.test.js +64 -2
  376. package/dist/selftest/sharing.test.js +50 -1
  377. package/dist/selftest/storage.test.d.ts +2 -0
  378. package/dist/selftest/storage.test.js +363 -0
  379. package/dist/selftest/support/fixtures.d.ts +14 -0
  380. package/dist/selftest/support/releases.js +1 -1
  381. package/dist/selftest/toolchains.test.js +21 -0
  382. package/dist/selftest/update-service.test.js +87 -3
  383. package/dist/selftest/vpn.test.d.ts +2 -0
  384. package/dist/selftest/vpn.test.js +279 -0
  385. package/dist/selftest/web.test.d.ts +2 -0
  386. package/dist/selftest/web.test.js +304 -0
  387. package/dist/shared/apps/catalogue.js +31 -0
  388. package/dist/shared/channel/index.d.ts +1 -0
  389. package/dist/shared/channel/index.js +1 -0
  390. package/dist/shared/channel/run-dir.d.ts +6 -1
  391. package/dist/shared/channel/run-dir.js +12 -1
  392. package/dist/shared/channel/schema.d.ts +19 -0
  393. package/dist/shared/channel/schema.js +11 -0
  394. package/dist/shared/channel/secrets.d.ts +28 -0
  395. package/dist/shared/channel/secrets.js +44 -0
  396. package/dist/shared/vpn/download.d.ts +13 -0
  397. package/dist/shared/vpn/download.js +14 -0
  398. package/dist/shared/vpn/kill-switch.d.ts +18 -0
  399. package/dist/shared/vpn/kill-switch.js +81 -0
  400. package/dist/shared/vpn/ovpn.d.ts +23 -0
  401. package/dist/shared/vpn/ovpn.js +244 -0
  402. package/dist/shared/web/index.d.ts +1 -0
  403. package/dist/shared/web/index.js +1 -0
  404. package/dist/shared/web/protocol.d.ts +61 -0
  405. package/dist/shared/web/protocol.js +35 -0
  406. package/dist/sync/sync-cycle.js +5 -1
  407. package/dist/sync/sync-state.d.ts +1 -0
  408. package/dist/sync/sync-state.js +1 -0
  409. package/dist/sync/watcher.js +10 -0
  410. package/dist/web/index.html +13 -0
  411. package/dist/web/main-CXESL347.js +45 -0
  412. package/dist/web/main-VLR7DVQ4.css +1 -0
  413. package/native/csharp/FolderSecurity.cs +29 -0
  414. package/native/scripts/protect-data.ps1 +29 -0
  415. package/native/scripts/read-folder-sddl.ps1 +10 -0
  416. package/native/scripts/set-folder-access.ps1 +49 -7
  417. package/node_modules/ws/LICENSE +20 -0
  418. package/node_modules/ws/README.md +548 -0
  419. package/node_modules/ws/browser.js +8 -0
  420. package/node_modules/ws/index.js +22 -0
  421. package/node_modules/ws/lib/buffer-util.js +131 -0
  422. package/node_modules/ws/lib/constants.js +19 -0
  423. package/node_modules/ws/lib/event-target.js +292 -0
  424. package/node_modules/ws/lib/extension.js +203 -0
  425. package/node_modules/ws/lib/limiter.js +55 -0
  426. package/node_modules/ws/lib/permessage-deflate.js +530 -0
  427. package/node_modules/ws/lib/receiver.js +743 -0
  428. package/node_modules/ws/lib/sender.js +607 -0
  429. package/node_modules/ws/lib/stream.js +161 -0
  430. package/node_modules/ws/lib/subprotocol.js +62 -0
  431. package/node_modules/ws/lib/validation.js +152 -0
  432. package/node_modules/ws/lib/websocket-server.js +562 -0
  433. package/node_modules/ws/lib/websocket.js +1421 -0
  434. package/node_modules/ws/package.json +74 -0
  435. package/node_modules/ws/wrapper.mjs +21 -0
  436. package/package.json +15 -5
  437. package/sandbox/csharp/EnvBroadcast.cs +33 -0
  438. package/sandbox/csharp/PathSync.cs +90 -0
  439. package/sandbox/scripts/install-shell-path.ps1 +73 -0
  440. package/sandbox/scripts/set-machine-environment.ps1 +37 -4
  441. package/schemas/config.schema.json +79 -4
  442. package/schemas/sandbox-config.schema.json +14 -1
  443. package/dist/cli/commands/repair/checks.d.ts +0 -2
  444. package/dist/cli/commands/repair/checks.js +0 -246
  445. package/dist/cli/menu/pages/start-page.d.ts +0 -43
  446. package/dist/cli/menu/pages/start-page.js +0 -192
  447. package/dist/cli/tui/tab-bar.d.ts +0 -9
  448. package/dist/cli/tui/tab-bar.js +0 -33
@@ -1,246 +0,0 @@
1
- // The repair checks, in the order they run. Each either confirms all is well, fixes the problem itself, or says what
2
- // you need to do. Nothing under the data folder is followed through a link.
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { spawnSync } from 'node:child_process';
6
- import _ from 'lodash';
7
- import { GB, freeBytesAt, humanBytes } from '../../../core/disk.js';
8
- import { assertTestWritable } from '../../../shared/test-guard.js';
9
- import { assertNoLinks, fileExists, isLink, isWin, removeLink } from '../../../core/util/index.js';
10
- import { SandboxChannel } from '../../../host/channel/index.js';
11
- import { sandboxFeatureInstalled } from '../../../host/sandbox/index.js';
12
- import { RunDir } from '../../../shared/channel/index.js';
13
- import { removeTree } from '../data/remove.js';
14
- import { deadPidFiles, findHalfInstalled, findLinks, findStagingLeftovers, globalPackages, resolvedVersionsValid, } from './finders.js';
15
- import { ok, whileRunning } from './types.js';
16
- function rel(root, p) {
17
- return path.relative(root, p) || '.';
18
- }
19
- /** Fails (throws) unless every folder from the data folder to `p` is real. */
20
- function guard(env, p) {
21
- assertNoLinks(path.dirname(env.dataPath), p);
22
- }
23
- export const CHECKS = [
24
- {
25
- name: 'Config file',
26
- run: (env) => env.configError
27
- ? {
28
- status: 'needs-you',
29
- detail: env.configError.message +
30
- (env.configError.fix ? ' ' + env.configError.fix : '') +
31
- ' (repair never rewrites your config; built-in defaults were used for the other checks.)',
32
- }
33
- : ok(env.ctx.loaded.configPath ? env.ctx.loaded.configPath + ' is valid.' : 'none; using the built-in defaults.'),
34
- },
35
- {
36
- name: 'Windows Sandbox feature',
37
- run: () => sandboxFeatureInstalled()
38
- ? ok('enabled.')
39
- : {
40
- status: 'needs-you',
41
- detail: (isWin ? 'Windows Sandbox is not turned on.' : 'This is not Windows.') +
42
- ' Run: sandbox setup (it checks this PC and offers to turn it on).',
43
- },
44
- },
45
- {
46
- name: 'Links in the data folder',
47
- run: (env) => {
48
- if (isLink(env.dataPath))
49
- return {
50
- status: 'needs-you',
51
- detail: env.dataPath +
52
- ' itself is a link or junction. agent-sandbox refuses to work through links; point storage.root at the real folder instead (sandbox config path).',
53
- };
54
- // A running sandbox can swap folders for links while we look; only check a stopped one.
55
- if (env.running)
56
- return whileRunning;
57
- const links = findLinks(env.dataPath);
58
- if (!links.length)
59
- return ok('none (nothing in ' + env.dataPath + ' points elsewhere).');
60
- // A link here can only have been made inside the sandbox; it could point at this PC's own files. Remove the link
61
- // itself, and only if every folder above it is still real.
62
- for (const link of links) {
63
- guard(env, path.dirname(link));
64
- removeLink(link);
65
- }
66
- return {
67
- status: 'fixed',
68
- detail: 'removed ' +
69
- links.length +
70
- ' link(s)/junction(s) the sandbox created, without following them: ' +
71
- links.map((l) => rel(env.dataPath, l)).join(', '),
72
- };
73
- },
74
- },
75
- {
76
- name: 'Sandbox run state',
77
- run: (env) => {
78
- if (env.running)
79
- return ok('a sandbox is running; its state is in use.');
80
- if (isLink(new RunDir(env.dataPath).root)) {
81
- new SandboxChannel(env.dataPath).reset();
82
- return { status: 'fixed', detail: 'the run folder was a link; removed the link itself.' };
83
- }
84
- // The last sandbox's status file is normal after it closes; sessions still marked running or unanswered requests
85
- // are not.
86
- const ghosts = new RunDir(env.dataPath)
87
- .listSessions()
88
- .filter((s) => s.phase === 'running' || s.phase === 'starting').length;
89
- const requests = new RunDir(env.dataPath).scanRequests();
90
- const pending = requests.valid.length + requests.invalid.length;
91
- if (!ghosts && !pending)
92
- return ok('clean.');
93
- new SandboxChannel(env.dataPath).reset();
94
- return {
95
- status: 'fixed',
96
- detail: 'no sandbox is running, but ' +
97
- _.compact([
98
- ghosts && ghosts + ' session(s) were still marked running',
99
- pending && pending + ' request(s) were never answered',
100
- ]).join(' and ') +
101
- '; cleared the run state so status/attach do not show ghosts.',
102
- };
103
- },
104
- },
105
- {
106
- name: 'Hidden-window state',
107
- run: (env) => {
108
- const file = path.join(env.storageRoot, 'run', 'hidden-windows.json');
109
- if (!fs.existsSync(file) && !isLink(file))
110
- return ok('clean.');
111
- if (env.running)
112
- return ok('a sandbox is running; kept.');
113
- assertTestWritable(file);
114
- fs.rmSync(file, { force: true });
115
- return {
116
- status: 'fixed',
117
- detail: 'removed the saved hidden-window list from a sandbox that is no longer running.',
118
- };
119
- },
120
- },
121
- {
122
- name: 'Sync watcher',
123
- run: (env) => {
124
- const dead = deadPidFiles(path.join(env.storageRoot, 'run'));
125
- if (!dead.length)
126
- return ok('no stale watcher records.');
127
- for (const f of dead) {
128
- assertTestWritable(f);
129
- fs.rmSync(f, { force: true });
130
- }
131
- return {
132
- status: 'fixed',
133
- detail: 'removed ' +
134
- dead.length +
135
- ' record(s) of a history sync watcher that is no longer running (the next launch starts a new one).',
136
- };
137
- },
138
- },
139
- {
140
- name: 'Interrupted downloads',
141
- run: (env) => {
142
- if (env.running)
143
- return whileRunning;
144
- guard(env, env.toolsDir);
145
- const found = findStagingLeftovers(env.toolsDir);
146
- if (!found.length)
147
- return ok('none.');
148
- for (const p of found)
149
- removeTree(p, env.dataPath);
150
- return {
151
- status: 'fixed',
152
- detail: 'removed ' +
153
- found.length +
154
- ' half-finished download/copy folder(s): ' +
155
- found.map((p) => rel(env.toolsDir, p)).join(', '),
156
- };
157
- },
158
- },
159
- {
160
- name: 'Half-installed toolchains',
161
- run: (env) => {
162
- if (env.running)
163
- return whileRunning;
164
- guard(env, env.toolsDir);
165
- const found = findHalfInstalled(env.toolsDir);
166
- if (!found.length)
167
- return ok('every toolchain folder has its program.');
168
- for (const f of found)
169
- removeTree(f.path, env.dataPath);
170
- return {
171
- status: 'fixed',
172
- detail: 'removed ' +
173
- found.map((f) => rel(env.toolsDir, f.path) + ' (no ' + f.missing + ')').join(', ') +
174
- '; the next sandbox reinstalls them.',
175
- };
176
- },
177
- },
178
- {
179
- name: 'Resolved versions cache',
180
- run: (env) => {
181
- const file = path.join(env.toolsDir, 'resolved-versions.json');
182
- if (!fs.existsSync(file) && !isLink(file))
183
- return ok('not created yet.');
184
- if (env.running)
185
- return whileRunning;
186
- guard(env, env.toolsDir);
187
- if (isLink(file)) {
188
- removeLink(file);
189
- return { status: 'fixed', detail: 'removed a link in place of tools\\resolved-versions.json.' };
190
- }
191
- if (fs.statSync(file).size < 4 * 1024 * 1024 && resolvedVersionsValid(fs.readFileSync(file, 'utf8')))
192
- return ok('valid.');
193
- assertTestWritable(file);
194
- fs.rmSync(file, { force: true });
195
- return {
196
- status: 'fixed',
197
- detail: 'tools\\resolved-versions.json was damaged; removed it (versions are looked up again on the next start).',
198
- };
199
- },
200
- },
201
- {
202
- name: 'Installed packages',
203
- run: () => {
204
- const npmCli = path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js');
205
- if (!fileExists(npmCli))
206
- return { status: 'skipped', detail: 'npm not found next to this Node (' + npmCli + ').' };
207
- // cwd = Node's own folder: npm reads .npmrc from the current folder, which could be a sandbox-writable workspace.
208
- const result = spawnSync(process.execPath, [npmCli, 'ls', '-g', '--json', '--depth=0'], {
209
- cwd: path.dirname(process.execPath),
210
- encoding: 'utf8',
211
- windowsHide: true,
212
- timeout: 60000,
213
- maxBuffer: 16 * 1024 * 1024,
214
- });
215
- const names = globalPackages(result.stdout ?? '');
216
- if (!names.length)
217
- return { status: 'skipped', detail: 'could not read the global npm packages.' };
218
- if (names.includes('agent-sandbox') && names.includes('windows-development-sandbox'))
219
- return {
220
- status: 'needs-you',
221
- detail: 'the old agent-sandbox package is still installed next to windows-development-sandbox, and their commands clash. Run: npm uninstall -g agent-sandbox',
222
- };
223
- return ok(names.includes('agent-sandbox')
224
- ? 'agent-sandbox installed (the old name; fine on its own).'
225
- : 'no old agent-sandbox package.');
226
- },
227
- },
228
- {
229
- name: 'Free disk',
230
- run: (env) => {
231
- const free = freeBytesAt(env.storageRoot);
232
- if (free === null)
233
- return { status: 'skipped', detail: 'could not check the drive of ' + env.storageRoot };
234
- if (free >= 20 * GB)
235
- return ok(humanBytes(free) + ' free.');
236
- return {
237
- status: 'warn',
238
- detail: humanBytes(free) +
239
- ' free on the drive of ' +
240
- env.storageRoot +
241
- (free < 5 * GB ? ': toolchains need several GB.' : ': getting low.') +
242
- ' See what is stored with: sandbox data, and free space with: sandbox data clean <target>',
243
- };
244
- },
245
- },
246
- ];
@@ -1,43 +0,0 @@
1
- import type { Context } from '../../commands/context.js';
2
- import { type App, type ListOptions, type ListResult } from '../../tui/index.js';
3
- import { ListPage, type Outcome } from './list-page.js';
4
- export type WindowChoice = 'config' | 'hide' | 'show';
5
- export interface StartModel {
6
- readonly folder: string;
7
- readonly defaultAgent: string;
8
- readonly agents: readonly {
9
- readonly name: string;
10
- readonly ready: boolean;
11
- }[];
12
- readonly last: string[] | undefined;
13
- readonly attach: boolean;
14
- readonly window: WindowChoice;
15
- /** Agents that can be run on this PC without the sandbox (see hostAgentsToShow). */
16
- readonly hostAgents: readonly string[];
17
- }
18
- /**
19
- * The "not sandboxed" entries: only while agent commands are on (typing the agent then starts the sandbox, so a way to
20
- * run the real one is needed), one per agent found installed on this PC.
21
- */
22
- export declare function hostAgentsToShow(enabled: boolean, found: readonly {
23
- harness: string;
24
- }[]): string[];
25
- /** The command line a start stands for. Pure. */
26
- export declare function startArgv(m: StartModel, agent: string, cwd: string): string[];
27
- /** The list for the start tab. Pure. */
28
- export declare function startOptions(m: StartModel, cwd?: string): ListOptions<string>;
29
- export declare class StartPage extends ListPage<string> {
30
- private readonly ctx;
31
- readonly label = "Start";
32
- private attach;
33
- private window;
34
- private folder;
35
- private model;
36
- constructor(app: App, ctx: Context);
37
- /** Is this agent already in the sandbox's persistent storage (so starting it needs no install)? */
38
- private installed;
39
- private current;
40
- protected load(): Promise<void>;
41
- protected options(): ListOptions<string>;
42
- protected act(result: ListResult<string>): Promise<Outcome<string>>;
43
- }
@@ -1,192 +0,0 @@
1
- // Tab 1: start an agent here. The agents are listed (Enter starts one), with the few options that matter right under
2
- // them; everything else is behind "More options…" (the full start form).
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { commandLine, readHistory } from '../../history.js';
6
- import { AgentCommandsService } from '../../services/index.js';
7
- import { commandSpec } from '../../manifest.js';
8
- import { Text, Theme } from '../../tui/index.js';
9
- import { CommandForm } from '../command-form.js';
10
- import { SeveralAgents } from '../several.js';
11
- import { ListPage } from './list-page.js';
12
- /**
13
- * The "not sandboxed" entries: only while agent commands are on (typing the agent then starts the sandbox, so a way to
14
- * run the real one is needed), one per agent found installed on this PC.
15
- */
16
- export function hostAgentsToShow(enabled, found) {
17
- return enabled ? found.map((a) => a.harness) : [];
18
- }
19
- const WINDOW_TEXT = { config: 'as configured', hide: 'hidden', show: 'shown' };
20
- /** The command line a start stands for. Pure. */
21
- export function startArgv(m, agent, cwd) {
22
- return [
23
- 'launch',
24
- '--harness',
25
- agent,
26
- ...(m.attach ? ['--terminal'] : []),
27
- ...(m.window === 'hide' ? ['--headless'] : m.window === 'show' ? ['--window'] : []),
28
- ...(path.resolve(m.folder).toLowerCase() === path.resolve(cwd).toLowerCase() ? [] : ['--workspace', m.folder]),
29
- ];
30
- }
31
- /** The list for the start tab. Pure. */
32
- export function startOptions(m, cwd = process.cwd()) {
33
- const section = 'Start in ' + path.basename(m.folder);
34
- const agents = [...m.agents].sort((a, b) => Number(b.name === m.defaultAgent) - Number(a.name === m.defaultAgent));
35
- return {
36
- path: [],
37
- intro: m.folder,
38
- items: [
39
- ...(m.last
40
- ? [
41
- {
42
- value: 'repeat',
43
- label: 'Repeat last',
44
- section: 'Quick start',
45
- hint: Theme.muted(Text.truncate(commandLine(m.last), 50)),
46
- description: 'Runs the last command again.',
47
- },
48
- ]
49
- : []),
50
- ...agents.map((a) => ({
51
- value: 'agent:' + a.name,
52
- label: 'Start ' + a.name,
53
- section,
54
- hint: (a.name === m.defaultAgent ? Theme.accent('default ') : '') +
55
- (a.ready ? Theme.ok('ready') : Theme.muted('installs on first start')),
56
- description: 'Runs: ' + commandLine(startArgv(m, a.name, cwd)),
57
- })),
58
- {
59
- value: 'opt:attach',
60
- label: 'Attach this terminal',
61
- section: 'Options',
62
- hint: m.attach ? Theme.ok('yes') : Theme.muted('no'),
63
- description: 'Shows the agent in this terminal (Ctrl+] detaches). Without it the agent runs in the sandbox.',
64
- },
65
- {
66
- value: 'opt:window',
67
- label: 'Sandbox window',
68
- section: 'Options',
69
- hint: WINDOW_TEXT[m.window],
70
- description: 'Hide or show the Windows Sandbox window (sbx-show brings a hidden one back).',
71
- },
72
- {
73
- value: 'opt:folder',
74
- label: 'Folder',
75
- section: 'Options',
76
- hint: Text.middle(m.folder, 40),
77
- description: 'The project folder to work on.',
78
- },
79
- ...m.hostAgents.map((agent) => ({
80
- value: 'host:' + agent,
81
- label: 'Run ' + agent + ' on this PC (not sandboxed)',
82
- section: 'Not sandboxed',
83
- description: 'Runs the real ' + agent + ' on this PC, with no sandbox around it.',
84
- })),
85
- {
86
- value: 'more',
87
- label: 'More options…',
88
- section: 'More',
89
- description: 'Node and Python versions, databases, scripts and the rest of the start form.',
90
- },
91
- {
92
- value: 'several',
93
- label: 'Start several agents…',
94
- section: 'More',
95
- description: 'One or more projects, one or more agents each, all in one sandbox.',
96
- },
97
- {
98
- value: 'noagent',
99
- label: 'Start a sandbox without an agent…',
100
- section: 'More',
101
- description: 'Tools and databases only.',
102
- },
103
- ],
104
- enterLabel: 'start',
105
- escapeLabel: 'quit',
106
- };
107
- }
108
- export class StartPage extends ListPage {
109
- ctx;
110
- label = 'Start';
111
- attach = false;
112
- window = 'config';
113
- folder = process.cwd();
114
- model;
115
- constructor(app, ctx) {
116
- super(app);
117
- this.ctx = ctx;
118
- }
119
- /** Is this agent already in the sandbox's persistent storage (so starting it needs no install)? */
120
- installed(name) {
121
- const h = this.ctx.loaded.config.harnesses[name];
122
- const dir = path.join(this.ctx.dataPath, 'tools', 'agents', name);
123
- return (Boolean(h) &&
124
- [h.hostExecutable, h.npmBin && h.npmBin + '.cmd', h.uvBin && h.uvBin + '.exe'].some((f) => f && fs.existsSync(path.join(dir, f))));
125
- }
126
- current() {
127
- const config = this.ctx.loaded.config;
128
- const commands = new AgentCommandsService(this.ctx).status();
129
- return {
130
- folder: this.folder,
131
- defaultAgent: config.defaultHarness,
132
- agents: Object.keys(config.harnesses).map((name) => ({ name, ready: this.installed(name) })),
133
- last: readHistory()[0]?.argv,
134
- attach: this.attach,
135
- window: this.window,
136
- hostAgents: hostAgentsToShow(commands.enabled, commands.found),
137
- };
138
- }
139
- load() {
140
- this.model = this.current();
141
- return Promise.resolve();
142
- }
143
- options() {
144
- this.model = this.current();
145
- return startOptions(this.model);
146
- }
147
- async act(result) {
148
- if (result.kind !== 'pick')
149
- return {};
150
- const id = result.value;
151
- const model = this.current();
152
- if (id.startsWith('host:'))
153
- return { exit: { kind: 'run', argv: ['host', id.slice(5)] } };
154
- if (id.startsWith('agent:'))
155
- return { exit: { kind: 'run', argv: startArgv(model, id.slice(6), process.cwd()) } };
156
- switch (id) {
157
- case 'repeat':
158
- return model.last ? { exit: { kind: 'run', argv: model.last } } : {};
159
- case 'opt:attach':
160
- this.attach = !this.attach;
161
- return {};
162
- case 'opt:window':
163
- this.window = this.window === 'config' ? 'hide' : this.window === 'hide' ? 'show' : 'config';
164
- return {};
165
- case 'opt:folder': {
166
- const typed = await this.app.text({
167
- path: ['Start', 'Folder'],
168
- label: 'Project folder',
169
- initial: this.folder,
170
- validate: (v) => (fs.existsSync(path.resolve(v)) ? true : 'That folder does not exist.'),
171
- });
172
- if (typed)
173
- this.folder = path.resolve(typed);
174
- return {};
175
- }
176
- case 'more': {
177
- const argv = await new CommandForm(this.app, this.ctx, commandSpec('launch'), startArgv(model, model.defaultAgent, process.cwd()).slice(1)).run();
178
- return argv ? { exit: { kind: 'run', argv } } : {};
179
- }
180
- case 'several': {
181
- const argv = await new SeveralAgents(this.app, this.ctx).run();
182
- return argv ? { exit: { kind: 'run', argv } } : {};
183
- }
184
- case 'noagent': {
185
- const argv = await new CommandForm(this.app, this.ctx, commandSpec('start')).run();
186
- return argv ? { exit: { kind: 'run', argv } } : {};
187
- }
188
- default:
189
- return {};
190
- }
191
- }
192
- }
@@ -1,9 +0,0 @@
1
- export interface TabInfo {
2
- readonly label: string;
3
- /** Something is waiting in this tab (unsaved changes). */
4
- readonly marked?: boolean;
5
- }
6
- export declare class TabBar {
7
- /** One line, exactly `width` columns wide: full names, then tighter, then numbers, then only the open tab. */
8
- static render(tabs: readonly TabInfo[], active: number, width: number): string;
9
- }
@@ -1,33 +0,0 @@
1
- // The tabs across the top of every screen: a number and a name each, shortened when the terminal is narrow.
2
- import { Text } from './text.js';
3
- import { Theme } from './theme.js';
4
- export class TabBar {
5
- /** One line, exactly `width` columns wide: full names, then tighter, then numbers, then only the open tab. */
6
- static render(tabs, active, width) {
7
- const paint = (text, on) => (on ? Theme.selected(text) : Theme.muted(text));
8
- const mark = (tab) => (tab.marked ? Theme.changed(Theme.glyph.changed) : '');
9
- const build = (pad, shown) => tabs
10
- .map((tab, i) => {
11
- const text = shown(i) + (tab.marked ? ' ' + Text.strip(mark(tab)) : '');
12
- // The open tab is in brackets too, so it shows without colour.
13
- if (i === active) {
14
- const space = ' '.repeat(Math.max(0, pad - 1));
15
- return paint(space + '[' + text + ']' + space, true);
16
- }
17
- return paint(' '.repeat(pad) + text + ' '.repeat(pad), false);
18
- })
19
- .join('');
20
- const full = (i) => i + 1 + ' ' + tabs[i].label;
21
- const attempts = [
22
- build(2, full),
23
- build(1, full),
24
- build(1, (i) => (i === active ? full(i) : String(i + 1))),
25
- build(0, (i) => (i === active ? full(i) : String(i + 1))),
26
- ];
27
- const fits = attempts.find((line) => Text.width(line) <= width - 1);
28
- if (fits)
29
- return Text.fit(fits, width);
30
- const only = '[' + (active + 1) + '/' + tabs.length + ' ' + tabs[active].label + ']';
31
- return Text.fit(Theme.selected(only), width);
32
- }
33
- }