@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,96 @@
1
+ // Copyright (c) 2025-present Minionry, Inc.
2
+ // SPDX-License-Identifier: LicenseRef-Minionry-Software
3
+ import { scopeExecutionDir } from './handler-context.js';
4
+ import { denyIfViewOnly } from './plan-helpers.js';
5
+ function broadcastPromptQueueSync(ctx, registry, tabId) {
6
+ ctx.broadcastToAll({
7
+ type: 'promptQueueSync',
8
+ tabId,
9
+ data: { tabId, queue: registry.getPromptQueue(tabId) },
10
+ });
11
+ }
12
+ export function handleQueueEnqueuePrompt(ctx, _ws, msg, tabId) {
13
+ const prompt = msg.data?.prompt;
14
+ if (typeof prompt !== 'string' || !prompt)
15
+ return;
16
+ const registry = ctx.getRegistry('');
17
+ registry.enqueuePrompt(tabId, {
18
+ prompt,
19
+ attachments: msg.data?.attachments,
20
+ meta: msg.data?.meta,
21
+ });
22
+ broadcastPromptQueueSync(ctx, registry, tabId);
23
+ }
24
+ export function handleQueueRemovePrompt(ctx, _ws, msg, tabId) {
25
+ const index = msg.data?.index;
26
+ if (typeof index !== 'number')
27
+ return;
28
+ const registry = ctx.getRegistry('');
29
+ registry.removeQueuedPrompt(tabId, index);
30
+ broadcastPromptQueueSync(ctx, registry, tabId);
31
+ }
32
+ export function handleQueueClearPrompts(ctx, _ws, _msg, tabId) {
33
+ const registry = ctx.getRegistry('');
34
+ registry.clearPromptQueue(tabId);
35
+ broadcastPromptQueueSync(ctx, registry, tabId);
36
+ }
37
+ function broadcastComposerQueueSync(ctx, registry, boardId) {
38
+ ctx.broadcastToAll({
39
+ type: 'composerPromptQueueSync',
40
+ data: { boardId, queue: registry.getBoardQueue(boardId).map((item) => ({ prompt: item.prompt })) },
41
+ });
42
+ }
43
+ const MODEL_WIRE_KEYS = [
44
+ 'modelStrategy', 'engine', 'model', 'effortLevel', 'fastMode',
45
+ 'runModel', 'runEngine', 'runEffortLevel', 'runFastMode',
46
+ ];
47
+ function pickModelWireFields(data) {
48
+ if (!data)
49
+ return undefined;
50
+ const picked = {};
51
+ let found = false;
52
+ for (const key of MODEL_WIRE_KEYS) {
53
+ if (key in data) {
54
+ picked[key] = data[key];
55
+ found = true;
56
+ }
57
+ }
58
+ return found ? picked : undefined;
59
+ }
60
+ export function handleQueueEnqueueComposerPrompt(ctx, ws, msg, workingDir, permission) {
61
+ if (denyIfViewOnly(ctx, ws, permission))
62
+ return;
63
+ const boardId = msg.data?.boardId;
64
+ const prompt = msg.data?.prompt;
65
+ if (typeof boardId !== 'string' || !boardId || typeof prompt !== 'string' || !prompt)
66
+ return;
67
+ const registry = ctx.getRegistry(workingDir);
68
+ const meta = {
69
+ executionDir: scopeExecutionDir(ctx, boardId),
70
+ agentTabId: typeof msg.data?.agentTabId === 'string' ? msg.data.agentTabId : undefined,
71
+ modelData: pickModelWireFields(msg.data),
72
+ };
73
+ registry.enqueueBoardPrompt(boardId, { prompt, attachments: msg.data?.attachments, meta });
74
+ broadcastComposerQueueSync(ctx, registry, boardId);
75
+ }
76
+ export function handleQueueRemoveComposerPrompt(ctx, ws, msg, workingDir, permission) {
77
+ if (denyIfViewOnly(ctx, ws, permission))
78
+ return;
79
+ const boardId = msg.data?.boardId;
80
+ const index = msg.data?.index;
81
+ if (typeof boardId !== 'string' || !boardId || typeof index !== 'number')
82
+ return;
83
+ const registry = ctx.getRegistry(workingDir);
84
+ registry.removeBoardQueuedPrompt(boardId, index);
85
+ broadcastComposerQueueSync(ctx, registry, boardId);
86
+ }
87
+ export function handleQueueClearComposerPrompts(ctx, ws, msg, workingDir, permission) {
88
+ if (denyIfViewOnly(ctx, ws, permission))
89
+ return;
90
+ const boardId = msg.data?.boardId;
91
+ if (typeof boardId !== 'string' || !boardId)
92
+ return;
93
+ const registry = ctx.getRegistry(workingDir);
94
+ registry.clearBoardQueue(boardId);
95
+ broadcastComposerQueueSync(ctx, registry, boardId);
96
+ }
@@ -0,0 +1,229 @@
1
+ // Copyright (c) 2025-present Minionry, Inc.
2
+ // SPDX-License-Identifier: LicenseRef-Minionry-Software
3
+ import { promises as fsp } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { spacePath } from '../space-layout.js';
6
+ import { movementWrittenFiles } from './movement-written-files.js';
7
+ import { attributeToTrackedDirectories } from './quality-tools.js';
8
+ import { findingCountsTowardGrade, } from './quality-types.js';
9
+ export const MAX_HISTORY_FILES = 200;
10
+ export const MAX_HISTORY_BYTES = 64 * 1024 * 1024;
11
+ export const MIN_TURNS_PER_FILE = 5;
12
+ export const MIN_TURNS_PER_SIDE = 10;
13
+ export const MAX_FILE_ROWS = 100;
14
+ export const AGENT_COST_STRUCTURAL_CATEGORIES = new Set([
15
+ 'complexity',
16
+ 'file-length',
17
+ 'function-length',
18
+ 'architecture',
19
+ 'oop',
20
+ 'maintainability',
21
+ 'duplication',
22
+ ]);
23
+ const RUN_LEVEL_BOARD_SESSION = /-pm-(?:BOARD-|run$)/;
24
+ const RECOGNIZED_WRITE_TOOL_ENGINE = 'claude-code';
25
+ export function isRunLevelBoardSession(fileName) {
26
+ return RUN_LEVEL_BOARD_SESSION.test(fileName.endsWith('.json') ? fileName.slice(0, -'.json'.length) : fileName);
27
+ }
28
+ export async function sampleAgentCost(options) {
29
+ try {
30
+ return await sample(options);
31
+ }
32
+ catch (error) {
33
+ return { available: false, reason: `agent-turn history could not be sampled: ${describeError(error, options.spaceRoot)}` };
34
+ }
35
+ }
36
+ function describeError(error, spaceRoot) {
37
+ const message = error instanceof Error ? error.message : String(error);
38
+ return message.split(spaceRoot).join('<space>');
39
+ }
40
+ async function sample(options) {
41
+ const historyDir = spacePath(options.spaceRoot, 'history');
42
+ let names;
43
+ try {
44
+ names = (await fsp.readdir(historyDir)).filter((name) => name.endsWith('.json') && !isRunLevelBoardSession(name));
45
+ }
46
+ catch (error) {
47
+ if (error.code === 'ENOENT') {
48
+ return { available: false, reason: 'no agent-turn history: this Space has no .minionry/history/ directory yet' };
49
+ }
50
+ return { available: false, reason: `agent-turn history could not be opened: ${describeError(error, options.spaceRoot)}` };
51
+ }
52
+ let unreadableFiles = 0;
53
+ const stats = await Promise.all(names.map(async (name) => {
54
+ try {
55
+ const s = await fsp.stat(join(historyDir, name));
56
+ return { name, mtimeMs: s.mtimeMs, size: s.size };
57
+ }
58
+ catch {
59
+ unreadableFiles += 1;
60
+ return null;
61
+ }
62
+ }));
63
+ const { selected, truncated } = selectNewest(stats.filter((s) => s !== null), options.maxFiles ?? MAX_HISTORY_FILES, options.maxBytes ?? MAX_HISTORY_BYTES);
64
+ const cache = options.persistence.loadAgentCostCache();
65
+ const fresh = {};
66
+ const movements = [];
67
+ for (const file of selected) {
68
+ const hit = cache[file.name];
69
+ if (hit && hit.mtimeMs === file.mtimeMs && hit.size === file.size) {
70
+ fresh[file.name] = hit;
71
+ movements.push(...hit.movements);
72
+ continue;
73
+ }
74
+ const parsed = await parseHistoryFile(join(historyDir, file.name));
75
+ if (parsed === null) {
76
+ unreadableFiles += 1;
77
+ continue;
78
+ }
79
+ fresh[file.name] = { mtimeMs: file.mtimeMs, size: file.size, movements: parsed };
80
+ movements.push(...parsed);
81
+ }
82
+ options.persistence.saveAgentCostCache(fresh);
83
+ return {
84
+ available: true,
85
+ sampledAt: new Date().toISOString(),
86
+ truncated,
87
+ unreadableFiles,
88
+ ...joinAgentCost(movements, options),
89
+ };
90
+ }
91
+ function selectNewest(files, maxFiles, maxBytes) {
92
+ const ordered = [...files].sort((a, b) => b.mtimeMs - a.mtimeMs);
93
+ const selected = [];
94
+ let bytes = 0;
95
+ for (const file of ordered) {
96
+ if (selected.length >= maxFiles || bytes + file.size > maxBytes)
97
+ return { selected, truncated: true };
98
+ selected.push(file);
99
+ bytes += file.size;
100
+ }
101
+ return { selected, truncated: false };
102
+ }
103
+ async function parseHistoryFile(path) {
104
+ let data;
105
+ try {
106
+ data = JSON.parse(await fsp.readFile(path, 'utf-8'));
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ if (typeof data !== 'object' || data === null)
112
+ return null;
113
+ const session = data;
114
+ if (!Array.isArray(session.movements))
115
+ return null;
116
+ const sessionEngine = typeof session.engine === 'string' ? session.engine : undefined;
117
+ return session.movements.map((movement) => reduceMovement(movement, sessionEngine));
118
+ }
119
+ function reduceMovement(movement, sessionEngine) {
120
+ const m = movement ?? {};
121
+ const reduced = {
122
+ engine: typeof m.engine === 'string' ? m.engine : (sessionEngine ?? RECOGNIZED_WRITE_TOOL_ENGINE),
123
+ toolUses: Array.isArray(m.toolUseHistory) ? m.toolUseHistory.length : 0,
124
+ written: movementWrittenFiles(m),
125
+ };
126
+ if (typeof m.outputTokens === 'number' && Number.isFinite(m.outputTokens))
127
+ reduced.outputTokens = m.outputTokens;
128
+ if (typeof m.durationMs === 'number' && Number.isFinite(m.durationMs))
129
+ reduced.durationMs = m.durationMs;
130
+ return reduced;
131
+ }
132
+ function placeMovement(m, options) {
133
+ if (m.written.length === 0) {
134
+ return m.toolUses > 0 && m.engine !== RECOGNIZED_WRITE_TOOL_ENGINE ? { kind: 'unattributed', reason: 'unknownWriteTools' } : { kind: 'elsewhere' };
135
+ }
136
+ if (m.outputTokens === undefined)
137
+ return { kind: 'unattributed', reason: 'missingOutputTokens' };
138
+ const attributed = attributeToTrackedDirectories(options.spaceRoot, [{ path: options.reportPath }], m.written);
139
+ if (attributed.length === 0)
140
+ return { kind: 'unattributed', reason: 'outsideSpaceRoot' };
141
+ const mine = attributed.find((entry) => entry.path === options.reportPath);
142
+ if (!mine)
143
+ return { kind: 'elsewhere' };
144
+ const placement = { kind: 'attributed', outputTokens: m.outputTokens, files: [...new Set(mine.files)] };
145
+ if (m.durationMs !== undefined)
146
+ placement.durationMs = m.durationMs;
147
+ return placement;
148
+ }
149
+ function tallyStructuralFiles(turn, structural, perFile) {
150
+ let touched = false;
151
+ for (const file of turn.files) {
152
+ if (!structural.has(file))
153
+ continue;
154
+ touched = true;
155
+ const samples = perFile.get(file) ?? { outputTokens: [], durationMs: [] };
156
+ samples.outputTokens.push(turn.outputTokens);
157
+ if (turn.durationMs !== undefined)
158
+ samples.durationMs.push(turn.durationMs);
159
+ perFile.set(file, samples);
160
+ }
161
+ return touched;
162
+ }
163
+ export function joinAgentCost(movements, options) {
164
+ const structural = activeStructuralFiles(options.results);
165
+ const unattributed = { missingOutputTokens: 0, outsideSpaceRoot: 0, unknownWriteTools: 0 };
166
+ const perFile = new Map();
167
+ const withStructural = [];
168
+ const withoutStructural = [];
169
+ for (const m of movements) {
170
+ const placed = placeMovement(m, options);
171
+ if (placed.kind === 'unattributed')
172
+ unattributed[placed.reason] += 1;
173
+ if (placed.kind !== 'attributed')
174
+ continue;
175
+ (tallyStructuralFiles(placed, structural, perFile) ? withStructural : withoutStructural).push(placed.outputTokens);
176
+ }
177
+ return {
178
+ sampledTurns: movements.length,
179
+ attributedTurns: withStructural.length + withoutStructural.length,
180
+ unattributed,
181
+ files: fileRows(perFile),
182
+ comparison: {
183
+ withStructuralFindings: side(withStructural),
184
+ withoutStructuralFindings: side(withoutStructural),
185
+ },
186
+ };
187
+ }
188
+ function activeStructuralFiles(results) {
189
+ const files = new Set();
190
+ for (const finding of [...(results.findings ?? []), ...(results.codeReview ?? [])]) {
191
+ if (!AGENT_COST_STRUCTURAL_CATEGORIES.has(finding.category) || !findingCountsTowardGrade(finding))
192
+ continue;
193
+ if (typeof finding.file !== 'string' || finding.file === '')
194
+ continue;
195
+ files.add(finding.file.replace(/^\.\//, ''));
196
+ }
197
+ return files;
198
+ }
199
+ function fileRows(perFile) {
200
+ return [...perFile.entries()]
201
+ .sort(([fileA, a], [fileB, b]) => b.outputTokens.length - a.outputTokens.length || (fileA < fileB ? -1 : fileA > fileB ? 1 : 0))
202
+ .slice(0, MAX_FILE_ROWS)
203
+ .map(([file, samples]) => fileRow(file, samples));
204
+ }
205
+ function fileRow(file, samples) {
206
+ const turns = samples.outputTokens.length;
207
+ if (turns < MIN_TURNS_PER_FILE)
208
+ return { file, turns, reason: `${plural(turns, 'turn')}; ${MIN_TURNS_PER_FILE} needed` };
209
+ const row = { file, turns, medianOutputTokens: median(samples.outputTokens) };
210
+ if (samples.durationMs.length >= MIN_TURNS_PER_FILE)
211
+ row.medianDurationMs = median(samples.durationMs);
212
+ else
213
+ row.reason = `${plural(samples.durationMs.length, 'turn')} recorded durationMs; ${MIN_TURNS_PER_FILE} needed`;
214
+ return row;
215
+ }
216
+ function side(outputTokens) {
217
+ const turns = outputTokens.length;
218
+ if (turns < MIN_TURNS_PER_SIDE)
219
+ return { turns, reason: `${plural(turns, 'turn')}; ${MIN_TURNS_PER_SIDE} needed` };
220
+ return { turns, medianOutputTokens: median(outputTokens) };
221
+ }
222
+ function median(values) {
223
+ const sorted = [...values].sort((a, b) => a - b);
224
+ const mid = Math.floor(sorted.length / 2);
225
+ return sorted.length % 2 === 1 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
226
+ }
227
+ function plural(count, noun) {
228
+ return `${count} ${noun}${count === 1 ? '' : 's'}`;
229
+ }
@@ -0,0 +1,113 @@
1
+ // Copyright (c) 2025-present Minionry, Inc.
2
+ // SPDX-License-Identifier: LicenseRef-Minionry-Software
3
+ import { relative, resolve } from 'node:path';
4
+ import { getQualityAgentNotes } from '../settings.js';
5
+ import { movementWrittenFiles } from './movement-written-files.js';
6
+ import { getPersistence } from './quality-handlers.js';
7
+ import { indexDismissals } from './quality-service.js';
8
+ export const QUALITY_NOTE_OPEN = '--- Minionry quality note ---';
9
+ export const QUALITY_NOTE_CLOSE = '--- End quality note ---';
10
+ export const QUALITY_NOTE_MAX_FINDINGS = 10;
11
+ export const QUALITY_NOTE_MAX_CHARS = 1_500;
12
+ export const QUALITY_NOTE_TRANSCRIPT_CODE = 'QUALITY_AGENT_NOTE';
13
+ export const QUALITY_REVIEW_TAB_PREFIX = 'quality-review-';
14
+ const SEVERITY_RANK = { critical: 0, high: 1, medium: 2, low: 3 };
15
+ const MAX_LINE_CHARS = 400;
16
+ const notes = new Map();
17
+ export function isInteractiveAgentTab(session, tabId) {
18
+ return session.appOrigin === undefined && !tabId.startsWith(QUALITY_REVIEW_TAB_PREFIX);
19
+ }
20
+ export function buildQualityAgentNote(spaceRoot, movement, announced) {
21
+ const written = new Set(movementWrittenFiles(movement).map((file) => resolve(file)));
22
+ if (written.size === 0)
23
+ return null;
24
+ const candidates = announced.flatMap((change) => noteFindingsOf(spaceRoot, written, change));
25
+ if (candidates.length === 0)
26
+ return null;
27
+ candidates.sort((a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity]);
28
+ const findings = fitWithinCaps(candidates);
29
+ return findings.length > 0 ? { spaceRoot, findings } : null;
30
+ }
31
+ function noteFindingsOf(spaceRoot, written, change) {
32
+ if (change.kind !== 'agentTurn' || change.worktree)
33
+ return [];
34
+ const out = [];
35
+ for (const f of change.results.findings) {
36
+ if (!qualifies(f))
37
+ continue;
38
+ const absolute = resolve(spaceRoot, change.path, f.file);
39
+ if (!written.has(absolute))
40
+ continue;
41
+ out.push({
42
+ severity: f.severity,
43
+ path: relative(spaceRoot, absolute),
44
+ line: f.line,
45
+ title: f.title,
46
+ ...(f.suggestion ? { suggestion: f.suggestion } : {}),
47
+ ...(f.fingerprint !== undefined ? { fingerprint: f.fingerprint } : {}),
48
+ reportPath: change.path,
49
+ });
50
+ }
51
+ return out;
52
+ }
53
+ function qualifies(f) {
54
+ return f.introduced === true && f.dismissal === undefined && f.status !== 'likely-fp' && SEVERITY_RANK[f.severity] <= SEVERITY_RANK.medium;
55
+ }
56
+ function fitWithinCaps(sorted) {
57
+ for (let count = Math.min(sorted.length, QUALITY_NOTE_MAX_FINDINGS); count > 0; count--) {
58
+ const prefix = sorted.slice(0, count);
59
+ if (renderQualityAgentNote(prefix).length <= QUALITY_NOTE_MAX_CHARS)
60
+ return prefix;
61
+ }
62
+ return [];
63
+ }
64
+ function renderFindingLine(f) {
65
+ const location = f.line === null ? f.path : `${f.path}:${f.line}`;
66
+ const line = [location, f.title, ...(f.suggestion ? [f.suggestion] : [])].join(' — ');
67
+ return line.length > MAX_LINE_CHARS ? `${line.slice(0, MAX_LINE_CHARS - 1)}…` : line;
68
+ }
69
+ export function renderQualityAgentNote(findings) {
70
+ const count = findings.length;
71
+ return [
72
+ QUALITY_NOTE_OPEN,
73
+ `The quality scan of your previous turn found ${count} new ${count === 1 ? 'issue' : 'issues'} in files you wrote (paths are relative to the Space root). Fix them in this turn, or say why they are intended:`,
74
+ ...findings.map((f) => `- ${renderFindingLine(f)}`),
75
+ QUALITY_NOTE_CLOSE,
76
+ ].join('\n');
77
+ }
78
+ export function recordQualityAgentNote(tabId, spaceRoot, movement, announced) {
79
+ const note = buildQualityAgentNote(spaceRoot, movement, announced);
80
+ if (!note)
81
+ return null;
82
+ if (!getQualityAgentNotes())
83
+ return null;
84
+ notes.set(tabId, note);
85
+ return note;
86
+ }
87
+ export function takeQualityAgentNote(tabId) {
88
+ const note = notes.get(tabId);
89
+ if (!note)
90
+ return null;
91
+ notes.delete(tabId);
92
+ if (!getQualityAgentNotes())
93
+ return null;
94
+ const suppressions = getPersistence(note.spaceRoot).loadSuppressions();
95
+ const indexes = new Map();
96
+ const kept = note.findings.filter((f) => {
97
+ if (f.fingerprint === undefined)
98
+ return true;
99
+ let index = indexes.get(f.reportPath);
100
+ if (!index) {
101
+ index = indexDismissals(f.reportPath, suppressions);
102
+ indexes.set(f.reportPath, index);
103
+ }
104
+ return !index.has(f.fingerprint);
105
+ });
106
+ return kept.length > 0 ? renderQualityAgentNote(kept) : null;
107
+ }
108
+ export function peekQualityAgentNote(tabId) {
109
+ return notes.get(tabId);
110
+ }
111
+ export function resetQualityAgentNotes() {
112
+ notes.clear();
113
+ }
@@ -0,0 +1,187 @@
1
+ // Copyright (c) 2025-present Minionry, Inc.
2
+ // SPDX-License-Identifier: LicenseRef-Minionry-Software
3
+ import { executeGitCommand } from '../git/command.js';
4
+ import { unquoteGitPath } from '../git/parsers.js';
5
+ import { findingCountsTowardGrade, } from './quality-types.js';
6
+ export const CHANGE_ACTIVITY_WINDOW_DAYS = 90;
7
+ export const CHANGE_ACTIVITY_COMMIT_CAP = 2_000;
8
+ export const CHANGE_ACTIVITY_MOST_CHANGED_FILES = 50;
9
+ const GIT_OPTIONS = {
10
+ timeoutMs: 60_000,
11
+ maxOutputBytes: 64 * 1024 * 1024,
12
+ env: { GIT_OPTIONAL_LOCKS: '0' },
13
+ };
14
+ const COMMIT_MARKER = '\0';
15
+ export const GIT_LOG_ARGV = Object.freeze([
16
+ '-c',
17
+ 'core.quotePath=true',
18
+ 'log',
19
+ '--numstat',
20
+ '--no-renames',
21
+ '--format=%x00%H%x00%cI',
22
+ `--since=${CHANGE_ACTIVITY_WINDOW_DAYS}.days.ago`,
23
+ `--max-count=${CHANGE_ACTIVITY_COMMIT_CAP + 1}`,
24
+ '--',
25
+ '.',
26
+ ]);
27
+ const GIT_PREFIX_ARGV = Object.freeze(['rev-parse', '--is-inside-work-tree', '--show-prefix']);
28
+ const GIT_HEAD_ARGV = Object.freeze(['rev-parse', 'HEAD', '--abbrev-ref', 'HEAD']);
29
+ const GIT_STATUS_ARGV = Object.freeze(['status', '--porcelain', '--untracked-files=normal', '--', '.']);
30
+ const NUMSTAT_LINE = /^(\d+|-)\t(\d+|-)\t(.+)$/;
31
+ const OBJECT_NAME = /^[0-9a-f]{40}(?:[0-9a-f]{24})?$/;
32
+ export async function sampleChangeActivity(options) {
33
+ try {
34
+ return await sample(options);
35
+ }
36
+ catch (error) {
37
+ return { changeActivity: unavailable(`change activity could not be sampled: ${describeError(error, options.dirPath)}`) };
38
+ }
39
+ }
40
+ function unavailable(reason) {
41
+ return { available: false, reason, windowDays: CHANGE_ACTIVITY_WINDOW_DAYS, commitsScanned: 0, truncated: false, files: {} };
42
+ }
43
+ async function sample(options) {
44
+ const { dirPath } = options;
45
+ const located = await executeGitCommand([...GIT_PREFIX_ARGV], dirPath, GIT_OPTIONS);
46
+ if (isGitMissing(located))
47
+ return { changeActivity: unavailable('git is not on PATH') };
48
+ if (located.exitCode !== 0) {
49
+ const reason = /not a git repository/i.test(located.stderr) ? 'not inside a git work tree' : `git rev-parse failed: ${firstLine(located.stderr) || `exit code ${located.exitCode}`}`;
50
+ return { changeActivity: unavailable(redact(reason, dirPath)) };
51
+ }
52
+ const [insideWorkTree = '', prefix = ''] = located.stdout.split('\n').map((line) => line.trim());
53
+ if (insideWorkTree !== 'true')
54
+ return { changeActivity: unavailable('not inside a git work tree') };
55
+ const [log, head, status] = await Promise.all([
56
+ executeGitCommand([...GIT_LOG_ARGV], dirPath, GIT_OPTIONS),
57
+ executeGitCommand([...GIT_HEAD_ARGV], dirPath, GIT_OPTIONS),
58
+ executeGitCommand([...GIT_STATUS_ARGV], dirPath, GIT_OPTIONS),
59
+ ]);
60
+ const commit = toCommitRef(head, status);
61
+ if (log.exitCode !== 0) {
62
+ return {
63
+ changeActivity: unavailable(redact(`git log failed: ${firstLine(log.stderr) || `exit code ${log.exitCode}`}`, dirPath)),
64
+ ...(commit ? { commit } : {}),
65
+ };
66
+ }
67
+ const parsed = parseGitLogNumstat(log.stdout, prefix);
68
+ return {
69
+ changeActivity: {
70
+ available: true,
71
+ windowDays: CHANGE_ACTIVITY_WINDOW_DAYS,
72
+ commitsScanned: parsed.commitsScanned,
73
+ truncated: parsed.truncated,
74
+ files: selectChangeActivityFiles(parsed.files, options.results),
75
+ },
76
+ ...(commit ? { commit } : {}),
77
+ };
78
+ }
79
+ function isGitMissing(result) {
80
+ return result.exitCode !== 0 && result.stdout === '' && /\bENOENT\b/.test(result.stderr);
81
+ }
82
+ function toCommitRef(head, status) {
83
+ if (head.exitCode !== 0 || status.exitCode !== 0)
84
+ return undefined;
85
+ const [sha = '', branch = ''] = head.stdout.split('\n').map((line) => line.trim());
86
+ if (!OBJECT_NAME.test(sha) || branch === '')
87
+ return undefined;
88
+ return { sha, branch, dirty: status.stdout.trim() !== '' };
89
+ }
90
+ function firstLine(text) {
91
+ return text.split('\n')[0]?.trim() ?? '';
92
+ }
93
+ function redact(text, dirPath) {
94
+ return text.split(dirPath).join('<directory>');
95
+ }
96
+ function describeError(error, dirPath) {
97
+ return redact(error instanceof Error ? error.message : String(error), dirPath);
98
+ }
99
+ export function parseGitLogNumstat(stdout, prefix) {
100
+ const dirPrefix = normalizePrefix(prefix);
101
+ const tallies = new Map();
102
+ let commitsScanned = 0;
103
+ let truncated = false;
104
+ let current = null;
105
+ for (const line of stdout.split('\n')) {
106
+ if (line.startsWith(COMMIT_MARKER)) {
107
+ if (commitsScanned >= CHANGE_ACTIVITY_COMMIT_CAP) {
108
+ truncated = true;
109
+ break;
110
+ }
111
+ commitsScanned += 1;
112
+ current = commitDate(line.split(COMMIT_MARKER)[2] ?? '');
113
+ }
114
+ else if (current !== null && line !== '') {
115
+ tallyNumstatLine(line, current, dirPrefix, tallies);
116
+ }
117
+ }
118
+ const files = {};
119
+ for (const [file, { commits, linesChanged, lastChangedAt }] of tallies)
120
+ files[file] = { commits, linesChanged, lastChangedAt };
121
+ return { commitsScanned, truncated, files };
122
+ }
123
+ function tallyNumstatLine(line, current, dirPrefix, tallies) {
124
+ const match = NUMSTAT_LINE.exec(line);
125
+ if (!match)
126
+ return;
127
+ const file = directoryRelative(decodeNumstatPath(match[3]), dirPrefix);
128
+ if (file === null)
129
+ return;
130
+ const linesChanged = numstatCount(match[1]) + numstatCount(match[2]);
131
+ const tally = tallies.get(file);
132
+ if (!tally) {
133
+ tallies.set(file, { commits: 1, linesChanged, lastChangedAt: current.at, lastChangedMs: current.atMs });
134
+ return;
135
+ }
136
+ tally.commits += 1;
137
+ tally.linesChanged += linesChanged;
138
+ if (current.atMs > tally.lastChangedMs) {
139
+ tally.lastChangedAt = current.at;
140
+ tally.lastChangedMs = current.atMs;
141
+ }
142
+ }
143
+ function normalizePrefix(prefix) {
144
+ const trimmed = prefix.trim().replace(/\/+$/, '');
145
+ return trimmed === '' ? '' : `${trimmed}/`;
146
+ }
147
+ function commitDate(raw) {
148
+ const atMs = Date.parse(raw);
149
+ return Number.isFinite(atMs) ? { at: new Date(atMs).toISOString(), atMs } : { at: raw, atMs: Number.NEGATIVE_INFINITY };
150
+ }
151
+ function numstatCount(field) {
152
+ return field === '-' ? 0 : Number(field);
153
+ }
154
+ function decodeNumstatPath(raw) {
155
+ if (!raw.startsWith('"'))
156
+ return raw;
157
+ return Buffer.from(unquoteGitPath(raw), 'latin1').toString('utf8');
158
+ }
159
+ function directoryRelative(repoRelative, dirPrefix) {
160
+ if (dirPrefix === '')
161
+ return repoRelative === '' ? null : repoRelative;
162
+ if (!repoRelative.startsWith(dirPrefix))
163
+ return null;
164
+ const relative = repoRelative.slice(dirPrefix.length);
165
+ return relative === '' ? null : relative;
166
+ }
167
+ export function selectChangeActivityFiles(files, results) {
168
+ const active = activeFindingFiles(results);
169
+ const ranked = Object.entries(files).sort(([fileA, a], [fileB, b]) => b.commits - a.commits || b.linesChanged - a.linesChanged || (fileA < fileB ? -1 : fileA > fileB ? 1 : 0));
170
+ const selected = {};
171
+ ranked.forEach(([file, row], index) => {
172
+ if (index < CHANGE_ACTIVITY_MOST_CHANGED_FILES || active.has(file))
173
+ selected[file] = row;
174
+ });
175
+ return selected;
176
+ }
177
+ function activeFindingFiles(results) {
178
+ const files = new Set();
179
+ for (const finding of [...(results.findings ?? []), ...(results.codeReview ?? [])]) {
180
+ if (!findingCountsTowardGrade(finding))
181
+ continue;
182
+ if (typeof finding.file !== 'string' || finding.file === '')
183
+ continue;
184
+ files.add(finding.file.replace(/^\.\//, ''));
185
+ }
186
+ return files;
187
+ }