claude-code-session-manager 0.86.0 → 0.88.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 (335) hide show
  1. package/README.md +26 -53
  2. package/dist/assets/AgentLibrary-BZ6IY2g1.js +3 -0
  3. package/dist/assets/{DataModel-Q4jhl24R.js → DataModel-dAoGAODX.js} +1 -1
  4. package/dist/assets/{History-Cj2FejEo.js → History-CF157HyX.js} +2 -2
  5. package/dist/assets/{Hooks-CaelQI6t.js → Hooks-CCPPipBk.js} +3 -3
  6. package/dist/assets/{HostBilko--v7cMR8I.js → HostBilko-Dlmz2m06.js} +1 -1
  7. package/dist/assets/{Library-DgI9oCCZ.js → Library-BaXcboWX.js} +1 -1
  8. package/dist/assets/{ListDetail-DYUZN-x-.js → ListDetail-CoUCzG5S.js} +1 -1
  9. package/dist/assets/MarkdownEditor-DTg3JlOT.js +1 -0
  10. package/dist/assets/{McpServers-ypCYURh3.js → McpServers-DdjY1sA3.js} +2 -2
  11. package/dist/assets/{Memory-C2qYp-3M.js → Memory-BJ3Jlw0C.js} +4 -4
  12. package/dist/assets/{Panel-Cj2kw-Zv.js → Panel-ygRSgc41.js} +1 -1
  13. package/dist/assets/Permissions-m0KAnccF.js +3 -0
  14. package/dist/assets/{Plugins-C1Vj8_dU.js → Plugins-CJRl6B3Q.js} +2 -2
  15. package/dist/assets/{ProvenanceBadge-DczPNM5U.js → ProvenanceBadge-w8cnlVvW.js} +1 -1
  16. package/dist/assets/{SaveBar-Cd_7U6Gb.js → SaveBar-BpyPcUIk.js} +1 -1
  17. package/dist/assets/Scheduler-D2ppxSfy.js +14 -0
  18. package/dist/assets/{ScopeSwitcher-DVSyI44-.js → ScopeSwitcher-EyuIwt-j.js} +1 -1
  19. package/dist/assets/Settings-BHSGGFEc.js +3 -0
  20. package/dist/assets/{SkillReferenceGraph-CUv1_Q2c.js → SkillReferenceGraph-BNaZ2JCF.js} +1 -1
  21. package/dist/assets/{Skills-C_YHkAy-.js → Skills-Dl3q75QV.js} +2 -2
  22. package/dist/assets/{SystemPrompt-B8R7T9xn.js → SystemPrompt-Bg6F-Cyp.js} +1 -1
  23. package/dist/assets/{TagLibrary-dj9YHWyy.js → TagLibrary-BSutflCy.js} +1 -1
  24. package/dist/assets/{TiptapBody-DnSBUjHE.js → TiptapBody-CXih4xrc.js} +1 -1
  25. package/dist/assets/{Toggle-CjV_BJn6.js → Toggle-2qtUHhA9.js} +1 -1
  26. package/dist/assets/{index-CXFQIPhO.js → index-B3emy2oI.js} +583 -583
  27. package/dist/assets/{index-CDo9xBR9.css → index-BHTX4OTc.css} +1 -1
  28. package/dist/assets/settingsSchema-CdzxaqwM.js +3 -0
  29. package/dist/assets/{whisperWorker-Dbia1OpC.js → whisperWorker-C7ZGQwKg.js} +7 -7
  30. package/dist/index.html +2 -2
  31. package/dist/vad/ort-wasm-simd-threaded.asyncify.mjs +106 -110
  32. package/dist/vad/ort-wasm-simd-threaded.asyncify.wasm +0 -0
  33. package/dist/vad/ort-wasm-simd-threaded.jsep.mjs +98 -98
  34. package/dist/vad/ort-wasm-simd-threaded.jsep.wasm +0 -0
  35. package/dist/vad/ort-wasm-simd-threaded.jspi.mjs +99 -102
  36. package/dist/vad/ort-wasm-simd-threaded.jspi.wasm +0 -0
  37. package/dist/vad/ort-wasm-simd-threaded.mjs +46 -46
  38. package/dist/vad/ort-wasm-simd-threaded.wasm +0 -0
  39. package/package.json +14 -17
  40. package/plugins/CLAUDE.md +61 -0
  41. package/plugins/session-manager-dev/.claude-plugin/plugin.json +1 -1
  42. package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +1 -1
  43. package/plugins/session-manager-dev/skills/ops-sweep/SKILL.md +1 -1
  44. package/scripts/README.md +59 -0
  45. package/scripts/audit-ops-hygiene.cjs +350 -0
  46. package/scripts/hooks/guard-destructive-git.cjs +10 -34
  47. package/scripts/hooks/guard-inline-implementation.cjs +14 -8
  48. package/scripts/hooks/guard-prd-writes.cjs +7 -36
  49. package/scripts/hooks/guard-self-schedule.cjs +175 -0
  50. package/scripts/ops-sweep.cjs +355 -0
  51. package/scripts/scheduler-mcp-server.cjs +35 -71
  52. package/src/main/__tests__/agentModelResolve.test.cjs +100 -9
  53. package/src/main/__tests__/bilkoHost-integration.test.cjs +3 -3
  54. package/src/main/__tests__/broadcastCoalescer.test.cjs +18 -0
  55. package/src/main/__tests__/chat-cancel-terminal.test.cjs +6 -9
  56. package/src/main/__tests__/chat-exit-close-race.test.cjs +3 -3
  57. package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +4 -5
  58. package/src/main/__tests__/chat-queue.test.cjs +2 -2
  59. package/src/main/__tests__/chat-stop-signal.test.cjs +2 -2
  60. package/src/main/__tests__/dep-orphan-archive-health.test.cjs +77 -0
  61. package/src/main/__tests__/dod-batchkey.test.cjs +2 -2
  62. package/src/main/__tests__/dod-drain-hook.test.cjs +2 -2
  63. package/src/main/__tests__/dod-report.test.cjs +2 -2
  64. package/src/main/__tests__/dod-reverify.test.cjs +2 -2
  65. package/src/main/__tests__/epicMint.test.cjs +4 -4
  66. package/src/main/__tests__/exchanges.test.cjs +2 -2
  67. package/src/main/__tests__/extractJson.test.cjs +2 -2
  68. package/src/main/__tests__/files-reject-credentials.test.cjs +1 -1
  69. package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +556 -0
  70. package/src/main/__tests__/health-build-freshness.test.cjs +39 -0
  71. package/src/main/__tests__/health-delegation-chain.test.cjs +17 -2
  72. package/src/main/__tests__/health-queue-dispatch.test.cjs +58 -7
  73. package/src/main/__tests__/health-tick-liveness.test.cjs +11 -3
  74. package/src/main/__tests__/health-usage-poller.test.cjs +70 -23
  75. package/src/main/__tests__/historyRollup.test.cjs +2 -2
  76. package/src/main/__tests__/kg-augment.test.cjs +2 -2
  77. package/src/main/__tests__/mcpStatus.test.cjs +2 -2
  78. package/src/main/__tests__/memoryAggregate.test.cjs +1 -1
  79. package/src/main/__tests__/memoryStale.test.cjs +1 -1
  80. package/src/main/__tests__/needsReviewLedger.test.cjs +162 -0
  81. package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +28 -4
  82. package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +48 -4
  83. package/src/main/__tests__/prd-group-allocator.test.cjs +2 -2
  84. package/src/main/__tests__/prdAdminRouteParity.test.cjs +2 -0
  85. package/src/main/__tests__/prdAdminRoutes.test.cjs +14 -2
  86. package/src/main/__tests__/prdAuthoringSeed.test.cjs +39 -0
  87. package/src/main/__tests__/prdCreateDisposition.test.cjs +201 -0
  88. package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +125 -0
  89. package/src/main/__tests__/prdLocations.test.cjs +100 -2
  90. package/src/main/__tests__/prdLocationsArchived.test.cjs +50 -1
  91. package/src/main/__tests__/prdSetDisposition.test.cjs +222 -0
  92. package/src/main/__tests__/proc-role-env.test.cjs +125 -0
  93. package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +304 -0
  94. package/src/main/__tests__/procname-sm-processes.test.cjs +127 -0
  95. package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +81 -401
  96. package/src/main/__tests__/projectPages.test.cjs +63 -149
  97. package/src/main/__tests__/queue-health-verdict.test.cjs +170 -0
  98. package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +117 -20
  99. package/src/main/__tests__/queue-starvation-per-project.test.cjs +14 -2
  100. package/src/main/__tests__/queueHistory.test.cjs +65 -2
  101. package/src/main/__tests__/rateLimitPollerStreak.test.cjs +38 -3
  102. package/src/main/__tests__/reconcileTiming.test.cjs +135 -0
  103. package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +181 -0
  104. package/src/main/__tests__/runVerify.test.cjs +5 -5
  105. package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +3 -3
  106. package/src/main/__tests__/scheduleJobTransitions.test.cjs +103 -3
  107. package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +143 -0
  108. package/src/main/__tests__/scheduler-autofix-select.test.cjs +2 -2
  109. package/src/main/__tests__/scheduler-autopromote.test.cjs +2 -2
  110. package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +3 -5
  111. package/src/main/__tests__/scheduler-boot-orphans.test.cjs +79 -98
  112. package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +121 -0
  113. package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +43 -0
  114. package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +161 -0
  115. package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +58 -0
  116. package/src/main/__tests__/scheduler-epic-digest.test.cjs +3 -5
  117. package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +2 -2
  118. package/src/main/__tests__/scheduler-gate-shadow.test.cjs +119 -0
  119. package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +390 -0
  120. package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +80 -0
  121. package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +25 -18
  122. package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +4 -4
  123. package/src/main/__tests__/scheduler-job-budget.test.cjs +172 -0
  124. package/src/main/__tests__/scheduler-launch-failure.test.cjs +3 -5
  125. package/src/main/__tests__/scheduler-looks-done.test.cjs +119 -10
  126. package/src/main/__tests__/scheduler-manual-pause.test.cjs +118 -0
  127. package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +26 -3
  128. package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +164 -0
  129. package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +17 -2
  130. package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +3 -5
  131. package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +41 -6
  132. package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +62 -6
  133. package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +3 -5
  134. package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +182 -3
  135. package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +87 -0
  136. package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +100 -0
  137. package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +3 -3
  138. package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +4 -4
  139. package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +110 -0
  140. package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +168 -0
  141. package/src/main/__tests__/scheduler-starve-escalation.test.cjs +18 -8
  142. package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +245 -0
  143. package/src/main/__tests__/scheduler-supervisor-record.test.cjs +81 -0
  144. package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +2 -2
  145. package/src/main/__tests__/scheduler-tick-wedge.test.cjs +172 -0
  146. package/src/main/__tests__/scheduler-transient-failure.test.cjs +2 -2
  147. package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +51 -11
  148. package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +3 -5
  149. package/src/main/__tests__/usageSingleFlight.test.cjs +157 -0
  150. package/src/main/__tests__/workTypeLibrary.test.cjs +1 -1
  151. package/src/main/bilkoHost.cjs +16 -7
  152. package/src/main/build-info.json +8 -0
  153. package/src/main/chatRunner.cjs +12 -7
  154. package/src/main/config.cjs +2 -3
  155. package/src/main/docEdit.cjs +4 -2
  156. package/src/main/health.cjs +268 -52
  157. package/src/main/heapSnapshot.cjs +2 -2
  158. package/src/main/historyAggregator.cjs +6 -1
  159. package/src/main/index.cjs +152 -50
  160. package/src/main/ipcSchemas.cjs +53 -17
  161. package/src/main/lib/__tests__/active-sessions.test.cjs +251 -0
  162. package/src/main/lib/__tests__/auditLog.test.cjs +38 -0
  163. package/src/main/lib/__tests__/bootSelfHeal.test.cjs +107 -0
  164. package/src/main/lib/__tests__/buildIdentity.test.cjs +121 -0
  165. package/src/main/lib/__tests__/cwdClassify.test.cjs +111 -0
  166. package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +95 -0
  167. package/src/main/lib/__tests__/delegationReadiness.test.cjs +323 -44
  168. package/src/main/lib/__tests__/dispatchLoop.test.cjs +63 -0
  169. package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +239 -0
  170. package/src/main/lib/__tests__/gateFixtures.json +20 -0
  171. package/src/main/lib/__tests__/gitWorktree.test.cjs +97 -1
  172. package/src/main/lib/__tests__/guardShims.test.cjs +151 -0
  173. package/src/main/lib/__tests__/instanceLock.test.cjs +93 -7
  174. package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +78 -0
  175. package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +11 -0
  176. package/src/main/lib/__tests__/localAdminHttp.test.cjs +1 -1
  177. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +6 -1
  178. package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +5 -5
  179. package/src/main/lib/__tests__/prdDisposition.test.cjs +224 -0
  180. package/src/main/lib/__tests__/procIdentity.test.cjs +119 -0
  181. package/src/main/lib/__tests__/procName.test.cjs +92 -0
  182. package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +67 -0
  183. package/src/main/lib/__tests__/reaperHelpers.test.cjs +179 -1
  184. package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +6 -7
  185. package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +37 -204
  186. package/src/main/lib/__tests__/schedulerPaths.test.cjs +226 -0
  187. package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +94 -0
  188. package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +56 -0
  189. package/src/main/lib/__tests__/sessionSlots.test.cjs +45 -0
  190. package/src/main/lib/__tests__/telemetryBacklog.test.cjs +1 -1
  191. package/src/main/lib/__tests__/upgradeDrain.test.cjs +130 -0
  192. package/src/main/lib/__tests__/usageCircuit.test.cjs +285 -0
  193. package/src/main/lib/__tests__/watchdog-helpers.test.cjs +375 -0
  194. package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +266 -0
  195. package/src/main/lib/activeIndexRebuild.cjs +1 -3
  196. package/{scripts → src/main}/lib/activeSessions.cjs +67 -89
  197. package/src/main/lib/adoptedRunSupervisor.cjs +136 -0
  198. package/src/main/lib/agentModelResolve.cjs +94 -24
  199. package/src/main/lib/agentPersonaSchema.cjs +2 -2
  200. package/src/main/lib/auditLog.cjs +30 -5
  201. package/src/main/lib/bootSelfHeal.cjs +88 -0
  202. package/src/main/lib/buildIdentity.cjs +113 -0
  203. package/src/main/lib/classifyPromptTicket.cjs +3 -2
  204. package/src/main/lib/claudeBin.cjs +37 -2
  205. package/src/main/lib/cleanEnv.cjs +27 -1
  206. package/src/main/lib/credentials.cjs +4 -2
  207. package/src/main/lib/cwdClassify.cjs +185 -0
  208. package/src/main/lib/definitionOfDone.cjs +296 -52
  209. package/src/main/lib/delegationReadiness.cjs +290 -225
  210. package/src/main/lib/dispatchLoop.cjs +40 -0
  211. package/src/main/lib/effectiveModelInfo.cjs +332 -0
  212. package/src/main/lib/ephemeralCwd.cjs +7 -28
  213. package/src/main/lib/epicMint.cjs +3 -3
  214. package/src/main/lib/gitWorktree.cjs +136 -19
  215. package/src/main/lib/guardShims.cjs +156 -0
  216. package/src/main/lib/historyRollup.cjs +6 -7
  217. package/src/main/lib/instanceLock.cjs +32 -5
  218. package/src/main/lib/jobDirtFilter.cjs +7 -2
  219. package/src/main/lib/jobSupervisorRecord.cjs +147 -0
  220. package/src/main/lib/jobWorktreeBootLive.cjs +9 -5
  221. package/src/main/lib/launchFailure.cjs +2 -1
  222. package/src/main/lib/localAdminHttp.cjs +9 -27
  223. package/src/main/lib/mcpToolCatalog.cjs +33 -78
  224. package/src/main/lib/needsReviewLedger.cjs +205 -0
  225. package/src/main/lib/opsErrorLog.cjs +1 -1
  226. package/src/main/lib/opsOwnership.cjs +27 -19
  227. package/src/main/lib/prdAuthoringSeed.cjs +36 -0
  228. package/src/main/lib/prdCreate.cjs +56 -1
  229. package/src/main/lib/prdDisposition.cjs +199 -0
  230. package/src/main/lib/prdFrontmatter.cjs +8 -2
  231. package/src/main/lib/prdLocations.cjs +214 -45
  232. package/src/main/lib/procIdentity.cjs +126 -0
  233. package/src/main/lib/procName.cjs +98 -0
  234. package/src/main/lib/projectHomeAdminRoutes.cjs +56 -327
  235. package/src/main/lib/projectRootResolve.cjs +1 -1
  236. package/src/main/lib/queueHistory.cjs +27 -8
  237. package/src/main/lib/queueStore.cjs +63 -38
  238. package/src/main/lib/quietMachineLease.cjs +19 -2
  239. package/src/main/lib/reaperHelpers.cjs +181 -15
  240. package/src/main/lib/reservationExpiry.cjs +30 -0
  241. package/src/main/lib/runClaudeP.cjs +4 -2
  242. package/src/main/lib/runLogRetention.cjs +3 -2
  243. package/src/main/lib/scheduleJobSchema.cjs +10 -2
  244. package/src/main/lib/scheduleJobTransitions.cjs +60 -0
  245. package/src/main/lib/schedulerBatch.cjs +27 -2
  246. package/src/main/lib/schedulerConfig.cjs +24 -0
  247. package/src/main/lib/schedulerPaths.cjs +175 -0
  248. package/src/main/lib/schedulerRuntimeState.cjs +59 -0
  249. package/src/main/lib/sessionSlots.cjs +47 -9
  250. package/src/main/lib/smProcNames.cjs +51 -0
  251. package/src/main/lib/upgradeDrain.cjs +188 -0
  252. package/src/main/lib/usageCircuit.cjs +206 -0
  253. package/{scripts → src/main}/lib/watchdogHelpers.cjs +71 -38
  254. package/src/main/lib/withTimeout.cjs +33 -0
  255. package/src/main/mcpStatus.cjs +4 -2
  256. package/src/main/pluginInstall.cjs +6 -2
  257. package/src/main/projectPages.cjs +41 -145
  258. package/src/main/pty.cjs +8 -1
  259. package/src/main/queueOps.cjs +10 -10
  260. package/src/main/runVerify.cjs +69 -3
  261. package/src/main/scheduler/prdParser.cjs +13 -0
  262. package/src/main/scheduler.cjs +2841 -482
  263. package/src/main/seedAgentPersonas.cjs +1 -1
  264. package/src/main/seedDevPlugin.cjs +1 -1
  265. package/src/main/seedSchedulerMcp.cjs +7 -6
  266. package/src/main/seedStatus.cjs +1 -1
  267. package/src/main/supervisor.cjs +5 -3
  268. package/src/main/templates/PRD_AUTHORING.md +50 -0
  269. package/src/main/usage.cjs +140 -58
  270. package/src/preload/api.d.ts +110 -65
  271. package/src/preload/index.cjs +12 -4
  272. package/src/seed/agents/project-home-builder.md +31 -48
  273. package/dist/assets/AgentLibrary-DTFL7y8G.js +0 -3
  274. package/dist/assets/MarkdownEditor-DCIubYWf.js +0 -1
  275. package/dist/assets/Permissions-BiYZNGYW.js +0 -3
  276. package/dist/assets/Scheduler-DcLBiJBq.js +0 -14
  277. package/dist/assets/Settings-Cv-pRyms.js +0 -3
  278. package/dist/assets/settingsSchema-BJVciriw.js +0 -3
  279. package/screenshots/.gitkeep +0 -0
  280. package/screenshots/README-screenshots.md +0 -13
  281. package/scripts/project-pages-logic/dist/logic.cjs +0 -4709
  282. package/scripts/render-project-pages/dist/renderer.cjs +0 -18900
  283. package/scripts/render-project-pages.cjs +0 -70
  284. package/scripts/validate-project-pages-summary.cjs +0 -62
  285. package/src/main/lib/projectPageSummarySchema.cjs +0 -181
  286. package/src/main/teams.cjs +0 -95
  287. package/src/main/templates/project-pages-catalog.json +0 -741
  288. package/src/main/templates/project-pages-default-home.html +0 -123
  289. package/src/main/templates/project-pages-pipeline.md +0 -417
  290. package/src/seed/prompts/code-review/ac-coverage-check.md +0 -8
  291. package/src/seed/prompts/code-review/correctness-only.md +0 -8
  292. package/src/seed/prompts/code-review/full-spectrum-high.md +0 -8
  293. package/src/seed/prompts/code-review/hallucination-check.md +0 -8
  294. package/src/seed/prompts/code-review/public-api-compat.md +0 -8
  295. package/src/seed/prompts/code-review/readability-naming.md +0 -8
  296. package/src/seed/prompts/debugging/bug-as-failing-test.md +0 -8
  297. package/src/seed/prompts/debugging/git-bisect-regression.md +0 -8
  298. package/src/seed/prompts/debugging/instrument-intermittent-bug.md +0 -8
  299. package/src/seed/prompts/debugging/localize-pipeline-failure.md +0 -8
  300. package/src/seed/prompts/debugging/reproduce-then-diagnose.md +0 -8
  301. package/src/seed/prompts/documentation/adr-from-change.md +0 -8
  302. package/src/seed/prompts/documentation/module-readme.md +0 -8
  303. package/src/seed/prompts/documentation/onboarding-plan.md +0 -8
  304. package/src/seed/prompts/documentation/refresh-claude-md.md +0 -8
  305. package/src/seed/prompts/documentation/tsdoc-public-exports.md +0 -8
  306. package/src/seed/prompts/git-pr/conventional-commit.md +0 -8
  307. package/src/seed/prompts/git-pr/draft-pr-title-body.md +0 -8
  308. package/src/seed/prompts/git-pr/pre-commit-safety-sweep.md +0 -8
  309. package/src/seed/prompts/git-pr/release-notes-block.md +0 -8
  310. package/src/seed/prompts/git-pr/split-large-pr.md +0 -8
  311. package/src/seed/prompts/performance/bundle-startup-audit.md +0 -8
  312. package/src/seed/prompts/performance/complexity-audit.md +0 -8
  313. package/src/seed/prompts/performance/cpu-profile-hot-path.md +0 -8
  314. package/src/seed/prompts/performance/db-query-plan-review.md +0 -8
  315. package/src/seed/prompts/performance/memory-leak-hunt.md +0 -8
  316. package/src/seed/prompts/qa/api-contract-tests.md +0 -8
  317. package/src/seed/prompts/qa/e2e-critical-path.md +0 -8
  318. package/src/seed/prompts/qa/failing-test-for-bug.md +0 -8
  319. package/src/seed/prompts/qa/find-missing-test-coverage.md +0 -8
  320. package/src/seed/prompts/qa/stabilize-flaky-test.md +0 -8
  321. package/src/seed/prompts/qa/tdd-red-first.md +0 -8
  322. package/src/seed/prompts/qa/visual-regression-review.md +0 -8
  323. package/src/seed/prompts/qa/wcag-axe-scan.md +0 -8
  324. package/src/seed/prompts/refactoring/dead-code-sweep.md +0 -8
  325. package/src/seed/prompts/refactoring/extract-duplicated-pattern.md +0 -8
  326. package/src/seed/prompts/refactoring/modernize-legacy-file.md +0 -8
  327. package/src/seed/prompts/refactoring/reduce-cyclomatic-complexity.md +0 -8
  328. package/src/seed/prompts/refactoring/tighten-module-boundaries.md +0 -8
  329. package/src/seed/prompts/security/authz-audit.md +0 -8
  330. package/src/seed/prompts/security/crypto-correctness.md +0 -8
  331. package/src/seed/prompts/security/cwe-top-25-hunt.md +0 -8
  332. package/src/seed/prompts/security/dependency-audit.md +0 -8
  333. package/src/seed/prompts/security/ipc-boundary-hardening.md +0 -8
  334. package/src/seed/prompts/security/owasp-top-10-staged-diff.md +0 -8
  335. package/src/seed/prompts/security/secret-credential-scan.md +0 -8
@@ -91,41 +91,104 @@ function reportExists(key, runsDir = RUNS_DIR) {
91
91
  return false;
92
92
  }
93
93
 
94
- // Shell metacharacters that require shell:true — prohibited by CLAUDE.md for
95
- // non-user-supplied strings. Commands containing these are marked unverifiable
96
- // rather than running under a shell, since CLAUDE.md restricts shell:true to
97
- // watchers.cjs and app:test-fire-hook only.
98
- const SHELL_META_RE = /[|>&;<`]|\$[({]/;
94
+ const DEFAULT_GATE_TIMEOUT_MS = 300_000;
99
95
 
100
96
  /**
101
- * Extract the first bounded AC test command from a PRD body.
102
- *
103
- * Searches the # Acceptance criteria section for lines containing a
104
- * `timeout NNN cmd [args...]` invocation. Returns the command string or null.
105
- *
106
- * Commands containing shell metacharacters (pipe, redirect, subshell) are
107
- * skipped — they cannot be run without shell:true which is prohibited here.
108
- * The parser falls through to the next AC line in that case.
109
- *
110
- * Complexity: O(L) where L = number of lines in the body (not user-scaled;
111
- * PRD bodies are bounded documents, typically < 200 lines).
112
- *
113
- * @param {string} prdBody PRD markdown with frontmatter already stripped.
114
- * @returns {string|null}
97
+ * Quote-aware tokenizer for ONE command segment — no shell. Returns the argv
98
+ * tokens, or null when an unquoted shell metacharacter survives (pipe,
99
+ * redirect, `;`, lone `&`, backtick, `$(`/`${`) or a quote is unbalanced.
100
+ * Complexity: O(n) over the segment's characters.
115
101
  */
116
- function extractAcCommand(prdBody) {
117
- if (!prdBody || typeof prdBody !== 'string') return null;
102
+ function tokenizeNoShell(seg) {
103
+ const tokens = [];
104
+ let cur = '';
105
+ let inTok = false;
106
+ let quote = null;
107
+ for (let i = 0; i < seg.length; i++) {
108
+ const c = seg[i];
109
+ if (quote) {
110
+ if (c === quote) quote = null;
111
+ else cur += c;
112
+ continue;
113
+ }
114
+ if (c === '"' || c === "'") { quote = c; inTok = true; continue; }
115
+ if (/\s/.test(c)) {
116
+ if (inTok) { tokens.push(cur); cur = ''; inTok = false; }
117
+ continue;
118
+ }
119
+ if ('|<>;&`'.includes(c) || (c === '$' && (seg[i + 1] === '(' || seg[i + 1] === '{'))) return null;
120
+ cur += c;
121
+ inTok = true;
122
+ }
123
+ if (quote) return null;
124
+ if (inTok) tokens.push(cur);
125
+ return tokens;
126
+ }
127
+
128
+ /**
129
+ * Split a command chain on `&&` outside quotes and backticks.
130
+ * Complexity: O(n).
131
+ */
132
+ function splitOnAndAnd(text) {
133
+ const segs = [];
134
+ let cur = '';
135
+ let quote = null;
136
+ for (let i = 0; i < text.length; i++) {
137
+ const c = text[i];
138
+ if (quote) {
139
+ cur += c;
140
+ if (c === quote) quote = null;
141
+ continue;
142
+ }
143
+ if (c === '"' || c === "'" || c === '`') { quote = c; cur += c; continue; }
144
+ if (c === '&' && text[i + 1] === '&') { segs.push(cur); cur = ''; i++; continue; }
145
+ cur += c;
146
+ }
147
+ segs.push(cur);
148
+ return segs;
149
+ }
150
+
151
+ /**
152
+ * Parse one `&&` chain into [{argv, timeoutMs, env, raw}]. Returns [] when any
153
+ * segment is empty or needs a shell — a half-parsed gate must never run.
154
+ * A leading `timeout N` (or `Ns`) token sets timeoutMs; leading literal
155
+ * `NAME=value` tokens become env (a `TMPDIR=` assignment is dropped — the
156
+ * shadow runner always supplies its own isolated TMPDIR; its value is
157
+ * typically the un-runnable `$(mktemp -d)`, which is handled here without a
158
+ * shell by simply never evaluating it).
159
+ */
160
+ function parseChain(text) {
161
+ const out = [];
162
+ for (const seg of splitOnAndAnd(text)) {
163
+ const raw = seg.trim();
164
+ if (!raw) return [];
165
+ // A dropped TMPDIR=$(mktemp -d) prefix is the one substitution we accept.
166
+ const stripped = raw.replace(/^TMPDIR=\$\(mktemp -d\)\s+/, '');
167
+ const tokens = tokenizeNoShell(stripped);
168
+ if (!tokens || !tokens.length) return [];
169
+ const env = {};
170
+ while (tokens.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0])) {
171
+ const [k, ...rest] = tokens.shift().split('=');
172
+ if (k !== 'TMPDIR') env[k] = rest.join('=');
173
+ }
174
+ let timeoutMs = DEFAULT_GATE_TIMEOUT_MS;
175
+ if (tokens[0] === 'timeout' && /^\d+s?$/.test(tokens[1] || '')) {
176
+ timeoutMs = parseInt(tokens[1], 10) * 1000;
177
+ tokens.splice(0, 2);
178
+ }
179
+ if (!tokens.length) return [];
180
+ out.push({ argv: tokens, timeoutMs, env, raw });
181
+ }
182
+ return out;
183
+ }
118
184
 
119
- // Parse line-by-line to locate the # Acceptance criteria section.
120
- // A regex lookahead approach with the `m` flag misidentifies `$` as
121
- // end-of-line (not end-of-string), causing the lazy capture to terminate
122
- // immediately. Line-by-line parsing avoids that pitfall.
123
- const lines = prdBody.split('\n');
185
+ /** Locate the `# Acceptance criteria` lines (whole body when the heading is absent). */
186
+ function acCandidateLines(body) {
187
+ const lines = body.split('\n');
124
188
  let inAcSection = false;
125
189
  let hasAcSection = false;
126
190
  let acHeadingLevel = 0;
127
191
  const acLines = [];
128
-
129
192
  for (const line of lines) {
130
193
  if (/^#+\s/i.test(line)) {
131
194
  const level = line.match(/^(#+)/)[1].length;
@@ -134,42 +197,127 @@ function extractAcCommand(prdBody) {
134
197
  hasAcSection = true;
135
198
  acHeadingLevel = level;
136
199
  } else if (inAcSection && level <= acHeadingLevel) {
137
- // A sibling or parent heading ends the AC section;
138
- // sub-headings (level > acHeadingLevel) stay inside it.
139
200
  inAcSection = false;
140
201
  }
141
202
  continue;
142
203
  }
143
204
  if (inAcSection) acLines.push(line);
144
205
  }
206
+ return hasAcSection ? acLines : lines;
207
+ }
145
208
 
146
- // Fall back to full body if no AC section header was found.
147
- const candidates = hasAcSection ? acLines : lines;
209
+ /**
210
+ * Read an explicit gate spec: frontmatter `gate:` (`none`, inline `[a, b]`, or
211
+ * a `- item` list) or a fenced ```gate block (one command chain per line).
212
+ * Returns { kind: 'none' } | { kind: 'commands', chains: string[] } | null.
213
+ */
214
+ function readExplicitGate(prdText) {
215
+ const fmMatch = prdText.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
216
+ if (fmMatch) {
217
+ const fmLines = fmMatch[1].split(/\r?\n/);
218
+ for (let i = 0; i < fmLines.length; i++) {
219
+ const m = fmLines[i].match(/^gate:\s*(.*)$/);
220
+ if (!m) continue;
221
+ const rest = m[1].trim();
222
+ if (/^(['"]?)none\1$/i.test(rest)) return { kind: 'none' };
223
+ const chains = [];
224
+ if (rest.startsWith('[') && rest.endsWith(']')) {
225
+ // Inline list — items may hold commas inside quotes, so split quote-aware.
226
+ let cur = ''; let q = null;
227
+ for (const c of rest.slice(1, -1)) {
228
+ if (q) { if (c === q) q = null; else cur += c; continue; }
229
+ if (c === '"' || c === "'") { q = c; continue; }
230
+ if (c === ',') { chains.push(cur.trim()); cur = ''; continue; }
231
+ cur += c;
232
+ }
233
+ chains.push(cur.trim());
234
+ } else if (rest === '') {
235
+ for (let j = i + 1; j < fmLines.length; j++) {
236
+ const li = fmLines[j].match(/^\s+-\s+(.*)$/);
237
+ if (!li) break;
238
+ chains.push(li[1].trim().replace(/^(['"])(.*)\1$/, '$2'));
239
+ }
240
+ }
241
+ const kept = chains.filter(Boolean);
242
+ if (kept.length) return { kind: 'commands', chains: kept };
243
+ }
244
+ }
245
+ const fence = prdText.match(/^```gate[ \t]*\r?\n([\s\S]*?)^```/m);
246
+ if (fence) {
247
+ const chains = fence[1].split('\n').map((l) => l.trim()).filter((l) => l && !l.startsWith('#'));
248
+ if (chains.length === 1 && /^none$/i.test(chains[0])) return { kind: 'none' };
249
+ if (chains.length) return { kind: 'commands', chains };
250
+ }
251
+ return null;
252
+ }
148
253
 
149
- for (const line of candidates) {
150
- // Prefer backtick-delimited inline code: `timeout NNN cmd ...`
151
- const backtickMatch = line.match(/`(timeout\s+\d+\s+[^`]+)`/i);
254
+ /**
255
+ * Resolve a PRD's gate: explicit spec first (frontmatter `gate:` / ```gate
256
+ * fence), else the first acceptance-criteria line carrying a parseable
257
+ * `timeout N …` chain (backtick span preferred, else bare from the first
258
+ * `timeout N`). Accepts the PRD with or without frontmatter.
259
+ *
260
+ * @param {string} prdText
261
+ * @returns {{ source: 'none'|'explicit'|'ac-line'|'absent', sequence: Array<{argv:string[], timeoutMs:number, env:object, raw:string}> }}
262
+ */
263
+ function resolveGate(prdText) {
264
+ if (!prdText || typeof prdText !== 'string') return { source: 'absent', sequence: [] };
265
+ const explicit = readExplicitGate(prdText);
266
+ if (explicit) {
267
+ if (explicit.kind === 'none') return { source: 'none', sequence: [] };
268
+ const sequence = [];
269
+ for (const chain of explicit.chains) {
270
+ const parsed = parseChain(chain);
271
+ if (!parsed.length) return { source: 'explicit', sequence: [] };
272
+ sequence.push(...parsed);
273
+ }
274
+ return { source: 'explicit', sequence };
275
+ }
276
+ const body = splitFrontmatter(prdText).body;
277
+ for (const line of acCandidateLines(body)) {
278
+ const backtickMatch = line.match(/`([^`]*\btimeout\s+\d+\s[^`]*)`/i);
152
279
  if (backtickMatch) {
153
- const cmd = backtickMatch[1].trim();
154
- if (!SHELL_META_RE.test(cmd)) return cmd;
280
+ const seq = parseChain(backtickMatch[1]);
281
+ if (seq.length) return { source: 'ac-line', sequence: seq };
155
282
  }
156
-
157
- // Fall back: bare `timeout NNN cmd ...` anywhere on the line.
158
- // Trim trailing all-lowercase-alpha tokens (prose words like "passes",
159
- // "and", "the") while keeping at least 4 tokens (timeout, N, binary,
160
- // first-arg). This prevents over-matching into prose that follows the
161
- // command on the same AC line (e.g. "timeout 60 npm test and verify").
283
+ // Bare fallback: from the first `timeout N` to end of line, dropping
284
+ // trailing all-lowercase prose words (keeping ≥ 4 tokens, as before).
162
285
  const rawMatch = line.match(/\btimeout\s+\d+\s+\S+(?:\s+\S+)*/);
163
286
  if (rawMatch) {
164
- const tokens = rawMatch[0].trim().split(/\s+/);
165
- while (tokens.length > 4 && /^[a-z]+$/.test(tokens[tokens.length - 1])) {
166
- tokens.pop();
167
- }
168
- const cmd = tokens.join(' ');
169
- if (!SHELL_META_RE.test(cmd)) return cmd;
287
+ const segs = splitOnAndAnd(rawMatch[0]);
288
+ const tokens = segs[segs.length - 1].trim().split(/\s+/);
289
+ while (tokens.length > 4 && /^[a-z]+$/.test(tokens[tokens.length - 1])) tokens.pop();
290
+ segs[segs.length - 1] = tokens.join(' ');
291
+ const seq = parseChain(segs.join('&&'));
292
+ if (seq.length) return { source: 'ac-line', sequence: seq };
170
293
  }
171
294
  }
172
- return null;
295
+ return { source: 'absent', sequence: [] };
296
+ }
297
+
298
+ /**
299
+ * The gate as an ordered list of no-shell commands: [{argv, timeoutMs}, …].
300
+ * Empty when there is no parseable gate or the PRD opted out with `gate: none`
301
+ * (resolveGate distinguishes the two). Complexity: O(L) over the PRD's lines.
302
+ *
303
+ * @param {string} prdBody PRD markdown (frontmatter optional).
304
+ * @returns {Array<{argv:string[], timeoutMs:number, env:object, raw:string}>}
305
+ */
306
+ function extractAcSequence(prdBody) {
307
+ return resolveGate(prdBody).sequence;
308
+ }
309
+
310
+ /**
311
+ * The single-command view of the gate, as the original `timeout NNN cmd …`
312
+ * string, or null when the gate is absent or is a multi-command chain
313
+ * (reverifyAc runs one command; the chain is the shadow runner's job).
314
+ *
315
+ * @param {string} prdBody PRD markdown with frontmatter already stripped.
316
+ * @returns {string|null}
317
+ */
318
+ function extractAcCommand(prdBody) {
319
+ const seq = extractAcSequence(prdBody);
320
+ return seq.length === 1 && seq[0].raw.startsWith('timeout') ? seq[0].raw : null;
173
321
  }
174
322
 
175
323
  /**
@@ -217,8 +365,8 @@ function reverifyAc(job, { timeoutMs = 60_000, prdsDir } = {}) {
217
365
  const cmd = extractAcCommand(prdBody);
218
366
  if (!cmd) return Promise.resolve(unverifiable());
219
367
 
220
- // Simple whitespace split — SHELL_META_RE in extractAcCommand already excludes
221
- // commands that would need a shell. Paths with spaces are not expected in AC
368
+ // Simple whitespace split — extractAcCommand already excludes
369
+ // commands that would need a shell (tokenizeNoShell). Paths with spaces are not expected in AC
222
370
  // commands (PRD authoring convention: use relative paths from cwd).
223
371
  const argv = cmd.trim().split(/\s+/);
224
372
  if (argv.length < 2) return Promise.resolve(unverifiable());
@@ -231,7 +379,7 @@ function reverifyAc(job, { timeoutMs = 60_000, prdsDir } = {}) {
231
379
  child = spawn(argv[0], argv.slice(1), {
232
380
  cwd: job.cwd,
233
381
  stdio: 'ignore',
234
- // No shell:true — extractAcCommand rejects commands with shell metacharacters.
382
+ // No shell:true — tokenizeNoShell rejects commands with shell metacharacters.
235
383
  });
236
384
  } catch (err) {
237
385
  resolve(unverifiable());
@@ -532,6 +680,99 @@ function writeReport(key, { acResults = [], riskFlags = [], runsDir } = {}) {
532
680
  return reportPath;
533
681
  }
534
682
 
683
+
684
+ // ─── Shadow gate runner ────────────────────────────────────────────────────────
685
+ // Runs a PRD's parsed gate sequence WITHOUT deciding anything: the caller
686
+ // records the outcome next to the verdict. Not a claude -p run, so it takes no
687
+ // slot from sessionSlots; instead a single module-level flag keeps at most one
688
+ // shadow gate in flight machine-wide (the scheduler is one process).
689
+ let gateInFlight = false;
690
+ const OUTPUT_TAIL_CHARS = 1000;
691
+
692
+ function runOneGateCommand(cmd, { cwd, env }) {
693
+ return new Promise((resolve) => {
694
+ const startNs = process.hrtime.bigint();
695
+ const ms = () => Math.round(Number(process.hrtime.bigint() - startNs) / 1e6);
696
+ const label = cmd.argv.join(' ');
697
+ let child;
698
+ try {
699
+ child = spawn(cmd.argv[0], cmd.argv.slice(1), {
700
+ cwd,
701
+ env: { ...env, ...cmd.env },
702
+ stdio: ['ignore', 'pipe', 'pipe'],
703
+ // No shell:true — the sequence was tokenized by tokenizeNoShell.
704
+ });
705
+ } catch {
706
+ resolve({ cmd: label, status: 'unavailable', code: null, ms: ms(), timedOut: false, tail: '' });
707
+ return;
708
+ }
709
+ let tail = '';
710
+ const onData = (d) => { tail = (tail + d).slice(-OUTPUT_TAIL_CHARS); };
711
+ child.stdout.on('data', onData);
712
+ child.stderr.on('data', onData);
713
+ let settled = false;
714
+ let timedOut = false;
715
+ let escalate;
716
+ const killTimer = setTimeout(() => {
717
+ timedOut = true;
718
+ try { child.kill('SIGTERM'); } catch { /* already dead */ }
719
+ escalate = setTimeout(() => {
720
+ try { child.kill('SIGKILL'); } catch { /* race */ }
721
+ }, 5_000);
722
+ if (escalate.unref) escalate.unref();
723
+ }, cmd.timeoutMs);
724
+ if (killTimer.unref) killTimer.unref();
725
+ const finish = (r) => {
726
+ if (settled) return;
727
+ settled = true;
728
+ clearTimeout(killTimer);
729
+ clearTimeout(escalate);
730
+ resolve({ cmd: label, ms: ms(), timedOut, tail, ...r });
731
+ };
732
+ child.on('error', () => finish({ status: 'unavailable', code: null }));
733
+ child.on('close', (code) => {
734
+ const exitCode = typeof code === 'number' ? code : -1;
735
+ finish({ status: exitCode === 0 ? 'pass' : 'fail', code: exitCode });
736
+ });
737
+ });
738
+ }
739
+
740
+ /**
741
+ * Run a gate sequence (extractAcSequence output) in `cwd` with `&&` semantics:
742
+ * stop at the first non-pass. Each run gets its own isolated TMPDIR (mkdtemp,
743
+ * removed afterwards) and CI=1, so a suite that sweeps its temp root can never
744
+ * touch a live one.
745
+ *
746
+ * @param {Array<{argv:string[], timeoutMs:number, env?:object}>} sequence
747
+ * @param {{ cwd: string }} opts
748
+ * @returns {Promise<{ status: 'green'|'red'|'unavailable'|'busy', results: object[] }>}
749
+ * 'busy' = another shadow gate is in flight; nothing ran, nothing to record.
750
+ */
751
+ async function runGateSequence(sequence, { cwd }) {
752
+ if (gateInFlight) return { status: 'busy', results: [] };
753
+ if (!Array.isArray(sequence) || !sequence.length) return { status: 'unavailable', results: [] };
754
+ try { fs.statSync(cwd); } catch { return { status: 'unavailable', results: [] }; }
755
+ gateInFlight = true;
756
+ let tmp = null;
757
+ try {
758
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-gate-shadow-'));
759
+ const env = { ...process.env, TMPDIR: tmp, CI: '1' };
760
+ const results = [];
761
+ for (const cmd of sequence) {
762
+ const r = await runOneGateCommand(cmd, { cwd, env });
763
+ results.push(r);
764
+ if (r.status === 'unavailable') return { status: 'unavailable', results };
765
+ if (r.status === 'fail') return { status: 'red', results };
766
+ }
767
+ return { status: 'green', results };
768
+ } catch {
769
+ return { status: 'unavailable', results: [] };
770
+ } finally {
771
+ gateInFlight = false;
772
+ if (tmp) { try { fs.rmSync(tmp, { recursive: true, force: true }); } catch { /* best-effort */ } }
773
+ }
774
+ }
775
+
535
776
  const WATERMARK_FILENAME = '.dod-watermark.json';
536
777
 
537
778
  /**
@@ -573,6 +814,9 @@ module.exports = {
573
814
  reportPathFor,
574
815
  reportExists,
575
816
  extractAcCommand,
817
+ extractAcSequence,
818
+ resolveGate,
819
+ runGateSequence,
576
820
  extractSection,
577
821
  reverifyAc,
578
822
  reverifyBatch,