@yemi33/minions 0.1.2447 → 0.1.2449

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 (315) hide show
  1. package/bin/cli-api-client.js +1 -1
  2. package/bin/install-internal-minions.js +1382 -44
  3. package/bin/install-layout.js +150 -0
  4. package/bin/minions.js +460 -167
  5. package/dashboard/docs/typography.md +65 -12
  6. package/dashboard/js/command-center.js +66 -7
  7. package/dashboard/js/detail-panel.js +36 -0
  8. package/dashboard/js/memory-panel.js +59 -12
  9. package/dashboard/js/qa.js +186 -45
  10. package/dashboard/js/refresh.js +148 -12
  11. package/dashboard/js/render-dispatch.js +3 -4
  12. package/dashboard/js/render-inbox.js +2 -2
  13. package/dashboard/js/render-other.js +3 -3
  14. package/dashboard/js/render-pipelines.js +14 -0
  15. package/dashboard/js/render-plans.js +57 -9
  16. package/dashboard/js/render-prd.js +132 -23
  17. package/dashboard/js/render-prs.js +195 -166
  18. package/dashboard/js/render-schedules.js +63 -3
  19. package/dashboard/js/render-utils.js +3 -3
  20. package/dashboard/js/render-watches.js +19 -3
  21. package/dashboard/js/render-work-items.js +238 -30
  22. package/dashboard/js/settings.js +205 -54
  23. package/dashboard/js/utils.js +51 -1
  24. package/dashboard/pages/home.html +1 -1
  25. package/dashboard/pages/qa.html +1 -16
  26. package/dashboard/pages/work.html +40 -0
  27. package/dashboard/shared/cc-limits.js +79 -0
  28. package/dashboard/shared/pr-filters.js +21 -38
  29. package/dashboard/shared/project-git-summary.js +1 -1
  30. package/dashboard/shared/record-filters.js +169 -0
  31. package/dashboard/shared/watches-source.js +1 -1
  32. package/dashboard/shared/welcome-popup.js +1 -1
  33. package/dashboard/shared/wi-filters.js +302 -0
  34. package/dashboard/slim/body.html +1 -0
  35. package/dashboard/slim/js/command-send.js +26 -0
  36. package/dashboard/slim/js/modals-tiles.js +380 -39
  37. package/dashboard/slim/js/status.js +13 -21
  38. package/dashboard/slim/layout.html +1 -0
  39. package/dashboard/slim/panel-bootstrap.js +6 -2
  40. package/dashboard/slim/styles.css +38 -0
  41. package/dashboard/styles.css +159 -55
  42. package/dashboard-build.js +52 -6
  43. package/dashboard.js +956 -423
  44. package/docs/README.md +11 -6
  45. package/docs/api-errors.md +2 -2
  46. package/docs/architecture-review-2026-07-09.md +1 -1
  47. package/docs/architecture.excalidraw +2 -2
  48. package/docs/auto-discovery.md +18 -9
  49. package/docs/branch-derivation.md +4 -4
  50. package/docs/capture-demos.js +39 -2
  51. package/docs/ci-runner-canary.md +123 -0
  52. package/docs/claude-md-propagation.md +2 -2
  53. package/docs/cloud-agent-dispatch.md +204 -0
  54. package/docs/command-center.md +7 -7
  55. package/docs/completion-reports.md +43 -20
  56. package/docs/constants.md +10 -3
  57. package/docs/constellation-bridge.md +134 -6
  58. package/docs/constellation-style-telemetry.md +4 -4
  59. package/docs/contracts/capability-protocol.v1.json +165 -0
  60. package/docs/cooldown-merge-semantics.md +12 -12
  61. package/docs/copilot-cli-schema.md +7 -7
  62. package/docs/cross-repo-plans.md +10 -10
  63. package/docs/dead-code-audit-retractions.md +5 -5
  64. package/docs/default-branch-ci.md +173 -0
  65. package/docs/deprecated.json +31 -31
  66. package/docs/design-inbox-entries-schema.md +3 -3
  67. package/docs/design-language.md +1051 -0
  68. package/docs/design-state-storage.md +11 -11
  69. package/docs/diagnostics-crash-reports.md +9 -9
  70. package/docs/diagnostics-memory.md +5 -5
  71. package/docs/documentation-audit-2026-07-09.md +7 -7
  72. package/docs/engine-restart.md +90 -5
  73. package/docs/harness-mode.md +1 -1
  74. package/docs/internal-install.md +338 -39
  75. package/docs/kb-dedup-duplicate-pair-investigation.md +5 -5
  76. package/docs/kb-pr3223-cascade-archiving.md +1 -1
  77. package/docs/kb-pr696-merge-conflict-docs.md +6 -6
  78. package/docs/kb-sweep.md +35 -35
  79. package/docs/keep-processes.md +1 -1
  80. package/docs/live-checkout-mode.md +30 -30
  81. package/docs/managed-spawn.md +18 -14
  82. package/docs/named-agents.md +7 -7
  83. package/docs/plan-lifecycle.md +69 -2
  84. package/docs/pr-author-identity.md +114 -0
  85. package/docs/pr-auto-fix-dispatch.md +19 -4
  86. package/docs/pr-comment-followup.md +6 -6
  87. package/docs/pr-review-fix-loop.md +59 -10
  88. package/docs/process-termination.md +40 -0
  89. package/docs/proposals/repo-pool-for-live-checkout.md +13 -13
  90. package/docs/qa-runbook-lifecycle.md +367 -17
  91. package/docs/qa-runbooks.md +3 -3
  92. package/docs/rfc-completion-json.md +18 -18
  93. package/docs/runtime-adapters.md +26 -21
  94. package/docs/security.md +6 -6
  95. package/docs/self-improvement.md +4 -4
  96. package/docs/shared-lifecycle-module-map.md +473 -472
  97. package/docs/skills.md +52 -3
  98. package/docs/slim-ux/concepts.md +121 -116
  99. package/docs/specs/agent-configurability.md +18 -18
  100. package/docs/specs/agent-rename.md +18 -18
  101. package/docs/team-memory.md +38 -21
  102. package/docs/timeouts-and-liveness.md +118 -10
  103. package/docs/tutorials/01-install-and-connect.md +1 -1
  104. package/docs/watches.md +40 -39
  105. package/docs/workspace-manifests.md +4 -4
  106. package/docs/worktree-lifecycle.md +293 -14
  107. package/engine/README.md +46 -0
  108. package/engine/{ado-comment.js → ado/comment.js} +8 -8
  109. package/engine/{ado-git-auth.js → ado/git-auth.js} +4 -4
  110. package/engine/{ado.js → ado/index.js} +417 -63
  111. package/engine/{ado-status.js → ado/status.js} +6 -8
  112. package/engine/{ado-token.js → ado/token.js} +1 -1
  113. package/engine/{acp-transport.js → agents/acp-transport.js} +62 -22
  114. package/engine/{agent-worker-pool.js → agents/agent-worker-pool.js} +17 -8
  115. package/engine/{cc-worker-pool.js → agents/cc-worker-pool.js} +16 -6
  116. package/engine/{claude-md-context.js → agents/claude-md-context.js} +5 -5
  117. package/engine/{harness-context.js → agents/harness-context.js} +5 -5
  118. package/engine/{harness.js → agents/harness.js} +3 -3
  119. package/engine/{llm.js → agents/llm.js} +18 -14
  120. package/engine/{model-discovery.js → agents/model-discovery.js} +2 -2
  121. package/engine/{playbook.js → agents/playbook.js} +155 -22
  122. package/engine/{pooled-agent-process.js → agents/pooled-agent-process.js} +14 -12
  123. package/engine/{preflight.js → agents/preflight.js} +29 -10
  124. package/engine/{spawn-agent.js → agents/spawn-agent.js} +25 -14
  125. package/engine/{spawn-phase-watchdog.js → agents/spawn-phase-watchdog.js} +16 -7
  126. package/engine/{steering.js → agents/steering.js} +5 -5
  127. package/engine/{tools-inventory.js → agents/tools-inventory.js} +2 -2
  128. package/engine/{agent-api-validation.js → api/agent-api-validation.js} +2 -2
  129. package/engine/{api-validation.js → api/api-validation.js} +1 -1
  130. package/engine/api/bridge.js +787 -0
  131. package/engine/{cc-api-validation.js → api/cc-api-validation.js} +1 -1
  132. package/engine/api/companion.js +560 -0
  133. package/engine/{content-api-validation.js → api/content-api-validation.js} +2 -2
  134. package/engine/{pr-issue-validation.js → api/pr-issue-validation.js} +33 -6
  135. package/engine/{settings-validation.js → api/settings-validation.js} +32 -4
  136. package/engine/api-contracts/agent-content.js +4 -4
  137. package/engine/api-contracts/capability-manifest.js +236 -0
  138. package/engine/api-contracts/capability-protocol.js +333 -0
  139. package/engine/api-contracts/cc-ops.js +1 -1
  140. package/engine/api-contracts/config-runtime.js +5 -0
  141. package/engine/api-contracts/core.js +28 -1
  142. package/engine/api-contracts/index.js +100 -0
  143. package/engine/api-contracts/orchestration.js +18 -5
  144. package/engine/api-contracts/pull-requests.js +37 -6
  145. package/engine/api-contracts/qa-process.js +29 -6
  146. package/engine/api-contracts/work-plan-prd.js +21 -1
  147. package/engine/cloud/contract.js +212 -0
  148. package/engine/cloud/index.js +159 -0
  149. package/engine/{execution-model.js → core/execution-model.js} +1 -1
  150. package/engine/{features.js → core/features.js} +4 -4
  151. package/engine/{operator-identity.js → core/operator-identity.js} +1 -1
  152. package/engine/{queries.js → core/queries.js} +201 -36
  153. package/engine/{safe-expr.js → core/safe-expr.js} +1 -1
  154. package/engine/{shared.js → core/shared.js} +1637 -175
  155. package/engine/{stdio-timestamps.js → core/stdio-timestamps.js} +1 -1
  156. package/engine/{untrusted-fence.js → core/untrusted-fence.js} +3 -3
  157. package/engine/db/index.js +11 -2
  158. package/engine/db/migrations/002-dispatches.js +3 -3
  159. package/engine/db/migrations/003-work-items.js +1 -1
  160. package/engine/db/migrations/004-pull-requests.js +1 -1
  161. package/engine/db/migrations/006-metrics.js +1 -1
  162. package/engine/db/migrations/007-watches.js +2 -2
  163. package/engine/db/migrations/008-small-state.js +1 -1
  164. package/engine/db/migrations/009-qa.js +1 -1
  165. package/engine/db/migrations/010-pr-links.js +1 -1
  166. package/engine/db/migrations/011-remaining-state.js +1 -1
  167. package/engine/db/migrations/012-steering-deliveries.js +2 -2
  168. package/engine/db/migrations/013-backfill-broken-note-links.js +1 -1
  169. package/engine/db/migrations/014-pr-fix-target-prefs.js +2 -2
  170. package/engine/db/migrations/015-plans-prds.js +0 -0
  171. package/engine/db/migrations/018-sql-only-cutover.js +2 -2
  172. package/engine/db/migrations/021-archived-work-items.js +1 -1
  173. package/engine/db/migrations/022-global-cc-session.js +1 -1
  174. package/engine/db/migrations/023-engine-state.js +1 -1
  175. package/engine/db/migrations/025-malformed-work-item-phantoms.js +1 -1
  176. package/engine/db/migrations/027-review-learning-lifecycle.js +1 -1
  177. package/engine/db/migrations/029-repair-reused-versions.js +20 -0
  178. package/engine/db/migrations/031-pr-author-identity.js +137 -0
  179. package/engine/{consolidation.js → memory/consolidation.js} +6 -6
  180. package/engine/{kb-sweep-runner.js → memory/kb-sweep-runner.js} +2 -2
  181. package/engine/{kb-sweep.js → memory/kb-sweep.js} +9 -7
  182. package/engine/{memory-retrieval.js → memory/memory-retrieval.js} +46 -4
  183. package/engine/{memory-store.js → memory/memory-store.js} +3 -3
  184. package/engine/{promotion.js → memory/promotion.js} +3 -3
  185. package/engine/{review-learning-backfill.js → memory/review-learning-backfill.js} +6 -6
  186. package/engine/{review-learning.js → memory/review-learning.js} +10 -5
  187. package/engine/{diagnostics-memory.js → observability/diagnostics-memory.js} +1 -1
  188. package/engine/{logs-store.js → observability/logs-store.js} +5 -5
  189. package/engine/{metrics-store.js → observability/metrics-store.js} +4 -4
  190. package/engine/{check-status.js → operations/check-status.js} +3 -3
  191. package/engine/{cli.js → operations/cli.js} +271 -113
  192. package/engine/{distribution.js → operations/distribution.js} +5 -6
  193. package/engine/{cleanup.js → orchestration/cleanup.js} +72 -45
  194. package/engine/{cooldown.js → orchestration/cooldown.js} +5 -5
  195. package/engine/{dispatch-events.js → orchestration/dispatch-events.js} +2 -2
  196. package/engine/{dispatch.js → orchestration/dispatch.js} +129 -36
  197. package/engine/orchestration/failed-scheduled-cleanup.js +274 -0
  198. package/engine/{lifecycle.js → orchestration/lifecycle.js} +198 -90
  199. package/engine/{meeting.js → orchestration/meeting.js} +6 -16
  200. package/engine/{pipeline.js → orchestration/pipeline.js} +12 -12
  201. package/engine/{pre-dispatch-eval.js → orchestration/pre-dispatch-eval.js} +10 -9
  202. package/engine/{routing.js → orchestration/routing.js} +3 -3
  203. package/engine/{schedule-bootstrap.js → orchestration/schedule-bootstrap.js} +4 -4
  204. package/engine/{scheduler.js → orchestration/scheduler.js} +38 -8
  205. package/engine/{timeout.js → orchestration/timeout.js} +158 -109
  206. package/engine/{db-events.js → persistence/db-events.js} +2 -2
  207. package/engine/{dispatch-store.js → persistence/dispatch-store.js} +7 -7
  208. package/engine/{inbox-store.js → persistence/inbox-store.js} +2 -2
  209. package/engine/{note-link-backfill.js → persistence/note-link-backfill.js} +4 -4
  210. package/engine/{pr-fix-target-store.js → persistence/pr-fix-target-store.js} +8 -8
  211. package/engine/{pull-requests-store.js → persistence/pull-requests-store.js} +21 -7
  212. package/engine/{small-state-store.js → persistence/small-state-store.js} +31 -31
  213. package/engine/persistence/state-operations.js +350 -0
  214. package/engine/{steering-store.js → persistence/steering-store.js} +6 -6
  215. package/engine/{issues.js → planning/issues.js} +2 -2
  216. package/engine/{plan-prd-validation.js → planning/plan-prd-validation.js} +8 -2
  217. package/engine/planning/prd-result-sidecar.js +190 -0
  218. package/engine/{prd-store.js → planning/prd-store.js} +17 -17
  219. package/engine/{project-discovery.js → planning/project-discovery.js} +5 -5
  220. package/engine/{projects.js → planning/projects.js} +10 -10
  221. package/engine/{resolve-area.js → planning/resolve-area.js} +1 -1
  222. package/engine/{work-item-validation.js → planning/work-item-validation.js} +39 -3
  223. package/engine/{work-items-store.js → planning/work-items-store.js} +29 -21
  224. package/engine/{keep-process-sweep.js → processes/keep-process-sweep.js} +57 -17
  225. package/engine/{managed-spawn-launcher.js → processes/managed-spawn-launcher.js} +3 -3
  226. package/engine/{managed-spawn.js → processes/managed-spawn.js} +97 -46
  227. package/engine/{process-utils.js → processes/process-utils.js} +599 -55
  228. package/engine/{abandoned-pr-reconciliation.js → providers/abandoned-pr-reconciliation.js} +17 -7
  229. package/engine/{comment-classifier.js → providers/comment-classifier.js} +85 -17
  230. package/engine/{comment-format.js → providers/comment-format.js} +5 -5
  231. package/engine/{gh-comment.js → providers/gh-comment.js} +15 -15
  232. package/engine/{gh-token.js → providers/gh-token.js} +4 -4
  233. package/engine/{github.js → providers/github.js} +131 -54
  234. package/engine/{pr-action.js → providers/pr-action.js} +13 -12
  235. package/engine/{pr-clone-keep.js → providers/pr-clone-keep.js} +7 -7
  236. package/engine/{pr-devbox.js → providers/pr-devbox.js} +6 -6
  237. package/engine/{pr-fix-target.js → providers/pr-fix-target.js} +13 -13
  238. package/engine/{pr-remote-patch.js → providers/pr-remote-patch.js} +4 -4
  239. package/engine/{pr-resolve.js → providers/pr-resolve.js} +7 -7
  240. package/engine/{pr-temp-clone.js → providers/pr-temp-clone.js} +5 -5
  241. package/engine/{pr-track.js → providers/pr-track.js} +11 -13
  242. package/engine/{shared-branch-pr-reconcile.js → providers/shared-branch-pr-reconcile.js} +4 -4
  243. package/engine/qa/auto-prd-qa.js +313 -0
  244. package/engine/{qa-from-prd.js → qa/from-prd.js} +42 -12
  245. package/engine/qa/prd-session.js +240 -0
  246. package/engine/{qa-process-validation.js → qa/process-validation.js} +14 -9
  247. package/engine/{qa-runbooks.js → qa/runbooks.js} +1 -1
  248. package/engine/{qa-runs.js → qa/runs.js} +286 -15
  249. package/engine/{qa-sessions.js → qa/sessions.js} +595 -49
  250. package/engine/qa/visual-journey.js +654 -0
  251. package/engine/{qa-runners.js → qa-runners/index.js} +7 -7
  252. package/engine/qa-runners/maestro.js +3 -3
  253. package/engine/qa-runners/playwright.js +2 -2
  254. package/engine/{restart-health.js → recovery/restart-health.js} +48 -4
  255. package/engine/recovery/stop-stack.js +607 -0
  256. package/engine/{supervisor.js → recovery/supervisor.js} +105 -175
  257. package/engine/{watchdog.js → recovery/watchdog.js} +136 -13
  258. package/engine/runtimes/claude.js +14 -12
  259. package/engine/runtimes/codex.js +8 -6
  260. package/engine/runtimes/copilot.js +17 -16
  261. package/engine/{watch-actions.js → watches/actions.js} +13 -13
  262. package/engine/{watches.js → watches/index.js} +43 -32
  263. package/engine/{watches-store.js → watches/store.js} +4 -4
  264. package/engine/{create-pr-worktree.js → worktrees/create-pr.js} +1 -1
  265. package/engine/{worktree-gc.js → worktrees/gc.js} +70 -22
  266. package/engine/worktrees/inventory.js +671 -0
  267. package/engine/{live-checkout.js → worktrees/live-checkout.js} +4 -4
  268. package/engine/{worktree-pool.js → worktrees/pool.js} +2 -2
  269. package/engine/{worktree-preflight.js → worktrees/preflight.js} +1 -0
  270. package/engine/worktrees/quarantine-refs.js +173 -0
  271. package/engine.js +1137 -208
  272. package/minions.js +147 -77
  273. package/package.json +10 -6
  274. package/playbooks/_pr-description-audit.md +110 -78
  275. package/playbooks/build-fix-complex.md +2 -0
  276. package/playbooks/fix.md +16 -12
  277. package/playbooks/implement-shared.md +2 -0
  278. package/playbooks/implement.md +19 -20
  279. package/playbooks/plan-to-prd.md +18 -3
  280. package/playbooks/qa-session-draft.md +136 -1
  281. package/playbooks/qa-session-execute.md +80 -2
  282. package/playbooks/qa-session-setup.md +17 -1
  283. package/playbooks/qa-validate.md +1 -1
  284. package/playbooks/setup.md +2 -0
  285. package/playbooks/shared-rules.md +25 -32
  286. package/playbooks/templates/followup-dispatch.md +4 -3
  287. package/playbooks/verify.md +1 -1
  288. package/prompts/cc-system.md +19 -27
  289. package/watch-plugins/README.md +92 -0
  290. package/watch-plugins/ado-author-prs.js +336 -0
  291. package/watch-plugins/gh-author-prs.js +375 -0
  292. package/watch-plugins/http.js +474 -0
  293. package/watch-plugins/teams-channel.js +869 -0
  294. package/docs/dev-composite-workflow.md +0 -101
  295. package/docs/pr-screenshots/pr-886/after-single-header.png +0 -0
  296. package/docs/pr-screenshots/pr-886/before-duplicate-header.png +0 -0
  297. package/docs/pr-screenshots/pr-895/01-cancellation-reason-detail.png +0 -0
  298. package/docs/pr-screenshots/pr-899/worker-pool-worktrees-AFTER.png +0 -0
  299. package/docs/pr-screenshots/pr-899/worker-pool-worktrees-BEFORE.png +0 -0
  300. package/docs/pr-screenshots/pr-901/projects-tab-default.png +0 -0
  301. package/docs/pr-screenshots/pr-901/projects-tab-fmf-selected.png +0 -0
  302. package/docs/pr-screenshots/pr-916/model-picker-AFTER-crop.png +0 -0
  303. package/docs/pr-screenshots/pr-916/model-picker-AFTER.png +0 -0
  304. package/docs/pr-screenshots/pr-916/model-picker-BEFORE-crop.png +0 -0
  305. package/docs/pr-screenshots/pr-916/model-picker-BEFORE.png +0 -0
  306. package/docs/pr-screenshots/pr-916/model-picker-dropdown-AFTER.png +0 -0
  307. package/docs/pr-screenshots/pr-979/auto-fix-pane-AFTER.png +0 -0
  308. package/docs/pr-screenshots/pr-979/auto-fix-pane-BEFORE.png +0 -0
  309. package/docs/pr-screenshots/pr-985/pr-column-em-dash-AFTER.png +0 -0
  310. package/docs/pr-screenshots/pr-985/pr-column-em-dash-BEFORE.png +0 -0
  311. package/docs/visual-evidence-ci.md +0 -103
  312. package/engine/bridge.js +0 -379
  313. package/engine/quarantine-refs.js +0 -103
  314. package/engine/state-operations.js +0 -178
  315. /package/engine/{steering-constraints.js → agents/steering-constraints.js} +0 -0
@@ -129,7 +129,7 @@
129
129
  * and a mock sentinel-existence probe via the private `_exists` option
130
130
  * (signature `(absPath:string) => boolean`, defaulting to fs.existsSync).
131
131
  * Production callers omit both and the helper falls back to
132
- * `require('./shared').shellSafeGit` and `fs.existsSync` respectively.
132
+ * `require('../core/shared').shellSafeGit` and `fs.existsSync` respectively.
133
133
  *
134
134
  * `checkLiveCheckoutDirty` / `checkLiveCheckoutStaleBase` (W-mrcifup2000c218a):
135
135
  * ALLOCATION-TIME pre-dispatch counterparts to the dirty / stale-base checks
@@ -151,7 +151,7 @@
151
151
 
152
152
  const fs = require('fs');
153
153
  const path = require('path');
154
- const shared = require('./shared');
154
+ const shared = require('../core/shared');
155
155
 
156
156
  // W-mqvejug6000eeb20 — generous stdout ceiling for the read-only git probes in
157
157
  // this module (`git status --porcelain`, `rev-parse`, …). Node's execFile
@@ -444,7 +444,7 @@ function _defaultResolveAutoFreshen(localPath) {
444
444
  // isolation / in tests that never trigger the write). Best-effort.
445
445
  function _defaultWriteInboxNote(slug, content) {
446
446
  // eslint-disable-next-line global-require
447
- return require('./dispatch').writeInboxAlert(slug, content);
447
+ return require('../orchestration/dispatch').writeInboxAlert(slug, content);
448
448
  }
449
449
 
450
450
  // Best-effort, side-effect-light resolution of `mainRef` as a restore target
@@ -1574,7 +1574,7 @@ async function checkLiveCheckoutStaleBase(opts = {}) {
1574
1574
  *
1575
1575
  * Dispatch-end counterpart to prepareLiveCheckout. Runs from spawnAgent's
1576
1576
  * onAgentClose (engine.js) on EVERY terminal result AND from the engine-restart
1577
- * orphan/reattach completion path (engine/cli.js), so the operator's working
1577
+ * orphan/reattach completion path (engine/operations/cli.js), so the operator's working
1578
1578
  * tree is switched back to the ref it was on before the live-mode agent ran.
1579
1579
  *
1580
1580
  * Behaviour (locked by human steer steer-bc5861ff95, 2026-06-19):
@@ -21,8 +21,8 @@
21
21
 
22
22
  const fs = require('fs');
23
23
  const path = require('path');
24
- const shared = require('./shared');
25
- const smallStateStore = require('./small-state-store');
24
+ const shared = require('../core/shared');
25
+ const smallStateStore = require('../persistence/small-state-store');
26
26
 
27
27
  const { log, ENGINE_DEFAULTS } = shared;
28
28
 
@@ -1,3 +1,4 @@
1
+ // engine/worktrees/preflight.js — disk-capacity gate before worktree allocation.
1
2
  const fs = require('fs');
2
3
  const path = require('path');
3
4
 
@@ -0,0 +1,173 @@
1
+ const shared = require('../core/shared');
2
+
3
+ // W-ms87lj8j018j2572 — the retention window is OWNED by engine/core/shared.js so the
4
+ // ref-prune window and `ENGINE_DEFAULTS.worktreeProtectedQuarantineRetentionMs`
5
+ // (which sweeps the corresponding quarantine DIRECTORIES) cannot drift apart.
6
+ // Re-exported here for existing consumers; never redefine the literal.
7
+ const { QUARANTINE_REF_RETENTION_DAYS, QUARANTINE_REF_RETENTION_MS } = shared;
8
+ const DELETE_CONCURRENCY = 8;
9
+
10
+ const QUARANTINE_REF_PREFIXES = Object.freeze([
11
+ 'refs/minions/quarantine/',
12
+ 'refs/minions/quarantine-wip/',
13
+ ]);
14
+
15
+ /** True only for refs inside the two Minions-owned quarantine namespaces.
16
+ * Branches, tags, and near-miss namespaces must never be pruned. */
17
+ function isQuarantineRef(ref) {
18
+ return QUARANTINE_REF_PREFIXES.some(prefix => String(ref || '').startsWith(prefix));
19
+ }
20
+
21
+ /** Canonical creation time encoded as the trailing `/<epoch-ms>` ref segment.
22
+ * Returns null for anything that is not a plain positive integer so callers
23
+ * can preserve (never speculatively delete) malformed refs. */
24
+ function quarantineRefTimestampMs(ref) {
25
+ const timestamp = String(ref || '').split('/').pop();
26
+ if (!/^\d+$/.test(timestamp)) return null;
27
+ const parsed = Number(timestamp);
28
+ return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;
29
+ }
30
+
31
+ function quarantineRefCreatedAtMs(ref, fallbackCreatedAt) {
32
+ const fromRef = quarantineRefTimestampMs(ref);
33
+ if (fromRef !== null) return fromRef;
34
+ const fallback = Date.parse(fallbackCreatedAt || '');
35
+ return Number.isFinite(fallback) ? fallback : null;
36
+ }
37
+
38
+ async function _readProjectQuarantineRefs(project) {
39
+ const output = await shared.shellSafeGit([
40
+ 'for-each-ref',
41
+ '--format=%(refname)|%(objectname)|%(creatordate:iso-strict)',
42
+ 'refs/minions/quarantine/',
43
+ 'refs/minions/quarantine-wip/',
44
+ ], { cwd: project.localPath, timeout: 15000 });
45
+ const seenRefs = new Set();
46
+ return String(output || '').split(/\r?\n/).filter(Boolean).map(line => {
47
+ const [ref, sha, fallbackCreatedAt] = line.split('|');
48
+ if (!ref || seenRefs.has(ref)) return null;
49
+ seenRefs.add(ref);
50
+ const createdAtMs = quarantineRefCreatedAtMs(ref, fallbackCreatedAt);
51
+ return { ref, sha, fallbackCreatedAt, createdAtMs };
52
+ }).filter(Boolean);
53
+ }
54
+
55
+ async function listQuarantineRefs(projects) {
56
+ const candidates = (Array.isArray(projects) ? projects : []).filter(project => project?.localPath);
57
+ const results = await Promise.allSettled(candidates.map(async project => {
58
+ const refs = await _readProjectQuarantineRefs(project);
59
+ return refs.map(({ ref, sha, fallbackCreatedAt, createdAtMs }) => {
60
+ return {
61
+ project: project.name || '',
62
+ ref,
63
+ sha,
64
+ createdAt: createdAtMs ? new Date(createdAtMs).toISOString() : (fallbackCreatedAt || ''),
65
+ kind: ref.startsWith('refs/minions/quarantine-wip/') ? 'wip' : 'commits',
66
+ };
67
+ });
68
+ }));
69
+ const items = [];
70
+ for (let i = 0; i < results.length; i++) {
71
+ const result = results[i];
72
+ if (result.status === 'fulfilled') items.push(...result.value);
73
+ else items.push({ project: candidates[i].name || '', error: result.reason?.message || String(result.reason) });
74
+ }
75
+ return items.sort((a, b) => String(b.createdAt || '').localeCompare(String(a.createdAt || '')));
76
+ }
77
+
78
+ async function _mapWithConcurrency(items, limit, worker) {
79
+ // Canonical implementation lives in engine/core/shared.js — kept as a thin
80
+ // alias so there is only one promise-pool in the worktree modules.
81
+ await shared.mapWithConcurrency(items, limit, worker);
82
+ }
83
+
84
+ /** TTL sweep for Minions quarantine recovery refs.
85
+ * Fails safe: only refs in the two Minions-owned namespaces whose ref-name
86
+ * timestamp proves they are at least `retentionMs` old are deleted, each with a
87
+ * SHA-guarded `update-ref -d`. Malformed refs and per-project/per-ref failures
88
+ * are reported, never treated as expiry. Idempotent — a second sweep finds
89
+ * nothing left to remove. W-ms87rbe601a66d13 — a non-positive `retentionMs`
90
+ * means INDEFINITE retention (the `0` opt-out mirrored from the directory
91
+ * sweep) and deletes nothing; it must never read as "everything is expired". */
92
+ async function pruneExpiredQuarantineRefs(projects, {
93
+ now = Date.now(),
94
+ retentionMs = QUARANTINE_REF_RETENTION_MS,
95
+ } = {}) {
96
+ const expiryEnabled = Number.isFinite(Number(retentionMs)) && Number(retentionMs) > 0;
97
+ const candidates = (Array.isArray(projects) ? projects : []).filter(project => project?.localPath);
98
+ const results = await Promise.allSettled(candidates.map(async project => {
99
+ const refs = (await _readProjectQuarantineRefs(project)).filter(item => isQuarantineRef(item.ref));
100
+ const scanned = refs.length;
101
+ const malformedRefs = [];
102
+ const expired = [];
103
+ let retained = 0;
104
+
105
+ for (const item of refs) {
106
+ const createdAtMs = quarantineRefTimestampMs(item.ref);
107
+ if (createdAtMs === null) {
108
+ malformedRefs.push({ project: project.name || '', ref: item.ref });
109
+ continue;
110
+ }
111
+ if (expiryEnabled && now - createdAtMs >= retentionMs) expired.push(item);
112
+ else retained++;
113
+ }
114
+
115
+ let removed = 0;
116
+ const failures = [];
117
+ await _mapWithConcurrency(expired, DELETE_CONCURRENCY, async item => {
118
+ try {
119
+ await shared.shellSafeGit(['update-ref', '-d', item.ref, item.sha], {
120
+ cwd: project.localPath,
121
+ timeout: 15000,
122
+ });
123
+ removed++;
124
+ } catch (e) {
125
+ failures.push({
126
+ project: project.name || '',
127
+ ref: item.ref,
128
+ error: e?.message || String(e),
129
+ });
130
+ }
131
+ });
132
+ return { scanned, removed, retained, malformedRefs, failures };
133
+ }));
134
+
135
+ const summary = {
136
+ scanned: 0,
137
+ removed: 0,
138
+ retained: 0,
139
+ malformed: 0,
140
+ failed: 0,
141
+ malformedRefs: [],
142
+ errors: [],
143
+ };
144
+ for (let i = 0; i < results.length; i++) {
145
+ const result = results[i];
146
+ if (result.status === 'fulfilled') {
147
+ summary.scanned += result.value.scanned;
148
+ summary.removed += result.value.removed;
149
+ summary.retained += result.value.retained;
150
+ summary.malformed += result.value.malformedRefs.length;
151
+ summary.malformedRefs.push(...result.value.malformedRefs);
152
+ summary.failed += result.value.failures.length;
153
+ summary.errors.push(...result.value.failures);
154
+ } else {
155
+ summary.errors.push({
156
+ project: candidates[i]?.name || '',
157
+ error: result.reason?.message || String(result.reason),
158
+ });
159
+ }
160
+ }
161
+ return summary;
162
+ }
163
+
164
+ module.exports = {
165
+ QUARANTINE_REF_RETENTION_DAYS,
166
+ QUARANTINE_REF_RETENTION_MS,
167
+ QUARANTINE_REF_PREFIXES,
168
+ isQuarantineRef,
169
+ quarantineRefTimestampMs,
170
+ quarantineRefCreatedAtMs,
171
+ listQuarantineRefs,
172
+ pruneExpiredQuarantineRefs,
173
+ };