claude-code-session-manager 0.98.0 → 0.100.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 (431) hide show
  1. package/README.md +3 -3
  2. package/bin/cli.cjs +16 -4
  3. package/bin/node-floor.cjs +41 -0
  4. package/dist/assets/{DataModel-DCEgMTjH.js → DataModel-HdR0AxFq.js} +1 -1
  5. package/dist/assets/{History-Bfdoywlh.js → History-Dr4Jr_5z.js} +2 -2
  6. package/dist/assets/{Hooks-CKDJjTJV.js → Hooks-NhrvH3JP.js} +3 -3
  7. package/dist/assets/{Library-7akfgy67.js → Library-Dv_EtIMr.js} +1 -1
  8. package/dist/assets/{MarkdownEditor-DDesiqet.js → MarkdownEditor-DTKDWV_n.js} +1 -1
  9. package/dist/assets/{McpServers-D4lZtXof.js → McpServers-M034G9B3.js} +2 -2
  10. package/dist/assets/{Memory-CeI8G1w5.js → Memory-DzF1B4gx.js} +6 -6
  11. package/dist/assets/{Permissions-BGleLja4.js → Permissions-DrgbSGWl.js} +3 -3
  12. package/dist/assets/{Plugins-P4eCXy_S.js → Plugins-Bd3ef35w.js} +2 -2
  13. package/dist/assets/{ProvenanceBadge-BFczzI1B.js → ProvenanceBadge-DcBHT1Iy.js} +1 -1
  14. package/dist/assets/{SaveBar-l9jnEMES.js → SaveBar-rimJem-Y.js} +1 -1
  15. package/dist/assets/Scheduler-DjgFJl2w.js +16 -0
  16. package/dist/assets/{ScopeSwitcher-CjJi8ST5.js → ScopeSwitcher-CnAzTBrl.js} +1 -1
  17. package/dist/assets/Settings-Dc1F_sSg.js +3 -0
  18. package/dist/assets/{SkillReferenceGraph-CjbO01Sg.js → SkillReferenceGraph-B9aZDecM.js} +1 -1
  19. package/dist/assets/{Skills-BxZ9_fCR.js → Skills-DRXd18gu.js} +2 -2
  20. package/dist/assets/{SystemPrompt-D8vfFb8b.js → SystemPrompt-ahy5-Fwe.js} +1 -1
  21. package/dist/assets/{TagLibrary-2vzUo7YL.js → TagLibrary-C_tToDeL.js} +1 -1
  22. package/dist/assets/{TiptapBody-B8ZfbK90.js → TiptapBody-DvdefS6K.js} +1 -1
  23. package/dist/assets/{Toggle-BbW4nGGf.js → Toggle-6Jl5Njc6.js} +1 -1
  24. package/dist/assets/{index-CKH5Uxik.css → index-Bta-hwud.css} +1 -1
  25. package/dist/assets/{index-Cd98Q1lD.js → index-vx8O73l8.js} +497 -502
  26. package/dist/assets/{settingsSchema-IhUfucCF.js → settingsSchema-D6iRguNV.js} +1 -1
  27. package/dist/index.html +2 -2
  28. package/package.json +25 -29
  29. package/plugins/CLAUDE.md +6 -6
  30. package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +21 -19
  31. package/plugins/session-manager-dev/skills/builder/SKILL.md +3 -3
  32. package/plugins/session-manager-dev/skills/develop/SKILL.md +254 -510
  33. package/plugins/session-manager-dev/skills/develop/standards.md +17 -22
  34. package/scripts/README.md +3 -11
  35. package/scripts/audit-ops-hygiene.cjs +3 -3
  36. package/scripts/hooks/lib/guard-prd-writes-policy.cjs +1 -1
  37. package/scripts/hooks/lib/guard-self-schedule-policy.cjs +1 -1
  38. package/scripts/mint-epic.cjs +2 -3
  39. package/scripts/scheduler-mcp-server.cjs +36 -7
  40. package/src/main/agentLibrary.cjs +22 -2
  41. package/src/main/build-info.json +4 -4
  42. package/src/main/config.cjs +41 -38
  43. package/src/main/docEdit.cjs +4 -1
  44. package/src/main/files.cjs +2 -5
  45. package/src/main/health.cjs +1 -1
  46. package/src/main/index.cjs +23 -10
  47. package/src/main/ipcSchemas.cjs +28 -35
  48. package/src/main/lib/agentPersonaSchema.cjs +13 -2
  49. package/src/main/lib/atomicFs.cjs +116 -0
  50. package/src/main/lib/branchSweep.cjs +13 -12
  51. package/src/main/lib/buildTarget.cjs +3 -3
  52. package/src/main/lib/claudeCliCaps.cjs +129 -0
  53. package/src/main/lib/credentials.cjs +2 -4
  54. package/src/main/lib/crossProjectFeedback.cjs +3 -3
  55. package/src/main/lib/cwdClassify.cjs +15 -3
  56. package/src/main/lib/definitionOfDone.cjs +207 -125
  57. package/src/main/lib/dodDrainHook.cjs +11 -5
  58. package/src/main/lib/epicMint.cjs +2 -4
  59. package/src/main/lib/epicStatusMirror.cjs +8 -10
  60. package/src/main/lib/epicWorktreeProjectConfig.cjs +2 -4
  61. package/src/main/lib/gateAuthority.cjs +96 -0
  62. package/src/main/lib/gitExec.cjs +69 -0
  63. package/src/main/lib/gitWorktree.cjs +656 -92
  64. package/src/main/lib/instanceLock.cjs +5 -8
  65. package/src/main/lib/launchFailure.cjs +2 -3
  66. package/src/main/lib/macroLibrary.cjs +386 -0
  67. package/src/main/lib/mcpToolCatalog.cjs +26 -17
  68. package/src/main/lib/needsReviewLedger.cjs +1 -1
  69. package/src/main/lib/opsErrorLog.cjs +11 -1
  70. package/src/main/lib/opsOwnership.cjs +0 -5
  71. package/src/main/lib/pidAlive.cjs +32 -0
  72. package/src/main/lib/prdCreate.cjs +121 -12
  73. package/src/main/lib/prdDisposition.cjs +2 -2
  74. package/src/main/lib/prdGateFiles.cjs +284 -0
  75. package/src/main/lib/prdLocations.cjs +61 -0
  76. package/src/main/lib/prdMigration.cjs +2 -3
  77. package/src/main/lib/prdSizing.cjs +2 -1
  78. package/src/main/lib/promptSessionSchema.cjs +10 -2
  79. package/src/main/lib/rcaReport.cjs +4 -6
  80. package/src/main/lib/reaperHelpers.cjs +8 -1
  81. package/src/main/lib/reservationExpiry.cjs +6 -1
  82. package/src/main/lib/reviewNotice.cjs +263 -0
  83. package/src/main/lib/runClaudeP.cjs +4 -1
  84. package/src/main/lib/schedulerPaths.cjs +22 -2
  85. package/src/main/lib/sessionSlots.cjs +2 -4
  86. package/src/main/lib/shippedPersonaSeeds.cjs +179 -0
  87. package/src/main/lib/timeoutShim.cjs +123 -0
  88. package/src/main/lib/timeoutShimScript.cjs +275 -0
  89. package/src/main/lib/upgradeDrain.cjs +4 -10
  90. package/src/main/lib/watchdogHelpers.cjs +12 -25
  91. package/src/main/lib/workTypeLibrary.cjs +7 -1
  92. package/src/main/promptSessionEvents.cjs +37 -13
  93. package/src/main/scheduler.cjs +910 -198
  94. package/src/main/seedAgentPersonas.cjs +278 -23
  95. package/src/main/supervisor.cjs +4 -1
  96. package/src/main/templates/PRD_AUTHORING.md +126 -406
  97. package/src/preload/__tests__/preload-surface.test.cjs +68 -0
  98. package/src/preload/api.d.ts +41 -94
  99. package/src/preload/index.cjs +14 -9
  100. package/src/seed/agents/architect.md +1 -0
  101. package/src/seed/agents/dev-lead.md +17 -18
  102. package/src/seed/agents/project-home-builder.md +1 -0
  103. package/src/seed/agents/validator.md +10 -4
  104. package/dist/assets/HostBilko-CDVHE0hT.js +0 -1
  105. package/dist/assets/Scheduler-C_phpeUS.js +0 -16
  106. package/dist/assets/Settings-BIwZ3FGQ.js +0 -3
  107. package/src/main/__tests__/activeIndexMerge.test.cjs +0 -235
  108. package/src/main/__tests__/agentEffortResolve.test.cjs +0 -117
  109. package/src/main/__tests__/agentLibrary.test.cjs +0 -276
  110. package/src/main/__tests__/agentModelResolve.test.cjs +0 -311
  111. package/src/main/__tests__/agentOverlayWrite.test.cjs +0 -95
  112. package/src/main/__tests__/bilkoHost-deriveSlug.test.cjs +0 -26
  113. package/src/main/__tests__/bilkoHost-integration.test.cjs +0 -118
  114. package/src/main/__tests__/bilkoHostCore.test.cjs +0 -72
  115. package/src/main/__tests__/broadcastCoalescer.test.cjs +0 -122
  116. package/src/main/__tests__/chat-cancel-terminal.test.cjs +0 -120
  117. package/src/main/__tests__/chat-dead-channels.test.cjs +0 -63
  118. package/src/main/__tests__/chat-exit-close-race.test.cjs +0 -146
  119. package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +0 -139
  120. package/src/main/__tests__/chat-preamble-anchors.test.cjs +0 -100
  121. package/src/main/__tests__/chat-queue.test.cjs +0 -97
  122. package/src/main/__tests__/chat-stop-signal.test.cjs +0 -89
  123. package/src/main/__tests__/chatRunner-epic-worktree-execcwd.test.cjs +0 -125
  124. package/src/main/__tests__/chatRunner-session-flag-retry.test.cjs +0 -252
  125. package/src/main/__tests__/classifyPromptTicket.test.cjs +0 -101
  126. package/src/main/__tests__/classifyTranscriptLine.test.cjs +0 -201
  127. package/src/main/__tests__/computeDepHistorySatisfaction.test.cjs +0 -66
  128. package/src/main/__tests__/config-readText-bounded.test.cjs +0 -84
  129. package/src/main/__tests__/configWriteBoundaryOwners.test.cjs +0 -59
  130. package/src/main/__tests__/crossProjectFeedback.test.cjs +0 -334
  131. package/src/main/__tests__/crossProjectFeedbackRoutes.test.cjs +0 -161
  132. package/src/main/__tests__/dep-orphan-archive-health.test.cjs +0 -77
  133. package/src/main/__tests__/develop-skill-failure-modes.test.cjs +0 -70
  134. package/src/main/__tests__/docEdit.test.cjs +0 -244
  135. package/src/main/__tests__/dod-batchkey.test.cjs +0 -183
  136. package/src/main/__tests__/dod-drain-hook.test.cjs +0 -302
  137. package/src/main/__tests__/dod-report.test.cjs +0 -304
  138. package/src/main/__tests__/dod-reverify.test.cjs +0 -285
  139. package/src/main/__tests__/epicContextDigest.test.cjs +0 -174
  140. package/src/main/__tests__/epicMint.test.cjs +0 -332
  141. package/src/main/__tests__/epicMintTelemetryTap.test.cjs +0 -64
  142. package/src/main/__tests__/epicStatusMirror.test.cjs +0 -110
  143. package/src/main/__tests__/epicValidationHook.test.cjs +0 -291
  144. package/src/main/__tests__/exchanges.test.cjs +0 -122
  145. package/src/main/__tests__/exchangesPromptId.test.cjs +0 -61
  146. package/src/main/__tests__/extractJson.test.cjs +0 -51
  147. package/src/main/__tests__/files-reject-credentials.test.cjs +0 -40
  148. package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +0 -556
  149. package/src/main/__tests__/flatPrdTickSweep.test.cjs +0 -110
  150. package/src/main/__tests__/health-build-freshness.test.cjs +0 -39
  151. package/src/main/__tests__/health-claude-md-budget.test.cjs +0 -57
  152. package/src/main/__tests__/health-credentials.test.cjs +0 -81
  153. package/src/main/__tests__/health-delegation-chain.test.cjs +0 -124
  154. package/src/main/__tests__/health-per-project-stall.test.cjs +0 -84
  155. package/src/main/__tests__/health-prd-migration.test.cjs +0 -37
  156. package/src/main/__tests__/health-queue-dispatch.test.cjs +0 -135
  157. package/src/main/__tests__/health-starve-escalation.test.cjs +0 -94
  158. package/src/main/__tests__/health-tick-liveness.test.cjs +0 -179
  159. package/src/main/__tests__/health-usage-poller.test.cjs +0 -144
  160. package/src/main/__tests__/health-worktree-cap-blocked.test.cjs +0 -65
  161. package/src/main/__tests__/heapSnapshot.test.cjs +0 -121
  162. package/src/main/__tests__/historyAggregatorIntraday.test.cjs +0 -313
  163. package/src/main/__tests__/historyDashboard.test.cjs +0 -163
  164. package/src/main/__tests__/historyRollup.test.cjs +0 -333
  165. package/src/main/__tests__/intradayRefresh.test.cjs +0 -39
  166. package/src/main/__tests__/ipcSchemas-dependsOn.test.cjs +0 -39
  167. package/src/main/__tests__/kg-augment.test.cjs +0 -195
  168. package/src/main/__tests__/loadGateDetailTick.test.cjs +0 -31
  169. package/src/main/__tests__/machineProfile.test.cjs +0 -152
  170. package/src/main/__tests__/mcpStatus.test.cjs +0 -61
  171. package/src/main/__tests__/memoryAggregate.test.cjs +0 -109
  172. package/src/main/__tests__/memoryStale.test.cjs +0 -88
  173. package/src/main/__tests__/needsReviewLedger.test.cjs +0 -162
  174. package/src/main/__tests__/openExternalApp-spawn-error.test.cjs +0 -25
  175. package/src/main/__tests__/opsErrorLog.test.cjs +0 -109
  176. package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +0 -173
  177. package/src/main/__tests__/personaMerge.test.cjs +0 -169
  178. package/src/main/__tests__/planValidator.test.cjs +0 -125
  179. package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +0 -176
  180. package/src/main/__tests__/prd-group-allocator.test.cjs +0 -119
  181. package/src/main/__tests__/prdAdminRouteParity.test.cjs +0 -70
  182. package/src/main/__tests__/prdAdminRoutes.test.cjs +0 -718
  183. package/src/main/__tests__/prdAgentType.test.cjs +0 -103
  184. package/src/main/__tests__/prdAuthoringSeed.test.cjs +0 -39
  185. package/src/main/__tests__/prdCreate.test.cjs +0 -979
  186. package/src/main/__tests__/prdCreateAdoption.test.cjs +0 -205
  187. package/src/main/__tests__/prdCreateDisposition.test.cjs +0 -201
  188. package/src/main/__tests__/prdCreatePlanId.test.cjs +0 -132
  189. package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +0 -117
  190. package/src/main/__tests__/prdFrontmatterDependsOn.test.cjs +0 -136
  191. package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +0 -125
  192. package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +0 -108
  193. package/src/main/__tests__/prdLocations.test.cjs +0 -195
  194. package/src/main/__tests__/prdLocationsArchived.test.cjs +0 -201
  195. package/src/main/__tests__/prdMigration.test.cjs +0 -349
  196. package/src/main/__tests__/prdMigrationLegacyAdopt.test.cjs +0 -91
  197. package/src/main/__tests__/prdParserHighWater.test.cjs +0 -74
  198. package/src/main/__tests__/prdParserSourcePromptId.test.cjs +0 -65
  199. package/src/main/__tests__/prdSetDisposition.test.cjs +0 -222
  200. package/src/main/__tests__/prdSizing.test.cjs +0 -106
  201. package/src/main/__tests__/prdSourcePromptIdBackfill.test.cjs +0 -118
  202. package/src/main/__tests__/prdUpdateDependsOn.test.cjs +0 -160
  203. package/src/main/__tests__/proc-role-env.test.cjs +0 -125
  204. package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +0 -304
  205. package/src/main/__tests__/procname-sm-processes.test.cjs +0 -127
  206. package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +0 -177
  207. package/src/main/__tests__/projectPages.test.cjs +0 -137
  208. package/src/main/__tests__/promptSessionEvents.test.cjs +0 -234
  209. package/src/main/__tests__/promptSessionSchema.test.cjs +0 -101
  210. package/src/main/__tests__/promptSessionTranscript.test.cjs +0 -0
  211. package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +0 -159
  212. package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +0 -282
  213. package/src/main/__tests__/pty-session-open-telemetry.test.cjs +0 -96
  214. package/src/main/__tests__/pty-write-result.test.cjs +0 -46
  215. package/src/main/__tests__/queue-health-verdict.test.cjs +0 -170
  216. package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +0 -286
  217. package/src/main/__tests__/queue-starvation-per-project.test.cjs +0 -147
  218. package/src/main/__tests__/queueHistory.test.cjs +0 -355
  219. package/src/main/__tests__/queueOps-interactive-ac-lint.test.cjs +0 -65
  220. package/src/main/__tests__/queueOpsArchiveDestination.test.cjs +0 -65
  221. package/src/main/__tests__/queueOpsAutoArchive.test.cjs +0 -211
  222. package/src/main/__tests__/rateLimitPollerStreak.test.cjs +0 -128
  223. package/src/main/__tests__/rcaReport.test.cjs +0 -266
  224. package/src/main/__tests__/reconcileFlatPrdSweep.test.cjs +0 -119
  225. package/src/main/__tests__/reconcileTiming.test.cjs +0 -135
  226. package/src/main/__tests__/runLogRetention.test.cjs +0 -489
  227. package/src/main/__tests__/runVerify-atomic-verdicts.test.cjs +0 -26
  228. package/src/main/__tests__/runVerify-blocked-by-foreign-wip.test.cjs +0 -58
  229. package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +0 -191
  230. package/src/main/__tests__/runVerify-policy-denial.test.cjs +0 -89
  231. package/src/main/__tests__/runVerify-transcript-commit-evidence.test.cjs +0 -225
  232. package/src/main/__tests__/runVerify.test.cjs +0 -1784
  233. package/src/main/__tests__/scheduleJobSchema.test.cjs +0 -127
  234. package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +0 -65
  235. package/src/main/__tests__/scheduleJobTransitions.test.cjs +0 -277
  236. package/src/main/__tests__/scheduleJobTransitionsGrep.test.cjs +0 -59
  237. package/src/main/__tests__/scheduleJobTransitionsTelemetryTap.test.cjs +0 -72
  238. package/src/main/__tests__/scheduler-admin-routes.test.cjs +0 -199
  239. package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +0 -143
  240. package/src/main/__tests__/scheduler-already-satisfied-on-main.test.cjs +0 -105
  241. package/src/main/__tests__/scheduler-archive-completed-prd.test.cjs +0 -102
  242. package/src/main/__tests__/scheduler-archived-twin-guard.test.cjs +0 -155
  243. package/src/main/__tests__/scheduler-autofix-outcome.test.cjs +0 -188
  244. package/src/main/__tests__/scheduler-autofix-select.test.cjs +0 -439
  245. package/src/main/__tests__/scheduler-autopromote.test.cjs +0 -51
  246. package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +0 -101
  247. package/src/main/__tests__/scheduler-blocked-by-foreign-wip.test.cjs +0 -107
  248. package/src/main/__tests__/scheduler-boot-orphans.test.cjs +0 -153
  249. package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +0 -121
  250. package/src/main/__tests__/scheduler-clear-queue-history.test.cjs +0 -134
  251. package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +0 -244
  252. package/src/main/__tests__/scheduler-committed-in-window.test.cjs +0 -182
  253. package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +0 -43
  254. package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +0 -168
  255. package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +0 -58
  256. package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +0 -81
  257. package/src/main/__tests__/scheduler-epic-digest.test.cjs +0 -227
  258. package/src/main/__tests__/scheduler-failed-autoreset.test.cjs +0 -121
  259. package/src/main/__tests__/scheduler-finalize-dispatch-guards.test.cjs +0 -229
  260. package/src/main/__tests__/scheduler-find-prd-dir.test.cjs +0 -75
  261. package/src/main/__tests__/scheduler-fix-plan-path.test.cjs +0 -119
  262. package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +0 -46
  263. package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +0 -78
  264. package/src/main/__tests__/scheduler-gate-shadow.test.cjs +0 -119
  265. package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +0 -390
  266. package/src/main/__tests__/scheduler-heal-refusal.test.cjs +0 -61
  267. package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +0 -80
  268. package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +0 -323
  269. package/src/main/__tests__/scheduler-integration-failure-stamp.test.cjs +0 -41
  270. package/src/main/__tests__/scheduler-investigation-clean-skip.test.cjs +0 -63
  271. package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +0 -123
  272. package/src/main/__tests__/scheduler-job-budget.test.cjs +0 -172
  273. package/src/main/__tests__/scheduler-job-overrun.test.cjs +0 -175
  274. package/src/main/__tests__/scheduler-launch-failure.test.cjs +0 -199
  275. package/src/main/__tests__/scheduler-leftover-fields.test.cjs +0 -52
  276. package/src/main/__tests__/scheduler-leftover-quarantine.test.cjs +0 -199
  277. package/src/main/__tests__/scheduler-looks-done.test.cjs +0 -537
  278. package/src/main/__tests__/scheduler-manual-pause.test.cjs +0 -118
  279. package/src/main/__tests__/scheduler-mechanical-recovery.test.cjs +0 -245
  280. package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +0 -46
  281. package/src/main/__tests__/scheduler-mutate-reentrancy.test.cjs +0 -117
  282. package/src/main/__tests__/scheduler-needs-review-autoresolve.test.cjs +0 -197
  283. package/src/main/__tests__/scheduler-never-stop.test.cjs +0 -157
  284. package/src/main/__tests__/scheduler-no-dead-end-status.test.cjs +0 -152
  285. package/src/main/__tests__/scheduler-no-orphan-run-dir.test.cjs +0 -81
  286. package/src/main/__tests__/scheduler-notify-originating-tab-transcript.test.cjs +0 -87
  287. package/src/main/__tests__/scheduler-notify-originating-tab.test.cjs +0 -343
  288. package/src/main/__tests__/scheduler-periodic-reverify-guard.test.cjs +0 -217
  289. package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +0 -164
  290. package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +0 -161
  291. package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +0 -178
  292. package/src/main/__tests__/scheduler-quarantine-autoresolve.test.cjs +0 -165
  293. package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +0 -257
  294. package/src/main/__tests__/scheduler-rate-limit-cooldown-freshness.test.cjs +0 -123
  295. package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +0 -152
  296. package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +0 -156
  297. package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +0 -754
  298. package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +0 -87
  299. package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +0 -100
  300. package/src/main/__tests__/scheduler-reconcile-history-backfill.test.cjs +0 -105
  301. package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +0 -203
  302. package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +0 -247
  303. package/src/main/__tests__/scheduler-reset-job-fields-guard.test.cjs +0 -77
  304. package/src/main/__tests__/scheduler-resume-recovery.test.cjs +0 -254
  305. package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +0 -115
  306. package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +0 -380
  307. package/src/main/__tests__/scheduler-sigterm-commit.test.cjs +0 -43
  308. package/src/main/__tests__/scheduler-stall-per-project.test.cjs +0 -126
  309. package/src/main/__tests__/scheduler-starve-escalation.test.cjs +0 -154
  310. package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +0 -252
  311. package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +0 -185
  312. package/src/main/__tests__/scheduler-stuck-failed-escalation.test.cjs +0 -136
  313. package/src/main/__tests__/scheduler-supervisor-record.test.cjs +0 -81
  314. package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +0 -54
  315. package/src/main/__tests__/scheduler-tick-wedge.test.cjs +0 -172
  316. package/src/main/__tests__/scheduler-transient-failure.test.cjs +0 -141
  317. package/src/main/__tests__/scheduler-unreadable-queue-guard.test.cjs +0 -62
  318. package/src/main/__tests__/scheduler-utilization-hold.test.cjs +0 -89
  319. package/src/main/__tests__/scheduler-verify-prd-path.test.cjs +0 -109
  320. package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +0 -234
  321. package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +0 -120
  322. package/src/main/__tests__/scheduler-writeprd-epic-rollback.test.cjs +0 -105
  323. package/src/main/__tests__/schedulerBatchRootBlocker.test.cjs +0 -117
  324. package/src/main/__tests__/schedulerStateSidecarRestore.test.cjs +0 -110
  325. package/src/main/__tests__/seedAgentPersonas.test.cjs +0 -184
  326. package/src/main/__tests__/seedSchedulerMcp.test.cjs +0 -211
  327. package/src/main/__tests__/seedStatus.test.cjs +0 -100
  328. package/src/main/__tests__/seedValidatorPersona.test.cjs +0 -116
  329. package/src/main/__tests__/stop-signal-anchor.test.cjs +0 -75
  330. package/src/main/__tests__/telemetryClient.test.cjs +0 -1055
  331. package/src/main/__tests__/telemetryContract.test.cjs +0 -930
  332. package/src/main/__tests__/telemetrySettings.test.cjs +0 -210
  333. package/src/main/__tests__/transcripts-batch-flush.test.cjs +0 -249
  334. package/src/main/__tests__/transcripts-doFlush-array.test.cjs +0 -124
  335. package/src/main/__tests__/transcripts-paged-reads.test.cjs +0 -241
  336. package/src/main/__tests__/transcripts-worktree-epic-path.test.cjs +0 -154
  337. package/src/main/__tests__/transcriptsUsageFor.test.cjs +0 -206
  338. package/src/main/__tests__/uniquePrdNumbers.test.cjs +0 -153
  339. package/src/main/__tests__/usageSingleFlight.test.cjs +0 -169
  340. package/src/main/__tests__/validationSentinels.test.cjs +0 -84
  341. package/src/main/__tests__/workTypeLibrary.test.cjs +0 -89
  342. package/src/main/bilkoHost.cjs +0 -314
  343. package/src/main/bilkoHostCore.cjs +0 -89
  344. package/src/main/lib/__tests__/active-sessions.test.cjs +0 -251
  345. package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +0 -179
  346. package/src/main/lib/__tests__/agentPersonaSchema.test.cjs +0 -67
  347. package/src/main/lib/__tests__/auditLog.test.cjs +0 -38
  348. package/src/main/lib/__tests__/bootSelfHeal.test.cjs +0 -107
  349. package/src/main/lib/__tests__/branchSweep.test.cjs +0 -164
  350. package/src/main/lib/__tests__/buildIdentity.test.cjs +0 -121
  351. package/src/main/lib/__tests__/buildTarget.test.cjs +0 -52
  352. package/src/main/lib/__tests__/childWithLog.test.cjs +0 -321
  353. package/src/main/lib/__tests__/coldBootPromptSessionsWrite.test.cjs +0 -87
  354. package/src/main/lib/__tests__/crashTelemetry.test.cjs +0 -103
  355. package/src/main/lib/__tests__/credentials-futile-refresh.test.cjs +0 -115
  356. package/src/main/lib/__tests__/cwdClassify.test.cjs +0 -111
  357. package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +0 -95
  358. package/src/main/lib/__tests__/delegationReadiness.test.cjs +0 -1175
  359. package/src/main/lib/__tests__/dispatchLoop.test.cjs +0 -63
  360. package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +0 -244
  361. package/src/main/lib/__tests__/ephemeralCwd.test.cjs +0 -91
  362. package/src/main/lib/__tests__/epicDelegationStats.test.cjs +0 -137
  363. package/src/main/lib/__tests__/epicSpawnCwd.test.cjs +0 -283
  364. package/src/main/lib/__tests__/epicSpawnPlan.test.cjs +0 -196
  365. package/src/main/lib/__tests__/epicTranscriptPath.test.cjs +0 -163
  366. package/src/main/lib/__tests__/epicWorktreeBoot.test.cjs +0 -136
  367. package/src/main/lib/__tests__/epicWorktreeMerge.test.cjs +0 -130
  368. package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +0 -117
  369. package/src/main/lib/__tests__/epicWorktreeProjectConfig.test.cjs +0 -137
  370. package/src/main/lib/__tests__/fixChainDepth.test.cjs +0 -40
  371. package/src/main/lib/__tests__/fixtures/204-mercury-steam-horse.log.txt +0 -13
  372. package/src/main/lib/__tests__/fixtures/scheduler-machine.json.corrupt-1789147548 +0 -34
  373. package/src/main/lib/__tests__/gateFixtures.json +0 -20
  374. package/src/main/lib/__tests__/gitCacheBound.test.cjs +0 -69
  375. package/src/main/lib/__tests__/gitWorktree.test.cjs +0 -1478
  376. package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +0 -107
  377. package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +0 -153
  378. package/src/main/lib/__tests__/guardShims.test.cjs +0 -158
  379. package/src/main/lib/__tests__/importReferences.spec.cjs +0 -56
  380. package/src/main/lib/__tests__/instanceLock.test.cjs +0 -173
  381. package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +0 -78
  382. package/src/main/lib/__tests__/jobWorktree.test.cjs +0 -199
  383. package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +0 -82
  384. package/src/main/lib/__tests__/landedSinceRun.test.cjs +0 -133
  385. package/src/main/lib/__tests__/launchFailure.test.cjs +0 -220
  386. package/src/main/lib/__tests__/loadGate.test.cjs +0 -303
  387. package/src/main/lib/__tests__/localAdminHttp.test.cjs +0 -214
  388. package/src/main/lib/__tests__/loopDelay.test.cjs +0 -68
  389. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +0 -107
  390. package/src/main/lib/__tests__/modelCatalog.test.cjs +0 -202
  391. package/src/main/lib/__tests__/opsOwnership.test.cjs +0 -113
  392. package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +0 -328
  393. package/src/main/lib/__tests__/opsRootNestedWrite.test.cjs +0 -51
  394. package/src/main/lib/__tests__/opsRootResolve.test.cjs +0 -149
  395. package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +0 -82
  396. package/src/main/lib/__tests__/prdDisposition.test.cjs +0 -224
  397. package/src/main/lib/__tests__/procIdentity.test.cjs +0 -119
  398. package/src/main/lib/__tests__/procName.test.cjs +0 -92
  399. package/src/main/lib/__tests__/projectBriefCore.test.cjs +0 -216
  400. package/src/main/lib/__tests__/projectRootResolve.test.cjs +0 -148
  401. package/src/main/lib/__tests__/queueHealth.test.cjs +0 -58
  402. package/src/main/lib/__tests__/queueStoreAtomicWrite.test.cjs +0 -88
  403. package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +0 -190
  404. package/src/main/lib/__tests__/quietMachineLease.test.cjs +0 -39
  405. package/src/main/lib/__tests__/rateLimitWindow.test.cjs +0 -88
  406. package/src/main/lib/__tests__/reaperHelpers.test.cjs +0 -577
  407. package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +0 -312
  408. package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +0 -213
  409. package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +0 -125
  410. package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +0 -127
  411. package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +0 -109
  412. package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +0 -71
  413. package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +0 -216
  414. package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +0 -183
  415. package/src/main/lib/__tests__/schedulerPaths.test.cjs +0 -226
  416. package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +0 -133
  417. package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +0 -56
  418. package/src/main/lib/__tests__/sessionSlots.test.cjs +0 -144
  419. package/src/main/lib/__tests__/telemetryBacklog.test.cjs +0 -626
  420. package/src/main/lib/__tests__/telemetryBoot.test.cjs +0 -134
  421. package/src/main/lib/__tests__/telemetryConsent.test.cjs +0 -136
  422. package/src/main/lib/__tests__/telemetryCounters.test.cjs +0 -57
  423. package/src/main/lib/__tests__/telemetryCountersMetadataColumn.test.cjs +0 -98
  424. package/src/main/lib/__tests__/terminalRunOutcome.test.cjs +0 -200
  425. package/src/main/lib/__tests__/toolUseClassify.test.cjs +0 -53
  426. package/src/main/lib/__tests__/updateCheck.test.cjs +0 -63
  427. package/src/main/lib/__tests__/upgradeDrain.test.cjs +0 -130
  428. package/src/main/lib/__tests__/usageCircuit.test.cjs +0 -354
  429. package/src/main/lib/__tests__/watchdog-helpers.test.cjs +0 -441
  430. package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +0 -266
  431. package/src/main/lib/kgExchangePairing.cjs +0 -75
@@ -1,314 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * bilkoHost.cjs — Stage A (deterministic bundle prep) for the "Host on
5
- * Bilko.run" tab. See session-manager-operations/architecture/
6
- * bilko-host-integration.md for the full design.
7
- *
8
- * Model: ONE Bilko project (slug) hosts a LIST of documents — a root
9
- * document (subpath '', dist/index.html — "the project itself") plus any
10
- * number of sub-path documents (subpath 'special-doc/01',
11
- * dist/special-doc/01/index.html → bilko.run/projects/<slug>/special-doc/01/).
12
- * `documents.json` is the list; `dist/` is always rebuilt wholesale from it
13
- * (rm + rewrite) so it can never drift from the list — the same "full
14
- * replace" semantics Bilko's own publish_static_project already uses, which
15
- * is exactly what makes local deletion reliably propagate live (see
16
- * bilkoHostCore.cjs's header comment).
17
- *
18
- * This module owns `session-manager-operations/bilko-host/documents.json` +
19
- * `dist/{**,manifest.json}` (writer id `bilko-host`, OWNERS-enforced via
20
- * config.cjs's write helpers). It never talks to the bilko-host MCP itself
21
- * and never writes publish-state.json — that's Stage B, run by the
22
- * bilko-host-publisher Epic's own session with its own Write tool
23
- * (agent-authored artifact, same as project-pages/output/*.html; not
24
- * enforceable by OWNERS). Directory removal (rm -rf of dist/ before a
25
- * rebuild) uses raw fs directly, same precedent as epicMint.cjs/
26
- * queueStore.cjs using raw fs for their own owned namespace — this module
27
- * IS the declared owner of `bilko-host`, so there is no foreign-writer risk
28
- * to guard against here.
29
- */
30
-
31
- const { ipcMain } = require('electron');
32
- const { opsPath } = require('./lib/opsOwnership.cjs');
33
- const fsp = require('node:fs/promises');
34
- const path = require('node:path');
35
- const crypto = require('node:crypto');
36
- const { execFileSync } = require('node:child_process');
37
- const { gzipSync } = require('node:zlib');
38
- const config = require('./config.cjs');
39
- const {
40
- validateSubpath,
41
- validateDocumentSet,
42
- documentDistRelPath,
43
- documentUrl,
44
- } = require('./bilkoHostCore.cjs');
45
-
46
- const WRITER = 'bilko-host';
47
- const PROJECT_PAGE_LENSES = new Set(['home', 'marketing', 'feature', 'architecture']);
48
-
49
- function homePagePath(cwd) {
50
- return opsPath(cwd, 'project-pages', 'home.html');
51
- }
52
-
53
- function bilkoHostDir(cwd) {
54
- return opsPath(cwd, 'bilko-host');
55
- }
56
-
57
- function distDir(cwd) {
58
- return path.join(bilkoHostDir(cwd), 'dist');
59
- }
60
-
61
- function documentsPath(cwd) {
62
- return path.join(bilkoHostDir(cwd), 'documents.json');
63
- }
64
-
65
- /** Kebab-case a project name into a slug candidate. Pure. */
66
- function deriveSlug(projectDirName) {
67
- return String(projectDirName)
68
- .trim()
69
- .toLowerCase()
70
- .replace(/[^a-z0-9]+/g, '-')
71
- .replace(/^-+|-+$/g, '')
72
- .slice(0, 64) || 'project';
73
- }
74
-
75
- function gitInfo(cwd) {
76
- const run = (args, fallback) => {
77
- try {
78
- return execFileSync('git', args, { cwd, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
79
- } catch {
80
- return fallback;
81
- }
82
- };
83
- return {
84
- gitSha: run(['rev-parse', '--short', 'HEAD'], '0000000'),
85
- gitBranch: run(['rev-parse', '--abbrev-ref', 'HEAD'], 'main'),
86
- };
87
- }
88
-
89
- async function readDocuments(cwd) {
90
- const result = await config.readJson(documentsPath(cwd));
91
- if (result.exists && !result.parseError && Array.isArray(result.data?.documents)) {
92
- return result.data.documents;
93
- }
94
- return null;
95
- }
96
-
97
- async function writeDocuments(cwd, documents) {
98
- await config.writeJson(documentsPath(cwd), { documents }, { writer: WRITER });
99
- }
100
-
101
- /**
102
- * Reads everything the tab needs to render its status card: whether a
103
- * Project Page exists to seed a root document from, the project's
104
- * package.json (for the compatibility gate + default slug/version), the
105
- * current document list, and any bundle/publish state already on disk.
106
- */
107
- async function get({ cwd }) {
108
- const realCwd = config.validatePath(cwd);
109
-
110
- // The single Project Home page (project-pages/home.html) seeds the root
111
- // document. `hasMarketingPage` is the renderer's legacy field name for
112
- // "a root-document source page exists".
113
- const marketingResult = await config.readText(homePagePath(realCwd));
114
- const pkgResult = await config.readJson(path.join(realCwd, 'package.json'));
115
- const pkg = pkgResult.exists && !pkgResult.parseError ? pkgResult.data : null;
116
-
117
- const documents = (await readDocuments(realCwd)) ?? [];
118
-
119
- const bundleManifestResult = await config.readJson(path.join(distDir(realCwd), 'manifest.json'));
120
- const bundleManifest = bundleManifestResult.exists && !bundleManifestResult.parseError
121
- ? bundleManifestResult.data
122
- : null;
123
-
124
- const publishStateResult = await config.readJson(path.join(bilkoHostDir(realCwd), 'publish-state.json'));
125
- const publishState = publishStateResult.exists && !publishStateResult.parseError
126
- ? publishStateResult.data
127
- : null;
128
-
129
- const slug = bundleManifest?.slug
130
- ?? deriveSlug(pkg && typeof pkg.name === 'string' ? pkg.name : path.basename(realCwd));
131
-
132
- return {
133
- hasMarketingPage: marketingResult.exists,
134
- projectName: pkg && typeof pkg.name === 'string' ? pkg.name : path.basename(realCwd),
135
- packagePrivate: pkg ? pkg.private === true : false,
136
- packageHomepage: pkg && typeof pkg.homepage === 'string' ? pkg.homepage : null,
137
- packageVersion: pkg && typeof pkg.version === 'string' ? pkg.version : '0.0.0',
138
- defaultSlug: deriveSlug(pkg && typeof pkg.name === 'string' ? pkg.name : path.basename(realCwd)),
139
- documents: documents.map((d) => ({ ...d, url: documentUrl(slug, d.subpath) })),
140
- // A rebuild is owed whenever the bundle on disk doesn't reflect the
141
- // current document list — the tab uses this to gray out "up to date"
142
- // vs. prompt "Prepare Bundle" again, and (post-publish) to warn that a
143
- // removed document is still live until the next Publish.
144
- bundleStale: bundleManifest ? bundleManifest.documentCount !== documents.length : documents.length > 0,
145
- bundleManifest,
146
- publishState,
147
- };
148
- }
149
-
150
- /** Seeds documents.json with a single root document (the Project Home page, home.html) if it doesn't exist yet. */
151
- async function ensureSeededDocuments(cwd) {
152
- const existing = await readDocuments(cwd);
153
- if (existing) return existing;
154
- const seeded = [{
155
- id: crypto.randomUUID(),
156
- subpath: '',
157
- title: 'Project (Home)',
158
- source: { kind: 'project-page-lens', lens: 'home' },
159
- addedAt: new Date().toISOString(),
160
- }];
161
- await writeDocuments(cwd, seeded);
162
- return seeded;
163
- }
164
-
165
- /**
166
- * Add a hosted document. `source` is either
167
- * `{ kind: 'project-page-lens', lens: 'home'|'marketing'|'feature'|'architecture' }`
168
- * (reuses an already-generated Project Page lens) or
169
- * `{ kind: 'file', path: <repo-relative path> }` (any other local HTML —
170
- * e.g. a HUMAN_LEARN page or a hand-authored explainer).
171
- */
172
- async function addDocument({ cwd, subpath, title, source }) {
173
- const realCwd = config.validatePath(cwd);
174
- const subpathCheck = validateSubpath(subpath);
175
- if (!subpathCheck.ok) throw new Error(subpathCheck.error);
176
- if (source.kind === 'project-page-lens' && !PROJECT_PAGE_LENSES.has(source.lens)) {
177
- throw new Error(`unknown Project Page lens: ${source.lens}`);
178
- }
179
-
180
- const documents = (await readDocuments(realCwd)) ?? await ensureSeededDocuments(realCwd);
181
- if (subpath === '') {
182
- throw new Error('the root document (subpath "") always exists — edit it instead of adding a second one');
183
- }
184
- if (documents.some((d) => d.subpath === subpath)) {
185
- throw new Error(`a document already uses subpath "${subpath}"`);
186
- }
187
-
188
- const next = [...documents, {
189
- id: crypto.randomUUID(),
190
- subpath,
191
- title,
192
- source,
193
- addedAt: new Date().toISOString(),
194
- }];
195
- const setCheck = validateDocumentSet(next);
196
- if (!setCheck.ok) throw new Error(setCheck.error);
197
-
198
- await writeDocuments(realCwd, next);
199
- return { documents: next };
200
- }
201
-
202
- /**
203
- * Remove a hosted document (never the root). This only updates
204
- * documents.json — the file stays in `dist/` (and, if already published,
205
- * live on bilko.run) until the next Prepare Bundle + Publish, which is the
206
- * confirmed mechanism that actually removes it (Bilko's publish tool
207
- * rm -rf's + rebuilds the whole slug directory every publish).
208
- */
209
- async function removeDocument({ cwd, id }) {
210
- const realCwd = config.validatePath(cwd);
211
- const documents = (await readDocuments(realCwd)) ?? [];
212
- const target = documents.find((d) => d.id === id);
213
- if (!target) throw new Error(`no document with id ${id}`);
214
- if (target.subpath === '') throw new Error('cannot remove the root document');
215
-
216
- const next = documents.filter((d) => d.id !== id);
217
- await writeDocuments(realCwd, next);
218
- return { documents: next };
219
- }
220
-
221
- async function resolveDocumentHtml(cwd, doc) {
222
- if (doc.source.kind === 'project-page-lens') {
223
- // Only `home` is generated now (one home.html); other lens names are
224
- // retired and have no output anywhere — fail loudly rather than fall back.
225
- if (doc.source.lens !== 'home') {
226
- throw new Error(`document "${doc.title}" points at the retired "${doc.source.lens}" Project Page lens; only the single home.html page is generated now`);
227
- }
228
- const result = await config.readText(homePagePath(cwd));
229
- if (!result.exists) {
230
- throw new Error(`document "${doc.title}" points at the ${doc.source.lens} Project Page, but it hasn't been generated yet`);
231
- }
232
- return result.text;
233
- }
234
- if (doc.source.kind === 'file') {
235
- const abs = config.validatePath(path.join(cwd, doc.source.path));
236
- const result = await config.readText(abs);
237
- if (!result.exists) throw new Error(`document "${doc.title}"'s source file is missing: ${doc.source.path}`);
238
- return result.text;
239
- }
240
- throw new Error(`unknown document source kind: ${doc.source.kind}`);
241
- }
242
-
243
- /**
244
- * Stage A: rebuild the ENTIRE dist/ tree from documents.json (rm + rewrite,
245
- * mirroring Bilko's own full-replace publish semantics so local state can
246
- * never lag the document list) + dist/manifest.json (host-contract manifest
247
- * schema, one per bundle — golden.path/expect always point at the root
248
- * document). Idempotent.
249
- */
250
- async function prepareBundle({ cwd, slug }) {
251
- const realCwd = config.validatePath(cwd);
252
- const documents = await ensureSeededDocuments(realCwd);
253
-
254
- const setCheck = validateDocumentSet(documents);
255
- if (!setCheck.ok) throw new Error(setCheck.error);
256
-
257
- const pkgResult = await config.readJson(path.join(realCwd, 'package.json'));
258
- const pkg = pkgResult.exists && !pkgResult.parseError ? pkgResult.data : {};
259
- const version = typeof pkg.version === 'string' ? pkg.version : '0.0.0';
260
-
261
- const dist = distDir(realCwd);
262
- await fsp.rm(dist, { recursive: true, force: true });
263
-
264
- let totalGz = 0;
265
- for (const doc of documents) {
266
- const html = await resolveDocumentHtml(realCwd, doc);
267
- const relPath = documentDistRelPath(doc.subpath);
268
- await config.writeTextAtomic(path.join(dist, relPath), html, { writer: WRITER });
269
- totalGz += gzipSync(Buffer.from(html, 'utf8')).length;
270
- }
271
-
272
- const { gitSha, gitBranch } = gitInfo(realCwd);
273
- const goldenExpect = pkg && typeof pkg.name === 'string' ? pkg.name : slug;
274
-
275
- const manifest = {
276
- schemaVersion: 1,
277
- slug,
278
- version,
279
- builtAt: new Date().toISOString(),
280
- gitSha,
281
- gitBranch,
282
- hostKit: { version: '0.0.0' },
283
- golden: { path: `/projects/${slug}/`, expect: goldenExpect },
284
- health: {},
285
- bundle: { sizeBytesGz: totalGz, fileCount: documents.length },
286
- // Not part of the host-contract schema itself — this app's own staleness
287
- // check (get()'s bundleStale) compares this against documents.length.
288
- documentCount: documents.length,
289
- documents: documents.map((d) => ({ subpath: d.subpath, title: d.title })),
290
- };
291
-
292
- await config.writeJson(path.join(dist, 'manifest.json'), manifest, { writer: WRITER });
293
-
294
- return { distPath: dist, manifest };
295
- }
296
-
297
- function registerBilkoHostIpc() {
298
- const { schemas: s, validated: v } = require('./ipcSchemas.cjs');
299
- ipcMain.handle('bilko-host:get', v(s.bilkoHostCwd, get));
300
- ipcMain.handle('bilko-host:prepare-bundle', v(s.bilkoHostPrepareBundle, prepareBundle));
301
- ipcMain.handle('bilko-host:add-document', v(s.bilkoHostAddDocument, addDocument));
302
- ipcMain.handle('bilko-host:remove-document', v(s.bilkoHostRemoveDocument, removeDocument));
303
- }
304
-
305
- module.exports = {
306
- registerBilkoHostIpc,
307
- get,
308
- prepareBundle,
309
- addDocument,
310
- removeDocument,
311
- deriveSlug,
312
- bilkoHostDir,
313
- distDir,
314
- };
@@ -1,89 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * bilkoHostCore.cjs — pure logic for the "Host on Bilko.run" tab's
5
- * multi-document bundle model. No fs/IPC here (that's bilkoHost.cjs) so
6
- * this stays unit-testable without a real project directory.
7
- *
8
- * Model: ONE Bilko project (one registry slug, one `dist/` tree) can host
9
- * MANY documents — exactly one root document (subpath `''`, becomes
10
- * dist/index.html — "the project itself") plus any number of sub-path
11
- * documents (subpath 'special-doc/01', becomes dist/special-doc/01/
12
- * index.html → bilko.run/projects/<slug>/special-doc/01/). This mirrors how
13
- * Bilko's own publish_static_project already works: it `rm -rf`s then
14
- * `cp -r`s the WHOLE public/projects/<slug>/ tree on every publish, so
15
- * removing a document locally and re-publishing is guaranteed to remove it
16
- * live too — no separate per-document delete API needed on Bilko's side.
17
- */
18
-
19
- const SUBPATH_SEGMENT = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
20
- const MAX_SEGMENTS = 6;
21
- const MAX_SUBPATH_LENGTH = 200;
22
-
23
- /**
24
- * Validates a document's subpath. `''` (root) is always valid. Otherwise
25
- * every '/'-separated segment must be lowercase kebab-case, no '.'/'..',
26
- * no leading/trailing/double slashes, bounded depth and length.
27
- */
28
- function validateSubpath(subpath) {
29
- if (typeof subpath !== 'string') return { ok: false, error: 'subpath must be a string' };
30
- if (subpath === '') return { ok: true, error: null };
31
- if (subpath.length > MAX_SUBPATH_LENGTH) return { ok: false, error: 'subpath is too long' };
32
- if (subpath.startsWith('/') || subpath.endsWith('/')) {
33
- return { ok: false, error: 'subpath must not start or end with /' };
34
- }
35
- const segments = subpath.split('/');
36
- if (segments.length > MAX_SEGMENTS) return { ok: false, error: `subpath has more than ${MAX_SEGMENTS} segments` };
37
- for (const seg of segments) {
38
- if (!SUBPATH_SEGMENT.test(seg)) {
39
- return { ok: false, error: `invalid subpath segment "${seg}" — use lowercase kebab-case` };
40
- }
41
- }
42
- return { ok: true, error: null };
43
- }
44
-
45
- /**
46
- * Validates a full document list: subpaths individually valid, exactly one
47
- * root document, no duplicate subpaths. Pure — takes the array shape
48
- * documents.json stores, `[{ id, subpath, ... }]`.
49
- */
50
- function validateDocumentSet(documents) {
51
- if (!Array.isArray(documents) || documents.length === 0) {
52
- return { ok: false, error: 'at least one document (the root) is required' };
53
- }
54
- const seen = new Set();
55
- let rootCount = 0;
56
- for (const doc of documents) {
57
- const v = validateSubpath(doc.subpath);
58
- if (!v.ok) return { ok: false, error: `document "${doc.id}": ${v.error}` };
59
- if (seen.has(doc.subpath)) return { ok: false, error: `duplicate subpath "${doc.subpath}"` };
60
- seen.add(doc.subpath);
61
- if (doc.subpath === '') rootCount += 1;
62
- }
63
- if (rootCount !== 1) return { ok: false, error: 'exactly one document must have subpath "" (the project root)' };
64
- return { ok: true, error: null };
65
- }
66
-
67
- /** Where a document's rendered HTML lands inside dist/. Pure path math. */
68
- function documentDistRelPath(subpath) {
69
- return subpath === '' ? 'index.html' : `${subpath}/index.html`;
70
- }
71
-
72
- /**
73
- * The bilko.run URL a document resolves to once published, given the
74
- * project's slug. Pure — used by the tab to render "will be live at" links
75
- * before anything is actually published.
76
- */
77
- function documentUrl(slug, subpath) {
78
- return subpath === '' ? `https://bilko.run/projects/${slug}/` : `https://bilko.run/projects/${slug}/${subpath}/`;
79
- }
80
-
81
- module.exports = {
82
- SUBPATH_SEGMENT,
83
- MAX_SEGMENTS,
84
- MAX_SUBPATH_LENGTH,
85
- validateSubpath,
86
- validateDocumentSet,
87
- documentDistRelPath,
88
- documentUrl,
89
- };
@@ -1,251 +0,0 @@
1
- 'use strict';
2
-
3
- // Run: timeout 120 npx vitest run src/main/lib/__tests__/active-sessions.test.cjs
4
-
5
- import { vi } from 'vitest';
6
- const assert = require('node:assert/strict');
7
- const fs = require('node:fs');
8
- const os = require('node:os');
9
- const path = require('node:path');
10
- const { activeProjectCwds, allProjectCwds, bustProjectCwdCache } = require('../activeSessions.cjs');
11
-
12
- function tmpDir() {
13
- return fs.mkdtempSync(path.join(os.tmpdir(), 'active-sessions-test-'));
14
- }
15
-
16
- function writeTranscript(projectsDir, slug, fileName, cwd, mtimeMsAgo) {
17
- const projDir = path.join(projectsDir, slug);
18
- fs.mkdirSync(projDir, { recursive: true });
19
- const fp = path.join(projDir, fileName);
20
- fs.writeFileSync(fp, JSON.stringify({ cwd }) + '\n');
21
- const mtime = new Date(Date.now() - mtimeMsAgo);
22
- fs.utimesSync(fp, mtime, mtime);
23
- return fp;
24
- }
25
-
26
- test('two recent + one stale + one nonexistent → returns exactly the two recent existing cwds', () => {
27
- const base = tmpDir();
28
- try {
29
- const projectsDir = path.join(base, 'projects');
30
- const cwdA = path.join(base, 'proj-a');
31
- const cwdB = path.join(base, 'proj-b');
32
- const cwdC = path.join(base, 'proj-c'); // stale — exists on disk
33
- const cwdMissing = path.join(base, 'proj-missing'); // never created
34
- fs.mkdirSync(cwdA);
35
- fs.mkdirSync(cwdB);
36
- fs.mkdirSync(cwdC);
37
-
38
- const MAX_AGE_MIN = 90;
39
- writeTranscript(projectsDir, 'slug-a', 'a.jsonl', cwdA, 10 * 60 * 1000);
40
- writeTranscript(projectsDir, 'slug-b', 'b.jsonl', cwdB, 10 * 60 * 1000);
41
- writeTranscript(projectsDir, 'slug-c', 'c.jsonl', cwdC, 120 * 60 * 1000);
42
- writeTranscript(projectsDir, 'slug-missing', 'm.jsonl', cwdMissing, 10 * 60 * 1000);
43
-
44
- const result = activeProjectCwds(MAX_AGE_MIN, { projectsDir });
45
-
46
- assert.equal(
47
- result.length, 2,
48
- `expected 2 cwds, got ${result.length}: ${JSON.stringify(result)}`,
49
- );
50
- assert.ok(result.includes(cwdA), `cwdA must be in result`);
51
- assert.ok(result.includes(cwdB), `cwdB must be in result`);
52
- assert.ok(!result.includes(cwdC), 'stale cwdC must not appear');
53
- assert.ok(!result.includes(cwdMissing), 'nonexistent path must not appear');
54
- } finally {
55
- fs.rmSync(base, { recursive: true, force: true });
56
- }
57
- });
58
-
59
- test('duplicate cwd across two project dirs → deduped to one entry', () => {
60
- const base = tmpDir();
61
- try {
62
- const projectsDir = path.join(base, 'projects');
63
- const cwdA = path.join(base, 'proj-a');
64
- fs.mkdirSync(cwdA);
65
-
66
- writeTranscript(projectsDir, 'slug-1', 'a.jsonl', cwdA, 5 * 60 * 1000);
67
- writeTranscript(projectsDir, 'slug-2', 'b.jsonl', cwdA, 5 * 60 * 1000);
68
-
69
- const result = activeProjectCwds(90, { projectsDir });
70
- assert.equal(result.length, 1, 'duplicate cwd must be deduped');
71
- assert.equal(result[0], cwdA);
72
- } finally {
73
- fs.rmSync(base, { recursive: true, force: true });
74
- }
75
- });
76
-
77
- test('missing projects dir → empty result', () => {
78
- const base = tmpDir();
79
- try {
80
- const result = activeProjectCwds(90, { projectsDir: path.join(base, 'no-such-dir') });
81
- assert.deepEqual(result, []);
82
- } finally {
83
- fs.rmSync(base, { recursive: true, force: true });
84
- }
85
- });
86
-
87
- test('prompts.jsonl absent → transcripts still detected (sole detection path)', () => {
88
- const base = tmpDir();
89
- try {
90
- // No knowledge-log / prompts.jsonl anywhere in this tmp tree — the
91
- // function must not need it. logPath, if passed, is a harmless no-op.
92
- const projectsDir = path.join(base, 'projects');
93
- const cwdA = path.join(base, 'proj-a');
94
- fs.mkdirSync(cwdA);
95
-
96
- writeTranscript(projectsDir, 'slug-a', 'a.jsonl', cwdA, 5 * 60 * 1000);
97
-
98
- const missingLogPath = path.join(base, 'knowledge-log', 'prompts.jsonl');
99
- assert.ok(!fs.existsSync(missingLogPath), 'sanity: log path must not exist');
100
-
101
- const result = activeProjectCwds(90, { projectsDir, logPath: missingLogPath });
102
- assert.deepEqual(result, [cwdA]);
103
- } finally {
104
- fs.rmSync(base, { recursive: true, force: true });
105
- }
106
- });
107
-
108
- test('fresh transcript mtime with no prompt log present → cwd is returned', () => {
109
- const base = tmpDir();
110
- try {
111
- const projectsDir = path.join(base, 'projects');
112
- const cwdA = path.join(base, 'proj-fresh');
113
- fs.mkdirSync(cwdA);
114
-
115
- writeTranscript(projectsDir, 'slug-fresh', 'fresh.jsonl', cwdA, 60 * 1000); // 1 min ago
116
-
117
- const result = activeProjectCwds(90, { projectsDir });
118
- assert.equal(result.length, 1);
119
- assert.equal(result[0], cwdA);
120
- } finally {
121
- fs.rmSync(base, { recursive: true, force: true });
122
- }
123
- });
124
-
125
- test('garbage lines in transcript are skipped, cwd read from last parseable line', () => {
126
- const base = tmpDir();
127
- try {
128
- const projectsDir = path.join(base, 'projects');
129
- const cwdA = path.join(base, 'proj-a');
130
- fs.mkdirSync(cwdA);
131
-
132
- const projDir = path.join(projectsDir, 'slug-a');
133
- fs.mkdirSync(projDir, { recursive: true });
134
- const fp = path.join(projDir, 'a.jsonl');
135
- fs.writeFileSync(fp, [
136
- JSON.stringify({ cwd: cwdA }),
137
- 'not json at all!!!',
138
- '{ broken',
139
- ].join('\n') + '\n');
140
- const mtime = new Date(Date.now() - 5 * 60 * 1000);
141
- fs.utimesSync(fp, mtime, mtime);
142
-
143
- const result = activeProjectCwds(90, { projectsDir });
144
- assert.equal(result.length, 1);
145
- assert.equal(result[0], cwdA);
146
- } finally {
147
- fs.rmSync(base, { recursive: true, force: true });
148
- }
149
- });
150
-
151
- test('5 consecutive allProjectCwds() calls with the same args perform ONE directory scan', () => {
152
- const base = tmpDir();
153
- try {
154
- const projectsDir = path.join(base, 'projects');
155
- const cwdA = path.join(base, 'proj-a');
156
- fs.mkdirSync(cwdA);
157
- writeTranscript(projectsDir, 'slug-a', 'a.jsonl', cwdA, 5 * 60 * 1000);
158
-
159
- bustProjectCwdCache();
160
- const readdirSpy = vi.spyOn(fs, 'readdirSync');
161
-
162
- const first = allProjectCwds({ projectsDir });
163
- const callsAfterFirst = readdirSpy.mock.calls.length;
164
- assert.ok(callsAfterFirst > 0, 'first call must actually scan');
165
-
166
- for (let i = 0; i < 4; i++) {
167
- const again = allProjectCwds({ projectsDir });
168
- assert.deepEqual(again, first);
169
- }
170
-
171
- assert.equal(
172
- readdirSpy.mock.calls.length, callsAfterFirst,
173
- 'the 4 repeat calls must not perform any additional directory scan',
174
- );
175
- } finally {
176
- vi.restoreAllMocks();
177
- fs.rmSync(base, { recursive: true, force: true });
178
- }
179
- });
180
-
181
- test('bustProjectCwdCache() forces the very next call to rescan', () => {
182
- const base = tmpDir();
183
- try {
184
- const projectsDir = path.join(base, 'projects');
185
- const cwdA = path.join(base, 'proj-a');
186
- fs.mkdirSync(cwdA);
187
- writeTranscript(projectsDir, 'slug-a', 'a.jsonl', cwdA, 5 * 60 * 1000);
188
-
189
- bustProjectCwdCache();
190
- allProjectCwds({ projectsDir }); // warm the cache
191
-
192
- const readdirSpy = vi.spyOn(fs, 'readdirSync');
193
- allProjectCwds({ projectsDir });
194
- assert.equal(readdirSpy.mock.calls.length, 0, 'a cache hit must not scan');
195
-
196
- bustProjectCwdCache();
197
- allProjectCwds({ projectsDir });
198
- assert.ok(readdirSpy.mock.calls.length > 0, 'a bust must force a rescan on the next call');
199
- } finally {
200
- vi.restoreAllMocks();
201
- fs.rmSync(base, { recursive: true, force: true });
202
- }
203
- });
204
-
205
- test('allProjectCwds() and activeProjectCwds(90) do not share a cache entry', () => {
206
- const base = tmpDir();
207
- try {
208
- const projectsDir = path.join(base, 'projects');
209
- const cwdFresh = path.join(base, 'proj-fresh');
210
- const cwdStale = path.join(base, 'proj-stale');
211
- fs.mkdirSync(cwdFresh);
212
- fs.mkdirSync(cwdStale);
213
- writeTranscript(projectsDir, 'slug-fresh', 'fresh.jsonl', cwdFresh, 5 * 60 * 1000);
214
- writeTranscript(projectsDir, 'slug-stale', 'stale.jsonl', cwdStale, 120 * 60 * 1000);
215
-
216
- bustProjectCwdCache();
217
- // allProjectCwds (maxAgeMin Infinity, maxCwds 500) sees both — cached
218
- // first under its own key.
219
- const all = allProjectCwds({ projectsDir });
220
- assert.ok(all.includes(cwdFresh) && all.includes(cwdStale));
221
-
222
- // activeProjectCwds(90) must recompute under its OWN key, not return
223
- // allProjectCwds' cached (Infinity, 500) result — proving the cache key
224
- // includes maxAgeMin/maxCwds, not just projectsDir.
225
- const active = activeProjectCwds(90, { projectsDir });
226
- assert.ok(active.includes(cwdFresh), 'fresh cwd must be present');
227
- assert.ok(!active.includes(cwdStale), 'stale cwd must be excluded by the 90-min filter');
228
- } finally {
229
- fs.rmSync(base, { recursive: true, force: true });
230
- }
231
- });
232
-
233
- test('missing projectsDir returns [] and does not poison the cache once the dir appears', () => {
234
- const base = tmpDir();
235
- try {
236
- const projectsDir = path.join(base, 'projects');
237
- bustProjectCwdCache();
238
-
239
- assert.deepEqual(activeProjectCwds(90, { projectsDir }), []);
240
- assert.deepEqual(activeProjectCwds(90, { projectsDir }), []);
241
-
242
- const cwdA = path.join(base, 'proj-a');
243
- fs.mkdirSync(cwdA);
244
- writeTranscript(projectsDir, 'slug-a', 'a.jsonl', cwdA, 5 * 60 * 1000);
245
-
246
- const result = activeProjectCwds(90, { projectsDir });
247
- assert.deepEqual(result, [cwdA], 'the dir appearing later must be visible, not stuck on a cached []');
248
- } finally {
249
- fs.rmSync(base, { recursive: true, force: true });
250
- }
251
- });