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,157 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-never-stop.test.cjs — the invariant: if a queue holds ready PRDs,
|
|
3
|
-
* something must drive them.
|
|
4
|
-
*
|
|
5
|
-
* Every stall observed in this codebase was a different CAUSE with the same
|
|
6
|
-
* SHAPE — ready rows, nothing running, nobody ticking:
|
|
7
|
-
* - a rate-limited exit stamped terminal 'failed' (2026-09-05: 42 rows)
|
|
8
|
-
* - a spin loop past the manual-clear cooldown
|
|
9
|
-
* - a worktree merge-back leaving the project on a job branch
|
|
10
|
-
* - a job parked needs_review with no fix plan
|
|
11
|
-
* - app churn under session-manager-operations/ counted as unfinished work
|
|
12
|
-
* - the billing meter itself 429ing so utilization never reported
|
|
13
|
-
* Guarding each cause individually always lags the next one, so the watchdog
|
|
14
|
-
* guards the shape.
|
|
15
|
-
*
|
|
16
|
-
* Run: timeout 180 npx vitest run src/main/__tests__/scheduler-never-stop.test.cjs
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
'use strict';
|
|
20
|
-
|
|
21
|
-
// vitest, NOT node:test — this repo's suite is vitest-only (CLAUDE.md).
|
|
22
|
-
import { test } from 'vitest';
|
|
23
|
-
const assert = require('node:assert/strict');
|
|
24
|
-
const fs = require('node:fs');
|
|
25
|
-
const os = require('node:os');
|
|
26
|
-
const path = require('node:path');
|
|
27
|
-
|
|
28
|
-
// HOME before require: every state path is baked from os.homedir() at load.
|
|
29
|
-
process.env.HOME = fs.mkdtempSync(path.join(os.tmpdir(), 'never-stop-test-'));
|
|
30
|
-
|
|
31
|
-
const {
|
|
32
|
-
classifyQueueStarvation,
|
|
33
|
-
QUEUE_STARVATION_MS,
|
|
34
|
-
stripAppOwnedChurn,
|
|
35
|
-
} = require('../scheduler.cjs');
|
|
36
|
-
|
|
37
|
-
const CWD = '/home/bilko/Projects/starry-night-ships';
|
|
38
|
-
const NOW = Date.parse('2026-09-05T23:00:00.000Z');
|
|
39
|
-
const idleFor = (ms) => NOW - ms;
|
|
40
|
-
const LONG = QUEUE_STARVATION_MS + 60_000;
|
|
41
|
-
|
|
42
|
-
const base = (over = {}) => ({
|
|
43
|
-
jobs: [{ slug: 'a', cwd: CWD, status: 'pending', dependsOn: [] }],
|
|
44
|
-
paused: null,
|
|
45
|
-
runningCount: 0,
|
|
46
|
-
lastRunAtMs: idleFor(LONG),
|
|
47
|
-
now: NOW,
|
|
48
|
-
...over,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// ── the invariant ────────────────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
test('ready work + nothing running + long idle => starved, and a tick would help', () => {
|
|
54
|
-
const v = classifyQueueStarvation(base());
|
|
55
|
-
assert.equal(v.kind, 'starved');
|
|
56
|
-
assert.equal(v.pending, 1);
|
|
57
|
-
assert.equal(v.dispatchable, 1);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('the real incident shape: 40 ready rows, 0 running, idle for hours', () => {
|
|
61
|
-
const jobs = Array.from({ length: 40 }, (_, i) => ({
|
|
62
|
-
slug: `${207 + i}-step`, cwd: CWD, status: 'pending', dependsOn: [],
|
|
63
|
-
}));
|
|
64
|
-
const v = classifyQueueStarvation(base({ jobs, lastRunAtMs: idleFor(3 * 60 * 60_000) }));
|
|
65
|
-
assert.equal(v.kind, 'starved');
|
|
66
|
-
assert.equal(v.dispatchable, 40);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// ── it must NOT fire when the queue is legitimately quiet ────────────────────
|
|
70
|
-
|
|
71
|
-
test('a running job means the queue is flowing — never starved', () => {
|
|
72
|
-
assert.equal(classifyQueueStarvation(base({ runningCount: 1 })), null);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('no pending rows is not a stall', () => {
|
|
76
|
-
assert.equal(classifyQueueStarvation(base({ jobs: [{ slug: 'a', cwd: CWD, status: 'completed' }] })), null);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test('paused is a DECISION, not a stall — the watchdog must never override it', () => {
|
|
80
|
-
assert.equal(classifyQueueStarvation(base({ paused: { reason: 'rate_limit', resumeAt: null } })), null);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('inside the idle threshold the normal path gets its chance first', () => {
|
|
84
|
-
assert.equal(classifyQueueStarvation(base({ lastRunAtMs: idleFor(QUEUE_STARVATION_MS - 1000) })), null);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test('a never-recorded lastRunAt counts as infinitely idle, not as healthy', () => {
|
|
88
|
-
const v = classifyQueueStarvation(base({ lastRunAtMs: NaN }));
|
|
89
|
-
assert.equal(v.kind, 'starved');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// ── blocked is a DIFFERENT verdict from starved ──────────────────────────────
|
|
93
|
-
|
|
94
|
-
test('every pending row behind a terminal dep => blocked, not starved (a tick cannot help)', () => {
|
|
95
|
-
const jobs = [
|
|
96
|
-
{ slug: '206-lava-ape', cwd: CWD, status: 'failed', dependsOn: [] },
|
|
97
|
-
{ slug: '207-body', cwd: CWD, status: 'pending', dependsOn: ['206-lava-ape'] },
|
|
98
|
-
{ slug: '208-docs', cwd: CWD, status: 'pending', dependsOn: ['207-body'] },
|
|
99
|
-
];
|
|
100
|
-
const v = classifyQueueStarvation(base({ jobs }));
|
|
101
|
-
assert.equal(v.kind, 'blocked');
|
|
102
|
-
assert.equal(v.pending, 2);
|
|
103
|
-
assert.equal(v.dispatchable, 0);
|
|
104
|
-
assert.deepEqual(v.blockedChains[0].blockedBy, ['206-lava-ape']);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test('one dispatchable row among blocked ones still counts as starved — the queue can make progress', () => {
|
|
108
|
-
const jobs = [
|
|
109
|
-
{ slug: 'x-dead', cwd: CWD, status: 'failed', dependsOn: [] },
|
|
110
|
-
{ slug: 'y-blocked', cwd: CWD, status: 'pending', dependsOn: ['x-dead'] },
|
|
111
|
-
{ slug: 'z-ready', cwd: CWD, status: 'pending', dependsOn: [] },
|
|
112
|
-
];
|
|
113
|
-
const v = classifyQueueStarvation(base({ jobs }));
|
|
114
|
-
assert.equal(v.kind, 'starved');
|
|
115
|
-
assert.equal(v.dispatchable, 1);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test('a project blocked while ANOTHER project has ready work is still starved overall', () => {
|
|
119
|
-
const jobs = [
|
|
120
|
-
{ slug: 'a-dead', cwd: '/p/one', status: 'failed', dependsOn: [] },
|
|
121
|
-
{ slug: 'b-blocked', cwd: '/p/one', status: 'pending', dependsOn: ['a-dead'] },
|
|
122
|
-
{ slug: 'c-ready', cwd: '/p/two', status: 'pending', dependsOn: [] },
|
|
123
|
-
];
|
|
124
|
-
assert.equal(classifyQueueStarvation(base({ jobs })).kind, 'starved');
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// ── app-owned churn must never be blamed on a job ────────────────────────────
|
|
128
|
-
|
|
129
|
-
test('stripAppOwnedChurn drops session-manager-operations churn, keeps real source', () => {
|
|
130
|
-
const out = stripAppOwnedChurn([
|
|
131
|
-
'src/main/scheduler.cjs',
|
|
132
|
-
'session-manager-operations/scheduler/state/queue.json',
|
|
133
|
-
'session-manager-operations/scheduler/state/history.jsonl',
|
|
134
|
-
'session-manager-operations/prompt-sessions/active-index.json',
|
|
135
|
-
'dashboard/panels/outcome-stats.jsx',
|
|
136
|
-
]);
|
|
137
|
-
assert.deepEqual(out, ['src/main/scheduler.cjs', 'dashboard/panels/outcome-stats.jsx']);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test('stripAppOwnedChurn preserves the null contract (git status unavailable != left nothing)', () => {
|
|
141
|
-
assert.equal(stripAppOwnedChurn(null), null);
|
|
142
|
-
assert.equal(stripAppOwnedChurn(undefined), undefined);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
test('stripAppOwnedChurn only matches a whole path segment, never a substring', () => {
|
|
146
|
-
assert.deepEqual(
|
|
147
|
-
stripAppOwnedChurn(['docs/session-manager-operations-guide.md', 'a/session-manager-operations/x.json']),
|
|
148
|
-
['docs/session-manager-operations-guide.md'],
|
|
149
|
-
);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
test('a job that leaves REAL source dirty still parks — the filter must not excuse that', () => {
|
|
153
|
-
assert.deepEqual(
|
|
154
|
-
stripAppOwnedChurn(['session-manager-operations/scheduler/state/queue.json', 'scripts/arena/titan.gd']),
|
|
155
|
-
['scripts/arena/titan.gd'],
|
|
156
|
-
);
|
|
157
|
-
});
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-no-dead-end-status.test.cjs
|
|
3
|
-
*
|
|
4
|
-
* Structural guard for the no-human-intervention guarantee (this PRD): every
|
|
5
|
-
* value in `JOB_STATUSES` (imported from scheduleJobSchema.cjs — the real
|
|
6
|
-
* array, never a hand-written copy) must either be genuinely final
|
|
7
|
-
* (completed/skipped) or have at least one AUTOMATED selector that can move
|
|
8
|
-
* a row parked in it, with no human action required.
|
|
9
|
-
*
|
|
10
|
-
* Each non-final status is asserted by CONSTRUCTING a representative parked
|
|
11
|
-
* row (a stale timestamp + a counter positioned so the row is still
|
|
12
|
-
* selectable) and showing the named selector actually returns it — not by
|
|
13
|
-
* asserting a hand-maintained status -> selector-name string map, which
|
|
14
|
-
* would pass even if the real wiring silently broke. If a future change adds
|
|
15
|
-
* a new status to JOB_STATUSES with no automated exit wired up here, this
|
|
16
|
-
* test fails loudly instead of the row becoming a new, silent dead end.
|
|
17
|
-
*
|
|
18
|
-
* HOME is overridden to a tmp dir BEFORE requiring scheduler.cjs — same
|
|
19
|
-
* reason as scheduler-failed-autoreset.test.cjs (appendAuditEvent writes
|
|
20
|
-
* under $HOME/.claude/session-manager/audit-log.jsonl).
|
|
21
|
-
*
|
|
22
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/scheduler-no-dead-end-status.test.cjs
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
'use strict';
|
|
26
|
-
|
|
27
|
-
const assert = require('node:assert/strict');
|
|
28
|
-
const fs = require('node:fs');
|
|
29
|
-
const os = require('node:os');
|
|
30
|
-
const path = require('node:path');
|
|
31
|
-
|
|
32
|
-
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'no-dead-end-status-test-'));
|
|
33
|
-
process.env.HOME = tmpHome;
|
|
34
|
-
|
|
35
|
-
const { JOB_STATUSES } = require('../lib/scheduleJobSchema.cjs');
|
|
36
|
-
const {
|
|
37
|
-
selectFailedAutoResetTargets,
|
|
38
|
-
FAILED_AUTORESET_CAP,
|
|
39
|
-
selectExhaustedNeedsReviewTargets,
|
|
40
|
-
NEEDS_REVIEW_RESOLVE_CAP,
|
|
41
|
-
selectQuarantineAutoResolveTargets,
|
|
42
|
-
QUARANTINE_RESOLVE_CAP,
|
|
43
|
-
findStrandedInvestigations,
|
|
44
|
-
INVESTIGATION_MAX_MS,
|
|
45
|
-
} = require('../scheduler.cjs');
|
|
46
|
-
const { selectReapableJobs } = require('../lib/reaperHelpers.cjs');
|
|
47
|
-
const { pickForProject } = require('../lib/schedulerBatch.cjs');
|
|
48
|
-
|
|
49
|
-
const MIN_MS = 60_000;
|
|
50
|
-
|
|
51
|
-
// Every terminal status (no automated exit needed — nothing should ever
|
|
52
|
-
// move a row out of these) and every non-terminal status's proof that a
|
|
53
|
-
// row parked there is reachable by an automated selector, keyed only for
|
|
54
|
-
// this test's own assertions (never treated as authoritative wiring below).
|
|
55
|
-
const FINAL_STATUSES = new Set(['completed', 'skipped']);
|
|
56
|
-
|
|
57
|
-
test('JOB_STATUSES contains exactly the statuses this test accounts for (fails loudly on drift)', () => {
|
|
58
|
-
// Not a hand-maintained selector map — just a manifest of what this file
|
|
59
|
-
// below actually exercises, so an entirely new, unhandled status trips
|
|
60
|
-
// this assertion instead of silently passing the loop below with zero
|
|
61
|
-
// coverage.
|
|
62
|
-
const accountedFor = new Set([
|
|
63
|
-
'pending', 'running', 'investigating', 'completed', 'skipped', 'failed', 'needs_review', 'quarantined',
|
|
64
|
-
]);
|
|
65
|
-
const unaccounted = JOB_STATUSES.filter((s) => !accountedFor.has(s));
|
|
66
|
-
if (unaccounted.length > 0) {
|
|
67
|
-
throw new Error(
|
|
68
|
-
`HALT: JOB_STATUSES has status(es) with no automated-exit test coverage: ${unaccounted.join(', ')} — `
|
|
69
|
-
+ 'add a case to scheduler-no-dead-end-status.test.cjs before shipping this status.',
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('every terminal status in JOB_STATUSES is genuinely final (completed/skipped only)', () => {
|
|
75
|
-
for (const status of JOB_STATUSES) {
|
|
76
|
-
if (status === 'completed' || status === 'skipped') continue;
|
|
77
|
-
assert.ok(!FINAL_STATUSES.has(status), `${status} must not be treated as final`);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('pending: a fresh pending row with no blockers is picked for dispatch by pickForProject', () => {
|
|
82
|
-
assert.ok(JOB_STATUSES.includes('pending'));
|
|
83
|
-
const job = { slug: 'pending-row', cwd: '/home/user/project', status: 'pending' };
|
|
84
|
-
const { batch } = pickForProject([job], new Set(), 5);
|
|
85
|
-
assert.ok(batch.some((j) => j.slug === 'pending-row'), 'pending row must be dispatch-eligible with no blockers');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test('running: a running row whose pid is provably dead is reaped by selectReapableJobs', () => {
|
|
89
|
-
assert.ok(JOB_STATUSES.includes('running'));
|
|
90
|
-
const job = {
|
|
91
|
-
slug: 'dead-running-row',
|
|
92
|
-
cwd: '/home/user/project',
|
|
93
|
-
status: 'running',
|
|
94
|
-
runtime: { pid: 12345 },
|
|
95
|
-
};
|
|
96
|
-
const { reapable } = selectReapableJobs([job], Date.now(), { pidAlive: () => false, grace: 5 * MIN_MS });
|
|
97
|
-
assert.ok(reapable.some((r) => r.slug === 'dead-running-row'), 'a running row with a dead pid must be reapable');
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test('investigating: a stranded investigation (stale, no live pid) is found by findStrandedInvestigations', () => {
|
|
101
|
-
assert.ok(JOB_STATUSES.includes('investigating'));
|
|
102
|
-
const job = {
|
|
103
|
-
slug: 'stranded-investigation',
|
|
104
|
-
cwd: '/home/user/project',
|
|
105
|
-
status: 'investigating',
|
|
106
|
-
statusHistory: [{ to: 'investigating', from: 'failed', at: new Date(Date.now() - (INVESTIGATION_MAX_MS + 5 * MIN_MS)).toISOString() }],
|
|
107
|
-
};
|
|
108
|
-
const found = findStrandedInvestigations([job], Date.now(), INVESTIGATION_MAX_MS, () => false);
|
|
109
|
-
assert.ok(found.some((f) => f.slug === 'stranded-investigation'), 'a stale investigating row with no live pid must be found');
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test('failed: a stale failed row under its auto-reset cap is selected by selectFailedAutoResetTargets', () => {
|
|
113
|
-
assert.ok(JOB_STATUSES.includes('failed'));
|
|
114
|
-
const job = {
|
|
115
|
-
slug: 'stale-failed-row',
|
|
116
|
-
cwd: '/home/user/project',
|
|
117
|
-
status: 'failed',
|
|
118
|
-
failedAutoResetAttempts: FAILED_AUTORESET_CAP - 1,
|
|
119
|
-
statusHistory: [{ to: 'failed', at: new Date(Date.now() - 60 * MIN_MS).toISOString() }],
|
|
120
|
-
};
|
|
121
|
-
const found = selectFailedAutoResetTargets([job], Date.now(), 10 * MIN_MS);
|
|
122
|
-
assert.ok(found.some((f) => f.slug === 'stale-failed-row'), 'a stale failed row under the cap must be auto-reset-selectable');
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test('needs_review: an exhausted, stale needs_review row is selected by selectExhaustedNeedsReviewTargets', () => {
|
|
126
|
-
assert.ok(JOB_STATUSES.includes('needs_review'));
|
|
127
|
-
const job = {
|
|
128
|
-
slug: 'exhausted-needs-review-row',
|
|
129
|
-
cwd: '/home/user/project',
|
|
130
|
-
status: 'needs_review',
|
|
131
|
-
autoFixAttempted: true,
|
|
132
|
-
autoFixOutcome: 'no-plan',
|
|
133
|
-
autoFixRetries: 1,
|
|
134
|
-
exhaustedResolveAttempts: NEEDS_REVIEW_RESOLVE_CAP,
|
|
135
|
-
statusHistory: [{ to: 'needs_review', at: new Date(Date.now() - 60 * MIN_MS).toISOString() }],
|
|
136
|
-
};
|
|
137
|
-
const found = selectExhaustedNeedsReviewTargets([job], Date.now(), 30 * MIN_MS);
|
|
138
|
-
assert.ok(found.some((f) => f.slug === 'exhausted-needs-review-row'), 'an exhausted, stale needs_review row must be auto-resolve-selectable');
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
test('quarantined: a stale quarantined row under its resolve cap is selected by selectQuarantineAutoResolveTargets', () => {
|
|
142
|
-
assert.ok(JOB_STATUSES.includes('quarantined'));
|
|
143
|
-
const job = {
|
|
144
|
-
slug: 'stale-quarantined-row',
|
|
145
|
-
cwd: '/home/user/project',
|
|
146
|
-
status: 'quarantined',
|
|
147
|
-
quarantineResolveAttempts: QUARANTINE_RESOLVE_CAP - 1,
|
|
148
|
-
statusHistory: [{ to: 'quarantined', at: new Date(Date.now() - 60 * MIN_MS).toISOString() }],
|
|
149
|
-
};
|
|
150
|
-
const found = selectQuarantineAutoResolveTargets([job], Date.now(), 30 * MIN_MS);
|
|
151
|
-
assert.ok(found.some((f) => f.slug === 'stale-quarantined-row'), 'a stale quarantined row under the cap must be auto-resolve-selectable');
|
|
152
|
-
});
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-no-orphan-run-dir.test.cjs — PRD 1120: pickRunDir() must not
|
|
3
|
-
* mkdir a run directory until a dispatch actually commits (executeJob's
|
|
4
|
-
* first write). A dispatch that aborts inside spawnJob before that point —
|
|
5
|
-
* e.g. sessionSlots.acquire() returning null, the earliest exit in spawnJob
|
|
6
|
-
* — must leave RUNS_DIR untouched.
|
|
7
|
-
*
|
|
8
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/scheduler-no-orphan-run-dir.test.cjs
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
|
|
14
|
-
const fs = require('node:fs');
|
|
15
|
-
const os = require('node:os');
|
|
16
|
-
const path = require('node:path');
|
|
17
|
-
|
|
18
|
-
let tmpHome;
|
|
19
|
-
let originalHome;
|
|
20
|
-
let originalSlots;
|
|
21
|
-
let scheduler;
|
|
22
|
-
let sessionSlots;
|
|
23
|
-
|
|
24
|
-
beforeAll(() => {
|
|
25
|
-
originalHome = process.env.HOME;
|
|
26
|
-
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-no-orphan-rundir-'));
|
|
27
|
-
process.env.HOME = tmpHome;
|
|
28
|
-
originalSlots = process.env.SM_SESSION_SLOTS;
|
|
29
|
-
scheduler = require('../scheduler.cjs');
|
|
30
|
-
sessionSlots = require('../lib/sessionSlots.cjs');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
afterAll(() => {
|
|
34
|
-
process.env.HOME = originalHome;
|
|
35
|
-
if (originalSlots === undefined) delete process.env.SM_SESSION_SLOTS;
|
|
36
|
-
else process.env.SM_SESSION_SLOTS = originalSlots;
|
|
37
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
afterEach(() => {
|
|
41
|
-
sessionSlots.__resetForTests();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
function runsDirEntryCount() {
|
|
45
|
-
const runsDir = path.join(tmpHome, '.claude', 'session-manager', 'scheduled-plans', 'runs');
|
|
46
|
-
try {
|
|
47
|
-
return fs.readdirSync(runsDir).length;
|
|
48
|
-
} catch {
|
|
49
|
-
return 0;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
test('pickRunDir() allocates a runId/dir pair without creating the directory', () => {
|
|
54
|
-
const before = runsDirEntryCount();
|
|
55
|
-
const { runId, dir } = scheduler.pickRunDir();
|
|
56
|
-
expect(runId).toBeTruthy();
|
|
57
|
-
expect(fs.existsSync(dir)).toBe(false);
|
|
58
|
-
expect(runsDirEntryCount()).toBe(before);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('a dispatch that bails at slot-acquisition (earliest spawnJob exit) leaves no directory under RUNS_DIR', async () => {
|
|
62
|
-
// Force sessionSlots.acquire() to return null immediately — no slots at all.
|
|
63
|
-
process.env.SM_SESSION_SLOTS = '0';
|
|
64
|
-
const before = runsDirEntryCount();
|
|
65
|
-
|
|
66
|
-
const slug = `1120-slot-miss-${process.pid}-${Math.floor(Math.random() * 1e6)}`;
|
|
67
|
-
const projectCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-no-orphan-rundir-project-'));
|
|
68
|
-
try {
|
|
69
|
-
await scheduler.spawnJob({ slug, cwd: projectCwd }, `run-${slug}`, path.join(
|
|
70
|
-
tmpHome, '.claude', 'session-manager', 'scheduled-plans', 'runs', `run-${slug}`
|
|
71
|
-
), projectCwd);
|
|
72
|
-
|
|
73
|
-
expect(runsDirEntryCount()).toBe(before);
|
|
74
|
-
expect(fs.existsSync(path.join(
|
|
75
|
-
tmpHome, '.claude', 'session-manager', 'scheduled-plans', 'runs', `run-${slug}`
|
|
76
|
-
))).toBe(false);
|
|
77
|
-
} finally {
|
|
78
|
-
delete process.env.SM_SESSION_SLOTS;
|
|
79
|
-
fs.rmSync(projectCwd, { recursive: true, force: true });
|
|
80
|
-
}
|
|
81
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-notify-originating-tab-transcript.test.cjs — unit tests for the
|
|
3
|
-
* PRD 863 addition to notifyOriginatingTab: persisting the job's real
|
|
4
|
-
* result text (read from the run's log) to the durable per-Epic transcript
|
|
5
|
-
* store, independent of the existing short-status-chip notification.
|
|
6
|
-
*
|
|
7
|
-
* Run: timeout 300 npx vitest run src/main/__tests__/scheduler-notify-originating-tab-transcript.test.cjs
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
'use strict';
|
|
11
|
-
|
|
12
|
-
import { test, expect, vi } from 'vitest';
|
|
13
|
-
const { notifyOriginatingTab, extractResultTextFromLog } = require('../scheduler.cjs');
|
|
14
|
-
|
|
15
|
-
test('extractResultTextFromLog returns null for a missing log path', () => {
|
|
16
|
-
expect(extractResultTextFromLog(null)).toBeNull();
|
|
17
|
-
expect(extractResultTextFromLog('/does/not/exist.log')).toBeNull();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('appends the job result text to the transcript store when sourcePromptId is known', async () => {
|
|
21
|
-
const appendTranscriptTurn = vi.fn(async () => true);
|
|
22
|
-
const readResultFromLog = vi.fn(() => 'the real agent result text');
|
|
23
|
-
const appendResponseEvent = vi.fn(async () => true);
|
|
24
|
-
const parsePrdRaw = vi.fn(async () => ({ sourcePromptId: 'psess-abc' }));
|
|
25
|
-
|
|
26
|
-
await notifyOriginatingTab(
|
|
27
|
-
{ slug: '863-transcript', status: 'completed', cwd: '/some/cwd', runId: 'run-1' },
|
|
28
|
-
{ parsePrdRaw, appendResponseEvent, appendTranscriptTurn, readResultFromLog },
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
expect(appendTranscriptTurn).toHaveBeenCalledTimes(1);
|
|
32
|
-
expect(appendTranscriptTurn).toHaveBeenCalledWith('/some/cwd', 'psess-abc', {
|
|
33
|
-
role: 'assistant',
|
|
34
|
-
text: 'the real agent result text',
|
|
35
|
-
eventId: 'prd-result:863-transcript:run-1',
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('falls back to the short status message when the run log has no result text', async () => {
|
|
40
|
-
const appendTranscriptTurn = vi.fn(async () => true);
|
|
41
|
-
const readResultFromLog = vi.fn(() => null);
|
|
42
|
-
const appendResponseEvent = vi.fn(async () => true);
|
|
43
|
-
const parsePrdRaw = vi.fn(async () => ({ sourcePromptId: 'psess-abc' }));
|
|
44
|
-
|
|
45
|
-
await notifyOriginatingTab(
|
|
46
|
-
{ slug: '863-fallback', status: 'completed', cwd: '/some/cwd', runId: 'run-1' },
|
|
47
|
-
{ parsePrdRaw, appendResponseEvent, appendTranscriptTurn, readResultFromLog },
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
expect(appendTranscriptTurn).toHaveBeenCalledWith(
|
|
51
|
-
'/some/cwd',
|
|
52
|
-
'psess-abc',
|
|
53
|
-
expect.objectContaining({ text: expect.stringContaining('863-fallback') }),
|
|
54
|
-
);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test('a throwing transcript append never breaks the existing notification path', async () => {
|
|
58
|
-
const appendTranscriptTurn = vi.fn(async () => {
|
|
59
|
-
throw new Error('disk full');
|
|
60
|
-
});
|
|
61
|
-
const readResultFromLog = vi.fn(() => 'result text');
|
|
62
|
-
const appendResponseEvent = vi.fn(async () => true);
|
|
63
|
-
const parsePrdRaw = vi.fn(async () => ({ sourcePromptId: 'psess-abc' }));
|
|
64
|
-
|
|
65
|
-
await expect(
|
|
66
|
-
notifyOriginatingTab(
|
|
67
|
-
{ slug: '863-safe', status: 'completed', cwd: '/some/cwd', runId: 'run-1' },
|
|
68
|
-
{ parsePrdRaw, appendResponseEvent, appendTranscriptTurn, readResultFromLog },
|
|
69
|
-
),
|
|
70
|
-
).resolves.toBeUndefined();
|
|
71
|
-
|
|
72
|
-
expect(appendResponseEvent).toHaveBeenCalledTimes(1);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('no cwd on the job skips the transcript append but does not throw', async () => {
|
|
76
|
-
const appendTranscriptTurn = vi.fn(async () => true);
|
|
77
|
-
const readResultFromLog = vi.fn(() => 'result text');
|
|
78
|
-
const appendResponseEvent = vi.fn(async () => true);
|
|
79
|
-
const parsePrdRaw = vi.fn(async () => ({ sourcePromptId: 'psess-abc' }));
|
|
80
|
-
|
|
81
|
-
await notifyOriginatingTab(
|
|
82
|
-
{ slug: '863-nocwd', status: 'completed', cwd: null, runId: 'run-1' },
|
|
83
|
-
{ parsePrdRaw, appendResponseEvent, appendTranscriptTurn, readResultFromLog },
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
expect(appendTranscriptTurn).not.toHaveBeenCalled();
|
|
87
|
-
});
|