@yemi33/minions 0.1.2448 → 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 +58 -4
  7. package/dashboard/js/detail-panel.js +36 -0
  8. package/dashboard/js/memory-panel.js +59 -12
  9. package/dashboard/js/qa.js +179 -20
  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 +13 -2
  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
@@ -1,6 +1,6 @@
1
- // engine/distribution.js — identity of the *installed* Minions distribution.
1
+ // engine/operations/distribution.js — identity of the *installed* Minions distribution.
2
2
  //
3
- // Minions ships from one source tree as two npm packages (tools/prepare-package.js):
3
+ // Minions ships from one source tree as two npm packages (scripts/prepare-package.js):
4
4
  // • public → `@yemi33/minions` (npmjs, yemi33/minions)
5
5
  // • internal → `@yemishin_microsoft/minions` (GitHub Packages; overridable
6
6
  // at publish time via INTERNAL_PACKAGE_NAME)
@@ -34,9 +34,8 @@ const INTERNAL_WELCOME_MESSAGE = 'Welcome to the internal Minions!';
34
34
  const INSTALLATION_ID_KEY = 'installationId';
35
35
  const INTERNAL_WELCOME_ACK_KEY = 'internalWelcome';
36
36
 
37
- // The installed package root: engine/ lives one level under it in both the npm
38
- // tarball and the git checkout.
39
- const PACKAGE_ROOT = path.join(__dirname, '..');
37
+ // The installed package root is two levels above this domain module.
38
+ const PACKAGE_ROOT = path.join(__dirname, '..', '..');
40
39
 
41
40
  function _packageJsonPath(opts) {
42
41
  if (opts && opts.packageJsonPath) return opts.packageJsonPath;
@@ -88,7 +87,7 @@ function resolveDistribution(opts) {
88
87
  }
89
88
 
90
89
  function _smallState() {
91
- return require('./small-state-store');
90
+ return require('../persistence/small-state-store');
92
91
  }
93
92
 
94
93
  function _newInstallationId() {
@@ -1,13 +1,13 @@
1
1
  /**
2
- * engine/cleanup.js — Periodic cleanup: temp files, worktrees, zombies, migrations.
2
+ * engine/orchestration/cleanup.js — Periodic cleanup: temp files, worktrees, zombies, migrations.
3
3
  * Extracted from engine.js for modularity. No logic changes.
4
4
  */
5
5
 
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
- const shared = require('./shared');
9
- const queries = require('./queries');
10
- const smallStateStore = require('./small-state-store');
8
+ const shared = require('../core/shared');
9
+ const queries = require('../core/queries');
10
+ const smallStateStore = require('../persistence/small-state-store');
11
11
 
12
12
  const { exec, execAsync, execSilent, log, ts, ENGINE_DEFAULTS } = shared;
13
13
  const { safeJson, safeJsonArr, safeJsonNoRestore, safeWrite, safeReadDir, readWorkItems, readPullRequests, mutateCooldowns, mutateMetrics, mutateWorkItems, getProjects,
@@ -22,7 +22,7 @@ const PLANS_DIR = queries.PLANS_DIR;
22
22
  // Lazy require to break circular dependency with engine.js
23
23
  // Only needed for engine().activeProcesses — log/ts come from shared.js
24
24
  let _engine = null;
25
- function engine() { if (!_engine) _engine = require('../engine'); return _engine; }
25
+ function engine() { if (!_engine) _engine = require('../../engine'); return _engine; }
26
26
 
27
27
  // Lazy require for dispatch module
28
28
  let _dispatch = null;
@@ -32,7 +32,7 @@ function dispatchModule() { if (!_dispatch) _dispatch = require('./dispatch'); r
32
32
  // protected; idle-entry TTL cleanup remains owned by worktree-pool.pruneStale.
33
33
  let _worktreePool = null;
34
34
  function worktreePool() {
35
- if (!_worktreePool) _worktreePool = require('./worktree-pool');
35
+ if (!_worktreePool) _worktreePool = require('../worktrees/pool');
36
36
  return _worktreePool;
37
37
  }
38
38
 
@@ -179,7 +179,7 @@ function cleanupMergedPrLocalBranch(root, project, pr) {
179
179
  * Sweep leaked test-fixture meetings from a `meetings/` directory.
180
180
  *
181
181
  * Meeting unit/integration tests don't all honor MINIONS_TEST_DIR
182
- * (engine/meeting.js is in ISOLATED_MODULES, but tests that load it after the
182
+ * (engine/orchestration/meeting.js is in ISOLATED_MODULES, but tests that load it after the
183
183
  * env var is unset, or that fail before cleanup, leave `.json` + `.json.backup`
184
184
  * sidecars behind). The engine's tick loop then re-discovers these fixtures
185
185
  * every tick, fails playbook validation ("missing required template variables:
@@ -422,7 +422,7 @@ function pruneOrphanManagedLogs(opts = {}) {
422
422
  const now = Number.isFinite(Number(opts.now)) ? Number(opts.now) : Date.now();
423
423
  const specs = Array.isArray(opts.specs)
424
424
  ? opts.specs
425
- : require('./managed-spawn').listManagedSpecs();
425
+ : require('../processes/managed-spawn').listManagedSpecs();
426
426
  const normalize = value => {
427
427
  const resolved = path.resolve(String(value || ''));
428
428
  return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
@@ -640,7 +640,7 @@ async function runCleanup(config, verbose = false) {
640
640
  cleaned.orphanWorktreeDirs = 0;
641
641
  cleaned.worktreeReconcileFailed = 0;
642
642
  try {
643
- const reconcile = require('./worktree-gc').reconcileStaleWorktreeDirectories({
643
+ const reconcile = require('../worktrees/gc').reconcileStaleWorktreeDirectories({
644
644
  projects,
645
645
  dispatchSnap: getDispatch(),
646
646
  worktreeRootRel: config.engine?.worktreeRoot || ENGINE_DEFAULTS.worktreeRoot,
@@ -660,7 +660,7 @@ async function runCleanup(config, verbose = false) {
660
660
  const _reapedScratchRoots = new Set(); // reap each worktree root's .agent-temp once per cleanup
661
661
  let activeSharedBranchPlans = [];
662
662
  try {
663
- activeSharedBranchPlans = require('./prd-store').listPrdRows()
663
+ activeSharedBranchPlans = require('../planning/prd-store').listPrdRows()
664
664
  .map(row => row.plan)
665
665
  .filter(plan => plan?.branch_strategy === 'shared-branch' && plan.feature_branch && plan.status !== 'completed');
666
666
  } catch { /* optional */ }
@@ -773,7 +773,7 @@ async function runCleanup(config, verbose = false) {
773
773
  // Sequential probing was the dominant cost in the cleanup phase
774
774
  // (5–15s tick stall every 10 ticks at 50+ worktrees), but unbounded
775
775
  // Promise.all would spawn 50+ concurrent git children — bad on Windows
776
- // where each fork pays AV-scan overhead. Mirrors engine/ado.js:611.
776
+ // where each fork pays AV-scan overhead. Mirrors engine/ado/index.js:611.
777
777
  const BRANCH_PROBE_CONCURRENCY = 5;
778
778
  const branchMap = new Map();
779
779
  for (let i = 0; i < allDirs.length; i += BRANCH_PROBE_CONCURRENCY) {
@@ -789,7 +789,7 @@ async function runCleanup(config, verbose = false) {
789
789
  const _anchoredProcessCwds = [];
790
790
  let _anchorProbeFailed = false;
791
791
  try {
792
- const _ms = require('./managed-spawn');
792
+ const _ms = require('../processes/managed-spawn');
793
793
  for (const rec of _ms.listManagedSpecs()) {
794
794
  if (rec && typeof rec.cwd === 'string' && rec.cwd.length > 0) {
795
795
  try { _anchoredProcessCwds.push(shared.realPathForComparison(rec.cwd)); }
@@ -801,7 +801,7 @@ async function runCleanup(config, verbose = false) {
801
801
  log('warn', `managed-spawn cwd anchor lookup failed: ${e.message}`);
802
802
  }
803
803
  try {
804
- const _kp = require('./keep-process-sweep');
804
+ const _kp = require('../processes/keep-process-sweep');
805
805
  _anchoredProcessCwds.push(..._kp.getActiveKeepProcessCwds());
806
806
  } catch (e) {
807
807
  _anchorProbeFailed = true;
@@ -1022,6 +1022,10 @@ async function runCleanup(config, verbose = false) {
1022
1022
  }
1023
1023
  } catch (e) { log('warn', 'worktree-pool prune: ' + e.message); }
1024
1024
 
1025
+ let processSnapshot = [];
1026
+ try { processSnapshot = shared.listAllProcesses(); }
1027
+ catch (e) { log('warn', 'cleanup process snapshot: ' + e.message); }
1028
+
1025
1029
  // 4. Kill zombie agent processes not tracked by the engine
1026
1030
  // List all node processes, check if any are running spawn-agent.js for our minions
1027
1031
  try {
@@ -1043,11 +1047,12 @@ async function runCleanup(config, verbose = false) {
1043
1047
  let pid;
1044
1048
  try { pid = Number(fs.readFileSync(pidFilePath, 'utf8').trim()); } catch { return; }
1045
1049
  if (activePids.has(pid)) return;
1046
- if (Number.isInteger(pid) && pid > 0 && shared.isProcessCommandLineMatchingAgent(pid)) {
1047
- try {
1048
- shared.killImmediate({ pid });
1049
- cleaned.zombies++;
1050
- } catch { /* process may already be gone */ }
1050
+ if (shared.terminateProcess('engine.cleanup.stale-agent-pid', { pid }, {
1051
+ recordedAtMs: stat.mtimeMs,
1052
+ processes: processSnapshot,
1053
+ skewMs: 2000,
1054
+ })) {
1055
+ cleaned.zombies++;
1051
1056
  }
1052
1057
  if (layout === 'dispatch-dir') {
1053
1058
  try { shared.removeDispatchTmpDir(path.dirname(pidFilePath)); } catch {}
@@ -1056,24 +1061,22 @@ async function runCleanup(config, verbose = false) {
1056
1061
  }
1057
1062
  cleaned.stalePidFiles++;
1058
1063
  });
1059
- for (const [id, info] of activeProcesses.entries()) {
1060
- if (!activeIds.has(id)) {
1061
- shared.killImmediate(info.proc);
1062
- activeProcesses.delete(id);
1063
- cleaned.zombies++;
1064
- }
1065
- }
1064
+ cleaned.zombies += require('./timeout').cancelTrackedProcessesWithoutDispatch(
1065
+ activeProcesses,
1066
+ dispatch.active,
1067
+ { processes: processSnapshot },
1068
+ );
1066
1069
  } catch (e) { log('warn', 'cleanup zombie processes: ' + e.message); }
1067
1070
 
1068
- // 4b. Sweep stray MCP descendants. Spawn-agent.js reaps its descendants on
1071
+ // 4b. Detect stray MCP descendants. Spawn-agent.js reaps its descendants on
1069
1072
  // close, but a hard kill (engine restart, OS crash) can skip that path and
1070
1073
  // leave orphan node.exe processes running MCP servers (Azure, Playwright,
1071
- // Loop, etc.) reparented away from the Minions tree. This sweep walks
1072
- // descendants from every anchor we know (engine, dashboard, active spawn-
1073
- // agents) and kills any node MCP processes outside that set.
1074
+ // Loop, etc.) reparented away from the Minions tree. We cannot prove that an
1075
+ // unanchored global process belongs to this runtime, so report it without
1076
+ // killing it; leaking is safer than terminating another checkout's process.
1074
1077
  cleaned.strayMcps = 0;
1075
1078
  try {
1076
- const allProcs = shared.listAllProcesses();
1079
+ const allProcs = processSnapshot;
1077
1080
  if (allProcs.length) {
1078
1081
  const anchorPids = [process.pid];
1079
1082
  for (const info of activeProcesses.values()) {
@@ -1093,8 +1096,8 @@ async function runCleanup(config, verbose = false) {
1093
1096
  // any agents/<id>/keep-pids.json file are anchors, so the reachability
1094
1097
  // walk treats them (and their MCP grandchildren) as legitimate.
1095
1098
  try {
1096
- const keepProcessSweep = require('./keep-process-sweep');
1097
- for (const pid of keepProcessSweep.getActiveAnchorPids()) anchorPids.push(pid);
1099
+ const keepProcessSweep = require('../processes/keep-process-sweep');
1100
+ for (const pid of keepProcessSweep.getActiveAnchorPids({ processes: allProcs })) anchorPids.push(pid);
1098
1101
  } catch (e) { log('warn', `cleanup: keep-process anchor lookup failed: ${e.message}`); }
1099
1102
  const reach = shared.listProcessReachable(anchorPids, allProcs);
1100
1103
  // MCP server commandlines. Matches scoped (@modelcontextprotocol/*,
@@ -1112,8 +1115,7 @@ async function runCleanup(config, verbose = false) {
1112
1115
  strayPids.push(p.pid);
1113
1116
  }
1114
1117
  if (strayPids.length) {
1115
- cleaned.strayMcps = shared.killByPidsImmediate(strayPids);
1116
- log('info', `Cleanup: ${cleaned.strayMcps}/${strayPids.length} stray MCP descendants reaped`);
1118
+ log('warn', `Cleanup: detected ${strayPids.length} unanchored MCP process(es); leaving them running because ownership is unproven`);
1117
1119
  }
1118
1120
  }
1119
1121
  } catch (e) { log('warn', 'cleanup stray MCPs: ' + e.message); }
@@ -1342,7 +1344,7 @@ async function runCleanup(config, verbose = false) {
1342
1344
  // changes clobbered by this pass's stale in-memory copy (lost-update race —
1343
1345
  // writePrd's _upsertPrd does a full-column data=? replace, not a merge).
1344
1346
  try {
1345
- const prdStore = require('./prd-store');
1347
+ const prdStore = require('../planning/prd-store');
1346
1348
  const prdFiles = prdStore.listPrdRows().filter(row => !row.archived).map(row => row.filename);
1347
1349
  for (const pf of prdFiles) {
1348
1350
  // Cheap out-of-transaction peek to skip PRDs that clearly need no work;
@@ -1381,7 +1383,7 @@ async function runCleanup(config, verbose = false) {
1381
1383
  queries.getWorkItems(config, { enrich: false }).map(wi => wi?.id).filter(Boolean)
1382
1384
  );
1383
1385
 
1384
- const prdStore = require('./prd-store');
1386
+ const prdStore = require('../planning/prd-store');
1385
1387
  const orphanPrdEntries = prdStore.listPrdRows().filter(row => !row.archived).map(row => row.filename);
1386
1388
  for (const pf of orphanPrdEntries) {
1387
1389
  const peek = prdStore.readPrd(pf);
@@ -1598,7 +1600,7 @@ async function runCleanup(config, verbose = false) {
1598
1600
  cleaned.expiredReviewCandidates = 0;
1599
1601
  cleaned.prunedLifecycleEvents = 0;
1600
1602
  try {
1601
- const memoryStore = require('./memory-store');
1603
+ const memoryStore = require('../memory/memory-store');
1602
1604
  cleaned.expiredReviewCandidates = memoryStore.expireStaleReviewLearningCandidates();
1603
1605
  cleaned.prunedLifecycleEvents = memoryStore.pruneMemoryLifecycleEvents();
1604
1606
  if (cleaned.expiredReviewCandidates > 0 || cleaned.prunedLifecycleEvents > 0) {
@@ -1608,20 +1610,45 @@ async function runCleanup(config, verbose = false) {
1608
1610
 
1609
1611
  // 20. Recovery refs outlive the 24-hour quarantine-directory window so an
1610
1612
  // operator can still recover preserved commits/WIP after directory cleanup.
1611
- // Bound that independent recovery window at 10 days.
1613
+ // W-ms87rbe601a66d13 bound that window at the SAME retention the protected
1614
+ // quarantine-DIRECTORY sweep uses (`engine.worktreeProtectedQuarantineRetentionMs`,
1615
+ // default `shared.QUARANTINE_REF_RETENTION_MS`) rather than the built-in
1616
+ // constant, so lowering the setting moves both sides together and `0` keeps
1617
+ // refs indefinitely exactly like the directories.
1612
1618
  cleaned.quarantineRefs = 0;
1613
1619
  try {
1614
- const { pruneExpiredQuarantineRefs } = require('./quarantine-refs');
1615
- const result = await pruneExpiredQuarantineRefs(projects);
1620
+ const { pruneExpiredQuarantineRefs } = require('../worktrees/quarantine-refs');
1621
+ const retentionMs = shared.resolveQuarantineRetentionMs(config);
1622
+ const retentionDays = retentionMs / (24 * 60 * 60 * 1000);
1623
+ const result = await pruneExpiredQuarantineRefs(projects, { retentionMs });
1616
1624
  cleaned.quarantineRefs = result.removed;
1617
- if (result.removed > 0) {
1618
- log('info', `cleanup: pruned ${result.removed} quarantine recovery ref(s) older than 10 days`);
1625
+ cleaned.quarantineRefsMalformed = result.malformed;
1626
+ cleaned.quarantineRefFailures = result.failed;
1627
+ if (result.removed > 0 || result.failed > 0) {
1628
+ log('info', `cleanup: pruned ${result.removed}/${result.scanned} quarantine recovery ref(s) older than ${retentionDays} days (retained ${result.retained}, failed ${result.failed})`);
1629
+ }
1630
+ if (result.malformed > 0) {
1631
+ const sample = result.malformedRefs.slice(0, 5).map(entry => entry.ref).join(', ');
1632
+ log('warn', `quarantine-ref retention: preserved ${result.malformed} ref(s) with an unparseable timestamp: ${sample}`);
1619
1633
  }
1620
1634
  for (const failure of result.errors) {
1621
- log('warn', `quarantine-ref retention (${failure.project || 'unknown project'}): ${failure.error}`);
1635
+ log('warn', `quarantine-ref retention (${failure.project || 'unknown project'}${failure.ref ? ` ${failure.ref}` : ''}): ${failure.error}`);
1622
1636
  }
1623
1637
  } catch (e) { log('warn', `quarantine-ref retention: ${e.message}`); }
1624
1638
 
1639
+ // 21. Superseded failed-scheduled work-item retention (W-msckn1lp002xdf6b).
1640
+ // Machine-generated scheduled-run failures (hourly review/fetch sweeps, etc.)
1641
+ // otherwise accumulate indefinitely. This daily sweep keeps the newest failure
1642
+ // per schedule for diagnosis and prunes older superseded failures past the 24h
1643
+ // window; human-authored / non-scheduled failures are never touched. Its own
1644
+ // cadence gate makes it a near no-op on most cleanup ticks.
1645
+ cleaned.failedScheduledPruned = 0;
1646
+ try {
1647
+ const { pruneSupersededFailedScheduledItems } = require('./failed-scheduled-cleanup');
1648
+ const result = pruneSupersededFailedScheduledItems(config);
1649
+ cleaned.failedScheduledPruned = (result && result.pruned) || 0;
1650
+ } catch (e) { log('warn', `failed-scheduled retention: ${e.message}`); }
1651
+
1625
1652
  return cleaned;
1626
1653
  }
1627
1654
 
@@ -1644,7 +1671,7 @@ function scrubStaleMetrics() {
1644
1671
 
1645
1672
  /**
1646
1673
  * Periodic per-tick worktree sweep. Aggregates the two pruners in
1647
- * `engine/worktree-gc.js` so a long-lived engine catches orphans the
1674
+ * `engine/worktrees/gc.js` so a long-lived engine catches orphans the
1648
1675
  * boot-only reconcile would miss:
1649
1676
  *
1650
1677
  * - `pruneOrphanWorktrees`: walks `<localPath>/<worktreeRoot>` and reaps
@@ -1664,7 +1691,7 @@ function scrubStaleMetrics() {
1664
1691
  * resolves with the same object after its final counters are refreshed.
1665
1692
  */
1666
1693
  function runPeriodicWorktreeSweep(config) {
1667
- const worktreeGc = require('./worktree-gc');
1694
+ const worktreeGc = require('../worktrees/gc');
1668
1695
  const allProjects = getProjects(config);
1669
1696
  // PL-live-checkout-reliability-hardening — EXCLUDE live-checkout projects from
1670
1697
  // registry-derived destructive pruners. Filesystem reconciliation below still
@@ -1,11 +1,11 @@
1
1
  /**
2
- * engine/cooldown.js — Dispatch cooldowns, deduplication, and context coalescing.
2
+ * engine/orchestration/cooldown.js — Dispatch cooldowns, deduplication, and context coalescing.
3
3
  * Extracted from engine.js.
4
4
  */
5
5
 
6
- const shared = require('./shared');
7
- const queries = require('./queries');
8
- const smallStateStore = require('./small-state-store');
6
+ const shared = require('../core/shared');
7
+ const queries = require('../core/queries');
8
+ const smallStateStore = require('../persistence/small-state-store');
9
9
 
10
10
  const { mutateCooldowns, log, ENGINE_DEFAULTS } = shared;
11
11
 
@@ -274,7 +274,7 @@ function isAlreadyDispatched(key) {
274
274
  */
275
275
  function isBranchActive(branch) {
276
276
  if (!branch) return null;
277
- const { sanitizeBranch } = require('./shared');
277
+ const { sanitizeBranch } = require('../core/shared');
278
278
  const normalized = sanitizeBranch(branch);
279
279
  const dispatch = queries.getDispatch();
280
280
  return (dispatch.active || []).find(d => {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * engine/dispatch-events.js — Single source of truth for dispatch terminal events.
2
+ * engine/orchestration/dispatch-events.js — Single source of truth for dispatch terminal events.
3
3
  *
4
4
  * W-mpob4nyk0006580e: The live view banner ("✓ Task complete" / "✗ Task ended
5
5
  * with …") must mirror `dispatch.result` exactly. Previously the banner was
@@ -29,7 +29,7 @@
29
29
  const fs = require('fs');
30
30
  const path = require('path');
31
31
  const { EventEmitter } = require('events');
32
- const shared = require('./shared');
32
+ const shared = require('../core/shared');
33
33
 
34
34
  const MAX_RING_ENTRIES = 50; // bound file size + memory; dev tool
35
35
  const REPLAY_TTL_MS = 5 * 60 * 1000; // 5 min — long enough for tab refresh