@minionry/minion 0.7.36

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 (476) hide show
  1. package/LICENSE +14 -0
  2. package/PRIVACY.md +357 -0
  3. package/README.md +57 -0
  4. package/THIRD_PARTY_NOTICES.md +245 -0
  5. package/bin/branding.js +4 -0
  6. package/bin/commands/browser-install.js +483 -0
  7. package/bin/commands/create-sandbox.js +542 -0
  8. package/bin/commands/fingerprint.js +101 -0
  9. package/bin/commands/login.js +400 -0
  10. package/bin/commands/logout.js +93 -0
  11. package/bin/commands/minions.js +211 -0
  12. package/bin/commands/sandboxes.js +309 -0
  13. package/bin/commands/status.js +298 -0
  14. package/bin/commands/whoami.js +153 -0
  15. package/bin/launch-env.js +35 -0
  16. package/bin/machine-identity.js +221 -0
  17. package/bin/machine-layout.js +200 -0
  18. package/bin/minion.js +839 -0
  19. package/bin/platform-endpoints.js +8 -0
  20. package/bin/postinstall.js +52 -0
  21. package/bin/pty-doctor.js +326 -0
  22. package/bin/pty-locator.js +110 -0
  23. package/bin/pty-provision.js +186 -0
  24. package/bin/sandbox/Dockerfile +78 -0
  25. package/bin/sandbox/entrypoint.sh +14 -0
  26. package/bin/sandbox/install-repo.sh +53 -0
  27. package/bin/sandbox/seccomp-userns.json +883 -0
  28. package/bin/sandbox-config.js +306 -0
  29. package/dist/bin/machine-identity.js +221 -0
  30. package/dist/bin/machine-layout.js +200 -0
  31. package/dist/electron-host/agent-lease.js +141 -0
  32. package/dist/electron-host/dom-driver.js +642 -0
  33. package/dist/electron-host/ipc-protocol.js +89 -0
  34. package/dist/electron-host/js-driver.js +216 -0
  35. package/dist/electron-host/view-manager.js +254 -0
  36. package/dist/server/cli/engine-resume.js +49 -0
  37. package/dist/server/cli/eta-estimator.js +278 -0
  38. package/dist/server/cli/headless/background-activity.js +109 -0
  39. package/dist/server/cli/headless/claude-invoker-process.js +614 -0
  40. package/dist/server/cli/headless/claude-invoker-stall.js +150 -0
  41. package/dist/server/cli/headless/claude-invoker-stream.js +555 -0
  42. package/dist/server/cli/headless/claude-invoker-tools.js +148 -0
  43. package/dist/server/cli/headless/claude-invoker.js +151 -0
  44. package/dist/server/cli/headless/engine-availability.js +92 -0
  45. package/dist/server/cli/headless/engine-notice.js +185 -0
  46. package/dist/server/cli/headless/haiku-assessments.js +293 -0
  47. package/dist/server/cli/headless/headless-logger.js +75 -0
  48. package/dist/server/cli/headless/index.js +9 -0
  49. package/dist/server/cli/headless/mcp-config.js +314 -0
  50. package/dist/server/cli/headless/native-timeout-detector.js +72 -0
  51. package/dist/server/cli/headless/output-utils.js +71 -0
  52. package/dist/server/cli/headless/prompt-utils.js +82 -0
  53. package/dist/server/cli/headless/resilient-runner.js +326 -0
  54. package/dist/server/cli/headless/retry-strategies.js +292 -0
  55. package/dist/server/cli/headless/runner.js +245 -0
  56. package/dist/server/cli/headless/stall-assessor.js +295 -0
  57. package/dist/server/cli/headless/tool-watchdog.js +447 -0
  58. package/dist/server/cli/headless/types.js +18 -0
  59. package/dist/server/cli/history-portability.js +85 -0
  60. package/dist/server/cli/improvisation-attachments.js +99 -0
  61. package/dist/server/cli/improvisation-history-store.js +121 -0
  62. package/dist/server/cli/improvisation-movements.js +137 -0
  63. package/dist/server/cli/improvisation-output-queue.js +34 -0
  64. package/dist/server/cli/improvisation-retry.js +8 -0
  65. package/dist/server/cli/improvisation-session-manager.js +1016 -0
  66. package/dist/server/cli/improvisation-types.js +31 -0
  67. package/dist/server/cli/plan-lifecycle.js +72 -0
  68. package/dist/server/cli/prompt-builders.js +371 -0
  69. package/dist/server/cli/retry/retry-best-result.js +28 -0
  70. package/dist/server/cli/retry/retry-context-loss.js +75 -0
  71. package/dist/server/cli/retry/retry-recovery-strategies.js +213 -0
  72. package/dist/server/cli/retry/retry-resume-strategy.js +20 -0
  73. package/dist/server/cli/retry/retry-runner-factory.js +92 -0
  74. package/dist/server/cli/retry/retry-tool-results.js +22 -0
  75. package/dist/server/cli/retry/retry-types.js +3 -0
  76. package/dist/server/engines/EngineEvent.js +57 -0
  77. package/dist/server/engines/claude/ClaudeCodeEngine.js +316 -0
  78. package/dist/server/engines/claude/claude-command.js +32 -0
  79. package/dist/server/engines/codex/CodexEngine.js +469 -0
  80. package/dist/server/engines/codex/codex-auth.js +203 -0
  81. package/dist/server/engines/codex/codex-invoker.js +205 -0
  82. package/dist/server/engines/codex/codex-provision.js +215 -0
  83. package/dist/server/engines/credentials/credential-probe.js +88 -0
  84. package/dist/server/engines/credentials/model-profiles.js +249 -0
  85. package/dist/server/engines/credentials/provider-credentials.js +146 -0
  86. package/dist/server/engines/engine-event-stream.js +52 -0
  87. package/dist/server/engines/execution/engine-session.js +380 -0
  88. package/dist/server/engines/factory.js +42 -0
  89. package/dist/server/engines/hermes/HermesEngine.js +628 -0
  90. package/dist/server/engines/hermes/hermes-auth.js +159 -0
  91. package/dist/server/engines/hermes/hermes-gateway-home.js +271 -0
  92. package/dist/server/engines/hermes/hermes-invoker.js +350 -0
  93. package/dist/server/engines/hermes/hermes-provision.js +318 -0
  94. package/dist/server/engines/read-only.js +20 -0
  95. package/dist/server/engines/types.js +27 -0
  96. package/dist/server/handlers/company-execution-registry.js +67 -0
  97. package/dist/server/handlers/company-handlers.js +514 -0
  98. package/dist/server/handlers/company-triggers.js +189 -0
  99. package/dist/server/handlers/company-types.js +3 -0
  100. package/dist/server/index.js +244 -0
  101. package/dist/server/mcp/app-tools-bridge.js +110 -0
  102. package/dist/server/mcp/app-tools-mcp-server.js +99 -0
  103. package/dist/server/mcp/bouncer-integration.js +744 -0
  104. package/dist/server/mcp/browser-mcp-server.js +915 -0
  105. package/dist/server/mcp/browser-redaction.js +103 -0
  106. package/dist/server/mcp/classifier/BouncerClassifier.js +3 -0
  107. package/dist/server/mcp/classifier/ClaudeBouncerClassifier.js +212 -0
  108. package/dist/server/mcp/classifier/factory.js +124 -0
  109. package/dist/server/mcp/classifier/health.js +54 -0
  110. package/dist/server/mcp/classifier/telemetry.js +0 -0
  111. package/dist/server/mcp/company-patterns.js +104 -0
  112. package/dist/server/mcp/department-profiles.js +133 -0
  113. package/dist/server/mcp/quality-bridge.js +153 -0
  114. package/dist/server/mcp/quality-mcp-server.js +105 -0
  115. package/dist/server/mcp/security-analysis.js +384 -0
  116. package/dist/server/mcp/security-audit.js +152 -0
  117. package/dist/server/mcp/security-patterns.js +314 -0
  118. package/dist/server/mcp/server.js +194 -0
  119. package/dist/server/mcp/test-utils/agent-simulator.js +301 -0
  120. package/dist/server/mcp/test-utils/e2e-agent.js +103 -0
  121. package/dist/server/mcp/test-utils/e2e-capture.js +92 -0
  122. package/dist/server/mcp/test-utils/e2e-client.js +116 -0
  123. package/dist/server/mcp/test-utils/e2e-fixtures.js +87 -0
  124. package/dist/server/mcp/test-utils/e2e-gating.js +8 -0
  125. package/dist/server/mcp/test-utils/e2e-harness.js +8 -0
  126. package/dist/server/mcp/test-utils/e2e-scenarios.js +105 -0
  127. package/dist/server/routes/files.js +18 -0
  128. package/dist/server/routes/improvise.js +64 -0
  129. package/dist/server/routes/index.js +7 -0
  130. package/dist/server/routes/instances.js +41 -0
  131. package/dist/server/routes/internal.js +900 -0
  132. package/dist/server/routes/notifications.js +110 -0
  133. package/dist/server/server-setup.js +282 -0
  134. package/dist/server/services/agent-push.js +148 -0
  135. package/dist/server/services/analytics.js +197 -0
  136. package/dist/server/services/apps/build.js +249 -0
  137. package/dist/server/services/apps/greenlight.js +199 -0
  138. package/dist/server/services/apps/install.js +101 -0
  139. package/dist/server/services/apps/layout.js +35 -0
  140. package/dist/server/services/apps/serve.js +665 -0
  141. package/dist/server/services/apps/space-apps.js +248 -0
  142. package/dist/server/services/auth.js +48 -0
  143. package/dist/server/services/browser/chrome-sandbox.js +245 -0
  144. package/dist/server/services/browser/chromium-launch-spec.js +51 -0
  145. package/dist/server/services/browser/claude-reasoner.js +669 -0
  146. package/dist/server/services/browser/debug-log.js +3 -0
  147. package/dist/server/services/browser/driver-state.js +546 -0
  148. package/dist/server/services/browser/electron-provision.js +256 -0
  149. package/dist/server/services/browser/host-internal.js +245 -0
  150. package/dist/server/services/browser/host-mock.js +334 -0
  151. package/dist/server/services/browser/host-types.js +3 -0
  152. package/dist/server/services/browser/host.js +1067 -0
  153. package/dist/server/services/browser/index.js +4 -0
  154. package/dist/server/services/browser/ipc-client.js +354 -0
  155. package/dist/server/services/browser/pipewire-sink.js +199 -0
  156. package/dist/server/services/browser/preflight.js +590 -0
  157. package/dist/server/services/browser/reasoning-agent.js +659 -0
  158. package/dist/server/services/browser/sandbox-policy.js +169 -0
  159. package/dist/server/services/browser/stderr-noise-filter.js +26 -0
  160. package/dist/server/services/browser/telemetry.js +107 -0
  161. package/dist/server/services/browser/xvfb-supervisor.js +139 -0
  162. package/dist/server/services/browser-frame-policy.js +56 -0
  163. package/dist/server/services/client-id.js +32 -0
  164. package/dist/server/services/collab/registry.js +408 -0
  165. package/dist/server/services/collab/session.js +489 -0
  166. package/dist/server/services/collab/text-diff.js +28 -0
  167. package/dist/server/services/collab/types.js +19 -0
  168. package/dist/server/services/e2ee-group-key.js +197 -0
  169. package/dist/server/services/e2ee-identity.js +203 -0
  170. package/dist/server/services/file-explorer-ops.js +328 -0
  171. package/dist/server/services/file-transfer-zip.js +188 -0
  172. package/dist/server/services/files.js +111 -0
  173. package/dist/server/services/git/branch-ops.js +62 -0
  174. package/dist/server/services/git/command.js +68 -0
  175. package/dist/server/services/git/commit-message.js +74 -0
  176. package/dist/server/services/git/diff-ops.js +56 -0
  177. package/dist/server/services/git/haiku.js +76 -0
  178. package/dist/server/services/git/head-watcher.js +226 -0
  179. package/dist/server/services/git/index.js +17 -0
  180. package/dist/server/services/git/log-ops.js +98 -0
  181. package/dist/server/services/git/merge-ops.js +314 -0
  182. package/dist/server/services/git/parsers.js +401 -0
  183. package/dist/server/services/git/remote-ops.js +192 -0
  184. package/dist/server/services/git/status-ops.js +105 -0
  185. package/dist/server/services/git/suggestion-ops.js +80 -0
  186. package/dist/server/services/git/tag-ops.js +36 -0
  187. package/dist/server/services/git/types.js +4 -0
  188. package/dist/server/services/git/worktree-ops.js +114 -0
  189. package/dist/server/services/instances.js +337 -0
  190. package/dist/server/services/model-catalog.js +247 -0
  191. package/dist/server/services/observability/posthog.js +153 -0
  192. package/dist/server/services/pathUtils.js +114 -0
  193. package/dist/server/services/plan/agent-loader.js +97 -0
  194. package/dist/server/services/plan/agent-manager.js +363 -0
  195. package/dist/server/services/plan/agent-resolver.js +74 -0
  196. package/dist/server/services/plan/agents/assess-stall.md +33 -0
  197. package/dist/server/services/plan/agents/browser-planner.md +53 -0
  198. package/dist/server/services/plan/agents/browser-reasoner.md +114 -0
  199. package/dist/server/services/plan/agents/check-injection.md +95 -0
  200. package/dist/server/services/plan/agents/classify-error.md +30 -0
  201. package/dist/server/services/plan/agents/code-review.md +142 -0
  202. package/dist/server/services/plan/agents/commit-message.md +28 -0
  203. package/dist/server/services/plan/agents/detect-context-loss.md +30 -0
  204. package/dist/server/services/plan/agents/execute-issue.md +58 -0
  205. package/dist/server/services/plan/agents/fix-quality.md +25 -0
  206. package/dist/server/services/plan/agents/plan-coordinator.md +72 -0
  207. package/dist/server/services/plan/agents/pr-description.md +29 -0
  208. package/dist/server/services/plan/agents/retry-task.md +27 -0
  209. package/dist/server/services/plan/agents/review-code.md +38 -0
  210. package/dist/server/services/plan/agents/review-quality.md +45 -0
  211. package/dist/server/services/plan/agents/triage-findings.md +78 -0
  212. package/dist/server/services/plan/agents/verify-review.md +57 -0
  213. package/dist/server/services/plan/approval-evaluator.js +143 -0
  214. package/dist/server/services/plan/board-archive.js +102 -0
  215. package/dist/server/services/plan/board-config.js +108 -0
  216. package/dist/server/services/plan/board-export.js +214 -0
  217. package/dist/server/services/plan/composer-prompt.js +115 -0
  218. package/dist/server/services/plan/composer.js +664 -0
  219. package/dist/server/services/plan/config-installer.js +103 -0
  220. package/dist/server/services/plan/dependency-resolver.js +137 -0
  221. package/dist/server/services/plan/executor.js +696 -0
  222. package/dist/server/services/plan/front-matter.js +43 -0
  223. package/dist/server/services/plan/issue-classification.js +10 -0
  224. package/dist/server/services/plan/issue-effort.js +182 -0
  225. package/dist/server/services/plan/issue-loader.js +35 -0
  226. package/dist/server/services/plan/issue-prompt-builder.js +152 -0
  227. package/dist/server/services/plan/issue-retry.js +42 -0
  228. package/dist/server/services/plan/issue-writer.js +102 -0
  229. package/dist/server/services/plan/metrics-collector.js +272 -0
  230. package/dist/server/services/plan/output-manager.js +77 -0
  231. package/dist/server/services/plan/parser-core.js +435 -0
  232. package/dist/server/services/plan/parser-migration.js +108 -0
  233. package/dist/server/services/plan/parser.js +258 -0
  234. package/dist/server/services/plan/plan-runner-factory.js +68 -0
  235. package/dist/server/services/plan/pm-timeline.js +320 -0
  236. package/dist/server/services/plan/progress-log.js +101 -0
  237. package/dist/server/services/plan/prompt-builder.js +142 -0
  238. package/dist/server/services/plan/quality-delta.js +274 -0
  239. package/dist/server/services/plan/readiness-planner.js +34 -0
  240. package/dist/server/services/plan/review-gate.js +409 -0
  241. package/dist/server/services/plan/review-report.js +134 -0
  242. package/dist/server/services/plan/review-verdict-stream.js +161 -0
  243. package/dist/server/services/plan/state-reconciler.js +238 -0
  244. package/dist/server/services/plan/template-diff.js +175 -0
  245. package/dist/server/services/plan/template-instantiator.js +516 -0
  246. package/dist/server/services/plan/template-manifest.js +56 -0
  247. package/dist/server/services/plan/template-types.js +3 -0
  248. package/dist/server/services/plan/trigger-evaluator.js +211 -0
  249. package/dist/server/services/plan/types.js +3 -0
  250. package/dist/server/services/plan/watcher.js +73 -0
  251. package/dist/server/services/platform-credentials.js +56 -0
  252. package/dist/server/services/platform-e2ee.js +421 -0
  253. package/dist/server/services/platform-envelope.js +102 -0
  254. package/dist/server/services/platform-heartbeat.js +88 -0
  255. package/dist/server/services/platform-reconnect.js +60 -0
  256. package/dist/server/services/platform-token-lifecycle.js +95 -0
  257. package/dist/server/services/platform-url.js +17 -0
  258. package/dist/server/services/platform.js +656 -0
  259. package/dist/server/services/runtime-info.js +9 -0
  260. package/dist/server/services/schedule/agent-schedule-store.js +232 -0
  261. package/dist/server/services/schedule/agent-scheduler.js +323 -0
  262. package/dist/server/services/schedule/daily-timing.js +105 -0
  263. package/dist/server/services/schedule/quality-schedule-launch.js +11 -0
  264. package/dist/server/services/schedule/quality-schedule-store.js +211 -0
  265. package/dist/server/services/schedule/quality-scheduler.js +215 -0
  266. package/dist/server/services/schedule/run-bootstrap.js +329 -0
  267. package/dist/server/services/schedule/schedule-store.js +238 -0
  268. package/dist/server/services/schedule/schedule-wire.js +77 -0
  269. package/dist/server/services/schedule/scheduler.js +310 -0
  270. package/dist/server/services/schedule/template-source.js +97 -0
  271. package/dist/server/services/sdk/agent-sessions.js +264 -0
  272. package/dist/server/services/sdk/agents.js +557 -0
  273. package/dist/server/services/sdk/app-endpoints.js +48 -0
  274. package/dist/server/services/sdk/app-tools.js +303 -0
  275. package/dist/server/services/sdk/audit.js +48 -0
  276. package/dist/server/services/sdk/browser-transport.js +188 -0
  277. package/dist/server/services/sdk/browser.js +605 -0
  278. package/dist/server/services/sdk/composer.js +129 -0
  279. package/dist/server/services/sdk/connect.js +273 -0
  280. package/dist/server/services/sdk/consent-cooldown.js +31 -0
  281. package/dist/server/services/sdk/endpoint-url.js +141 -0
  282. package/dist/server/services/sdk/endpoints.js +314 -0
  283. package/dist/server/services/sdk/file-change-notify.js +36 -0
  284. package/dist/server/services/sdk/files-app.js +163 -0
  285. package/dist/server/services/sdk/files-search.js +131 -0
  286. package/dist/server/services/sdk/files-transfer.js +279 -0
  287. package/dist/server/services/sdk/files-workspace.js +233 -0
  288. package/dist/server/services/sdk/git.js +520 -0
  289. package/dist/server/services/sdk/grant-store.js +318 -0
  290. package/dist/server/services/sdk/host-ops.js +84 -0
  291. package/dist/server/services/sdk/inference-claude.js +214 -0
  292. package/dist/server/services/sdk/inference.js +247 -0
  293. package/dist/server/services/sdk/live-registry.js +42 -0
  294. package/dist/server/services/sdk/local-app-bindings.js +71 -0
  295. package/dist/server/services/sdk/pipeline.js +190 -0
  296. package/dist/server/services/sdk/pm-execute.js +228 -0
  297. package/dist/server/services/sdk/pm-planning-tap.js +29 -0
  298. package/dist/server/services/sdk/pm-schedule.js +165 -0
  299. package/dist/server/services/sdk/pm.js +634 -0
  300. package/dist/server/services/sdk/quality-change-notify.js +20 -0
  301. package/dist/server/services/sdk/quality-schedule.js +165 -0
  302. package/dist/server/services/sdk/quality.js +602 -0
  303. package/dist/server/services/sdk/rate-limits.js +198 -0
  304. package/dist/server/services/sdk/registry.js +597 -0
  305. package/dist/server/services/sdk/revoke.js +86 -0
  306. package/dist/server/services/sdk/run-profile.js +41 -0
  307. package/dist/server/services/sdk/sandbox.js +89 -0
  308. package/dist/server/services/sdk/storage.js +110 -0
  309. package/dist/server/services/sdk/streams.js +147 -0
  310. package/dist/server/services/sdk/terminal.js +201 -0
  311. package/dist/server/services/sdk/test-utils/workshop-browser-app.js +466 -0
  312. package/dist/server/services/sentry.js +99 -0
  313. package/dist/server/services/settings.js +374 -0
  314. package/dist/server/services/snippets/expander.js +87 -0
  315. package/dist/server/services/snippets/index.js +6 -0
  316. package/dist/server/services/snippets/loader.js +119 -0
  317. package/dist/server/services/snippets/parser.js +52 -0
  318. package/dist/server/services/snippets/types.js +3 -0
  319. package/dist/server/services/snippets/watcher.js +60 -0
  320. package/dist/server/services/space-layout.js +80 -0
  321. package/dist/server/services/system-prompts.js +219 -0
  322. package/dist/server/services/terminal/pty-manager.js +206 -0
  323. package/dist/server/services/terminal/pty-utils.js +150 -0
  324. package/dist/server/services/timeline/assembler.js +890 -0
  325. package/dist/server/services/timeline/contract.js +196 -0
  326. package/dist/server/services/timeline/index.js +4 -0
  327. package/dist/server/services/websocket/agent-schedule-handlers.js +217 -0
  328. package/dist/server/services/websocket/apps-handlers.js +399 -0
  329. package/dist/server/services/websocket/ask-user-question-bridge.js +112 -0
  330. package/dist/server/services/websocket/autocomplete-index.js +415 -0
  331. package/dist/server/services/websocket/autocomplete-match.js +243 -0
  332. package/dist/server/services/websocket/autocomplete.js +407 -0
  333. package/dist/server/services/websocket/browser-agent-runtime.js +208 -0
  334. package/dist/server/services/websocket/browser-device-profile.js +46 -0
  335. package/dist/server/services/websocket/browser-handlers.js +377 -0
  336. package/dist/server/services/websocket/browser-host-broadcast.js +179 -0
  337. package/dist/server/services/websocket/browser-ice-config.js +121 -0
  338. package/dist/server/services/websocket/browser-payloads.js +222 -0
  339. package/dist/server/services/websocket/browser-viewer-lifecycle.js +84 -0
  340. package/dist/server/services/websocket/browser-viewer-registry.js +118 -0
  341. package/dist/server/services/websocket/collab-broadcast.js +11 -0
  342. package/dist/server/services/websocket/collab-handlers.js +116 -0
  343. package/dist/server/services/websocket/commit-suggestion-service.js +132 -0
  344. package/dist/server/services/websocket/debug-log.js +38 -0
  345. package/dist/server/services/websocket/dispatch-util.js +10 -0
  346. package/dist/server/services/websocket/engine-auth-handlers.js +323 -0
  347. package/dist/server/services/websocket/engine-credential-watcher.js +83 -0
  348. package/dist/server/services/websocket/engine-profile-handlers.js +92 -0
  349. package/dist/server/services/websocket/file-definition-handlers.js +180 -0
  350. package/dist/server/services/websocket/file-download-handler.js +291 -0
  351. package/dist/server/services/websocket/file-explorer-handlers.js +291 -0
  352. package/dist/server/services/websocket/file-search-handlers.js +267 -0
  353. package/dist/server/services/websocket/file-share-handlers.js +328 -0
  354. package/dist/server/services/websocket/file-transfer-http.js +361 -0
  355. package/dist/server/services/websocket/file-upload-handler.js +267 -0
  356. package/dist/server/services/websocket/file-utils.js +346 -0
  357. package/dist/server/services/websocket/git-branch-handlers.js +90 -0
  358. package/dist/server/services/websocket/git-diff-handlers.js +59 -0
  359. package/dist/server/services/websocket/git-handlers.js +212 -0
  360. package/dist/server/services/websocket/git-head-watcher.js +85 -0
  361. package/dist/server/services/websocket/git-log-handlers.js +104 -0
  362. package/dist/server/services/websocket/git-pr-handlers.js +56 -0
  363. package/dist/server/services/websocket/git-tag-handlers.js +53 -0
  364. package/dist/server/services/websocket/git-utils.js +11 -0
  365. package/dist/server/services/websocket/git-worktree-handlers.js +521 -0
  366. package/dist/server/services/websocket/handler-context.js +113 -0
  367. package/dist/server/services/websocket/handler.js +1197 -0
  368. package/dist/server/services/websocket/index.js +5 -0
  369. package/dist/server/services/websocket/movement-written-files.js +26 -0
  370. package/dist/server/services/websocket/msg-id-tracker.js +48 -0
  371. package/dist/server/services/websocket/plan-board-handlers.js +410 -0
  372. package/dist/server/services/websocket/plan-execution-handlers.js +244 -0
  373. package/dist/server/services/websocket/plan-handlers.js +67 -0
  374. package/dist/server/services/websocket/plan-helpers.js +161 -0
  375. package/dist/server/services/websocket/plan-issue-handlers.js +168 -0
  376. package/dist/server/services/websocket/plan-sprint-handlers.js +190 -0
  377. package/dist/server/services/websocket/plan-transfer-handlers.js +310 -0
  378. package/dist/server/services/websocket/pm-timeline-broadcast.js +28 -0
  379. package/dist/server/services/websocket/post-session-scan.js +132 -0
  380. package/dist/server/services/websocket/prompt-queue-handlers.js +96 -0
  381. package/dist/server/services/websocket/quality-agent-cost.js +229 -0
  382. package/dist/server/services/websocket/quality-agent-notes.js +113 -0
  383. package/dist/server/services/websocket/quality-change-activity.js +187 -0
  384. package/dist/server/services/websocket/quality-complexity.js +345 -0
  385. package/dist/server/services/websocket/quality-dependencies.js +445 -0
  386. package/dist/server/services/websocket/quality-duplication.js +162 -0
  387. package/dist/server/services/websocket/quality-eta.js +65 -0
  388. package/dist/server/services/websocket/quality-fingerprint.js +104 -0
  389. package/dist/server/services/websocket/quality-grading.js +575 -0
  390. package/dist/server/services/websocket/quality-handlers.js +48 -0
  391. package/dist/server/services/websocket/quality-linting.js +270 -0
  392. package/dist/server/services/websocket/quality-operations.js +54 -0
  393. package/dist/server/services/websocket/quality-persistence.js +410 -0
  394. package/dist/server/services/websocket/quality-review-agent.js +526 -0
  395. package/dist/server/services/websocket/quality-run.js +220 -0
  396. package/dist/server/services/websocket/quality-secrets.js +0 -0
  397. package/dist/server/services/websocket/quality-service.js +775 -0
  398. package/dist/server/services/websocket/quality-tools.js +383 -0
  399. package/dist/server/services/websocket/quality-triage-agent.js +101 -0
  400. package/dist/server/services/websocket/quality-types.js +149 -0
  401. package/dist/server/services/websocket/recommended-answers.js +28 -0
  402. package/dist/server/services/websocket/schedule-handlers.js +197 -0
  403. package/dist/server/services/websocket/sdk-agent-host.js +569 -0
  404. package/dist/server/services/websocket/sdk-browser-host.js +459 -0
  405. package/dist/server/services/websocket/sdk-composer-host.js +10 -0
  406. package/dist/server/services/websocket/sdk-git-host.js +115 -0
  407. package/dist/server/services/websocket/sdk-handlers.js +242 -0
  408. package/dist/server/services/websocket/sdk-pm-execution-host.js +63 -0
  409. package/dist/server/services/websocket/sdk-pm-schedule-host.js +21 -0
  410. package/dist/server/services/websocket/sdk-quality-schedule-host.js +34 -0
  411. package/dist/server/services/websocket/sdk-terminal-host.js +140 -0
  412. package/dist/server/services/websocket/session-handlers.js +565 -0
  413. package/dist/server/services/websocket/session-history.js +335 -0
  414. package/dist/server/services/websocket/session-initialization.js +315 -0
  415. package/dist/server/services/websocket/session-registry.js +340 -0
  416. package/dist/server/services/websocket/session-role-directory.js +39 -0
  417. package/dist/server/services/websocket/settings-handlers.js +276 -0
  418. package/dist/server/services/websocket/skill-handlers.js +324 -0
  419. package/dist/server/services/websocket/skill-watcher.js +83 -0
  420. package/dist/server/services/websocket/snippet-handlers.js +261 -0
  421. package/dist/server/services/websocket/tab-broadcast.js +35 -0
  422. package/dist/server/services/websocket/tab-event-buffer.js +110 -0
  423. package/dist/server/services/websocket/tab-event-replay.js +47 -0
  424. package/dist/server/services/websocket/tab-handlers.js +211 -0
  425. package/dist/server/services/websocket/terminal-handlers.js +268 -0
  426. package/dist/server/services/websocket/types.js +96 -0
  427. package/dist/server/types/company-messages.js +102 -0
  428. package/dist/server/utils/agent-manager.js +202 -0
  429. package/dist/server/utils/console-timestamps.js +24 -0
  430. package/dist/server/utils/file-store.js +112 -0
  431. package/dist/server/utils/paths.js +28 -0
  432. package/dist/server/utils/port-manager.js +43 -0
  433. package/dist/server/utils/port.js +204 -0
  434. package/electron-host/dist/agent-lease.js +141 -0
  435. package/electron-host/dist/capture-recovery.js +77 -0
  436. package/electron-host/dist/codec-policy.js +37 -0
  437. package/electron-host/dist/controller-channel.js +60 -0
  438. package/electron-host/dist/controller-handlers.js +153 -0
  439. package/electron-host/dist/device-emulator.js +106 -0
  440. package/electron-host/dist/dom-driver.js +642 -0
  441. package/electron-host/dist/domain-registry.js +159 -0
  442. package/electron-host/dist/domain-validators.js +308 -0
  443. package/electron-host/dist/editable-focus-reporter.js +143 -0
  444. package/electron-host/dist/fake-peer.test-util.js +105 -0
  445. package/electron-host/dist/host-log.js +31 -0
  446. package/electron-host/dist/host-wire.js +11 -0
  447. package/electron-host/dist/input-router.js +421 -0
  448. package/electron-host/dist/ipc-protocol.js +89 -0
  449. package/electron-host/dist/ipc-server.js +193 -0
  450. package/electron-host/dist/js-driver.js +216 -0
  451. package/electron-host/dist/main-guards.js +70 -0
  452. package/electron-host/dist/main.js +716 -0
  453. package/electron-host/dist/roster-sync.js +87 -0
  454. package/electron-host/dist/rpc-context.js +1 -0
  455. package/electron-host/dist/rpc-tab-methods.js +138 -0
  456. package/electron-host/dist/rpc-webrtc-methods.js +121 -0
  457. package/electron-host/dist/screen-capture-cache.js +147 -0
  458. package/electron-host/dist/sdk-injector.js +166 -0
  459. package/electron-host/dist/sdp.js +102 -0
  460. package/electron-host/dist/session-surface.js +78 -0
  461. package/electron-host/dist/surface-sizing.js +59 -0
  462. package/electron-host/dist/view-manager.js +254 -0
  463. package/electron-host/dist/viewer-registry.js +46 -0
  464. package/electron-host/dist/viewer-session.js +288 -0
  465. package/electron-host/dist/webrtc-channels.js +14 -0
  466. package/electron-host/dist/webrtc-controller.js +57 -0
  467. package/electron-host/dist/webrtc-ice-filter.js +13 -0
  468. package/electron-host/dist/webrtc-peer.js +45 -0
  469. package/electron-host/package.json +12 -0
  470. package/electron-host/tsconfig.json +23 -0
  471. package/electron-host/webrtc-controller-preload.cjs +3 -0
  472. package/electron-host/webrtc-controller.html +14 -0
  473. package/package.json +85 -0
  474. package/vendor/e2ee/LICENSE +14 -0
  475. package/vendor/e2ee/package.json +14 -0
  476. package/vendor/e2ee/src/index.js +310 -0
@@ -0,0 +1,542 @@
1
+ // Copyright (c) 2025-present Minionry, Inc.
2
+ // SPDX-License-Identifier: LicenseRef-Minionry-Software
3
+
4
+
5
+ import { spawn } from 'node:child_process';
6
+ import { existsSync, mkdirSync, readFileSync, rmSync, truncateSync, writeFileSync } from 'node:fs';
7
+ import { dirname, join, resolve } from 'node:path';
8
+ import { createInterface } from 'node:readline';
9
+ import { fileURLToPath } from 'node:url';
10
+ import { APP_NAME } from '../branding.js';
11
+ import { machinePath } from '../machine-layout.js';
12
+ import {
13
+ buildDiskImageCommands,
14
+ buildPlainVolumeArgs,
15
+ buildRunArgs,
16
+ checkSandboxName,
17
+ defaultSandboxName,
18
+ parseRepoInput,
19
+ parseSandboxArgs,
20
+ REPO_KINDS,
21
+ SANDBOX_IMAGE_TAG,
22
+ sandboxNames,
23
+ } from '../sandbox-config.js';
24
+
25
+ const __filename = fileURLToPath(import.meta.url);
26
+ const __dirname = dirname(__filename);
27
+ const BUILD_CONTEXT = resolve(__dirname, '..', 'sandbox');
28
+ const PUBLIC_REGISTRY = 'https://registry.npmjs.org/';
29
+ const CLI_REGISTRY =
30
+ JSON.parse(readFileSync(resolve(__dirname, '..', '..', 'package.json'), 'utf-8')).publishConfig?.registry ??
31
+ PUBLIC_REGISTRY;
32
+ const REGISTRY_LABEL = 'minionry.registry';
33
+ export const IMAGE_BUILD_ARGS = [
34
+ '-t',
35
+ SANDBOX_IMAGE_TAG,
36
+ '--build-arg',
37
+ `MINION_REGISTRY=${CLI_REGISTRY}`,
38
+ '--label',
39
+ `${REGISTRY_LABEL}=${CLI_REGISTRY}`,
40
+ BUILD_CONTEXT,
41
+ ];
42
+ const SANDBOXES_DIR = machinePath('sandboxes');
43
+
44
+ const colors = {
45
+ reset: '\x1b[0m',
46
+ bold: '\x1b[1m',
47
+ green: '\x1b[32m',
48
+ yellow: '\x1b[33m',
49
+ red: '\x1b[31m',
50
+ dim: '\x1b[2m',
51
+ cyan: '\x1b[36m',
52
+ };
53
+
54
+ function log(msg, color = '') {
55
+ console.log(`${color}${msg}${colors.reset}`);
56
+ }
57
+
58
+ export function runCapture(cmd, args) {
59
+ return new Promise((resolveRun) => {
60
+ const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'] });
61
+ let stdout = '';
62
+ let stderr = '';
63
+ child.stdout.on('data', (d) => {
64
+ stdout += d;
65
+ });
66
+ child.stderr.on('data', (d) => {
67
+ stderr += d;
68
+ });
69
+ child.on('error', (err) => {
70
+ resolveRun({ ok: false, code: null, stdout, stderr, missing: err.code === 'ENOENT' });
71
+ });
72
+ child.on('exit', (code) => {
73
+ resolveRun({ ok: code === 0, code, stdout, stderr, missing: false });
74
+ });
75
+ });
76
+ }
77
+
78
+ function runInherit(cmd, args) {
79
+ return new Promise((resolveRun) => {
80
+ const child = spawn(cmd, args, { stdio: ['ignore', 'inherit', 'inherit'] });
81
+ child.on('error', () => resolveRun({ ok: false, code: null }));
82
+ child.on('exit', (code) => resolveRun({ ok: code === 0, code }));
83
+ });
84
+ }
85
+
86
+ export function createAsker() {
87
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
88
+ const pending = [];
89
+ const waiters = [];
90
+ let closed = false;
91
+
92
+ rl.on('line', (line) => {
93
+ const waiter = waiters.shift();
94
+ if (waiter) waiter(line);
95
+ else pending.push(line);
96
+ });
97
+ rl.on('close', () => {
98
+ closed = true;
99
+ while (waiters.length > 0) waiters.shift()(null);
100
+ });
101
+ rl.on('SIGINT', () => {
102
+ rl.close();
103
+ process.stdout.write('\n');
104
+ process.exit(130);
105
+ });
106
+
107
+ const question = (text) => {
108
+ if (pending.length > 0) {
109
+ const line = pending.shift();
110
+ process.stdout.write(`${text}${line}\n`);
111
+ return Promise.resolve(line);
112
+ }
113
+ if (closed) {
114
+ process.stdout.write(`${text}\n`);
115
+ return Promise.resolve(null);
116
+ }
117
+ rl.setPrompt(text);
118
+ rl.prompt();
119
+ return new Promise((resolveAnswer) => waiters.push(resolveAnswer));
120
+ };
121
+
122
+ return { rl, question };
123
+ }
124
+
125
+ function aborted() {
126
+ log('\n Cancelled — nothing was created.\n', colors.dim);
127
+ process.exit(130);
128
+ }
129
+
130
+ async function askRepo(question, label) {
131
+ for (;;) {
132
+ const answer = await question(` ${label} ${colors.dim}(press Enter to skip):${colors.reset} `);
133
+ if (answer === null) aborted();
134
+ const parsed = parseRepoInput(answer);
135
+ if (parsed.ok) return parsed.url;
136
+ log(` ${parsed.error}`, colors.yellow);
137
+ }
138
+ }
139
+
140
+ export async function confirm(question, text, { defaultYes = true } = {}) {
141
+ const answer = await question(`${text} ${colors.dim}${defaultYes ? '[Y/n]' : '[y/N]'}${colors.reset} `);
142
+ if (answer === null) return false;
143
+ const trimmed = answer.trim();
144
+ if (trimmed === '') return defaultYes;
145
+ return defaultYes ? !/^n/i.test(trimmed) : /^y/i.test(trimmed);
146
+ }
147
+
148
+ async function checkDocker() {
149
+ const info = await runCapture('docker', ['info', '--format', '{{json .}}']);
150
+ if (info.missing) return { status: 'missing' };
151
+ if (!info.ok) return { status: 'daemon', message: info.stderr.trim() || info.stdout.trim() };
152
+ try {
153
+ const parsed = JSON.parse(info.stdout);
154
+ if (parsed.ServerErrors?.length) {
155
+ return { status: 'daemon', message: parsed.ServerErrors.join('; ') };
156
+ }
157
+ const rootless = (parsed.SecurityOptions || []).some((o) => String(o).includes('rootless'));
158
+ return { status: 'ok', osType: parsed.OSType || 'unknown', rootless };
159
+ } catch {
160
+ return { status: 'daemon', message: 'Could not parse `docker info` output.' };
161
+ }
162
+ }
163
+
164
+ function printDockerMissing() {
165
+ log(' Docker is required for sandboxes but was not found on this machine.\n', colors.red);
166
+ log(' Install it, then re-run this command:', colors.bold);
167
+ log(' Linux: curl -fsSL https://get.docker.com | sh', colors.cyan);
168
+ log(' sudo usermod -aG docker $USER && newgrp docker', colors.cyan);
169
+ log(' macOS: https://docs.docker.com/desktop/setup/install/mac-install/', colors.cyan);
170
+ log('');
171
+ }
172
+
173
+ function printDockerDaemonHelp(message) {
174
+ log(' Docker is installed but the daemon is not reachable.\n', colors.red);
175
+ if (message) log(` ${colors.dim}${message}${colors.reset}`);
176
+ log(' Try:', colors.bold);
177
+ if (process.platform === 'darwin') {
178
+ log(' Open Docker Desktop and wait for it to finish starting.', colors.cyan);
179
+ } else {
180
+ log(' sudo systemctl start docker', colors.cyan);
181
+ if (/permission denied/i.test(message || '')) {
182
+ log(' sudo usermod -aG docker $USER && newgrp docker (fixes "permission denied")', colors.cyan);
183
+ }
184
+ }
185
+ log('');
186
+ }
187
+
188
+ export async function takenDockerNames() {
189
+ const [containers, volumes] = await Promise.all([
190
+ runCapture('docker', ['ps', '-a', '--format', '{{.Names}}']),
191
+ runCapture('docker', ['volume', 'ls', '--format', '{{.Name}}']),
192
+ ]);
193
+ const names = [];
194
+ for (const result of [containers, volumes]) {
195
+ if (result.ok) names.push(...result.stdout.split('\n').map((l) => l.trim()).filter(Boolean));
196
+ }
197
+ return names;
198
+ }
199
+
200
+ export const imagePathFor = (name) => join(SANDBOXES_DIR, `${name}.img`);
201
+
202
+ const nameProblem = (name, taken) =>
203
+ checkSandboxName(name, { taken, imageExists: existsSync(imagePathFor(name)) });
204
+
205
+ function printNameProblem(name, problem, color) {
206
+ if (problem.invalid) {
207
+ log(` ${problem.invalid}`, color);
208
+ return;
209
+ }
210
+ const { container, volume } = sandboxNames(name);
211
+ log(` A sandbox named "${name}" already exists (or left remains):`, color);
212
+ if (problem.clashes.includes('container')) {
213
+ log(` - container "${container}" (docker rm -f ${container})`, colors.dim);
214
+ }
215
+ if (problem.clashes.includes('volume')) {
216
+ log(` - volume "${volume}" (docker volume rm ${volume})`, colors.dim);
217
+ }
218
+ if (problem.clashes.includes('image')) {
219
+ log(` - disk image ${imagePathFor(name)} (rm it if you no longer need that data)`, colors.dim);
220
+ }
221
+ if (!problem.clashes.includes('container')) {
222
+ log(' (a rename keeps the original volume name — check: minion list sandboxes)', colors.dim);
223
+ }
224
+ }
225
+
226
+ function firstFreeName(taken) {
227
+ let candidate = defaultSandboxName(taken);
228
+ while (existsSync(imagePathFor(candidate))) {
229
+ taken.push(sandboxNames(candidate).container, sandboxNames(candidate).volume);
230
+ candidate = defaultSandboxName(taken);
231
+ }
232
+ return candidate;
233
+ }
234
+
235
+ async function resolveName(explicitName) {
236
+ const taken = await takenDockerNames();
237
+
238
+ if (!explicitName) return { taken, names: null, suggested: firstFreeName(taken) };
239
+
240
+ const problem = nameProblem(explicitName, taken);
241
+ if (problem) {
242
+ log('');
243
+ printNameProblem(explicitName, problem, colors.red);
244
+ log('\n Pick another name: minion create sandbox <name>\n', colors.dim);
245
+ process.exit(1);
246
+ }
247
+ return { taken, names: sandboxNames(explicitName), suggested: explicitName };
248
+ }
249
+
250
+ async function askName(question, taken, suggested) {
251
+ for (;;) {
252
+ const answer = await question(` Sandbox name ${colors.dim}[${suggested}]:${colors.reset} `);
253
+ if (answer === null) aborted();
254
+ const name = answer.trim() === '' ? suggested : answer.trim();
255
+ const problem = nameProblem(name, taken);
256
+ if (!problem) return sandboxNames(name);
257
+ printNameProblem(name, problem, colors.yellow);
258
+ }
259
+ }
260
+
261
+ async function createCappedDisk(names, diskGb) {
262
+ const imagePath = imagePathFor(names.name);
263
+ const plan = buildDiskImageCommands({ imagePath, sizeGb: diskGb, volume: names.volume });
264
+
265
+ mkdirSync(SANDBOXES_DIR, { recursive: true });
266
+
267
+ const cleanup = async ({ volume }) => {
268
+ if (volume) await runCapture('docker', ['volume', 'rm', names.volume]);
269
+ rmSync(imagePath, { force: true });
270
+ };
271
+
272
+ try {
273
+ writeFileSync(imagePath, '');
274
+ truncateSync(imagePath, plan.imageBytes);
275
+ } catch (err) {
276
+ log(` Could not create the disk image: ${err.message}`, colors.yellow);
277
+ return false;
278
+ }
279
+
280
+ const mkfs = await runCapture(plan.mkfs[0], plan.mkfs[1]);
281
+ if (!mkfs.ok) {
282
+ log(` mkfs.ext4 failed${mkfs.missing ? ' (not installed — e2fsprogs)' : ''}: ${mkfs.stderr.trim()}`, colors.yellow);
283
+ await cleanup({ volume: false });
284
+ return false;
285
+ }
286
+
287
+ const volume = await runCapture(plan.volumeCreate[0], plan.volumeCreate[1]);
288
+ if (!volume.ok) {
289
+ log(` docker volume create failed: ${volume.stderr.trim()}`, colors.yellow);
290
+ await cleanup({ volume: false });
291
+ return false;
292
+ }
293
+
294
+ const smoke = await runCapture('docker', [
295
+ 'run', '--rm', '--entrypoint', '/bin/true', '-v', `${names.volume}:/mnt`, SANDBOX_IMAGE_TAG,
296
+ ]);
297
+ if (!smoke.ok) {
298
+ log(` This Docker daemon could not mount the loopback disk: ${smoke.stderr.trim()}`, colors.yellow);
299
+ await cleanup({ volume: true });
300
+ return false;
301
+ }
302
+
303
+ return true;
304
+ }
305
+
306
+ function waitForFirstBoot(container) {
307
+ return runCapture('docker', [
308
+ 'exec', container, 'bash', '-c',
309
+ 'for i in $(seq 180); do [ -f "$HOME/.sandbox-provisioned" ] && exit 0; sleep 1; done; exit 1',
310
+ ]);
311
+ }
312
+
313
+ async function pendingCliInstall(container) {
314
+ const marker = await runCapture('docker', [
315
+ 'exec', container, 'bash', '-c', 'cat "$HOME/.minion-cli-missing" 2>/dev/null',
316
+ ]);
317
+ return marker.ok ? marker.stdout.trim() : '';
318
+ }
319
+
320
+ export async function requireDocker() {
321
+ const docker = await checkDocker();
322
+ if (docker.status === 'missing') {
323
+ printDockerMissing();
324
+ process.exit(1);
325
+ }
326
+ if (docker.status === 'daemon') {
327
+ printDockerDaemonHelp(docker.message);
328
+ process.exit(1);
329
+ }
330
+ return docker;
331
+ }
332
+
333
+ async function diskCapSupported(docker) {
334
+ if (docker.osType !== 'linux' || docker.rootless || process.platform !== 'linux') return false;
335
+ return !(await runCapture('mkfs.ext4', ['-V'])).missing;
336
+ }
337
+
338
+ function printPlan({ names, memoryGb, diskGb, repoUrls, capPlanned, imageExists, rebuild }) {
339
+ log(`\n ${colors.bold}Plan${colors.reset}`);
340
+ log(` Sandbox ${names.name} ${colors.dim}(container ${names.container})${colors.reset}`);
341
+ if (memoryGb) log(` Memory ${memoryGb} GB cap, swap disabled`);
342
+ if (diskGb && capPlanned) {
343
+ log(` Disk ${diskGb} GB hard cap ${colors.dim}(loopback ext4 at ${imagePathFor(names.name)})${colors.reset}`);
344
+ } else if (diskGb) {
345
+ log(` Disk ${diskGb} GB requested — ${colors.yellow}no hard cap on this host${colors.reset} ${colors.dim}(needs a root Linux Docker daemon + mkfs.ext4)${colors.reset}`);
346
+ }
347
+ for (const { kind } of REPO_KINDS) {
348
+ const rowLabel = kind[0].toUpperCase() + kind.slice(1);
349
+ log(` ${rowLabel.padEnd(10)}${repoUrls[kind] ?? `${colors.dim}skipped${colors.reset}`}`);
350
+ }
351
+ const imageNote = imageExists && !rebuild
352
+ ? `${colors.dim}(cached)${colors.reset}`
353
+ : `${colors.yellow}(will build now — several minutes on the first run)${colors.reset}`;
354
+ log(` Image ${SANDBOX_IMAGE_TAG} ${imageNote}`);
355
+ log('');
356
+ }
357
+
358
+ async function runWizard({ names, suggested, taken, memoryGb, diskGb, capPlanned, imageExists, rebuild }) {
359
+ const { rl, question } = createAsker();
360
+
361
+ let resolved = names;
362
+ if (!resolved) {
363
+ log(` ${colors.dim}Name it whatever you like — it becomes the sandbox's hostname and how${colors.reset}`);
364
+ log(` ${colors.dim}every minion command refers to it. Enter takes the suggestion.${colors.reset}`);
365
+ resolved = await askName(question, taken, suggested);
366
+ log('');
367
+ }
368
+
369
+ log(` ${colors.dim}Optionally seed the sandbox from public git repos (installable later too):${colors.reset}`);
370
+ log(` ${colors.dim}Press Enter to skip any of them.${colors.reset}`);
371
+ const repoUrls = {};
372
+ for (const { kind, label, dest } of REPO_KINDS) {
373
+ repoUrls[kind] = await askRepo(question, `${label} → ${dest}`);
374
+ }
375
+
376
+ printPlan({ names: resolved, memoryGb, diskGb, repoUrls, capPlanned, imageExists, rebuild });
377
+ const confirmed = await confirm(question, ' Create this sandbox?');
378
+ rl.close();
379
+ return { names: resolved, repoUrls, confirmed };
380
+ }
381
+
382
+ async function cachedImageMatches() {
383
+ const image = await runCapture('docker', ['image', 'inspect', '--format', '{{ json .Config.Labels }}', SANDBOX_IMAGE_TAG]);
384
+ if (!image.ok) return false;
385
+ let labels = null;
386
+ try {
387
+ labels = JSON.parse(image.stdout);
388
+ } catch {
389
+ }
390
+ const registry = labels?.[REGISTRY_LABEL];
391
+ if (registry ? registry === CLI_REGISTRY : CLI_REGISTRY !== PUBLIC_REGISTRY) return true;
392
+ log(` ${colors.dim}The cached ${SANDBOX_IMAGE_TAG} image installs the minion CLI from ${registry ?? 'another registry'}; this CLI came from ${CLI_REGISTRY}, so it will be rebuilt.${colors.reset}\n`);
393
+ return false;
394
+ }
395
+
396
+ async function ensureImage(imageExists, rebuild) {
397
+ if (imageExists && !rebuild) return;
398
+ log(`\n Building ${SANDBOX_IMAGE_TAG}...`, colors.bold);
399
+ const build = await runInherit('docker', ['build', ...IMAGE_BUILD_ARGS]);
400
+ if (!build.ok) {
401
+ log('\n Image build failed — nothing was created. Re-run to try again.\n', colors.red);
402
+ process.exit(1);
403
+ }
404
+ }
405
+
406
+ async function provisionDisk(names, diskGb, capPlanned) {
407
+ let diskCapped = false;
408
+ if (diskGb && capPlanned) {
409
+ log('\n Creating the capped disk region...', colors.bold);
410
+ diskCapped = await createCappedDisk(names, diskGb);
411
+ if (!diskCapped) {
412
+ log(' Falling back to an uncapped volume — the sandbox still gets its own isolated disk region, but the size cap will not be enforced.', colors.yellow);
413
+ }
414
+ }
415
+ if (!diskCapped) {
416
+ const plain = await runCapture('docker', buildPlainVolumeArgs(names.volume));
417
+ if (!plain.ok) {
418
+ log(`\n Could not create the sandbox volume: ${plain.stderr.trim()}\n`, colors.red);
419
+ process.exit(1);
420
+ }
421
+ }
422
+ return diskCapped;
423
+ }
424
+
425
+ async function installRepos(names, repoUrls, bootOk) {
426
+ for (const { kind, label, dest } of REPO_KINDS) {
427
+ const url = repoUrls[kind];
428
+ if (!url) continue;
429
+ const retryCmd = `docker exec -it ${names.container} sandbox-install-repo ${kind} ${url}`;
430
+ if (!bootOk) {
431
+ log(` Skipped the ${kind} install — run it once the sandbox is healthy: ${retryCmd}`, colors.yellow);
432
+ continue;
433
+ }
434
+ log(`\n Installing ${label} → ${dest}...`, colors.bold);
435
+ const install = await runInherit('docker', ['exec', names.container, 'sandbox-install-repo', kind, url]);
436
+ if (!install.ok) {
437
+ log(` Failed — retry any time with: ${retryCmd}`, colors.yellow);
438
+ }
439
+ }
440
+ }
441
+
442
+ function printDone({ names, memoryGb, diskGb, diskCapped, cliInstall, sandboxedBrowser = true }) {
443
+ log(`\n Sandbox "${names.name}" is ready.\n`, colors.bold + colors.green);
444
+ if (memoryGb) log(` Memory ${memoryGb} GB cap (swap disabled)`);
445
+ if (diskCapped) {
446
+ log(` Disk ${diskGb} GB hard cap — ${imagePathFor(names.name)} ${colors.dim}(sparse: uses host disk only as the sandbox writes)${colors.reset}`);
447
+ } else if (diskGb) {
448
+ log(` Disk volume ${names.volume} ${colors.yellow}(size cap not enforced on this host)${colors.reset}`);
449
+ }
450
+ if (!sandboxedBrowser) {
451
+ log(` Browser Chromium runs unsandboxed inside this sandbox ${colors.dim}(the daemon rejected the seccomp profile; the container is the boundary)${colors.reset}`, colors.yellow);
452
+ }
453
+ if (memoryGb || diskGb || !sandboxedBrowser) log('');
454
+ log(' Enter it:', colors.bold);
455
+ log(` docker exec -it ${names.container} zsh`, colors.cyan);
456
+ log('');
457
+ if (cliInstall) {
458
+ log(' Install the minion CLI:', colors.bold + colors.yellow);
459
+ log(' The build skipped it — the registry rejected the install. Inside the', colors.dim);
460
+ log(' sandbox, authenticate to the registry, then run:', colors.dim);
461
+ log(` ${cliInstall}`, colors.cyan);
462
+ log('');
463
+ }
464
+ log(' Create Spaces in it:', colors.bold);
465
+ log(' Inside the sandbox, run "minion login", then "minion" from any folder', colors.dim);
466
+ log(' (~/spaces is ready for them). The sandbox then appears as its own', colors.dim);
467
+ log(` machine in ${APP_NAME}.`, colors.dim);
468
+ log('');
469
+ log(' Manage it:', colors.bold);
470
+ log(' minion list sandboxes', colors.dim);
471
+ log(` minion rename sandbox ${names.name} <new-name>`, colors.dim);
472
+ log(` minion restart sandbox ${names.name}`, colors.dim);
473
+ if (memoryGb) log(` minion restart sandbox ${names.name} --uncap (lift the memory cap later)`, colors.dim);
474
+ log(` Stop: docker stop ${names.container}`, colors.dim);
475
+ log(` Delete: docker rm -f ${names.container} && docker volume rm ${names.volume}${diskCapped ? ` && rm ${imagePathFor(names.name)}` : ''}`, colors.dim);
476
+ log('');
477
+ }
478
+
479
+ export async function createSandbox(args = []) {
480
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
481
+ log('\n "minion create sandbox" is interactive — run it from a terminal.\n', colors.red);
482
+ process.exit(1);
483
+ }
484
+
485
+ const parsed = parseSandboxArgs(args);
486
+ if (!parsed.ok) {
487
+ log(`\n ${parsed.error}`, colors.red);
488
+ log(' Usage: minion create sandbox [name] [--rebuild] [--memory <GB>] [--disk <GB>]\n', colors.dim);
489
+ process.exit(1);
490
+ }
491
+ const { name: explicitName, rebuild, memoryGb, diskGb } = parsed;
492
+
493
+ log(`\n ${APP_NAME} Sandbox Setup\n`, colors.bold + colors.cyan);
494
+ log(' Creates an isolated sandbox — its own disk region, provisioned with', colors.dim);
495
+ log(' zsh, Node, Claude Code and the minion CLI, ready for you to create', colors.dim);
496
+ log(' Spaces in.\n', colors.dim);
497
+
498
+ const docker = await requireDocker();
499
+ const { taken, names: explicitNames, suggested } = await resolveName(explicitName);
500
+ const imageExists = await cachedImageMatches();
501
+ const capPlanned = diskGb !== null && (await diskCapSupported(docker));
502
+
503
+ const { names, repoUrls, confirmed } = await runWizard({
504
+ names: explicitNames, suggested, taken, memoryGb, diskGb, capPlanned, imageExists, rebuild,
505
+ });
506
+ if (!confirmed) {
507
+ log('\n Cancelled — nothing was created.\n', colors.dim);
508
+ process.exit(0);
509
+ }
510
+
511
+ await ensureImage(imageExists, rebuild);
512
+ const diskCapped = await provisionDisk(names, diskGb, capPlanned);
513
+
514
+ log(' Starting the sandbox...', colors.bold);
515
+ let run = await runCapture('docker', buildRunArgs({ names, memoryGb, diskGb, diskCapped }));
516
+ let sandboxedBrowser = true;
517
+ if (!run.ok && /seccomp/i.test(run.stderr)) {
518
+ log(` This Docker daemon rejected the browser seccomp profile — starting without it: ${run.stderr.trim()}`, colors.yellow);
519
+ await runCapture('docker', ['rm', '-f', names.container]);
520
+ run = await runCapture('docker', buildRunArgs({ names, memoryGb, diskGb, diskCapped, seccompProfile: null }));
521
+ sandboxedBrowser = false;
522
+ }
523
+ if (!run.ok) {
524
+ log(`\n docker run failed: ${run.stderr.trim()}`, colors.red);
525
+ await runCapture('docker', ['volume', 'rm', names.volume]);
526
+ if (diskCapped) rmSync(imagePathFor(names.name), { force: true });
527
+ log(' Cleaned up — nothing was left behind. Re-run to try again.\n', colors.dim);
528
+ process.exit(1);
529
+ }
530
+
531
+ log(` ${colors.dim}First boot: installing the toolchain into the sandbox disk...${colors.reset}`);
532
+ const boot = await waitForFirstBoot(names.container);
533
+ if (!boot.ok) {
534
+ log(` First boot did not finish cleanly — inspect it with: docker logs ${names.container}`, colors.yellow);
535
+ }
536
+
537
+ await installRepos(names, repoUrls, boot.ok);
538
+ const cliInstall = boot.ok ? await pendingCliInstall(names.container) : '';
539
+ printDone({ names, memoryGb, diskGb, diskCapped, cliInstall, sandboxedBrowser });
540
+ }
541
+
542
+ export default createSandbox;
@@ -0,0 +1,101 @@
1
+
2
+ import { APP_NAME } from '../branding.js';
3
+ import { launchFlagSuffix } from '../launch-env.js';
4
+
5
+ const colors = {
6
+ reset: '\x1b[0m',
7
+ bold: '\x1b[1m',
8
+ green: '\x1b[32m',
9
+ yellow: '\x1b[33m',
10
+ red: '\x1b[31m',
11
+ dim: '\x1b[2m',
12
+ cyan: '\x1b[36m',
13
+ };
14
+
15
+ function log(msg, color = '') {
16
+ console.log(`${color}${msg}${colors.reset}`);
17
+ }
18
+
19
+ const E2EE_PUBLIC_KEY_PATTERN = /^[A-Za-z0-9_-]{43}$/;
20
+
21
+ async function loadE2eeIdentityModule() {
22
+ try {
23
+ return await import('../../dist/server/services/e2ee-identity.js');
24
+ } catch {
25
+ try {
26
+ const tsx = await import('tsx/esm/api');
27
+ return await tsx.tsImport('../../server/services/e2ee-identity.ts', import.meta.url);
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ }
33
+
34
+ export async function fingerprint(args = []) {
35
+ const envSuffix = launchFlagSuffix(process.env.MINIONRY_ENV);
36
+ const peerKey = args.find((a) => !a.startsWith('-'));
37
+
38
+ log(`\n ${APP_NAME} — Verify encryption\n`, colors.bold + colors.cyan);
39
+
40
+ const mod = await loadE2eeIdentityModule();
41
+ if (!mod?.ensureE2eeIdentity) {
42
+ log(' Could not load the encryption module on this runtime.', colors.yellow);
43
+ log(' End-to-end encryption may be unavailable here.', colors.dim);
44
+ log('');
45
+ return;
46
+ }
47
+
48
+ const status = await mod.ensureE2eeIdentity();
49
+ if (!status?.available || !status.publicKey) {
50
+ log(' Encryption isn\'t set up on this machine yet.', colors.yellow);
51
+ if (status?.reason) log(` Reason: ${status.reason}`, colors.dim);
52
+ log('');
53
+ log(` Sign in to set up an encryption identity:`, colors.dim);
54
+ log(` minion login${envSuffix}`, colors.dim);
55
+ log('');
56
+ return;
57
+ }
58
+
59
+ if (!peerKey) {
60
+ log(' This machine\'s encryption key', colors.bold);
61
+ log(` ${status.publicKey}`, colors.dim);
62
+ log('');
63
+ log(' To check that your browser is talking to THIS machine (and not an', colors.dim);
64
+ log(' impostor), open the Space in the web app, choose "Verify encryption",', colors.dim);
65
+ log(' and run the command it shows you here. Then compare the two safety', colors.dim);
66
+ log(' numbers — they must match exactly.', colors.dim);
67
+ log('');
68
+ return;
69
+ }
70
+
71
+ if (!E2EE_PUBLIC_KEY_PATTERN.test(peerKey)) {
72
+ log(' That doesn\'t look like a web session key.', colors.red);
73
+ log(' Copy the exact command shown under "Verify encryption" in the web app.', colors.dim);
74
+ log('');
75
+ log(` Usage: minion fingerprint <web-session-key>`, colors.dim);
76
+ log('');
77
+ process.exitCode = 1;
78
+ return;
79
+ }
80
+
81
+ let safetyNumber;
82
+ try {
83
+ safetyNumber = await mod.deriveSessionSafetyNumber(peerKey);
84
+ } catch (err) {
85
+ log(' Could not compute a safety number.', colors.red);
86
+ log(` ${err instanceof Error ? err.message : String(err)}`, colors.dim);
87
+ log('');
88
+ process.exitCode = 1;
89
+ return;
90
+ }
91
+
92
+ log(' Safety number', colors.bold);
93
+ log(` ${safetyNumber}`, colors.green + colors.bold);
94
+ log('');
95
+ log(' Compare this with the number shown in the web app.', colors.dim);
96
+ log(' If every group matches, your connection is verified end to end.', colors.dim);
97
+ log(` If they ${colors.reset}${colors.yellow}don't${colors.reset}${colors.dim} match, stop — someone may be intercepting this Space.`, colors.dim);
98
+ log('');
99
+ }
100
+
101
+ export default fingerprint;