claude-code-session-manager 0.98.0 → 0.100.0

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 (431) hide show
  1. package/README.md +3 -3
  2. package/bin/cli.cjs +16 -4
  3. package/bin/node-floor.cjs +41 -0
  4. package/dist/assets/{DataModel-DCEgMTjH.js → DataModel-HdR0AxFq.js} +1 -1
  5. package/dist/assets/{History-Bfdoywlh.js → History-Dr4Jr_5z.js} +2 -2
  6. package/dist/assets/{Hooks-CKDJjTJV.js → Hooks-NhrvH3JP.js} +3 -3
  7. package/dist/assets/{Library-7akfgy67.js → Library-Dv_EtIMr.js} +1 -1
  8. package/dist/assets/{MarkdownEditor-DDesiqet.js → MarkdownEditor-DTKDWV_n.js} +1 -1
  9. package/dist/assets/{McpServers-D4lZtXof.js → McpServers-M034G9B3.js} +2 -2
  10. package/dist/assets/{Memory-CeI8G1w5.js → Memory-DzF1B4gx.js} +6 -6
  11. package/dist/assets/{Permissions-BGleLja4.js → Permissions-DrgbSGWl.js} +3 -3
  12. package/dist/assets/{Plugins-P4eCXy_S.js → Plugins-Bd3ef35w.js} +2 -2
  13. package/dist/assets/{ProvenanceBadge-BFczzI1B.js → ProvenanceBadge-DcBHT1Iy.js} +1 -1
  14. package/dist/assets/{SaveBar-l9jnEMES.js → SaveBar-rimJem-Y.js} +1 -1
  15. package/dist/assets/Scheduler-DjgFJl2w.js +16 -0
  16. package/dist/assets/{ScopeSwitcher-CjJi8ST5.js → ScopeSwitcher-CnAzTBrl.js} +1 -1
  17. package/dist/assets/Settings-Dc1F_sSg.js +3 -0
  18. package/dist/assets/{SkillReferenceGraph-CjbO01Sg.js → SkillReferenceGraph-B9aZDecM.js} +1 -1
  19. package/dist/assets/{Skills-BxZ9_fCR.js → Skills-DRXd18gu.js} +2 -2
  20. package/dist/assets/{SystemPrompt-D8vfFb8b.js → SystemPrompt-ahy5-Fwe.js} +1 -1
  21. package/dist/assets/{TagLibrary-2vzUo7YL.js → TagLibrary-C_tToDeL.js} +1 -1
  22. package/dist/assets/{TiptapBody-B8ZfbK90.js → TiptapBody-DvdefS6K.js} +1 -1
  23. package/dist/assets/{Toggle-BbW4nGGf.js → Toggle-6Jl5Njc6.js} +1 -1
  24. package/dist/assets/{index-CKH5Uxik.css → index-Bta-hwud.css} +1 -1
  25. package/dist/assets/{index-Cd98Q1lD.js → index-vx8O73l8.js} +497 -502
  26. package/dist/assets/{settingsSchema-IhUfucCF.js → settingsSchema-D6iRguNV.js} +1 -1
  27. package/dist/index.html +2 -2
  28. package/package.json +25 -29
  29. package/plugins/CLAUDE.md +6 -6
  30. package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +21 -19
  31. package/plugins/session-manager-dev/skills/builder/SKILL.md +3 -3
  32. package/plugins/session-manager-dev/skills/develop/SKILL.md +254 -510
  33. package/plugins/session-manager-dev/skills/develop/standards.md +17 -22
  34. package/scripts/README.md +3 -11
  35. package/scripts/audit-ops-hygiene.cjs +3 -3
  36. package/scripts/hooks/lib/guard-prd-writes-policy.cjs +1 -1
  37. package/scripts/hooks/lib/guard-self-schedule-policy.cjs +1 -1
  38. package/scripts/mint-epic.cjs +2 -3
  39. package/scripts/scheduler-mcp-server.cjs +36 -7
  40. package/src/main/agentLibrary.cjs +22 -2
  41. package/src/main/build-info.json +4 -4
  42. package/src/main/config.cjs +41 -38
  43. package/src/main/docEdit.cjs +4 -1
  44. package/src/main/files.cjs +2 -5
  45. package/src/main/health.cjs +1 -1
  46. package/src/main/index.cjs +23 -10
  47. package/src/main/ipcSchemas.cjs +28 -35
  48. package/src/main/lib/agentPersonaSchema.cjs +13 -2
  49. package/src/main/lib/atomicFs.cjs +116 -0
  50. package/src/main/lib/branchSweep.cjs +13 -12
  51. package/src/main/lib/buildTarget.cjs +3 -3
  52. package/src/main/lib/claudeCliCaps.cjs +129 -0
  53. package/src/main/lib/credentials.cjs +2 -4
  54. package/src/main/lib/crossProjectFeedback.cjs +3 -3
  55. package/src/main/lib/cwdClassify.cjs +15 -3
  56. package/src/main/lib/definitionOfDone.cjs +207 -125
  57. package/src/main/lib/dodDrainHook.cjs +11 -5
  58. package/src/main/lib/epicMint.cjs +2 -4
  59. package/src/main/lib/epicStatusMirror.cjs +8 -10
  60. package/src/main/lib/epicWorktreeProjectConfig.cjs +2 -4
  61. package/src/main/lib/gateAuthority.cjs +96 -0
  62. package/src/main/lib/gitExec.cjs +69 -0
  63. package/src/main/lib/gitWorktree.cjs +656 -92
  64. package/src/main/lib/instanceLock.cjs +5 -8
  65. package/src/main/lib/launchFailure.cjs +2 -3
  66. package/src/main/lib/macroLibrary.cjs +386 -0
  67. package/src/main/lib/mcpToolCatalog.cjs +26 -17
  68. package/src/main/lib/needsReviewLedger.cjs +1 -1
  69. package/src/main/lib/opsErrorLog.cjs +11 -1
  70. package/src/main/lib/opsOwnership.cjs +0 -5
  71. package/src/main/lib/pidAlive.cjs +32 -0
  72. package/src/main/lib/prdCreate.cjs +121 -12
  73. package/src/main/lib/prdDisposition.cjs +2 -2
  74. package/src/main/lib/prdGateFiles.cjs +284 -0
  75. package/src/main/lib/prdLocations.cjs +61 -0
  76. package/src/main/lib/prdMigration.cjs +2 -3
  77. package/src/main/lib/prdSizing.cjs +2 -1
  78. package/src/main/lib/promptSessionSchema.cjs +10 -2
  79. package/src/main/lib/rcaReport.cjs +4 -6
  80. package/src/main/lib/reaperHelpers.cjs +8 -1
  81. package/src/main/lib/reservationExpiry.cjs +6 -1
  82. package/src/main/lib/reviewNotice.cjs +263 -0
  83. package/src/main/lib/runClaudeP.cjs +4 -1
  84. package/src/main/lib/schedulerPaths.cjs +22 -2
  85. package/src/main/lib/sessionSlots.cjs +2 -4
  86. package/src/main/lib/shippedPersonaSeeds.cjs +179 -0
  87. package/src/main/lib/timeoutShim.cjs +123 -0
  88. package/src/main/lib/timeoutShimScript.cjs +275 -0
  89. package/src/main/lib/upgradeDrain.cjs +4 -10
  90. package/src/main/lib/watchdogHelpers.cjs +12 -25
  91. package/src/main/lib/workTypeLibrary.cjs +7 -1
  92. package/src/main/promptSessionEvents.cjs +37 -13
  93. package/src/main/scheduler.cjs +910 -198
  94. package/src/main/seedAgentPersonas.cjs +278 -23
  95. package/src/main/supervisor.cjs +4 -1
  96. package/src/main/templates/PRD_AUTHORING.md +126 -406
  97. package/src/preload/__tests__/preload-surface.test.cjs +68 -0
  98. package/src/preload/api.d.ts +41 -94
  99. package/src/preload/index.cjs +14 -9
  100. package/src/seed/agents/architect.md +1 -0
  101. package/src/seed/agents/dev-lead.md +17 -18
  102. package/src/seed/agents/project-home-builder.md +1 -0
  103. package/src/seed/agents/validator.md +10 -4
  104. package/dist/assets/HostBilko-CDVHE0hT.js +0 -1
  105. package/dist/assets/Scheduler-C_phpeUS.js +0 -16
  106. package/dist/assets/Settings-BIwZ3FGQ.js +0 -3
  107. package/src/main/__tests__/activeIndexMerge.test.cjs +0 -235
  108. package/src/main/__tests__/agentEffortResolve.test.cjs +0 -117
  109. package/src/main/__tests__/agentLibrary.test.cjs +0 -276
  110. package/src/main/__tests__/agentModelResolve.test.cjs +0 -311
  111. package/src/main/__tests__/agentOverlayWrite.test.cjs +0 -95
  112. package/src/main/__tests__/bilkoHost-deriveSlug.test.cjs +0 -26
  113. package/src/main/__tests__/bilkoHost-integration.test.cjs +0 -118
  114. package/src/main/__tests__/bilkoHostCore.test.cjs +0 -72
  115. package/src/main/__tests__/broadcastCoalescer.test.cjs +0 -122
  116. package/src/main/__tests__/chat-cancel-terminal.test.cjs +0 -120
  117. package/src/main/__tests__/chat-dead-channels.test.cjs +0 -63
  118. package/src/main/__tests__/chat-exit-close-race.test.cjs +0 -146
  119. package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +0 -139
  120. package/src/main/__tests__/chat-preamble-anchors.test.cjs +0 -100
  121. package/src/main/__tests__/chat-queue.test.cjs +0 -97
  122. package/src/main/__tests__/chat-stop-signal.test.cjs +0 -89
  123. package/src/main/__tests__/chatRunner-epic-worktree-execcwd.test.cjs +0 -125
  124. package/src/main/__tests__/chatRunner-session-flag-retry.test.cjs +0 -252
  125. package/src/main/__tests__/classifyPromptTicket.test.cjs +0 -101
  126. package/src/main/__tests__/classifyTranscriptLine.test.cjs +0 -201
  127. package/src/main/__tests__/computeDepHistorySatisfaction.test.cjs +0 -66
  128. package/src/main/__tests__/config-readText-bounded.test.cjs +0 -84
  129. package/src/main/__tests__/configWriteBoundaryOwners.test.cjs +0 -59
  130. package/src/main/__tests__/crossProjectFeedback.test.cjs +0 -334
  131. package/src/main/__tests__/crossProjectFeedbackRoutes.test.cjs +0 -161
  132. package/src/main/__tests__/dep-orphan-archive-health.test.cjs +0 -77
  133. package/src/main/__tests__/develop-skill-failure-modes.test.cjs +0 -70
  134. package/src/main/__tests__/docEdit.test.cjs +0 -244
  135. package/src/main/__tests__/dod-batchkey.test.cjs +0 -183
  136. package/src/main/__tests__/dod-drain-hook.test.cjs +0 -302
  137. package/src/main/__tests__/dod-report.test.cjs +0 -304
  138. package/src/main/__tests__/dod-reverify.test.cjs +0 -285
  139. package/src/main/__tests__/epicContextDigest.test.cjs +0 -174
  140. package/src/main/__tests__/epicMint.test.cjs +0 -332
  141. package/src/main/__tests__/epicMintTelemetryTap.test.cjs +0 -64
  142. package/src/main/__tests__/epicStatusMirror.test.cjs +0 -110
  143. package/src/main/__tests__/epicValidationHook.test.cjs +0 -291
  144. package/src/main/__tests__/exchanges.test.cjs +0 -122
  145. package/src/main/__tests__/exchangesPromptId.test.cjs +0 -61
  146. package/src/main/__tests__/extractJson.test.cjs +0 -51
  147. package/src/main/__tests__/files-reject-credentials.test.cjs +0 -40
  148. package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +0 -556
  149. package/src/main/__tests__/flatPrdTickSweep.test.cjs +0 -110
  150. package/src/main/__tests__/health-build-freshness.test.cjs +0 -39
  151. package/src/main/__tests__/health-claude-md-budget.test.cjs +0 -57
  152. package/src/main/__tests__/health-credentials.test.cjs +0 -81
  153. package/src/main/__tests__/health-delegation-chain.test.cjs +0 -124
  154. package/src/main/__tests__/health-per-project-stall.test.cjs +0 -84
  155. package/src/main/__tests__/health-prd-migration.test.cjs +0 -37
  156. package/src/main/__tests__/health-queue-dispatch.test.cjs +0 -135
  157. package/src/main/__tests__/health-starve-escalation.test.cjs +0 -94
  158. package/src/main/__tests__/health-tick-liveness.test.cjs +0 -179
  159. package/src/main/__tests__/health-usage-poller.test.cjs +0 -144
  160. package/src/main/__tests__/health-worktree-cap-blocked.test.cjs +0 -65
  161. package/src/main/__tests__/heapSnapshot.test.cjs +0 -121
  162. package/src/main/__tests__/historyAggregatorIntraday.test.cjs +0 -313
  163. package/src/main/__tests__/historyDashboard.test.cjs +0 -163
  164. package/src/main/__tests__/historyRollup.test.cjs +0 -333
  165. package/src/main/__tests__/intradayRefresh.test.cjs +0 -39
  166. package/src/main/__tests__/ipcSchemas-dependsOn.test.cjs +0 -39
  167. package/src/main/__tests__/kg-augment.test.cjs +0 -195
  168. package/src/main/__tests__/loadGateDetailTick.test.cjs +0 -31
  169. package/src/main/__tests__/machineProfile.test.cjs +0 -152
  170. package/src/main/__tests__/mcpStatus.test.cjs +0 -61
  171. package/src/main/__tests__/memoryAggregate.test.cjs +0 -109
  172. package/src/main/__tests__/memoryStale.test.cjs +0 -88
  173. package/src/main/__tests__/needsReviewLedger.test.cjs +0 -162
  174. package/src/main/__tests__/openExternalApp-spawn-error.test.cjs +0 -25
  175. package/src/main/__tests__/opsErrorLog.test.cjs +0 -109
  176. package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +0 -173
  177. package/src/main/__tests__/personaMerge.test.cjs +0 -169
  178. package/src/main/__tests__/planValidator.test.cjs +0 -125
  179. package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +0 -176
  180. package/src/main/__tests__/prd-group-allocator.test.cjs +0 -119
  181. package/src/main/__tests__/prdAdminRouteParity.test.cjs +0 -70
  182. package/src/main/__tests__/prdAdminRoutes.test.cjs +0 -718
  183. package/src/main/__tests__/prdAgentType.test.cjs +0 -103
  184. package/src/main/__tests__/prdAuthoringSeed.test.cjs +0 -39
  185. package/src/main/__tests__/prdCreate.test.cjs +0 -979
  186. package/src/main/__tests__/prdCreateAdoption.test.cjs +0 -205
  187. package/src/main/__tests__/prdCreateDisposition.test.cjs +0 -201
  188. package/src/main/__tests__/prdCreatePlanId.test.cjs +0 -132
  189. package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +0 -117
  190. package/src/main/__tests__/prdFrontmatterDependsOn.test.cjs +0 -136
  191. package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +0 -125
  192. package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +0 -108
  193. package/src/main/__tests__/prdLocations.test.cjs +0 -195
  194. package/src/main/__tests__/prdLocationsArchived.test.cjs +0 -201
  195. package/src/main/__tests__/prdMigration.test.cjs +0 -349
  196. package/src/main/__tests__/prdMigrationLegacyAdopt.test.cjs +0 -91
  197. package/src/main/__tests__/prdParserHighWater.test.cjs +0 -74
  198. package/src/main/__tests__/prdParserSourcePromptId.test.cjs +0 -65
  199. package/src/main/__tests__/prdSetDisposition.test.cjs +0 -222
  200. package/src/main/__tests__/prdSizing.test.cjs +0 -106
  201. package/src/main/__tests__/prdSourcePromptIdBackfill.test.cjs +0 -118
  202. package/src/main/__tests__/prdUpdateDependsOn.test.cjs +0 -160
  203. package/src/main/__tests__/proc-role-env.test.cjs +0 -125
  204. package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +0 -304
  205. package/src/main/__tests__/procname-sm-processes.test.cjs +0 -127
  206. package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +0 -177
  207. package/src/main/__tests__/projectPages.test.cjs +0 -137
  208. package/src/main/__tests__/promptSessionEvents.test.cjs +0 -234
  209. package/src/main/__tests__/promptSessionSchema.test.cjs +0 -101
  210. package/src/main/__tests__/promptSessionTranscript.test.cjs +0 -0
  211. package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +0 -159
  212. package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +0 -282
  213. package/src/main/__tests__/pty-session-open-telemetry.test.cjs +0 -96
  214. package/src/main/__tests__/pty-write-result.test.cjs +0 -46
  215. package/src/main/__tests__/queue-health-verdict.test.cjs +0 -170
  216. package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +0 -286
  217. package/src/main/__tests__/queue-starvation-per-project.test.cjs +0 -147
  218. package/src/main/__tests__/queueHistory.test.cjs +0 -355
  219. package/src/main/__tests__/queueOps-interactive-ac-lint.test.cjs +0 -65
  220. package/src/main/__tests__/queueOpsArchiveDestination.test.cjs +0 -65
  221. package/src/main/__tests__/queueOpsAutoArchive.test.cjs +0 -211
  222. package/src/main/__tests__/rateLimitPollerStreak.test.cjs +0 -128
  223. package/src/main/__tests__/rcaReport.test.cjs +0 -266
  224. package/src/main/__tests__/reconcileFlatPrdSweep.test.cjs +0 -119
  225. package/src/main/__tests__/reconcileTiming.test.cjs +0 -135
  226. package/src/main/__tests__/runLogRetention.test.cjs +0 -489
  227. package/src/main/__tests__/runVerify-atomic-verdicts.test.cjs +0 -26
  228. package/src/main/__tests__/runVerify-blocked-by-foreign-wip.test.cjs +0 -58
  229. package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +0 -191
  230. package/src/main/__tests__/runVerify-policy-denial.test.cjs +0 -89
  231. package/src/main/__tests__/runVerify-transcript-commit-evidence.test.cjs +0 -225
  232. package/src/main/__tests__/runVerify.test.cjs +0 -1784
  233. package/src/main/__tests__/scheduleJobSchema.test.cjs +0 -127
  234. package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +0 -65
  235. package/src/main/__tests__/scheduleJobTransitions.test.cjs +0 -277
  236. package/src/main/__tests__/scheduleJobTransitionsGrep.test.cjs +0 -59
  237. package/src/main/__tests__/scheduleJobTransitionsTelemetryTap.test.cjs +0 -72
  238. package/src/main/__tests__/scheduler-admin-routes.test.cjs +0 -199
  239. package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +0 -143
  240. package/src/main/__tests__/scheduler-already-satisfied-on-main.test.cjs +0 -105
  241. package/src/main/__tests__/scheduler-archive-completed-prd.test.cjs +0 -102
  242. package/src/main/__tests__/scheduler-archived-twin-guard.test.cjs +0 -155
  243. package/src/main/__tests__/scheduler-autofix-outcome.test.cjs +0 -188
  244. package/src/main/__tests__/scheduler-autofix-select.test.cjs +0 -439
  245. package/src/main/__tests__/scheduler-autopromote.test.cjs +0 -51
  246. package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +0 -101
  247. package/src/main/__tests__/scheduler-blocked-by-foreign-wip.test.cjs +0 -107
  248. package/src/main/__tests__/scheduler-boot-orphans.test.cjs +0 -153
  249. package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +0 -121
  250. package/src/main/__tests__/scheduler-clear-queue-history.test.cjs +0 -134
  251. package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +0 -244
  252. package/src/main/__tests__/scheduler-committed-in-window.test.cjs +0 -182
  253. package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +0 -43
  254. package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +0 -168
  255. package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +0 -58
  256. package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +0 -81
  257. package/src/main/__tests__/scheduler-epic-digest.test.cjs +0 -227
  258. package/src/main/__tests__/scheduler-failed-autoreset.test.cjs +0 -121
  259. package/src/main/__tests__/scheduler-finalize-dispatch-guards.test.cjs +0 -229
  260. package/src/main/__tests__/scheduler-find-prd-dir.test.cjs +0 -75
  261. package/src/main/__tests__/scheduler-fix-plan-path.test.cjs +0 -119
  262. package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +0 -46
  263. package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +0 -78
  264. package/src/main/__tests__/scheduler-gate-shadow.test.cjs +0 -119
  265. package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +0 -390
  266. package/src/main/__tests__/scheduler-heal-refusal.test.cjs +0 -61
  267. package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +0 -80
  268. package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +0 -323
  269. package/src/main/__tests__/scheduler-integration-failure-stamp.test.cjs +0 -41
  270. package/src/main/__tests__/scheduler-investigation-clean-skip.test.cjs +0 -63
  271. package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +0 -123
  272. package/src/main/__tests__/scheduler-job-budget.test.cjs +0 -172
  273. package/src/main/__tests__/scheduler-job-overrun.test.cjs +0 -175
  274. package/src/main/__tests__/scheduler-launch-failure.test.cjs +0 -199
  275. package/src/main/__tests__/scheduler-leftover-fields.test.cjs +0 -52
  276. package/src/main/__tests__/scheduler-leftover-quarantine.test.cjs +0 -199
  277. package/src/main/__tests__/scheduler-looks-done.test.cjs +0 -537
  278. package/src/main/__tests__/scheduler-manual-pause.test.cjs +0 -118
  279. package/src/main/__tests__/scheduler-mechanical-recovery.test.cjs +0 -245
  280. package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +0 -46
  281. package/src/main/__tests__/scheduler-mutate-reentrancy.test.cjs +0 -117
  282. package/src/main/__tests__/scheduler-needs-review-autoresolve.test.cjs +0 -197
  283. package/src/main/__tests__/scheduler-never-stop.test.cjs +0 -157
  284. package/src/main/__tests__/scheduler-no-dead-end-status.test.cjs +0 -152
  285. package/src/main/__tests__/scheduler-no-orphan-run-dir.test.cjs +0 -81
  286. package/src/main/__tests__/scheduler-notify-originating-tab-transcript.test.cjs +0 -87
  287. package/src/main/__tests__/scheduler-notify-originating-tab.test.cjs +0 -343
  288. package/src/main/__tests__/scheduler-periodic-reverify-guard.test.cjs +0 -217
  289. package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +0 -164
  290. package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +0 -161
  291. package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +0 -178
  292. package/src/main/__tests__/scheduler-quarantine-autoresolve.test.cjs +0 -165
  293. package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +0 -257
  294. package/src/main/__tests__/scheduler-rate-limit-cooldown-freshness.test.cjs +0 -123
  295. package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +0 -152
  296. package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +0 -156
  297. package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +0 -754
  298. package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +0 -87
  299. package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +0 -100
  300. package/src/main/__tests__/scheduler-reconcile-history-backfill.test.cjs +0 -105
  301. package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +0 -203
  302. package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +0 -247
  303. package/src/main/__tests__/scheduler-reset-job-fields-guard.test.cjs +0 -77
  304. package/src/main/__tests__/scheduler-resume-recovery.test.cjs +0 -254
  305. package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +0 -115
  306. package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +0 -380
  307. package/src/main/__tests__/scheduler-sigterm-commit.test.cjs +0 -43
  308. package/src/main/__tests__/scheduler-stall-per-project.test.cjs +0 -126
  309. package/src/main/__tests__/scheduler-starve-escalation.test.cjs +0 -154
  310. package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +0 -252
  311. package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +0 -185
  312. package/src/main/__tests__/scheduler-stuck-failed-escalation.test.cjs +0 -136
  313. package/src/main/__tests__/scheduler-supervisor-record.test.cjs +0 -81
  314. package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +0 -54
  315. package/src/main/__tests__/scheduler-tick-wedge.test.cjs +0 -172
  316. package/src/main/__tests__/scheduler-transient-failure.test.cjs +0 -141
  317. package/src/main/__tests__/scheduler-unreadable-queue-guard.test.cjs +0 -62
  318. package/src/main/__tests__/scheduler-utilization-hold.test.cjs +0 -89
  319. package/src/main/__tests__/scheduler-verify-prd-path.test.cjs +0 -109
  320. package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +0 -234
  321. package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +0 -120
  322. package/src/main/__tests__/scheduler-writeprd-epic-rollback.test.cjs +0 -105
  323. package/src/main/__tests__/schedulerBatchRootBlocker.test.cjs +0 -117
  324. package/src/main/__tests__/schedulerStateSidecarRestore.test.cjs +0 -110
  325. package/src/main/__tests__/seedAgentPersonas.test.cjs +0 -184
  326. package/src/main/__tests__/seedSchedulerMcp.test.cjs +0 -211
  327. package/src/main/__tests__/seedStatus.test.cjs +0 -100
  328. package/src/main/__tests__/seedValidatorPersona.test.cjs +0 -116
  329. package/src/main/__tests__/stop-signal-anchor.test.cjs +0 -75
  330. package/src/main/__tests__/telemetryClient.test.cjs +0 -1055
  331. package/src/main/__tests__/telemetryContract.test.cjs +0 -930
  332. package/src/main/__tests__/telemetrySettings.test.cjs +0 -210
  333. package/src/main/__tests__/transcripts-batch-flush.test.cjs +0 -249
  334. package/src/main/__tests__/transcripts-doFlush-array.test.cjs +0 -124
  335. package/src/main/__tests__/transcripts-paged-reads.test.cjs +0 -241
  336. package/src/main/__tests__/transcripts-worktree-epic-path.test.cjs +0 -154
  337. package/src/main/__tests__/transcriptsUsageFor.test.cjs +0 -206
  338. package/src/main/__tests__/uniquePrdNumbers.test.cjs +0 -153
  339. package/src/main/__tests__/usageSingleFlight.test.cjs +0 -169
  340. package/src/main/__tests__/validationSentinels.test.cjs +0 -84
  341. package/src/main/__tests__/workTypeLibrary.test.cjs +0 -89
  342. package/src/main/bilkoHost.cjs +0 -314
  343. package/src/main/bilkoHostCore.cjs +0 -89
  344. package/src/main/lib/__tests__/active-sessions.test.cjs +0 -251
  345. package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +0 -179
  346. package/src/main/lib/__tests__/agentPersonaSchema.test.cjs +0 -67
  347. package/src/main/lib/__tests__/auditLog.test.cjs +0 -38
  348. package/src/main/lib/__tests__/bootSelfHeal.test.cjs +0 -107
  349. package/src/main/lib/__tests__/branchSweep.test.cjs +0 -164
  350. package/src/main/lib/__tests__/buildIdentity.test.cjs +0 -121
  351. package/src/main/lib/__tests__/buildTarget.test.cjs +0 -52
  352. package/src/main/lib/__tests__/childWithLog.test.cjs +0 -321
  353. package/src/main/lib/__tests__/coldBootPromptSessionsWrite.test.cjs +0 -87
  354. package/src/main/lib/__tests__/crashTelemetry.test.cjs +0 -103
  355. package/src/main/lib/__tests__/credentials-futile-refresh.test.cjs +0 -115
  356. package/src/main/lib/__tests__/cwdClassify.test.cjs +0 -111
  357. package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +0 -95
  358. package/src/main/lib/__tests__/delegationReadiness.test.cjs +0 -1175
  359. package/src/main/lib/__tests__/dispatchLoop.test.cjs +0 -63
  360. package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +0 -244
  361. package/src/main/lib/__tests__/ephemeralCwd.test.cjs +0 -91
  362. package/src/main/lib/__tests__/epicDelegationStats.test.cjs +0 -137
  363. package/src/main/lib/__tests__/epicSpawnCwd.test.cjs +0 -283
  364. package/src/main/lib/__tests__/epicSpawnPlan.test.cjs +0 -196
  365. package/src/main/lib/__tests__/epicTranscriptPath.test.cjs +0 -163
  366. package/src/main/lib/__tests__/epicWorktreeBoot.test.cjs +0 -136
  367. package/src/main/lib/__tests__/epicWorktreeMerge.test.cjs +0 -130
  368. package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +0 -117
  369. package/src/main/lib/__tests__/epicWorktreeProjectConfig.test.cjs +0 -137
  370. package/src/main/lib/__tests__/fixChainDepth.test.cjs +0 -40
  371. package/src/main/lib/__tests__/fixtures/204-mercury-steam-horse.log.txt +0 -13
  372. package/src/main/lib/__tests__/fixtures/scheduler-machine.json.corrupt-1789147548 +0 -34
  373. package/src/main/lib/__tests__/gateFixtures.json +0 -20
  374. package/src/main/lib/__tests__/gitCacheBound.test.cjs +0 -69
  375. package/src/main/lib/__tests__/gitWorktree.test.cjs +0 -1478
  376. package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +0 -107
  377. package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +0 -153
  378. package/src/main/lib/__tests__/guardShims.test.cjs +0 -158
  379. package/src/main/lib/__tests__/importReferences.spec.cjs +0 -56
  380. package/src/main/lib/__tests__/instanceLock.test.cjs +0 -173
  381. package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +0 -78
  382. package/src/main/lib/__tests__/jobWorktree.test.cjs +0 -199
  383. package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +0 -82
  384. package/src/main/lib/__tests__/landedSinceRun.test.cjs +0 -133
  385. package/src/main/lib/__tests__/launchFailure.test.cjs +0 -220
  386. package/src/main/lib/__tests__/loadGate.test.cjs +0 -303
  387. package/src/main/lib/__tests__/localAdminHttp.test.cjs +0 -214
  388. package/src/main/lib/__tests__/loopDelay.test.cjs +0 -68
  389. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +0 -107
  390. package/src/main/lib/__tests__/modelCatalog.test.cjs +0 -202
  391. package/src/main/lib/__tests__/opsOwnership.test.cjs +0 -113
  392. package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +0 -328
  393. package/src/main/lib/__tests__/opsRootNestedWrite.test.cjs +0 -51
  394. package/src/main/lib/__tests__/opsRootResolve.test.cjs +0 -149
  395. package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +0 -82
  396. package/src/main/lib/__tests__/prdDisposition.test.cjs +0 -224
  397. package/src/main/lib/__tests__/procIdentity.test.cjs +0 -119
  398. package/src/main/lib/__tests__/procName.test.cjs +0 -92
  399. package/src/main/lib/__tests__/projectBriefCore.test.cjs +0 -216
  400. package/src/main/lib/__tests__/projectRootResolve.test.cjs +0 -148
  401. package/src/main/lib/__tests__/queueHealth.test.cjs +0 -58
  402. package/src/main/lib/__tests__/queueStoreAtomicWrite.test.cjs +0 -88
  403. package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +0 -190
  404. package/src/main/lib/__tests__/quietMachineLease.test.cjs +0 -39
  405. package/src/main/lib/__tests__/rateLimitWindow.test.cjs +0 -88
  406. package/src/main/lib/__tests__/reaperHelpers.test.cjs +0 -577
  407. package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +0 -312
  408. package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +0 -213
  409. package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +0 -125
  410. package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +0 -127
  411. package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +0 -109
  412. package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +0 -71
  413. package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +0 -216
  414. package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +0 -183
  415. package/src/main/lib/__tests__/schedulerPaths.test.cjs +0 -226
  416. package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +0 -133
  417. package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +0 -56
  418. package/src/main/lib/__tests__/sessionSlots.test.cjs +0 -144
  419. package/src/main/lib/__tests__/telemetryBacklog.test.cjs +0 -626
  420. package/src/main/lib/__tests__/telemetryBoot.test.cjs +0 -134
  421. package/src/main/lib/__tests__/telemetryConsent.test.cjs +0 -136
  422. package/src/main/lib/__tests__/telemetryCounters.test.cjs +0 -57
  423. package/src/main/lib/__tests__/telemetryCountersMetadataColumn.test.cjs +0 -98
  424. package/src/main/lib/__tests__/terminalRunOutcome.test.cjs +0 -200
  425. package/src/main/lib/__tests__/toolUseClassify.test.cjs +0 -53
  426. package/src/main/lib/__tests__/updateCheck.test.cjs +0 -63
  427. package/src/main/lib/__tests__/upgradeDrain.test.cjs +0 -130
  428. package/src/main/lib/__tests__/usageCircuit.test.cjs +0 -354
  429. package/src/main/lib/__tests__/watchdog-helpers.test.cjs +0 -441
  430. package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +0 -266
  431. package/src/main/lib/kgExchangePairing.cjs +0 -75
@@ -1,355 +0,0 @@
1
- /**
2
- * queueHistory.test.cjs — unit tests for src/main/lib/queueHistory.cjs and
3
- * scheduler.cjs's selectHistoryJobs merge.
4
- *
5
- * Run: timeout 300 npx vitest run src/main/__tests__/queueHistory.test.cjs
6
- */
7
-
8
- 'use strict';
9
-
10
- import { test, expect, beforeEach, afterEach } from 'vitest';
11
- const fs = require('node:fs');
12
- const os = require('node:os');
13
- const path = require('node:path');
14
-
15
- const RETENTION_MS = 7 * 24 * 60 * 60_000;
16
- const NOW = Date.parse('2026-07-24T12:00:00.000Z');
17
-
18
- function fresh(overrides = {}) {
19
- return {
20
- slug: '01-fresh',
21
- status: 'completed',
22
- runId: 'run-1',
23
- finishedAt: new Date(NOW - 1 * 60 * 60_000).toISOString(), // 1h ago
24
- ...overrides,
25
- };
26
- }
27
-
28
- function old(overrides = {}) {
29
- return {
30
- slug: '02-old',
31
- status: 'completed',
32
- runId: 'run-2',
33
- finishedAt: new Date(NOW - 10 * 24 * 60 * 60_000).toISOString(), // 10d ago
34
- ...overrides,
35
- };
36
- }
37
-
38
- let queueHistory;
39
- let prevOverride;
40
-
41
- beforeEach(() => {
42
- // Point HISTORY_PATH at an isolated tmpdir file (SM_HISTORY_PATH_OVERRIDE)
43
- // instead of the real machine-global history.jsonl — a live Electron
44
- // instance's scheduler.cjs writes that same global file concurrently,
45
- // which races this suite's unlink/append calls and produces real
46
- // production data in place of the expected empty state.
47
- prevOverride = process.env.SM_HISTORY_PATH_OVERRIDE;
48
- process.env.SM_HISTORY_PATH_OVERRIDE = path.join(
49
- os.tmpdir(),
50
- `queueHistory-test-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.jsonl`
51
- );
52
-
53
- // Fresh require per test so HISTORY_PATH's target file starts clean.
54
- delete require.cache[require.resolve('../lib/queueHistory.cjs')];
55
- queueHistory = require('../lib/queueHistory.cjs');
56
- try { fs.unlinkSync(queueHistory.historyPath()); } catch { /* ok if absent */ }
57
- });
58
-
59
- afterEach(() => {
60
- try { fs.unlinkSync(queueHistory.historyPath()); } catch { /* ok if absent */ }
61
- if (prevOverride === undefined) delete process.env.SM_HISTORY_PATH_OVERRIDE;
62
- else process.env.SM_HISTORY_PATH_OVERRIDE = prevOverride;
63
- });
64
-
65
- // ---------- partitionJobs ----------
66
-
67
- test('partitionJobs: fresh completed job stays hot', () => {
68
- const { hot, toArchive } = queueHistory.partitionJobs([fresh()], NOW);
69
- expect(hot.map((j) => j.slug)).toEqual(['01-fresh']);
70
- expect(toArchive).toEqual([]);
71
- });
72
-
73
- test('partitionJobs: old completed job archives', () => {
74
- const { hot, toArchive } = queueHistory.partitionJobs([old()], NOW);
75
- expect(hot).toEqual([]);
76
- expect(toArchive.map((j) => j.slug)).toEqual(['02-old']);
77
- });
78
-
79
- test('partitionJobs: old failed job archives', () => {
80
- const j = old({ slug: '03-old-failed', status: 'failed', runId: 'run-3' });
81
- const { hot, toArchive } = queueHistory.partitionJobs([j], NOW);
82
- expect(hot).toEqual([]);
83
- expect(toArchive.map((x) => x.slug)).toEqual(['03-old-failed']);
84
- });
85
-
86
- test('partitionJobs: running and pending jobs never archive, regardless of age', () => {
87
- const running = old({ slug: '04-running', status: 'running', runId: 'run-4', finishedAt: null });
88
- const pending = old({ slug: '05-pending', status: 'pending', runId: null, finishedAt: null });
89
- const { hot, toArchive } = queueHistory.partitionJobs([running, pending], NOW);
90
- expect(toArchive).toEqual([]);
91
- expect(hot.map((j) => j.slug).sort()).toEqual(['04-running', '05-pending']);
92
- });
93
-
94
- test('partitionJobs: old skipped job archives (never-ran rows must age out of the hot queue too)', () => {
95
- const j = old({ slug: '03b-old-skipped', status: 'skipped', runId: 'run-3b' });
96
- const { hot, toArchive } = queueHistory.partitionJobs([j], NOW);
97
- expect(hot).toEqual([]);
98
- expect(toArchive.map((x) => x.slug)).toEqual(['03b-old-skipped']);
99
- });
100
-
101
- test('partitionJobs: needs_review jobs never archive', () => {
102
- const j = old({ slug: '06-review', status: 'needs_review', runId: 'run-6' });
103
- const { hot, toArchive } = queueHistory.partitionJobs([j], NOW);
104
- expect(toArchive).toEqual([]);
105
- expect(hot.map((x) => x.slug)).toEqual(['06-review']);
106
- });
107
-
108
- test('partitionJobs: job with no/invalid finishedAt stays hot even if old status', () => {
109
- const j = { slug: '07-nofinish', status: 'completed', runId: 'run-7', finishedAt: null };
110
- const { hot, toArchive } = queueHistory.partitionJobs([j], NOW);
111
- expect(toArchive).toEqual([]);
112
- expect(hot.map((x) => x.slug)).toEqual(['07-nofinish']);
113
- });
114
-
115
- test('partitionJobs: fix-plan linkage keeps an old original hot while its fix is pending', () => {
116
- const original = old({ slug: '08-thing', status: 'failed', runId: 'run-8' });
117
- const fixPlan = { slug: '08-fix-thing', status: 'pending', runId: null, finishedAt: null };
118
- const { hot, toArchive } = queueHistory.partitionJobs([original, fixPlan], NOW);
119
- expect(toArchive).toEqual([]);
120
- expect(hot.map((x) => x.slug).sort()).toEqual(['08-fix-thing', '08-thing']);
121
- });
122
-
123
- test('partitionJobs: fix-plan linkage keeps an old original hot while its fix is running', () => {
124
- const original = old({ slug: '09-thing', status: 'failed', runId: 'run-9' });
125
- const fixPlan = { slug: '09-fix-thing', status: 'running', runId: 'run-9b', finishedAt: null };
126
- const { hot, toArchive } = queueHistory.partitionJobs([original, fixPlan], NOW);
127
- expect(toArchive).toEqual([]);
128
- expect(hot.map((x) => x.slug).sort()).toEqual(['09-fix-thing', '09-thing']);
129
- });
130
-
131
- test('partitionJobs: an old original with a COMPLETED fix-plan is free to archive (no longer protected)', () => {
132
- const original = old({ slug: '10-thing', status: 'completed', runId: 'run-10' });
133
- const fixPlan = old({ slug: '10-fix-thing', status: 'completed', runId: 'run-10b' });
134
- const { hot, toArchive } = queueHistory.partitionJobs([original, fixPlan], NOW);
135
- expect(hot).toEqual([]);
136
- expect(toArchive.map((x) => x.slug).sort()).toEqual(['10-fix-thing', '10-thing']);
137
- });
138
-
139
- test('partitionJobs: respects opts.retentionMs override', () => {
140
- const j = { slug: '11-recent', status: 'completed', runId: 'run-11', finishedAt: new Date(NOW - 2 * 60 * 60_000).toISOString() };
141
- const { toArchive } = queueHistory.partitionJobs([j], NOW, { retentionMs: 60 * 60_000 }); // 1h retention
142
- expect(toArchive.map((x) => x.slug)).toEqual(['11-recent']);
143
- });
144
-
145
- // ---------- appendHistory / readHistory ----------
146
-
147
- test('appendHistory writes entries, readHistory reads them back newest-first', async () => {
148
- const a = old({ slug: 'a', runId: 'ra', finishedAt: new Date(NOW - 3 * 60 * 60_000).toISOString() });
149
- const b = old({ slug: 'b', runId: 'rb', finishedAt: new Date(NOW - 1 * 60 * 60_000).toISOString() });
150
- await queueHistory.appendHistory([a, b]);
151
- const read = await queueHistory.readHistory({ limit: 10 });
152
- // appended in file order a,b; readHistory reverses file order to newest-appended-first
153
- expect(read.map((j) => j.slug)).toEqual(['b', 'a']);
154
- });
155
-
156
- test('appendHistory dedupes by slug+runId against what is already on disk', async () => {
157
- const a = old({ slug: 'dup', runId: 'r1' });
158
- const r1 = await queueHistory.appendHistory([a]);
159
- expect(r1.appended).toBe(1);
160
- const r2 = await queueHistory.appendHistory([a]); // replay of the same batch (crash-recovery scenario)
161
- expect(r2.appended).toBe(0);
162
- const read = await queueHistory.readHistory({ limit: 10 });
163
- expect(read.length).toBe(1);
164
- });
165
-
166
- test('appendHistory: a needs_review ledger line and a terminal row sharing slug+runId do NOT dedupe against each other', async () => {
167
- // An entry and its resolution line (needsReviewLedger.cjs) deliberately
168
- // reference the SAME runId as each other — and a slug's terminal archive
169
- // row can later reuse that same runId too (same run, different `kind`).
170
- // jobKey must bucket by kind or the second/third write looks like a
171
- // crash-replay of the first and silently never lands.
172
- const entryLine = { kind: 'needs_review_entry', slug: 'ledger-dup', runId: 'shared-run', at: new Date(NOW).toISOString(), reason: 'uncommitted_changes', source: 'spawnJob:finalize' };
173
- const resolutionLine = { kind: 'needs_review_resolution', slug: 'ledger-dup', runId: 'shared-run', at: new Date(NOW).toISOString(), resolvedTo: 'completed', ladderRung: 'reverify', source: 'reverifyNeedsReview:heal', dwellMs: 1000 };
174
- const terminalLine = old({ slug: 'ledger-dup', runId: 'shared-run' });
175
- const r1 = await queueHistory.appendHistory([entryLine]);
176
- const r2 = await queueHistory.appendHistory([resolutionLine]);
177
- const r3 = await queueHistory.appendHistory([terminalLine]);
178
- expect(r1.appended).toBe(1);
179
- expect(r2.appended).toBe(1);
180
- expect(r3.appended).toBe(1);
181
- const read = await queueHistory.readHistory({ limit: 10 });
182
- expect(read.filter((j) => j.slug === 'ledger-dup')).toHaveLength(3);
183
- });
184
-
185
- test('readHistory respects limit and returns [] when file is absent', async () => {
186
- const empty = await queueHistory.readHistory({ limit: 5 });
187
- expect(empty).toEqual([]);
188
-
189
- // Realistic append order: oldest finishedAt first (append-only file grows
190
- // forward in time), so s7 is both last-appended and newest.
191
- const entries = Array.from({ length: 8 }, (_, i) => old({ slug: `s${i}`, runId: `r${i}`, finishedAt: new Date(NOW - (7 - i) * 60_000).toISOString() }));
192
- await queueHistory.appendHistory(entries);
193
- const read = await queueHistory.readHistory({ limit: 3 });
194
- expect(read.length).toBe(3);
195
- // Federated readHistory (2026-07-31) orders by finishedAt newest-first.
196
- expect(read.map((j) => j.slug)).toEqual(['s7', 's6', 's5']);
197
- });
198
-
199
- test('readHistory tail-reads correctly when the file is larger than one chunk', async () => {
200
- // Force many small appends so the file exceeds the initial 64KB read chunk.
201
- const bigEntries = Array.from({ length: 2000 }, (_, i) => ({
202
- slug: `bulk-${i}`,
203
- status: 'completed',
204
- runId: `bulk-run-${i}`,
205
- finishedAt: new Date(NOW - i * 1000).toISOString(),
206
- bodyPreview: 'x'.repeat(80),
207
- }));
208
- await queueHistory.appendHistory(bigEntries);
209
- const read = await queueHistory.readHistory({ limit: 5 });
210
- // The tail read only touches the file's end; whatever was read comes back
211
- // ordered by finishedAt newest-first.
212
- expect(read.length).toBe(5);
213
- const t = (j) => Date.parse(j.finishedAt);
214
- for (let i = 1; i < read.length; i++) expect(t(read[i - 1])).toBeGreaterThanOrEqual(t(read[i]));
215
- });
216
-
217
- // ---------- selectHistoryJobs merge (scheduler.cjs) ----------
218
-
219
- test('selectHistoryJobs merges hot jobs[] and history tail, newest-first, deduped', () => {
220
- const { selectHistoryJobs } = require('../scheduler.cjs');
221
- const hotJob = fresh({ slug: 'hot-1', runId: 'rh1' });
222
- const historyEntry = old({ slug: 'hist-1', runId: 'rhist1' });
223
- const merged = selectHistoryJobs([hotJob], 10, [historyEntry]);
224
- expect(merged.map((j) => j.slug)).toEqual(['hot-1', 'hist-1']); // hot is newer
225
- });
226
-
227
- test('selectHistoryJobs: jobs[] entry wins over a duplicate history entry with the same slug+runId', () => {
228
- const { selectHistoryJobs } = require('../scheduler.cjs');
229
- const hotCopy = fresh({ slug: 'dup', runId: 'rd', bodyPreview: 'from-hot' });
230
- const historyCopy = fresh({ slug: 'dup', runId: 'rd', bodyPreview: 'from-history' });
231
- const merged = selectHistoryJobs([hotCopy], 10, [historyCopy]);
232
- expect(merged.length).toBe(1);
233
- expect(merged[0].bodyPreview).toBe('from-hot');
234
- });
235
-
236
- test('selectHistoryJobs: default historyEntries=[] preserves old call shape', () => {
237
- const { selectHistoryJobs } = require('../scheduler.cjs');
238
- const merged = selectHistoryJobs([fresh()], 10);
239
- expect(merged.map((j) => j.slug)).toEqual(['01-fresh']);
240
- });
241
-
242
- test('selectHistoryJobs: needs_review ledger lines (kind !== "terminal") are excluded from the merged result', () => {
243
- // The History view renders ScheduleJob-shaped rows (status, exitCode, ...)
244
- // — a needs_review_entry/needs_review_resolution line (needsReviewLedger.cjs)
245
- // has neither, and must not slip through as a statusless row in that table.
246
- const { selectHistoryJobs } = require('../scheduler.cjs');
247
- const terminalEntry = old({ slug: 'hist-1', runId: 'rhist1' });
248
- const ledgerEntry = { kind: 'needs_review_entry', slug: 'ledger-1', runId: 'rledger1', at: new Date(NOW).toISOString(), reason: 'uncommitted_changes', source: 'spawnJob:finalize' };
249
- const ledgerResolution = { kind: 'needs_review_resolution', slug: 'ledger-1', runId: 'rledger1', at: new Date(NOW).toISOString(), resolvedTo: 'completed', ladderRung: 'reverify', source: 'reverifyNeedsReview:heal', dwellMs: 500 };
250
- const merged = selectHistoryJobs([], 10, [terminalEntry, ledgerEntry, ledgerResolution]);
251
- expect(merged.map((j) => j.slug)).toEqual(['hist-1']);
252
- });
253
-
254
- // ---------- historyTerminalBySlug ----------
255
- //
256
- // Guards against scheduler.cjs's reconcile() resurrecting an already-
257
- // archived-to-history job as a fresh 'pending' entry (and the scheduler
258
- // then genuinely re-executing an already-completed PRD) just because its
259
- // job row already left jobs[]. reconcile() consults this map before
260
- // treating an unmatched on-disk PRD slug as brand-new.
261
-
262
- test('historyTerminalBySlug: returns status + finishedAt for every archived slug', async () => {
263
- const a = old({ slug: 'term-completed', status: 'completed', runId: 'rc' });
264
- const b = old({ slug: 'term-failed', status: 'failed', runId: 'rf' });
265
- await queueHistory.appendHistory([a, b]);
266
-
267
- const map = await queueHistory.historyTerminalBySlug();
268
- expect(map.get('term-completed')).toEqual({ status: 'completed', finishedAt: a.finishedAt, landedCommit: null });
269
- expect(map.get('term-failed')).toEqual({ status: 'failed', finishedAt: b.finishedAt, landedCommit: null });
270
- expect(map.has('never-archived-slug')).toBe(false);
271
- });
272
-
273
- test('historyTerminalBySlug: returns an empty map when history.jsonl is absent', async () => {
274
- const map = await queueHistory.historyTerminalBySlug();
275
- expect(map.size).toBe(0);
276
- });
277
-
278
- test('historyTerminalBySlug: cache invalidates after a new appendHistory call (mtime changes)', async () => {
279
- const a = old({ slug: 'cache-1', runId: 'rca' });
280
- await queueHistory.appendHistory([a]);
281
- const first = await queueHistory.historyTerminalBySlug();
282
- expect(first.has('cache-1')).toBe(true);
283
- expect(first.has('cache-2')).toBe(false);
284
-
285
- const b = old({ slug: 'cache-2', runId: 'rcb' });
286
- await queueHistory.appendHistory([b]);
287
- const second = await queueHistory.historyTerminalBySlug();
288
- expect(second.has('cache-1')).toBe(true);
289
- expect(second.has('cache-2')).toBe(true);
290
- });
291
-
292
- test('historyTerminalBySlug: ignores needs_review ledger lines, even a LATER one for an already-terminal slug', async () => {
293
- // Chronological order matters here: the terminal row lands first, and a
294
- // needs_review_entry for the SAME slug (a later re-run parking again)
295
- // lands after it. Without the kind guard, last-line-wins would replace
296
- // the true 'completed' record with a status-less ledger row.
297
- const terminal = old({ slug: 'mixed-1', status: 'completed', runId: 'rterm' });
298
- await queueHistory.appendHistory([terminal]);
299
- await queueHistory.appendHistory([{
300
- kind: 'needs_review_entry', slug: 'mixed-1', runId: 'rlater', cwd: null,
301
- at: new Date(NOW).toISOString(), reason: 'uncommitted_changes', source: 'spawnJob:finalize',
302
- }]);
303
-
304
- const map = await queueHistory.historyTerminalBySlug();
305
- expect(map.get('mixed-1')).toEqual({ status: 'completed', finishedAt: terminal.finishedAt, landedCommit: null });
306
- });
307
-
308
- // ---------- completedSlugsForCwd (PRD 1122) ----------
309
- //
310
- // Feeds scheduler.cjs's computeDepHistorySatisfaction: a dependsOn slug with
311
- // no live queue row is only satisfied when it shows up here (or in
312
- // prds-archived/) — scoped to ONE project's own history shard so a
313
- // same-named PRD in an unrelated project can never satisfy a dep.
314
-
315
- test('completedSlugsForCwd: returns slugs completed in this project\'s own shard only', async () => {
316
- const projectCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-1122-projA-'));
317
- const otherCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-1122-projB-'));
318
- await queueHistory.appendHistory([
319
- old({ slug: '900-base', status: 'completed', runId: 'ra', cwd: projectCwd }),
320
- old({ slug: '901-failed', status: 'failed', runId: 'rb', cwd: projectCwd }),
321
- old({ slug: '900-base', status: 'completed', runId: 'rc', cwd: otherCwd }),
322
- ]);
323
-
324
- const slugs = await queueHistory.completedSlugsForCwd(projectCwd);
325
- expect(slugs.has('900-base')).toBe(true);
326
- expect(slugs.has('901-failed')).toBe(false);
327
-
328
- // Same slug completed in a DIFFERENT project must not leak across.
329
- const otherSlugs = await queueHistory.completedSlugsForCwd(otherCwd);
330
- expect(otherSlugs.has('900-base')).toBe(true);
331
- const unrelatedCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-1122-projC-'));
332
- expect((await queueHistory.completedSlugsForCwd(unrelatedCwd)).size).toBe(0);
333
- });
334
-
335
- test('completedSlugsForCwd: returns an empty Set when the project has no history shard yet', async () => {
336
- const freshCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-1122-fresh-'));
337
- const slugs = await queueHistory.completedSlugsForCwd(freshCwd);
338
- expect(slugs.size).toBe(0);
339
- });
340
-
341
- test('completedSlugsForCwd: ignores needs_review ledger lines even when they are the newest line for a completed slug', async () => {
342
- const projectCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-1122-ledger-'));
343
- await queueHistory.appendHistory([
344
- old({ slug: '900-base', status: 'completed', runId: 'ra', cwd: projectCwd }),
345
- ]);
346
- // A later needs_review park for a NEW run of the same slug must not blank
347
- // out the earlier 'completed' record read by completedSlugsForCwd.
348
- await queueHistory.appendHistory([{
349
- kind: 'needs_review_entry', slug: '900-base', runId: 'rb', cwd: projectCwd,
350
- at: new Date(NOW).toISOString(), reason: 'uncommitted_changes', source: 'spawnJob:finalize',
351
- }]);
352
-
353
- const slugs = await queueHistory.completedSlugsForCwd(projectCwd);
354
- expect(slugs.has('900-base')).toBe(true);
355
- });
@@ -1,65 +0,0 @@
1
- /**
2
- * queueOps-interactive-ac-lint.test.cjs — lint for AC checkboxes that
3
- * instruct an interactive/GUI-rendering step (xvfb-run, playwright test,
4
- * electron.launch, screenshot, ...) that a headless claude -p executor can
5
- * never satisfy (see the 776/779 exit143 incidents, 2026-07-30). Must key off
6
- * AC-checkbox context specifically — a PRD's Out-of-scope/notes prose telling
7
- * the executor NOT to do this (PRDs 780/787/788's pattern) must not trigger.
8
- *
9
- * Run: timeout 120 npx vitest run src/main/__tests__/queueOps-interactive-ac-lint.test.cjs
10
- */
11
-
12
- 'use strict';
13
-
14
- import { test, expect } from 'vitest';
15
- const fs = require('node:fs');
16
- const os = require('node:os');
17
- const path = require('node:path');
18
- const { lintOneAsync } = require('../queueOps.cjs');
19
-
20
- function writeTmpPrd(body) {
21
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-lint-interactive-'));
22
- const p = path.join(dir, 'test-prd.md');
23
- const raw = `---\ntitle: "test"\ncwd: ~\nestimateMinutes: 10\n---\n\n${body}\n`;
24
- fs.writeFileSync(p, raw, 'utf8');
25
- return p;
26
- }
27
-
28
- test('flags a PRD with xvfb-run as an AC checkbox line', async () => {
29
- const p = writeTmpPrd(
30
- '# Acceptance criteria\n\n- [ ] `xvfb-run -a npx playwright test tests/e2e/foo.spec.ts` passes\n',
31
- );
32
- const { findings } = await lintOneAsync(p);
33
- expect(findings.some((f) => f.rule === 'interactive-xvfb')).toBe(true);
34
- });
35
-
36
- test('flags a PRD with playwright electron.launch as an AC checkbox line', async () => {
37
- const p = writeTmpPrd(
38
- '# Acceptance criteria\n\n- [ ] Playwright `electron.launch` boots the app and captures a screenshot of the Scheduler tab\n',
39
- );
40
- const { findings } = await lintOneAsync(p);
41
- expect(findings.some((f) => f.rule === 'interactive-electron-launch')).toBe(true);
42
- });
43
-
44
- test('does NOT flag Out-of-scope/notes prose that mentions xvfb without being a checkbox line', async () => {
45
- const p = writeTmpPrd(
46
- '# Acceptance criteria\n\n- [ ] `timeout 300 npm run typecheck` passes\n' +
47
- '- [ ] `timeout 300 npx vitest run src/foo.test.ts` passes\n\n' +
48
- 'NOTE: do NOT add a `playwright test ... under xvfb` acceptance criterion here. Two prior\n' +
49
- 'links in this chain stalled and were SIGTERM\'d (exit 143) on exactly that step — a headless\n' +
50
- '`claude -p` executor spawning `xvfb-run`/Playwright hits a tool-use rejection and hangs.\n\n' +
51
- '# Out of scope\n\n' +
52
- '- Making xvfb-run/Playwright actually work inside a headless claude -p job — out of scope\n',
53
- );
54
- const { findings } = await lintOneAsync(p);
55
- expect(findings.filter((f) => f.rule.startsWith('interactive-')).length).toBe(0);
56
- });
57
-
58
- test('a clean PRD with only typecheck/vitest AC is not flagged', async () => {
59
- const p = writeTmpPrd(
60
- '# Acceptance criteria\n\n- [ ] `timeout 300 npm run typecheck` passes\n' +
61
- '- [ ] `timeout 300 npx vitest run src/foo.test.ts` passes\n',
62
- );
63
- const { findings } = await lintOneAsync(p);
64
- expect(findings.filter((f) => f.rule.startsWith('interactive-')).length).toBe(0);
65
- });
@@ -1,65 +0,0 @@
1
- /**
2
- * queueOpsArchiveDestination.test.cjs — an archived PRD lands beside its OWN
3
- * source, not in the machine-level scheduled-plans tree.
4
- *
5
- * PRD sources are per-project and per-Epic (CLAUDE.md's TAB → EPIC → PRD
6
- * model): `<cwd>/session-manager-operations/scheduler/epics/<epic-id>/prds/`.
7
- * `~/.claude/session-manager/scheduled-plans/` holds only run logs and
8
- * PRD_AUTHORING.md. archiveOne resolved its SOURCE per-project (findPrdDir)
9
- * but hardcoded its DESTINATION to the global PRDS_ARCHIVE_DIR, so a manual
10
- * archive yanked a PRD out of its Epic and stranded it in the retired global
11
- * tree — splitting one Epic's history across two locations.
12
- *
13
- * Observed 2026-08-13: archiving 1035-epic-worktree-ui-surfacing put it under
14
- * scheduled-plans/prds-archived/ while its three chain siblings (1032/1033/
15
- * 1034, archived by scheduler.cjs's own on-completion mover) sat correctly in
16
- * the Epic's prds-archived/. Two movers, two destinations, same operation.
17
- *
18
- * Run: timeout 120 npx vitest run src/main/__tests__/queueOpsArchiveDestination.test.cjs
19
- */
20
-
21
- 'use strict';
22
-
23
- import { test, expect } from 'vitest';
24
- const path = require('node:path');
25
- const { archiveDirForSource, PRDS_DIR, PRDS_ARCHIVE_DIR } = require('../queueOps.cjs');
26
-
27
- const EPIC_PRDS = '/home/u/Projects/proj/session-manager-operations/scheduler/epics/my-epic-abc123/prds';
28
- const TS = '2026-08-14T05-03-41-156Z';
29
-
30
- test('an Epic PRD archives into that Epic\'s own prds-archived/, beside its prds/', () => {
31
- const dir = archiveDirForSource(EPIC_PRDS, TS);
32
- expect(dir).toBe(path.join(path.dirname(EPIC_PRDS), 'prds-archived', TS));
33
- // Concretely: same Epic dir, sibling of prds/.
34
- expect(dir).toBe(
35
- `/home/u/Projects/proj/session-manager-operations/scheduler/epics/my-epic-abc123/prds-archived/${TS}`,
36
- );
37
- });
38
-
39
- test('an Epic PRD never lands under the machine-level scheduled-plans tree', () => {
40
- const dir = archiveDirForSource(EPIC_PRDS, TS);
41
- expect(dir.startsWith(PRDS_ARCHIVE_DIR)).toBe(false);
42
- expect(dir).not.toContain('.claude/session-manager/scheduled-plans');
43
- });
44
-
45
- test('the archived PRD stays inside its own project — the ops root never changes', () => {
46
- const dir = archiveDirForSource(EPIC_PRDS, TS);
47
- expect(dir.startsWith('/home/u/Projects/proj/session-manager-operations/')).toBe(true);
48
- });
49
-
50
- test('two Epics in the same project archive to their own separate dirs', () => {
51
- const other = '/home/u/Projects/proj/session-manager-operations/scheduler/epics/other-epic-def456/prds';
52
- expect(archiveDirForSource(EPIC_PRDS, TS)).not.toBe(archiveDirForSource(other, TS));
53
- });
54
-
55
- test('a legacy flat PRD still archives to the global prds-archived/ — old behavior unchanged', () => {
56
- const dir = archiveDirForSource(PRDS_DIR, TS);
57
- expect(dir).toBe(path.join(PRDS_ARCHIVE_DIR, TS));
58
- });
59
-
60
- test('the batch timestamp is shared, so one archive call reads as one event', () => {
61
- const a = archiveDirForSource(EPIC_PRDS, TS);
62
- const b = archiveDirForSource('/home/u/Projects/other/session-manager-operations/scheduler/epics/e/prds', TS);
63
- expect(path.basename(a)).toBe(TS);
64
- expect(path.basename(b)).toBe(TS);
65
- });