@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,101 @@
1
+ // Copyright (c) 2025-present Minionry, Inc.
2
+ // SPDX-License-Identifier: LicenseRef-Minionry-Software
3
+ import { existsSync } from 'node:fs';
4
+ import { appendFile, mkdir, readFile, writeFile } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ import { validateIssuePath } from './issue-writer.js';
7
+ export async function ensureOutputDirs(pmDir, boardDir) {
8
+ if (boardDir) {
9
+ const boardOutDir = join(boardDir, 'out');
10
+ if (!existsSync(boardOutDir))
11
+ await mkdir(boardOutDir, { recursive: true });
12
+ return;
13
+ }
14
+ if (pmDir) {
15
+ const outDir = join(pmDir, 'out');
16
+ if (!existsSync(outDir))
17
+ await mkdir(outDir, { recursive: true });
18
+ }
19
+ }
20
+ export async function appendProgressEntry(pmDir, boardDir, issues, waveStart, warn, browserActivity) {
21
+ if (!pmDir)
22
+ return;
23
+ const progressPath = boardDir ? join(boardDir, 'progress.md') : join(pmDir, 'progress.md');
24
+ const durationMin = Math.round((Date.now() - waveStart) / 60_000);
25
+ const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);
26
+ const { completed, failed } = await partitionByOnDiskStatus(pmDir, issues);
27
+ const lines = [
28
+ '',
29
+ `## ${timestamp} — Wave [${issues.map(i => i.id).join(', ')}]`,
30
+ '',
31
+ `- **Duration**: ${durationMin} min`,
32
+ `- **Completed**: ${completed.length}/${issues.length}${completed.length > 0 ? ` (${completed.join(', ')})` : ''}`,
33
+ ];
34
+ if (failed.length > 0) {
35
+ lines.push(`- **Failed**: ${failed.join(', ')}`);
36
+ }
37
+ lines.push(...renderBrowserActivitySection(issues, browserActivity));
38
+ lines.push('');
39
+ await writeProgressLines(progressPath, lines, warn);
40
+ }
41
+ function renderBrowserActivitySection(issues, browserActivity) {
42
+ if (!browserActivity || browserActivity.size === 0)
43
+ return [];
44
+ const out = [];
45
+ let any = false;
46
+ for (const issue of issues) {
47
+ const entry = browserActivity.get(issue.id);
48
+ if (!entry || entry.calls === 0)
49
+ continue;
50
+ if (!any) {
51
+ out.push('', '### Browser activity', '');
52
+ any = true;
53
+ }
54
+ const toolList = entry.tools.slice(0, 8).join(', ');
55
+ const truncated = entry.tools.length > 8 ? `, +${entry.tools.length - 8} more` : '';
56
+ out.push(`- **${issue.id}** — ${entry.calls} call(s): ${toolList}${truncated}`);
57
+ if (entry.finalUrl) {
58
+ out.push(` - Final URL: ${entry.finalUrl}`);
59
+ }
60
+ out.push(' - Screenshot: see latest frame in BrowserView');
61
+ }
62
+ return out;
63
+ }
64
+ export async function appendProgressNote(pmDir, boardDir, note, warn) {
65
+ if (!pmDir)
66
+ return;
67
+ const progressPath = boardDir ? join(boardDir, 'progress.md') : join(pmDir, 'progress.md');
68
+ const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);
69
+ await writeProgressLines(progressPath, ['', `- ${timestamp} — ${note}`, ''], warn);
70
+ }
71
+ async function partitionByOnDiskStatus(pmDir, issues) {
72
+ const completed = [];
73
+ const failed = [];
74
+ for (const issue of issues) {
75
+ try {
76
+ const content = await readFile(validateIssuePath(issue.path, pmDir), 'utf-8');
77
+ const statusMatch = content.match(/^status:\s*(\S+)/m);
78
+ if (statusMatch?.[1] === 'done')
79
+ completed.push(issue.id);
80
+ else
81
+ failed.push(issue.id);
82
+ }
83
+ catch {
84
+ failed.push(issue.id);
85
+ }
86
+ }
87
+ return { completed, failed };
88
+ }
89
+ async function writeProgressLines(filePath, lines, warn) {
90
+ try {
91
+ if (existsSync(filePath)) {
92
+ await appendFile(filePath, `\n${lines.join('\n')}`, 'utf-8');
93
+ }
94
+ else {
95
+ await writeFile(filePath, `# Board Progress\n${lines.join('\n')}`, 'utf-8');
96
+ }
97
+ }
98
+ catch (err) {
99
+ warn(`Warning: failed to write progress log: ${err instanceof Error ? err.message : String(err)}`);
100
+ }
101
+ }
@@ -0,0 +1,142 @@
1
+ // Copyright (c) 2025-present Minionry, Inc.
2
+ // SPDX-License-Identifier: LicenseRef-Minionry-Software
3
+ import { join } from 'node:path';
4
+ import { specsDirOrDefault } from '../space-layout.js';
5
+ export function buildCoordinatorPrompt(options) {
6
+ const { issues, workingDir, pmDir, boardDir, existingDocs, resolveOutputPath } = options;
7
+ const outDir = resolveOutDir(workingDir, pmDir, boardDir);
8
+ const teamName = `pm-wave-${Date.now()}`;
9
+ const issueBlocks = issues.map(issue => buildIssueBlock(issue, existingDocs, resolveOutputPath)).join('\n\n---\n\n');
10
+ const teammateSpawns = issues.map(issue => buildTeammateSpawn(issue, teamName, pmDir, existingDocs, resolveOutputPath)).join('\n\n');
11
+ return assembleCoordinatorPrompt({ issues, workingDir, pmDir, outDir, teamName, issueBlocks, teammateSpawns });
12
+ }
13
+ function resolveOutDir(workingDir, pmDir, boardDir) {
14
+ if (boardDir)
15
+ return join(boardDir, 'out');
16
+ if (pmDir)
17
+ return join(pmDir, 'out');
18
+ return join(specsDirOrDefault(workingDir), 'out');
19
+ }
20
+ function buildIssueBlock(issue, existingDocs, resolveOutputPath) {
21
+ const criteria = issue.acceptanceCriteria
22
+ .map(c => `- [${c.checked ? 'x' : ' '}] ${c.text}`)
23
+ .join('\n');
24
+ const files = issue.filesToModify.length > 0
25
+ ? `\nFiles to modify:\n${issue.filesToModify.map(f => `- ${f}`).join('\n')}`
26
+ : '';
27
+ const predecessorDocs = resolvePredecessorDocs(issue, existingDocs);
28
+ const predecessorSection = predecessorDocs.length > 0
29
+ ? `\nPredecessor outputs to read:\n${predecessorDocs.map(d => `- ${d}`).join('\n')}`
30
+ : '';
31
+ return `### ${issue.id}: ${issue.title}
32
+
33
+ **Type**: ${issue.type} | **Priority**: ${issue.priority} | **Estimate**: ${issue.estimate ?? 'unestimated'}
34
+
35
+ **Description**:
36
+ ${issue.description}
37
+
38
+ **Acceptance Criteria**:
39
+ ${criteria || 'No specific criteria defined.'}
40
+
41
+ **Technical Notes**:
42
+ ${issue.technicalNotes || 'None'}
43
+ ${files}${predecessorSection}
44
+
45
+ **Output file**: ${resolveOutputPath(issue)}`;
46
+ }
47
+ function buildTeammateSpawn(issue, teamName, pmDir, existingDocs, resolveOutputPath) {
48
+ const predecessorDocs = resolvePredecessorDocs(issue, existingDocs);
49
+ const predInstr = predecessorDocs.length > 0
50
+ ? `Read these predecessor output docs before starting: ${predecessorDocs.join(', ')}. `
51
+ : '';
52
+ const outputFile = resolveOutputPath(issue);
53
+ const fileOwnership = issue.filesToModify.length > 0
54
+ ? `\n> FILE OWNERSHIP: You own these files exclusively: ${issue.filesToModify.join(', ')}. Other teammates own all other files.`
55
+ : '';
56
+ return `Spawn teammate **${issue.id.toLowerCase()}** using the **Agent** tool with \`team_name: "${teamName}"\` and \`name: "${issue.id.toLowerCase()}"\`:
57
+ > ${predInstr}Work on issue ${issue.id}: ${issue.title}.
58
+ > Read the full spec at ${pmDir ? join(pmDir, issue.path) : issue.path}.
59
+ > Execute all acceptance criteria.
60
+ > Write all output and results to ${outputFile} — this is the handoff artifact for downstream issues.
61
+ > After writing output, update the issue front matter: change \`status: in_progress\` to \`status: done\`.
62
+ > The orchestrator manages STATE.md. Stay within this issue's scope.${fileOwnership}`;
63
+ }
64
+ function assembleCoordinatorPrompt(args) {
65
+ const { issues, workingDir, pmDir, outDir, teamName, issueBlocks, teammateSpawns } = args;
66
+ const issueCount = issues.length;
67
+ const plural = issueCount > 1 ? 's' : '';
68
+ const checklist = issues.map(i => `- [ ] ${i.id.toLowerCase()}`).join('\n');
69
+ const teammateNames = issues.map(i => `- \`${i.id.toLowerCase()}\``).join('\n');
70
+ return `You are the team lead coordinating ${issueCount} issue${plural} using Agent Teams.
71
+
72
+ ## Project Directory
73
+ Working directory: ${workingDir}
74
+ Plan directory: ${pmDir || specsDirOrDefault(workingDir)}
75
+
76
+ ## Issues to Execute
77
+
78
+ ${issueBlocks}
79
+
80
+ ## Execution Protocol — Agent Teams
81
+
82
+ All team coordination uses exactly two tools:
83
+ - **Agent** — spawn teammates (include \`team_name\` and \`name\` in each call)
84
+ - **SendMessage** — message teammates after they are spawned
85
+
86
+ ### Step 1: Spawn all teammates in one message
87
+
88
+ Send a single message containing ${issueCount} **Agent** tool calls. Include \`team_name: "${teamName}"\` and a unique \`name\` in each call. The team starts automatically when the first teammate is spawned — the \`team_name\` parameter handles all setup.
89
+
90
+ ${teammateSpawns}
91
+
92
+ ### Step 2: Wait for every teammate to finish
93
+
94
+ After spawning, idle notifications arrive automatically as messages — you will be notified when each teammate finishes. Between notifications, you have nothing to do. Simply state that you are waiting and let the system deliver notifications to you.
95
+
96
+ Your first action after spawning all teammates: output a brief status message listing all teammates and confirming you are waiting for their idle notifications. Then wait.
97
+
98
+ Track completion against this checklist — proceed to Step 3 only after all are checked:
99
+ ${checklist}
100
+
101
+ Exact teammate names for SendMessage (messages to any other name are silently dropped):
102
+ ${teammateNames}
103
+
104
+ When you receive an idle notification from a teammate:
105
+ - Check off that teammate in the checklist above
106
+ - Verify their output file exists on disk using the **Read** tool
107
+
108
+ If 15 minutes pass without an idle notification from a specific teammate, send them a progress check via **SendMessage** using the exact name from the list above. After 5 more minutes with no response, check their output file and issue status on disk — if the output exists and status is \`done\`, mark them complete. Otherwise, update the issue status based on whatever partial work exists, then continue.
109
+
110
+ Staying active until all teammates finish is essential — when the lead exits, all teammate processes stop and their in-progress work is lost. When unsure whether a teammate is still working, keep waiting.
111
+
112
+ ### Step 3: Verify outputs
113
+
114
+ Once every teammate has completed or been handled:
115
+ 1. Verify each output file exists in ${outDir}/ using **Read** or **Glob**
116
+ 2. Verify each issue's front matter status is \`done\`
117
+ 3. For any missing output or status update, write it yourself
118
+ 4. The orchestrator manages STATE.md separately — focus on output files and issue front matter only
119
+
120
+ ### Step 4: Clean up and exit
121
+
122
+ After all outputs are verified:
123
+ - Send each remaining active teammate a shutdown message via **SendMessage**
124
+ - Then exit — the orchestrator handles the next wave
125
+
126
+ ## Coordination Rules
127
+
128
+ - The team starts implicitly when you spawn the first teammate with \`team_name\`. Cleanup happens automatically when all teammates exit or the lead exits.
129
+ - Wait for idle notifications from all ${issueCount} teammates before exiting — this ensures all work is saved to disk.
130
+ - Each teammate writes its output to disk (the handoff artifact for downstream issues). Research kept only in conversation is lost when the teammate exits.
131
+ - Each teammate updates its issue front matter status to \`done\` when finished.
132
+ - One issue per teammate — each teammate stays within its assigned scope.
133
+ - Use only the exact teammate names listed above for SendMessage.`;
134
+ }
135
+ function resolvePredecessorDocs(issue, existingDocs) {
136
+ return issue.blockedBy
137
+ .map(bp => {
138
+ const blockerId = bp.replace(/^backlog\//, '').replace(/\.md$/, '');
139
+ return existingDocs.find(d => d.toLowerCase().includes(blockerId.toLowerCase()));
140
+ })
141
+ .filter(Boolean);
142
+ }
@@ -0,0 +1,274 @@
1
+ // Copyright (c) 2025-present Minionry, Inc.
2
+ // SPDX-License-Identifier: LicenseRef-Minionry-Software
3
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
4
+ import { extname, join, relative, resolve } from 'node:path';
5
+ import { getPersistence } from '../websocket/quality-handlers.js';
6
+ import { QualityPersistence } from '../websocket/quality-persistence.js';
7
+ import { indexDismissals, isActiveFinding, runQualityScan } from '../websocket/quality-service.js';
8
+ import { attributeToTrackedDirectories, detectEcosystem } from '../websocket/quality-tools.js';
9
+ import { SOURCE_EXTENSIONS } from '../websocket/quality-types.js';
10
+ import { resolveIsCodeTask } from './issue-classification.js';
11
+ export const QUALITY_DELTA_DIRNAME = 'quality';
12
+ export const QUALITY_DELTA_MAX_FINDINGS = 200;
13
+ export const WORKTREE_NOT_CHECKED_REASON = 'worktree boards are not checked yet';
14
+ export function qualityGateSkipReason(issue, gate) {
15
+ if (gate === 'off')
16
+ return "quality_gate is 'off'";
17
+ if (issue.reviewGate === 'none')
18
+ return "review_gate is 'none'";
19
+ if (!resolveIsCodeTask(issue))
20
+ return 'document issue';
21
+ return null;
22
+ }
23
+ export function unavailableQualityDelta(issueId, gate, reason, now = new Date()) {
24
+ return { issueId, recordedAt: now.toISOString(), gate, available: false, reason };
25
+ }
26
+ function isInside(dir, path) {
27
+ return path === dir || path.startsWith(`${dir}/`);
28
+ }
29
+ function rootRelative(root, absolute) {
30
+ return relative(root, absolute).split('\\').join('/');
31
+ }
32
+ function uncheckableReason(absolute) {
33
+ if (!existsSync(absolute))
34
+ return 'no such file';
35
+ try {
36
+ if (!statSync(absolute).isFile())
37
+ return 'not a file';
38
+ }
39
+ catch {
40
+ return 'not readable';
41
+ }
42
+ const ext = extname(absolute).toLowerCase();
43
+ if (!SOURCE_EXTENSIONS.has(ext)) {
44
+ return `not a source file the analyzers read (${ext || 'no extension'})`;
45
+ }
46
+ return null;
47
+ }
48
+ function noEcosystemReason(dirPath) {
49
+ const where = dirPath === '.' ? 'the working directory' : `'${dirPath}'`;
50
+ return `no ecosystem detected in ${where} — no package.json, pyproject.toml, setup.py, requirements.txt, Cargo.toml, go.mod, Package.swift or build.gradle there, so no analyzer can run on it`;
51
+ }
52
+ function trackedDirectories(root) {
53
+ return QualityPersistence.isSetUp(root) ? getPersistence(root).loadConfig() : [];
54
+ }
55
+ async function scanDirectory(root, dirPath, dir, files, signal) {
56
+ if (!QualityPersistence.isSetUp(root)) {
57
+ return (await runQualityScan(dir, { files, signal })).findings;
58
+ }
59
+ const persistence = getPersistence(root);
60
+ const results = await runQualityScan(dir, {
61
+ files,
62
+ signal,
63
+ baseline: persistence.loadBaseline(dirPath),
64
+ dismissals: indexDismissals(dirPath, persistence.loadSuppressionsFor(dirPath)),
65
+ });
66
+ return results.findings;
67
+ }
68
+ async function scanPaths(deps, paths) {
69
+ const root = resolve(deps.spaceRoot);
70
+ const { admitted, unchecked } = admitPaths(root, paths);
71
+ const checked = [];
72
+ const findings = [];
73
+ for (const { path: dirPath, files } of attributeToTrackedDirectories(root, trackedDirectories(root), [...admitted])) {
74
+ const dir = resolve(root, dirPath);
75
+ const relPaths = files.map((file) => rootRelative(root, resolve(dir, file)));
76
+ if (detectEcosystem(dir).every((eco) => eco === 'unknown')) {
77
+ const reason = noEcosystemReason(dirPath);
78
+ for (const path of relPaths)
79
+ unchecked.push({ path, reason });
80
+ continue;
81
+ }
82
+ const scanned = await scanDirectory(root, dirPath, dir, files, deps.signal);
83
+ checked.push(...relPaths);
84
+ for (const finding of scanned) {
85
+ if (!isActiveFinding(finding))
86
+ continue;
87
+ findings.push({ finding, path: rootRelative(root, resolve(dir, finding.file)) });
88
+ }
89
+ }
90
+ return { checked, unchecked, findings };
91
+ }
92
+ function admitPaths(root, paths) {
93
+ const admitted = new Set();
94
+ const unchecked = [];
95
+ for (const path of paths) {
96
+ const absolute = resolve(root, path);
97
+ if (!isInside(root, absolute)) {
98
+ unchecked.push({ path, reason: 'outside the working directory — only files inside it are checked' });
99
+ continue;
100
+ }
101
+ const reason = uncheckableReason(absolute);
102
+ if (reason)
103
+ unchecked.push({ path: rootRelative(root, absolute), reason });
104
+ else
105
+ admitted.add(absolute);
106
+ }
107
+ return { admitted, unchecked };
108
+ }
109
+ function listedPaths(issue) {
110
+ const paths = [];
111
+ for (const entry of issue.filesToModify) {
112
+ const path = entry.trim().replace(/^`(.*)`$/, '$1');
113
+ if (!path || /^Output:/i.test(path))
114
+ continue;
115
+ if (!paths.includes(path))
116
+ paths.push(path);
117
+ }
118
+ return paths;
119
+ }
120
+ function errorMessage(error) {
121
+ return error instanceof Error ? error.message : String(error);
122
+ }
123
+ export async function captureQualityBaseline(deps, issue, now = new Date()) {
124
+ const root = resolve(deps.spaceRoot);
125
+ const missing = [];
126
+ const present = [];
127
+ for (const path of listedPaths(issue)) {
128
+ const absolute = resolve(root, path);
129
+ if (isInside(root, absolute) && !existsSync(absolute))
130
+ missing.push(rootRelative(root, absolute));
131
+ else
132
+ present.push(path);
133
+ }
134
+ try {
135
+ const outcome = await scanPaths(deps, present);
136
+ const fingerprints = new Set();
137
+ for (const { finding } of outcome.findings) {
138
+ if (finding.fingerprint !== undefined)
139
+ fingerprints.add(finding.fingerprint);
140
+ }
141
+ return {
142
+ available: true,
143
+ baseline: {
144
+ capturedAt: now.toISOString(),
145
+ checked: outcome.checked,
146
+ missing,
147
+ unchecked: outcome.unchecked,
148
+ fingerprints: [...fingerprints],
149
+ },
150
+ };
151
+ }
152
+ catch (error) {
153
+ return { available: false, reason: `baseline scan failed: ${errorMessage(error)}` };
154
+ }
155
+ }
156
+ function isIntroduced(finding, path, baseline, created) {
157
+ if (created.has(path))
158
+ return true;
159
+ return finding.fingerprint === undefined || !baseline.has(finding.fingerprint);
160
+ }
161
+ const SEVERITY_RANK = { critical: 0, high: 1, medium: 2, low: 3 };
162
+ function toDeltaFinding(finding, path) {
163
+ return {
164
+ severity: finding.severity,
165
+ category: finding.category,
166
+ path,
167
+ line: finding.line,
168
+ title: finding.title,
169
+ ...(finding.suggestion ? { suggestion: finding.suggestion } : {}),
170
+ fingerprint: finding.fingerprint ?? '',
171
+ };
172
+ }
173
+ export async function computeQualityDelta(deps, args, now = new Date()) {
174
+ const { issue, gate, baseline, writtenFiles } = args;
175
+ if (!baseline.available)
176
+ return unavailableQualityDelta(issue.id, gate, baseline.reason, now);
177
+ const root = resolve(deps.spaceRoot);
178
+ const paths = new Map();
179
+ for (const path of [...listedPaths(issue), ...writtenFiles]) {
180
+ const absolute = resolve(root, path);
181
+ if (!paths.has(absolute))
182
+ paths.set(absolute, path);
183
+ }
184
+ let outcome;
185
+ try {
186
+ outcome = await scanPaths(deps, [...paths.values()]);
187
+ }
188
+ catch (error) {
189
+ return unavailableQualityDelta(issue.id, gate, `delta scan failed: ${errorMessage(error)}`, now);
190
+ }
191
+ const known = new Set(baseline.baseline.fingerprints);
192
+ const createdFiles = baseline.baseline.missing.filter((path) => existsSync(resolve(root, path)));
193
+ const created = new Set(createdFiles);
194
+ const introducedAll = outcome.findings
195
+ .filter(({ finding, path }) => isIntroduced(finding, path, known, created))
196
+ .sort((a, b) => SEVERITY_RANK[a.finding.severity] - SEVERITY_RANK[b.finding.severity]);
197
+ const listed = introducedAll.slice(0, QUALITY_DELTA_MAX_FINDINGS);
198
+ return {
199
+ issueId: issue.id,
200
+ recordedAt: now.toISOString(),
201
+ gate,
202
+ available: true,
203
+ baselineAt: baseline.baseline.capturedAt,
204
+ checked: outcome.checked,
205
+ unchecked: outcome.unchecked,
206
+ createdFiles,
207
+ introducedCount: introducedAll.length,
208
+ introduced: listed.map(({ finding, path }) => toDeltaFinding(finding, path)),
209
+ truncated: introducedAll.length > listed.length,
210
+ };
211
+ }
212
+ export function qualityDeltaDir(boardDir) {
213
+ return join(boardDir, QUALITY_DELTA_DIRNAME);
214
+ }
215
+ export function persistQualityDelta(boardDir, record, epochMs = Date.now()) {
216
+ const dir = qualityDeltaDir(boardDir);
217
+ if (!existsSync(dir))
218
+ mkdirSync(dir, { recursive: true });
219
+ const path = join(dir, `${record.issueId}-${epochMs}.json`);
220
+ writeFileSync(path, `${JSON.stringify(record, null, 2)}\n`, 'utf-8');
221
+ return path;
222
+ }
223
+ const DELTA_FILE_RE = /^(.+)-(\d+)\.json$/;
224
+ export function readLatestQualityDeltas(boardDir) {
225
+ const dir = qualityDeltaDir(boardDir);
226
+ const newest = new Map();
227
+ let names;
228
+ try {
229
+ names = readdirSync(dir);
230
+ }
231
+ catch {
232
+ return new Map();
233
+ }
234
+ for (const name of names) {
235
+ const match = name.match(DELTA_FILE_RE);
236
+ if (!match)
237
+ continue;
238
+ const epochMs = Number(match[2]);
239
+ const current = newest.get(match[1]);
240
+ if (!current || epochMs > current.epochMs)
241
+ newest.set(match[1], { epochMs, name });
242
+ }
243
+ const records = new Map();
244
+ for (const [issueId, { name }] of newest) {
245
+ try {
246
+ const record = JSON.parse(readFileSync(join(dir, name), 'utf-8'));
247
+ if (record && typeof record === 'object' && record.issueId === issueId)
248
+ records.set(issueId, record);
249
+ }
250
+ catch {
251
+ }
252
+ }
253
+ return records;
254
+ }
255
+ const SEVERITIES = ['critical', 'high', 'medium', 'low'];
256
+ export function summarizeQualityDelta(record) {
257
+ const { recordedAt, gate } = record;
258
+ if (!record.available)
259
+ return { available: false, recordedAt, gate, reason: record.reason };
260
+ const introduced = Object.fromEntries(SEVERITIES.map((severity) => [severity, 0]));
261
+ for (const finding of record.introduced) {
262
+ if (finding.severity in introduced)
263
+ introduced[finding.severity] += 1;
264
+ }
265
+ return {
266
+ available: true,
267
+ recordedAt,
268
+ gate,
269
+ introducedCount: record.introducedCount,
270
+ introduced,
271
+ truncated: record.truncated,
272
+ uncheckedCount: record.unchecked.length,
273
+ };
274
+ }
@@ -0,0 +1,34 @@
1
+ // Copyright (c) 2025-present Minionry, Inc.
2
+ // SPDX-License-Identifier: LicenseRef-Minionry-Software
3
+ const TERMINAL_STATUSES = new Set(['done', 'cancelled']);
4
+ export function buildCompletionReason(issues, epicScope) {
5
+ const nonEpic = issues.filter(i => i.type !== 'epic');
6
+ const done = nonEpic.filter(i => TERMINAL_STATUSES.has(i.status)).length;
7
+ const blocked = nonEpic.filter(i => i.status === 'todo').length;
8
+ if (done === nonEpic.length)
9
+ return epicScope ? 'All epic issues are done' : 'All issues are done';
10
+ if (blocked > 0)
11
+ return `${done}/${nonEpic.length} issues done, ${blocked} blocked by incomplete dependencies`;
12
+ return epicScope ? 'All epic issues are done or blocked' : 'All work is done or blocked';
13
+ }
14
+ export function detectDeadState(issues) {
15
+ const nonEpic = issues.filter(i => i.type !== 'epic');
16
+ const stuck = nonEpic.filter(i => !TERMINAL_STATUSES.has(i.status) && i.status !== 'todo');
17
+ if (stuck.length === 0)
18
+ return null;
19
+ const stuckIds = stuck.map(i => `${i.id} (${i.status})`).join(', ');
20
+ const issueByPath = new Map(issues.map(i => [i.path, i]));
21
+ const blockedByStuck = nonEpic.filter(i => {
22
+ if (i.status !== 'todo')
23
+ return false;
24
+ return i.blockedBy.some(bp => {
25
+ const blocker = issueByPath.get(bp);
26
+ return blocker && !TERMINAL_STATUSES.has(blocker.status);
27
+ });
28
+ });
29
+ const blockedIds = blockedByStuck.map(i => i.id).join(', ');
30
+ return `Board stuck: ${stuckIds} cannot progress${blockedIds ? `. Blocking: ${blockedIds}` : ''}`;
31
+ }
32
+ export function hasBlockedIssues(issues) {
33
+ return issues.some(i => i.type !== 'epic' && !TERMINAL_STATUSES.has(i.status) && i.status !== 'todo');
34
+ }