claude-code-session-manager 0.87.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 (290) hide show
  1. package/README.md +26 -53
  2. package/dist/assets/{AgentLibrary-DyLWzZDf.js → AgentLibrary-BZ6IY2g1.js} +1 -1
  3. package/dist/assets/{DataModel--mISIJ6h.js → DataModel-dAoGAODX.js} +1 -1
  4. package/dist/assets/{History-C2ahUXTg.js → History-CF157HyX.js} +1 -1
  5. package/dist/assets/{Hooks-BiC6oyR2.js → Hooks-CCPPipBk.js} +1 -1
  6. package/dist/assets/{HostBilko-BPleEOld.js → HostBilko-Dlmz2m06.js} +1 -1
  7. package/dist/assets/{Library-Dc8Qst1R.js → Library-BaXcboWX.js} +1 -1
  8. package/dist/assets/{ListDetail-DIXh-OLX.js → ListDetail-CoUCzG5S.js} +1 -1
  9. package/dist/assets/{MarkdownEditor-C90bkLXK.js → MarkdownEditor-DTg3JlOT.js} +1 -1
  10. package/dist/assets/{McpServers-DqcbLOLZ.js → McpServers-DdjY1sA3.js} +1 -1
  11. package/dist/assets/{Memory-CW62MXlh.js → Memory-BJ3Jlw0C.js} +1 -1
  12. package/dist/assets/{Panel-Bw1FhRuF.js → Panel-ygRSgc41.js} +1 -1
  13. package/dist/assets/{Permissions-BcUC-5y8.js → Permissions-m0KAnccF.js} +1 -1
  14. package/dist/assets/{Plugins-BnKx9flD.js → Plugins-CJRl6B3Q.js} +2 -2
  15. package/dist/assets/{ProvenanceBadge-Bw5vNVPT.js → ProvenanceBadge-w8cnlVvW.js} +1 -1
  16. package/dist/assets/{SaveBar-CWr0O_w-.js → SaveBar-BpyPcUIk.js} +1 -1
  17. package/dist/assets/{Scheduler-DYdLuUqq.js → Scheduler-D2ppxSfy.js} +7 -7
  18. package/dist/assets/{ScopeSwitcher-CrBLbg8s.js → ScopeSwitcher-EyuIwt-j.js} +1 -1
  19. package/dist/assets/{Settings-DluB-vN1.js → Settings-BHSGGFEc.js} +1 -1
  20. package/dist/assets/{SkillReferenceGraph-CHLSseay.js → SkillReferenceGraph-BNaZ2JCF.js} +1 -1
  21. package/dist/assets/{Skills-gNdo_HNK.js → Skills-Dl3q75QV.js} +1 -1
  22. package/dist/assets/{SystemPrompt-Cru05-Ia.js → SystemPrompt-Bg6F-Cyp.js} +1 -1
  23. package/dist/assets/{TagLibrary-DNHY0xou.js → TagLibrary-BSutflCy.js} +1 -1
  24. package/dist/assets/{TiptapBody-I4lmbCgP.js → TiptapBody-CXih4xrc.js} +1 -1
  25. package/dist/assets/{Toggle-bWMHjmRh.js → Toggle-2qtUHhA9.js} +1 -1
  26. package/dist/assets/{index-fc_JjdxL.js → index-B3emy2oI.js} +356 -356
  27. package/dist/assets/{index-DV3PorRY.css → index-BHTX4OTc.css} +1 -1
  28. package/dist/assets/{settingsSchema-BfhtZnGD.js → settingsSchema-CdzxaqwM.js} +1 -1
  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 +10 -13
  40. package/scripts/README.md +59 -0
  41. package/scripts/audit-ops-hygiene.cjs +350 -0
  42. package/scripts/hooks/guard-destructive-git.cjs +10 -34
  43. package/scripts/hooks/guard-inline-implementation.cjs +14 -8
  44. package/scripts/hooks/guard-prd-writes.cjs +7 -36
  45. package/scripts/hooks/guard-self-schedule.cjs +175 -0
  46. package/scripts/ops-sweep.cjs +355 -0
  47. package/scripts/scheduler-mcp-server.cjs +28 -71
  48. package/src/main/__tests__/bilkoHost-integration.test.cjs +3 -3
  49. package/src/main/__tests__/chat-cancel-terminal.test.cjs +6 -9
  50. package/src/main/__tests__/chat-exit-close-race.test.cjs +3 -3
  51. package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +4 -5
  52. package/src/main/__tests__/chat-queue.test.cjs +2 -2
  53. package/src/main/__tests__/chat-stop-signal.test.cjs +2 -2
  54. package/src/main/__tests__/dep-orphan-archive-health.test.cjs +77 -0
  55. package/src/main/__tests__/dod-batchkey.test.cjs +2 -2
  56. package/src/main/__tests__/dod-drain-hook.test.cjs +2 -2
  57. package/src/main/__tests__/dod-report.test.cjs +2 -2
  58. package/src/main/__tests__/dod-reverify.test.cjs +2 -2
  59. package/src/main/__tests__/epicMint.test.cjs +2 -2
  60. package/src/main/__tests__/exchanges.test.cjs +2 -2
  61. package/src/main/__tests__/extractJson.test.cjs +2 -2
  62. package/src/main/__tests__/files-reject-credentials.test.cjs +1 -1
  63. package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +556 -0
  64. package/src/main/__tests__/health-build-freshness.test.cjs +39 -0
  65. package/src/main/__tests__/health-delegation-chain.test.cjs +15 -1
  66. package/src/main/__tests__/health-queue-dispatch.test.cjs +58 -7
  67. package/src/main/__tests__/health-tick-liveness.test.cjs +11 -3
  68. package/src/main/__tests__/health-usage-poller.test.cjs +70 -23
  69. package/src/main/__tests__/historyRollup.test.cjs +2 -2
  70. package/src/main/__tests__/kg-augment.test.cjs +2 -2
  71. package/src/main/__tests__/mcpStatus.test.cjs +2 -2
  72. package/src/main/__tests__/memoryAggregate.test.cjs +1 -1
  73. package/src/main/__tests__/memoryStale.test.cjs +1 -1
  74. package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +25 -1
  75. package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +33 -3
  76. package/src/main/__tests__/prd-group-allocator.test.cjs +2 -2
  77. package/src/main/__tests__/prdAdminRouteParity.test.cjs +2 -0
  78. package/src/main/__tests__/prdAdminRoutes.test.cjs +14 -2
  79. package/src/main/__tests__/prdAuthoringSeed.test.cjs +39 -0
  80. package/src/main/__tests__/prdLocationsArchived.test.cjs +20 -13
  81. package/src/main/__tests__/proc-role-env.test.cjs +125 -0
  82. package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +304 -0
  83. package/src/main/__tests__/procname-sm-processes.test.cjs +127 -0
  84. package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +81 -401
  85. package/src/main/__tests__/projectPages.test.cjs +63 -149
  86. package/src/main/__tests__/queue-health-verdict.test.cjs +9 -9
  87. package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +117 -20
  88. package/src/main/__tests__/queueHistory.test.cjs +2 -2
  89. package/src/main/__tests__/rateLimitPollerStreak.test.cjs +38 -3
  90. package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +181 -0
  91. package/src/main/__tests__/runVerify.test.cjs +5 -5
  92. package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +3 -3
  93. package/src/main/__tests__/scheduleJobTransitions.test.cjs +2 -2
  94. package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +143 -0
  95. package/src/main/__tests__/scheduler-autofix-select.test.cjs +2 -2
  96. package/src/main/__tests__/scheduler-autopromote.test.cjs +2 -2
  97. package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +3 -5
  98. package/src/main/__tests__/scheduler-boot-orphans.test.cjs +78 -97
  99. package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +161 -0
  100. package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +58 -0
  101. package/src/main/__tests__/scheduler-epic-digest.test.cjs +3 -5
  102. package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +2 -2
  103. package/src/main/__tests__/scheduler-gate-shadow.test.cjs +119 -0
  104. package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +46 -0
  105. package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +80 -0
  106. package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +25 -18
  107. package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +4 -4
  108. package/src/main/__tests__/scheduler-launch-failure.test.cjs +3 -5
  109. package/src/main/__tests__/scheduler-looks-done.test.cjs +26 -7
  110. package/src/main/__tests__/scheduler-manual-pause.test.cjs +118 -0
  111. package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +26 -3
  112. package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +17 -2
  113. package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +3 -5
  114. package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +41 -6
  115. package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +62 -6
  116. package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +3 -5
  117. package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +23 -4
  118. package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +100 -0
  119. package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +3 -3
  120. package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +4 -4
  121. package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +110 -0
  122. package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +81 -1
  123. package/src/main/__tests__/scheduler-starve-escalation.test.cjs +4 -4
  124. package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +245 -0
  125. package/src/main/__tests__/scheduler-supervisor-record.test.cjs +81 -0
  126. package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +2 -2
  127. package/src/main/__tests__/scheduler-tick-wedge.test.cjs +172 -0
  128. package/src/main/__tests__/scheduler-transient-failure.test.cjs +2 -2
  129. package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +37 -11
  130. package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +3 -5
  131. package/src/main/__tests__/usageSingleFlight.test.cjs +157 -0
  132. package/src/main/__tests__/workTypeLibrary.test.cjs +1 -1
  133. package/src/main/bilkoHost.cjs +16 -7
  134. package/src/main/build-info.json +8 -0
  135. package/src/main/chatRunner.cjs +4 -2
  136. package/src/main/config.cjs +2 -3
  137. package/src/main/docEdit.cjs +4 -2
  138. package/src/main/health.cjs +267 -51
  139. package/src/main/heapSnapshot.cjs +2 -2
  140. package/src/main/historyAggregator.cjs +1 -1
  141. package/src/main/index.cjs +61 -10
  142. package/src/main/ipcSchemas.cjs +6 -17
  143. package/src/main/lib/__tests__/auditLog.test.cjs +38 -0
  144. package/src/main/lib/__tests__/buildIdentity.test.cjs +121 -0
  145. package/src/main/lib/__tests__/cwdClassify.test.cjs +111 -0
  146. package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +95 -0
  147. package/src/main/lib/__tests__/delegationReadiness.test.cjs +1 -1
  148. package/src/main/lib/__tests__/dispatchLoop.test.cjs +63 -0
  149. package/src/main/lib/__tests__/gateFixtures.json +20 -0
  150. package/src/main/lib/__tests__/gitWorktree.test.cjs +8 -1
  151. package/src/main/lib/__tests__/instanceLock.test.cjs +93 -7
  152. package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +78 -0
  153. package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +11 -0
  154. package/src/main/lib/__tests__/localAdminHttp.test.cjs +1 -1
  155. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +6 -1
  156. package/src/main/lib/__tests__/procIdentity.test.cjs +119 -0
  157. package/src/main/lib/__tests__/procName.test.cjs +92 -0
  158. package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +67 -0
  159. package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +6 -7
  160. package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +37 -204
  161. package/src/main/lib/__tests__/schedulerPaths.test.cjs +226 -0
  162. package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +94 -0
  163. package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +56 -0
  164. package/src/main/lib/__tests__/sessionSlots.test.cjs +45 -0
  165. package/src/main/lib/__tests__/telemetryBacklog.test.cjs +1 -1
  166. package/src/main/lib/__tests__/upgradeDrain.test.cjs +130 -0
  167. package/src/main/lib/__tests__/usageCircuit.test.cjs +61 -0
  168. package/src/main/lib/__tests__/watchdog-helpers.test.cjs +63 -0
  169. package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +73 -0
  170. package/src/main/lib/activeIndexRebuild.cjs +1 -3
  171. package/src/main/lib/activeSessions.cjs +20 -88
  172. package/src/main/lib/adoptedRunSupervisor.cjs +136 -0
  173. package/src/main/lib/agentModelResolve.cjs +33 -1
  174. package/src/main/lib/agentPersonaSchema.cjs +2 -2
  175. package/src/main/lib/auditLog.cjs +30 -5
  176. package/src/main/lib/buildIdentity.cjs +113 -0
  177. package/src/main/lib/classifyPromptTicket.cjs +3 -2
  178. package/src/main/lib/claudeBin.cjs +37 -2
  179. package/src/main/lib/cleanEnv.cjs +27 -1
  180. package/src/main/lib/credentials.cjs +4 -2
  181. package/src/main/lib/cwdClassify.cjs +185 -0
  182. package/src/main/lib/definitionOfDone.cjs +296 -52
  183. package/src/main/lib/dispatchLoop.cjs +40 -0
  184. package/src/main/lib/effectiveModelInfo.cjs +9 -10
  185. package/src/main/lib/ephemeralCwd.cjs +7 -28
  186. package/src/main/lib/gitWorktree.cjs +95 -8
  187. package/src/main/lib/guardShims.cjs +3 -3
  188. package/src/main/lib/historyRollup.cjs +6 -7
  189. package/src/main/lib/instanceLock.cjs +32 -5
  190. package/src/main/lib/jobSupervisorRecord.cjs +147 -0
  191. package/src/main/lib/jobWorktreeBootLive.cjs +9 -5
  192. package/src/main/lib/localAdminHttp.cjs +9 -27
  193. package/src/main/lib/mcpToolCatalog.cjs +29 -77
  194. package/src/main/lib/opsOwnership.cjs +27 -19
  195. package/src/main/lib/prdAuthoringSeed.cjs +36 -0
  196. package/src/main/lib/prdLocations.cjs +48 -1
  197. package/src/main/lib/procIdentity.cjs +126 -0
  198. package/src/main/lib/procName.cjs +98 -0
  199. package/src/main/lib/projectHomeAdminRoutes.cjs +56 -327
  200. package/src/main/lib/queueHistory.cjs +8 -7
  201. package/src/main/lib/queueStore.cjs +57 -37
  202. package/src/main/lib/quietMachineLease.cjs +19 -2
  203. package/src/main/lib/reservationExpiry.cjs +30 -0
  204. package/src/main/lib/runClaudeP.cjs +4 -2
  205. package/src/main/lib/runLogRetention.cjs +3 -2
  206. package/src/main/lib/scheduleJobSchema.cjs +2 -2
  207. package/src/main/lib/scheduleJobTransitions.cjs +29 -2
  208. package/src/main/lib/schedulerBatch.cjs +27 -2
  209. package/src/main/lib/schedulerPaths.cjs +175 -0
  210. package/src/main/lib/schedulerRuntimeState.cjs +59 -0
  211. package/src/main/lib/sessionSlots.cjs +47 -9
  212. package/src/main/lib/smProcNames.cjs +51 -0
  213. package/src/main/lib/upgradeDrain.cjs +188 -0
  214. package/src/main/lib/usageCircuit.cjs +53 -6
  215. package/src/main/lib/watchdogHelpers.cjs +70 -37
  216. package/src/main/lib/withTimeout.cjs +33 -0
  217. package/src/main/mcpStatus.cjs +4 -2
  218. package/src/main/pluginInstall.cjs +6 -2
  219. package/src/main/projectPages.cjs +41 -145
  220. package/src/main/pty.cjs +8 -1
  221. package/src/main/queueOps.cjs +10 -10
  222. package/src/main/runVerify.cjs +69 -3
  223. package/src/main/scheduler.cjs +1598 -381
  224. package/src/main/seedAgentPersonas.cjs +1 -1
  225. package/src/main/seedDevPlugin.cjs +1 -1
  226. package/src/main/seedSchedulerMcp.cjs +7 -6
  227. package/src/main/seedStatus.cjs +1 -1
  228. package/src/main/supervisor.cjs +5 -3
  229. package/src/main/usage.cjs +126 -62
  230. package/src/preload/api.d.ts +18 -64
  231. package/src/preload/index.cjs +2 -4
  232. package/src/seed/agents/project-home-builder.md +31 -48
  233. package/screenshots/.gitkeep +0 -0
  234. package/screenshots/README-screenshots.md +0 -13
  235. package/src/main/lib/projectPageSummarySchema.cjs +0 -181
  236. package/src/main/teams.cjs +0 -95
  237. package/src/main/templates/project-pages-catalog.json +0 -741
  238. package/src/main/templates/project-pages-default-home.html +0 -123
  239. package/src/main/templates/project-pages-pipeline.md +0 -417
  240. package/src/seed/prompts/code-review/ac-coverage-check.md +0 -8
  241. package/src/seed/prompts/code-review/correctness-only.md +0 -8
  242. package/src/seed/prompts/code-review/full-spectrum-high.md +0 -8
  243. package/src/seed/prompts/code-review/hallucination-check.md +0 -8
  244. package/src/seed/prompts/code-review/public-api-compat.md +0 -8
  245. package/src/seed/prompts/code-review/readability-naming.md +0 -8
  246. package/src/seed/prompts/debugging/bug-as-failing-test.md +0 -8
  247. package/src/seed/prompts/debugging/git-bisect-regression.md +0 -8
  248. package/src/seed/prompts/debugging/instrument-intermittent-bug.md +0 -8
  249. package/src/seed/prompts/debugging/localize-pipeline-failure.md +0 -8
  250. package/src/seed/prompts/debugging/reproduce-then-diagnose.md +0 -8
  251. package/src/seed/prompts/documentation/adr-from-change.md +0 -8
  252. package/src/seed/prompts/documentation/module-readme.md +0 -8
  253. package/src/seed/prompts/documentation/onboarding-plan.md +0 -8
  254. package/src/seed/prompts/documentation/refresh-claude-md.md +0 -8
  255. package/src/seed/prompts/documentation/tsdoc-public-exports.md +0 -8
  256. package/src/seed/prompts/git-pr/conventional-commit.md +0 -8
  257. package/src/seed/prompts/git-pr/draft-pr-title-body.md +0 -8
  258. package/src/seed/prompts/git-pr/pre-commit-safety-sweep.md +0 -8
  259. package/src/seed/prompts/git-pr/release-notes-block.md +0 -8
  260. package/src/seed/prompts/git-pr/split-large-pr.md +0 -8
  261. package/src/seed/prompts/performance/bundle-startup-audit.md +0 -8
  262. package/src/seed/prompts/performance/complexity-audit.md +0 -8
  263. package/src/seed/prompts/performance/cpu-profile-hot-path.md +0 -8
  264. package/src/seed/prompts/performance/db-query-plan-review.md +0 -8
  265. package/src/seed/prompts/performance/memory-leak-hunt.md +0 -8
  266. package/src/seed/prompts/qa/api-contract-tests.md +0 -8
  267. package/src/seed/prompts/qa/e2e-critical-path.md +0 -8
  268. package/src/seed/prompts/qa/failing-test-for-bug.md +0 -8
  269. package/src/seed/prompts/qa/find-missing-test-coverage.md +0 -8
  270. package/src/seed/prompts/qa/stabilize-flaky-test.md +0 -8
  271. package/src/seed/prompts/qa/tdd-red-first.md +0 -8
  272. package/src/seed/prompts/qa/visual-regression-review.md +0 -8
  273. package/src/seed/prompts/qa/wcag-axe-scan.md +0 -8
  274. package/src/seed/prompts/refactoring/dead-code-sweep.md +0 -8
  275. package/src/seed/prompts/refactoring/extract-duplicated-pattern.md +0 -8
  276. package/src/seed/prompts/refactoring/modernize-legacy-file.md +0 -8
  277. package/src/seed/prompts/refactoring/reduce-cyclomatic-complexity.md +0 -8
  278. package/src/seed/prompts/refactoring/tighten-module-boundaries.md +0 -8
  279. package/src/seed/prompts/security/authz-audit.md +0 -8
  280. package/src/seed/prompts/security/crypto-correctness.md +0 -8
  281. package/src/seed/prompts/security/cwe-top-25-hunt.md +0 -8
  282. package/src/seed/prompts/security/dependency-audit.md +0 -8
  283. package/src/seed/prompts/security/ipc-boundary-hardening.md +0 -8
  284. package/src/seed/prompts/security/owasp-top-10-staged-diff.md +0 -8
  285. package/src/seed/prompts/security/secret-credential-scan.md +0 -8
  286. package/web/README.md +0 -41
  287. package/web/project-pages/logic/dist/logic.cjs +0 -4709
  288. package/web/project-pages/render.cjs +0 -70
  289. package/web/project-pages/renderer/dist/renderer.cjs +0 -18900
  290. package/web/project-pages/validate-summary.cjs +0 -62
@@ -0,0 +1,350 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * audit-ops-hygiene.cjs — one-off (re-runnable) investigation for
4
+ * session-manager-operations/architecture/ops-maintenance-protocol.md
5
+ * Patterns C and D. Read-only: never moves, archives, or deletes anything.
6
+ *
7
+ * Pattern C — legacy flat `scheduler/prds/` layout: reports the current
8
+ * top-level file count vs `scheduler/prds-archived/`, and whether
9
+ * `scheduler/state/queue.json` still references any top-level (non
10
+ * epic-scoped) prdPath, to distinguish "stuck legacy debt" from
11
+ * "legitimately in-flight, already draining via normal completion."
12
+ *
13
+ * Pattern D — orphaned top-level `prompt-sessions/*.json` files (no
14
+ * matching `scheduler/epics/<id>/` dir): for each, inspects its own event
15
+ * chain for `prd_created` events, then — since a dispatched PRD auto-mints
16
+ * its OWN epic dir via epicMint.cjs, with a slug distinct from the
17
+ * originating prompt-session id — searches every PRD `.md` under
18
+ * `scheduler/` for a `sourcePromptId:` frontmatter match before concluding
19
+ * anything is actually lost.
20
+ *
21
+ * Pattern E — PRDs authored outside the sanctioned `scheduler_create_prd` MCP
22
+ * tool (the /develop skill's manual-write fallback is meant to be a rare,
23
+ * flagged last resort — see CLAUDE.md's "PRD authoring is API-only"). Every
24
+ * API-created PRD gets a `prd_create` record in the machine-wide audit log
25
+ * (`~/.claude/session-manager/audit-log.jsonl`, `src/main/lib/auditLog.cjs`)
26
+ * keyed by cwd+slug. This check is deliberately narrow: it only inspects PRD
27
+ * `.md` files `git status` reports as UNTRACKED (never committed yet) — a
28
+ * PRD's file mtime is USELESS as a "recently authored" signal because these
29
+ * files are committed to the target repo, so any `git clone`/`checkout`/
30
+ * `git clean` resets every tracked PRD's mtime to "now" regardless of when it
31
+ * was actually authored (a first draft of this check used mtime and would
32
+ * have false-positived on nearly every already-committed PRD after a fresh
33
+ * checkout). An untracked file, by contrast, really was just created in this
34
+ * working tree. A cwd that isn't a git repo, or has no untracked PRDs, is
35
+ * reported clean — this check simply doesn't apply there. Reported as a
36
+ * hygiene finding, never blocked, exactly like Patterns C/D.
37
+ *
38
+ * Usage: node scripts/audit-ops-hygiene.cjs [cwd] (defaults to cwd)
39
+ */
40
+ 'use strict';
41
+
42
+ const fs = require('node:fs');
43
+ const path = require('node:path');
44
+ const { execFileSync } = require('node:child_process');
45
+
46
+ const { auditLogPath } = require('../src/main/lib/schedulerPaths.cjs');
47
+ const projectCwd = process.argv[2] || process.cwd();
48
+ const OPS_ROOT = path.join(projectCwd, 'session-manager-operations');
49
+ const SESSIONS_DIR = path.join(OPS_ROOT, 'prompt-sessions');
50
+ const SCHEDULER_DIR = path.join(OPS_ROOT, 'scheduler');
51
+ const EPICS_DIR = path.join(SCHEDULER_DIR, 'epics');
52
+ const FLAT_PRDS_DIR = path.join(SCHEDULER_DIR, 'prds');
53
+ const ARCHIVED_PRDS_DIR = path.join(SCHEDULER_DIR, 'prds-archived');
54
+ const QUEUE_PATH = path.join(SCHEDULER_DIR, 'state', 'queue.json');
55
+ // Override hook for tests only — production always uses the real path.
56
+ function resolveAuditLogPath() {
57
+ return process.env.SM_AUDIT_LOG_PATH_OVERRIDE || auditLogPath();
58
+ }
59
+
60
+ function readJson(p, fallback) {
61
+ try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return fallback; }
62
+ }
63
+
64
+ function listDir(p) {
65
+ try { return fs.readdirSync(p, { withFileTypes: true }); } catch { return []; }
66
+ }
67
+
68
+ function auditPatternC() {
69
+ const flatMdFiles = listDir(FLAT_PRDS_DIR).filter((e) => e.isFile() && e.name.endsWith('.md')).map((e) => e.name);
70
+ const archivedCount = listDir(ARCHIVED_PRDS_DIR).filter((e) => e.isFile() && e.name.endsWith('.md')).length;
71
+ const queue = readJson(QUEUE_PATH, { jobs: [] });
72
+ const jobs = Array.isArray(queue.jobs) ? queue.jobs : [];
73
+ const flatQueueRefs = jobs.filter((j) => typeof j.prdPath === 'string' && j.prdPath.includes(`${path.sep}prds${path.sep}`) && !j.prdPath.includes(`${path.sep}epics${path.sep}`));
74
+
75
+ return {
76
+ flatTopLevelMdCount: flatMdFiles.length,
77
+ flatTopLevelMdFiles: flatMdFiles,
78
+ archivedCount,
79
+ queueJobsTotal: jobs.length,
80
+ queueJobsReferencingFlatDir: flatQueueRefs.map((j) => ({ slug: j.slug, status: j.status, prdPath: j.prdPath })),
81
+ verdict: flatMdFiles.length === 0
82
+ ? 'RESOLVED: flat prds/ is currently empty of .md files — consolidation/normal completion has fully drained it.'
83
+ : (flatQueueRefs.length > 0
84
+ ? 'IN-FLIGHT: remaining flat files are referenced by live queue jobs — legitimate in-flight work, not stuck debt.'
85
+ : 'INVESTIGATE: remaining flat files have no live queue reference — check history for stuck/abandoned status before treating as debt.'),
86
+ };
87
+ }
88
+
89
+ const SOURCE_PROMPT_RE = /^sourcePromptId:\s*(.+?)\s*$/m;
90
+
91
+ function findPrdFilesForEpic(epicId) {
92
+ const hits = [];
93
+ function walk(dir) {
94
+ for (const ent of listDir(dir)) {
95
+ const full = path.join(dir, ent.name);
96
+ if (ent.isDirectory()) { walk(full); continue; }
97
+ if (!ent.name.endsWith('.md')) continue;
98
+ let head;
99
+ try { head = fs.readFileSync(full, 'utf8').slice(0, 2000); } catch { continue; }
100
+ const m = SOURCE_PROMPT_RE.exec(head);
101
+ if (m && m[1] === epicId) hits.push(full);
102
+ }
103
+ }
104
+ walk(SCHEDULER_DIR);
105
+ return hits;
106
+ }
107
+
108
+ function auditPatternD() {
109
+ const toplevel = listDir(SESSIONS_DIR)
110
+ .filter((e) => e.isFile() && e.name.endsWith('.json') && e.name !== 'active-index.json')
111
+ .map((e) => e.name.slice(0, -'.json'.length))
112
+ .sort();
113
+ const epicDirs = new Set(listDir(EPICS_DIR).filter((e) => e.isDirectory()).map((e) => e.name));
114
+
115
+ const neverStarted = [];
116
+ const accountedForElsewhere = [];
117
+ const dataLoss = [];
118
+ const unreadable = [];
119
+
120
+ for (const epicId of toplevel) {
121
+ if (epicDirs.has(epicId)) continue; // has a matching epics/ dir — not orphaned
122
+
123
+ const data = readJson(path.join(SESSIONS_DIR, `${epicId}.json`), null);
124
+ if (!data) { unreadable.push(epicId); continue; }
125
+
126
+ const events = Array.isArray(data.events) ? data.events : [];
127
+ const prdEvents = events.filter((e) => e && e.kind === 'prd_created');
128
+ const session = data.session || {};
129
+ const record = {
130
+ id: epicId,
131
+ status: session.status,
132
+ goalText: (session.goalText || '').slice(0, 80),
133
+ prdCreatedCount: prdEvents.length,
134
+ };
135
+
136
+ if (prdEvents.length === 0) { neverStarted.push(record); continue; }
137
+
138
+ const found = findPrdFilesForEpic(epicId);
139
+ if (found.length > 0) {
140
+ record.resolvedEpicDirs = [...new Set(found
141
+ .filter((f) => f.startsWith(EPICS_DIR + path.sep))
142
+ .map((f) => path.relative(EPICS_DIR, f).split(path.sep)[0]))];
143
+ accountedForElsewhere.push(record);
144
+ } else {
145
+ dataLoss.push(record);
146
+ }
147
+ }
148
+
149
+ return {
150
+ toplevelCount: toplevel.length,
151
+ epicDirsCount: epicDirs.size,
152
+ orphanedCount: toplevel.length - [...epicDirs].filter((d) => toplevel.includes(d)).length,
153
+ neverStarted,
154
+ accountedForElsewhere,
155
+ dataLoss,
156
+ unreadable,
157
+ };
158
+ }
159
+
160
+ /** Every `prd_create` audit event's `${cwd}::${slug}` key. */
161
+ function readPrdCreateAuditKeys() {
162
+ const keys = new Set();
163
+ let lines;
164
+ try { lines = fs.readFileSync(resolveAuditLogPath(), 'utf8').split('\n'); } catch { return keys; }
165
+ for (const line of lines) {
166
+ if (!line.trim()) continue;
167
+ let rec;
168
+ try { rec = JSON.parse(line); } catch { continue; }
169
+ if (rec?.kind === 'prd_create' && rec?.cwd && rec?.slug) {
170
+ keys.add(`${rec.cwd}::${rec.slug}`);
171
+ }
172
+ }
173
+ return keys;
174
+ }
175
+
176
+ /**
177
+ * PRD `.md` files `git status --porcelain` reports as untracked (`??`),
178
+ * scoped to `session-manager-operations/scheduler/**\/prds/`. Returns null
179
+ * when `projectCwd` isn't a git repo (or `git` isn't available) — the
180
+ * caller then reports "not applicable" rather than a false CLEAN, since an
181
+ * already-committed bypass wouldn't show up here at all.
182
+ */
183
+ function listUntrackedPrdFiles() {
184
+ let out;
185
+ try {
186
+ out = execFileSync('git', ['status', '--porcelain', '--untracked-files=all', '--', 'session-manager-operations/scheduler'], {
187
+ cwd: projectCwd,
188
+ encoding: 'utf8',
189
+ stdio: ['ignore', 'pipe', 'ignore'],
190
+ });
191
+ } catch {
192
+ return null;
193
+ }
194
+ const hits = [];
195
+ for (const line of out.split('\n')) {
196
+ if (!line.startsWith('?? ')) continue;
197
+ const rel = line.slice(3).trim();
198
+ if (!rel.endsWith('.md')) continue;
199
+ if (path.basename(path.dirname(rel)) !== 'prds') continue; // excludes prds-archived/
200
+ hits.push(path.join(projectCwd, rel));
201
+ }
202
+ return hits;
203
+ }
204
+
205
+ function auditPatternE() {
206
+ const untracked = listUntrackedPrdFiles();
207
+ if (untracked === null) {
208
+ return {
209
+ applicable: false,
210
+ checkedCount: 0,
211
+ unattributedCount: 0,
212
+ unattributed: [],
213
+ verdict: 'NOT APPLICABLE: target cwd is not a git repo (or git is unavailable) — cannot distinguish freshly-authored PRDs from committed history.',
214
+ };
215
+ }
216
+
217
+ const keys = readPrdCreateAuditKeys();
218
+ const unattributed = [];
219
+ for (const file of untracked) {
220
+ const slug = path.basename(file, '.md');
221
+ const key = `${projectCwd}::${slug}`;
222
+ if (!keys.has(key)) {
223
+ unattributed.push({ file: path.relative(SCHEDULER_DIR, file), slug });
224
+ }
225
+ }
226
+
227
+ return {
228
+ applicable: true,
229
+ checkedCount: untracked.length,
230
+ unattributedCount: unattributed.length,
231
+ unattributed,
232
+ verdict: unattributed.length === 0
233
+ ? 'CLEAN: every untracked (not-yet-committed) PRD has a matching prd_create record.'
234
+ : 'INVESTIGATE: untracked PRD(s) with no matching prd_create audit event — likely hand-authored via the /develop manual-write fallback (bypassing scheduler_create_prd). Confirm the bypass was reported and verify the file by hand.',
235
+ };
236
+ }
237
+
238
+ /**
239
+ * Pattern F — referential-integrity report for the Agent/WorkType/Epic/PRD/Job
240
+ * ERD's unvalidated-string foreign keys (`PromptSession.agentType` -> a
241
+ * persona file, `PromptSession.tag` -> the WorkType union, queue-row
242
+ * `epicId`/`sourcePromptId` -> an Epic). "Throw on write, report on read":
243
+ * epicMint.cjs's ensureEpic refuses to MINT a bad reference; this pass only
244
+ * REPORTS references that were valid at creation and later went dangling
245
+ * (persona renamed/deleted, Epic archived) — that is legitimate history, not
246
+ * something this script repairs. Read-only, same as every other pattern here.
247
+ */
248
+ function auditPatternF() {
249
+ const { WORK_TYPES } = require('../src/main/lib/workTypeLibrary.cjs');
250
+ const { personaFileExists } = require('../src/main/lib/epicMint.cjs');
251
+
252
+ const index = readJson(path.join(SESSIONS_DIR, 'active-index.json'), null);
253
+ const sessions = index && typeof index.sessions === 'object' && index.sessions ? index.sessions : {};
254
+
255
+ const danglingAgentType = [];
256
+ const invalidTag = [];
257
+ for (const [epicId, session] of Object.entries(sessions)) {
258
+ if (!session || typeof session !== 'object') continue;
259
+ if (session.agentType && !personaFileExists(projectCwd, session.agentType)) {
260
+ danglingAgentType.push({ epicId, agentType: session.agentType });
261
+ }
262
+ if (session.tag && !WORK_TYPES.includes(session.tag)) {
263
+ invalidTag.push({ epicId, tag: session.tag });
264
+ }
265
+ }
266
+
267
+ const queue = readJson(QUEUE_PATH, { jobs: [] });
268
+ const jobs = Array.isArray(queue.jobs) ? queue.jobs : [];
269
+ const danglingJobRefs = [];
270
+ for (const job of jobs) {
271
+ const jobId = job.slug ?? null;
272
+ if (job.epicId && !Object.prototype.hasOwnProperty.call(sessions, job.epicId)) {
273
+ danglingJobRefs.push({ jobId, field: 'epicId', value: job.epicId });
274
+ }
275
+ if (job.sourcePromptId && !Object.prototype.hasOwnProperty.call(sessions, job.sourcePromptId)) {
276
+ danglingJobRefs.push({ jobId, field: 'sourcePromptId', value: job.sourcePromptId });
277
+ }
278
+ }
279
+
280
+ const totalFindings = danglingAgentType.length + invalidTag.length + danglingJobRefs.length;
281
+
282
+ return {
283
+ danglingAgentTypeCount: danglingAgentType.length,
284
+ danglingAgentType,
285
+ invalidTagCount: invalidTag.length,
286
+ invalidTag,
287
+ danglingJobRefCount: danglingJobRefs.length,
288
+ danglingJobRefs,
289
+ verdict: totalFindings === 0
290
+ ? 'CLEAN: every Epic agentType/tag and queue epicId/sourcePromptId reference resolves.'
291
+ : 'INVESTIGATE: dangling reference(s) found — advisory only, no repair performed (see ops-maintenance-protocol.md).',
292
+ };
293
+ }
294
+
295
+ function main() {
296
+ const c = auditPatternC();
297
+ const d = auditPatternD();
298
+ const e = auditPatternE();
299
+ const f = auditPatternF();
300
+
301
+ console.log('=== Pattern C: flat scheduler/prds/ ===');
302
+ console.log(` top-level .md files: ${c.flatTopLevelMdCount}`);
303
+ console.log(` prds-archived/ .md files: ${c.archivedCount}`);
304
+ console.log(` queue jobs referencing flat dir: ${c.queueJobsReferencingFlatDir.length}`);
305
+ console.log(` verdict: ${c.verdict}`);
306
+ console.log();
307
+ console.log('=== Pattern D: orphaned prompt-sessions/*.json ===');
308
+ console.log(` top-level files: ${d.toplevelCount}, epics/ dirs: ${d.epicDirsCount}`);
309
+ console.log(` never-started (safe, no PRD history): ${d.neverStarted.length}`);
310
+ console.log(` accounted-for-elsewhere (PRD landed under a differently-named epics/ dir): ${d.accountedForElsewhere.length}`);
311
+ console.log(` DATA LOSS candidates (PRD history, no PRD file found anywhere): ${d.dataLoss.length}`);
312
+ if (d.dataLoss.length > 0) {
313
+ for (const r of d.dataLoss) console.log(` ESCALATE: ${r.id} (${r.prdCreatedCount} prd_created event(s))`);
314
+ }
315
+ if (d.unreadable.length > 0) console.log(` unreadable: ${d.unreadable.join(', ')}`);
316
+ console.log();
317
+ console.log('=== Pattern E: hand-authored PRDs (bypassed scheduler_create_prd) ===');
318
+ console.log(` PRDs checked: ${e.checkedCount}`);
319
+ console.log(` unattributed (no matching prd_create audit event): ${e.unattributedCount}`);
320
+ if (e.unattributed.length > 0) {
321
+ for (const u of e.unattributed) console.log(` FLAG: ${u.file}`);
322
+ }
323
+ console.log(` verdict: ${e.verdict}`);
324
+ console.log();
325
+ console.log('=== Pattern F: referential integrity (agentType / tag / queue epicId+sourcePromptId) ===');
326
+ console.log(` dangling agentType refs: ${f.danglingAgentTypeCount}`);
327
+ if (f.danglingAgentType.length > 0) {
328
+ for (const r of f.danglingAgentType) console.log(` FLAG: Epic ${r.epicId} -> agentType '${r.agentType}'`);
329
+ }
330
+ console.log(` invalid tag values: ${f.invalidTagCount}`);
331
+ if (f.invalidTag.length > 0) {
332
+ for (const r of f.invalidTag) console.log(` FLAG: Epic ${r.epicId} -> tag '${r.tag}'`);
333
+ }
334
+ console.log(` dangling queue job refs: ${f.danglingJobRefCount}`);
335
+ if (f.danglingJobRefs.length > 0) {
336
+ for (const r of f.danglingJobRefs) console.log(` FLAG: job ${r.jobId ?? '(no slug)'} -> ${r.field} '${r.value}'`);
337
+ }
338
+ console.log(` verdict: ${f.verdict}`);
339
+
340
+ return { patternC: c, patternD: d, patternE: e, patternF: f };
341
+ }
342
+
343
+ if (require.main === module) {
344
+ const result = main();
345
+ if (process.env.AUDIT_JSON_OUT) {
346
+ fs.writeFileSync(process.env.AUDIT_JSON_OUT, JSON.stringify(result, null, 2));
347
+ }
348
+ }
349
+
350
+ module.exports = { auditPatternC, auditPatternD, auditPatternE, auditPatternF };
@@ -67,36 +67,13 @@
67
67
  * guard row (src/main/lib/delegationReadiness.cjs's installDestructiveGitGuard,
68
68
  * which merges into any existing hooks block instead of clobbering it).
69
69
  *
70
- * The standardized approach is REFERENCE, not vendor — do NOT copy this file
71
- * into the adopting repo. Vendoring drifts (guard-prd-writes.cjs already saw
72
- * this happen with its one adopter), and the enforcement logic belongs with
73
- * the owner (this repo), not forked into every consumer.
74
- *
75
- * This file lives in the session-manager repo, so a relative
76
- * `node scripts/hooks/guard-destructive-git.cjs` command only resolves when
77
- * the hook runs with THIS repo as cwd. Pasting that relative string into
78
- * another project yields a hook that exits non-zero WITHOUT code 2 — a
79
- * non-blocking error — so it silently guards nothing. Any other project's
80
- * `.claude/settings.json` must reference this file by its ABSOLUTE path:
81
- *
82
- * {
83
- * "hooks": {
84
- * "PreToolUse": [
85
- * {
86
- * "matcher": "Bash",
87
- * "hooks": [
88
- * {
89
- * "type": "command",
90
- * "command": "node /home/bilko/Projects/session-manager/scripts/hooks/guard-destructive-git.cjs"
91
- * }
92
- * ]
93
- * }
94
- * ]
95
- * }
96
- * }
97
- *
98
- * This is still opt-in per project, same as above — never auto-install this
99
- * into every project's settings without the human choosing to add it there.
70
+ * Adopted by REFERENCE through the stable shim
71
+ * `~/.claude/session-manager/hooks/guard-destructive-git.cjs`, written by
72
+ * src/main/lib/guardShims.cjs (installed by src/main/lib/delegationReadiness.cjs).
73
+ * The shim carries no guard logic — it reads `app-root.json` and require()s this
74
+ * file from the currently running app, so an app upgrade never breaks an adopter.
75
+ * Never vendor: do not copy this file into another repo, and do not hardcode an
76
+ * absolute path to it in another project's `.claude/settings.json`.
100
77
  *
101
78
  * ── Uninstall ────────────────────────────────────────────────────────────
102
79
  * Remove the `PreToolUse` entry above from `.claude/settings.json`. The
@@ -121,10 +98,9 @@ const { execFileSync } = require('node:child_process');
121
98
 
122
99
  // Duplicated from src/main/lib/gitWorktree.cjs's KIND_CONFIG — see this
123
100
  // file's header for why this is a deliberate duplication, not a require.
124
- const WORKTREE_ROOTS = [
125
- path.join(os.tmpdir(), 'session-manager-job-worktrees'),
126
- path.join(os.tmpdir(), 'session-manager-epic-worktrees'),
127
- ];
101
+ // Same SM_WORKTREE_ROOT-else-tmpdir base as schedulerPaths.worktreeBase().
102
+ const WORKTREE_BASE = process.env.SM_WORKTREE_ROOT || os.tmpdir();
103
+ const WORKTREE_ROOTS = ['job', 'epic'].map((k) => path.join(WORKTREE_BASE, `session-manager-${k}-worktrees`));
128
104
  const BRANCH_PREFIXES = ['sm-job/', 'sm-epic/'];
129
105
 
130
106
  const MAX_SH_C_DEPTH = 5;
@@ -28,14 +28,13 @@
28
28
  * everything for that one Epic only.
29
29
  *
30
30
  * ── Install (per-project, NOT machine-wide) ─────────────────────────────
31
- * Adopting project: press "Fix it" on the "Inline-implementation guard hook
32
- * installed" row of the New Epic readiness banner — it runs
33
- * installInlineImplementationGuard() (src/main/lib/delegationReadiness.cjs),
34
- * which merges a hook referencing THIS repo's own absolute script path into
35
- * `<your project>/.claude/settings.json`'s `Write|Edit|NotebookEdit` matcher,
36
- * the same reference-not-vendor path guard-prd-writes.cjs uses. Hand-editing
37
- * settings.json (below) is a degraded last resort for when the app isn't
38
- * running — add the command alongside guard-prd-writes.cjs in the SAME
31
+ * Adopted by REFERENCE through the stable shim
32
+ * `~/.claude/session-manager/hooks/guard-inline-implementation.cjs`, written by
33
+ * src/main/lib/guardShims.cjs (installed by src/main/lib/delegationReadiness.cjs's
34
+ * installInlineImplementationGuard(), via "Fix it" on the New Epic readiness
35
+ * banner). Never vendor: do not copy this file or hardcode an absolute path to it.
36
+ * The example below is THIS repo's own `.claude/settings.json` (relative command,
37
+ * cwd = repo root); add the command alongside guard-prd-writes.cjs in the SAME
39
38
  * `Write|Edit|NotebookEdit` matcher's `hooks` array:
40
39
  *
41
40
  * {
@@ -78,6 +77,8 @@
78
77
  const fs = require('node:fs');
79
78
  const path = require('node:path');
80
79
  const { execFileSync } = require('node:child_process');
80
+ // Pure fs helper only — deliberately NOT gitWorktree (keeps this hook light).
81
+ const { nearestGitEntry } = require('../../src/main/lib/cwdClassify.cjs');
81
82
 
82
83
  const SOURCE_DIRS = ['src', 'scripts', 'plugins', 'bin'];
83
84
  const DENY_TAGS = new Set(['feature', 'bug']);
@@ -122,6 +123,11 @@ function resolveOpsRootCwd(rawCwd) {
122
123
  return rawCwd;
123
124
  }
124
125
  try {
126
+ // Only a `.git` FILE (linked worktree) needs git to find the shared dir; a
127
+ // `.git` directory IS the project root, so skip the spawn.
128
+ const entry = nearestGitEntry(rawCwd);
129
+ if (!entry) return rawCwd;
130
+ if (!entry.isFile) return entry.dir;
125
131
  const commonDir = execFileSync(
126
132
  'git',
127
133
  ['rev-parse', '--path-format=absolute', '--git-common-dir'],
@@ -43,42 +43,13 @@
43
43
  * row (src/main/lib/delegationReadiness.cjs's installPrdWriteGuard, which
44
44
  * merges into any existing hooks block instead of clobbering it).
45
45
  *
46
- * The standardized approach is REFERENCE, not vendor — do NOT copy this file
47
- * into the adopting repo. Vendoring drifts (it already did, with exactly one
48
- * adopter), and what is being guarded is session-manager-operations/scheduler/,
49
- * Session Manager's own territory inside someone else's repo, so the
50
- * enforcement logic belongs with the owner.
51
- *
52
- * This file lives in the session-manager repo, so a relative
53
- * `node scripts/hooks/guard-prd-writes.cjs` command only resolves when the
54
- * hook runs with THIS repo as cwd. Pasting that relative string into another
55
- * project yields a hook that exits non-zero WITHOUT code 2 — a non-blocking
56
- * error — so it silently guards nothing. Any other project's
57
- * `.claude/settings.json` must reference this file by its ABSOLUTE path:
58
- *
59
- * {
60
- * "hooks": {
61
- * "PreToolUse": [
62
- * {
63
- * "matcher": "Write|Edit|NotebookEdit",
64
- * "hooks": [
65
- * {
66
- * "type": "command",
67
- * "command": "node /home/bilko/Projects/session-manager/scripts/hooks/guard-prd-writes.cjs"
68
- * }
69
- * ]
70
- * }
71
- * ]
72
- * }
73
- * }
74
- *
75
- * This is still opt-in per project, same as above — never auto-install this
76
- * into every project's settings without the human choosing to add it there.
77
- *
78
- * Roll out to another project by copying this file + the same settings.json
79
- * entry into that project — deliberately not published as a global/user-
80
- * scoped hook so a project can opt in individually (see this PRD's
81
- * Implementation notes: "scope the hook to the session-manager repo first").
46
+ * Adopted by REFERENCE through the stable shim
47
+ * `~/.claude/session-manager/hooks/guard-prd-writes.cjs`, written by
48
+ * src/main/lib/guardShims.cjs (installed by src/main/lib/delegationReadiness.cjs).
49
+ * The shim carries no guard logic — it reads `app-root.json` and require()s this
50
+ * file from the currently running app, so an app upgrade never breaks an adopter.
51
+ * Never vendor: do not copy this file into another repo, and do not hardcode an
52
+ * absolute path to it in another project's `.claude/settings.json`.
82
53
  *
83
54
  * ── Uninstall ────────────────────────────────────────────────────────────
84
55
  * Remove the `PreToolUse` entry above from `.claude/settings.json`. The