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
@@ -48,17 +48,10 @@ const OWNERS = Object.freeze({
48
48
  'scheduler': 'scheduler',
49
49
  // Project Home owns the synthesized Brief (generate + hand-edit).
50
50
  'project-brief': 'project-home',
51
- // Project Home also owns the app-side render path for Project Pages
52
- // (summary.json/picks.json/output/* written via the
53
- // /admin/project-home/render route, config.cjs's writeJson). This is a
54
- // NARROWER claim than "project-home owns everything under this folder":
55
- // the SAME folder is also written directly by a project-home-builder
56
- // Epic's own Write tool, which never goes through config.cjs and so is
57
- // NOT governed by this table at all (see
58
- // session-manager-operations/project-pages/README.md). Declaring the
59
- // namespace here only closes the fail-closed gap for the app's own write
60
- // path — it does not claim exclusivity over the agent's Write-tool calls,
61
- // which remain outside this law by construction.
51
+ // Project Home owns project-pages/home.html, written only via the
52
+ // project_home_write MCP tool -> /admin/project-home/write route
53
+ // (config.cjs's writeTextAtomic). See
54
+ // session-manager-operations/project-pages/README.md.
62
55
  'project-pages': 'project-home',
63
56
  // Structured per-tab error log lines (JSONL), tagged for tracing/analysis.
64
57
  'logs': 'logs',
@@ -177,11 +170,13 @@ function assertOpsWrite(absPath, writer) {
177
170
  // worktree-cwd hazard (PRD 1082; incidents 2026-08-30, 2026-09-01).
178
171
  const { inOps } = parseOpsPath(absPath);
179
172
  if (inOps) {
180
- const segs = absPath.split(path.sep);
181
- const idx = segs.lastIndexOf(OPS_ROOT_DIR);
182
- const projectRoot = segs.slice(0, idx).join(path.sep) || path.sep;
183
- const { isEphemeralCwd } = require('./ephemeralCwd.cjs');
184
- if (isEphemeralCwd(projectRoot)) {
173
+ // innermostOpsRoot (lastIndexOf) is the fact THIS gate keys on; activeSessions
174
+ // truncates at the outermost instead — cwdClassify returns both, unified in
175
+ // neither direction.
176
+ const { classifyCwd } = require('./cwdClassify.cjs');
177
+ const projectRoot = path.dirname(classifyCwd(absPath).innermostOpsRoot);
178
+ const { kind, reason } = classifyCwd(projectRoot);
179
+ if (kind === 'ephemeral' || kind === 'worktree') {
185
180
  const err = new Error(
186
181
  `refusing to write ${OPS_ROOT_DIR}/ state under an ephemeral project root `
187
182
  + `(tmpdir or linked git worktree): "${projectRoot}" — see lib/opsOwnership.cjs resolveProjectRoot`,
@@ -189,6 +184,17 @@ function assertOpsWrite(absPath, writer) {
189
184
  err.ephemeral = true;
190
185
  throw err;
191
186
  }
187
+ if (kind === 'unknown') {
188
+ // Fail closed on the unprovable case (worktree .git file whose admin
189
+ // back-reference is gone, garbled .git file): the exact shape behind the
190
+ // lost-Epics incidents. WRITES only — reads and dispatch stay open.
191
+ const err = new Error(
192
+ `refusing to write ${OPS_ROOT_DIR}/ state under "${projectRoot}": project identity `
193
+ + `cannot be proven (${reason}) — see lib/cwdClassify.cjs`,
194
+ );
195
+ err.unknownCwd = true;
196
+ throw err;
197
+ }
192
198
  }
193
199
  }
194
200
 
@@ -236,10 +242,12 @@ function resolveProjectRoot(cwd, { opsInternal = 'normalize' } = {}) {
236
242
  `resolveProjectRoot: cwd must be a project root, not a path inside ${OPS_ROOT_DIR}/, got "${cwd}"`,
237
243
  );
238
244
  }
239
- // Lazy: activeSessions → gitWorktree → (lazily) config.cjs → this module.
240
- const { projectRootOf } = require('../../../scripts/lib/activeSessions.cjs');
245
+ // Lazy: cwdClassify → schedulerPaths; ephemeralCwd → cwdClassify.
246
+ const { classifyCwd } = require('./cwdClassify.cjs');
241
247
  const { isEphemeralCwd } = require('./ephemeralCwd.cjs');
242
- const root = projectRootOf(cwd);
248
+ // `unknown` deliberately does NOT throw here: reads and dispatch must keep
249
+ // working; assertOpsWrite is the choke point that refuses the WRITE.
250
+ const root = classifyCwd(cwd).projectRoot;
243
251
  if (isEphemeralCwd(root)) {
244
252
  const err = new Error(
245
253
  `resolveProjectRoot: refusing ephemeral cwd (tmpdir or linked git worktree), got "${cwd}"`,
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+ // Seed-when-the-stamp-differs for the bundled PRD_AUTHORING.md guide.
3
+ // Pure fs + injected writer so it is testable without an Electron app.
4
+
5
+ const fs = require('fs');
6
+
7
+ const STAMP_RE = /^<!--\s*PRD_AUTHORING\.md\s+(v\d+)\s*-->/;
8
+
9
+ /** Version stamp from line 1 of `text`, or null when absent. */
10
+ function readStamp(text) {
11
+ const first = String(text).split(/\r?\n/, 1)[0];
12
+ const m = STAMP_RE.exec(first);
13
+ return m ? m[1] : null;
14
+ }
15
+
16
+ /** True when dest should be (re)written from src: missing/unstamped/differing stamp. */
17
+ function shouldSeed(srcText, destText) {
18
+ if (destText == null) return true;
19
+ const destStamp = readStamp(destText);
20
+ return destStamp === null || destStamp !== readStamp(srcText);
21
+ }
22
+
23
+ /**
24
+ * Overwrite `dest` with `src` when shouldSeed. `write(abs, text)` is the atomic
25
+ * writer (config.writeTextAtomic). Resolves true when it wrote, false otherwise.
26
+ */
27
+ async function seedAuthoringGuide({ src, dest, write }) {
28
+ if (!fs.existsSync(src)) return false;
29
+ const srcText = fs.readFileSync(src, 'utf8');
30
+ const destText = fs.existsSync(dest) ? fs.readFileSync(dest, 'utf8') : null;
31
+ if (!shouldSeed(srcText, destText)) return false;
32
+ await write(dest, srcText);
33
+ return true;
34
+ }
35
+
36
+ module.exports = { readStamp, shouldSeed, seedAuthoringGuide };
@@ -30,6 +30,7 @@ const { fixChainDepthOf, baseSlugOf } = require('./fixChainDepth.cjs');
30
30
  const { DEFAULT_PRD_AGENT_TYPE, assertAgentTypeWritable } = require('./prdAgentType.cjs');
31
31
  const { resolveDepSlug, findNearMatches } = require('./depSlugResolve.cjs');
32
32
  const { isFixPlanSlug } = require('./fixPlanSlug.cjs');
33
+ const { isIncomplete, resolveChainTerminals } = require('./prdDisposition.cjs');
33
34
 
34
35
  // A caller-supplied slug that already starts with its own `NN-` (e.g.
35
36
  // "254-perf-x") used to silently become the double-prefixed row
@@ -74,7 +75,7 @@ function deriveSlugFromTitle(title) {
74
75
  function buildPrdBody(input) {
75
76
  const {
76
77
  title, cwd, estimateMinutes, goal, acceptanceCriteria,
77
- implementationNotes, outOfScope, sourcePromptId, sourceTabId, tag, agentType, dependsOn, quietMachine,
78
+ implementationNotes, outOfScope, sourcePromptId, sourceTabId, tag, agentType, dependsOn, quietMachine, disposition,
78
79
  } = input;
79
80
 
80
81
  // No `parallelGroup` frontmatter key by convention (SKILL.md) — the NN-
@@ -108,6 +109,11 @@ function buildPrdBody(input) {
108
109
  fmLines.push(`agentType: ${agentType || DEFAULT_PRD_AGENT_TYPE}`);
109
110
  // Explicit ordering (PRD 832): replaces the retired shared-NN convention.
110
111
  if (dependsOn && dependsOn.length) fmLines.push(`dependsOn: [${dependsOn.join(', ')}]`);
112
+ // Wave-authoring decision (scheduler wave-disposition PRD) — only ever set
113
+ // when createPrd() actually had a disposition to record (see the call
114
+ // site above); a first-ever PRD in an Epic, or one with its own explicit
115
+ // dependsOn, has nothing to decide against and omits this key.
116
+ if (disposition) fmLines.push(`disposition: ${disposition}`);
111
117
  // Opt-in exclusive-lease flag (PRD 1107): serializes this job against
112
118
  // every other job machine-wide for its run, for a PRD whose acceptance
113
119
  // criteria are wall-clock/timing measurements that CPU contention from
@@ -237,6 +243,55 @@ async function createPrd(input, remote) {
237
243
  if (fallback) input = { ...input, sourcePromptId: fallback };
238
244
  }
239
245
 
246
+ // Wave-disposition decision point (scheduler wave-disposition PRD): only
247
+ // matters for a PRD that would become a ROOT of its own wave — one the
248
+ // caller didn't already give an explicit dependsOn (that already fixes
249
+ // its position in some chain) — joining an Epic whose sourcePromptId this
250
+ // PRD shares. See prdDisposition.cjs's header for the full contract.
251
+ if (input.sourcePromptId && (!input.dependsOn || input.dependsOn.length === 0)) {
252
+ let epicRows = [];
253
+ try {
254
+ const listing = await remote.listPrds({ cwd: input.cwd, fields: 'full', limit: Number.MAX_SAFE_INTEGER });
255
+ epicRows = (listing?.prds ?? []).filter((p) => p.sourcePromptId === input.sourcePromptId);
256
+ } catch (e) {
257
+ console.warn(`[prdCreate] disposition resolution skipped (listPrds failed): ${e?.message ?? e}`);
258
+ }
259
+ if (epicRows.some((p) => isIncomplete(p.status))) {
260
+ let disposition = input.disposition ?? null;
261
+ if (!disposition) {
262
+ // A headless PRD executor's own job has SM_SCHEDULER_JOB_SLUG set on
263
+ // its env (scheduler.cjs stamps every spawned job's child env with
264
+ // it) — no human is present to ask, so the conservative default
265
+ // ('append') applies and is logged as a default, never as a silent
266
+ // choice. Anything else (a live interactive Epic chat session, or a
267
+ // direct admin-route call) is refused instead of guessed — see this
268
+ // PRD's AC2.
269
+ const nonInteractive = Boolean(process.env.SM_SCHEDULER_JOB_SLUG);
270
+ if (!nonInteractive) {
271
+ return {
272
+ ok: false,
273
+ status: 400,
274
+ error: `Epic ${input.sourcePromptId} already has incomplete PRDs — pass disposition: "append" ` +
275
+ '(extend the existing chain behind its current tail) or "new-head" (an independent root, ' +
276
+ 'eligible to run in parallel) to record this wave\'s relationship to the existing plan.',
277
+ };
278
+ }
279
+ disposition = 'append';
280
+ console.warn(`[prdCreate] disposition defaulted to "append" for a non-interactive caller (epic ${input.sourcePromptId})`);
281
+ appendAuditEvent('prd_disposition_defaulted', { cwd: input.cwd, epicId: input.sourcePromptId, disposition });
282
+ }
283
+ if (disposition === 'append') {
284
+ // Only the Epic's still-incomplete rows count as "the active plan" to
285
+ // append behind — a completed, undepended-upon row would otherwise
286
+ // also read as a terminal, silently attaching this wave to already-
287
+ // finished work instead of purely the current chain's live tail(s).
288
+ const terminals = resolveChainTerminals(epicRows.filter((p) => isIncomplete(p.status)));
289
+ if (terminals.length) input = { ...input, dependsOn: terminals };
290
+ }
291
+ input = { ...input, disposition };
292
+ }
293
+ }
294
+
240
295
  if (input.slug) {
241
296
  const nnMatch = SLUG_HAS_NN_PREFIX_RE.exec(input.slug);
242
297
  if (nnMatch) {
@@ -0,0 +1,199 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * prdDisposition.cjs — the wave-authoring decision (scheduler wave-
5
+ * disposition PRD): when a new PRD wave joins an Epic that already has
6
+ * incomplete PRDs, does the wave APPEND behind the existing chain's tail, or
7
+ * start an independent NEW-HEAD root eligible to run in parallel? Before
8
+ * this module the choice didn't exist — every new root PRD silently landed
9
+ * as a parallel-eligible row, so waves interleaved with no recorded
10
+ * relationship and a human reading the backlog couldn't tell a plan from a
11
+ * pile.
12
+ *
13
+ * Two call sites:
14
+ * - prdCreate.cjs's createPrd() — AUTHORING TIME. Resolves 'append' into a
15
+ * concrete dependsOn via resolveChainTerminals() over the Epic's
16
+ * existing rows.
17
+ * - scheduler.cjs's `schedule:set-prd-disposition` IPC handler — CHANGING
18
+ * an already-written PRD's disposition from the Scheduler UI. Uses
19
+ * computeDispositionRewrite() to validate the rewrite is safe before
20
+ * handing the new dependsOn to remote.updatePrd (which itself refuses a
21
+ * non-pending/quarantined row — see scheduler.cjs's updatePrd).
22
+ *
23
+ * `rows` throughout is the same shape listPrdsInternal() already produces:
24
+ * { slug, status, dependsOn }. dependsOn entries are resolved against `rows`
25
+ * via depSlugResolve.cjs's resolveDepSlug — the SAME rule
26
+ * schedulerBatch.cjs's findBlockingDep and prdCreate.cjs's write-time FK
27
+ * check use, so a terminal/cycle computed here can never disagree with what
28
+ * the scheduler considers a row's real blockers at run time.
29
+ */
30
+
31
+ const { resolveDepSlug } = require('./depSlugResolve.cjs');
32
+
33
+ /** A row is "incomplete" (still part of the Epic's active plan) unless it
34
+ * has actually finished. Treats every other status — including a brand-new
35
+ * row with no queue entry yet (`status: null`) — as incomplete, since none
36
+ * of those represent shipped work a wave could safely ignore. */
37
+ function isIncomplete(status) {
38
+ return status !== 'completed';
39
+ }
40
+
41
+ /** Resolve each row's dependsOn entries to actual row slugs present in
42
+ * `rows`, via the shared resolution rule. A dep that doesn't resolve to
43
+ * anything in this row set (dangling, or lives outside this Epic) is
44
+ * dropped — it can't affect this Epic's own terminal computation. */
45
+ function resolvedDependents(rows) {
46
+ const slugs = rows.map((r) => r.slug);
47
+ const dependedUpon = new Set();
48
+ for (const r of rows) {
49
+ for (const dep of r.dependsOn ?? []) {
50
+ for (const resolved of resolveDepSlug(dep, slugs)) dependedUpon.add(resolved);
51
+ }
52
+ }
53
+ return dependedUpon;
54
+ }
55
+
56
+ /** Every row participating in a dependsOn cycle within `rows` (self-loops
57
+ * included) — mirrors backlogTree.ts's detectCycles (renderer-only, can't
58
+ * be required from this CJS main-process module; kept in sync by hand). */
59
+ function detectCycles(rows) {
60
+ const bySlug = new Map(rows.map((r) => [r.slug, r]));
61
+ const slugs = rows.map((r) => r.slug);
62
+ const color = new Map();
63
+ const cyclic = new Set();
64
+ const stack = [];
65
+
66
+ function visit(slug) {
67
+ color.set(slug, 1);
68
+ stack.push(slug);
69
+ const r = bySlug.get(slug);
70
+ const deps = new Set();
71
+ for (const dep of r?.dependsOn ?? []) {
72
+ for (const resolved of resolveDepSlug(dep, slugs)) deps.add(resolved);
73
+ }
74
+ for (const dep of deps) {
75
+ const c = color.get(dep);
76
+ if (c === 1) {
77
+ const idx = stack.indexOf(dep);
78
+ for (let i = idx; i < stack.length; i++) cyclic.add(stack[i]);
79
+ } else if (c === undefined) {
80
+ visit(dep);
81
+ }
82
+ }
83
+ stack.pop();
84
+ color.set(slug, 2);
85
+ }
86
+
87
+ for (const r of rows) {
88
+ if (!color.has(r.slug)) visit(r.slug);
89
+ }
90
+ return cyclic;
91
+ }
92
+
93
+ /**
94
+ * Terminal (leaf) slugs of the dependency forest formed by `rows` — the
95
+ * row(s) nothing else in `rows` depends on. This is what an 'append'
96
+ * disposition attaches a new wave's root behind: depending on every current
97
+ * terminal means the new wave runs only once everything already queued (in
98
+ * every existing head) has finished, the conservative reading of "append".
99
+ * A row participating in a cycle is excluded — never used as a rewrite
100
+ * target, since a cycle indicates the existing graph shouldn't be extended
101
+ * until it's fixed by hand.
102
+ */
103
+ function resolveChainTerminals(rows) {
104
+ if (!rows.length) return [];
105
+ const dependedUpon = resolvedDependents(rows);
106
+ const cyclic = detectCycles(rows);
107
+ return rows
108
+ .map((r) => r.slug)
109
+ .filter((slug) => !dependedUpon.has(slug) && !cyclic.has(slug));
110
+ }
111
+
112
+ /**
113
+ * Would setting `slug`'s dependsOn to `newDependsOn` create a cycle? Checks
114
+ * reachability from each (resolved) proposed dependency back to `slug`
115
+ * following the EXISTING graph in `rows` (never `slug`'s own current
116
+ * dependsOn, which is being replaced) — a direct self-reference is always a
117
+ * cycle, checked first without needing a graph walk.
118
+ */
119
+ function wouldCreateCycle(rows, slug, newDependsOn) {
120
+ const slugs = rows.map((r) => r.slug);
121
+ const bySlug = new Map(rows.map((r) => [r.slug, r]));
122
+ const resolvedTargets = new Set();
123
+ for (const dep of newDependsOn) {
124
+ for (const resolved of resolveDepSlug(dep, slugs)) resolvedTargets.add(resolved);
125
+ }
126
+ if (resolvedTargets.has(slug)) return true;
127
+
128
+ const visited = new Set();
129
+ function reachesSlug(from) {
130
+ if (from === slug) return true;
131
+ if (visited.has(from)) return false;
132
+ visited.add(from);
133
+ const r = bySlug.get(from);
134
+ for (const dep of r?.dependsOn ?? []) {
135
+ for (const resolved of resolveDepSlug(dep, slugs)) {
136
+ if (reachesSlug(resolved)) return true;
137
+ }
138
+ }
139
+ return false;
140
+ }
141
+ for (const target of resolvedTargets) {
142
+ if (reachesSlug(target)) return true;
143
+ }
144
+ return false;
145
+ }
146
+
147
+ /**
148
+ * Validates and computes the new dependsOn for a disposition change on an
149
+ * already-written PRD (the Scheduler UI's "promote to head" / "attach
150
+ * behind another chain" action). Pure — returns the new dependsOn value on
151
+ * success; the caller (scheduler.cjs's IPC handler) is responsible for
152
+ * actually persisting it via remote.updatePrd, which independently refuses
153
+ * a non-pending/quarantined row (defense in depth, not duplicated here).
154
+ *
155
+ * Refuses (ok: false) when:
156
+ * - `slug` isn't a known row.
157
+ * - the row itself is 'running' or 'completed' — never touch live or
158
+ * shipped work.
159
+ * - any of the row's CURRENT dependsOn entries already resolved
160
+ * ('completed') — the row may already be scheduler-eligible, and
161
+ * rewriting its ordering out from under a resolved blocker risks
162
+ * resurrecting/racing already-finished work (see this module's header).
163
+ * - the proposed dependsOn would create a cycle.
164
+ */
165
+ function computeDispositionRewrite({ slug, disposition, dependsOn, rows }) {
166
+ const row = rows.find((r) => r.slug === slug);
167
+ if (!row) return { ok: false, error: `PRD not found: ${slug}` };
168
+ if (row.status === 'running' || row.status === 'completed') {
169
+ return { ok: false, error: `cannot change disposition of a "${row.status}" PRD — it is no longer part of the open plan` };
170
+ }
171
+
172
+ const slugs = rows.map((r) => r.slug);
173
+ for (const dep of row.dependsOn ?? []) {
174
+ for (const resolved of resolveDepSlug(dep, slugs)) {
175
+ const depRow = rows.find((r) => r.slug === resolved);
176
+ if (depRow?.status === 'completed') {
177
+ return {
178
+ ok: false,
179
+ error: `refusing to rewrite dependsOn: blocker "${resolved}" has already completed — this PRD may ` +
180
+ 'already be eligible to run; changing its ordering now risks resurrecting finished work',
181
+ };
182
+ }
183
+ }
184
+ }
185
+
186
+ const newDependsOn = disposition === 'new-head' ? [] : Array.from(new Set(dependsOn ?? []));
187
+ if (newDependsOn.length && wouldCreateCycle(rows, slug, newDependsOn)) {
188
+ return { ok: false, error: `dependsOn ${JSON.stringify(newDependsOn)} would create a dependency cycle` };
189
+ }
190
+
191
+ return { ok: true, dependsOn: newDependsOn };
192
+ }
193
+
194
+ module.exports = {
195
+ isIncomplete,
196
+ resolveChainTerminals,
197
+ wouldCreateCycle,
198
+ computeDispositionRewrite,
199
+ };
@@ -77,8 +77,8 @@ function splitFrontmatter(raw) {
77
77
  * never emitted, which is how `scheduler_update_prd` clears a dependency.
78
78
  */
79
79
 
80
- const RECOGNIZED_KEYS = new Set(['title', 'cwd', 'estimateMinutes', 'parallelGroup', 'sourcePromptId', 'sourceTabId', 'tag', 'agentType', 'createdVia', 'issuedAt', 'dependsOn', 'quietMachine']);
81
- const EMIT_ORDER = ['title', 'cwd', 'estimateMinutes', 'parallelGroup', 'sourcePromptId', 'sourceTabId', 'tag', 'agentType', 'createdVia', 'issuedAt', 'dependsOn', 'quietMachine'];
80
+ const RECOGNIZED_KEYS = new Set(['title', 'cwd', 'estimateMinutes', 'parallelGroup', 'sourcePromptId', 'sourceTabId', 'tag', 'agentType', 'createdVia', 'issuedAt', 'dependsOn', 'quietMachine', 'disposition']);
81
+ const EMIT_ORDER = ['title', 'cwd', 'estimateMinutes', 'parallelGroup', 'sourcePromptId', 'sourceTabId', 'tag', 'agentType', 'createdVia', 'issuedAt', 'dependsOn', 'quietMachine', 'disposition'];
82
82
  const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
83
83
 
84
84
  function indentOf(line) {
@@ -179,6 +179,12 @@ function applyKey(fm, key, after) {
179
179
  // a no-op line for the overwhelming majority of PRDs that omit it.
180
180
  if (v === true) fm.quietMachine = true;
181
181
  return;
182
+ case 'disposition':
183
+ // Wave-authoring decision ('append'/'new-head') — see
184
+ // src/renderer/lib/prdFrontmatter.ts's mirror of this field for the
185
+ // full rationale. Only these two values are recognized.
186
+ if (v === 'append' || v === 'new-head') fm.disposition = v;
187
+ return;
182
188
  }
183
189
  }
184
190