@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
@@ -57,7 +57,7 @@ two stay in lockstep.
57
57
  > token that breaks the "all px" rule and is explicitly allowlisted in
58
58
  > the tripwire.
59
59
 
60
- ### 12px readability floor (W-mr3xgejt0008d3a5, W-mryzdch9000f069c)
60
+ ### 12px readability floor (W-mr3xgejt0008d3a5, W-mryzdch9000f069c, W-ms9bjrvu002gaf64)
61
61
 
62
62
  `--text-sm` was raised from an 11px base to **12px** so it clears the 12px
63
63
  readability floor in both stylesheets: classic renders it at `12 × 1.05 =
@@ -70,21 +70,74 @@ from `--text-xs` to `--text-sm`. **W-mryzdch9000f069c then bumped the
70
70
  remaining ~190 `--text-xs` *usages* across `dashboard/**`** (CSS rules,
71
71
  inline `style="font-size:var(--text-xs)"`, and JS template strings) to
72
72
  `--text-sm`, so almost all dashboard text now renders at or above the floor.
73
- The `--text-xs` token declaration itself is unchanged (still
74
- `calc(10px * var(--minions-text-scale))` in both stylesheets) — this was a
75
- usage migration, not a value change.
73
+ **W-ms9bjrvu002gaf64 swept the six callsites that had drifted back in** (see
74
+ "Why this list drifts" below). The `--text-xs` token declaration itself is
75
+ unchanged (still `calc(10px * var(--minions-text-scale))` in both
76
+ stylesheets) — every pass was a usage migration, not a value change.
76
77
 
77
- `--text-xs` is now retained at only these genuinely-dense chrome callsites,
78
- where 12px would clip or misalign a fixed-size component:
78
+ #### Retention test
79
79
 
80
- - `.token-chart-labels span` token-usage chart axis labels squeezed into
81
- fixed `min-width:8px; max-width:24px` columns with `overflow:hidden`; 12px
82
- would clip the labels.
83
- - `.qa-phase-arrow` the decorative `→` separator glyph between QA phase
84
- chips (a micro-glyph, not readable text).
80
+ A callsite may keep `--text-xs` only when it is **not readable text**:
81
+
82
+ 1. a purely decorative glyph the user never reads — typically drawn from
83
+ CSS `content:` and/or marked `aria-hidden="true"`; or
84
+ 2. text inside a fixed-size box where 12px would clip or misalign it.
85
+
86
+ Anything a user actually reads — labels, help prose, counts, state
87
+ readouts — goes to `--text-sm`, even when it is small chrome.
88
+
89
+ #### Retained callsites
90
+
91
+ Verified against `dashboard/**` at W-ms9bjrvu002gaf64:
92
+
93
+ | Callsite | Why it keeps `--text-xs` |
94
+ | -------- | ------------------------ |
95
+ | `.token-chart-labels span` (`styles.css:196`) | Rule 2 — token-usage chart axis labels squeezed into fixed `min-width:8px; max-width:24px` columns with `overflow:hidden`; 12px clips them. |
96
+ | `.settings-rail-fold .fold-chevron::before` (`styles.css:1333`) | Rule 1 — the `▸` fold-disclosure glyph, drawn from CSS `content: '\25B8'` onto an `aria-hidden="true"` span. |
97
+ | `.qa-phase-arrow` (`styles.css:1835`) | Rule 1 — the decorative `→` separator between QA phase chips (a micro-glyph, not readable text). |
98
+
99
+ That is the complete list. Re-derive it at any time with:
100
+
101
+ ```bash
102
+ git grep -n 'var(--text-xs)' -- dashboard/
103
+ ```
104
+
105
+ Expect exactly four hits: the three rows above plus the `.text-xs` utility
106
+ class declaration. (The `--text-xs:` *token* declarations in
107
+ `dashboard/styles.css` and `dashboard/slim/styles.css` don't match
108
+ `var(--text-xs)`, so they don't show up.) Any other hit is drift — either
109
+ justify it against the retention test and add a row here, or move it to
110
+ `--text-sm`.
85
111
 
86
112
  The `.text-xs` utility class (`.text-xs { font-size: var(--text-xs); }`)
87
- stays declared as the token's escape hatch but currently has no callsites.
113
+ stays declared as the token's escape hatch and still has **no callsites** —
114
+ re-verified repo-wide at W-ms9bjrvu002gaf64 (no `class="text-xs"`,
115
+ `classList`, or `className` reference in any `.css` / `.html` / `.js`).
116
+ `dashboard/slim/` declares `--text-xs` but never uses it.
117
+
118
+ #### Why this list drifts
119
+
120
+ The tripwire (`test/unit/dashboard-font-size-tokens.test.js`) enforces "no
121
+ raw `Npx` font-size" — it does **not** enforce *which* token a selector
122
+ picks. So `--text-xs` silently re-enters `dashboard/**` whenever new UI
123
+ copies a nearby rule, and nothing fails CI. W-ms9bjrvu002gaf64 found six
124
+ such callsites: three merged in parallel with the W-mryzdch9000f069c sweep
125
+ and so were never in its diff (#916, #944, #982), and three landed after it
126
+ (#979, #1027, #1066). All six failed the retention test and moved to
127
+ `--text-sm`:
128
+
129
+ | Callsite | Arrived in | Why it moved |
130
+ | -------- | ---------- | ------------ |
131
+ | `.model-combo-label` | #916 | The model label a user reads in the Command Center / Settings model picker. |
132
+ | `.settings-rail-fold .match-count` | #982 | Its own sibling `.settings-rail-btn .match-count` was already `--text-sm` with otherwise identical declarations. |
133
+ | `.settings-tile-state` | #979 | The visible `ON` / `OFF` readout on the auto-fix gate tiles. |
134
+ | `.settings-section-head .settings-section-num` | #1066 | Step numerals in the "Plan & PR Workflow" badges; the 22px circle has room for 12px. |
135
+ | Per-project "Create PRs as draft" help `<div>` (`js/settings.js`) | #944 | Multi-sentence help prose — and it rendered smaller than its own `--text-sm` label. |
136
+ | Codex "CC sandbox" security help `<div>` (`js/settings.js`) | #1027 | Same pattern: explanatory prose below a `--text-sm` label. |
137
+
138
+ When adding dense chrome, reach for `--text-sm` first. `--text-xs` is a
139
+ last resort that needs a retention-test justification and a row in the
140
+ table above.
88
141
 
89
142
  The `--text-sm` selectors already on the token (`.table th`, `.pr-table th`,
90
143
  `.token-agent-table th`, `.status-badge`, `.sidebar-link`, slim
@@ -271,7 +271,14 @@ function _ccBuildTranscript(tab) {
271
271
  // eslint-disable-next-line no-unsanitized/property -- reason: renderMd()/escHtml() produced persisted message HTML before this transcript text extraction (see dashboard/js/utils.js)
272
272
  tmp.innerHTML = html;
273
273
  var text = (tmp.textContent || tmp.innerText || '').trim();
274
- if (text) out.push({ role: m.role, text: text });
274
+ if (text) {
275
+ // Bound each entry to the server's transcriptTextMaxChars so a
276
+ // previously-persisted oversized message (legacy history from before the
277
+ // client guard, or a cross-surface Slim write) cannot poison future sends
278
+ // as `body.transcript[N].text has an invalid length` (W-mscjjqdh).
279
+ if (window.MinionsCcLimits) text = window.MinionsCcLimits.boundTranscriptText(text);
280
+ out.push({ role: m.role, text: text });
281
+ }
275
282
  }
276
283
  return out.slice(-CC_TRANSCRIPT_MAX_TURNS);
277
284
  }
@@ -321,10 +328,19 @@ async function _ccDashboardHealth() {
321
328
  var controller = new AbortController();
322
329
  var timer = setTimeout(function() { controller.abort(); }, 3000);
323
330
  try {
324
- var res = await fetch('/api/status', { signal: controller.signal, cache: 'no-store' });
331
+ // Probe the lightweight /api/health endpoint NOT /api/status. During a
332
+ // long-running Command Center turn the ~2 KB /api/status snapshot rebuild
333
+ // competes for the event loop and can time out (or abort at our 3s budget)
334
+ // even though the dashboard process is perfectly alive and this very stream
335
+ // is still flowing. Reading a status timeout as "dashboard unreachable" is
336
+ // exactly the false "Dashboard connection lost — restart Minions" bug this
337
+ // guards against. /api/health does no status-cache rebuild and no per-agent
338
+ // file IO, so a fast 200 proves the process is live and able to service
339
+ // requests; it also carries dashboardStartedAt for restart detection.
340
+ var res = await fetch('/api/health', { signal: controller.signal, cache: 'no-store' });
325
341
  if (!(res && res.ok)) return { reachable: false, restarted: false };
326
342
  var data = await res.json().catch(function() { return null; });
327
- var currentDashId = data && data.version ? data.version.dashboardStartedAt : null;
343
+ var currentDashId = data ? data.dashboardStartedAt : null;
328
344
  var knownDashId = window._lastStatus && window._lastStatus.version ? window._lastStatus.version.dashboardStartedAt : null;
329
345
  return {
330
346
  reachable: true,
@@ -1059,11 +1075,36 @@ function ccAddMessage(role, html, skipSave, targetTabId, meta) {
1059
1075
  return messageId;
1060
1076
  }
1061
1077
 
1078
+ // Show an actionable "message too long" validation notice for the given tab
1079
+ // WITHOUT persisting it (skipSave) — the notice is transient UI, not a turn, so
1080
+ // it never enters tab.messages and cannot itself poison the transcript. Renders
1081
+ // a centered system bubble in the active tab and always fires a toast so a
1082
+ // background-tab rejection is still surfaced (W-mscjjqdh).
1083
+ function _ccNotifyMessageTooLong(length, limit, tabId) {
1084
+ var text = window.MinionsCcLimits
1085
+ ? window.MinionsCcLimits.messageTooLongText(length, limit)
1086
+ : 'Message is too long. Shorten it and send again — your text is still in the box.';
1087
+ ccAddMessage('system', '<span style="color:var(--red)">' + escHtml(text) + '</span>', true, tabId || _ccActiveTabId);
1088
+ showToast('cmd-toast', 'Message too long', false);
1089
+ }
1090
+
1062
1091
  async function ccSend(options) {
1063
1092
  var intentMetadata = options && options.intentMetadata ? options.intentMetadata : null;
1064
1093
  var input = document.getElementById('cc-input');
1065
1094
  var message = input.value.trim();
1066
1095
  if (!message) return;
1096
+
1097
+ // Length guard BEFORE clearing the composer / queueing / rendering / persisting
1098
+ // (W-mscjjqdh). An oversized message fails server validation as
1099
+ // `body.message has an invalid length`, and — if persisted first — poisons
1100
+ // every later send through the carried transcript. Reject it here and keep the
1101
+ // rejected text in the composer so the user can trim and resend.
1102
+ var lenCheck = window.MinionsCcLimits ? window.MinionsCcLimits.checkMessage(message) : { ok: true };
1103
+ if (!lenCheck.ok) {
1104
+ _ccNotifyMessageTooLong(lenCheck.length, lenCheck.limit, _ccActiveTabId);
1105
+ return; // composer intentionally NOT cleared — text preserved for editing
1106
+ }
1107
+
1067
1108
  input.value = '';
1068
1109
 
1069
1110
  var tab = _ccActiveTab();
@@ -1155,6 +1196,19 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1155
1196
  var activeTabId = forceTabId || _ccActiveTabId;
1156
1197
  var activeTab = _ccTabs.find(function(t) { return t.id === activeTabId; }) || _ccActiveTab();
1157
1198
  if (!activeTab) return;
1199
+
1200
+ // Defensive length guard for every path that reaches here bypassing the
1201
+ // ccSend() composer check: queue drain, retry (ccRetryLast), programmatic
1202
+ // sends, and a restored-localStorage queue (W-mscjjqdh). Never render, persist
1203
+ // (addMsg → tab.messages), or POST an oversized message — it fails server
1204
+ // validation and poisons the transcript for all later sends. Drop it with an
1205
+ // actionable notice instead of looping on a message that can never succeed.
1206
+ var guard = window.MinionsCcLimits ? window.MinionsCcLimits.checkMessage(message) : { ok: true };
1207
+ if (!guard.ok) {
1208
+ _ccNotifyMessageTooLong(guard.length, guard.limit, activeTabId);
1209
+ return;
1210
+ }
1211
+
1158
1212
  // P-2a6d8e74 — snapshot + clear pending image attachments for this turn.
1159
1213
  // Only fresh user sends carry images (retries/programmatic sends set
1160
1214
  // skipUserMsg and reuse the already-dispatched text). v1 = current turn only.
@@ -1175,9 +1229,14 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1175
1229
 
1176
1230
  if (!skipUserMsg) addMsg('user', escHtml(message) + _ccAttachmentBadge(sendImages.length));
1177
1231
 
1178
- // Remove queue indicator before processing (it'll be re-added if more queued)
1179
- var existingQueueEl = document.getElementById('cc-queue-indicator');
1180
- if (existingQueueEl) existingQueueEl.remove();
1232
+ // NOTE: no queue-indicator teardown here on purpose. This used to remove a
1233
+ // single `#cc-queue-indicator` element, a vestige of an older one-node design;
1234
+ // that id has not existed since indicators became one `.cc-queue-item` node per
1235
+ // queued message, so the call was a silent no-op. _renderQueueIndicator() clears
1236
+ // every `.cc-queue-item` before re-rendering, so it solely owns their lifecycle.
1237
+ // Re-adding a removal here would wipe the indicators the drain loop and retry
1238
+ // path render for STILL-queued messages immediately before calling this
1239
+ // function, hiding them for the whole in-flight request.
1181
1240
 
1182
1241
  var ccStartTime = Date.now();
1183
1242
  var reconnectAttempts = 0;
@@ -1343,7 +1402,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1343
1402
  _ccReplayPending = false;
1344
1403
  }
1345
1404
  if (evt.type === 'chunk') {
1346
- // evt.segmentId (from engine/llm.js) marks distinct assistant text
1405
+ // evt.segmentId (from engine/agents/llm.js) marks distinct assistant text
1347
1406
  // blocks; ccSegmentsApplyChunk falls back to a heuristic when it's
1348
1407
  // absent (Copilot pool path / live replay).
1349
1408
  ccSegmentsApplyChunk(segments, evt.text || '', evt.segmentId);
@@ -10,6 +10,42 @@ function closeDetail() {
10
10
  stopLiveStream();
11
11
  }
12
12
 
13
+ // Shared predicate: Escape must NOT dismiss the panel while the user is typing
14
+ // in an editable field, matching the deliberate exemption in dashboard/js/modal.js
15
+ // (INPUT / TEXTAREA / contentEditable). The panel hosts editable fields — the
16
+ // charter <textarea> (renderCharterEditor, scope 'detail') and the
17
+ // <input id="live-steer-input"> — so without this guard Escape would discard an
18
+ // unsaved charter draft or a typed steering message unrecoverably. Declared as a
19
+ // function declaration so it hoists across the concatenated global dashboard
20
+ // script and is reachable from the slim twin handler in
21
+ // dashboard/slim/panel-bootstrap.js (single source of truth, no forked copy).
22
+ function isEditableEventTarget(ev) {
23
+ var t = ev && ev.target;
24
+ if (t && t.tagName) {
25
+ var tag = String(t.tagName).toUpperCase();
26
+ if (tag === 'INPUT' || tag === 'TEXTAREA' || t.isContentEditable) return true;
27
+ }
28
+ return false;
29
+ }
30
+
31
+ // W-ms24qw0n — Esc closes the bespoke agent detail slide-in panel. The panel is
32
+ // NOT part of the #modal stack, so modal.js's Escape handler never reaches it.
33
+ // Only act when #detail-panel is open, so a closed panel is a no-op and the
34
+ // modal.js handler (and any other Escape listener) still runs. Registered once
35
+ // at module load with a double-registration guard. Mirrors the slim-UX parity
36
+ // handler in dashboard/slim/panel-bootstrap.js.
37
+ if (typeof document !== 'undefined' && typeof document.addEventListener === 'function' && !window.__minionsDetailEscBound) {
38
+ window.__minionsDetailEscBound = true;
39
+ document.addEventListener('keydown', function(ev) {
40
+ if (ev.key !== 'Escape' && ev.keyCode !== 27) return;
41
+ if (isEditableEventTarget(ev)) return;
42
+ var panel = document.getElementById('detail-panel');
43
+ if (panel && panel.classList.contains('open')) {
44
+ closeDetail();
45
+ }
46
+ });
47
+ }
48
+
13
49
  function renderDetailTabs(detail) {
14
50
  const isWorking = detail.statusData?.status === 'working';
15
51
  const tabs = [
@@ -26,6 +26,36 @@ const MEMORY_SPARKLINE_WINDOW_MS = 60 * 60 * 1000; // 1 hour
26
26
  let _memoryPanelLiveInterval = null;
27
27
  let _memoryPanelHistoryInterval = null;
28
28
  let _memoryPanelMounted = false;
29
+ // Embed-mode suspend (W-ms4odb8h009a5d16). When the /engine screen is embedded
30
+ // in the slim cockpit's Engine tile (?embed=1) its iframe is kept mounted but
31
+ // hidden; without an explicit signal these two diagnostics pollers would run
32
+ // forever in the background, contending with the slim cockpit's own polling.
33
+ // The slim visibility bridge (dashboard/js/refresh.js) calls suspend/resume as
34
+ // the iframe is hidden/shown. A normal classic /engine visit is NOT embed mode,
35
+ // so it eager-mounts and never suspends — behavior there is unchanged.
36
+ let _memoryPanelSuspended = false;
37
+
38
+ function _memIsEmbed() {
39
+ try { return document.documentElement.classList.contains('embed'); } catch (e) { return false; }
40
+ }
41
+
42
+ function _memStartIntervals() {
43
+ _memRefreshLive();
44
+ _memRefreshHistory();
45
+ _memoryPanelLiveInterval = setInterval(_memRefreshLive, MEMORY_POLL_LIVE_MS);
46
+ _memoryPanelHistoryInterval = setInterval(_memRefreshHistory, MEMORY_POLL_HISTORY_MS);
47
+ }
48
+
49
+ function _memStopIntervals() {
50
+ if (_memoryPanelLiveInterval) {
51
+ clearInterval(_memoryPanelLiveInterval);
52
+ _memoryPanelLiveInterval = null;
53
+ }
54
+ if (_memoryPanelHistoryInterval) {
55
+ clearInterval(_memoryPanelHistoryInterval);
56
+ _memoryPanelHistoryInterval = null;
57
+ }
58
+ }
29
59
 
30
60
  function _memFmtBytes(n) {
31
61
  if (!Number.isFinite(n)) return '—';
@@ -278,24 +308,39 @@ function mountMemoryPanel() {
278
308
  // against partial DOM states during test harnesses).
279
309
  if (!document.getElementById('memory-panel-content')) return;
280
310
  _memoryPanelMounted = true;
281
- _memRefreshLive();
282
- _memRefreshHistory();
283
- _memoryPanelLiveInterval = setInterval(_memRefreshLive, MEMORY_POLL_LIVE_MS);
284
- _memoryPanelHistoryInterval = setInterval(_memRefreshHistory, MEMORY_POLL_HISTORY_MS);
285
311
  _memWireHeapSnapshotButton();
312
+ // Embed mode (slim Engine tile): defer the heavy pollers until the iframe is
313
+ // first SHOWN. The slim visibility bridge calls resumeMemoryPanel() on
314
+ // visibility:true, so even the cold boot inside the hidden iframe stays light.
315
+ // Classic direct /engine visits eager-mount below (unchanged).
316
+ if (_memIsEmbed()) {
317
+ _memoryPanelSuspended = true;
318
+ return;
319
+ }
320
+ _memStartIntervals();
286
321
  }
287
322
 
288
323
  function unmountMemoryPanel() {
289
324
  if (!_memoryPanelMounted) return;
290
325
  _memoryPanelMounted = false;
291
- if (_memoryPanelLiveInterval) {
292
- clearInterval(_memoryPanelLiveInterval);
293
- _memoryPanelLiveInterval = null;
294
- }
295
- if (_memoryPanelHistoryInterval) {
296
- clearInterval(_memoryPanelHistoryInterval);
297
- _memoryPanelHistoryInterval = null;
298
- }
326
+ _memoryPanelSuspended = false;
327
+ _memStopIntervals();
328
+ }
329
+
330
+ // Suspend/resume the diagnostics pollers without unmounting (embed-mode only).
331
+ // Wired through the SAME slim→embed visibility message the /api/status poll
332
+ // suspend uses (dashboard/js/refresh.js), so there is one visibility protocol,
333
+ // not two. Idempotent and safe to call before mount.
334
+ function suspendMemoryPanel() {
335
+ if (!_memoryPanelMounted || _memoryPanelSuspended) return;
336
+ _memoryPanelSuspended = true;
337
+ _memStopIntervals();
338
+ }
339
+
340
+ function resumeMemoryPanel() {
341
+ if (!_memoryPanelMounted || !_memoryPanelSuspended) return;
342
+ _memoryPanelSuspended = false;
343
+ _memStartIntervals();
299
344
  }
300
345
 
301
346
  // Register the lifecycle hooks against the canonical maps in state.js.
@@ -319,6 +364,8 @@ try {
319
364
  window.MinionsMemoryPanel = {
320
365
  mountMemoryPanel,
321
366
  unmountMemoryPanel,
367
+ suspendMemoryPanel,
368
+ resumeMemoryPanel,
322
369
  _buildSparkline: _memBuildSparkline,
323
370
  _captureHeapSnapshot: _memCaptureHeapSnapshot,
324
371
  };