claude-code-session-manager 0.87.0 → 0.88.1

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 (291) hide show
  1. package/README.md +26 -53
  2. package/dist/assets/{AgentLibrary-DyLWzZDf.js → AgentLibrary-kQF8_wAw.js} +1 -1
  3. package/dist/assets/{DataModel--mISIJ6h.js → DataModel-CY_mMnsr.js} +1 -1
  4. package/dist/assets/{History-C2ahUXTg.js → History-Sji2brb0.js} +1 -1
  5. package/dist/assets/{Hooks-BiC6oyR2.js → Hooks-CtqpO-p5.js} +1 -1
  6. package/dist/assets/{HostBilko-BPleEOld.js → HostBilko-DN0ydOCr.js} +1 -1
  7. package/dist/assets/{Library-Dc8Qst1R.js → Library-CoiLZTKh.js} +1 -1
  8. package/dist/assets/{ListDetail-DIXh-OLX.js → ListDetail-CmqiQ_io.js} +1 -1
  9. package/dist/assets/{MarkdownEditor-C90bkLXK.js → MarkdownEditor-HPoNeKhT.js} +1 -1
  10. package/dist/assets/{McpServers-DqcbLOLZ.js → McpServers-Bj1X3_NT.js} +1 -1
  11. package/dist/assets/{Memory-CW62MXlh.js → Memory-1PKjsM3b.js} +1 -1
  12. package/dist/assets/{Panel-Bw1FhRuF.js → Panel-I1s6ghPo.js} +1 -1
  13. package/dist/assets/{Permissions-BcUC-5y8.js → Permissions-BhiiZjHQ.js} +1 -1
  14. package/dist/assets/{Plugins-BnKx9flD.js → Plugins-gv3_fkPX.js} +2 -2
  15. package/dist/assets/{ProvenanceBadge-Bw5vNVPT.js → ProvenanceBadge-BGcgBd8V.js} +1 -1
  16. package/dist/assets/{SaveBar-CWr0O_w-.js → SaveBar-BGr9eZ4g.js} +1 -1
  17. package/dist/assets/{Scheduler-DYdLuUqq.js → Scheduler-Bdo_awPq.js} +7 -7
  18. package/dist/assets/{ScopeSwitcher-CrBLbg8s.js → ScopeSwitcher-ukl0qWaA.js} +1 -1
  19. package/dist/assets/{Settings-DluB-vN1.js → Settings-DJkFj22G.js} +1 -1
  20. package/dist/assets/{SkillReferenceGraph-CHLSseay.js → SkillReferenceGraph-0t1Qblp6.js} +1 -1
  21. package/dist/assets/{Skills-gNdo_HNK.js → Skills-CeVdBGE-.js} +1 -1
  22. package/dist/assets/{SystemPrompt-Cru05-Ia.js → SystemPrompt-CfKvNHi3.js} +1 -1
  23. package/dist/assets/{TagLibrary-DNHY0xou.js → TagLibrary-DAzNaUPd.js} +1 -1
  24. package/dist/assets/{TiptapBody-I4lmbCgP.js → TiptapBody--S_rGXoA.js} +1 -1
  25. package/dist/assets/{Toggle-bWMHjmRh.js → Toggle-Dszm0xnp.js} +1 -1
  26. package/dist/assets/{index-DV3PorRY.css → index-BHTX4OTc.css} +1 -1
  27. package/dist/assets/{index-fc_JjdxL.js → index-Dp4Rc--q.js} +356 -356
  28. package/dist/assets/{settingsSchema-BfhtZnGD.js → settingsSchema-BLbssMYo.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 +27 -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-stall-per-project.test.cjs +14 -0
  124. package/src/main/__tests__/scheduler-starve-escalation.test.cjs +4 -4
  125. package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +245 -0
  126. package/src/main/__tests__/scheduler-supervisor-record.test.cjs +81 -0
  127. package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +2 -2
  128. package/src/main/__tests__/scheduler-tick-wedge.test.cjs +172 -0
  129. package/src/main/__tests__/scheduler-transient-failure.test.cjs +2 -2
  130. package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +37 -11
  131. package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +3 -5
  132. package/src/main/__tests__/usageSingleFlight.test.cjs +157 -0
  133. package/src/main/__tests__/workTypeLibrary.test.cjs +1 -1
  134. package/src/main/bilkoHost.cjs +16 -7
  135. package/src/main/build-info.json +8 -0
  136. package/src/main/chatRunner.cjs +4 -2
  137. package/src/main/config.cjs +2 -3
  138. package/src/main/docEdit.cjs +4 -2
  139. package/src/main/health.cjs +276 -52
  140. package/src/main/heapSnapshot.cjs +2 -2
  141. package/src/main/historyAggregator.cjs +1 -1
  142. package/src/main/index.cjs +61 -10
  143. package/src/main/ipcSchemas.cjs +6 -17
  144. package/src/main/lib/__tests__/auditLog.test.cjs +38 -0
  145. package/src/main/lib/__tests__/buildIdentity.test.cjs +121 -0
  146. package/src/main/lib/__tests__/cwdClassify.test.cjs +111 -0
  147. package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +95 -0
  148. package/src/main/lib/__tests__/delegationReadiness.test.cjs +1 -1
  149. package/src/main/lib/__tests__/dispatchLoop.test.cjs +63 -0
  150. package/src/main/lib/__tests__/gateFixtures.json +20 -0
  151. package/src/main/lib/__tests__/gitWorktree.test.cjs +8 -1
  152. package/src/main/lib/__tests__/instanceLock.test.cjs +93 -7
  153. package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +78 -0
  154. package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +11 -0
  155. package/src/main/lib/__tests__/localAdminHttp.test.cjs +1 -1
  156. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +6 -1
  157. package/src/main/lib/__tests__/procIdentity.test.cjs +119 -0
  158. package/src/main/lib/__tests__/procName.test.cjs +92 -0
  159. package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +67 -0
  160. package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +6 -7
  161. package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +37 -204
  162. package/src/main/lib/__tests__/schedulerPaths.test.cjs +226 -0
  163. package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +94 -0
  164. package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +56 -0
  165. package/src/main/lib/__tests__/sessionSlots.test.cjs +45 -0
  166. package/src/main/lib/__tests__/telemetryBacklog.test.cjs +1 -1
  167. package/src/main/lib/__tests__/upgradeDrain.test.cjs +130 -0
  168. package/src/main/lib/__tests__/usageCircuit.test.cjs +61 -0
  169. package/src/main/lib/__tests__/watchdog-helpers.test.cjs +63 -0
  170. package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +73 -0
  171. package/src/main/lib/activeIndexRebuild.cjs +1 -3
  172. package/src/main/lib/activeSessions.cjs +20 -88
  173. package/src/main/lib/adoptedRunSupervisor.cjs +136 -0
  174. package/src/main/lib/agentModelResolve.cjs +33 -1
  175. package/src/main/lib/agentPersonaSchema.cjs +2 -2
  176. package/src/main/lib/auditLog.cjs +30 -5
  177. package/src/main/lib/buildIdentity.cjs +113 -0
  178. package/src/main/lib/classifyPromptTicket.cjs +3 -2
  179. package/src/main/lib/claudeBin.cjs +37 -2
  180. package/src/main/lib/cleanEnv.cjs +27 -1
  181. package/src/main/lib/credentials.cjs +4 -2
  182. package/src/main/lib/cwdClassify.cjs +185 -0
  183. package/src/main/lib/definitionOfDone.cjs +296 -52
  184. package/src/main/lib/dispatchLoop.cjs +40 -0
  185. package/src/main/lib/effectiveModelInfo.cjs +9 -10
  186. package/src/main/lib/ephemeralCwd.cjs +7 -28
  187. package/src/main/lib/gitWorktree.cjs +95 -8
  188. package/src/main/lib/guardShims.cjs +3 -3
  189. package/src/main/lib/historyRollup.cjs +6 -7
  190. package/src/main/lib/instanceLock.cjs +32 -5
  191. package/src/main/lib/jobSupervisorRecord.cjs +147 -0
  192. package/src/main/lib/jobWorktreeBootLive.cjs +9 -5
  193. package/src/main/lib/localAdminHttp.cjs +9 -27
  194. package/src/main/lib/mcpToolCatalog.cjs +29 -77
  195. package/src/main/lib/opsOwnership.cjs +27 -19
  196. package/src/main/lib/prdAuthoringSeed.cjs +36 -0
  197. package/src/main/lib/prdLocations.cjs +48 -1
  198. package/src/main/lib/procIdentity.cjs +126 -0
  199. package/src/main/lib/procName.cjs +98 -0
  200. package/src/main/lib/projectHomeAdminRoutes.cjs +56 -327
  201. package/src/main/lib/queueHistory.cjs +8 -7
  202. package/src/main/lib/queueStore.cjs +57 -37
  203. package/src/main/lib/quietMachineLease.cjs +19 -2
  204. package/src/main/lib/reservationExpiry.cjs +30 -0
  205. package/src/main/lib/runClaudeP.cjs +4 -2
  206. package/src/main/lib/runLogRetention.cjs +3 -2
  207. package/src/main/lib/scheduleJobSchema.cjs +2 -2
  208. package/src/main/lib/scheduleJobTransitions.cjs +29 -2
  209. package/src/main/lib/schedulerBatch.cjs +27 -2
  210. package/src/main/lib/schedulerPaths.cjs +175 -0
  211. package/src/main/lib/schedulerRuntimeState.cjs +59 -0
  212. package/src/main/lib/sessionSlots.cjs +47 -9
  213. package/src/main/lib/smProcNames.cjs +51 -0
  214. package/src/main/lib/upgradeDrain.cjs +188 -0
  215. package/src/main/lib/usageCircuit.cjs +53 -6
  216. package/src/main/lib/watchdogHelpers.cjs +70 -37
  217. package/src/main/lib/withTimeout.cjs +33 -0
  218. package/src/main/mcpStatus.cjs +4 -2
  219. package/src/main/pluginInstall.cjs +6 -2
  220. package/src/main/projectPages.cjs +41 -145
  221. package/src/main/pty.cjs +8 -1
  222. package/src/main/queueOps.cjs +10 -10
  223. package/src/main/runVerify.cjs +69 -3
  224. package/src/main/scheduler.cjs +1607 -383
  225. package/src/main/seedAgentPersonas.cjs +1 -1
  226. package/src/main/seedDevPlugin.cjs +1 -1
  227. package/src/main/seedSchedulerMcp.cjs +7 -6
  228. package/src/main/seedStatus.cjs +1 -1
  229. package/src/main/supervisor.cjs +5 -3
  230. package/src/main/usage.cjs +126 -62
  231. package/src/preload/api.d.ts +18 -64
  232. package/src/preload/index.cjs +2 -4
  233. package/src/seed/agents/project-home-builder.md +31 -48
  234. package/screenshots/.gitkeep +0 -0
  235. package/screenshots/README-screenshots.md +0 -13
  236. package/src/main/lib/projectPageSummarySchema.cjs +0 -181
  237. package/src/main/teams.cjs +0 -95
  238. package/src/main/templates/project-pages-catalog.json +0 -741
  239. package/src/main/templates/project-pages-default-home.html +0 -123
  240. package/src/main/templates/project-pages-pipeline.md +0 -417
  241. package/src/seed/prompts/code-review/ac-coverage-check.md +0 -8
  242. package/src/seed/prompts/code-review/correctness-only.md +0 -8
  243. package/src/seed/prompts/code-review/full-spectrum-high.md +0 -8
  244. package/src/seed/prompts/code-review/hallucination-check.md +0 -8
  245. package/src/seed/prompts/code-review/public-api-compat.md +0 -8
  246. package/src/seed/prompts/code-review/readability-naming.md +0 -8
  247. package/src/seed/prompts/debugging/bug-as-failing-test.md +0 -8
  248. package/src/seed/prompts/debugging/git-bisect-regression.md +0 -8
  249. package/src/seed/prompts/debugging/instrument-intermittent-bug.md +0 -8
  250. package/src/seed/prompts/debugging/localize-pipeline-failure.md +0 -8
  251. package/src/seed/prompts/debugging/reproduce-then-diagnose.md +0 -8
  252. package/src/seed/prompts/documentation/adr-from-change.md +0 -8
  253. package/src/seed/prompts/documentation/module-readme.md +0 -8
  254. package/src/seed/prompts/documentation/onboarding-plan.md +0 -8
  255. package/src/seed/prompts/documentation/refresh-claude-md.md +0 -8
  256. package/src/seed/prompts/documentation/tsdoc-public-exports.md +0 -8
  257. package/src/seed/prompts/git-pr/conventional-commit.md +0 -8
  258. package/src/seed/prompts/git-pr/draft-pr-title-body.md +0 -8
  259. package/src/seed/prompts/git-pr/pre-commit-safety-sweep.md +0 -8
  260. package/src/seed/prompts/git-pr/release-notes-block.md +0 -8
  261. package/src/seed/prompts/git-pr/split-large-pr.md +0 -8
  262. package/src/seed/prompts/performance/bundle-startup-audit.md +0 -8
  263. package/src/seed/prompts/performance/complexity-audit.md +0 -8
  264. package/src/seed/prompts/performance/cpu-profile-hot-path.md +0 -8
  265. package/src/seed/prompts/performance/db-query-plan-review.md +0 -8
  266. package/src/seed/prompts/performance/memory-leak-hunt.md +0 -8
  267. package/src/seed/prompts/qa/api-contract-tests.md +0 -8
  268. package/src/seed/prompts/qa/e2e-critical-path.md +0 -8
  269. package/src/seed/prompts/qa/failing-test-for-bug.md +0 -8
  270. package/src/seed/prompts/qa/find-missing-test-coverage.md +0 -8
  271. package/src/seed/prompts/qa/stabilize-flaky-test.md +0 -8
  272. package/src/seed/prompts/qa/tdd-red-first.md +0 -8
  273. package/src/seed/prompts/qa/visual-regression-review.md +0 -8
  274. package/src/seed/prompts/qa/wcag-axe-scan.md +0 -8
  275. package/src/seed/prompts/refactoring/dead-code-sweep.md +0 -8
  276. package/src/seed/prompts/refactoring/extract-duplicated-pattern.md +0 -8
  277. package/src/seed/prompts/refactoring/modernize-legacy-file.md +0 -8
  278. package/src/seed/prompts/refactoring/reduce-cyclomatic-complexity.md +0 -8
  279. package/src/seed/prompts/refactoring/tighten-module-boundaries.md +0 -8
  280. package/src/seed/prompts/security/authz-audit.md +0 -8
  281. package/src/seed/prompts/security/crypto-correctness.md +0 -8
  282. package/src/seed/prompts/security/cwe-top-25-hunt.md +0 -8
  283. package/src/seed/prompts/security/dependency-audit.md +0 -8
  284. package/src/seed/prompts/security/ipc-boundary-hardening.md +0 -8
  285. package/src/seed/prompts/security/owasp-top-10-staged-diff.md +0 -8
  286. package/src/seed/prompts/security/secret-credential-scan.md +0 -8
  287. package/web/README.md +0 -41
  288. package/web/project-pages/logic/dist/logic.cjs +0 -4709
  289. package/web/project-pages/render.cjs +0 -70
  290. package/web/project-pages/renderer/dist/renderer.cjs +0 -18900
  291. package/web/project-pages/validate-summary.cjs +0 -62
@@ -1,27 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
- * projectPages.cjs — read-only backend for Project Home's Project Pages
5
- * display (PRD 932). Reads what the `project-home-builder` Epic's own
6
- * session writes directly with its Write tool
7
- * (`session-manager-operations/project-pages/output/*.html` + manifest.json)
8
- * — this module never writes any CONTENT (the one exception, watchOutput()'s
9
- * `fs.mkdirSync` to ensure the output dir exists before attaching a watcher,
10
- * creates an empty directory only), matching the corrected "not an
11
- * OWNERS namespace" storage/ownership note in
12
- * session-manager-operations/architecture/project-pages-pipeline.md and
13
- * session-manager-operations/project-pages/README.md. Structure mirrors
14
- * projectBrief.cjs's `get()`: validatePath first, config.cjs read helpers,
15
- * one ipcMain.handle registered from index.cjs's registerXHandlers() pattern.
16
- *
17
- * Shipped default (PRD "project-home-hosted-html-spec"): when a project has
18
- * never generated its own output, `get()` no longer returns the bare
19
- * `{ output: null }` empty-state signal — it falls back to a build-time
20
- * default `home.html` shipped with the app (`templates/`), returned with
21
- * `isDefault: true` and `generatedAt: null` so the renderer can label
22
- * provenance. That default is read from a fixed app-relative path, never
23
- * written into any project's own `session-manager-operations/` tree — this
24
- * module stays read-only.
4
+ * projectPages.cjs — read-only backend for Project Home. The whole feature is
5
+ * ONE self-contained HTML file, `session-manager-operations/project-pages/
6
+ * home.html`, written by the `project_home_write` admin route
7
+ * (lib/projectHomeAdminRoutes.cjs). This module only reads it: get() plus a
8
+ * refcounted per-cwd watcher that pushes `project-pages:changed`. It never
9
+ * writes content (watch()'s mkdir creates an empty directory only).
25
10
  */
26
11
 
27
12
  const { ipcMain } = require('electron');
@@ -37,128 +22,49 @@ function attachWindow(window) {
37
22
  mainWindow = window;
38
23
  }
39
24
 
40
- function outputDir(cwd) {
41
- return opsPath(cwd, 'project-pages', 'output');
25
+ function homePath(cwd) {
26
+ return opsPath(cwd, 'project-pages', 'home.html');
42
27
  }
43
28
 
44
29
  /**
45
- * Resolve `cwd`'s output dir, treating the opsOwnership "ephemeral cwd"
46
- * throw (a tmpdir/linked-worktree project root — see opsOwnership.cjs's
47
- * resolveProjectRoot) as "no output dir available" rather than letting it
48
- * propagate. Both get() and the watcher below go through this so a builder
49
- * Epic running in a worktree can never crash either path.
30
+ * Resolve `cwd`'s home.html path, treating the opsOwnership "ephemeral cwd"
31
+ * throw (a tmpdir/linked-worktree project root) as "no path available"
32
+ * rather than letting it propagate.
50
33
  */
51
- function tryOutputDir(realCwd) {
34
+ function tryHomePath(realCwd) {
52
35
  try {
53
- return { dir: outputDir(realCwd), ephemeral: false };
36
+ return { file: homePath(realCwd), ephemeral: false };
54
37
  } catch (e) {
55
- if (e.ephemeral) return { dir: null, ephemeral: true };
38
+ if (e.ephemeral) return { file: null, ephemeral: true };
56
39
  throw e;
57
40
  }
58
41
  }
59
42
 
60
- // Shipped build-time asset (see PRD "project-home-hosted-html-spec"'s
61
- // default-document requirement) — a fixed app-relative path with no
62
- // user-controlled segment, so it deliberately does NOT go through
63
- // config.cjs's validatePath (whose allowedRoots is the user's home dir and
64
- // would reject/mis-resolve a path under the app's own install directory,
65
- // e.g. when installed via npx/global npm outside $HOME). Read once and
66
- // cached in-process; this file never changes at runtime.
67
- const DEFAULT_HOME_PATH = path.join(__dirname, 'templates', 'project-pages-default-home.html');
68
- let cachedDefaultHomeHtml = null;
69
- function readDefaultHomeHtml() {
70
- if (cachedDefaultHomeHtml === null) {
71
- cachedDefaultHomeHtml = fs.readFileSync(DEFAULT_HOME_PATH, 'utf8');
72
- }
73
- return cachedDefaultHomeHtml;
74
- }
75
- function defaultOutput() {
76
- return { home: readDefaultHomeHtml(), generatedAt: null, isDefault: true };
77
- }
78
-
79
- // The original 4 lenses stay required — their absence still means "no
80
- // Project Pages generated yet" (now the shipped-default fallback rather
81
- // than a bare null). 'brief' was added later (5th lens): a project that
82
- // generated its output BEFORE 'brief'
83
- // existed has home/marketing/feature/architecture.html but no brief.html, and
84
- // that must keep reading as "has output" rather than suddenly regressing to
85
- // the empty state for every pre-existing project. So brief.html is read
86
- // tolerantly — present, its text is returned; absent, the field is simply
87
- // omitted from the payload rather than failing the whole read.
88
- // Partial-output strategy (see this file's module doc + PRD
89
- // "project-home-generate-preflight-and-push"): the render route
90
- // (projectHomeAdminRoutes.cjs's doRender) writes every lens file
91
- // concurrently and writes manifest.json ONLY AFTER all of them have landed.
92
- // So manifest.json's existence is already an all-or-nothing commit signal —
93
- // gating get() on it (below) means a reader can never observe a lens file
94
- // that arrived without its siblings. No second partial-state representation
95
- // is needed; this file just relies on that write order.
96
- const REQUIRED_LENSES = ['home', 'marketing', 'feature', 'architecture'];
97
- const OPTIONAL_LENSES = ['brief'];
98
- const LENSES = [...REQUIRED_LENSES, ...OPTIONAL_LENSES];
99
-
43
+ /** -> { html: string|null, mtimeMs: number|null } */
100
44
  async function get({ cwd }) {
101
45
  const realCwd = config.validatePath(cwd);
102
- const { dir, ephemeral } = tryOutputDir(realCwd);
103
- if (ephemeral) {
104
- return { output: defaultOutput() };
105
- }
106
- const manifestResult = await config.readJson(path.join(dir, 'manifest.json'));
107
- if (!manifestResult.exists || !manifestResult.data || manifestResult.parseError) {
108
- return { output: defaultOutput() };
109
- }
110
-
111
- const htmlResults = await Promise.all(
112
- LENSES.map((lens) => config.readText(path.join(dir, `${lens}.html`))),
113
- );
114
- const byLens = Object.fromEntries(LENSES.map((lens, i) => [lens, htmlResults[i]]));
115
- if (REQUIRED_LENSES.some((lens) => !byLens[lens].exists)) {
116
- return { output: defaultOutput() };
117
- }
118
-
119
- const generatedAt = typeof manifestResult.data.generatedAt === 'string' ? manifestResult.data.generatedAt : null;
120
- if (!generatedAt) {
121
- return { output: defaultOutput() };
122
- }
123
-
124
- const output = {
125
- home: byLens.home.text,
126
- marketing: byLens.marketing.text,
127
- feature: byLens.feature.text,
128
- architecture: byLens.architecture.text,
129
- generatedAt,
130
- isDefault: false,
131
- };
132
- if (byLens.brief.exists) {
133
- output.brief = byLens.brief.text;
134
- }
135
-
136
- return { output };
46
+ const { file, ephemeral } = tryHomePath(realCwd);
47
+ if (ephemeral) return { html: null, mtimeMs: null };
48
+ const res = await config.readText(file);
49
+ if (!res.exists) return { html: null, mtimeMs: null };
50
+ return { html: res.text, mtimeMs: res.mtimeMs };
137
51
  }
138
52
 
139
- // ─── Push channel (PRD "project-home-generate-preflight-and-push") ────────
140
- //
141
- // project-pages:get above is a one-shot pull, fetched once at mount by
142
- // ProjectHome.tsx. That leaves a finished (or stuck) builder Epic invisible
143
- // until the next manual refresh/app restart. This section adds a per-cwd
144
- // chokidar watcher on the output dir (the same debounced-write library
145
- // config.cjs already uses for its generic file watcher) that recomputes
146
- // get() and pushes it to the renderer whenever the dir changes.
53
+ // ─── Push channel ─────────────────────────────────────────────────────────
147
54
  //
148
- // Map<realCwd, { watcher, refCount }> — refcounted like config.cjs's own
149
- // watchers Map so more than one mounted component watching the same cwd
150
- // doesn't spawn a second chokidar instance, and doesn't get torn down by
151
- // the first component's unmount while a second is still watching.
55
+ // project-pages:get is a one-shot pull; this adds a per-cwd chokidar watcher
56
+ // on the project-pages dir that recomputes get() and pushes it to the
57
+ // renderer when home.html is added/changed/removed. Map<realCwd, { watcher,
58
+ // refCount }> — refcounted so several mounted components watching the same
59
+ // cwd share one chokidar instance.
152
60
  const outputWatchers = new Map();
153
61
 
154
62
  /**
155
- * Watch `cwd`'s output dir. Resolves `{ ok: true }` once watching is actually
156
- * live (or already watching), or `{ ok: false, reason: 'ephemeral' |
157
- * 'invalid-cwd' }` when there is nothing safe to watch — callers must not
158
- * treat that as an error, just as "no live updates for this cwd" (e.g. a
159
- * worktree cwd). Async: waits for chokidar's own 'ready' before resolving so
160
- * a write landing immediately after the call is never missed in the window
161
- * before the underlying fs watch handle is actually registered.
63
+ * Watch `cwd`'s home.html. Resolves `{ ok: true }` once watching is live (or
64
+ * already watching), or `{ ok: false, reason: 'ephemeral' | 'invalid-cwd' }`
65
+ * when there is nothing safe to watch — not an error, just "no live updates
66
+ * for this cwd". Waits for chokidar's 'ready' so a write landing right after
67
+ * the call is never missed.
162
68
  */
163
69
  async function watchOutput(cwd) {
164
70
  let realCwd;
@@ -174,40 +80,32 @@ async function watchOutput(cwd) {
174
80
  return { ok: true };
175
81
  }
176
82
 
177
- const { dir, ephemeral } = tryOutputDir(realCwd);
83
+ const { file, ephemeral } = tryHomePath(realCwd);
178
84
  if (ephemeral) {
179
85
  return { ok: false, reason: 'ephemeral' };
180
86
  }
181
- // Ensure the (possibly not-yet-generated) output dir exists before
182
- // chokidar attaches: watching a path 3 levels deep that doesn't exist yet
183
- // does not reliably pick up files later written into it (verified — the
184
- // watcher silently misses the first write without this). This creates an
185
- // EMPTY directory only, no content, so it does not conflict with this
186
- // module's read-only contract or the single-writer law (opsOwnership.cjs)
187
- // — it bypasses config.cjs's writer-tracked write path deliberately,
188
- // exactly like a project-home-builder Epic's own untracked Write-tool
189
- // calls into this same folder (see opsOwnership.cjs's 'project-pages'
190
- // entry).
87
+ // Watch the parent dir (chokidar silently misses the first write of a file
88
+ // in a not-yet-existing dir). mkdir creates an EMPTY directory only — no
89
+ // content, so the single-writer law (opsOwnership.cjs) is not involved.
90
+ const dir = path.dirname(file);
191
91
  fs.mkdirSync(dir, { recursive: true });
192
92
 
193
- const push = async () => {
93
+ const push = async (changedPath) => {
94
+ if (changedPath && path.resolve(changedPath) !== path.resolve(file)) return; // only home.html
194
95
  let result;
195
96
  try {
196
97
  result = await get({ cwd: realCwd });
197
98
  } catch {
198
99
  return; // best-effort; the renderer keeps its last-known output
199
100
  }
200
- sendIfAlive(mainWindow, 'project-pages:changed', { cwd: realCwd, output: result.output });
101
+ sendIfAlive(mainWindow, 'project-pages:changed', { cwd: realCwd, html: result.html, mtimeMs: result.mtimeMs });
201
102
  };
202
103
 
203
104
  const watcher = chokidar.watch(dir, {
204
105
  ignoreInitial: true,
205
106
  persistent: true,
206
- // manifest.json is the LAST file doRender writes (see REQUIRED_LENSES's
207
- // comment above) — but the burst of per-lens writes leading up to it
208
- // still fires several fs events in quick succession. awaitWriteFinish
209
- // (same 50ms/25ms shape config.cjs's generic watcher uses) collapses
210
- // that burst into one push instead of flapping the UI once per file.
107
+ depth: 0,
108
+ // Same 50ms/25ms shape config.cjs's generic watcher uses.
211
109
  awaitWriteFinish: { stabilityThreshold: 50, pollInterval: 25 },
212
110
  });
213
111
  watcher.on('add', push);
@@ -264,8 +162,6 @@ module.exports = {
264
162
  watchOutput,
265
163
  unwatchOutput,
266
164
  closeAllOutputWatchers,
267
- DEFAULT_HOME_PATH,
268
- readDefaultHomeHtml,
269
165
  // Test-only introspection of the refcounted watcher map.
270
166
  _outputWatchers: outputWatchers,
271
167
  };
package/src/main/pty.cjs CHANGED
@@ -17,6 +17,7 @@ const path = require('node:path');
17
17
  const os = require('node:os');
18
18
  const fs = require('node:fs');
19
19
  const { addAllowedRoot } = require('./config.cjs');
20
+ const { aliasedShellBin } = require('./lib/smProcNames.cjs');
20
21
  const { cleanChildEnv, pathWithUserBins } = require('./lib/cleanEnv.cjs');
21
22
  const { checkInsideHome } = require('./lib/insideHome.cjs');
22
23
  const { sendIfAlive } = require('./lib/sendToRenderer.cjs');
@@ -187,7 +188,13 @@ class PtyManager {
187
188
  let proc;
188
189
  try {
189
190
  // Interactive login shell so aliases / nvm / PATH resolve correctly.
190
- proc = pty.spawn(shell, ['-il'], {
191
+ // `sm-shell` comm (pn-03) via symlink — node-pty has no argv0 option.
192
+ // ONLY interactive terminal tabs get this alias. supervisor.cjs
193
+ // getChildBashCmdlines matches comm === 'bash' EXACTLY over a scheduler
194
+ // job's descendants; no shell in a job's process tree is ever spawned
195
+ // through here, so that detection is unaffected. Non-bash/zsh shells and
196
+ // any alias failure fall back to the real path.
197
+ proc = pty.spawn(aliasedShellBin(shell), ['-il'], {
191
198
  name: 'xterm-256color',
192
199
  cols,
193
200
  rows,
@@ -32,18 +32,16 @@
32
32
  const fs = require('node:fs');
33
33
  const fsp = require('node:fs/promises');
34
34
  const path = require('node:path');
35
- const os = require('node:os');
36
35
  const { ipcMain } = require('electron');
37
36
  const { SCHEDULE_SLUG_RE: SLUG_RE, schemas } = require('./ipcSchemas.cjs');
38
37
  const logs = require('./logs.cjs');
39
38
  const config = require('./config.cjs');
40
39
  const { expandHome } = require('./lib/expandHome.cjs');
41
40
  const { HISTORY_RETENTION_MS } = require('./lib/schedulerConfig.cjs');
41
+ const schedulerPaths = require('./lib/schedulerPaths.cjs');
42
42
 
43
- const ROOT = path.join(os.homedir(), '.claude', 'session-manager', 'scheduled-plans');
44
- const PRDS_DIR = path.join(ROOT, 'prds');
45
- const PRDS_ARCHIVE_DIR = path.join(ROOT, 'prds-archived');
46
- const RETAG_LOG = path.join(ROOT, 'retag-log.jsonl');
43
+ // Lazy: resolved via lib/schedulerPaths.cjs at each use (SM_SCHEDULER_HOME).
44
+ const prdsArchiveDir = () => path.join(schedulerPaths.scheduledPlansRoot(), 'prds-archived');
47
45
 
48
46
  // ────────────────────────────────────────────── lint rules
49
47
 
@@ -136,7 +134,7 @@ const { resolvePrdsDirs, resolvePrdWriteDir, listEpicPrdDirs } = require('./lib/
136
134
  // aggregates both so the linter/archive/retag operations still see every
137
135
  // PRD regardless of which dir it currently lives in.
138
136
  function candidatePrdsDirs() {
139
- return [PRDS_DIR, ...resolvePrdsDirs()];
137
+ return [schedulerPaths.prdsRoot(), ...resolvePrdsDirs()];
140
138
  }
141
139
 
142
140
  /**
@@ -574,9 +572,9 @@ async function retagOne({ slug, parallelGroup, estimateMinutes }) {
574
572
  async function appendRetagLog(entries) {
575
573
  if (entries.length === 0) return;
576
574
  try {
577
- await fsp.mkdir(ROOT, { recursive: true });
575
+ await fsp.mkdir(schedulerPaths.scheduledPlansRoot(), { recursive: true });
578
576
  const lines = entries.map((e) => JSON.stringify({ ts: new Date().toISOString(), ...e }) + '\n').join('');
579
- await fsp.appendFile(RETAG_LOG, lines);
577
+ await fsp.appendFile(path.join(schedulerPaths.scheduledPlansRoot(), 'retag-log.jsonl'), lines);
580
578
  } catch (e) {
581
579
  logs.writeLine({ level: 'warn', scope: 'queueOps', message: 'retag log append failed', meta: { error: e?.message } });
582
580
  }
@@ -629,9 +627,11 @@ module.exports = {
629
627
  selectAutoArchivable,
630
628
  autoArchiveCompleted,
631
629
  retagMany,
632
- PRDS_DIR,
633
- PRDS_ARCHIVE_DIR,
634
630
  archiveDirForSource,
635
631
  candidatePrdsDirs,
636
632
  findPrdDir,
637
633
  };
634
+
635
+ // Lazy path getters (SM_SCHEDULER_HOME resolved at read, never at require).
636
+ Object.defineProperty(module.exports, 'PRDS_DIR', { get: schedulerPaths.prdsRoot, enumerable: true });
637
+ Object.defineProperty(module.exports, 'PRDS_ARCHIVE_DIR', { get: prdsArchiveDir, enumerable: true });
@@ -808,9 +808,30 @@ function allDeliverablesAlreadyTracked({ cwd, paths, execImpl = execFileSync, ti
808
808
  * same slug landed, if any — supplied by the
809
809
  * caller (scheduler.cjs). Used by the
810
810
  * pass_no_commit_prior_run_verified exemption.
811
+ * @param {string|null} [params.jobLandedCommitThisRun] The commit SHA THIS run's own
812
+ * guard cwd HEAD advanced to (spawnJob's
813
+ * `headAtExit` when it differs from
814
+ * `guardHeadBefore`), or the equivalent
815
+ * already-persisted `job.landedCommit` when
816
+ * re-verifying a stale needs_review row. This
817
+ * is a HEAD delta observed for THIS job's own
818
+ * dispatch — strictly stronger attribution than
819
+ * `committedDuringRun`'s repo-wide window scan —
820
+ * and, unlike the now-deleted `sm-job/<slug>`
821
+ * branch tip, it survives `cleanupWorktree`.
822
+ * Used by the ground-truth-outranks-heuristics
823
+ * rule below. Default null for back-compat.
824
+ * @param {number|null} [params.exitCode] The run's process exit code. The
825
+ * ground-truth-outranks-heuristics rule only
826
+ * ever applies when this is exactly 0 — default
827
+ * null so callers that don't pass it keep
828
+ * today's behavior byte-for-byte.
811
829
  * @returns {Promise<{verdict:string, reason:string, downgradeTo:string|null}>}
812
830
  */
813
- async function verifyRun({ runDir, prdPath, queueEntry, allJobs = [], committedDuringRun = false, allowPreSentinelHeal = false, ghExecImpl, priorLandedCommit = null }) {
831
+ async function verifyRun({
832
+ runDir, prdPath, queueEntry, allJobs = [], committedDuringRun = false, allowPreSentinelHeal = false,
833
+ ghExecImpl, priorLandedCommit = null, jobLandedCommitThisRun = null, exitCode = null,
834
+ }) {
814
835
  const { slug } = queueEntry;
815
836
  const logPath = path.join(runDir, `${slug}.log`);
816
837
  const verdictsPath = path.join(runDir, `${slug}.verdicts.json`);
@@ -865,9 +886,22 @@ async function verifyRun({ runDir, prdPath, queueEntry, allJobs = [], committedD
865
886
  // gitHead()/committedInWindow() both fail closed there. In that case
866
887
  // ONLY, fall back to the harness-emitted commit evidence in the
867
888
  // transcript, which git itself produced and the model cannot fabricate.
889
+ //
890
+ // jobLandedCommitThisRun (spawnJob's own guardHeadBefore/headAtExit delta,
891
+ // or the equivalent already-persisted job.landedCommit on a re-verify
892
+ // pass) is folded into the SAME commitEvidence signal used everywhere in
893
+ // this function — a HEAD delta observed for THIS job's own dispatch is at
894
+ // least as strong as the repo-wide committedDuringRun window scan, so
895
+ // every exemption below that already trusts commitEvidence (no_verdict_
896
+ // sentinel, pass_no_commit, the PASS+commitEvidence sentinel override)
897
+ // should trust this evidence too, not just the new ground-truth rule.
868
898
  const cwdIsGitRepo = isGitRepo(queueEntry?.cwd);
869
- const commitEvidence = committedDuringRun || (!cwdIsGitRepo && transcriptCommitLanded);
870
- const commitEvidenceSource = (!committedDuringRun && commitEvidence) ? 'transcript' : null;
899
+ const commitEvidence = committedDuringRun || Boolean(jobLandedCommitThisRun) || (!cwdIsGitRepo && transcriptCommitLanded);
900
+ let commitEvidenceSource = null;
901
+ if (!committedDuringRun) {
902
+ if (jobLandedCommitThisRun) commitEvidenceSource = 'jobLandedCommitThisRun';
903
+ else if (commitEvidence) commitEvidenceSource = 'transcript';
904
+ }
871
905
 
872
906
  // ── 3. HALT detection ─────────────────────────────────────────────────
873
907
  // Primary: check the final `{"type":"result"}` event's `result` text.
@@ -990,6 +1024,38 @@ async function verifyRun({ runDir, prdPath, queueEntry, allJobs = [], committedD
990
1024
 
991
1025
  // Scan for the SCHEDULER_VERDICT sentinel emitted by the finish protocol.
992
1026
  const sentinel = scanSentinel(resultEvent, events);
1027
+
1028
+ // Ground truth outranks heuristics: an exit-0 run that landed a commit
1029
+ // ATTRIBUTABLE TO THIS RUN (spawnJob's own guardHeadBefore/headAtExit
1030
+ // delta, or the repo-wide committedDuringRun window scan) and never
1031
+ // printed an explicit SCHEDULER_VERDICT: FAIL demotes every
1032
+ // transcript_errors/verify_unavailable hit from `issues` to `annotations`
1033
+ // — a tool error the agent already recovered from three calls later, or
1034
+ // an environment probe, says nothing once the work is materially proven
1035
+ // to have landed. Deliberately narrower than the sentinel-override below:
1036
+ // it needs no PASS claim at all, only the ABSENCE of an explicit FAIL, so
1037
+ // it also catches the majority no-sentinel-at-all park class that the
1038
+ // PASS+commitEvidence override (further below) can never reach. Never
1039
+ // demotes pass_no_commit/no_verdict_sentinel/abandoned_background_task —
1040
+ // those are added below this point and are about the ABSENCE of a
1041
+ // sentinel/commit, which this same evidence does not resolve.
1042
+ // (Incident: 1218-fo-01 — a `git apply` "patch does not apply" tool error
1043
+ // at event 179/209 was retried and succeeded 3 events later, the run
1044
+ // landed commit d1edf15, and the row was parked needs_review anyway,
1045
+ // spawning a $3.74 fix-plan investigation into work that needed no fix.)
1046
+ const groundTruthOutranksHeuristics = exitCode === 0 && commitEvidence && sentinel !== 'fail';
1047
+ if (groundTruthOutranksHeuristics) {
1048
+ for (let k = issues.length - 1; k >= 0; k--) {
1049
+ if (issues[k].verdict === 'transcript_errors' || issues[k].verdict === 'verify_unavailable') {
1050
+ annotations.push({
1051
+ verdict: issues[k].verdict,
1052
+ reason: `${issues[k].reason} (demoted: exit 0 + commit landed this run outranks transcript heuristics)`,
1053
+ });
1054
+ issues.splice(k, 1);
1055
+ }
1056
+ }
1057
+ }
1058
+
993
1059
  const sentinelFields = sentinel ? { sentinel } : {};
994
1060
  const extras = (annotations.length || sentinel)
995
1061
  ? { ...(annotations.length ? { annotations } : {}), ...sentinelFields }