claude-code-session-manager 0.98.0 → 0.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/bin/cli.cjs +16 -4
- package/bin/node-floor.cjs +41 -0
- package/dist/assets/{DataModel-DCEgMTjH.js → DataModel-HdR0AxFq.js} +1 -1
- package/dist/assets/{History-Bfdoywlh.js → History-Dr4Jr_5z.js} +2 -2
- package/dist/assets/{Hooks-CKDJjTJV.js → Hooks-NhrvH3JP.js} +3 -3
- package/dist/assets/{Library-7akfgy67.js → Library-Dv_EtIMr.js} +1 -1
- package/dist/assets/{MarkdownEditor-DDesiqet.js → MarkdownEditor-DTKDWV_n.js} +1 -1
- package/dist/assets/{McpServers-D4lZtXof.js → McpServers-M034G9B3.js} +2 -2
- package/dist/assets/{Memory-CeI8G1w5.js → Memory-DzF1B4gx.js} +6 -6
- package/dist/assets/{Permissions-BGleLja4.js → Permissions-DrgbSGWl.js} +3 -3
- package/dist/assets/{Plugins-P4eCXy_S.js → Plugins-Bd3ef35w.js} +2 -2
- package/dist/assets/{ProvenanceBadge-BFczzI1B.js → ProvenanceBadge-DcBHT1Iy.js} +1 -1
- package/dist/assets/{SaveBar-l9jnEMES.js → SaveBar-rimJem-Y.js} +1 -1
- package/dist/assets/Scheduler-DjgFJl2w.js +16 -0
- package/dist/assets/{ScopeSwitcher-CjJi8ST5.js → ScopeSwitcher-CnAzTBrl.js} +1 -1
- package/dist/assets/Settings-Dc1F_sSg.js +3 -0
- package/dist/assets/{SkillReferenceGraph-CjbO01Sg.js → SkillReferenceGraph-B9aZDecM.js} +1 -1
- package/dist/assets/{Skills-BxZ9_fCR.js → Skills-DRXd18gu.js} +2 -2
- package/dist/assets/{SystemPrompt-D8vfFb8b.js → SystemPrompt-ahy5-Fwe.js} +1 -1
- package/dist/assets/{TagLibrary-2vzUo7YL.js → TagLibrary-C_tToDeL.js} +1 -1
- package/dist/assets/{TiptapBody-B8ZfbK90.js → TiptapBody-DvdefS6K.js} +1 -1
- package/dist/assets/{Toggle-BbW4nGGf.js → Toggle-6Jl5Njc6.js} +1 -1
- package/dist/assets/{index-CKH5Uxik.css → index-Bta-hwud.css} +1 -1
- package/dist/assets/{index-Cd98Q1lD.js → index-vx8O73l8.js} +497 -502
- package/dist/assets/{settingsSchema-IhUfucCF.js → settingsSchema-D6iRguNV.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +25 -29
- package/plugins/CLAUDE.md +6 -6
- package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +21 -19
- package/plugins/session-manager-dev/skills/builder/SKILL.md +3 -3
- package/plugins/session-manager-dev/skills/develop/SKILL.md +254 -510
- package/plugins/session-manager-dev/skills/develop/standards.md +17 -22
- package/scripts/README.md +3 -11
- package/scripts/audit-ops-hygiene.cjs +3 -3
- package/scripts/hooks/lib/guard-prd-writes-policy.cjs +1 -1
- package/scripts/hooks/lib/guard-self-schedule-policy.cjs +1 -1
- package/scripts/mint-epic.cjs +2 -3
- package/scripts/scheduler-mcp-server.cjs +36 -7
- package/src/main/agentLibrary.cjs +22 -2
- package/src/main/build-info.json +4 -4
- package/src/main/config.cjs +41 -38
- package/src/main/docEdit.cjs +4 -1
- package/src/main/files.cjs +2 -5
- package/src/main/health.cjs +1 -1
- package/src/main/index.cjs +23 -10
- package/src/main/ipcSchemas.cjs +28 -35
- package/src/main/lib/agentPersonaSchema.cjs +13 -2
- package/src/main/lib/atomicFs.cjs +116 -0
- package/src/main/lib/branchSweep.cjs +13 -12
- package/src/main/lib/buildTarget.cjs +3 -3
- package/src/main/lib/claudeCliCaps.cjs +129 -0
- package/src/main/lib/credentials.cjs +2 -4
- package/src/main/lib/crossProjectFeedback.cjs +3 -3
- package/src/main/lib/cwdClassify.cjs +15 -3
- package/src/main/lib/definitionOfDone.cjs +207 -125
- package/src/main/lib/dodDrainHook.cjs +11 -5
- package/src/main/lib/epicMint.cjs +2 -4
- package/src/main/lib/epicStatusMirror.cjs +8 -10
- package/src/main/lib/epicWorktreeProjectConfig.cjs +2 -4
- package/src/main/lib/gateAuthority.cjs +96 -0
- package/src/main/lib/gitExec.cjs +69 -0
- package/src/main/lib/gitWorktree.cjs +656 -92
- package/src/main/lib/instanceLock.cjs +5 -8
- package/src/main/lib/launchFailure.cjs +2 -3
- package/src/main/lib/macroLibrary.cjs +386 -0
- package/src/main/lib/mcpToolCatalog.cjs +26 -17
- package/src/main/lib/needsReviewLedger.cjs +1 -1
- package/src/main/lib/opsErrorLog.cjs +11 -1
- package/src/main/lib/opsOwnership.cjs +0 -5
- package/src/main/lib/pidAlive.cjs +32 -0
- package/src/main/lib/prdCreate.cjs +121 -12
- package/src/main/lib/prdDisposition.cjs +2 -2
- package/src/main/lib/prdGateFiles.cjs +284 -0
- package/src/main/lib/prdLocations.cjs +61 -0
- package/src/main/lib/prdMigration.cjs +2 -3
- package/src/main/lib/prdSizing.cjs +2 -1
- package/src/main/lib/promptSessionSchema.cjs +10 -2
- package/src/main/lib/rcaReport.cjs +4 -6
- package/src/main/lib/reaperHelpers.cjs +8 -1
- package/src/main/lib/reservationExpiry.cjs +6 -1
- package/src/main/lib/reviewNotice.cjs +263 -0
- package/src/main/lib/runClaudeP.cjs +4 -1
- package/src/main/lib/schedulerPaths.cjs +22 -2
- package/src/main/lib/sessionSlots.cjs +2 -4
- package/src/main/lib/shippedPersonaSeeds.cjs +179 -0
- package/src/main/lib/timeoutShim.cjs +123 -0
- package/src/main/lib/timeoutShimScript.cjs +275 -0
- package/src/main/lib/upgradeDrain.cjs +4 -10
- package/src/main/lib/watchdogHelpers.cjs +12 -25
- package/src/main/lib/workTypeLibrary.cjs +7 -1
- package/src/main/promptSessionEvents.cjs +37 -13
- package/src/main/scheduler.cjs +910 -198
- package/src/main/seedAgentPersonas.cjs +278 -23
- package/src/main/supervisor.cjs +4 -1
- package/src/main/templates/PRD_AUTHORING.md +126 -406
- package/src/preload/__tests__/preload-surface.test.cjs +68 -0
- package/src/preload/api.d.ts +41 -94
- package/src/preload/index.cjs +14 -9
- package/src/seed/agents/architect.md +1 -0
- package/src/seed/agents/dev-lead.md +17 -18
- package/src/seed/agents/project-home-builder.md +1 -0
- package/src/seed/agents/validator.md +10 -4
- package/dist/assets/HostBilko-CDVHE0hT.js +0 -1
- package/dist/assets/Scheduler-C_phpeUS.js +0 -16
- package/dist/assets/Settings-BIwZ3FGQ.js +0 -3
- package/src/main/__tests__/activeIndexMerge.test.cjs +0 -235
- package/src/main/__tests__/agentEffortResolve.test.cjs +0 -117
- package/src/main/__tests__/agentLibrary.test.cjs +0 -276
- package/src/main/__tests__/agentModelResolve.test.cjs +0 -311
- package/src/main/__tests__/agentOverlayWrite.test.cjs +0 -95
- package/src/main/__tests__/bilkoHost-deriveSlug.test.cjs +0 -26
- package/src/main/__tests__/bilkoHost-integration.test.cjs +0 -118
- package/src/main/__tests__/bilkoHostCore.test.cjs +0 -72
- package/src/main/__tests__/broadcastCoalescer.test.cjs +0 -122
- package/src/main/__tests__/chat-cancel-terminal.test.cjs +0 -120
- package/src/main/__tests__/chat-dead-channels.test.cjs +0 -63
- package/src/main/__tests__/chat-exit-close-race.test.cjs +0 -146
- package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +0 -139
- package/src/main/__tests__/chat-preamble-anchors.test.cjs +0 -100
- package/src/main/__tests__/chat-queue.test.cjs +0 -97
- package/src/main/__tests__/chat-stop-signal.test.cjs +0 -89
- package/src/main/__tests__/chatRunner-epic-worktree-execcwd.test.cjs +0 -125
- package/src/main/__tests__/chatRunner-session-flag-retry.test.cjs +0 -252
- package/src/main/__tests__/classifyPromptTicket.test.cjs +0 -101
- package/src/main/__tests__/classifyTranscriptLine.test.cjs +0 -201
- package/src/main/__tests__/computeDepHistorySatisfaction.test.cjs +0 -66
- package/src/main/__tests__/config-readText-bounded.test.cjs +0 -84
- package/src/main/__tests__/configWriteBoundaryOwners.test.cjs +0 -59
- package/src/main/__tests__/crossProjectFeedback.test.cjs +0 -334
- package/src/main/__tests__/crossProjectFeedbackRoutes.test.cjs +0 -161
- package/src/main/__tests__/dep-orphan-archive-health.test.cjs +0 -77
- package/src/main/__tests__/develop-skill-failure-modes.test.cjs +0 -70
- package/src/main/__tests__/docEdit.test.cjs +0 -244
- package/src/main/__tests__/dod-batchkey.test.cjs +0 -183
- package/src/main/__tests__/dod-drain-hook.test.cjs +0 -302
- package/src/main/__tests__/dod-report.test.cjs +0 -304
- package/src/main/__tests__/dod-reverify.test.cjs +0 -285
- package/src/main/__tests__/epicContextDigest.test.cjs +0 -174
- package/src/main/__tests__/epicMint.test.cjs +0 -332
- package/src/main/__tests__/epicMintTelemetryTap.test.cjs +0 -64
- package/src/main/__tests__/epicStatusMirror.test.cjs +0 -110
- package/src/main/__tests__/epicValidationHook.test.cjs +0 -291
- package/src/main/__tests__/exchanges.test.cjs +0 -122
- package/src/main/__tests__/exchangesPromptId.test.cjs +0 -61
- package/src/main/__tests__/extractJson.test.cjs +0 -51
- package/src/main/__tests__/files-reject-credentials.test.cjs +0 -40
- package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +0 -556
- package/src/main/__tests__/flatPrdTickSweep.test.cjs +0 -110
- package/src/main/__tests__/health-build-freshness.test.cjs +0 -39
- package/src/main/__tests__/health-claude-md-budget.test.cjs +0 -57
- package/src/main/__tests__/health-credentials.test.cjs +0 -81
- package/src/main/__tests__/health-delegation-chain.test.cjs +0 -124
- package/src/main/__tests__/health-per-project-stall.test.cjs +0 -84
- package/src/main/__tests__/health-prd-migration.test.cjs +0 -37
- package/src/main/__tests__/health-queue-dispatch.test.cjs +0 -135
- package/src/main/__tests__/health-starve-escalation.test.cjs +0 -94
- package/src/main/__tests__/health-tick-liveness.test.cjs +0 -179
- package/src/main/__tests__/health-usage-poller.test.cjs +0 -144
- package/src/main/__tests__/health-worktree-cap-blocked.test.cjs +0 -65
- package/src/main/__tests__/heapSnapshot.test.cjs +0 -121
- package/src/main/__tests__/historyAggregatorIntraday.test.cjs +0 -313
- package/src/main/__tests__/historyDashboard.test.cjs +0 -163
- package/src/main/__tests__/historyRollup.test.cjs +0 -333
- package/src/main/__tests__/intradayRefresh.test.cjs +0 -39
- package/src/main/__tests__/ipcSchemas-dependsOn.test.cjs +0 -39
- package/src/main/__tests__/kg-augment.test.cjs +0 -195
- package/src/main/__tests__/loadGateDetailTick.test.cjs +0 -31
- package/src/main/__tests__/machineProfile.test.cjs +0 -152
- package/src/main/__tests__/mcpStatus.test.cjs +0 -61
- package/src/main/__tests__/memoryAggregate.test.cjs +0 -109
- package/src/main/__tests__/memoryStale.test.cjs +0 -88
- package/src/main/__tests__/needsReviewLedger.test.cjs +0 -162
- package/src/main/__tests__/openExternalApp-spawn-error.test.cjs +0 -25
- package/src/main/__tests__/opsErrorLog.test.cjs +0 -109
- package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +0 -173
- package/src/main/__tests__/personaMerge.test.cjs +0 -169
- package/src/main/__tests__/planValidator.test.cjs +0 -125
- package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +0 -176
- package/src/main/__tests__/prd-group-allocator.test.cjs +0 -119
- package/src/main/__tests__/prdAdminRouteParity.test.cjs +0 -70
- package/src/main/__tests__/prdAdminRoutes.test.cjs +0 -718
- package/src/main/__tests__/prdAgentType.test.cjs +0 -103
- package/src/main/__tests__/prdAuthoringSeed.test.cjs +0 -39
- package/src/main/__tests__/prdCreate.test.cjs +0 -979
- package/src/main/__tests__/prdCreateAdoption.test.cjs +0 -205
- package/src/main/__tests__/prdCreateDisposition.test.cjs +0 -201
- package/src/main/__tests__/prdCreatePlanId.test.cjs +0 -132
- package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +0 -117
- package/src/main/__tests__/prdFrontmatterDependsOn.test.cjs +0 -136
- package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +0 -125
- package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +0 -108
- package/src/main/__tests__/prdLocations.test.cjs +0 -195
- package/src/main/__tests__/prdLocationsArchived.test.cjs +0 -201
- package/src/main/__tests__/prdMigration.test.cjs +0 -349
- package/src/main/__tests__/prdMigrationLegacyAdopt.test.cjs +0 -91
- package/src/main/__tests__/prdParserHighWater.test.cjs +0 -74
- package/src/main/__tests__/prdParserSourcePromptId.test.cjs +0 -65
- package/src/main/__tests__/prdSetDisposition.test.cjs +0 -222
- package/src/main/__tests__/prdSizing.test.cjs +0 -106
- package/src/main/__tests__/prdSourcePromptIdBackfill.test.cjs +0 -118
- package/src/main/__tests__/prdUpdateDependsOn.test.cjs +0 -160
- package/src/main/__tests__/proc-role-env.test.cjs +0 -125
- package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +0 -304
- package/src/main/__tests__/procname-sm-processes.test.cjs +0 -127
- package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +0 -177
- package/src/main/__tests__/projectPages.test.cjs +0 -137
- package/src/main/__tests__/promptSessionEvents.test.cjs +0 -234
- package/src/main/__tests__/promptSessionSchema.test.cjs +0 -101
- package/src/main/__tests__/promptSessionTranscript.test.cjs +0 -0
- package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +0 -159
- package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +0 -282
- package/src/main/__tests__/pty-session-open-telemetry.test.cjs +0 -96
- package/src/main/__tests__/pty-write-result.test.cjs +0 -46
- package/src/main/__tests__/queue-health-verdict.test.cjs +0 -170
- package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +0 -286
- package/src/main/__tests__/queue-starvation-per-project.test.cjs +0 -147
- package/src/main/__tests__/queueHistory.test.cjs +0 -355
- package/src/main/__tests__/queueOps-interactive-ac-lint.test.cjs +0 -65
- package/src/main/__tests__/queueOpsArchiveDestination.test.cjs +0 -65
- package/src/main/__tests__/queueOpsAutoArchive.test.cjs +0 -211
- package/src/main/__tests__/rateLimitPollerStreak.test.cjs +0 -128
- package/src/main/__tests__/rcaReport.test.cjs +0 -266
- package/src/main/__tests__/reconcileFlatPrdSweep.test.cjs +0 -119
- package/src/main/__tests__/reconcileTiming.test.cjs +0 -135
- package/src/main/__tests__/runLogRetention.test.cjs +0 -489
- package/src/main/__tests__/runVerify-atomic-verdicts.test.cjs +0 -26
- package/src/main/__tests__/runVerify-blocked-by-foreign-wip.test.cjs +0 -58
- package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +0 -191
- package/src/main/__tests__/runVerify-policy-denial.test.cjs +0 -89
- package/src/main/__tests__/runVerify-transcript-commit-evidence.test.cjs +0 -225
- package/src/main/__tests__/runVerify.test.cjs +0 -1784
- package/src/main/__tests__/scheduleJobSchema.test.cjs +0 -127
- package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +0 -65
- package/src/main/__tests__/scheduleJobTransitions.test.cjs +0 -277
- package/src/main/__tests__/scheduleJobTransitionsGrep.test.cjs +0 -59
- package/src/main/__tests__/scheduleJobTransitionsTelemetryTap.test.cjs +0 -72
- package/src/main/__tests__/scheduler-admin-routes.test.cjs +0 -199
- package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +0 -143
- package/src/main/__tests__/scheduler-already-satisfied-on-main.test.cjs +0 -105
- package/src/main/__tests__/scheduler-archive-completed-prd.test.cjs +0 -102
- package/src/main/__tests__/scheduler-archived-twin-guard.test.cjs +0 -155
- package/src/main/__tests__/scheduler-autofix-outcome.test.cjs +0 -188
- package/src/main/__tests__/scheduler-autofix-select.test.cjs +0 -439
- package/src/main/__tests__/scheduler-autopromote.test.cjs +0 -51
- package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +0 -101
- package/src/main/__tests__/scheduler-blocked-by-foreign-wip.test.cjs +0 -107
- package/src/main/__tests__/scheduler-boot-orphans.test.cjs +0 -153
- package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +0 -121
- package/src/main/__tests__/scheduler-clear-queue-history.test.cjs +0 -134
- package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +0 -244
- package/src/main/__tests__/scheduler-committed-in-window.test.cjs +0 -182
- package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +0 -43
- package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +0 -168
- package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +0 -58
- package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +0 -81
- package/src/main/__tests__/scheduler-epic-digest.test.cjs +0 -227
- package/src/main/__tests__/scheduler-failed-autoreset.test.cjs +0 -121
- package/src/main/__tests__/scheduler-finalize-dispatch-guards.test.cjs +0 -229
- package/src/main/__tests__/scheduler-find-prd-dir.test.cjs +0 -75
- package/src/main/__tests__/scheduler-fix-plan-path.test.cjs +0 -119
- package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +0 -46
- package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +0 -78
- package/src/main/__tests__/scheduler-gate-shadow.test.cjs +0 -119
- package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +0 -390
- package/src/main/__tests__/scheduler-heal-refusal.test.cjs +0 -61
- package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +0 -80
- package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +0 -323
- package/src/main/__tests__/scheduler-integration-failure-stamp.test.cjs +0 -41
- package/src/main/__tests__/scheduler-investigation-clean-skip.test.cjs +0 -63
- package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +0 -123
- package/src/main/__tests__/scheduler-job-budget.test.cjs +0 -172
- package/src/main/__tests__/scheduler-job-overrun.test.cjs +0 -175
- package/src/main/__tests__/scheduler-launch-failure.test.cjs +0 -199
- package/src/main/__tests__/scheduler-leftover-fields.test.cjs +0 -52
- package/src/main/__tests__/scheduler-leftover-quarantine.test.cjs +0 -199
- package/src/main/__tests__/scheduler-looks-done.test.cjs +0 -537
- package/src/main/__tests__/scheduler-manual-pause.test.cjs +0 -118
- package/src/main/__tests__/scheduler-mechanical-recovery.test.cjs +0 -245
- package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +0 -46
- package/src/main/__tests__/scheduler-mutate-reentrancy.test.cjs +0 -117
- package/src/main/__tests__/scheduler-needs-review-autoresolve.test.cjs +0 -197
- package/src/main/__tests__/scheduler-never-stop.test.cjs +0 -157
- package/src/main/__tests__/scheduler-no-dead-end-status.test.cjs +0 -152
- package/src/main/__tests__/scheduler-no-orphan-run-dir.test.cjs +0 -81
- package/src/main/__tests__/scheduler-notify-originating-tab-transcript.test.cjs +0 -87
- package/src/main/__tests__/scheduler-notify-originating-tab.test.cjs +0 -343
- package/src/main/__tests__/scheduler-periodic-reverify-guard.test.cjs +0 -217
- package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +0 -164
- package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +0 -161
- package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +0 -178
- package/src/main/__tests__/scheduler-quarantine-autoresolve.test.cjs +0 -165
- package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +0 -257
- package/src/main/__tests__/scheduler-rate-limit-cooldown-freshness.test.cjs +0 -123
- package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +0 -152
- package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +0 -156
- package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +0 -754
- package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +0 -87
- package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +0 -100
- package/src/main/__tests__/scheduler-reconcile-history-backfill.test.cjs +0 -105
- package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +0 -203
- package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +0 -247
- package/src/main/__tests__/scheduler-reset-job-fields-guard.test.cjs +0 -77
- package/src/main/__tests__/scheduler-resume-recovery.test.cjs +0 -254
- package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +0 -115
- package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +0 -380
- package/src/main/__tests__/scheduler-sigterm-commit.test.cjs +0 -43
- package/src/main/__tests__/scheduler-stall-per-project.test.cjs +0 -126
- package/src/main/__tests__/scheduler-starve-escalation.test.cjs +0 -154
- package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +0 -252
- package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +0 -185
- package/src/main/__tests__/scheduler-stuck-failed-escalation.test.cjs +0 -136
- package/src/main/__tests__/scheduler-supervisor-record.test.cjs +0 -81
- package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +0 -54
- package/src/main/__tests__/scheduler-tick-wedge.test.cjs +0 -172
- package/src/main/__tests__/scheduler-transient-failure.test.cjs +0 -141
- package/src/main/__tests__/scheduler-unreadable-queue-guard.test.cjs +0 -62
- package/src/main/__tests__/scheduler-utilization-hold.test.cjs +0 -89
- package/src/main/__tests__/scheduler-verify-prd-path.test.cjs +0 -109
- package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +0 -234
- package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +0 -120
- package/src/main/__tests__/scheduler-writeprd-epic-rollback.test.cjs +0 -105
- package/src/main/__tests__/schedulerBatchRootBlocker.test.cjs +0 -117
- package/src/main/__tests__/schedulerStateSidecarRestore.test.cjs +0 -110
- package/src/main/__tests__/seedAgentPersonas.test.cjs +0 -184
- package/src/main/__tests__/seedSchedulerMcp.test.cjs +0 -211
- package/src/main/__tests__/seedStatus.test.cjs +0 -100
- package/src/main/__tests__/seedValidatorPersona.test.cjs +0 -116
- package/src/main/__tests__/stop-signal-anchor.test.cjs +0 -75
- package/src/main/__tests__/telemetryClient.test.cjs +0 -1055
- package/src/main/__tests__/telemetryContract.test.cjs +0 -930
- package/src/main/__tests__/telemetrySettings.test.cjs +0 -210
- package/src/main/__tests__/transcripts-batch-flush.test.cjs +0 -249
- package/src/main/__tests__/transcripts-doFlush-array.test.cjs +0 -124
- package/src/main/__tests__/transcripts-paged-reads.test.cjs +0 -241
- package/src/main/__tests__/transcripts-worktree-epic-path.test.cjs +0 -154
- package/src/main/__tests__/transcriptsUsageFor.test.cjs +0 -206
- package/src/main/__tests__/uniquePrdNumbers.test.cjs +0 -153
- package/src/main/__tests__/usageSingleFlight.test.cjs +0 -169
- package/src/main/__tests__/validationSentinels.test.cjs +0 -84
- package/src/main/__tests__/workTypeLibrary.test.cjs +0 -89
- package/src/main/bilkoHost.cjs +0 -314
- package/src/main/bilkoHostCore.cjs +0 -89
- package/src/main/lib/__tests__/active-sessions.test.cjs +0 -251
- package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +0 -179
- package/src/main/lib/__tests__/agentPersonaSchema.test.cjs +0 -67
- package/src/main/lib/__tests__/auditLog.test.cjs +0 -38
- package/src/main/lib/__tests__/bootSelfHeal.test.cjs +0 -107
- package/src/main/lib/__tests__/branchSweep.test.cjs +0 -164
- package/src/main/lib/__tests__/buildIdentity.test.cjs +0 -121
- package/src/main/lib/__tests__/buildTarget.test.cjs +0 -52
- package/src/main/lib/__tests__/childWithLog.test.cjs +0 -321
- package/src/main/lib/__tests__/coldBootPromptSessionsWrite.test.cjs +0 -87
- package/src/main/lib/__tests__/crashTelemetry.test.cjs +0 -103
- package/src/main/lib/__tests__/credentials-futile-refresh.test.cjs +0 -115
- package/src/main/lib/__tests__/cwdClassify.test.cjs +0 -111
- package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +0 -95
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +0 -1175
- package/src/main/lib/__tests__/dispatchLoop.test.cjs +0 -63
- package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +0 -244
- package/src/main/lib/__tests__/ephemeralCwd.test.cjs +0 -91
- package/src/main/lib/__tests__/epicDelegationStats.test.cjs +0 -137
- package/src/main/lib/__tests__/epicSpawnCwd.test.cjs +0 -283
- package/src/main/lib/__tests__/epicSpawnPlan.test.cjs +0 -196
- package/src/main/lib/__tests__/epicTranscriptPath.test.cjs +0 -163
- package/src/main/lib/__tests__/epicWorktreeBoot.test.cjs +0 -136
- package/src/main/lib/__tests__/epicWorktreeMerge.test.cjs +0 -130
- package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +0 -117
- package/src/main/lib/__tests__/epicWorktreeProjectConfig.test.cjs +0 -137
- package/src/main/lib/__tests__/fixChainDepth.test.cjs +0 -40
- package/src/main/lib/__tests__/fixtures/204-mercury-steam-horse.log.txt +0 -13
- package/src/main/lib/__tests__/fixtures/scheduler-machine.json.corrupt-1789147548 +0 -34
- package/src/main/lib/__tests__/gateFixtures.json +0 -20
- package/src/main/lib/__tests__/gitCacheBound.test.cjs +0 -69
- package/src/main/lib/__tests__/gitWorktree.test.cjs +0 -1478
- package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +0 -107
- package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +0 -153
- package/src/main/lib/__tests__/guardShims.test.cjs +0 -158
- package/src/main/lib/__tests__/importReferences.spec.cjs +0 -56
- package/src/main/lib/__tests__/instanceLock.test.cjs +0 -173
- package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +0 -78
- package/src/main/lib/__tests__/jobWorktree.test.cjs +0 -199
- package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +0 -82
- package/src/main/lib/__tests__/landedSinceRun.test.cjs +0 -133
- package/src/main/lib/__tests__/launchFailure.test.cjs +0 -220
- package/src/main/lib/__tests__/loadGate.test.cjs +0 -303
- package/src/main/lib/__tests__/localAdminHttp.test.cjs +0 -214
- package/src/main/lib/__tests__/loopDelay.test.cjs +0 -68
- package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +0 -107
- package/src/main/lib/__tests__/modelCatalog.test.cjs +0 -202
- package/src/main/lib/__tests__/opsOwnership.test.cjs +0 -113
- package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +0 -328
- package/src/main/lib/__tests__/opsRootNestedWrite.test.cjs +0 -51
- package/src/main/lib/__tests__/opsRootResolve.test.cjs +0 -149
- package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +0 -82
- package/src/main/lib/__tests__/prdDisposition.test.cjs +0 -224
- package/src/main/lib/__tests__/procIdentity.test.cjs +0 -119
- package/src/main/lib/__tests__/procName.test.cjs +0 -92
- package/src/main/lib/__tests__/projectBriefCore.test.cjs +0 -216
- package/src/main/lib/__tests__/projectRootResolve.test.cjs +0 -148
- package/src/main/lib/__tests__/queueHealth.test.cjs +0 -58
- package/src/main/lib/__tests__/queueStoreAtomicWrite.test.cjs +0 -88
- package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +0 -190
- package/src/main/lib/__tests__/quietMachineLease.test.cjs +0 -39
- package/src/main/lib/__tests__/rateLimitWindow.test.cjs +0 -88
- package/src/main/lib/__tests__/reaperHelpers.test.cjs +0 -577
- package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +0 -312
- package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +0 -213
- package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +0 -125
- package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +0 -127
- package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +0 -109
- package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +0 -71
- package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +0 -216
- package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +0 -183
- package/src/main/lib/__tests__/schedulerPaths.test.cjs +0 -226
- package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +0 -133
- package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +0 -56
- package/src/main/lib/__tests__/sessionSlots.test.cjs +0 -144
- package/src/main/lib/__tests__/telemetryBacklog.test.cjs +0 -626
- package/src/main/lib/__tests__/telemetryBoot.test.cjs +0 -134
- package/src/main/lib/__tests__/telemetryConsent.test.cjs +0 -136
- package/src/main/lib/__tests__/telemetryCounters.test.cjs +0 -57
- package/src/main/lib/__tests__/telemetryCountersMetadataColumn.test.cjs +0 -98
- package/src/main/lib/__tests__/terminalRunOutcome.test.cjs +0 -200
- package/src/main/lib/__tests__/toolUseClassify.test.cjs +0 -53
- package/src/main/lib/__tests__/updateCheck.test.cjs +0 -63
- package/src/main/lib/__tests__/upgradeDrain.test.cjs +0 -130
- package/src/main/lib/__tests__/usageCircuit.test.cjs +0 -354
- package/src/main/lib/__tests__/watchdog-helpers.test.cjs +0 -441
- package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +0 -266
- package/src/main/lib/kgExchangePairing.cjs +0 -75
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Ported from the retired top-level test-root directory (a node:test suite,
|
|
4
|
-
// never runnable by this repo's vitest-only setup — see CLAUDE.md's Commands
|
|
5
|
-
// section). The existing src/main/lib/__tests__/reaperHelpers.test.cjs
|
|
6
|
-
// exercises classifyRunOutcome extensively via selectReapableJobs and the
|
|
7
|
-
// rate-limit paths, but never asserts claudePidAlive directly (only ever
|
|
8
|
-
// injects a stand-in `pidAlive` function), and never pins the bare
|
|
9
|
-
// no-result/empty-file/malformed-event edge cases below. These fill that
|
|
10
|
-
// gap.
|
|
11
|
-
//
|
|
12
|
-
// Run: timeout 120 npx vitest run src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs
|
|
13
|
-
|
|
14
|
-
const assert = require('node:assert/strict');
|
|
15
|
-
const os = require('node:os');
|
|
16
|
-
const path = require('node:path');
|
|
17
|
-
const fs = require('node:fs');
|
|
18
|
-
const { claudePidAlive, classifyRunOutcome } = require('../lib/reaperHelpers.cjs');
|
|
19
|
-
|
|
20
|
-
// ─────────────────────────────────────────── claudePidAlive
|
|
21
|
-
|
|
22
|
-
test('claudePidAlive: nonexistent pid (999999) returns false', () => {
|
|
23
|
-
assert.equal(claudePidAlive(999999), false);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('claudePidAlive: pid 0 returns false', () => {
|
|
27
|
-
assert.equal(claudePidAlive(0), false);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('claudePidAlive: pid 1 returns false', () => {
|
|
31
|
-
assert.equal(claudePidAlive(1), false);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test('claudePidAlive: null returns false', () => {
|
|
35
|
-
assert.equal(claudePidAlive(null), false);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('claudePidAlive: undefined returns false', () => {
|
|
39
|
-
assert.equal(claudePidAlive(undefined), false);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
// ─────────────────────────────────────────── classifyRunOutcome
|
|
43
|
-
|
|
44
|
-
function writeTempLog(content) {
|
|
45
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'reaper-basics-test-'));
|
|
46
|
-
const filePath = path.join(dir, 'test.log');
|
|
47
|
-
fs.writeFileSync(filePath, content, 'utf8');
|
|
48
|
-
return filePath;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
test('classifyRunOutcome: success without an is_error field → success', () => {
|
|
52
|
-
const p = writeTempLog('{"type":"result","subtype":"success","result":"ok"}\n');
|
|
53
|
-
assert.equal(classifyRunOutcome(p), 'success');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test('classifyRunOutcome: subtype success but is_error:true → failed (error wins)', () => {
|
|
57
|
-
const p = writeTempLog('{"type":"result","subtype":"success","is_error":true}\n');
|
|
58
|
-
assert.equal(classifyRunOutcome(p), 'failed');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('classifyRunOutcome: no result event in the tail → no_result', () => {
|
|
62
|
-
const log = [
|
|
63
|
-
'{"type":"assistant","message":"working"}',
|
|
64
|
-
'{"type":"tool_use","name":"bash"}',
|
|
65
|
-
'some plain text log line',
|
|
66
|
-
].join('\n');
|
|
67
|
-
const p = writeTempLog(log);
|
|
68
|
-
assert.equal(classifyRunOutcome(p), 'no_result');
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test('classifyRunOutcome: empty file → no_result', () => {
|
|
72
|
-
const p = writeTempLog('');
|
|
73
|
-
assert.equal(classifyRunOutcome(p), 'no_result');
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test('classifyRunOutcome: last result event wins when multiple exist', () => {
|
|
77
|
-
const log = [
|
|
78
|
-
'{"type":"result","subtype":"success"}',
|
|
79
|
-
'{"type":"result","subtype":"error","is_error":true}',
|
|
80
|
-
].join('\n');
|
|
81
|
-
const p = writeTempLog(log);
|
|
82
|
-
assert.equal(classifyRunOutcome(p), 'failed');
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test('classifyRunOutcome: nonexistent file → no_result (readTail swallows I/O errors)', () => {
|
|
86
|
-
assert.equal(classifyRunOutcome('/nonexistent/path/that/cannot/exist.log'), 'no_result');
|
|
87
|
-
});
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-reconcile-cwd-preserve.test.cjs — regression test for the
|
|
3
|
-
* data-loss bug found while chasing PRD 1218's test:unit gate: reconcile()
|
|
4
|
-
* rebuilt a queue row's `cwd` unconditionally from its PRD's own
|
|
5
|
-
* frontmatter (`cwd: p.cwd`) at all three of its row-construction sites. A
|
|
6
|
-
* PRD file with no `cwd:` frontmatter key — every hand-written or legacy PRD,
|
|
7
|
-
* and every fixture in this test suite before this fix — parses to
|
|
8
|
-
* `p.cwd === undefined`, which nulled the row's real, already-correct `cwd`.
|
|
9
|
-
* queueStore.writeSplit's `job.cwd || defaultCwd` bucketing then relocated
|
|
10
|
-
* the row into schedulerBatch.cjs's DEFAULT_PROJECT_CWD shard
|
|
11
|
-
* (`~/Projects/session-manager`) — the WRONG project — while the row's own
|
|
12
|
-
* project's shard was rewritten without it. A PRD's frontmatter `cwd` must
|
|
13
|
-
* REFINE a row's existing `cwd`, never erase one.
|
|
14
|
-
*
|
|
15
|
-
* Covers the normal refresh path (an existing row matched to its PRD) and
|
|
16
|
-
* the fresh-discovery path (a PRD with no prior row, falling back to the
|
|
17
|
-
* project root it was actually found under via
|
|
18
|
-
* prdLocations.deriveProjectCwdFromPrdPath rather than nulling to
|
|
19
|
-
* DEFAULT_PROJECT_CWD).
|
|
20
|
-
*
|
|
21
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
'use strict';
|
|
25
|
-
|
|
26
|
-
import { test, expect, beforeAll, afterAll } from 'vitest';
|
|
27
|
-
const fs = require('node:fs');
|
|
28
|
-
const os = require('node:os');
|
|
29
|
-
const path = require('node:path');
|
|
30
|
-
|
|
31
|
-
let tmpHome;
|
|
32
|
-
let originalHome;
|
|
33
|
-
let reconcile;
|
|
34
|
-
let DEFAULT_PROJECT_CWD;
|
|
35
|
-
|
|
36
|
-
beforeAll(() => {
|
|
37
|
-
originalHome = process.env.HOME;
|
|
38
|
-
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-reconcile-cwd-preserve-'));
|
|
39
|
-
process.env.HOME = tmpHome;
|
|
40
|
-
({ reconcile } = require('../scheduler.cjs'));
|
|
41
|
-
({ DEFAULT_PROJECT_CWD } = require('../lib/schedulerBatch.cjs'));
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
afterAll(() => {
|
|
45
|
-
process.env.HOME = originalHome;
|
|
46
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// allProjectCwds()/activeProjectCwds() (queueStore.cjs's stateCwds) discover
|
|
50
|
-
// project cwds by scanning ~/.claude/projects/*/*.jsonl for a `cwd` field —
|
|
51
|
-
// same pattern as scheduler-reap-dead-running-jobs.test.cjs and friends.
|
|
52
|
-
function registerActiveProject(cwd) {
|
|
53
|
-
const projectsDir = path.join(tmpHome, '.claude', 'projects');
|
|
54
|
-
const slugDir = path.join(projectsDir, `fake-project-slug-${path.basename(cwd)}`);
|
|
55
|
-
fs.mkdirSync(slugDir, { recursive: true });
|
|
56
|
-
fs.writeFileSync(path.join(slugDir, 'transcript.jsonl'), JSON.stringify({ cwd }) + '\n');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
test('reconcile() never nulls an existing row\'s cwd because its PRD has no cwd: frontmatter', async () => {
|
|
60
|
-
const projectCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-reconcile-cwd-preserve-project-'));
|
|
61
|
-
registerActiveProject(projectCwd);
|
|
62
|
-
|
|
63
|
-
const slug = `1218-cwd-preserve-${process.pid}-${Math.floor(Math.random() * 1e6)}`;
|
|
64
|
-
const prdsDir = path.join(projectCwd, 'session-manager-operations', 'scheduler', 'epics', 'test-fixture-epic', 'prds');
|
|
65
|
-
fs.mkdirSync(prdsDir, { recursive: true });
|
|
66
|
-
// Deliberately NO `cwd:` frontmatter key — the exact shape of every
|
|
67
|
-
// hand-written or legacy PRD that triggered the bug.
|
|
68
|
-
fs.writeFileSync(path.join(prdsDir, `${slug}.md`), '# Goal\n\nNo cwd frontmatter here.\n', 'utf8');
|
|
69
|
-
|
|
70
|
-
const job = { slug, title: 'x', cwd: projectCwd, status: 'pending' };
|
|
71
|
-
const state = { jobs: [job] };
|
|
72
|
-
|
|
73
|
-
await reconcile(state);
|
|
74
|
-
|
|
75
|
-
const row = state.jobs.find((j) => j.slug === slug);
|
|
76
|
-
expect(row).toBeDefined();
|
|
77
|
-
expect(row.cwd).toBe(projectCwd);
|
|
78
|
-
expect(row.cwd).not.toBe(DEFAULT_PROJECT_CWD);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('reconcile() gives a freshly-discovered, frontmatter-less PRD the project root it was actually found under, never DEFAULT_PROJECT_CWD', async () => {
|
|
82
|
-
const projectCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-reconcile-cwd-preserve-fresh-'));
|
|
83
|
-
registerActiveProject(projectCwd);
|
|
84
|
-
|
|
85
|
-
const slug = `1218-cwd-preserve-fresh-${process.pid}-${Math.floor(Math.random() * 1e6)}`;
|
|
86
|
-
const prdsDir = path.join(projectCwd, 'session-manager-operations', 'scheduler', 'epics', 'test-fixture-epic', 'prds');
|
|
87
|
-
fs.mkdirSync(prdsDir, { recursive: true });
|
|
88
|
-
fs.writeFileSync(path.join(prdsDir, `${slug}.md`), '# Goal\n\nNo cwd frontmatter here either.\n', 'utf8');
|
|
89
|
-
|
|
90
|
-
// No prior row at all — this PRD is discovered fresh by reconcile()'s own
|
|
91
|
-
// onDisk scan, not handed in via `state.jobs`.
|
|
92
|
-
const state = { jobs: [] };
|
|
93
|
-
|
|
94
|
-
await reconcile(state);
|
|
95
|
-
|
|
96
|
-
const row = state.jobs.find((j) => j.slug === slug);
|
|
97
|
-
expect(row).toBeDefined();
|
|
98
|
-
expect(row.cwd).toBe(projectCwd);
|
|
99
|
-
expect(row.cwd).not.toBe(DEFAULT_PROJECT_CWD);
|
|
100
|
-
});
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-reconcile-history-backfill.test.cjs — regression test for the
|
|
3
|
-
* bug found 2026-08-02 while investigating why session-manager's own
|
|
4
|
-
* Scheduler tab showed an empty Queue AND an empty History: a completed
|
|
5
|
-
* job's PRD `.md` is archived immediately (archiveCompletedPrd, called right
|
|
6
|
-
* when the job finishes) — long before HISTORY_RETENTION_MS (7 days) would
|
|
7
|
-
* ever cause queueHistory.partitionJobs to append it to history.jsonl. The
|
|
8
|
-
* very next reconcile() pass then found the .md gone and silently dropped
|
|
9
|
-
* the job's row from jobs[] via the "terminal job whose .md is gone was
|
|
10
|
-
* archived on purpose" branch, without ever writing it to history.jsonl —
|
|
11
|
-
* total loss of the completed job's record.
|
|
12
|
-
*
|
|
13
|
-
* reconcile() must now backfill history.jsonl for exactly this case before
|
|
14
|
-
* dropping the row.
|
|
15
|
-
*
|
|
16
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/scheduler-reconcile-history-backfill.test.cjs
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
'use strict';
|
|
20
|
-
|
|
21
|
-
import { test, expect, afterEach, vi } from 'vitest';
|
|
22
|
-
const fs = require('node:fs');
|
|
23
|
-
const os = require('node:os');
|
|
24
|
-
const path = require('node:path');
|
|
25
|
-
|
|
26
|
-
const tmpDirs = [];
|
|
27
|
-
|
|
28
|
-
function makeFixtureCwd() {
|
|
29
|
-
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-reconcile-history-'));
|
|
30
|
-
tmpDirs.push(cwd);
|
|
31
|
-
return cwd;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
afterEach(() => {
|
|
35
|
-
vi.resetModules();
|
|
36
|
-
while (tmpDirs.length) {
|
|
37
|
-
const dir = tmpDirs.pop();
|
|
38
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('reconcile() backfills history.jsonl for a completed job whose PRD file is already gone', async () => {
|
|
43
|
-
const cwd = makeFixtureCwd();
|
|
44
|
-
const opsRoot = path.join(cwd, 'session-manager-operations');
|
|
45
|
-
fs.mkdirSync(path.join(opsRoot, 'scheduler', 'prds'), { recursive: true });
|
|
46
|
-
fs.mkdirSync(path.join(opsRoot, 'scheduler', 'state'), { recursive: true });
|
|
47
|
-
|
|
48
|
-
const { reconcile } = require('../scheduler.cjs');
|
|
49
|
-
|
|
50
|
-
const job = {
|
|
51
|
-
slug: '999-vanished-prd',
|
|
52
|
-
title: 'Vanished PRD',
|
|
53
|
-
cwd,
|
|
54
|
-
status: 'completed',
|
|
55
|
-
finishedAt: new Date().toISOString(),
|
|
56
|
-
exitCode: 0,
|
|
57
|
-
error: null,
|
|
58
|
-
runId: 'run-1',
|
|
59
|
-
};
|
|
60
|
-
// No matching .md anywhere under prds/ or prds-archived/ for this slug —
|
|
61
|
-
// simulates the file having already been archived by archiveCompletedPrd
|
|
62
|
-
// in the same tick the job finished, well before this reconcile() call.
|
|
63
|
-
const state = { jobs: [job] };
|
|
64
|
-
|
|
65
|
-
await reconcile(state);
|
|
66
|
-
|
|
67
|
-
expect(state.jobs.find((j) => j.slug === job.slug)).toBeUndefined();
|
|
68
|
-
|
|
69
|
-
const historyPath = path.join(opsRoot, 'scheduler', 'state', 'history.jsonl');
|
|
70
|
-
expect(fs.existsSync(historyPath)).toBe(true);
|
|
71
|
-
const lines = fs.readFileSync(historyPath, 'utf8').trim().split('\n').filter(Boolean);
|
|
72
|
-
const recorded = lines.map((l) => JSON.parse(l)).find((e) => e.slug === job.slug);
|
|
73
|
-
expect(recorded).toBeDefined();
|
|
74
|
-
expect(recorded.status).toBe('completed');
|
|
75
|
-
expect(recorded.runId).toBe('run-1');
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test('reconcile() does not double-write history for a job already recorded there', async () => {
|
|
79
|
-
const cwd = makeFixtureCwd();
|
|
80
|
-
const opsRoot = path.join(cwd, 'session-manager-operations');
|
|
81
|
-
fs.mkdirSync(path.join(opsRoot, 'scheduler', 'prds'), { recursive: true });
|
|
82
|
-
const stateDir = path.join(opsRoot, 'scheduler', 'state');
|
|
83
|
-
fs.mkdirSync(stateDir, { recursive: true });
|
|
84
|
-
|
|
85
|
-
const job = {
|
|
86
|
-
slug: '998-already-recorded',
|
|
87
|
-
title: 'Already recorded',
|
|
88
|
-
cwd,
|
|
89
|
-
status: 'completed',
|
|
90
|
-
finishedAt: new Date().toISOString(),
|
|
91
|
-
exitCode: 0,
|
|
92
|
-
error: null,
|
|
93
|
-
runId: 'run-2',
|
|
94
|
-
};
|
|
95
|
-
const historyPath = path.join(stateDir, 'history.jsonl');
|
|
96
|
-
fs.writeFileSync(historyPath, JSON.stringify(job) + '\n', 'utf8');
|
|
97
|
-
|
|
98
|
-
const { reconcile } = require('../scheduler.cjs');
|
|
99
|
-
const state = { jobs: [job] };
|
|
100
|
-
await reconcile(state);
|
|
101
|
-
|
|
102
|
-
const lines = fs.readFileSync(historyPath, 'utf8').trim().split('\n').filter(Boolean);
|
|
103
|
-
const matches = lines.map((l) => JSON.parse(l)).filter((e) => e.slug === job.slug);
|
|
104
|
-
expect(matches.length).toBe(1);
|
|
105
|
-
});
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-reconcile-invalid-repair.test.cjs — end-to-end reproduction of
|
|
3
|
-
* the 2026-08-07 1021/1022 incident: a queue.json row with `"status":
|
|
4
|
-
* "queued"` (a value outside ScheduleJobStatus) sat unpicked for 4+ hours.
|
|
5
|
-
*
|
|
6
|
-
* queueStore.shapeJobs (scheduleJobSchema.cjs, landed by a prior PRD)
|
|
7
|
-
* already quarantines such a row into `invalidJobs` on read rather than
|
|
8
|
-
* passing it through — but reconcile() itself was still add-only (`if
|
|
9
|
-
* (seen.has(slug)) continue`), so a quarantined row was never repaired, only
|
|
10
|
-
* silently absent from state.jobs with no log of what its bad status had
|
|
11
|
-
* been.
|
|
12
|
-
*
|
|
13
|
-
* This test exercises the real quarantine path (queueStore.shapeJobs on the
|
|
14
|
-
* raw incident JSON) against a real on-disk PRD, runs the real reconcile(),
|
|
15
|
-
* and asserts: computeStallSummary flags the PRE-repair state as stalled,
|
|
16
|
-
* reconcile() repairs the row to 'pending', logs the repair at warn level,
|
|
17
|
-
* and audits it.
|
|
18
|
-
*
|
|
19
|
-
* HOME-isolated (mirrors scheduler-prd-missing-skip.test.cjs): stub HOME to
|
|
20
|
-
* a mkdtemp dir before requiring scheduler.cjs/queueStore.cjs, and register
|
|
21
|
-
* the fixture project as "active" via a fake ~/.claude/projects transcript —
|
|
22
|
-
* reconcile's PRD/history discovery (prdLocations.cjs, queueHistory.cjs)
|
|
23
|
-
* only scans cwds it can find that way.
|
|
24
|
-
*
|
|
25
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
'use strict';
|
|
29
|
-
|
|
30
|
-
import { test, expect, beforeAll, afterAll, afterEach, vi } from 'vitest';
|
|
31
|
-
const fs = require('node:fs');
|
|
32
|
-
const os = require('node:os');
|
|
33
|
-
const path = require('node:path');
|
|
34
|
-
|
|
35
|
-
let tmpHome;
|
|
36
|
-
let originalHome;
|
|
37
|
-
let scheduler;
|
|
38
|
-
let queueStore;
|
|
39
|
-
|
|
40
|
-
beforeAll(() => {
|
|
41
|
-
originalHome = process.env.HOME;
|
|
42
|
-
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-reconcile-repair-home-'));
|
|
43
|
-
process.env.HOME = tmpHome;
|
|
44
|
-
|
|
45
|
-
scheduler = require('../scheduler.cjs');
|
|
46
|
-
queueStore = require('../lib/queueStore.cjs');
|
|
47
|
-
|
|
48
|
-
if (!scheduler.PRDS_DIR.startsWith(tmpHome)) {
|
|
49
|
-
throw new Error(`refusing to run: PRDS_DIR (${scheduler.PRDS_DIR}) is not under the temp HOME (${tmpHome})`);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
afterAll(() => {
|
|
54
|
-
process.env.HOME = originalHome;
|
|
55
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
afterEach(() => {
|
|
59
|
-
vi.restoreAllMocks();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
function registerActiveProject(cwd) {
|
|
63
|
-
const projectsDir = path.join(tmpHome, '.claude', 'projects');
|
|
64
|
-
const slugDir = path.join(projectsDir, `fake-project-slug-${path.basename(cwd)}`);
|
|
65
|
-
fs.mkdirSync(slugDir, { recursive: true });
|
|
66
|
-
fs.writeFileSync(path.join(slugDir, 'transcript.jsonl'), JSON.stringify({ cwd }) + '\n');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function makeFixtureProject(prefix) {
|
|
70
|
-
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
71
|
-
registerActiveProject(cwd);
|
|
72
|
-
const opsRoot = path.join(cwd, 'session-manager-operations');
|
|
73
|
-
const prdsDir = path.join(opsRoot, 'scheduler', 'prds');
|
|
74
|
-
const stateDir = path.join(opsRoot, 'scheduler', 'state');
|
|
75
|
-
fs.mkdirSync(prdsDir, { recursive: true });
|
|
76
|
-
fs.mkdirSync(stateDir, { recursive: true });
|
|
77
|
-
return { cwd, prdsDir, stateDir };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
test('reconcile() repairs a queue row with an invalid status back to pending, logs, and audits it', async () => {
|
|
81
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-reconcile-repair-proj-');
|
|
82
|
-
try {
|
|
83
|
-
// Real on-disk PRD (its file location is the reconcile source of truth).
|
|
84
|
-
fs.writeFileSync(
|
|
85
|
-
path.join(prdsDir, '1021-fix-the-thing.md'),
|
|
86
|
-
'---\ntitle: Fix the thing\ncwd: ' + cwd + '\nestimateMinutes: 15\n---\n\n# Goal\nFix it.\n',
|
|
87
|
-
'utf8',
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
// The exact incident shape: a row whose status is 'queued', outside
|
|
91
|
-
// ScheduleJobStatus entirely.
|
|
92
|
-
const badRow = {
|
|
93
|
-
slug: '1021-fix-the-thing',
|
|
94
|
-
title: 'Fix the thing',
|
|
95
|
-
cwd,
|
|
96
|
-
status: 'queued',
|
|
97
|
-
runId: null,
|
|
98
|
-
startedAt: null,
|
|
99
|
-
finishedAt: null,
|
|
100
|
-
exitCode: null,
|
|
101
|
-
error: null,
|
|
102
|
-
};
|
|
103
|
-
const queuePath = path.join(stateDir, 'queue.json');
|
|
104
|
-
fs.writeFileSync(queuePath, JSON.stringify({ jobs: [badRow] }, null, 2), 'utf8');
|
|
105
|
-
|
|
106
|
-
// Exercise the REAL quarantine gate (same one queueStore.readMerged runs
|
|
107
|
-
// at boot/every IPC read) rather than hand-building invalidJobs.
|
|
108
|
-
const { jobs, invalid } = queueStore.shapeJobs(fs.readFileSync(queuePath, 'utf8'), queuePath);
|
|
109
|
-
expect(jobs.length).toBe(0); // the bad row never reaches state.jobs
|
|
110
|
-
expect(invalid.length).toBe(1);
|
|
111
|
-
expect(invalid[0].slug).toBe(badRow.slug);
|
|
112
|
-
expect(invalid[0].row.status).toBe('queued');
|
|
113
|
-
|
|
114
|
-
const state = { jobs, invalidJobs: invalid, paused: null };
|
|
115
|
-
|
|
116
|
-
// Stall detector must flag the PRE-repair state: the queue holds a
|
|
117
|
-
// (quarantined) job but nothing is running or pending and it isn't
|
|
118
|
-
// paused — this is exactly the condition that was silent for 4+ hours.
|
|
119
|
-
const preRepairStall = scheduler.computeStallSummary(state);
|
|
120
|
-
expect(preRepairStall.stalled).toBe(true);
|
|
121
|
-
expect(preRepairStall.total).toBe(1);
|
|
122
|
-
expect(preRepairStall.running).toBe(0);
|
|
123
|
-
expect(preRepairStall.pending).toBe(0);
|
|
124
|
-
|
|
125
|
-
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
126
|
-
// scheduler.cjs destructures `appendAuditEvent` out of auditLog.cjs at
|
|
127
|
-
// require time, so spying on the module's export property after the
|
|
128
|
-
// fact wouldn't intercept scheduler.cjs's already-bound reference —
|
|
129
|
-
// assert against the real (tmpHome-isolated) audit log file instead.
|
|
130
|
-
const { auditLogPath } = require('../lib/auditLog.cjs');
|
|
131
|
-
expect(auditLogPath().startsWith(tmpHome)).toBe(true);
|
|
132
|
-
|
|
133
|
-
queueStore.bustCwdCache();
|
|
134
|
-
await scheduler.reconcile(state);
|
|
135
|
-
|
|
136
|
-
const repaired = state.jobs.find((j) => j.slug === badRow.slug);
|
|
137
|
-
expect(repaired).toBeDefined();
|
|
138
|
-
expect(repaired.status).toBe('pending');
|
|
139
|
-
|
|
140
|
-
const warnedRepair = warnSpy.mock.calls.some((args) =>
|
|
141
|
-
String(args[0]).includes('repaired invalid queue row') && String(args[0]).includes(badRow.slug),
|
|
142
|
-
);
|
|
143
|
-
expect(warnedRepair).toBe(true);
|
|
144
|
-
|
|
145
|
-
const auditLines = fs.readFileSync(auditLogPath(), 'utf8').trim().split('\n').filter(Boolean).map((l) => JSON.parse(l));
|
|
146
|
-
const auditedRepair = auditLines.some(
|
|
147
|
-
(rec) => rec.kind === 'scheduler_row_repaired' && rec.slug === badRow.slug && rec.oldStatus === 'queued',
|
|
148
|
-
);
|
|
149
|
-
expect(auditedRepair).toBe(true);
|
|
150
|
-
|
|
151
|
-
// Post-repair, the same condition must no longer read as stalled.
|
|
152
|
-
const postRepairStall = scheduler.computeStallSummary(state);
|
|
153
|
-
expect(postRepairStall.stalled).toBe(false);
|
|
154
|
-
} finally {
|
|
155
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
test('reconcile() does not resurrect an invalid row whose slug already has a terminal history record', async () => {
|
|
160
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-reconcile-repair-done-');
|
|
161
|
-
try {
|
|
162
|
-
fs.writeFileSync(
|
|
163
|
-
path.join(prdsDir, '1022-already-done.md'),
|
|
164
|
-
'---\ntitle: Already done\ncwd: ' + cwd + '\nestimateMinutes: 15\n---\n\n# Goal\nDone.\n',
|
|
165
|
-
'utf8',
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
const badRow = {
|
|
169
|
-
slug: '1022-already-done',
|
|
170
|
-
title: 'Already done',
|
|
171
|
-
cwd,
|
|
172
|
-
status: 'queued',
|
|
173
|
-
runId: 'run-xyz',
|
|
174
|
-
startedAt: new Date().toISOString(),
|
|
175
|
-
finishedAt: null,
|
|
176
|
-
exitCode: null,
|
|
177
|
-
error: null,
|
|
178
|
-
};
|
|
179
|
-
const queuePath = path.join(stateDir, 'queue.json');
|
|
180
|
-
fs.writeFileSync(queuePath, JSON.stringify({ jobs: [badRow] }, null, 2), 'utf8');
|
|
181
|
-
|
|
182
|
-
const { jobs, invalid } = queueStore.shapeJobs(fs.readFileSync(queuePath, 'utf8'), queuePath);
|
|
183
|
-
expect(invalid.length).toBe(1);
|
|
184
|
-
|
|
185
|
-
const state = { jobs, invalidJobs: invalid, paused: null };
|
|
186
|
-
|
|
187
|
-
// A terminal record already exists for this slug — reconcile must never
|
|
188
|
-
// repair the corrupted row back into a runnable 'pending' state on top
|
|
189
|
-
// of already-shipped work.
|
|
190
|
-
fs.writeFileSync(
|
|
191
|
-
path.join(stateDir, 'history.jsonl'),
|
|
192
|
-
JSON.stringify({ slug: badRow.slug, status: 'completed', finishedAt: new Date().toISOString(), runId: 'run-xyz' }) + '\n',
|
|
193
|
-
'utf8',
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
queueStore.bustCwdCache();
|
|
197
|
-
await scheduler.reconcile(state);
|
|
198
|
-
|
|
199
|
-
expect(state.jobs.find((j) => j.slug === badRow.slug)).toBeUndefined();
|
|
200
|
-
} finally {
|
|
201
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
202
|
-
}
|
|
203
|
-
});
|