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,146 +0,0 @@
1
- /**
2
- * chat-exit-close-race.test.cjs — regression for the exit/close race that
3
- * silently dropped a pure-text-only final turn (PRD 716).
4
- *
5
- * Bug: the terminal-event fallback was wired to `child.on('exit', ...)`
6
- * instead of `child.on('close', ...)`. Node only guarantees all buffered
7
- * stdout 'data' events have been delivered by 'close', not 'exit' — 'exit'
8
- * can fire before the final stdout chunk (last assistant text + terminating
9
- * `result` line) reaches the parent's 'data' handler. When that happened,
10
- * the exit fallback ran first, set the one-shot terminalSent latch, and
11
- * broadcast a misleading chat:run:error. The real result line then parsed
12
- * moments later, but emitTerminal silently no-op'd and the genuine
13
- * chat:run:complete was dropped.
14
- *
15
- * Fix: use `child.on('close', ...)` for the fallback so it only fires once
16
- * Node guarantees stdout is fully drained — a real result event that arrives
17
- * (even "late", right up against process exit) always wins.
18
- *
19
- * This test mocks node:child_process.spawn so it can deterministically
20
- * reproduce the exact race ordering (exit fires, THEN the final stdout chunk
21
- * arrives, THEN close fires) rather than relying on real OS/pipe timing,
22
- * which is not reliably reproducible from a real child process.
23
- *
24
- * Run: timeout 300 npx vitest run src/main/__tests__/chat-exit-close-race.test.cjs
25
- */
26
-
27
- 'use strict';
28
-
29
- delete process.env.SM_CHAT_CONCURRENCY;
30
-
31
- import { test, afterAll } from 'vitest';
32
- const assert = require('node:assert/strict');
33
- const EventEmitter = require('node:events');
34
- const cp = require('node:child_process');
35
- const fs = require('node:fs');
36
- const os = require('node:os');
37
- const path = require('node:path');
38
-
39
- // Replace spawn BEFORE chatRunner.cjs is first required, so the module's
40
- // top-level `const { spawn } = require('node:child_process')` destructuring
41
- // captures this mock instead of the real implementation.
42
- const originalSpawn = cp.spawn;
43
- let nextChild = null;
44
- cp.spawn = () => {
45
- const child = new EventEmitter();
46
- child.stdout = new EventEmitter();
47
- child.stderr = new EventEmitter();
48
- child.pid = 424242;
49
- child.kill = () => {};
50
- nextChild = child;
51
- return child;
52
- };
53
-
54
- const cr = require('../chatRunner.cjs');
55
-
56
- // Scratch project dir under os.tmpdir() — never the real repo root (opsErrorLog would pollute it).
57
- const scratchCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-chat-cwd-'));
58
-
59
- const tick = () => new Promise((r) => setImmediate(r));
60
-
61
- test('a final-text-only turn whose stdout chunk lands after exit still surfaces chat:run:complete', async () => {
62
- nextChild = null;
63
- const events = [];
64
- cr.attachWindow({
65
- isDestroyed: () => false,
66
- webContents: {
67
- isDestroyed: () => false,
68
- send: (channel, payload) => events.push({ channel, payload }),
69
- },
70
- });
71
-
72
- cr.run({ tabId: 'T2', sessionId: 'S2', prompt: 'show me a sample post', cwd: scratchCwd, resume: false });
73
-
74
- for (let i = 0; i < 20 && !nextChild; i++) await tick();
75
- const child = nextChild;
76
- assert.ok(child, 'spawn should have been invoked');
77
-
78
- const text = 'Here is your sample post, all in one go.';
79
- const lines =
80
- JSON.stringify({ type: 'assistant', message: { content: [{ type: 'text', text }] } }) +
81
- '\n' +
82
- JSON.stringify({ type: 'result', subtype: 'success', result: text }) +
83
- '\n';
84
-
85
- // The exact race: 'exit' fires first (process already gone from the OS's
86
- // perspective), the final stdout chunk is delivered to the 'data' handler
87
- // only after that, and 'close' — which Node guarantees fires after all
88
- // stdout data has been delivered — fires last.
89
- child.emit('exit', 0, null);
90
- child.stdout.emit('data', Buffer.from(lines));
91
- child.emit('close', 0, null);
92
-
93
- await tick();
94
- await tick();
95
-
96
- const terminal = events.filter((e) => isTerminal(e.channel));
97
- assert.equal(terminal.length, 1, 'exactly one terminal event is emitted');
98
- assert.equal(
99
- terminal[0].channel,
100
- 'chat:run:complete',
101
- 'the real result event must win over the generic exit-fallback error',
102
- );
103
- assert.equal(terminal[0].payload.finalMessage, text);
104
- });
105
-
106
- test('a crashed process with no result event ever emitted still fires the fallback chat:run:error', async () => {
107
- nextChild = null;
108
- const events = [];
109
- cr.attachWindow({
110
- isDestroyed: () => false,
111
- webContents: {
112
- isDestroyed: () => false,
113
- send: (channel, payload) => events.push({ channel, payload }),
114
- },
115
- });
116
-
117
- cr.run({ tabId: 'T3', sessionId: 'S3', prompt: 'anything', cwd: scratchCwd, resume: false });
118
-
119
- for (let i = 0; i < 20 && !nextChild; i++) await tick();
120
- const child = nextChild;
121
- assert.ok(child, 'spawn should have been invoked');
122
-
123
- // Crashes with no stdout at all — 'close' is the only event that fires.
124
- child.emit('close', 1, null);
125
-
126
- await tick();
127
- await tick();
128
-
129
- const terminal = events.filter((e) => isTerminal(e.channel));
130
- assert.equal(terminal.length, 1, 'exactly one terminal event is emitted');
131
- assert.equal(terminal[0].channel, 'chat:run:error', 'a crash with no result surfaces as an error turn');
132
- assert.match(terminal[0].payload.message, /process exited without a result event/);
133
- });
134
-
135
- function isTerminal(channel) {
136
- return (
137
- channel === 'chat:run:complete' ||
138
- channel === 'chat:run:needs-input' ||
139
- channel === 'chat:run:error'
140
- );
141
- }
142
-
143
- afterAll(() => {
144
- cp.spawn = originalSpawn;
145
- delete process.env.SM_CHAT_CONCURRENCY;
146
- });
@@ -1,139 +0,0 @@
1
- /**
2
- * chat-mcp-consent-notice.test.cjs — regression for the headless MCP-consent
3
- * hang: a chat run with stdin closed can never answer an MCP server's own
4
- * interactive consent flow (e.g. `/design consent`). This drives the real
5
- * stdout parser with a synthetic stream-json `tool_result` denial line and
6
- * asserts a `chat:run:notice` event is broadcast — informational, not a
7
- * terminal event.
8
- *
9
- * Run: timeout 300 npx vitest run src/main/__tests__/chat-mcp-consent-notice.test.cjs
10
- */
11
-
12
- 'use strict';
13
-
14
- delete process.env.SM_CHAT_CONCURRENCY;
15
-
16
- import { test } from 'vitest';
17
- const assert = require('node:assert/strict');
18
- const fs = require('node:fs');
19
- const os = require('node:os');
20
- const path = require('node:path');
21
-
22
- // Scratch project dir under os.tmpdir() — never the real repo root (opsErrorLog would pollute it).
23
- const scratchCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-chat-cwd-'));
24
- const claudeStub = require('../../../tests/helpers/claudeStub.cjs');
25
-
26
- function writeStub(lines) {
27
- const body = lines.map((l) => `process.stdout.write(${JSON.stringify(JSON.stringify(l))} + "\\n");`).join('\n');
28
- return claudeStub.writeClaudeStub({ body: `${body}\nprocess.exit(0);` });
29
- }
30
-
31
- function isTerminal(channel) {
32
- return (
33
- channel === 'chat:run:complete' ||
34
- channel === 'chat:run:needs-input' ||
35
- channel === 'chat:run:error'
36
- );
37
- }
38
-
39
- test('MCP consent denial in a tool_result surfaces a chat:run:notice event', async () => {
40
- const stubPath = writeStub([
41
- {
42
- type: 'user',
43
- message: {
44
- content: [
45
- {
46
- type: 'tool_result',
47
- tool_use_id: 'toolu_1',
48
- is_error: true,
49
- content: [
50
- {
51
- type: 'text',
52
- text:
53
- "Claude Design: write_files The user hasn't granted this — run /design consent " +
54
- "to grant it (it can't be approved automatically in this permission mode).",
55
- },
56
- ],
57
- },
58
- ],
59
- },
60
- },
61
- { type: 'result', subtype: 'success', result: 'done anyway' },
62
- ]);
63
- process.env.SM_CLAUDE_BIN = stubPath;
64
- delete require.cache[require.resolve('../chatRunner.cjs')];
65
- const cr = require('../chatRunner.cjs');
66
-
67
- const events = [];
68
- cr.attachWindow({
69
- isDestroyed: () => false,
70
- webContents: {
71
- isDestroyed: () => false,
72
- send: (channel, payload) => events.push({ channel, payload }),
73
- },
74
- });
75
-
76
- cr.run({ tabId: 'T-notice', sessionId: 'S-notice', prompt: 'do a design thing', cwd: scratchCwd, resume: false });
77
-
78
- for (let i = 0; i < 60 && !events.some((e) => isTerminal(e.channel)); i++) {
79
- await new Promise((r) => setTimeout(r, 25));
80
- }
81
-
82
- const notice = events.find((e) => e.channel === 'chat:run:notice');
83
- assert.ok(notice, 'chat:run:notice should be broadcast');
84
- assert.match(notice.payload.message, /consent/i, 'message mentions consent');
85
- assert.match(notice.payload.message, /terminal/i, 'message mentions the raw terminal session');
86
-
87
- // Notice is informational, not terminal — the normal result still fires.
88
- const terminal = events.filter((e) => isTerminal(e.channel));
89
- assert.equal(terminal.length, 1, 'exactly one terminal event still fires');
90
- assert.equal(terminal[0].channel, 'chat:run:complete');
91
-
92
- try { fs.unlinkSync(stubPath); } catch { /* already gone */ }
93
- delete process.env.SM_CLAUDE_BIN;
94
- });
95
-
96
- test('a normal tool_result with no consent marker does not fire chat:run:notice', async () => {
97
- const stubPath = writeStub([
98
- {
99
- type: 'user',
100
- message: {
101
- content: [
102
- {
103
- type: 'tool_result',
104
- tool_use_id: 'toolu_2',
105
- is_error: false,
106
- content: [{ type: 'text', text: 'Wrote 3 files successfully.' }],
107
- },
108
- ],
109
- },
110
- },
111
- { type: 'result', subtype: 'success', result: 'all good' },
112
- ]);
113
- process.env.SM_CLAUDE_BIN = stubPath;
114
- delete require.cache[require.resolve('../chatRunner.cjs')];
115
- const cr = require('../chatRunner.cjs');
116
-
117
- const events = [];
118
- cr.attachWindow({
119
- isDestroyed: () => false,
120
- webContents: {
121
- isDestroyed: () => false,
122
- send: (channel, payload) => events.push({ channel, payload }),
123
- },
124
- });
125
-
126
- cr.run({ tabId: 'T-clean', sessionId: 'S-clean', prompt: 'do a normal thing', cwd: scratchCwd, resume: false });
127
-
128
- for (let i = 0; i < 60 && !events.some((e) => isTerminal(e.channel)); i++) {
129
- await new Promise((r) => setTimeout(r, 25));
130
- }
131
-
132
- assert.ok(
133
- !events.some((e) => e.channel === 'chat:run:notice'),
134
- 'no chat:run:notice should fire for a clean tool_result (no false positive)',
135
- );
136
-
137
- try { fs.unlinkSync(stubPath); } catch { /* already gone */ }
138
- delete process.env.SM_CLAUDE_BIN;
139
- });
@@ -1,100 +0,0 @@
1
- /**
2
- * chat-preamble-anchors.test.cjs — drift guard between chatRunner's injected
3
- * instruction blocks and the renderer's splitter that hides them.
4
- *
5
- * `src/renderer/lib/promptPreamble.ts` anchors each block on its FIRST and
6
- * LAST sentence only, because it cannot import this main-process .cjs. That
7
- * indirection is safe ONLY while those anchors still bracket the real text —
8
- * so this test composes the exact `fullPrompt` chatRunner builds and asserts
9
- * the splitter recovers the human's words exactly. Reword either block's
10
- * opening or closing sentence and this fails here, loudly, instead of the
11
- * boilerplate silently reappearing in every user bubble.
12
- *
13
- * Run: timeout 120 npx vitest run src/main/__tests__/chat-preamble-anchors.test.cjs
14
- */
15
-
16
- 'use strict';
17
-
18
- const path = require('path');
19
-
20
- import { test, expect } from 'vitest';
21
-
22
- const { STOP_SIGNAL_INSTRUCTION, CHAT_MODE_TRUTH_INSTRUCTION } = require('../chatRunner.cjs');
23
-
24
- const HUMAN = 'Review the Alpaca limits and report back what we can trade for free.';
25
-
26
- async function loadSplitter() {
27
- const mod = await import(
28
- /* @vite-ignore */ path.resolve(__dirname, '..', '..', 'renderer', 'lib', 'promptPreamble.ts')
29
- );
30
- return mod;
31
- }
32
-
33
- test('the real fullPrompt splits back into exactly the human’s words', async () => {
34
- const { splitInjectedPreamble } = await loadSplitter();
35
- // Mirrors chatRunner's own composition at its `-p` call site.
36
- const fullPrompt = STOP_SIGNAL_INSTRUCTION + CHAT_MODE_TRUTH_INSTRUCTION + HUMAN;
37
-
38
- const split = splitInjectedPreamble(fullPrompt);
39
- expect(split.body).toBe(HUMAN);
40
- expect(split.blockKeys).toEqual(['stop-signal', 'chat-mode-truth']);
41
- expect(split.preamble).toBeTruthy();
42
- // Nothing is invented or lost: preamble + body reconstitute the input.
43
- expect(split.preamble.length + split.body.length).toBeLessThanOrEqual(fullPrompt.length);
44
- expect(fullPrompt.startsWith(split.preamble)).toBe(true);
45
- expect(fullPrompt.endsWith(split.body)).toBe(true);
46
- });
47
-
48
- test('each block strips independently, so one being absent still works', async () => {
49
- const { splitInjectedPreamble } = await loadSplitter();
50
-
51
- const onlyStop = splitInjectedPreamble(STOP_SIGNAL_INSTRUCTION + HUMAN);
52
- expect(onlyStop.body).toBe(HUMAN);
53
- expect(onlyStop.blockKeys).toEqual(['stop-signal']);
54
-
55
- const onlyTruth = splitInjectedPreamble(CHAT_MODE_TRUTH_INSTRUCTION + HUMAN);
56
- expect(onlyTruth.body).toBe(HUMAN);
57
- expect(onlyTruth.blockKeys).toEqual(['chat-mode-truth']);
58
- });
59
-
60
- test('a prompt with no injected blocks is returned untouched', async () => {
61
- const { splitInjectedPreamble } = await loadSplitter();
62
- const split = splitInjectedPreamble(HUMAN);
63
- expect(split.preamble).toBe(null);
64
- expect(split.body).toBe(HUMAN);
65
- expect(split.blockKeys).toEqual([]);
66
- });
67
-
68
- test('EDGE: a boilerplate-only prompt is NOT stripped to an empty bubble', async () => {
69
- const { splitInjectedPreamble } = await loadSplitter();
70
- const onlyBoilerplate = STOP_SIGNAL_INSTRUCTION + CHAT_MODE_TRUTH_INSTRUCTION;
71
- const split = splitInjectedPreamble(onlyBoilerplate);
72
- expect(split.preamble).toBe(null);
73
- expect(split.body).toBe(onlyBoilerplate);
74
- });
75
-
76
- test('EDGE: a truncated block (opening present, closing missing) is left fully intact', async () => {
77
- const { splitInjectedPreamble } = await loadSplitter();
78
- // Simulates a reworded/cut-off block: better to over-show boilerplate than
79
- // to guess at a boundary and eat the human's words.
80
- const truncated = `${STOP_SIGNAL_INSTRUCTION.slice(0, 120)}\n\n${HUMAN}`;
81
- const split = splitInjectedPreamble(truncated);
82
- expect(split.preamble).toBe(null);
83
- expect(split.body).toBe(truncated);
84
- });
85
-
86
- test('the two blocks strip in either order', async () => {
87
- const { splitInjectedPreamble } = await loadSplitter();
88
- const reversed = CHAT_MODE_TRUTH_INSTRUCTION + STOP_SIGNAL_INSTRUCTION + HUMAN;
89
- const split = splitInjectedPreamble(reversed);
90
- expect(split.body).toBe(HUMAN);
91
- expect(split.blockKeys).toEqual(['chat-mode-truth', 'stop-signal']);
92
- });
93
-
94
- test('EDGE: boilerplate quoted inside the human’s own message is never stripped', async () => {
95
- const { splitInjectedPreamble } = await loadSplitter();
96
- const quoting = `Why does chat prepend this?\n\n${STOP_SIGNAL_INSTRUCTION}`;
97
- const split = splitInjectedPreamble(quoting);
98
- expect(split.preamble).toBe(null);
99
- expect(split.body).toBe(quoting);
100
- });
@@ -1,97 +0,0 @@
1
- /**
2
- * chat-queue.test.cjs — unit tests for the chatRunner serial run queue (v0.34).
3
- * Asserts the "up to two loops at a time" guarantee: SILENT (automated probe)
4
- * runs execute up to the concurrency cap in FIFO order, and a queued
5
- * (not-yet-started) silent run can be cancelled without running. PRD 493:
6
- * this cap/FIFO governs silent runs only — manual runs bypass it entirely
7
- * (see chatRunner.spec.ts's "manual runs are uncapped" tests).
8
- *
9
- * Run: timeout 300 npx vitest run src/main/__tests__/chat-queue.test.cjs
10
- */
11
-
12
- 'use strict';
13
-
14
- // Force the default cap (2) regardless of the developer's shell env.
15
- delete process.env.SM_CHAT_CONCURRENCY;
16
-
17
- import { test } from 'vitest';
18
- const assert = require('node:assert/strict');
19
- const cr = require('../chatRunner.cjs');
20
-
21
- const tick = () => new Promise((r) => setImmediate(r));
22
- const job = (id) => ({ tabId: id, sessionId: id, prompt: 'x', cwd: '/', resume: true, silent: true });
23
-
24
- test('runs execute up to the concurrency cap in FIFO order', async () => {
25
- const order = [];
26
- let active = 0;
27
- let maxActive = 0;
28
- // Stub the spawn: each run resolves on the next tick, so the queue must
29
- // advance via the pump's finally hook for C to ever run.
30
- cr.__setExecutor((j) => {
31
- active += 1;
32
- maxActive = Math.max(maxActive, active);
33
- order.push(j.tabId);
34
- return new Promise((res) => setImmediate(() => { active -= 1; res(); }));
35
- });
36
-
37
- cr.run(job('A'));
38
- cr.run(job('B'));
39
- cr.run(job('C'));
40
-
41
- // Drain the queue (each run takes one tick; allow generous headroom).
42
- for (let i = 0; i < 12 && order.length < 3; i++) await tick();
43
- await tick();
44
-
45
- assert.equal(maxActive, 2, 'up to two runs active at once under the default cap');
46
- assert.deepEqual(order, ['A', 'B', 'C'], 'runs execute in FIFO order');
47
-
48
- cr.__setExecutor(null); // restore real executor
49
- });
50
-
51
- test('cancelling a queued run drops it without executing', async () => {
52
- const order = [];
53
- cr.__setExecutor((j) => {
54
- order.push(j.tabId);
55
- return new Promise((res) => setImmediate(res));
56
- });
57
-
58
- // X and Y each take one of the two lanes; Z queues behind them. Cancel Z
59
- // before a lane frees.
60
- cr.run(job('X'));
61
- cr.run(job('Y'));
62
- cr.run(job('Z'));
63
- cr.cancel('Z'); // Z is still in the waiting list — drop it
64
-
65
- for (let i = 0; i < 8; i++) await tick();
66
-
67
- assert.deepEqual(order, ['X', 'Y'], 'only X and Y ran; Z was cancelled while queued');
68
-
69
- cr.__setExecutor(null);
70
- });
71
-
72
- test('a queued silent run never broadcasts chat:run:queued (silent runs stay invisible to the renderer)', async () => {
73
- const sent = [];
74
- cr.attachWindow({
75
- isDestroyed: () => false,
76
- webContents: { isDestroyed: () => false, send: (channel, payload) => sent.push({ channel, payload }) },
77
- });
78
- cr.__setExecutor((j) => new Promise((res) => setImmediate(res)));
79
-
80
- // P and Q take the two lanes under the default cap; R queues behind them —
81
- // this is the only path that ever populates chatRunner's `waiting` list,
82
- // and every job on it is silent (manual runs bypass the queue entirely).
83
- cr.run(job('P'));
84
- cr.run(job('Q'));
85
- cr.run(job('R'));
86
-
87
- for (let i = 0; i < 8; i++) await tick();
88
-
89
- assert.equal(
90
- sent.filter((s) => s.channel === 'chat:run:queued').length,
91
- 0,
92
- 'no chat:run:queued broadcast for a silent (automated probe) run',
93
- );
94
-
95
- cr.__setExecutor(null);
96
- cr.attachWindow(null);
97
- });
@@ -1,89 +0,0 @@
1
- /**
2
- * chat-stop-signal.test.cjs — unit tests for chatRunner.parseStopSignal, the
3
- * single source of truth for the terminal-chat stop-signal protocol (PRD 318).
4
- *
5
- * Run: timeout 300 npx vitest run src/main/__tests__/chat-stop-signal.test.cjs
6
- */
7
-
8
- 'use strict';
9
-
10
- import { test } from 'vitest';
11
- const assert = require('node:assert/strict');
12
- const { parseStopSignal, STOP_SENTINEL } = require('../chatRunner.cjs');
13
-
14
- test('sentinel present with valid JSON → questions array', () => {
15
- const text =
16
- 'I did some work but need to know which target.\n' +
17
- `${STOP_SENTINEL}\n` +
18
- '{"questions":["Which environment?","Overwrite existing config?"]}';
19
- const out = parseStopSignal(text);
20
- assert.deepEqual(out, {
21
- questions: ['Which environment?', 'Overwrite existing config?'],
22
- });
23
- });
24
-
25
- test('sentinel absent → null (run is complete)', () => {
26
- const text = 'All done. I created the file and the tests pass.';
27
- assert.equal(parseStopSignal(text), null);
28
- });
29
-
30
- test('sentinel present but malformed JSON → null (treated as complete, no crash)', () => {
31
- const text = `Here is a summary.\n${STOP_SENTINEL}\n{questions: [oops not json}`;
32
- assert.equal(parseStopSignal(text), null);
33
- });
34
-
35
- test('sentinel present but JSON lacks questions array → null', () => {
36
- const text = `${STOP_SENTINEL}\n{"foo":"bar"}`;
37
- assert.equal(parseStopSignal(text), null);
38
- });
39
-
40
- test('non-string input → null (no crash)', () => {
41
- assert.equal(parseStopSignal(undefined), null);
42
- assert.equal(parseStopSignal(null), null);
43
- assert.equal(parseStopSignal(42), null);
44
- });
45
-
46
- test('only the LAST sentinel occurrence is parsed', () => {
47
- const text =
48
- `${STOP_SENTINEL}\n{"questions":["stale earlier block"]}\n` +
49
- 'then the agent kept working...\n' +
50
- `${STOP_SENTINEL}\n{"questions":["the real question"]}`;
51
- assert.deepEqual(parseStopSignal(text), { questions: ['the real question'] });
52
- });
53
-
54
- test('blank lines between sentinel and JSON → questions array', () => {
55
- const text = `${STOP_SENTINEL}\n\n\n{"questions":["Which environment?"]}`;
56
- assert.deepEqual(parseStopSignal(text), { questions: ['Which environment?'] });
57
- });
58
-
59
- test('JSON wrapped in a ```json code fence → questions array', () => {
60
- const text =
61
- `${STOP_SENTINEL}\n` +
62
- '```json\n' +
63
- '{"questions":["Overwrite existing config?"]}\n' +
64
- '```';
65
- assert.deepEqual(parseStopSignal(text), { questions: ['Overwrite existing config?'] });
66
- });
67
-
68
- test('pretty-printed multi-line JSON → questions array', () => {
69
- const text =
70
- `${STOP_SENTINEL}\n` +
71
- '{\n' +
72
- ' "questions": [\n' +
73
- ' "Which environment?",\n' +
74
- ' "Overwrite existing config?"\n' +
75
- ' ]\n' +
76
- '}';
77
- assert.deepEqual(parseStopSignal(text), {
78
- questions: ['Which environment?', 'Overwrite existing config?'],
79
- });
80
- });
81
-
82
- test('trailing prose after the closing brace → questions array', () => {
83
- const text =
84
- `${STOP_SENTINEL}\n` +
85
- '{"questions":["Which environment?"]}\n' +
86
- '\n' +
87
- 'Let me know and I will continue.';
88
- assert.deepEqual(parseStopSignal(text), { questions: ['Which environment?'] });
89
- });