claude-code-session-manager 0.98.0 → 0.101.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 (441) 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-CXaH2GED.js +1 -0
  5. package/dist/assets/{History-Bfdoywlh.js → History-Cerii-HA.js} +2 -2
  6. package/dist/assets/{Hooks-CKDJjTJV.js → Hooks-aXMb5LDy.js} +3 -3
  7. package/dist/assets/{Library-7akfgy67.js → Library-WrJFKEOJ.js} +1 -1
  8. package/dist/assets/{MarkdownEditor-DDesiqet.js → MarkdownEditor-D1BMCXS7.js} +1 -1
  9. package/dist/assets/{McpServers-D4lZtXof.js → McpServers-Cf0davLd.js} +2 -2
  10. package/dist/assets/{Memory-CeI8G1w5.js → Memory-Dn6NHWPe.js} +6 -6
  11. package/dist/assets/Permissions-CTVuFPjg.js +3 -0
  12. package/dist/assets/{Plugins-P4eCXy_S.js → Plugins-C2TyF8Mn.js} +2 -2
  13. package/dist/assets/ProvenanceBadge-F_jwHSwE.js +1 -0
  14. package/dist/assets/{SaveBar-l9jnEMES.js → SaveBar-DA1KVJST.js} +1 -1
  15. package/dist/assets/Scheduler-Bm6Q_hlu.js +16 -0
  16. package/dist/assets/{ScopeSwitcher-CjJi8ST5.js → ScopeSwitcher-BygZlJca.js} +1 -1
  17. package/dist/assets/Settings-BYCiv5KV.js +3 -0
  18. package/dist/assets/{SkillReferenceGraph-CjbO01Sg.js → SkillReferenceGraph-CcLnl9np.js} +1 -1
  19. package/dist/assets/{Skills-BxZ9_fCR.js → Skills-ChffsdTD.js} +2 -2
  20. package/dist/assets/{SystemPrompt-D8vfFb8b.js → SystemPrompt-dNkfHE_M.js} +1 -1
  21. package/dist/assets/{TagLibrary-2vzUo7YL.js → TagLibrary-jVlEuB0m.js} +1 -1
  22. package/dist/assets/{TiptapBody-B8ZfbK90.js → TiptapBody-6_cdwcP0.js} +1 -1
  23. package/dist/assets/{Toggle-BbW4nGGf.js → Toggle-CVXqGpAP.js} +1 -1
  24. package/dist/assets/ViewTabs-DO1YVbpc.js +1 -0
  25. package/dist/assets/{index-CKH5Uxik.css → index-D89EUizB.css} +1 -1
  26. package/dist/assets/{index-Cd98Q1lD.js → index-DbCQPWWY.js} +747 -752
  27. package/dist/assets/{settingsSchema-IhUfucCF.js → settingsSchema-Wrvn-Yz1.js} +1 -1
  28. package/dist/index.html +2 -2
  29. package/package.json +25 -29
  30. package/plugins/CLAUDE.md +6 -6
  31. package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +21 -19
  32. package/plugins/session-manager-dev/skills/builder/SKILL.md +3 -3
  33. package/plugins/session-manager-dev/skills/develop/SKILL.md +254 -510
  34. package/plugins/session-manager-dev/skills/develop/standards.md +17 -22
  35. package/scripts/README.md +3 -11
  36. package/scripts/audit-ops-hygiene.cjs +3 -3
  37. package/scripts/hooks/lib/guard-prd-writes-policy.cjs +1 -1
  38. package/scripts/hooks/lib/guard-self-schedule-policy.cjs +1 -1
  39. package/scripts/mint-epic.cjs +2 -3
  40. package/scripts/scheduler-mcp-server.cjs +64 -7
  41. package/src/main/agentLibrary.cjs +22 -2
  42. package/src/main/build-info.json +4 -4
  43. package/src/main/chatRunner.cjs +4 -3
  44. package/src/main/config.cjs +41 -38
  45. package/src/main/docEdit.cjs +4 -1
  46. package/src/main/files.cjs +2 -5
  47. package/src/main/health.cjs +1 -1
  48. package/src/main/index.cjs +40 -11
  49. package/src/main/ipcSchemas.cjs +35 -34
  50. package/src/main/lib/agentPersonaSchema.cjs +13 -2
  51. package/src/main/lib/atomicFs.cjs +116 -0
  52. package/src/main/lib/branchSweep.cjs +13 -12
  53. package/src/main/lib/buildTarget.cjs +3 -3
  54. package/src/main/lib/builtinMacros.cjs +39 -0
  55. package/src/main/lib/claudeCliCaps.cjs +129 -0
  56. package/src/main/lib/credentials.cjs +2 -4
  57. package/src/main/lib/crossProjectFeedback.cjs +3 -3
  58. package/src/main/lib/cwdClassify.cjs +15 -3
  59. package/src/main/lib/definitionOfDone.cjs +207 -125
  60. package/src/main/lib/dodDrainHook.cjs +11 -5
  61. package/src/main/lib/epicMint.cjs +2 -4
  62. package/src/main/lib/epicStatusMirror.cjs +8 -10
  63. package/src/main/lib/epicWorktreeProjectConfig.cjs +2 -4
  64. package/src/main/lib/gateAuthority.cjs +96 -0
  65. package/src/main/lib/gitExec.cjs +69 -0
  66. package/src/main/lib/gitWorktree.cjs +656 -92
  67. package/src/main/lib/instanceLock.cjs +5 -8
  68. package/src/main/lib/launchFailure.cjs +2 -3
  69. package/src/main/lib/macroLibrary.cjs +480 -0
  70. package/src/main/lib/mcpToolCatalog.cjs +49 -17
  71. package/src/main/lib/needsReviewLedger.cjs +1 -1
  72. package/src/main/lib/opsErrorLog.cjs +11 -1
  73. package/src/main/lib/opsOwnership.cjs +5 -9
  74. package/src/main/lib/pidAlive.cjs +32 -0
  75. package/src/main/lib/prdCreate.cjs +121 -12
  76. package/src/main/lib/prdDisposition.cjs +2 -2
  77. package/src/main/lib/prdGateFiles.cjs +284 -0
  78. package/src/main/lib/prdLocations.cjs +61 -0
  79. package/src/main/lib/prdMigration.cjs +2 -3
  80. package/src/main/lib/prdSizing.cjs +2 -1
  81. package/src/main/lib/projectHomeAdminRoutes.cjs +136 -21
  82. package/src/main/lib/promptSessionSchema.cjs +10 -2
  83. package/src/main/lib/rcaReport.cjs +4 -6
  84. package/src/main/lib/reaperHelpers.cjs +8 -1
  85. package/src/main/lib/reservationExpiry.cjs +6 -1
  86. package/src/main/lib/reviewNotice.cjs +263 -0
  87. package/src/main/lib/runClaudeP.cjs +4 -1
  88. package/src/main/lib/schedulerPaths.cjs +22 -2
  89. package/src/main/lib/sessionSlots.cjs +2 -4
  90. package/src/main/lib/shippedPersonaSeeds.cjs +226 -0
  91. package/src/main/lib/smfileHeaders.cjs +66 -0
  92. package/src/main/lib/timeoutShim.cjs +123 -0
  93. package/src/main/lib/timeoutShimScript.cjs +275 -0
  94. package/src/main/lib/upgradeDrain.cjs +4 -10
  95. package/src/main/lib/watchdogHelpers.cjs +12 -25
  96. package/src/main/lib/workTypeLibrary.cjs +7 -1
  97. package/src/main/projectPages.cjs +43 -13
  98. package/src/main/promptSessionEvents.cjs +37 -13
  99. package/src/main/scheduler.cjs +910 -198
  100. package/src/main/seedAgentPersonas.cjs +279 -24
  101. package/src/main/supervisor.cjs +4 -1
  102. package/src/main/templates/PRD_AUTHORING.md +126 -406
  103. package/src/preload/__tests__/preload-surface.test.cjs +68 -0
  104. package/src/preload/api.d.ts +53 -94
  105. package/src/preload/index.cjs +14 -9
  106. package/src/seed/agents/architect.md +2 -0
  107. package/src/seed/agents/demo-video-builder.md +84 -0
  108. package/src/seed/agents/dev-lead.md +18 -18
  109. package/src/seed/agents/project-home-builder.md +66 -35
  110. package/src/seed/agents/validator.md +10 -4
  111. package/dist/assets/DataModel-DCEgMTjH.js +0 -1
  112. package/dist/assets/HostBilko-CDVHE0hT.js +0 -1
  113. package/dist/assets/Permissions-BGleLja4.js +0 -3
  114. package/dist/assets/ProvenanceBadge-BFczzI1B.js +0 -1
  115. package/dist/assets/Scheduler-C_phpeUS.js +0 -16
  116. package/dist/assets/Settings-BIwZ3FGQ.js +0 -3
  117. package/src/main/__tests__/activeIndexMerge.test.cjs +0 -235
  118. package/src/main/__tests__/agentEffortResolve.test.cjs +0 -117
  119. package/src/main/__tests__/agentLibrary.test.cjs +0 -276
  120. package/src/main/__tests__/agentModelResolve.test.cjs +0 -311
  121. package/src/main/__tests__/agentOverlayWrite.test.cjs +0 -95
  122. package/src/main/__tests__/bilkoHost-deriveSlug.test.cjs +0 -26
  123. package/src/main/__tests__/bilkoHost-integration.test.cjs +0 -118
  124. package/src/main/__tests__/bilkoHostCore.test.cjs +0 -72
  125. package/src/main/__tests__/broadcastCoalescer.test.cjs +0 -122
  126. package/src/main/__tests__/chat-cancel-terminal.test.cjs +0 -120
  127. package/src/main/__tests__/chat-dead-channels.test.cjs +0 -63
  128. package/src/main/__tests__/chat-exit-close-race.test.cjs +0 -146
  129. package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +0 -139
  130. package/src/main/__tests__/chat-preamble-anchors.test.cjs +0 -100
  131. package/src/main/__tests__/chat-queue.test.cjs +0 -97
  132. package/src/main/__tests__/chat-stop-signal.test.cjs +0 -89
  133. package/src/main/__tests__/chatRunner-epic-worktree-execcwd.test.cjs +0 -125
  134. package/src/main/__tests__/chatRunner-session-flag-retry.test.cjs +0 -252
  135. package/src/main/__tests__/classifyPromptTicket.test.cjs +0 -101
  136. package/src/main/__tests__/classifyTranscriptLine.test.cjs +0 -201
  137. package/src/main/__tests__/computeDepHistorySatisfaction.test.cjs +0 -66
  138. package/src/main/__tests__/config-readText-bounded.test.cjs +0 -84
  139. package/src/main/__tests__/configWriteBoundaryOwners.test.cjs +0 -59
  140. package/src/main/__tests__/crossProjectFeedback.test.cjs +0 -334
  141. package/src/main/__tests__/crossProjectFeedbackRoutes.test.cjs +0 -161
  142. package/src/main/__tests__/dep-orphan-archive-health.test.cjs +0 -77
  143. package/src/main/__tests__/develop-skill-failure-modes.test.cjs +0 -70
  144. package/src/main/__tests__/docEdit.test.cjs +0 -244
  145. package/src/main/__tests__/dod-batchkey.test.cjs +0 -183
  146. package/src/main/__tests__/dod-drain-hook.test.cjs +0 -302
  147. package/src/main/__tests__/dod-report.test.cjs +0 -304
  148. package/src/main/__tests__/dod-reverify.test.cjs +0 -285
  149. package/src/main/__tests__/epicContextDigest.test.cjs +0 -174
  150. package/src/main/__tests__/epicMint.test.cjs +0 -332
  151. package/src/main/__tests__/epicMintTelemetryTap.test.cjs +0 -64
  152. package/src/main/__tests__/epicStatusMirror.test.cjs +0 -110
  153. package/src/main/__tests__/epicValidationHook.test.cjs +0 -291
  154. package/src/main/__tests__/exchanges.test.cjs +0 -122
  155. package/src/main/__tests__/exchangesPromptId.test.cjs +0 -61
  156. package/src/main/__tests__/extractJson.test.cjs +0 -51
  157. package/src/main/__tests__/files-reject-credentials.test.cjs +0 -40
  158. package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +0 -556
  159. package/src/main/__tests__/flatPrdTickSweep.test.cjs +0 -110
  160. package/src/main/__tests__/health-build-freshness.test.cjs +0 -39
  161. package/src/main/__tests__/health-claude-md-budget.test.cjs +0 -57
  162. package/src/main/__tests__/health-credentials.test.cjs +0 -81
  163. package/src/main/__tests__/health-delegation-chain.test.cjs +0 -124
  164. package/src/main/__tests__/health-per-project-stall.test.cjs +0 -84
  165. package/src/main/__tests__/health-prd-migration.test.cjs +0 -37
  166. package/src/main/__tests__/health-queue-dispatch.test.cjs +0 -135
  167. package/src/main/__tests__/health-starve-escalation.test.cjs +0 -94
  168. package/src/main/__tests__/health-tick-liveness.test.cjs +0 -179
  169. package/src/main/__tests__/health-usage-poller.test.cjs +0 -144
  170. package/src/main/__tests__/health-worktree-cap-blocked.test.cjs +0 -65
  171. package/src/main/__tests__/heapSnapshot.test.cjs +0 -121
  172. package/src/main/__tests__/historyAggregatorIntraday.test.cjs +0 -313
  173. package/src/main/__tests__/historyDashboard.test.cjs +0 -163
  174. package/src/main/__tests__/historyRollup.test.cjs +0 -333
  175. package/src/main/__tests__/intradayRefresh.test.cjs +0 -39
  176. package/src/main/__tests__/ipcSchemas-dependsOn.test.cjs +0 -39
  177. package/src/main/__tests__/kg-augment.test.cjs +0 -195
  178. package/src/main/__tests__/loadGateDetailTick.test.cjs +0 -31
  179. package/src/main/__tests__/machineProfile.test.cjs +0 -152
  180. package/src/main/__tests__/mcpStatus.test.cjs +0 -61
  181. package/src/main/__tests__/memoryAggregate.test.cjs +0 -109
  182. package/src/main/__tests__/memoryStale.test.cjs +0 -88
  183. package/src/main/__tests__/needsReviewLedger.test.cjs +0 -162
  184. package/src/main/__tests__/openExternalApp-spawn-error.test.cjs +0 -25
  185. package/src/main/__tests__/opsErrorLog.test.cjs +0 -109
  186. package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +0 -173
  187. package/src/main/__tests__/personaMerge.test.cjs +0 -169
  188. package/src/main/__tests__/planValidator.test.cjs +0 -125
  189. package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +0 -176
  190. package/src/main/__tests__/prd-group-allocator.test.cjs +0 -119
  191. package/src/main/__tests__/prdAdminRouteParity.test.cjs +0 -70
  192. package/src/main/__tests__/prdAdminRoutes.test.cjs +0 -718
  193. package/src/main/__tests__/prdAgentType.test.cjs +0 -103
  194. package/src/main/__tests__/prdAuthoringSeed.test.cjs +0 -39
  195. package/src/main/__tests__/prdCreate.test.cjs +0 -979
  196. package/src/main/__tests__/prdCreateAdoption.test.cjs +0 -205
  197. package/src/main/__tests__/prdCreateDisposition.test.cjs +0 -201
  198. package/src/main/__tests__/prdCreatePlanId.test.cjs +0 -132
  199. package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +0 -117
  200. package/src/main/__tests__/prdFrontmatterDependsOn.test.cjs +0 -136
  201. package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +0 -125
  202. package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +0 -108
  203. package/src/main/__tests__/prdLocations.test.cjs +0 -195
  204. package/src/main/__tests__/prdLocationsArchived.test.cjs +0 -201
  205. package/src/main/__tests__/prdMigration.test.cjs +0 -349
  206. package/src/main/__tests__/prdMigrationLegacyAdopt.test.cjs +0 -91
  207. package/src/main/__tests__/prdParserHighWater.test.cjs +0 -74
  208. package/src/main/__tests__/prdParserSourcePromptId.test.cjs +0 -65
  209. package/src/main/__tests__/prdSetDisposition.test.cjs +0 -222
  210. package/src/main/__tests__/prdSizing.test.cjs +0 -106
  211. package/src/main/__tests__/prdSourcePromptIdBackfill.test.cjs +0 -118
  212. package/src/main/__tests__/prdUpdateDependsOn.test.cjs +0 -160
  213. package/src/main/__tests__/proc-role-env.test.cjs +0 -125
  214. package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +0 -304
  215. package/src/main/__tests__/procname-sm-processes.test.cjs +0 -127
  216. package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +0 -177
  217. package/src/main/__tests__/projectPages.test.cjs +0 -137
  218. package/src/main/__tests__/promptSessionEvents.test.cjs +0 -234
  219. package/src/main/__tests__/promptSessionSchema.test.cjs +0 -101
  220. package/src/main/__tests__/promptSessionTranscript.test.cjs +0 -0
  221. package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +0 -159
  222. package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +0 -282
  223. package/src/main/__tests__/pty-session-open-telemetry.test.cjs +0 -96
  224. package/src/main/__tests__/pty-write-result.test.cjs +0 -46
  225. package/src/main/__tests__/queue-health-verdict.test.cjs +0 -170
  226. package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +0 -286
  227. package/src/main/__tests__/queue-starvation-per-project.test.cjs +0 -147
  228. package/src/main/__tests__/queueHistory.test.cjs +0 -355
  229. package/src/main/__tests__/queueOps-interactive-ac-lint.test.cjs +0 -65
  230. package/src/main/__tests__/queueOpsArchiveDestination.test.cjs +0 -65
  231. package/src/main/__tests__/queueOpsAutoArchive.test.cjs +0 -211
  232. package/src/main/__tests__/rateLimitPollerStreak.test.cjs +0 -128
  233. package/src/main/__tests__/rcaReport.test.cjs +0 -266
  234. package/src/main/__tests__/reconcileFlatPrdSweep.test.cjs +0 -119
  235. package/src/main/__tests__/reconcileTiming.test.cjs +0 -135
  236. package/src/main/__tests__/runLogRetention.test.cjs +0 -489
  237. package/src/main/__tests__/runVerify-atomic-verdicts.test.cjs +0 -26
  238. package/src/main/__tests__/runVerify-blocked-by-foreign-wip.test.cjs +0 -58
  239. package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +0 -191
  240. package/src/main/__tests__/runVerify-policy-denial.test.cjs +0 -89
  241. package/src/main/__tests__/runVerify-transcript-commit-evidence.test.cjs +0 -225
  242. package/src/main/__tests__/runVerify.test.cjs +0 -1784
  243. package/src/main/__tests__/scheduleJobSchema.test.cjs +0 -127
  244. package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +0 -65
  245. package/src/main/__tests__/scheduleJobTransitions.test.cjs +0 -277
  246. package/src/main/__tests__/scheduleJobTransitionsGrep.test.cjs +0 -59
  247. package/src/main/__tests__/scheduleJobTransitionsTelemetryTap.test.cjs +0 -72
  248. package/src/main/__tests__/scheduler-admin-routes.test.cjs +0 -199
  249. package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +0 -143
  250. package/src/main/__tests__/scheduler-already-satisfied-on-main.test.cjs +0 -105
  251. package/src/main/__tests__/scheduler-archive-completed-prd.test.cjs +0 -102
  252. package/src/main/__tests__/scheduler-archived-twin-guard.test.cjs +0 -155
  253. package/src/main/__tests__/scheduler-autofix-outcome.test.cjs +0 -188
  254. package/src/main/__tests__/scheduler-autofix-select.test.cjs +0 -439
  255. package/src/main/__tests__/scheduler-autopromote.test.cjs +0 -51
  256. package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +0 -101
  257. package/src/main/__tests__/scheduler-blocked-by-foreign-wip.test.cjs +0 -107
  258. package/src/main/__tests__/scheduler-boot-orphans.test.cjs +0 -153
  259. package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +0 -121
  260. package/src/main/__tests__/scheduler-clear-queue-history.test.cjs +0 -134
  261. package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +0 -244
  262. package/src/main/__tests__/scheduler-committed-in-window.test.cjs +0 -182
  263. package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +0 -43
  264. package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +0 -168
  265. package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +0 -58
  266. package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +0 -81
  267. package/src/main/__tests__/scheduler-epic-digest.test.cjs +0 -227
  268. package/src/main/__tests__/scheduler-failed-autoreset.test.cjs +0 -121
  269. package/src/main/__tests__/scheduler-finalize-dispatch-guards.test.cjs +0 -229
  270. package/src/main/__tests__/scheduler-find-prd-dir.test.cjs +0 -75
  271. package/src/main/__tests__/scheduler-fix-plan-path.test.cjs +0 -119
  272. package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +0 -46
  273. package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +0 -78
  274. package/src/main/__tests__/scheduler-gate-shadow.test.cjs +0 -119
  275. package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +0 -390
  276. package/src/main/__tests__/scheduler-heal-refusal.test.cjs +0 -61
  277. package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +0 -80
  278. package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +0 -323
  279. package/src/main/__tests__/scheduler-integration-failure-stamp.test.cjs +0 -41
  280. package/src/main/__tests__/scheduler-investigation-clean-skip.test.cjs +0 -63
  281. package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +0 -123
  282. package/src/main/__tests__/scheduler-job-budget.test.cjs +0 -172
  283. package/src/main/__tests__/scheduler-job-overrun.test.cjs +0 -175
  284. package/src/main/__tests__/scheduler-launch-failure.test.cjs +0 -199
  285. package/src/main/__tests__/scheduler-leftover-fields.test.cjs +0 -52
  286. package/src/main/__tests__/scheduler-leftover-quarantine.test.cjs +0 -199
  287. package/src/main/__tests__/scheduler-looks-done.test.cjs +0 -537
  288. package/src/main/__tests__/scheduler-manual-pause.test.cjs +0 -118
  289. package/src/main/__tests__/scheduler-mechanical-recovery.test.cjs +0 -245
  290. package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +0 -46
  291. package/src/main/__tests__/scheduler-mutate-reentrancy.test.cjs +0 -117
  292. package/src/main/__tests__/scheduler-needs-review-autoresolve.test.cjs +0 -197
  293. package/src/main/__tests__/scheduler-never-stop.test.cjs +0 -157
  294. package/src/main/__tests__/scheduler-no-dead-end-status.test.cjs +0 -152
  295. package/src/main/__tests__/scheduler-no-orphan-run-dir.test.cjs +0 -81
  296. package/src/main/__tests__/scheduler-notify-originating-tab-transcript.test.cjs +0 -87
  297. package/src/main/__tests__/scheduler-notify-originating-tab.test.cjs +0 -343
  298. package/src/main/__tests__/scheduler-periodic-reverify-guard.test.cjs +0 -217
  299. package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +0 -164
  300. package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +0 -161
  301. package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +0 -178
  302. package/src/main/__tests__/scheduler-quarantine-autoresolve.test.cjs +0 -165
  303. package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +0 -257
  304. package/src/main/__tests__/scheduler-rate-limit-cooldown-freshness.test.cjs +0 -123
  305. package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +0 -152
  306. package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +0 -156
  307. package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +0 -754
  308. package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +0 -87
  309. package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +0 -100
  310. package/src/main/__tests__/scheduler-reconcile-history-backfill.test.cjs +0 -105
  311. package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +0 -203
  312. package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +0 -247
  313. package/src/main/__tests__/scheduler-reset-job-fields-guard.test.cjs +0 -77
  314. package/src/main/__tests__/scheduler-resume-recovery.test.cjs +0 -254
  315. package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +0 -115
  316. package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +0 -380
  317. package/src/main/__tests__/scheduler-sigterm-commit.test.cjs +0 -43
  318. package/src/main/__tests__/scheduler-stall-per-project.test.cjs +0 -126
  319. package/src/main/__tests__/scheduler-starve-escalation.test.cjs +0 -154
  320. package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +0 -252
  321. package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +0 -185
  322. package/src/main/__tests__/scheduler-stuck-failed-escalation.test.cjs +0 -136
  323. package/src/main/__tests__/scheduler-supervisor-record.test.cjs +0 -81
  324. package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +0 -54
  325. package/src/main/__tests__/scheduler-tick-wedge.test.cjs +0 -172
  326. package/src/main/__tests__/scheduler-transient-failure.test.cjs +0 -141
  327. package/src/main/__tests__/scheduler-unreadable-queue-guard.test.cjs +0 -62
  328. package/src/main/__tests__/scheduler-utilization-hold.test.cjs +0 -89
  329. package/src/main/__tests__/scheduler-verify-prd-path.test.cjs +0 -109
  330. package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +0 -234
  331. package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +0 -120
  332. package/src/main/__tests__/scheduler-writeprd-epic-rollback.test.cjs +0 -105
  333. package/src/main/__tests__/schedulerBatchRootBlocker.test.cjs +0 -117
  334. package/src/main/__tests__/schedulerStateSidecarRestore.test.cjs +0 -110
  335. package/src/main/__tests__/seedAgentPersonas.test.cjs +0 -184
  336. package/src/main/__tests__/seedSchedulerMcp.test.cjs +0 -211
  337. package/src/main/__tests__/seedStatus.test.cjs +0 -100
  338. package/src/main/__tests__/seedValidatorPersona.test.cjs +0 -116
  339. package/src/main/__tests__/stop-signal-anchor.test.cjs +0 -75
  340. package/src/main/__tests__/telemetryClient.test.cjs +0 -1055
  341. package/src/main/__tests__/telemetryContract.test.cjs +0 -930
  342. package/src/main/__tests__/telemetrySettings.test.cjs +0 -210
  343. package/src/main/__tests__/transcripts-batch-flush.test.cjs +0 -249
  344. package/src/main/__tests__/transcripts-doFlush-array.test.cjs +0 -124
  345. package/src/main/__tests__/transcripts-paged-reads.test.cjs +0 -241
  346. package/src/main/__tests__/transcripts-worktree-epic-path.test.cjs +0 -154
  347. package/src/main/__tests__/transcriptsUsageFor.test.cjs +0 -206
  348. package/src/main/__tests__/uniquePrdNumbers.test.cjs +0 -153
  349. package/src/main/__tests__/usageSingleFlight.test.cjs +0 -169
  350. package/src/main/__tests__/validationSentinels.test.cjs +0 -84
  351. package/src/main/__tests__/workTypeLibrary.test.cjs +0 -89
  352. package/src/main/bilkoHost.cjs +0 -314
  353. package/src/main/bilkoHostCore.cjs +0 -89
  354. package/src/main/lib/__tests__/active-sessions.test.cjs +0 -251
  355. package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +0 -179
  356. package/src/main/lib/__tests__/agentPersonaSchema.test.cjs +0 -67
  357. package/src/main/lib/__tests__/auditLog.test.cjs +0 -38
  358. package/src/main/lib/__tests__/bootSelfHeal.test.cjs +0 -107
  359. package/src/main/lib/__tests__/branchSweep.test.cjs +0 -164
  360. package/src/main/lib/__tests__/buildIdentity.test.cjs +0 -121
  361. package/src/main/lib/__tests__/buildTarget.test.cjs +0 -52
  362. package/src/main/lib/__tests__/childWithLog.test.cjs +0 -321
  363. package/src/main/lib/__tests__/coldBootPromptSessionsWrite.test.cjs +0 -87
  364. package/src/main/lib/__tests__/crashTelemetry.test.cjs +0 -103
  365. package/src/main/lib/__tests__/credentials-futile-refresh.test.cjs +0 -115
  366. package/src/main/lib/__tests__/cwdClassify.test.cjs +0 -111
  367. package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +0 -95
  368. package/src/main/lib/__tests__/delegationReadiness.test.cjs +0 -1175
  369. package/src/main/lib/__tests__/dispatchLoop.test.cjs +0 -63
  370. package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +0 -244
  371. package/src/main/lib/__tests__/ephemeralCwd.test.cjs +0 -91
  372. package/src/main/lib/__tests__/epicDelegationStats.test.cjs +0 -137
  373. package/src/main/lib/__tests__/epicSpawnCwd.test.cjs +0 -283
  374. package/src/main/lib/__tests__/epicSpawnPlan.test.cjs +0 -196
  375. package/src/main/lib/__tests__/epicTranscriptPath.test.cjs +0 -163
  376. package/src/main/lib/__tests__/epicWorktreeBoot.test.cjs +0 -136
  377. package/src/main/lib/__tests__/epicWorktreeMerge.test.cjs +0 -130
  378. package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +0 -117
  379. package/src/main/lib/__tests__/epicWorktreeProjectConfig.test.cjs +0 -137
  380. package/src/main/lib/__tests__/fixChainDepth.test.cjs +0 -40
  381. package/src/main/lib/__tests__/fixtures/204-mercury-steam-horse.log.txt +0 -13
  382. package/src/main/lib/__tests__/fixtures/scheduler-machine.json.corrupt-1789147548 +0 -34
  383. package/src/main/lib/__tests__/gateFixtures.json +0 -20
  384. package/src/main/lib/__tests__/gitCacheBound.test.cjs +0 -69
  385. package/src/main/lib/__tests__/gitWorktree.test.cjs +0 -1478
  386. package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +0 -107
  387. package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +0 -153
  388. package/src/main/lib/__tests__/guardShims.test.cjs +0 -158
  389. package/src/main/lib/__tests__/importReferences.spec.cjs +0 -56
  390. package/src/main/lib/__tests__/instanceLock.test.cjs +0 -173
  391. package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +0 -78
  392. package/src/main/lib/__tests__/jobWorktree.test.cjs +0 -199
  393. package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +0 -82
  394. package/src/main/lib/__tests__/landedSinceRun.test.cjs +0 -133
  395. package/src/main/lib/__tests__/launchFailure.test.cjs +0 -220
  396. package/src/main/lib/__tests__/loadGate.test.cjs +0 -303
  397. package/src/main/lib/__tests__/localAdminHttp.test.cjs +0 -214
  398. package/src/main/lib/__tests__/loopDelay.test.cjs +0 -68
  399. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +0 -107
  400. package/src/main/lib/__tests__/modelCatalog.test.cjs +0 -202
  401. package/src/main/lib/__tests__/opsOwnership.test.cjs +0 -113
  402. package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +0 -328
  403. package/src/main/lib/__tests__/opsRootNestedWrite.test.cjs +0 -51
  404. package/src/main/lib/__tests__/opsRootResolve.test.cjs +0 -149
  405. package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +0 -82
  406. package/src/main/lib/__tests__/prdDisposition.test.cjs +0 -224
  407. package/src/main/lib/__tests__/procIdentity.test.cjs +0 -119
  408. package/src/main/lib/__tests__/procName.test.cjs +0 -92
  409. package/src/main/lib/__tests__/projectBriefCore.test.cjs +0 -216
  410. package/src/main/lib/__tests__/projectRootResolve.test.cjs +0 -148
  411. package/src/main/lib/__tests__/queueHealth.test.cjs +0 -58
  412. package/src/main/lib/__tests__/queueStoreAtomicWrite.test.cjs +0 -88
  413. package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +0 -190
  414. package/src/main/lib/__tests__/quietMachineLease.test.cjs +0 -39
  415. package/src/main/lib/__tests__/rateLimitWindow.test.cjs +0 -88
  416. package/src/main/lib/__tests__/reaperHelpers.test.cjs +0 -577
  417. package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +0 -312
  418. package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +0 -213
  419. package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +0 -125
  420. package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +0 -127
  421. package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +0 -109
  422. package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +0 -71
  423. package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +0 -216
  424. package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +0 -183
  425. package/src/main/lib/__tests__/schedulerPaths.test.cjs +0 -226
  426. package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +0 -133
  427. package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +0 -56
  428. package/src/main/lib/__tests__/sessionSlots.test.cjs +0 -144
  429. package/src/main/lib/__tests__/telemetryBacklog.test.cjs +0 -626
  430. package/src/main/lib/__tests__/telemetryBoot.test.cjs +0 -134
  431. package/src/main/lib/__tests__/telemetryConsent.test.cjs +0 -136
  432. package/src/main/lib/__tests__/telemetryCounters.test.cjs +0 -57
  433. package/src/main/lib/__tests__/telemetryCountersMetadataColumn.test.cjs +0 -98
  434. package/src/main/lib/__tests__/terminalRunOutcome.test.cjs +0 -200
  435. package/src/main/lib/__tests__/toolUseClassify.test.cjs +0 -53
  436. package/src/main/lib/__tests__/updateCheck.test.cjs +0 -63
  437. package/src/main/lib/__tests__/upgradeDrain.test.cjs +0 -130
  438. package/src/main/lib/__tests__/usageCircuit.test.cjs +0 -354
  439. package/src/main/lib/__tests__/watchdog-helpers.test.cjs +0 -441
  440. package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +0 -266
  441. package/src/main/lib/kgExchangePairing.cjs +0 -75
@@ -1,107 +0,0 @@
1
- /**
2
- * gitWorktreeSalvage.test.cjs — PRD 1071: a job worktree's uncommitted diff
3
- * (tracked + untracked) is salvaged to a patch file before teardown, so a
4
- * job killed before its finish-protocol commit doesn't lose its work when
5
- * cleanupWorktree removes the checkout right after.
6
- *
7
- * Run: timeout 120 npx vitest run src/main/lib/__tests__/gitWorktreeSalvage.test.cjs
8
- */
9
-
10
- 'use strict';
11
-
12
- import { test, expect, beforeEach, afterEach } from 'vitest';
13
- const fs = require('node:fs');
14
- const os = require('node:os');
15
- const path = require('node:path');
16
- const { execFileSync } = require('node:child_process');
17
- const gitWorktree = require('../gitWorktree.cjs');
18
-
19
- let tmpRoot;
20
- let repoCwd;
21
- // config.cjs's writeTextAtomic (used internally by salvageWorktreeDiff)
22
- // restricts writes to a fixed allowlist — real prod call sites write under
23
- // `~/.claude/session-manager/scheduled-plans/runs/...`, which is covered by
24
- // config.cjs's WRITE_PREFIXES. Mirror that here instead of writing under
25
- // os.tmpdir() (which validateWrite would reject) — same convention as
26
- // coldBootPromptSessionsWrite.test.cjs.
27
- let outDir;
28
-
29
- function git(args, cwd) {
30
- return execFileSync('git', args, { cwd, encoding: 'utf8' });
31
- }
32
-
33
- function initRepo(dir) {
34
- fs.mkdirSync(dir, { recursive: true });
35
- git(['init', '-q'], dir);
36
- git(['config', 'user.email', 'test@example.com'], dir);
37
- git(['config', 'user.name', 'Test'], dir);
38
- fs.writeFileSync(path.join(dir, 'README.md'), 'hello\n', 'utf8');
39
- git(['add', '-A'], dir);
40
- git(['commit', '-q', '-m', 'initial'], dir);
41
- }
42
-
43
- beforeEach(() => {
44
- tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-gitworktree-salvage-'));
45
- repoCwd = path.join(tmpRoot, 'repo');
46
- initRepo(repoCwd);
47
- outDir = fs.mkdtempSync(path.join(os.homedir(), '.claude', 'sm-test-salvage-'));
48
- gitWorktree._resetActiveWorktreeCountForTests('job', 0);
49
- });
50
-
51
- afterEach(() => {
52
- fs.rmSync(tmpRoot, { recursive: true, force: true });
53
- fs.rmSync(outDir, { recursive: true, force: true });
54
- });
55
-
56
- test('dirty worktree (tracked edit + untracked file) produces a non-empty patch with the untracked file\'s contents', async () => {
57
- const slug = 'salvage-dirty';
58
- const created = await gitWorktree.createJobWorktree({ cwd: repoCwd, slug });
59
- expect(created.ok).toBe(true);
60
-
61
- fs.writeFileSync(path.join(created.dir, 'README.md'), 'hello\nedited\n', 'utf8');
62
- fs.writeFileSync(path.join(created.dir, 'new-file.txt'), 'brand new untracked content\n', 'utf8');
63
-
64
- const outFile = path.join(outDir, `${slug}.uncommitted.patch`);
65
- const result = await gitWorktree.salvageWorktreeDiff({ cwd: created.dir, outFile });
66
-
67
- expect(result.ok).toBe(true);
68
- expect(result.bytes).toBeGreaterThan(0);
69
- expect(fs.existsSync(outFile)).toBe(true);
70
- const patch = fs.readFileSync(outFile, 'utf8');
71
- expect(patch).toContain('new-file.txt');
72
- expect(patch).toContain('brand new untracked content');
73
- expect(patch).toContain('README.md');
74
- expect(patch).toContain('edited');
75
-
76
- await gitWorktree.cleanupJobWorktree({ cwd: repoCwd, dir: created.dir, branch: created.branch });
77
- });
78
-
79
- test('clean worktree produces no patch file (no 0-byte artifact)', async () => {
80
- const slug = 'salvage-clean';
81
- const created = await gitWorktree.createJobWorktree({ cwd: repoCwd, slug });
82
- expect(created.ok).toBe(true);
83
-
84
- const outFile = path.join(outDir, `${slug}.uncommitted.patch`);
85
- const result = await gitWorktree.salvageWorktreeDiff({ cwd: created.dir, outFile });
86
-
87
- expect(result.ok).toBe(false);
88
- expect(fs.existsSync(outFile)).toBe(false);
89
-
90
- await gitWorktree.cleanupJobWorktree({ cwd: repoCwd, dir: created.dir, branch: created.branch });
91
- });
92
-
93
- test('a git failure during salvage is swallowed (never throws) and cleanup still runs', async () => {
94
- const notAGitRepo = path.join(tmpRoot, 'not-a-repo');
95
- fs.mkdirSync(notAGitRepo, { recursive: true });
96
- const outFile = path.join(outDir, 'salvage-failure.uncommitted.patch');
97
-
98
- await expect(gitWorktree.salvageWorktreeDiff({ cwd: notAGitRepo, outFile })).resolves.toEqual({ ok: false });
99
- expect(fs.existsSync(outFile)).toBe(false);
100
-
101
- // Cleanup of an unrelated, never-created worktree is itself a no-op but
102
- // must still resolve without throwing — mirrors the finally-block shape in
103
- // scheduler.cjs where salvage failure must never block integration/cleanup.
104
- await expect(
105
- gitWorktree.cleanupJobWorktree({ cwd: repoCwd, dir: path.join(tmpRoot, 'never-existed'), branch: 'sm-job/does-not-exist' }),
106
- ).resolves.toBeUndefined();
107
- });
@@ -1,153 +0,0 @@
1
- /**
2
- * gitWorktreeSalvageDelta.test.cjs — PRD 1098: `salvageDirtyDelta` is the
3
- * shared-tree counterpart to `salvageWorktreeDiff` (gitWorktreeSalvage.test.cjs)
4
- * — it salvages an IN-PLACE job's uncommitted work without a throwaway
5
- * worktree checkout to diff and discard, so it must be strictly DELTA-scoped
6
- * (only the caller-supplied paths, never a whole-tree dump) and must never
7
- * mutate the shared tree (no add/stash/reset/checkout/clean) the way
8
- * `salvageWorktreeDiff`'s `git add -A --intent-to-add` deliberately can
9
- * against a disposable checkout.
10
- *
11
- * Run: timeout 120 npx vitest run src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs
12
- */
13
-
14
- 'use strict';
15
-
16
- import { test, expect, beforeEach, afterEach } from 'vitest';
17
- const fs = require('node:fs');
18
- const os = require('node:os');
19
- const path = require('node:path');
20
- const { execFileSync } = require('node:child_process');
21
- const gitWorktree = require('../gitWorktree.cjs');
22
-
23
- let tmpRoot;
24
- let repoCwd;
25
- let outDir;
26
-
27
- function git(args, cwd) {
28
- return execFileSync('git', args, { cwd, encoding: 'utf8' });
29
- }
30
-
31
- function initRepo(dir) {
32
- fs.mkdirSync(dir, { recursive: true });
33
- git(['init', '-q'], dir);
34
- git(['config', 'user.email', 'test@example.com'], dir);
35
- git(['config', 'user.name', 'Test'], dir);
36
- fs.writeFileSync(path.join(dir, 'README.md'), 'hello\n', 'utf8');
37
- fs.writeFileSync(path.join(dir, 'tracked-a.txt'), 'a\n', 'utf8');
38
- fs.writeFileSync(path.join(dir, 'tracked-b.txt'), 'b\n', 'utf8');
39
- git(['add', '-A'], dir);
40
- git(['commit', '-q', '-m', 'initial'], dir);
41
- }
42
-
43
- beforeEach(() => {
44
- tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-gitworktree-salvage-delta-'));
45
- repoCwd = path.join(tmpRoot, 'repo');
46
- initRepo(repoCwd);
47
- outDir = fs.mkdtempSync(path.join(os.homedir(), '.claude', 'sm-test-salvage-delta-'));
48
- });
49
-
50
- afterEach(() => {
51
- fs.rmSync(tmpRoot, { recursive: true, force: true });
52
- fs.rmSync(outDir, { recursive: true, force: true });
53
- });
54
-
55
- test('salvages only the given delta paths (tracked edit + untracked new file), never a pre-existing dirty file outside the delta', async () => {
56
- // Pre-existing WIP that must NEVER appear in the patch — the whole point
57
- // of delta-scoping.
58
- fs.writeFileSync(path.join(repoCwd, 'tracked-b.txt'), 'b\npre-existing human WIP\n', 'utf8');
59
-
60
- // This job's own delta: an edit to tracked-a.txt and a new untracked file.
61
- fs.writeFileSync(path.join(repoCwd, 'tracked-a.txt'), 'a\nedited by job\n', 'utf8');
62
- fs.writeFileSync(path.join(repoCwd, 'job-new-file.txt'), 'brand new job output\n', 'utf8');
63
-
64
- const outFile = path.join(outDir, 'delta.uncommitted.patch');
65
- const result = await gitWorktree.salvageDirtyDelta({
66
- cwd: repoCwd,
67
- paths: ['tracked-a.txt', 'job-new-file.txt'],
68
- outFile,
69
- });
70
-
71
- expect(result.ok).toBe(true);
72
- expect(result.bytes).toBeGreaterThan(0);
73
- const patch = fs.readFileSync(outFile, 'utf8');
74
- expect(patch).toContain('tracked-a.txt');
75
- expect(patch).toContain('edited by job');
76
- expect(patch).toContain('job-new-file.txt');
77
- expect(patch).toContain('brand new job output');
78
- // The sibling/human's pre-existing dirty file is NOT in the delta list —
79
- // it must never leak into this job's patch.
80
- expect(patch).not.toContain('pre-existing human WIP');
81
- });
82
-
83
- test('applies cleanly with git apply --check against a fresh clone of the base tree', async () => {
84
- fs.writeFileSync(path.join(repoCwd, 'tracked-a.txt'), 'a\nedited\n', 'utf8');
85
- fs.writeFileSync(path.join(repoCwd, 'job-new-file.txt'), 'new content\n', 'utf8');
86
-
87
- const outFile = path.join(outDir, 'apply-check.uncommitted.patch');
88
- const result = await gitWorktree.salvageDirtyDelta({
89
- cwd: repoCwd,
90
- paths: ['tracked-a.txt', 'job-new-file.txt'],
91
- outFile,
92
- });
93
- expect(result.ok).toBe(true);
94
-
95
- // Fresh clone of the same commit, clean, to prove the patch is
96
- // self-sufficient and applies against the pristine base state.
97
- const cleanCheckout = path.join(tmpRoot, 'clean-checkout');
98
- git(['clone', '-q', repoCwd, cleanCheckout], tmpRoot);
99
- expect(() => git(['apply', '--check', outFile], cleanCheckout)).not.toThrow();
100
- });
101
-
102
- test('never mutates the shared tree: git status and stash list are byte-identical before and after', async () => {
103
- // A human's own pre-existing WIP, deliberately outside the delta.
104
- fs.writeFileSync(path.join(repoCwd, 'tracked-b.txt'), 'b\nhuman wip\n', 'utf8');
105
- fs.writeFileSync(path.join(repoCwd, 'tracked-a.txt'), 'a\njob edit\n', 'utf8');
106
- fs.writeFileSync(path.join(repoCwd, 'job-new-file.txt'), 'job output\n', 'utf8');
107
-
108
- const statusBefore = git(['status', '--porcelain'], repoCwd);
109
- const stashBefore = git(['stash', 'list'], repoCwd);
110
-
111
- const outFile = path.join(outDir, 'no-mutate.uncommitted.patch');
112
- const result = await gitWorktree.salvageDirtyDelta({
113
- cwd: repoCwd,
114
- paths: ['tracked-a.txt', 'job-new-file.txt'],
115
- outFile,
116
- });
117
- expect(result.ok).toBe(true);
118
-
119
- const statusAfter = git(['status', '--porcelain'], repoCwd);
120
- const stashAfter = git(['stash', 'list'], repoCwd);
121
- expect(statusAfter).toBe(statusBefore);
122
- expect(stashAfter).toBe(stashBefore);
123
- });
124
-
125
- test('no delta paths dirty at call time produces no patch file (no 0-byte artifact)', async () => {
126
- const outFile = path.join(outDir, 'clean.uncommitted.patch');
127
- const result = await gitWorktree.salvageDirtyDelta({
128
- cwd: repoCwd,
129
- paths: ['tracked-a.txt'],
130
- outFile,
131
- });
132
- expect(result.ok).toBe(false);
133
- expect(fs.existsSync(outFile)).toBe(false);
134
- });
135
-
136
- test('empty paths list is a no-op', async () => {
137
- const outFile = path.join(outDir, 'empty.uncommitted.patch');
138
- const result = await gitWorktree.salvageDirtyDelta({ cwd: repoCwd, paths: [], outFile });
139
- expect(result.ok).toBe(false);
140
- expect(fs.existsSync(outFile)).toBe(false);
141
- });
142
-
143
- test('a git failure (not a repo) is swallowed and never throws', async () => {
144
- const notAGitRepo = path.join(tmpRoot, 'not-a-repo');
145
- fs.mkdirSync(notAGitRepo, { recursive: true });
146
- fs.writeFileSync(path.join(notAGitRepo, 'x.txt'), 'x\n', 'utf8');
147
- const outFile = path.join(outDir, 'failure.uncommitted.patch');
148
-
149
- await expect(
150
- gitWorktree.salvageDirtyDelta({ cwd: notAGitRepo, paths: ['x.txt'], outFile }),
151
- ).resolves.toEqual({ ok: false });
152
- expect(fs.existsSync(outFile)).toBe(false);
153
- });
@@ -1,158 +0,0 @@
1
- /**
2
- * guardShims.test.cjs — unit tests for the stable, app-upgrade-proof guard
3
- * hook indirection (guardShims.cjs). Uses a temp "home" dir per test so the
4
- * real ~/.claude is never touched.
5
- *
6
- * Run: timeout 120 npx vitest run src/main/lib/__tests__/guardShims.test.cjs
7
- */
8
-
9
- import { test, expect, afterEach } from 'vitest';
10
- const fs = require('node:fs');
11
- const fsp = require('node:fs/promises');
12
- const os = require('node:os');
13
- const path = require('node:path');
14
- const { execFileSync } = require('node:child_process');
15
- const {
16
- APP_ROOT,
17
- GUARD_NAMES,
18
- hooksDir,
19
- pointerPath,
20
- shimPath,
21
- writeGuardShims,
22
- guardShimsExist,
23
- } = require('../guardShims.cjs');
24
-
25
- const tmpDirs = [];
26
- afterEach(async () => {
27
- while (tmpDirs.length) {
28
- const d = tmpDirs.pop();
29
- await fsp.rm(d, { recursive: true, force: true });
30
- }
31
- });
32
-
33
- async function mkTmp(prefix) {
34
- const d = await fsp.mkdtemp(path.join(os.tmpdir(), prefix));
35
- tmpDirs.push(d);
36
- return d;
37
- }
38
-
39
- /** Run a guard (by absolute path, e.g. a shim) as a child process, same
40
- * pattern delegationReadiness.test.cjs uses to exercise the real guards —
41
- * NEVER require() a guard/shim in-process, since its main() calls
42
- * process.exit(0) as a require-time side effect. */
43
- function runGuard(scriptPath, { toolName = 'Write', toolInput, cwd }) {
44
- return JSON.parse(execFileSync('node', [scriptPath], {
45
- input: JSON.stringify({ tool_name: toolName, tool_input: toolInput, cwd }),
46
- encoding: 'utf8',
47
- }));
48
- }
49
-
50
- test('writeGuardShims: writes the pointer file and all three shims under homeDir', async () => {
51
- const homeDir = await mkTmp('sm-guard-shims-home-');
52
- const r = await writeGuardShims({ homeDir });
53
- expect(r.ok).toBe(true);
54
-
55
- expect(fs.existsSync(pointerPath(homeDir))).toBe(true);
56
- expect(JSON.parse(fs.readFileSync(pointerPath(homeDir), 'utf8'))).toEqual({ appRoot: APP_ROOT });
57
- for (const name of GUARD_NAMES) {
58
- expect(fs.existsSync(shimPath(name, homeDir))).toBe(true);
59
- }
60
- expect(guardShimsExist(homeDir)).toBe(true);
61
- });
62
-
63
- test('writeGuardShims: does NOT vendor guard logic — the shim body only references the guard by name, never copies its source', async () => {
64
- const homeDir = await mkTmp('sm-guard-shims-home-');
65
- await writeGuardShims({ homeDir });
66
-
67
- const realSource = fs.readFileSync(path.join(APP_ROOT, 'scripts', 'hooks', 'guard-prd-writes.cjs'), 'utf8');
68
- const shimSource = fs.readFileSync(shimPath('guard-prd-writes.cjs', homeDir), 'utf8');
69
- expect(shimSource).not.toContain('SCHEDULER_SEGMENT'); // a guard-prd-writes-specific symbol
70
- expect(shimSource.length).toBeLessThan(realSource.length / 2);
71
- expect(shimSource).toContain("require(path.join(ptr.appRoot, 'scripts', 'hooks', 'guard-prd-writes.cjs'))");
72
- });
73
-
74
- test('writeGuardShims: idempotent — re-running with the same appRoot produces byte-identical files', async () => {
75
- const homeDir = await mkTmp('sm-guard-shims-home-');
76
- const r1 = await writeGuardShims({ homeDir });
77
- expect(r1.ok).toBe(true);
78
- const pointerBefore = fs.readFileSync(pointerPath(homeDir), 'utf8');
79
- const shimsBefore = GUARD_NAMES.map((n) => fs.readFileSync(shimPath(n, homeDir), 'utf8'));
80
-
81
- const r2 = await writeGuardShims({ homeDir });
82
- expect(r2.ok).toBe(true);
83
- expect(fs.readFileSync(pointerPath(homeDir), 'utf8')).toBe(pointerBefore);
84
- GUARD_NAMES.forEach((n, i) => {
85
- expect(fs.readFileSync(shimPath(n, homeDir), 'utf8')).toBe(shimsBefore[i]);
86
- });
87
- });
88
-
89
- test('writeGuardShims: the installed shim actually resolves through the pointer and runs the real guard logic', async () => {
90
- const homeDir = await mkTmp('sm-guard-shims-home-');
91
- const cwd = await mkTmp('sm-guard-shims-cwd-');
92
- await writeGuardShims({ homeDir });
93
-
94
- const denied = runGuard(shimPath('guard-prd-writes.cjs', homeDir), {
95
- toolInput: { file_path: path.join(cwd, 'session-manager-operations', 'scheduler', 'prds', '1234-x.md'), content: '# x' },
96
- cwd,
97
- });
98
- expect(denied.hookSpecificOutput?.permissionDecision).toBe('deny');
99
-
100
- const allowed = runGuard(shimPath('guard-prd-writes.cjs', homeDir), {
101
- toolInput: { file_path: path.join(cwd, 'src', 'x.ts'), content: 'x' },
102
- cwd,
103
- });
104
- expect(allowed.hookSpecificOutput?.permissionDecision).not.toBe('deny');
105
- });
106
-
107
- test('writeGuardShims: rewriting the pointer to a DIFFERENT app root lets an already-installed shim follow an app upgrade with no re-install', async () => {
108
- const homeDir = await mkTmp('sm-guard-shims-home-');
109
- const cwd = await mkTmp('sm-guard-shims-cwd-');
110
- await writeGuardShims({ homeDir }); // "first install", points at the real APP_ROOT
111
- const shimFile = shimPath('guard-prd-writes.cjs', homeDir);
112
- const shimBytesBefore = fs.readFileSync(shimFile, 'utf8');
113
-
114
- // Simulate an app upgrade: a second "app root" at a brand-new path, with
115
- // its own copy of scripts/hooks/guard-prd-writes.cjs — the file guardShims
116
- // reads through the pointer at invocation time — plus the sibling policy
117
- // module it `require()`s at load time (guard-prd-writes-policy.cjs, PRD
118
- // 1415); a real upgrade ships both since both are listed in package.json's
119
- // "files".
120
- const secondAppRoot = await mkTmp('sm-guard-shims-upgraded-app-');
121
- await fsp.mkdir(path.join(secondAppRoot, 'scripts', 'hooks', 'lib'), { recursive: true });
122
- await fsp.copyFile(
123
- path.join(APP_ROOT, 'scripts', 'hooks', 'guard-prd-writes.cjs'),
124
- path.join(secondAppRoot, 'scripts', 'hooks', 'guard-prd-writes.cjs'),
125
- );
126
- await fsp.copyFile(
127
- path.join(APP_ROOT, 'scripts', 'hooks', 'lib', 'guard-prd-writes-policy.cjs'),
128
- path.join(secondAppRoot, 'scripts', 'hooks', 'lib', 'guard-prd-writes-policy.cjs'),
129
- );
130
-
131
- const r = await writeGuardShims({ homeDir, appRoot: secondAppRoot });
132
- expect(r.ok).toBe(true);
133
- expect(JSON.parse(fs.readFileSync(pointerPath(homeDir), 'utf8')).appRoot).toBe(secondAppRoot);
134
- // The shim FILE at the already-installed path never changed.
135
- expect(fs.readFileSync(shimFile, 'utf8')).toBe(shimBytesBefore);
136
-
137
- // A project hook that already references this exact shim path keeps working.
138
- const denied = runGuard(shimFile, {
139
- toolInput: { file_path: path.join(cwd, 'session-manager-operations', 'scheduler', 'prds', '1234-x.md'), content: '# x' },
140
- cwd,
141
- });
142
- expect(denied.hookSpecificOutput?.permissionDecision).toBe('deny');
143
- });
144
-
145
- test('writeGuardShims: returns { ok:false, error } without throwing when homeDir cannot be written to', async () => {
146
- const base = await mkTmp('sm-guard-shims-unwritable-');
147
- const blocker = path.join(base, 'blocker-file');
148
- await fsp.writeFile(blocker, 'x', 'utf8');
149
- // A homeDir whose parent path segment is a plain FILE can never be mkdir'd
150
- // into (ENOTDIR) — reproduces "unwritable ~/.claude" without relying on
151
- // permission bits, which root would bypass.
152
- const homeDir = path.join(blocker, 'home');
153
-
154
- const r = await writeGuardShims({ homeDir });
155
- expect(r.ok).toBe(false);
156
- expect(r.error).toBeTruthy();
157
- expect(guardShimsExist(homeDir)).toBe(false);
158
- });
@@ -1,56 +0,0 @@
1
- /**
2
- * importReferences.spec.cjs — unit tests for listReferencedFiles, the IPC-facing
3
- * wrapper around personaImportHealth's `@path` import-chain walker.
4
- *
5
- * Run: timeout 120 npx vitest run src/main/lib/__tests__/importReferences.spec.cjs
6
- */
7
-
8
- 'use strict';
9
-
10
- import { test, expect } from 'vitest';
11
- const fs = require('node:fs');
12
- const os = require('node:os');
13
- const path = require('node:path');
14
- const { listReferencedFiles } = require('../importReferences.cjs');
15
-
16
- function mkTmpDir() {
17
- return fs.mkdtempSync(path.join(os.tmpdir(), 'import-refs-test-'));
18
- }
19
-
20
- test('listReferencedFiles: 2 valid @imports returns 2 entries with correct sizeBytes/tokenEstimate/ok', () => {
21
- const dir = mkTmpDir();
22
- const a = path.join(dir, 'a.md');
23
- const b = path.join(dir, 'b.md');
24
- const root = path.join(dir, 'root.md');
25
- fs.writeFileSync(a, 'x'.repeat(40));
26
- fs.writeFileSync(b, 'y'.repeat(8));
27
- fs.writeFileSync(root, `@${a}\n@${b}\n`);
28
-
29
- const result = listReferencedFiles(root);
30
-
31
- expect(result).toHaveLength(2);
32
- const byPath = Object.fromEntries(result.map((r) => [r.path, r]));
33
- expect(byPath[a]).toEqual({ path: a, exists: true, sizeBytes: 40, tokenEstimate: 10, ok: true });
34
- expect(byPath[b]).toEqual({ path: b, exists: true, sizeBytes: 8, tokenEstimate: 2, ok: true });
35
- });
36
-
37
- test('listReferencedFiles: missing import returns ok=false with sizeBytes 0', () => {
38
- const dir = mkTmpDir();
39
- const missing = path.join(dir, 'does-not-exist.md');
40
- const root = path.join(dir, 'root.md');
41
- fs.writeFileSync(root, `@${missing}\n`);
42
-
43
- const result = listReferencedFiles(root);
44
-
45
- expect(result).toEqual([
46
- { path: missing, exists: false, sizeBytes: 0, tokenEstimate: 0, ok: false },
47
- ]);
48
- });
49
-
50
- test('listReferencedFiles: zero @import lines returns an empty array', () => {
51
- const dir = mkTmpDir();
52
- const root = path.join(dir, 'root.md');
53
- fs.writeFileSync(root, 'no imports here, just prose.\n');
54
-
55
- expect(listReferencedFiles(root)).toEqual([]);
56
- });
@@ -1,173 +0,0 @@
1
- // PRD 834 — machine-wide scheduler-ownership lock. Secondary instances must
2
- // go scheduler-passive instead of running boot reconciliation / admin server
3
- // against the owner's queue state (live incident 2026-07-31).
4
- //
5
- // HOME is stubbed to a mkdtemp dir BEFORE requiring instanceLock.cjs (mirrors
6
- // scheduler-reconcile-invalid-repair.test.cjs): instanceLock.cjs pulls in
7
- // auditLog.cjs, whose audit log path resolves from
8
- // os.homedir() — so real ~/.claude/session-manager state must never be
9
- // touched by this suite.
10
- import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
11
- import fs from 'node:fs';
12
- import os from 'node:os';
13
- import path from 'node:path';
14
-
15
- let originalHome;
16
- let tmpHome;
17
- let instanceLock;
18
- let auditLogPath;
19
-
20
- beforeAll(() => {
21
- originalHome = process.env.HOME;
22
- tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-instance-lock-home-'));
23
- process.env.HOME = tmpHome;
24
- instanceLock = require('../instanceLock.cjs');
25
- ({ auditLogPath } = require('../auditLog.cjs'));
26
- if (!auditLogPath().startsWith(tmpHome)) {
27
- throw new Error(`refusing to run: auditLogPath() (${auditLogPath()}) is not under the temp HOME (${tmpHome})`);
28
- }
29
- });
30
-
31
- afterAll(() => {
32
- process.env.HOME = originalHome;
33
- fs.rmSync(tmpHome, { recursive: true, force: true });
34
- });
35
-
36
- // Thin pass-throughs so every test body below can keep calling these as
37
- // bare names, resolved lazily against the module loaded in beforeAll.
38
- const acquireSchedulerOwnership = (...args) => instanceLock.acquireSchedulerOwnership(...args);
39
- const releaseSchedulerOwnership = (...args) => instanceLock.releaseSchedulerOwnership(...args);
40
- const pidAlive = (...args) => instanceLock.pidAlive(...args);
41
- const lockPath = (...args) => instanceLock.lockPath(...args);
42
-
43
- function readAuditEvents() {
44
- if (!fs.existsSync(auditLogPath())) return [];
45
- return fs.readFileSync(auditLogPath(), 'utf8').trim().split('\n').filter(Boolean).map((l) => JSON.parse(l));
46
- }
47
-
48
- let dir;
49
-
50
- beforeEach(() => {
51
- dir = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-instance-lock-'));
52
- process.env.SM_SCHEDULER_LOCK_PATH = path.join(dir, 'scheduler-owner.lock');
53
- });
54
-
55
- afterEach(() => {
56
- delete process.env.SM_SCHEDULER_LOCK_PATH;
57
- delete process.env.SM_PROC_ROOT;
58
- fs.rmSync(dir, { recursive: true, force: true });
59
- if (fs.existsSync(auditLogPath())) fs.rmSync(auditLogPath(), { force: true });
60
- });
61
-
62
- describe('instanceLock (PRD 834)', () => {
63
- it('first acquirer becomes owner and writes its pid', () => {
64
- const res = acquireSchedulerOwnership();
65
- expect(res.owner).toBe(true);
66
- const onDisk = JSON.parse(fs.readFileSync(lockPath(), 'utf8'));
67
- expect(onDisk.pid).toBe(process.pid);
68
- });
69
-
70
- it('a live foreign holder makes acquisition passive with the holder pid reported', () => {
71
- // Use our own live pid as the "foreign" holder — pidAlive(process.pid) is
72
- // true, and acquire treats pid !== process.pid as foreign, so fake one by
73
- // writing pid 1 (init — always alive, never ours).
74
- fs.mkdirSync(path.dirname(lockPath()), { recursive: true });
75
- fs.writeFileSync(lockPath(), JSON.stringify({ pid: 1, startedAt: 'x' }));
76
- const res = acquireSchedulerOwnership();
77
- expect(res.owner).toBe(false);
78
- expect(res.holderPid).toBe(1);
79
- // The holder's lock is untouched.
80
- expect(JSON.parse(fs.readFileSync(lockPath(), 'utf8')).pid).toBe(1);
81
- });
82
-
83
- it('a stale lock (dead pid) is broken and ownership taken', () => {
84
- // Find a pid that is certainly dead: spawn nothing — use a huge pid
85
- // beyond pid_max defaults.
86
- fs.mkdirSync(path.dirname(lockPath()), { recursive: true });
87
- fs.writeFileSync(lockPath(), JSON.stringify({ pid: 2 ** 30, startedAt: 'x' }));
88
- const res = acquireSchedulerOwnership();
89
- expect(res.owner).toBe(true);
90
- expect(JSON.parse(fs.readFileSync(lockPath(), 'utf8')).pid).toBe(process.pid);
91
- });
92
-
93
- it('re-acquiring our own lock stays owner (idempotent across re-init)', () => {
94
- expect(acquireSchedulerOwnership().owner).toBe(true);
95
- expect(acquireSchedulerOwnership().owner).toBe(true);
96
- });
97
-
98
- it('release removes only our own lock', () => {
99
- acquireSchedulerOwnership();
100
- releaseSchedulerOwnership();
101
- expect(fs.existsSync(lockPath())).toBe(false);
102
- // A foreign lock is never removed by release.
103
- fs.writeFileSync(lockPath(), JSON.stringify({ pid: 1, startedAt: 'x' }));
104
- releaseSchedulerOwnership();
105
- expect(fs.existsSync(lockPath())).toBe(true);
106
- });
107
-
108
- it('a corrupt lock file is treated as stale, not fatal', () => {
109
- fs.mkdirSync(path.dirname(lockPath()), { recursive: true });
110
- fs.writeFileSync(lockPath(), 'not json {');
111
- const res = acquireSchedulerOwnership();
112
- expect(res.owner).toBe(true);
113
- });
114
-
115
- it('pidAlive: own pid alive, absurd pid dead', () => {
116
- expect(pidAlive(process.pid)).toBe(true);
117
- expect(pidAlive(2 ** 30)).toBe(false);
118
- expect(pidAlive(-5)).toBe(false);
119
- expect(pidAlive(0)).toBe(false);
120
- });
121
-
122
- it('a legacy lock ({pid, startedAt} only, no identity) is respected while its pid is alive', () => {
123
- // Mirrors the on-disk shape of every lock written before this PRD.
124
- fs.mkdirSync(path.dirname(lockPath()), { recursive: true });
125
- fs.writeFileSync(lockPath(), JSON.stringify({ pid: 1, startedAt: 'x' }));
126
- const res = acquireSchedulerOwnership();
127
- expect(res.owner).toBe(false);
128
- expect(res.holderPid).toBe(1);
129
- expect(JSON.parse(fs.readFileSync(lockPath(), 'utf8')).pid).toBe(1);
130
- // No identity information to compare, so no stale-lock-broken audit event.
131
- expect(readAuditEvents().some((e) => e.kind === 'stale_lock_broken')).toBe(false);
132
- });
133
-
134
- it('a recorded identity that no longer matches the live process at that (recycled) pid is broken, and audited', () => {
135
- // process.ppid is guaranteed alive for the lifetime of this test (the
136
- // vitest worker's own parent) — stand-in for "a hard crash left a lock
137
- // whose pid was later reused by an unrelated live process".
138
- const recycledPid = process.ppid;
139
- const procRoot = path.join(dir, 'proc');
140
- fs.mkdirSync(path.join(procRoot, String(recycledPid)), { recursive: true });
141
- fs.writeFileSync(
142
- path.join(procRoot, String(recycledPid), 'stat'),
143
- `${recycledPid} (bash) S 1 ${recycledPid} ${recycledPid} 0 -1 4194304 0 0 0 0 0 0 0 0 20 0 1 0 222222 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0\n`,
144
- );
145
- fs.writeFileSync(path.join(procRoot, String(recycledPid), 'cmdline'), 'bash\0');
146
- process.env.SM_PROC_ROOT = procRoot;
147
-
148
- fs.mkdirSync(path.dirname(lockPath()), { recursive: true });
149
- fs.writeFileSync(lockPath(), JSON.stringify({
150
- pid: recycledPid,
151
- startedAt: 'x',
152
- // The identity the crashed scheduler instance actually recorded — a
153
- // different cmdline/startTicks than the process now holding this pid.
154
- identity: { pid: recycledPid, startTicks: 111111, cmdline: 'claude --session-id old', complete: true },
155
- }));
156
-
157
- const res = acquireSchedulerOwnership();
158
- expect(res.owner).toBe(true);
159
- expect(JSON.parse(fs.readFileSync(lockPath(), 'utf8')).pid).toBe(process.pid);
160
-
161
- const auditEvents = readAuditEvents().filter((e) => e.kind === 'stale_lock_broken');
162
- expect(auditEvents.length).toBe(1);
163
- expect(auditEvents[0].recordedPid).toBe(recycledPid);
164
- });
165
-
166
- it('writeLockExclusive (via acquire) records a complete identity for this process', () => {
167
- acquireSchedulerOwnership();
168
- const onDisk = JSON.parse(fs.readFileSync(lockPath(), 'utf8'));
169
- expect(onDisk.identity).toBeTruthy();
170
- expect(onDisk.identity.pid).toBe(process.pid);
171
- expect(onDisk.identity.complete).toBe(true);
172
- });
173
- });