@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,4 +1,4 @@
1
- // engine/memory-retrieval.js — deterministic task-aware memory selection.
1
+ // engine/memory/memory-retrieval.js — deterministic task-aware memory selection.
2
2
 
3
3
  const memoryStore = require('./memory-store');
4
4
  const reviewLearning = require('./review-learning');
@@ -242,6 +242,40 @@ function _reviewLexTokens(text) {
242
242
  return new Set(tokens.filter(token => !REVIEW_LEX_STOP.has(token)));
243
243
  }
244
244
 
245
+ // Branch-name segments that carry no feature meaning (naming conventions and
246
+ // work-item / PR / dispatch identifiers) so a shared `work/` prefix or WI id
247
+ // never counts as feature affinity.
248
+ const REVIEW_BRANCH_NOISE_RE = /^(?:work|user|users|feature|feat|fix|bugfix|hotfix|chore|release|wip|dev|main|master|draft|pr|topic)$/;
249
+ // Work-item / PR / dispatch identifiers: a 1–2 letter prefix, a MANDATORY
250
+ // hyphen, then a 5+ char alnum id (e.g. `W-abc12345`, `P-a6137579`,
251
+ // `PL-mryta89f002y9ca5`). The hyphen is required so ordinary feature words that
252
+ // merely start with w/p/d (`dashboard`, `pipeline`, `dispatch`) are NOT mistaken
253
+ // for ids, and the prefix spans 1–2 letters so two-letter plan ids (`PL-…`) are
254
+ // caught. `REVIEW_LEADING_WORKITEM_ID_RE` strips such an id from the FRONT of a
255
+ // compound segment (`W-abc123-fix-login`) so the id fragment cannot bypass the
256
+ // whole-segment check and leak as a feature token.
257
+ const REVIEW_WORKITEM_ID_RE = /^[a-z]{1,2}-[0-9a-z]{5,}$/;
258
+ const REVIEW_LEADING_WORKITEM_ID_RE = /^[a-z]{1,2}-[0-9a-z]{5,}(?=[-_.]|$)/;
259
+
260
+ // Feature-affinity tokens: the "same branch / similar feature" signal, derived
261
+ // only from the current dispatch's PR branch and PR title (not the full task
262
+ // text). The branch is split into path segments first so naming-convention
263
+ // prefixes and whole work-item ids are dropped; a leading id is then stripped
264
+ // from any compound segment before the remaining descriptive segments are broken
265
+ // into words. Ranked above generic lexical relevance so a lesson from a prior PR
266
+ // on the same branch/feature outranks one that merely shares an incidental token.
267
+ function _reviewFeatureTokens(context = {}) {
268
+ const words = [];
269
+ for (const seg of String(context.prBranch || '').split(/[/\s]+/)) {
270
+ const s = seg.trim().toLowerCase();
271
+ if (!s || REVIEW_BRANCH_NOISE_RE.test(s) || REVIEW_WORKITEM_ID_RE.test(s)) continue;
272
+ for (const word of s.replace(REVIEW_LEADING_WORKITEM_ID_RE, '').split(/[-_.]+/)) {
273
+ if (word) words.push(word);
274
+ }
275
+ }
276
+ return _reviewLexTokens([context.prTitle, words.join(' ')].filter(Boolean).join(' '));
277
+ }
278
+
245
279
  function _overlapCount(a, b) {
246
280
  if (!a.length || !b.length) return 0;
247
281
  const other = new Set(b);
@@ -264,6 +298,7 @@ function _lessonFacets(record) {
264
298
  // lexically unrelated task touching the same file/symbol still recalls it.
265
299
  function rankApplicableReviewLearnings(records, hints, options = {}) {
266
300
  const hintTokens = options.hintTokens || _reviewLexTokens(options.queryText || '');
301
+ const featureTokens = options.featureTokens instanceof Set ? options.featureTokens : new Set();
267
302
  const scored = (Array.isArray(records) ? records : []).map(record => {
268
303
  const facets = _lessonFacets(record);
269
304
  const symbolOverlap = _overlapCount(hints.symbols, facets.symbols);
@@ -272,6 +307,8 @@ function rankApplicableReviewLearnings(records, hints, options = {}) {
272
307
  const lessonTokens = _reviewLexTokens(
273
308
  `${record.title || ''}\n${record.body || ''}\n${(record.tags || []).join(' ')}`,
274
309
  );
310
+ let featureOverlap = 0;
311
+ for (const token of featureTokens) if (lessonTokens.has(token)) featureOverlap += 1;
275
312
  let lexical = 0;
276
313
  for (const token of hintTokens) if (lessonTokens.has(token)) lexical += 1;
277
314
  const confidence = Math.max(0, Math.min(1, Number(record.confidence) || 0));
@@ -279,21 +316,24 @@ function rankApplicableReviewLearnings(records, hints, options = {}) {
279
316
  if (symbolOverlap) reasons.push('exact-symbol');
280
317
  if (fileOverlap) reasons.push('exact-file');
281
318
  if (tagOverlap) reasons.push('exact-tag');
319
+ if (featureOverlap) reasons.push('feature-branch');
282
320
  if (lexical) reasons.push('lexical');
283
- const applicable = (symbolOverlap + fileOverlap + tagOverlap) > 0 || lexical > 0;
321
+ const applicable = (symbolOverlap + fileOverlap + tagOverlap + featureOverlap) > 0 || lexical > 0;
284
322
  if (!applicable) reasons.push('not-applicable');
285
323
  const score =
286
324
  (symbolOverlap * 1000000) +
287
325
  (fileOverlap * 10000) +
288
326
  (tagOverlap * 100) +
327
+ Math.min(90, featureOverlap * 30) +
289
328
  Math.min(50, lexical) +
290
329
  confidence;
291
- return { record, facets, symbolOverlap, fileOverlap, tagOverlap, lexical, confidence, applicable, score, reasons };
330
+ return { record, facets, symbolOverlap, fileOverlap, tagOverlap, featureOverlap, lexical, confidence, applicable, score, reasons };
292
331
  });
293
332
  return scored.sort((a, b) =>
294
333
  b.symbolOverlap - a.symbolOverlap ||
295
334
  b.fileOverlap - a.fileOverlap ||
296
335
  b.tagOverlap - a.tagOverlap ||
336
+ b.featureOverlap - a.featureOverlap ||
297
337
  b.lexical - a.lexical ||
298
338
  b.confidence - a.confidence ||
299
339
  Number(b.record.updatedAt || 0) - Number(a.record.updatedAt || 0) ||
@@ -371,7 +411,8 @@ function retrieveApplicableReviewLearnings(context = {}, options = {}) {
371
411
  });
372
412
 
373
413
  const hintTokens = _reviewLexTokens(_reviewContextText(context));
374
- const ranked = rankApplicableReviewLearnings(audienceFiltered, hints, { hintTokens });
414
+ const featureTokens = _reviewFeatureTokens(context);
415
+ const ranked = rankApplicableReviewLearnings(audienceFiltered, hints, { hintTokens, featureTokens });
375
416
 
376
417
  const selected = [];
377
418
  const decisionTrace = [];
@@ -441,5 +482,6 @@ module.exports = {
441
482
  deriveReviewFacetHints,
442
483
  rankApplicableReviewLearnings,
443
484
  retrieveApplicableReviewLearnings,
485
+ _reviewFeatureTokens,
444
486
  _truncateUtf8,
445
487
  };
@@ -1,8 +1,8 @@
1
- // engine/memory-store.js — SQL-backed long-term memory records and retrieval.
1
+ // engine/memory/memory-store.js — SQL-backed long-term memory records and retrieval.
2
2
 
3
3
  const crypto = require('crypto');
4
- const { getDb, withTransaction, prepareCached } = require('./db');
5
- const { emitStateEvent } = require('./db-events');
4
+ const { getDb, withTransaction, prepareCached } = require('../db');
5
+ const { emitStateEvent } = require('../persistence/db-events');
6
6
  const reviewLearning = require('./review-learning');
7
7
 
8
8
  const MEMORY_TYPES = new Set(['semantic', 'episodic', 'procedural']);
@@ -1,4 +1,4 @@
1
- // engine/promotion.js — human-approved promotion of verified review lessons into
1
+ // engine/memory/promotion.js — human-approved promotion of verified review lessons into
2
2
  // repository guidance (project skills or allowlisted instruction files) and the
3
3
  // shared project-bound skill work-item queueing logic reused by skill
4
4
  // extraction. Promotion NEVER edits an operator checkout: every path queues a
@@ -7,7 +7,7 @@
7
7
  // merges through native instruction/skill discovery (P-192d3660).
8
8
 
9
9
  const crypto = require('crypto');
10
- const shared = require('./shared');
10
+ const shared = require('../core/shared');
11
11
  const reviewLearning = require('./review-learning');
12
12
 
13
13
  const { WI_STATUS, WORK_TYPE } = shared;
@@ -191,7 +191,7 @@ function buildPromotionWorkItemFields({ lesson, memoryIds, rules, targetKind, pr
191
191
  }
192
192
 
193
193
  // Shared project-bound skill work-item queueing extracted from
194
- // engine/lifecycle.js#extractSkillsFromOutput. Resolves a real (non-central)
194
+ // engine/orchestration/lifecycle.js#extractSkillsFromOutput. Resolves a real (non-central)
195
195
  // project, deduplicates on the "Add skill: <name>" title, and queues an
196
196
  // implementation work item. Returns { created, workItemId, duplicateOf } or null
197
197
  // when the project cannot be resolved.
@@ -1,4 +1,4 @@
1
- // engine/review-learning-backfill.js — strict, offline backfill of durable
1
+ // engine/memory/review-learning-backfill.js — strict, offline backfill of durable
2
2
  // review-learning lessons from legacy artifacts.
3
3
  //
4
4
  // The backfill scans deterministic, bounded slices of legacy sources and imports
@@ -16,7 +16,7 @@
16
16
 
17
17
  const fs = require('fs');
18
18
  const path = require('path');
19
- const shared = require('./shared');
19
+ const shared = require('../core/shared');
20
20
  const reviewLearning = require('./review-learning');
21
21
 
22
22
  const REASON_BUCKETS = Object.freeze([
@@ -82,7 +82,7 @@ function _normalizeContext(context = {}) {
82
82
  return { project, prId, authorAgent, allowedSourceKeys };
83
83
  }
84
84
 
85
- // Mirrors engine/lifecycle.js#_groupReviewLearningEntries: collapse normalized
85
+ // Mirrors engine/orchestration/lifecycle.js#_groupReviewLearningEntries: collapse normalized
86
86
  // completion entries into one lesson group per finding key, flagging conflicting
87
87
  // dispositions/audiences so they are rejected rather than silently merged.
88
88
  function _groupEntries(entries) {
@@ -303,7 +303,7 @@ function scanCompletionArtifacts(dir, { project } = {}) {
303
303
  if (files.length === 0) return [];
304
304
 
305
305
  let dispatch = { pending: [], active: [], completed: [] };
306
- try { dispatch = require('./dispatch-store').readDispatchSectioned() || dispatch; } catch {}
306
+ try { dispatch = require('../persistence/dispatch-store').readDispatchSectioned() || dispatch; } catch {}
307
307
  const entriesById = new Map();
308
308
  for (const list of ['completed', 'active', 'pending']) {
309
309
  for (const entry of (dispatch[list] || [])) {
@@ -312,7 +312,7 @@ function scanCompletionArtifacts(dir, { project } = {}) {
312
312
  }
313
313
 
314
314
  let buildContext = null;
315
- try { buildContext = require('./lifecycle').buildReviewLearningCompletionContext; } catch {}
315
+ try { buildContext = require('../orchestration/lifecycle').buildReviewLearningCompletionContext; } catch {}
316
316
 
317
317
  const records = [];
318
318
  for (const file of files) {
@@ -384,7 +384,7 @@ function scanLegacyFeedbackFiles(dir) {
384
384
  function scanTrackedPrRecords(dir) {
385
385
  let prs = [];
386
386
  try {
387
- const prStore = require('./pull-requests-store');
387
+ const prStore = require('../persistence/pull-requests-store');
388
388
  prs = (prStore.readAllPullRequests ? prStore.readAllPullRequests() : prStore.readPullRequests?.()) || [];
389
389
  } catch { prs = []; }
390
390
  return prs
@@ -1,4 +1,4 @@
1
- // engine/review-learning.js — bounded domain primitives for review-derived memory.
1
+ // engine/memory/review-learning.js — bounded domain primitives for review-derived memory.
2
2
 
3
3
  const crypto = require('crypto');
4
4
  const {
@@ -6,7 +6,7 @@ const {
6
6
  parseCanonicalPrId,
7
7
  redactSecrets,
8
8
  truncateTextBytes,
9
- } = require('./shared');
9
+ } = require('../core/shared');
10
10
 
11
11
  const REVIEW_LEARNING_SOURCE_TYPE = 'review-learning';
12
12
  const REVIEW_LEARNING_DISPOSITIONS = Object.freeze({
@@ -166,9 +166,9 @@ function _boundedIdentifier(value, maxBytes, label, pattern = /^[a-z0-9][a-z0-9.
166
166
  return text;
167
167
  }
168
168
 
169
- function _optionalIdentifier(value, maxBytes, label) {
169
+ function _optionalIdentifier(value, maxBytes, label, pattern) {
170
170
  if (value == null || String(value).trim() === '') return null;
171
- return _boundedIdentifier(value, maxBytes, label);
171
+ return _boundedIdentifier(value, maxBytes, label, pattern);
172
172
  }
173
173
 
174
174
  function _shortHash(value) {
@@ -1167,7 +1167,12 @@ function normalizeLifecycleEvent(input = {}) {
1167
1167
  area: normalizeReviewArea(input.area || 'general'),
1168
1168
  disposition,
1169
1169
  workItemId: _optionalIdentifier(input.workItemId, REVIEW_LEARNING_BOUNDS.refBytes, 'event work item id'),
1170
- dispatchId: _optionalIdentifier(input.dispatchId, REVIEW_LEARNING_BOUNDS.refBytes, 'event dispatch id'),
1170
+ dispatchId: _optionalIdentifier(
1171
+ input.dispatchId,
1172
+ REVIEW_LEARNING_BOUNDS.refBytes,
1173
+ 'event dispatch id',
1174
+ /^(?:[a-z0-9]|_any_)[a-z0-9._:/#|@+-]*$/i,
1175
+ ),
1171
1176
  identity: _optionalIdentifier(input.identity, REVIEW_LEARNING_BOUNDS.refBytes, 'event identity'),
1172
1177
  metadata: normalizeReviewMetadata(input.metadata || {}),
1173
1178
  createdAt: Number.isFinite(Number(input.createdAt)) ? Number(input.createdAt) : Date.now(),
@@ -1,5 +1,5 @@
1
1
  /**
2
- * engine/diagnostics-memory.js — In-process memory + event-loop + GC sampler.
2
+ * engine/observability/diagnostics-memory.js — Memory/event-loop/GC sampler.
3
3
  *
4
4
  * P-a1b2c3d4 (memory + perf audit plan). Importable from both engine.js and
5
5
  * dashboard.js — each Node process gets its own module-scope state (event-loop
@@ -1,4 +1,4 @@
1
- // engine/logs-store.js — SQL-backed engine logs.
1
+ // engine/observability/logs-store.js — SQL-backed engine logs.
2
2
  //
3
3
  // Logs differ from work_items / pull_requests / dispatches: they are
4
4
  // pure append-only with a tail-cap, so the store exposes a different
@@ -48,7 +48,7 @@ function _openWriter(dbFilePath) {
48
48
  db.exec('PRAGMA foreign_keys = ON');
49
49
  db.exec('PRAGMA synchronous = NORMAL');
50
50
  db.exec('PRAGMA busy_timeout = 5000');
51
- const { runMigrations } = require('./db/migrate');
51
+ const { runMigrations } = require('../db/migrate');
52
52
  runMigrations(db);
53
53
  conn = {
54
54
  db,
@@ -96,7 +96,7 @@ function appendLogsToDbFile(dbFilePath, entries) {
96
96
  return 0;
97
97
  }
98
98
 
99
- const shared = require('./shared');
99
+ const shared = require('../core/shared');
100
100
  const cap = (shared.ENGINE_DEFAULTS && shared.ENGINE_DEFAULTS.logCapEntries) || 2500;
101
101
  const trimTo = (shared.ENGINE_DEFAULTS && shared.ENGINE_DEFAULTS.logCapTrimTo) || 2000;
102
102
 
@@ -132,7 +132,7 @@ function appendLogsToDbFile(dbFilePath, entries) {
132
132
  // once per batch instead of per entry. Routed against the singleton
133
133
  // (not per-dbPath) because events are a cross-cutting concern keyed
134
134
  // off the engine's active state.db.
135
- try { require('./db-events').emitStateEvent('logs', { batch: inserted }); } catch { /* optional */ }
135
+ try { require('../persistence/db-events').emitStateEvent('logs', { batch: inserted }); } catch { /* optional */ }
136
136
  return inserted;
137
137
  }
138
138
 
@@ -145,7 +145,7 @@ function appendLogsToDbFile(dbFilePath, entries) {
145
145
  function readRecentLogs(n, opts) {
146
146
  const limit = Math.max(1, Math.min(10000, Number(n) || 50));
147
147
  const level = opts && opts.level ? String(opts.level) : null;
148
- const { getDb } = require('./db');
148
+ const { getDb } = require('../db');
149
149
  let db;
150
150
  try { db = getDb(); }
151
151
  catch { return []; }
@@ -1,4 +1,4 @@
1
- // engine/metrics-store.js — SQL-backed engine metrics.
1
+ // engine/observability/metrics-store.js — SQL-backed engine metrics.
2
2
  //
3
3
  // Metrics expose a flat object whose top-level keys mix
4
4
  // per-agent counters with reserved keys (`_engine`, `_daily`,
@@ -84,7 +84,7 @@ function _readAllRows(db) {
84
84
 
85
85
  // Read the full legacy-shape metrics object from SQL.
86
86
  function readMetrics() {
87
- const { getDb } = require('./db');
87
+ const { getDb } = require('../db');
88
88
  const db = getDb();
89
89
 
90
90
  migrateWatchCcTriageKeysOnce();
@@ -138,7 +138,7 @@ function _applyMetricsDiff(db, diff) {
138
138
  }
139
139
 
140
140
  function applyMetricsMutation(mutator) {
141
- const { getDb, withTransaction } = require('./db');
141
+ const { getDb, withTransaction } = require('../db');
142
142
  let db;
143
143
  try { db = getDb(); }
144
144
  catch (e) {
@@ -160,7 +160,7 @@ function applyMetricsMutation(mutator) {
160
160
  }
161
161
 
162
162
  function _resetMetricsTableForTest() {
163
- const { getDb } = require('./db');
163
+ const { getDb } = require('../db');
164
164
  try { getDb().exec('DELETE FROM metrics'); } catch { /* not initialized */ }
165
165
  }
166
166
 
@@ -1,16 +1,16 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const { safeJson, MINIONS_DIR, DONE_STATUSES } = require('./shared');
3
+ const { safeJson, MINIONS_DIR, DONE_STATUSES } = require('../core/shared');
4
4
 
5
5
  console.log('=== Work Items (non-done) ===');
6
6
  let items = [];
7
- try { items = require('./queries').getWorkItems() || []; } catch {}
7
+ try { items = require('../core/queries').getWorkItems() || []; } catch {}
8
8
  items.filter(i => !DONE_STATUSES.has(i.status)).forEach(i => {
9
9
  console.log(i.id, (i.status || '').padEnd(12), (i.type || '').padEnd(12), (i.title || '').slice(0, 60));
10
10
  });
11
11
 
12
12
  console.log('\n=== Agent Status (derived from dispatch) ===');
13
- const { getAgentStatus } = require('./queries');
13
+ const { getAgentStatus } = require('../core/queries');
14
14
  const config = safeJson(path.join(MINIONS_DIR, 'config.json')) || {};
15
15
  const agents = Object.keys(config.agents || {});
16
16
  if (agents.length === 0) {