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
@@ -130,4 +130,4 @@ async function seedAgentPersonas({ logger = console, writeLog = () => {} } = {})
130
130
  }
131
131
  }
132
132
 
133
- module.exports = { seedAgentPersonas, markerPath, MAX_ATTEMPTS };
133
+ module.exports = { seedAgentPersonas, markerPath, MAX_ATTEMPTS, PERSONAS };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * First-boot seeder for the bundled `session-manager-dev` plugin.
3
3
  *
4
- * The plugin (its 10 dev skills) ships inside the npx distribution. To make it
4
+ * The plugin (the dev skills under plugins/session-manager-dev/skills) ships inside the npx distribution. To make it
5
5
  * a true default, the app installs it on first launch from its own bundled
6
6
  * marketplace (offline — no GitHub/registry). Idempotent two ways:
7
7
  *
@@ -35,7 +35,7 @@ const fs = require('node:fs');
35
35
  const path = require('node:path');
36
36
  const os = require('node:os');
37
37
  const { spawn } = require('node:child_process');
38
- const { resolveClaudeBin } = require('./lib/claudeBin.cjs');
38
+ const { resolveClaudeBin, claudeSpawnTarget } = require('./lib/claudeBin.cjs');
39
39
  const { cleanChildEnv, pathWithUserBins } = require('./lib/cleanEnv.cjs');
40
40
  const { writeJsonSync } = require('./config.cjs');
41
41
 
@@ -106,13 +106,14 @@ function scriptPathMissing() {
106
106
  * No shell:true — argv array passed directly to spawn. */
107
107
  function runClaudeMcpAdd(serverPath) {
108
108
  return new Promise((resolve) => {
109
- const claudeBin = resolveClaudeBin();
109
+ const target = claudeSpawnTarget('aux', 'mcp-add');
110
110
  let proc;
111
111
  try {
112
112
  proc = spawn(
113
- claudeBin,
113
+ target.command,
114
114
  ['mcp', 'add', SERVER_NAME, '--scope', 'user', '--', 'node', serverPath],
115
115
  {
116
+ ...(target.argv0 ? { argv0: target.argv0 } : {}),
116
117
  cwd: os.homedir(),
117
118
  env: cleanChildEnv({ PATH: pathWithUserBins() }),
118
119
  stdio: 'ignore',
@@ -130,13 +131,13 @@ function runClaudeMcpAdd(serverPath) {
130
131
  /** Run `claude mcp remove session-manager-scheduler --scope user`, best-effort. */
131
132
  function runClaudeMcpRemove() {
132
133
  return new Promise((resolve) => {
133
- const claudeBin = resolveClaudeBin();
134
+ const target = claudeSpawnTarget('aux', 'mcp-remove');
134
135
  let proc;
135
136
  try {
136
137
  proc = spawn(
137
- claudeBin,
138
+ target.command,
138
139
  ['mcp', 'remove', SERVER_NAME, '--scope', 'user'],
139
- { cwd: os.homedir(), env: cleanChildEnv({ PATH: pathWithUserBins() }), stdio: 'ignore' }
140
+ { cwd: os.homedir(), env: cleanChildEnv({ PATH: pathWithUserBins() }), stdio: 'ignore', ...(target.argv0 ? { argv0: target.argv0 } : {}) }
140
141
  );
141
142
  } catch (err) {
142
143
  resolve({ ok: false, error: err?.message ?? String(err) });
@@ -43,7 +43,7 @@ const FIXES = {
43
43
  'dev-plugin': 'Open Plugins → Library and click Install next to "session-manager-dev".',
44
44
  'scheduler-mcp': () =>
45
45
  `Run in a terminal: claude mcp add ${seedSchedulerMcp.SERVER_NAME} --scope user -- node ${seedSchedulerMcp.serverScriptPath()}`,
46
- 'agent-personas': 'Copy src/seed/agents/architect.md and dev-lead.md into ~/.claude/agents/ (skip any that already exist there).',
46
+ 'agent-personas': `Copy ${seedAgentPersonas.PERSONAS.map((n) => `src/seed/agents/${n}.md`).join(', ')} into ~/.claude/agents/ (skip any that already exist there).`,
47
47
  };
48
48
 
49
49
  /** { 'dev-plugin': {status, fix}, 'scheduler-mcp': {status, fix}, 'agent-personas': {status, fix} } */
@@ -16,7 +16,8 @@ const path = require('node:path');
16
16
  const os = require('node:os');
17
17
  const { spawn, execFileSync } = require('node:child_process');
18
18
  const { ipcMain } = require('electron');
19
- const { resolveClaudeBin } = require('./lib/claudeBin.cjs');
19
+ const { resolveClaudeBin, claudeSpawnTarget } = require('./lib/claudeBin.cjs');
20
+ const { withProcRole } = require('./lib/cleanEnv.cjs');
20
21
 
21
22
  const HOME = os.homedir();
22
23
  const SUPERVISOR_LOG_PATH = path.join(HOME, '.claude', 'session-manager', 'supervisor.log');
@@ -207,7 +208,8 @@ function runProbe(claudeBin, prompt) {
207
208
  return new Promise((resolve) => {
208
209
  let child;
209
210
  try {
210
- child = spawn(claudeBin, [
211
+ const target = claudeSpawnTarget('aux', 'supervisor', claudeBin);
212
+ child = spawn(target.command, [
211
213
  '-p', prompt,
212
214
  '--model', 'claude-opus-4-7',
213
215
  '--no-session-persistence',
@@ -215,7 +217,7 @@ function runProbe(claudeBin, prompt) {
215
217
  '--max-budget-usd', '0.10',
216
218
  '--dangerously-skip-permissions',
217
219
  '--allowedTools', 'Bash',
218
- ], { stdio: ['ignore', 'pipe', 'pipe'] });
220
+ ], { env: withProcRole(process.env, 'aux'), stdio: ['ignore', 'pipe', 'pipe'], ...(target.argv0 ? { argv0: target.argv0 } : {}) });
219
221
  } catch (e) {
220
222
  console.error('[supervisor] probe spawn failed:', e?.message);
221
223
  resolve({ verdict: 'ok', action: 'none', targetPid: null, reason: `spawn failed: ${e?.message}`, costUsd: null });
@@ -23,6 +23,7 @@ const os = require('node:os');
23
23
  const { ipcMain } = require('electron');
24
24
  const { refreshIfNeeded, expiresAtMs } = require('./lib/credentials.cjs');
25
25
  const { writeJson } = require('./config.cjs');
26
+ const { createUsageCircuit, singleFlight } = require('./lib/usageCircuit.cjs');
26
27
 
27
28
  const USAGE_URL = 'https://api.anthropic.com/api/oauth/usage';
28
29
 
@@ -146,6 +147,18 @@ function classifyUsageResponse(status, bodyText) {
146
147
 
147
148
  let cache = null;
148
149
  let hydrationPromise = null;
150
+ // Retry-After suppression window: while `now < retryNotBeforeMs`, fetchUsage()
151
+ // refuses to issue another request and instead replays `lastRateLimitedResult`
152
+ // (annotated `suppressed: true`) — set only from a 429's Retry-After header.
153
+ let retryNotBeforeMs = 0;
154
+ let lastRateLimitedResult = null;
155
+
156
+ // Single shared circuit for the /api/oauth/usage meter. Both callers — the
157
+ // renderer's billing:fetch IPC handler and the scheduler's pollLoop — go
158
+ // through this same fetchUsage(), so a success recorded from EITHER caller
159
+ // clears the streak for both, and concurrent callers coalesce into one HTTP
160
+ // request via singleFlight.
161
+ const circuit = createUsageCircuit();
149
162
 
150
163
  async function hydrateCache() {
151
164
  try {
@@ -155,23 +168,17 @@ async function hydrateCache() {
155
168
  }
156
169
  }
157
170
 
171
+ function ensureHydrated() {
172
+ if (!hydrationPromise) hydrationPromise = hydrateCache();
173
+ return hydrationPromise;
174
+ }
175
+
158
176
  async function persistCache(c) {
159
177
  await writeJson(CACHE_PATH, c);
160
178
  }
161
179
 
162
- async function fetchUsage() {
163
- // Test stub: SM_MOCK_BILLING_KIND lets e2e tests simulate billing API responses
164
- // without hitting the real endpoint. Only active when SM_E2E=1 to prevent
165
- // accidental use in production.
166
- if (process.env.SM_E2E === '1' && process.env.SM_MOCK_BILLING_KIND) {
167
- const kind = process.env.SM_MOCK_BILLING_KIND;
168
- if (kind === 'meter_rate_limited') return { kind: 'meter_rate_limited', message: 'e2e stub', httpStatus: 429 };
169
- if (kind === 'transient') return { kind: 'transient', message: 'e2e stub', httpStatus: 503 };
170
- if (kind === 'auth') return { kind: 'auth', message: 'e2e stub', httpStatus: 401 };
171
- // 'ok' stub returns a minimal valid payload.
172
- return { kind: 'ok', data: { usage: { five_hour: { utilization: 10, resets_at: null }, seven_day: { utilization: 10, resets_at: null }, seven_day_sonnet: null, seven_day_opus: null, extra_usage: null }, subscriptionType: null, rateLimitTier: null, credentialsExpiresAt: null, fetchedAt: Date.now() } };
173
- }
174
-
180
+ /** The actual network round-trip, coalesced across concurrent callers below. */
181
+ async function networkFetchUsage() {
175
182
  // Check expiry and attempt proactive refresh before touching the network.
176
183
  const refresh = await refreshIfNeeded();
177
184
  if (refresh.kind === 'auth') {
@@ -181,6 +188,7 @@ async function fetchUsage() {
181
188
  // 'ok' or 'unsupported' — creds present and not yet expired
182
189
  const creds = refresh.creds;
183
190
 
191
+ let result;
184
192
  let r;
185
193
  try {
186
194
  r = await fetch(USAGE_URL, {
@@ -192,64 +200,107 @@ async function fetchUsage() {
192
200
  signal: AbortSignal.timeout(10_000),
193
201
  });
194
202
  } catch (e) {
195
- return { kind: 'transient', message: e.message || String(e), httpStatus: null };
196
- }
197
- if (r.status === 401 || r.status === 403) {
198
- const body = await r.text().catch(() => '');
199
- const ms = expiresAtMs(creds);
200
- return { kind: 'auth', message: body.slice(0, 200) || `HTTP ${r.status}`, httpStatus: r.status, expiredAt: ms };
201
- }
202
- if (r.status === 408 || r.status >= 500) {
203
- const body = await r.text().catch(() => '');
204
- return { kind: 'transient', message: body.slice(0, 200) || `HTTP ${r.status}`, httpStatus: r.status };
203
+ result = { kind: 'transient', message: e.message || String(e), httpStatus: null };
205
204
  }
206
- if (r.status === 429) {
207
- const body = await r.text().catch(() => '');
208
- let parsed = null;
209
- try { parsed = JSON.parse(body); } catch { /* */ }
210
- if (parsed?.error?.type === 'rate_limit_error') {
211
- return {
212
- kind: 'meter_rate_limited',
213
- message: body.slice(0, 200),
214
- httpStatus: 429,
215
- retryAfterMs: parseRetryAfterMs(r.headers.get('retry-after')),
205
+ if (!result) {
206
+ if (r.status === 401 || r.status === 403) {
207
+ const body = await r.text().catch(() => '');
208
+ const ms = expiresAtMs(creds);
209
+ result = { kind: 'auth', message: body.slice(0, 200) || `HTTP ${r.status}`, httpStatus: r.status, expiredAt: ms };
210
+ } else if (r.status === 408 || r.status >= 500) {
211
+ const body = await r.text().catch(() => '');
212
+ result = { kind: 'transient', message: body.slice(0, 200) || `HTTP ${r.status}`, httpStatus: r.status };
213
+ } else if (r.status === 429) {
214
+ const body = await r.text().catch(() => '');
215
+ let parsed = null;
216
+ try { parsed = JSON.parse(body); } catch { /* */ }
217
+ if (parsed?.error?.type === 'rate_limit_error') {
218
+ result = {
219
+ kind: 'meter_rate_limited',
220
+ message: body.slice(0, 200),
221
+ httpStatus: 429,
222
+ retryAfterMs: parseRetryAfterMs(r.headers.get('retry-after')),
223
+ };
224
+ } else {
225
+ result = { kind: 'transient', message: body.slice(0, 200) || 'HTTP 429', httpStatus: 429 };
226
+ }
227
+ } else if (!r.ok) {
228
+ const body = await r.text().catch(() => '');
229
+ result = { kind: 'transient', message: body.slice(0, 200) || `HTTP ${r.status}`, httpStatus: r.status };
230
+ } else {
231
+ const usage = await r.json();
232
+ result = {
233
+ kind: 'ok',
234
+ data: {
235
+ usage,
236
+ subscriptionType: creds.subscriptionType ?? null,
237
+ rateLimitTier: creds.rateLimitTier ?? null,
238
+ credentialsExpiresAt: creds.expiresAt ?? null,
239
+ fetchedAt: Date.now(),
240
+ },
216
241
  };
217
242
  }
218
- return { kind: 'transient', message: body.slice(0, 200) || 'HTTP 429', httpStatus: 429 };
219
243
  }
220
- if (!r.ok) {
221
- const body = await r.text().catch(() => '');
222
- return { kind: 'transient', message: body.slice(0, 200) || `HTTP ${r.status}`, httpStatus: r.status };
244
+
245
+ if (result.kind === 'ok') {
246
+ cache = { data: result.data, fetchedAt: Date.now(), sourceCredsExpiresAt: result.data.credentialsExpiresAt };
247
+ persistCache(cache).catch(() => {});
248
+ retryNotBeforeMs = 0;
249
+ lastRateLimitedResult = null;
250
+ circuit.recordSuccess(result.data);
251
+ } else if (result.kind === 'meter_rate_limited') {
252
+ lastRateLimitedResult = result;
253
+ if (Number.isFinite(result.retryAfterMs) && result.retryAfterMs > 0) {
254
+ retryNotBeforeMs = Date.now() + result.retryAfterMs;
255
+ }
256
+ circuit.recordFailure(result.kind);
257
+ } else if (result.kind === 'transient') {
258
+ circuit.recordFailure(result.kind);
223
259
  }
224
- const usage = await r.json();
225
- return {
226
- kind: 'ok',
227
- data: {
228
- usage,
229
- subscriptionType: creds.subscriptionType ?? null,
230
- rateLimitTier: creds.rateLimitTier ?? null,
231
- credentialsExpiresAt: creds.expiresAt ?? null,
232
- fetchedAt: Date.now(),
233
- },
234
- };
260
+ return result;
235
261
  }
236
262
 
237
- function registerBillingHandlers() {
238
- hydrationPromise = hydrateCache();
263
+ // Concurrent callers (the renderer's billing:fetch and the scheduler's
264
+ // pollLoop) coalesce into this one in-flight promise instead of each firing
265
+ // their own request against a rate-limited endpoint.
266
+ const singleFlightNetworkFetch = singleFlight(networkFetchUsage);
239
267
 
240
- ipcMain.handle('billing:fetch', async () => {
241
- if (hydrationPromise) { await hydrationPromise; hydrationPromise = null; }
268
+ /**
269
+ * The single owner of caching, single-flight de-duplication and Retry-After
270
+ * suppression for the usage meter. Every caller — renderer IPC and scheduler
271
+ * pollLoop alike — must go through this function rather than hitting the
272
+ * network or the cache file directly.
273
+ */
274
+ async function fetchUsage() {
275
+ // Test stub: SM_MOCK_BILLING_KIND lets e2e tests simulate billing API responses
276
+ // without hitting the real endpoint. Only active when SM_E2E=1 to prevent
277
+ // accidental use in production.
278
+ if (process.env.SM_E2E === '1' && process.env.SM_MOCK_BILLING_KIND) {
279
+ const kind = process.env.SM_MOCK_BILLING_KIND;
280
+ if (kind === 'meter_rate_limited') return { kind: 'meter_rate_limited', message: 'e2e stub', httpStatus: 429 };
281
+ if (kind === 'transient') return { kind: 'transient', message: 'e2e stub', httpStatus: 503 };
282
+ if (kind === 'auth') return { kind: 'auth', message: 'e2e stub', httpStatus: 401 };
283
+ // 'ok' stub returns a minimal valid payload.
284
+ return { kind: 'ok', data: { usage: { five_hour: { utilization: 10, resets_at: null }, seven_day: { utilization: 10, resets_at: null }, seven_day_sonnet: null, seven_day_opus: null, extra_usage: null }, subscriptionType: null, rateLimitTier: null, credentialsExpiresAt: null, fetchedAt: Date.now() } };
285
+ }
242
286
 
243
- if (cache && cache.fetchedAt && Date.now() - cache.fetchedAt < OK_CACHE_TTL_MS) {
244
- return { kind: 'ok', data: cache.data };
245
- }
287
+ await ensureHydrated();
288
+
289
+ if (cache && cache.fetchedAt && Date.now() - cache.fetchedAt < OK_CACHE_TTL_MS) {
290
+ return { kind: 'ok', data: cache.data };
291
+ }
292
+
293
+ if (lastRateLimitedResult && retryNotBeforeMs && Date.now() < retryNotBeforeMs) {
294
+ return { ...lastRateLimitedResult, suppressed: true };
295
+ }
296
+
297
+ return singleFlightNetworkFetch();
298
+ }
246
299
 
300
+ function registerBillingHandlers() {
301
+ ipcMain.handle('billing:fetch', async () => {
247
302
  const r = await fetchUsage();
248
- if (r.kind === 'ok') {
249
- cache = { data: r.data, fetchedAt: Date.now(), sourceCredsExpiresAt: r.data.credentialsExpiresAt };
250
- persistCache(cache).catch(() => {});
251
- return { kind: 'ok', data: r.data };
252
- }
303
+ if (r.kind === 'ok') return { kind: 'ok', data: r.data };
253
304
  if (r.kind === 'auth') {
254
305
  if (cache) return { kind: 'auth', message: r.message, httpStatus: r.httpStatus, expiredAt: r.expiredAt, cached: cache.data, staleSince: cache.fetchedAt };
255
306
  return r;
@@ -259,11 +310,24 @@ function registerBillingHandlers() {
259
310
  return r;
260
311
  }
261
312
  if (r.kind === 'meter_rate_limited') {
262
- if (cache) return { kind: 'meter_rate_limited', message: r.message, httpStatus: r.httpStatus, retryAfterMs: r.retryAfterMs, cached: cache.data, staleSince: cache.fetchedAt };
313
+ if (cache) return { kind: 'meter_rate_limited', message: r.message, httpStatus: r.httpStatus, retryAfterMs: r.retryAfterMs, suppressed: r.suppressed, cached: cache.data, staleSince: cache.fetchedAt };
263
314
  return r;
264
315
  }
265
316
  return r; // config
266
317
  });
267
318
  }
268
319
 
269
- module.exports = { registerBillingHandlers, fetchUsage, classifyUsageResponse, parseRetryAfterMs, usageMeterApplicable, readClaudeSettingsAuth };
320
+ module.exports = {
321
+ registerBillingHandlers,
322
+ fetchUsage,
323
+ classifyUsageResponse,
324
+ parseRetryAfterMs,
325
+ usageMeterApplicable,
326
+ readClaudeSettingsAuth,
327
+ // The single shared breaker instance — scheduler.cjs's pollLoop (and every
328
+ // other consumer) reads THIS object's state()/openedAt()/
329
+ // getConsecutiveFailures() rather than deriving its own, so a failure
330
+ // recorded via any path (poller, executor 429) opens the same circuit.
331
+ usageCircuit: circuit,
332
+ __usageCircuitForTest: circuit,
333
+ };
@@ -356,22 +356,23 @@ export interface DelegationReadinessCheck {
356
356
  | 'agent-personas'
357
357
  | 'prd-write-guard'
358
358
  | 'destructive-git-guard'
359
- | 'inline-implementation-guard';
359
+ | 'inline-implementation-guard'
360
+ | 'self-schedule-guard';
360
361
  label: string;
361
362
  ok: boolean;
362
363
  detail: string;
363
364
  fix: string | null;
364
365
  /** Non-null when Session Manager can install this fix itself, one press. */
365
- fixAction: 'install-prd-write-guard' | 'install-destructive-git-guard' | 'install-inline-implementation-guard' | null;
366
+ fixAction: 'install-prd-write-guard' | 'install-destructive-git-guard' | 'install-inline-implementation-guard' | 'install-self-schedule-guard' | null;
366
367
  /** True when ok:true is a WARNING (still passing, but worth a human's attention) — today only scheduler-mcp-project-duplicate. */
367
368
  warn?: boolean;
368
369
  /** True when this check didn't run because a precondition (another check) already failed — reported ok:true, not a failure. */
369
370
  skipped?: boolean;
370
371
  }
371
372
 
372
- /** Result of installPrdWriteGuard, installDestructiveGitGuard, and
373
- * installInlineImplementationGuard alike (delegationReadiness.cjs) — the
374
- * three installers share one contract. */
373
+ /** Result of installPrdWriteGuard, installDestructiveGitGuard,
374
+ * installInlineImplementationGuard, and installSelfScheduleGuard alike
375
+ * (delegationReadiness.cjs) — all four installers share one contract. */
375
376
  export interface InstallGuardResult {
376
377
  ok: boolean;
377
378
  action: 'installed' | 'repaired' | 'already-installed' | 'error';
@@ -658,13 +659,6 @@ export interface ScheduleJobStatusHistoryEntry {
658
659
  at: string;
659
660
  }
660
661
 
661
- export interface SchedulePaths {
662
- root: string;
663
- prds: string;
664
- runs: string;
665
- queue: string;
666
- }
667
-
668
662
  export type SchedulePauseReason = 'rate_limit' | 'auth' | 'network' | 'manual' | 'reset_failure';
669
663
 
670
664
  export interface SchedulePauseInfo {
@@ -858,8 +852,6 @@ export interface ScheduleStateSnapshot {
858
852
  * is saturated. Null before the first tick that evaluated it.
859
853
  */
860
854
  loadGate?: ScheduleLoadGate | null;
861
- /** Returned only by the initial state() call, not the broadcast event. */
862
- paths?: SchedulePaths;
863
855
  }
864
856
 
865
857
  export interface ScheduleLoadGate {
@@ -1081,26 +1073,6 @@ export interface WatcherClosedEvent {
1081
1073
  watcherId: string;
1082
1074
  }
1083
1075
 
1084
- export interface TeamMember {
1085
- name: string;
1086
- agentType: string | null;
1087
- model: string | null;
1088
- }
1089
-
1090
- export interface TeamInfo {
1091
- name: string;
1092
- configPath: string;
1093
- description: string | null;
1094
- leadAgentId: string | null;
1095
- members: TeamMember[];
1096
- memberCount: number;
1097
- inboxDepth: number;
1098
- }
1099
-
1100
- export interface TeamsListResult {
1101
- teams: TeamInfo[];
1102
- }
1103
-
1104
1076
  // ────────────────────────────────────────────── Bundle D — queue ops
1105
1077
 
1106
1078
  export interface LintFinding {
@@ -1297,29 +1269,12 @@ export type ProjectBriefUpdateResult =
1297
1269
  | { ok: true; brief: ProjectBrief }
1298
1270
  | { ok: false; error: string };
1299
1271
 
1300
- // ────────────────────────────────────────────── Project Pages (PRD 929-932, 969, project-home-hosted-html-spec)
1301
- export interface ProjectPagesOutput {
1302
- home: string;
1303
- /** Absent when `isDefault` is true — the shipped default only covers the home lens. */
1304
- marketing?: string;
1305
- /** Absent when `isDefault` is true — the shipped default only covers the home lens. */
1306
- feature?: string;
1307
- /** Absent when `isDefault` is true — the shipped default only covers the home lens. */
1308
- architecture?: string;
1309
- /** Absent for output generated before the 'brief' lens existed (PRD 969), or
1310
- * when `isDefault` is true — a project must regenerate to pick it up. */
1311
- brief?: string;
1312
- /** null for the shipped default (never generated). */
1313
- generatedAt: string | null;
1314
- /** True when `home` is the build-time shipped default, not this project's own
1315
- * generated output — the renderer must label provenance rather than infer it. */
1316
- isDefault: boolean;
1317
- }
1318
-
1272
+ // ────────────────────────────────────────────── Project Pages (single home.html)
1319
1273
  export interface ProjectPagesGetResult {
1320
- /** Never null in practice — a project with no generated output still gets the
1321
- * shipped default (isDefault: true). The type stays nullable defensively. */
1322
- output: ProjectPagesOutput | null;
1274
+ /** Contents of session-manager-operations/project-pages/home.html, or null when it has not been generated. */
1275
+ html: string | null;
1276
+ /** home.html's mtime, or null when `html` is null. */
1277
+ mtimeMs: number | null;
1323
1278
  }
1324
1279
 
1325
1280
  // ────────────────────────────────────────────── Host on Bilko.run
@@ -1593,7 +1548,8 @@ export interface SessionManagerAPI {
1593
1548
  gitBranch: (cwd: string) => Promise<string | null>;
1594
1549
  /** Publish target for 'build'-tagged Epics — null disables the Build toolbar button. */
1595
1550
  resolveBuildTarget: (cwd: string) => Promise<BuildTarget | null>;
1596
- rebootApp: () => void;
1551
+ /** Default: request a drain-first restart. `force: true` restarts immediately, killing running jobs. */
1552
+ rebootApp: (opts?: { force?: boolean }) => void;
1597
1553
  testFireHook: (args: TestFireHookArgs) => Promise<TestFireHookResult>;
1598
1554
  /** F7 — true under SM_E2E=1; renderer uses this to suppress wizard auto-trigger. */
1599
1555
  isE2E: () => Promise<boolean>;
@@ -1615,6 +1571,7 @@ export interface SessionManagerAPI {
1615
1571
  installPrdWriteGuard: (cwd: string) => Promise<InstallGuardResult>;
1616
1572
  installDestructiveGitGuard: (cwd: string) => Promise<InstallGuardResult>;
1617
1573
  installInlineImplementationGuard: (cwd: string) => Promise<InstallGuardResult>;
1574
+ installSelfScheduleGuard: (cwd: string) => Promise<InstallGuardResult>;
1618
1575
  onNewSession: (handler: () => void) => () => void;
1619
1576
  onRebootSession: (handler: () => void) => () => void;
1620
1577
  archiveProject: (encoded: string) => Promise<{ ok: boolean; error?: string }>;
@@ -1832,6 +1789,7 @@ export interface SessionManagerAPI {
1832
1789
  resetJob: (slug: string) => Promise<{ ok: boolean; error?: string }>;
1833
1790
  runNow: () => Promise<{ ok: boolean }>;
1834
1791
  forceTick: () => Promise<ActionOutcome>;
1792
+ pause: () => Promise<{ ok: boolean }>;
1835
1793
  resume: () => Promise<{ ok: boolean }>;
1836
1794
  /** Re-scan prds/ and merge into queue.json; broadcasts updated state. */
1837
1795
  rescan: () => Promise<ActionOutcome>;
@@ -1875,10 +1833,6 @@ export interface SessionManagerAPI {
1875
1833
  /** Return last 50 supervisor log entries, descending by ts. */
1876
1834
  getLog: () => Promise<SupervisorLogEntry[]>;
1877
1835
  };
1878
- teams: {
1879
- /** Enumerate ~/.claude/teams/<name>/config.json + inbox depths. */
1880
- list: () => Promise<TeamsListResult>;
1881
- };
1882
1836
  plugins: {
1883
1837
  /** Run `claude plugin install <slug>` in a hidden pty. Streams output
1884
1838
  * via `onInstallProgress`. Returns { ok, exitCode } on exit.
@@ -1936,14 +1890,14 @@ export interface SessionManagerAPI {
1936
1890
  update: (cwd: string, patch: ProjectBriefPatch) => Promise<ProjectBriefUpdateResult>;
1937
1891
  };
1938
1892
  projectPages: {
1939
- /** Read output/*.html + manifest.json (or `{output: null}` if none exist yet). Never fires an LLM call. */
1893
+ /** Read project-pages/home.html (`{html: null, mtimeMs: null}` if it does not exist yet). Never fires an LLM call. */
1940
1894
  get: (cwd: string) => Promise<ProjectPagesGetResult>;
1941
1895
  /** Start pushing `onChanged` events for this cwd's output dir. Refcounted per cwd; `ok:false` (reason 'ephemeral'|'invalid-cwd') means no live updates are possible, not an error. */
1942
1896
  watch: (cwd: string) => Promise<{ ok: boolean; reason?: 'ephemeral' | 'invalid-cwd' }>;
1943
1897
  /** Stop pushing `onChanged` events for this cwd — must be paired 1:1 with a prior `watch` call. */
1944
1898
  unwatch: (cwd: string) => Promise<{ ok: boolean }>;
1945
- /** Fires whenever a watched cwd's project-pages output dir changes, carrying the freshly recomputed output. */
1946
- onChanged: (handler: (payload: { cwd: string; output: ProjectPagesOutput | null }) => void) => () => void;
1899
+ /** Fires whenever a watched cwd's home.html is added/changed/removed, carrying the freshly read result. */
1900
+ onChanged: (handler: (payload: { cwd: string } & ProjectPagesGetResult) => void) => () => void;
1947
1901
  };
1948
1902
  bilkoHost: {
1949
1903
  /** Read compatibility-gate inputs + any existing bundle/publish state. Never fires an LLM call. */
@@ -9,7 +9,7 @@ contextBridge.exposeInMainWorld('api', {
9
9
  pickDirectory: () => ipcRenderer.invoke('app:pick-directory'),
10
10
  gitBranch: (cwd) => ipcRenderer.invoke('app:git-branch', { cwd }),
11
11
  resolveBuildTarget: (cwd) => ipcRenderer.invoke('build:resolve-target', { cwd }),
12
- rebootApp: () => ipcRenderer.send('app:reboot-app'),
12
+ rebootApp: (opts) => ipcRenderer.send('app:reboot-app', opts),
13
13
  archiveProject: (encoded) => ipcRenderer.invoke('app:archive-project', { encoded }),
14
14
  testFireHook: (args) => ipcRenderer.invoke('app:test-fire-hook', args),
15
15
  // F7: lets the renderer suppress the wizard auto-trigger under SM_E2E=1.
@@ -236,6 +236,7 @@ contextBridge.exposeInMainWorld('api', {
236
236
  resetJob: (slug) => ipcRenderer.invoke('schedule:reset-job', { slug }),
237
237
  runNow: () => ipcRenderer.invoke('schedule:run-now'),
238
238
  forceTick: () => ipcRenderer.invoke('schedule:force-tick'),
239
+ pause: () => ipcRenderer.invoke('schedule:pause'),
239
240
  resume: () => ipcRenderer.invoke('schedule:resume'),
240
241
  rescan: () => ipcRenderer.invoke('schedule:rescan'),
241
242
  clearQueue: () => ipcRenderer.invoke('schedule:clear-queue'),
@@ -281,9 +282,6 @@ contextBridge.exposeInMainWorld('api', {
281
282
  tickNow: () => ipcRenderer.invoke('supervisor:tick-now'),
282
283
  getLog: () => ipcRenderer.invoke('supervisor:get-log'),
283
284
  },
284
- teams: {
285
- list: () => ipcRenderer.invoke('teams:list'),
286
- },
287
285
  plugins: {
288
286
  install: (payload) => ipcRenderer.invoke('plugins:install', payload),
289
287
  abort: (slug) => ipcRenderer.invoke('plugins:abort', slug),
@@ -1,59 +1,42 @@
1
1
  ---
2
2
  name: project-home-builder
3
- description: Generates a project's 5 static Project Page HTML files (Home / Marketing Landing / Feature Description / Architecture Overview / Brief) by following the session-manager app's own MCP contract for the pipeline — portable to any machine with the app installed, no source-repo paths required.
3
+ description: Reads a project and writes ONE self-contained overview page (home.html) for its Project Home tab, then saves it with a single project_home_write call.
4
4
  tools: Read, Grep, Glob, Bash, Write, Edit
5
- title: Project Pages — Builder
5
+ title: Project Home — Builder
6
6
  ---
7
7
 
8
- You are the project-home-builder. Your whole job is to generate a project's Project Home pages by
9
- following the exact protocol the session-manager app hands you over MCP — never by re-deriving the
10
- pipeline from a repo you may not have, and never by inventing content.
11
-
12
- ## Ground on the live contract, every run
13
-
14
- 1. Call `project_home_get_contract` FIRST, before composing or reading anything else. It returns
15
- everything you need: the operating protocol, the `ProjectPageSummary`/`ProjectPagePicks` JSON
16
- schemas, the full component catalog for every lens (which slots exist, which variants are
17
- available per slot, and each variant's own selection notes), the exact output paths, and the
18
- full pipeline spec text.
19
- 2. Follow the protocol the contract response describes. It is the single source of truth for this
20
- run — do not fall back to a remembered or assumed version of the pipeline shape.
21
- 3. If `project_home_get_contract` is unavailable, errors, or the MCP tools it depends on
22
- (`project_home_validate_summary`, `project_home_render`, `project_home_status`) are not present
23
- in this session's toolset: **report that plainly and stop.** Do not attempt to build, script, or
24
- hand-roll any part of the pipeline yourself, and do not treat the missing contract as a coding
25
- task for this Epic. The pipeline is owned by the session-manager app, not by the target project.
8
+ You are the project-home-builder. Your whole job is to read the real project and produce a single
9
+ self-contained HTML overview page, then hand it to the app with one `project_home_write` call.
10
+
11
+ ## What the page is
12
+
13
+ One overview page for a person opening this project for the first time. It covers:
14
+
15
+ - **What it is** — a one- or two-sentence description of the project.
16
+ - **Who it's for** — the audience or user the project serves.
17
+ - **Structure** — the main directories/modules and what each one does.
18
+ - **How to run it** — the real install / build / start steps.
19
+ - **Key commands** — the commands a contributor actually uses (test, lint, build, etc.).
26
20
 
27
21
  ## Hard rules
28
22
 
29
- - **Never fabricate.** Every field of the summary you author must trace to something concrete about
30
- the real project: an Epic goal, a source file/dir, a documented convention, a git log entry, or an
31
- existing project brief. An omitted field beats an invented one, every time — no invented stats, no
32
- invented testimonials/quotes, no invented screenshots.
33
- - **Author the summary from real evidence.** Read the target project itself (its repo tree, its git
34
- history, its own docs/brief, its active Epics) to build the `ProjectPageSummary` the contract's
35
- schema describes — the contract gives you the shape, not the content.
36
- - **Validate before you render.** Call `project_home_validate_summary` with your composed summary
37
- and fix every returned `{field, message}` error, re-validating until it reports `valid: true`.
38
- Don't skip straight to rendering an unvalidated summary.
39
- - **Choose picks from the returned catalog only.** For every lens/slot the contract's catalog lists,
40
- pick the one variant that genuinely fits this project's summary content, using the catalog's own
41
- per-variant notes — never a variant name you assumed instead of one the catalog actually offered.
42
- - **Respect existing picks on a regenerate.** If the project already has picks for a slot, keep them
43
- unless this run was explicitly asked to start over — same spirit as any other pinned-content
44
- regenerate.
45
- - **Cost-gated, manual only.** This is a real-cost pass. Run it once per explicit "Generate" /
46
- "Regenerate" request — never automatically, never in a loop.
23
+ - **Never fabricate.** Every claim must trace to something you read in the project: its README,
24
+ manifest (`package.json`, `pyproject.toml`, ...), source tree, docs, or git history. An omitted
25
+ section beats an invented one — no invented stats, quotes, screenshots, or features.
26
+ - **Read before you write.** Explore the repo itself (tree, manifest, docs, recent git log) first.
27
+ - **Self-contained HTML only.** One complete HTML document with all CSS inline in a `<style>` block.
28
+ No `<script src>`, no `<link href="http...">`, no `@import`, no `url(http...)`, no external fonts
29
+ or images. Keep it under 1 MB. Support both light and dark color schemes.
30
+ - **Cost-gated, manual only.** Run once per explicit "Generate" / "Regenerate" request — never
31
+ automatically, never in a loop.
47
32
 
48
33
  ## Protocol
49
34
 
50
- 1. `project_home_get_contract` — read its protocol, schemas, and catalog before anything else.
51
- 2. Gather real evidence about the target project and compose a `ProjectPageSummary` matching the
52
- contract's schema.
53
- 3. `project_home_validate_summary` with that summary — fix and repeat until `valid: true`.
54
- 4. Choose one variant per lens/slot from the contract's catalog, forming a `ProjectPagePicks` object
55
- in the shape the contract specifies.
56
- 5. `project_home_render` with the validated summary and the picks — this is the only write path;
57
- it re-validates server-side and writes nothing on schema failure.
58
- 6. `project_home_status` — confirm the expected files now exist with a fresh `generatedAt`, and
59
- report what was generated.
35
+ 1. Read the project: manifest, README/docs, directory structure, key scripts, recent commits.
36
+ 2. Compose the single HTML document described above.
37
+ 3. Call `project_home_write` exactly once with `{ html }`. It validates the document and writes it as
38
+ the project's Project Home page.
39
+ 4. If the tool rejects the HTML, fix the reported problem and call it again; if
40
+ `project_home_write` is unavailable in this session, report that plainly and stop — do not build
41
+ any tooling in the target project as a workaround.
42
+ 5. Report in one or two lines what the page covers.
File without changes