claude-code-session-manager 0.97.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-D93FoaOm.js → DataModel-HdR0AxFq.js} +1 -1
- package/dist/assets/{History-CXxxqNP1.js → History-Dr4Jr_5z.js} +2 -2
- package/dist/assets/{Hooks-CzeYFQjq.js → Hooks-NhrvH3JP.js} +3 -3
- package/dist/assets/{Library-D2zPkwOC.js → Library-Dv_EtIMr.js} +1 -1
- package/dist/assets/{MarkdownEditor-DbinP78A.js → MarkdownEditor-DTKDWV_n.js} +1 -1
- package/dist/assets/{McpServers-Bu_sVGLr.js → McpServers-M034G9B3.js} +2 -2
- package/dist/assets/{Memory-BgiI6LZ_.js → Memory-DzF1B4gx.js} +6 -6
- package/dist/assets/{Permissions-C1MMzZRm.js → Permissions-DrgbSGWl.js} +3 -3
- package/dist/assets/{Plugins-Dhu6wAZi.js → Plugins-Bd3ef35w.js} +2 -2
- package/dist/assets/{ProvenanceBadge-C3AcWKMG.js → ProvenanceBadge-DcBHT1Iy.js} +1 -1
- package/dist/assets/{SaveBar-plwYm0iO.js → SaveBar-rimJem-Y.js} +1 -1
- package/dist/assets/Scheduler-DjgFJl2w.js +16 -0
- package/dist/assets/{ScopeSwitcher-DFy0vv_o.js → ScopeSwitcher-CnAzTBrl.js} +1 -1
- package/dist/assets/Settings-Dc1F_sSg.js +3 -0
- package/dist/assets/{SkillReferenceGraph-DsI7hRPB.js → SkillReferenceGraph-B9aZDecM.js} +1 -1
- package/dist/assets/{Skills-3E748UfB.js → Skills-DRXd18gu.js} +2 -2
- package/dist/assets/{SystemPrompt-BqmfUJOd.js → SystemPrompt-ahy5-Fwe.js} +1 -1
- package/dist/assets/{TagLibrary-CPz6fO8Q.js → TagLibrary-C_tToDeL.js} +1 -1
- package/dist/assets/{TiptapBody-D9EoBQ1P.js → TiptapBody-DvdefS6K.js} +1 -1
- package/dist/assets/{Toggle-BHAmZNDn.js → Toggle-6Jl5Njc6.js} +1 -1
- package/dist/assets/{index-CKH5Uxik.css → index-Bta-hwud.css} +1 -1
- package/dist/assets/{index-tn5JIVPj.js → index-vx8O73l8.js} +497 -502
- package/dist/assets/{settingsSchema-Crqy_aNz.js → settingsSchema-D6iRguNV.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +26 -29
- package/plugins/CLAUDE.md +6 -6
- package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +23 -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 +153 -19
- 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 +33 -30
- package/src/main/lib/workTypeLibrary.cjs +7 -1
- package/src/main/promptSessionEvents.cjs +37 -13
- package/src/main/queueOps.cjs +17 -6
- package/src/main/scheduler.cjs +975 -203
- 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-nESrTRIg.js +0 -1
- package/dist/assets/Scheduler-BVYTeh39.js +0 -16
- package/dist/assets/Settings-DIhGgdfs.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__/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 -154
- 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-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 -375
- package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +0 -266
- package/src/main/lib/kgExchangePairing.cjs +0 -75
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* prdSetDisposition.test.cjs — scheduler wave-disposition PRD:
|
|
3
|
-
* scheduler.remote.setPrdDisposition (backing the renderer's
|
|
4
|
-
* `schedule:set-prd-disposition` IPC action) is how a human changes an
|
|
5
|
-
* already-written PRD's disposition from the Scheduler UI — promoting an
|
|
6
|
-
* appended wave to its own head, or re-attaching a head behind another
|
|
7
|
-
* chain. Validates via prdDisposition.cjs's computeDispositionRewrite
|
|
8
|
-
* (cycle-safety, running/completed rows untouched) before delegating the
|
|
9
|
-
* actual write to the SAME remote.updatePrd every other PRD edit path uses.
|
|
10
|
-
*
|
|
11
|
-
* Mirrors prdUpdateDependsOn.test.cjs's HOME-isolation fixture.
|
|
12
|
-
*
|
|
13
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/prdSetDisposition.test.cjs
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
'use strict';
|
|
17
|
-
|
|
18
|
-
import { test, expect, beforeAll, afterAll } from 'vitest';
|
|
19
|
-
const fs = require('node:fs');
|
|
20
|
-
const os = require('node:os');
|
|
21
|
-
const path = require('node:path');
|
|
22
|
-
|
|
23
|
-
let tmpHome;
|
|
24
|
-
let originalHome;
|
|
25
|
-
let scheduler;
|
|
26
|
-
let queueStore;
|
|
27
|
-
let config;
|
|
28
|
-
|
|
29
|
-
beforeAll(() => {
|
|
30
|
-
originalHome = process.env.HOME;
|
|
31
|
-
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-set-disposition-home-'));
|
|
32
|
-
process.env.HOME = tmpHome;
|
|
33
|
-
|
|
34
|
-
scheduler = require('../scheduler.cjs');
|
|
35
|
-
queueStore = require('../lib/queueStore.cjs');
|
|
36
|
-
config = require('../config.cjs');
|
|
37
|
-
|
|
38
|
-
if (!scheduler.PRDS_DIR.startsWith(tmpHome)) {
|
|
39
|
-
throw new Error(`refusing to run: PRDS_DIR (${scheduler.PRDS_DIR}) is not under the temp HOME (${tmpHome})`);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
afterAll(() => {
|
|
44
|
-
process.env.HOME = originalHome;
|
|
45
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
function registerActiveProject(cwd) {
|
|
49
|
-
const projectsDir = path.join(tmpHome, '.claude', 'projects');
|
|
50
|
-
const slugDir = path.join(projectsDir, `fake-project-slug-${path.basename(cwd)}`);
|
|
51
|
-
fs.mkdirSync(slugDir, { recursive: true });
|
|
52
|
-
fs.writeFileSync(path.join(slugDir, 'transcript.jsonl'), JSON.stringify({ cwd }) + '\n');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function makeFixtureProject(prefix) {
|
|
56
|
-
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
57
|
-
registerActiveProject(cwd);
|
|
58
|
-
config.addAllowedRoot(cwd);
|
|
59
|
-
const opsRoot = path.join(cwd, 'session-manager-operations');
|
|
60
|
-
const prdsDir = path.join(opsRoot, 'scheduler', 'epics', 'test-epic-1', 'prds');
|
|
61
|
-
const stateDir = path.join(opsRoot, 'scheduler', 'state');
|
|
62
|
-
fs.mkdirSync(prdsDir, { recursive: true });
|
|
63
|
-
fs.mkdirSync(stateDir, { recursive: true });
|
|
64
|
-
fs.writeFileSync(path.join(stateDir, 'queue.json'), JSON.stringify({ jobs: [] }, null, 2), 'utf8');
|
|
65
|
-
queueStore.bustCwdCache();
|
|
66
|
-
return { cwd, prdsDir, stateDir };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function writePrd(prdsDir, filename, cwd, extraFrontmatter = '') {
|
|
70
|
-
fs.writeFileSync(
|
|
71
|
-
path.join(prdsDir, filename),
|
|
72
|
-
`---\ntitle: ${filename}\ncwd: ${cwd}\nestimateMinutes: 10\ncreatedVia: scheduler-api\n${extraFrontmatter}---\n\n# Goal\nDo the thing.\n`,
|
|
73
|
-
'utf8',
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Seeds a queue.json row for `slug` with the given status — setPrdDisposition
|
|
78
|
-
* (like updatePrd) reads job status off the live queue, not the PRD file. */
|
|
79
|
-
function seedQueueJob(stateDir, slug, status) {
|
|
80
|
-
fs.writeFileSync(
|
|
81
|
-
path.join(stateDir, 'queue.json'),
|
|
82
|
-
JSON.stringify({ jobs: [{ slug, status, title: slug, cwd: '' }] }, null, 2),
|
|
83
|
-
'utf8',
|
|
84
|
-
);
|
|
85
|
-
queueStore.bustCwdCache();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
test('append sets the expected edges', async () => {
|
|
89
|
-
const { cwd, prdsDir } = makeFixtureProject('sm-set-disposition-append-');
|
|
90
|
-
try {
|
|
91
|
-
writePrd(prdsDir, '3-wave1-tail.md', cwd);
|
|
92
|
-
writePrd(prdsDir, '4-wave2-root.md', cwd);
|
|
93
|
-
|
|
94
|
-
const result = await scheduler.remote.setPrdDisposition({
|
|
95
|
-
slug: '4-wave2-root',
|
|
96
|
-
cwd,
|
|
97
|
-
disposition: 'append',
|
|
98
|
-
dependsOn: ['3-wave1-tail'],
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
expect(result.ok).toBe(true);
|
|
102
|
-
const written = fs.readFileSync(path.join(prdsDir, '4-wave2-root.md'), 'utf8');
|
|
103
|
-
expect(written).toMatch(/^dependsOn: \[3-wave1-tail\]$/m);
|
|
104
|
-
expect(written).toMatch(/^disposition: append$/m);
|
|
105
|
-
} finally {
|
|
106
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('new-head sets none', async () => {
|
|
111
|
-
const { cwd, prdsDir } = makeFixtureProject('sm-set-disposition-new-head-');
|
|
112
|
-
try {
|
|
113
|
-
writePrd(prdsDir, '3-wave1-tail.md', cwd);
|
|
114
|
-
writePrd(prdsDir, '4-wave2-root.md', cwd, 'dependsOn: [wave1-tail]\ndisposition: append\n');
|
|
115
|
-
|
|
116
|
-
const result = await scheduler.remote.setPrdDisposition({
|
|
117
|
-
slug: '4-wave2-root',
|
|
118
|
-
cwd,
|
|
119
|
-
disposition: 'new-head',
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
expect(result.ok).toBe(true);
|
|
123
|
-
const written = fs.readFileSync(path.join(prdsDir, '4-wave2-root.md'), 'utf8');
|
|
124
|
-
expect(written).not.toContain('dependsOn');
|
|
125
|
-
expect(written).toMatch(/^disposition: new-head$/m);
|
|
126
|
-
} finally {
|
|
127
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
test('promoting a wave to a head removes exactly its root edges', async () => {
|
|
132
|
-
const { cwd, prdsDir } = makeFixtureProject('sm-set-disposition-promote-');
|
|
133
|
-
try {
|
|
134
|
-
writePrd(prdsDir, '3-wave1-tail.md', cwd);
|
|
135
|
-
writePrd(prdsDir, '5-other-head.md', cwd);
|
|
136
|
-
writePrd(prdsDir, '4-wave2-root.md', cwd, 'dependsOn: [wave1-tail]\ndisposition: append\n');
|
|
137
|
-
|
|
138
|
-
const result = await scheduler.remote.setPrdDisposition({
|
|
139
|
-
slug: '4-wave2-root',
|
|
140
|
-
cwd,
|
|
141
|
-
disposition: 'new-head',
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
expect(result.ok).toBe(true);
|
|
145
|
-
const promoted = fs.readFileSync(path.join(prdsDir, '4-wave2-root.md'), 'utf8');
|
|
146
|
-
expect(promoted).not.toContain('dependsOn');
|
|
147
|
-
// The unrelated sibling head is untouched by this call.
|
|
148
|
-
const other = fs.readFileSync(path.join(prdsDir, '5-other-head.md'), 'utf8');
|
|
149
|
-
expect(other).not.toContain('dependsOn');
|
|
150
|
-
} finally {
|
|
151
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
test('a change that would create a cycle is rejected, and nothing is written', async () => {
|
|
156
|
-
const { cwd, prdsDir } = makeFixtureProject('sm-set-disposition-cycle-');
|
|
157
|
-
try {
|
|
158
|
-
writePrd(prdsDir, '3-a.md', cwd, 'dependsOn: [b]\n');
|
|
159
|
-
writePrd(prdsDir, '4-b.md', cwd);
|
|
160
|
-
const before = fs.readFileSync(path.join(prdsDir, '4-b.md'), 'utf8');
|
|
161
|
-
|
|
162
|
-
const result = await scheduler.remote.setPrdDisposition({
|
|
163
|
-
slug: '4-b',
|
|
164
|
-
cwd,
|
|
165
|
-
disposition: 'append',
|
|
166
|
-
dependsOn: ['3-a'],
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
expect(result.ok).toBe(false);
|
|
170
|
-
expect(result.error).toMatch(/cycle/i);
|
|
171
|
-
const after = fs.readFileSync(path.join(prdsDir, '4-b.md'), 'utf8');
|
|
172
|
-
expect(after).toBe(before);
|
|
173
|
-
} finally {
|
|
174
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test('running rows are untouched', async () => {
|
|
179
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-set-disposition-running-');
|
|
180
|
-
try {
|
|
181
|
-
writePrd(prdsDir, '3-wave1-tail.md', cwd);
|
|
182
|
-
writePrd(prdsDir, '4-wave2-root.md', cwd, 'dependsOn: [wave1-tail]\ndisposition: append\n');
|
|
183
|
-
seedQueueJob(stateDir, '4-wave2-root', 'running');
|
|
184
|
-
const before = fs.readFileSync(path.join(prdsDir, '4-wave2-root.md'), 'utf8');
|
|
185
|
-
|
|
186
|
-
const result = await scheduler.remote.setPrdDisposition({
|
|
187
|
-
slug: '4-wave2-root',
|
|
188
|
-
cwd,
|
|
189
|
-
disposition: 'new-head',
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
expect(result.ok).toBe(false);
|
|
193
|
-
expect(result.error).toMatch(/running/i);
|
|
194
|
-
const after = fs.readFileSync(path.join(prdsDir, '4-wave2-root.md'), 'utf8');
|
|
195
|
-
expect(after).toBe(before);
|
|
196
|
-
} finally {
|
|
197
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
test('completed rows are untouched', async () => {
|
|
202
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-set-disposition-completed-');
|
|
203
|
-
try {
|
|
204
|
-
writePrd(prdsDir, '3-wave1-tail.md', cwd);
|
|
205
|
-
writePrd(prdsDir, '4-wave2-root.md', cwd, 'dependsOn: [wave1-tail]\ndisposition: append\n');
|
|
206
|
-
seedQueueJob(stateDir, '4-wave2-root', 'completed');
|
|
207
|
-
const before = fs.readFileSync(path.join(prdsDir, '4-wave2-root.md'), 'utf8');
|
|
208
|
-
|
|
209
|
-
const result = await scheduler.remote.setPrdDisposition({
|
|
210
|
-
slug: '4-wave2-root',
|
|
211
|
-
cwd,
|
|
212
|
-
disposition: 'new-head',
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
expect(result.ok).toBe(false);
|
|
216
|
-
expect(result.error).toMatch(/completed/i);
|
|
217
|
-
const after = fs.readFileSync(path.join(prdsDir, '4-wave2-root.md'), 'utf8');
|
|
218
|
-
expect(after).toBe(before);
|
|
219
|
-
} finally {
|
|
220
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
221
|
-
}
|
|
222
|
-
});
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* prdSizing.test.cjs — unit tests for sizingWarnings (PRD 1403).
|
|
3
|
-
*
|
|
4
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/prdSizing.test.cjs
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
'use strict';
|
|
8
|
-
|
|
9
|
-
import { test, expect } from 'vitest';
|
|
10
|
-
const { SIZING_LIMITS, sizingWarnings } = require('../lib/prdSizing.cjs');
|
|
11
|
-
|
|
12
|
-
function compliantInput(overrides = {}) {
|
|
13
|
-
return {
|
|
14
|
-
estimateMinutes: 10,
|
|
15
|
-
acceptanceCriteria: ['widget frobnicates on click', 'unit test covers the frobnication path'],
|
|
16
|
-
goal: 'Add frobnication to the widget subsystem.',
|
|
17
|
-
implementationNotes: 'See src/widget.cjs:10.',
|
|
18
|
-
...overrides,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
test('compliant PRD yields no warnings', () => {
|
|
23
|
-
expect(sizingWarnings(compliantInput())).toEqual([]);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('warns when estimateMinutes exceeds the limit', () => {
|
|
27
|
-
const warnings = sizingWarnings(compliantInput({ estimateMinutes: SIZING_LIMITS.estimateMinutes + 1 }));
|
|
28
|
-
expect(warnings.some((w) => /estimateMinutes/.test(w))).toBe(true);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('does not warn when estimateMinutes is exactly the limit', () => {
|
|
32
|
-
const warnings = sizingWarnings(compliantInput({ estimateMinutes: SIZING_LIMITS.estimateMinutes }));
|
|
33
|
-
expect(warnings.some((w) => /estimateMinutes/.test(w))).toBe(false);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('warns when acceptanceCriteria has more than the limit of lines', () => {
|
|
37
|
-
const acceptanceCriteria = Array.from({ length: SIZING_LIMITS.acLines + 1 }, (_, i) => `criterion ${i}`);
|
|
38
|
-
const warnings = sizingWarnings(compliantInput({ acceptanceCriteria }));
|
|
39
|
-
expect(warnings.some((w) => /acceptanceCriteria has/.test(w))).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('does not warn when acceptanceCriteria has exactly the limit of lines', () => {
|
|
43
|
-
const acceptanceCriteria = Array.from({ length: SIZING_LIMITS.acLines }, (_, i) => `criterion ${i}`);
|
|
44
|
-
const warnings = sizingWarnings(compliantInput({ acceptanceCriteria }));
|
|
45
|
-
expect(warnings.some((w) => /acceptanceCriteria has/.test(w))).toBe(false);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('warns when an AC line exceeds the per-line character limit', () => {
|
|
49
|
-
const longLine = 'x'.repeat(SIZING_LIMITS.acLineChars + 1);
|
|
50
|
-
const warnings = sizingWarnings(compliantInput({ acceptanceCriteria: [longLine] }));
|
|
51
|
-
expect(warnings.some((w) => /exceed \d+ characters/.test(w))).toBe(true);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('does not warn when an AC line is exactly at the per-line character limit', () => {
|
|
55
|
-
const line = 'x'.repeat(SIZING_LIMITS.acLineChars);
|
|
56
|
-
const warnings = sizingWarnings(compliantInput({ acceptanceCriteria: [line] }));
|
|
57
|
-
expect(warnings.some((w) => /exceed \d+ characters/.test(w))).toBe(false);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('warns on an open-ended search-and-fix AC line', () => {
|
|
61
|
-
const warnings = sizingWarnings(compliantInput({
|
|
62
|
-
acceptanceCriteria: ['grep e2e specs and update expectations to match the new sort order'],
|
|
63
|
-
}));
|
|
64
|
-
expect(warnings.some((w) => /open-ended search-and-fix/.test(w))).toBe(true);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('does not warn on an AC line that merely mentions grep or update in isolation', () => {
|
|
68
|
-
const warnings = sizingWarnings(compliantInput({
|
|
69
|
-
acceptanceCriteria: ['grep confirms no leftover references to the old flag'],
|
|
70
|
-
}));
|
|
71
|
-
expect(warnings.some((w) => /open-ended search-and-fix/.test(w))).toBe(false);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('warns on an open-ended search-and-fix AC line whose "then"/"update" half is a second sentence', () => {
|
|
75
|
-
const warnings = sizingWarnings(compliantInput({
|
|
76
|
-
acceptanceCriteria: ['Grep the repo for every usage of the old flag. Then update each call site.'],
|
|
77
|
-
}));
|
|
78
|
-
expect(warnings.some((w) => /open-ended search-and-fix/.test(w))).toBe(true);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('warns on an AC line with two or more timeout commands', () => {
|
|
82
|
-
const warnings = sizingWarnings(compliantInput({
|
|
83
|
-
acceptanceCriteria: ['timeout 120 npm run typecheck && timeout 300 npm run test:unit both pass'],
|
|
84
|
-
}));
|
|
85
|
-
expect(warnings.some((w) => /two or more `timeout/.test(w))).toBe(true);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test('does not warn on an AC line with a single timeout command', () => {
|
|
89
|
-
const warnings = sizingWarnings(compliantInput({
|
|
90
|
-
acceptanceCriteria: ['timeout 120 npm run typecheck passes'],
|
|
91
|
-
}));
|
|
92
|
-
expect(warnings.some((w) => /two or more `timeout/.test(w))).toBe(false);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
test('warns when goal + implementationNotes + joined AC exceeds the body character limit', () => {
|
|
96
|
-
const warnings = sizingWarnings(compliantInput({
|
|
97
|
-
goal: 'g'.repeat(SIZING_LIMITS.bodyChars + 1),
|
|
98
|
-
}));
|
|
99
|
-
expect(warnings.some((w) => /exceeding the \d+-character sizing limit/.test(w))).toBe(true);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test('does not warn when the combined body is exactly at the character limit', () => {
|
|
103
|
-
const goal = 'g'.repeat(SIZING_LIMITS.bodyChars);
|
|
104
|
-
const warnings = sizingWarnings({ estimateMinutes: 10, acceptanceCriteria: [], goal, implementationNotes: '' });
|
|
105
|
-
expect(warnings.some((w) => /exceeding the \d+-character sizing limit/.test(w))).toBe(false);
|
|
106
|
-
});
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* prdSourcePromptIdBackfill.test.cjs — PRD 830: a PRD file's location under
|
|
3
|
-
* `.../scheduler/epics/<epicId>/prds/<slug>.md` already IS its Epic
|
|
4
|
-
* membership, so ingest should stamp `sourcePromptId = <epicId>` whenever
|
|
5
|
-
* frontmatter doesn't supply one — instead of leaving it null forever.
|
|
6
|
-
*
|
|
7
|
-
* Covers:
|
|
8
|
-
* - deriveEpicIdFromPrdPath: pure path-shape extraction (prdLocations.cjs)
|
|
9
|
-
* - parsePrdRaw: dir-derived stamping + frontmatter-wins precedence
|
|
10
|
-
* - reconcileSourcePromptId: pending-only backfill (scheduler.cjs)
|
|
11
|
-
*
|
|
12
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/prdSourcePromptIdBackfill.test.cjs
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
'use strict';
|
|
16
|
-
|
|
17
|
-
import { test, expect } from 'vitest';
|
|
18
|
-
const fsp = require('node:fs/promises');
|
|
19
|
-
const os = require('node:os');
|
|
20
|
-
const path = require('node:path');
|
|
21
|
-
|
|
22
|
-
const { deriveEpicIdFromPrdPath, resolveEpicPrdWriteDir } = require('../lib/prdLocations.cjs');
|
|
23
|
-
const { parsePrdRaw, _resetCache } = require('../scheduler/prdParser.cjs');
|
|
24
|
-
const { reconcileSourcePromptId } = require('../scheduler.cjs');
|
|
25
|
-
|
|
26
|
-
async function mkProjectCwd() {
|
|
27
|
-
return fsp.mkdtemp(path.join(os.tmpdir(), 'sm-prd-backfill-'));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// ---------- deriveEpicIdFromPrdPath ----------
|
|
31
|
-
|
|
32
|
-
test('deriveEpicIdFromPrdPath extracts the epic id from a well-formed epic PRD path', async () => {
|
|
33
|
-
const cwd = await mkProjectCwd();
|
|
34
|
-
const epicId = 'some-epic-abc123';
|
|
35
|
-
const dir = resolveEpicPrdWriteDir(cwd, epicId);
|
|
36
|
-
await fsp.mkdir(dir, { recursive: true });
|
|
37
|
-
const filePath = path.join(dir, '900-example.md');
|
|
38
|
-
expect(deriveEpicIdFromPrdPath(filePath)).toBe(epicId);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('deriveEpicIdFromPrdPath returns null for the retired flat prds/ layout', () => {
|
|
42
|
-
const filePath = '/home/user/Projects/foo/session-manager-operations/scheduler/prds/900-example.md';
|
|
43
|
-
expect(deriveEpicIdFromPrdPath(filePath)).toBe(null);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test('deriveEpicIdFromPrdPath returns null for an unrelated path', () => {
|
|
47
|
-
expect(deriveEpicIdFromPrdPath('/tmp/whatever/900-example.md')).toBe(null);
|
|
48
|
-
expect(deriveEpicIdFromPrdPath(null)).toBe(null);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// ---------- parsePrdRaw: dir-derived stamping + frontmatter-wins ----------
|
|
52
|
-
|
|
53
|
-
test('parsePrdRaw derives sourcePromptId from the parent epic dir when frontmatter omits it', async () => {
|
|
54
|
-
_resetCache();
|
|
55
|
-
const cwd = await mkProjectCwd();
|
|
56
|
-
const epicId = 'derive-me-epic-def456';
|
|
57
|
-
const dir = resolveEpicPrdWriteDir(cwd, epicId);
|
|
58
|
-
await fsp.mkdir(dir, { recursive: true });
|
|
59
|
-
const filePath = path.join(dir, '901-hand-authored.md');
|
|
60
|
-
await fsp.writeFile(filePath, [
|
|
61
|
-
'---',
|
|
62
|
-
'title: Hand-authored, no sourcePromptId',
|
|
63
|
-
`cwd: ${cwd}`,
|
|
64
|
-
'---',
|
|
65
|
-
'# Goal',
|
|
66
|
-
'',
|
|
67
|
-
'Do the thing.',
|
|
68
|
-
'',
|
|
69
|
-
].join('\n'));
|
|
70
|
-
|
|
71
|
-
const parsed = await parsePrdRaw(filePath);
|
|
72
|
-
expect(parsed.sourcePromptId).toBe(epicId);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('parsePrdRaw: explicit frontmatter sourcePromptId wins over the dir-derived epic id', async () => {
|
|
76
|
-
_resetCache();
|
|
77
|
-
const cwd = await mkProjectCwd();
|
|
78
|
-
const epicId = 'dir-epic-ghi789';
|
|
79
|
-
const dir = resolveEpicPrdWriteDir(cwd, epicId);
|
|
80
|
-
await fsp.mkdir(dir, { recursive: true });
|
|
81
|
-
const filePath = path.join(dir, '902-explicit.md');
|
|
82
|
-
await fsp.writeFile(filePath, [
|
|
83
|
-
'---',
|
|
84
|
-
'title: Explicit sourcePromptId',
|
|
85
|
-
`cwd: ${cwd}`,
|
|
86
|
-
'sourcePromptId: ticket-explicit-999',
|
|
87
|
-
'---',
|
|
88
|
-
'# Goal',
|
|
89
|
-
'',
|
|
90
|
-
'Do the thing.',
|
|
91
|
-
'',
|
|
92
|
-
].join('\n'));
|
|
93
|
-
|
|
94
|
-
const parsed = await parsePrdRaw(filePath);
|
|
95
|
-
expect(parsed.sourcePromptId).toBe('ticket-explicit-999');
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// ---------- reconcileSourcePromptId: pending-only backfill ----------
|
|
99
|
-
|
|
100
|
-
test('reconcileSourcePromptId backfills a pending job whose sourcePromptId is null', () => {
|
|
101
|
-
const job = { slug: 'x', status: 'pending', sourcePromptId: null };
|
|
102
|
-
expect(reconcileSourcePromptId(job, 'epic-abc')).toBe('epic-abc');
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test('reconcileSourcePromptId leaves a running job untouched even if its sourcePromptId is null', () => {
|
|
106
|
-
const job = { slug: 'x', status: 'running', sourcePromptId: null };
|
|
107
|
-
expect(reconcileSourcePromptId(job, 'epic-abc')).toBe(null);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('reconcileSourcePromptId leaves a completed job untouched even if its sourcePromptId is null', () => {
|
|
111
|
-
const job = { slug: 'x', status: 'completed', sourcePromptId: null };
|
|
112
|
-
expect(reconcileSourcePromptId(job, 'epic-abc')).toBe(null);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('reconcileSourcePromptId keeps a pending job\'s existing value if the fresh parse yields null', () => {
|
|
116
|
-
const job = { slug: 'x', status: 'pending', sourcePromptId: 'already-set' };
|
|
117
|
-
expect(reconcileSourcePromptId(job, null)).toBe('already-set');
|
|
118
|
-
});
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* prdUpdateDependsOn.test.cjs — PRD 1124: scheduler.remote.updatePrd accepts
|
|
3
|
-
* a `dependsOn` array patch, validates it write-time against the SAME
|
|
4
|
-
* resolver (depSlugResolve.cjs) scheduler_create_prd's prdCreate.cjs uses,
|
|
5
|
-
* and accepts an explicit empty array to CLEAR the dependency.
|
|
6
|
-
*
|
|
7
|
-
* Mirrors scheduler-reconcile-quarantine.test.cjs's HOME-isolation fixture.
|
|
8
|
-
*
|
|
9
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/prdUpdateDependsOn.test.cjs
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
'use strict';
|
|
13
|
-
|
|
14
|
-
import { test, expect, beforeAll, afterAll } from 'vitest';
|
|
15
|
-
const fs = require('node:fs');
|
|
16
|
-
const os = require('node:os');
|
|
17
|
-
const path = require('node:path');
|
|
18
|
-
|
|
19
|
-
let tmpHome;
|
|
20
|
-
let originalHome;
|
|
21
|
-
let scheduler;
|
|
22
|
-
let queueStore;
|
|
23
|
-
let config;
|
|
24
|
-
|
|
25
|
-
beforeAll(() => {
|
|
26
|
-
originalHome = process.env.HOME;
|
|
27
|
-
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-update-prd-dependson-home-'));
|
|
28
|
-
process.env.HOME = tmpHome;
|
|
29
|
-
|
|
30
|
-
scheduler = require('../scheduler.cjs');
|
|
31
|
-
queueStore = require('../lib/queueStore.cjs');
|
|
32
|
-
config = require('../config.cjs');
|
|
33
|
-
|
|
34
|
-
if (!scheduler.PRDS_DIR.startsWith(tmpHome)) {
|
|
35
|
-
throw new Error(`refusing to run: PRDS_DIR (${scheduler.PRDS_DIR}) is not under the temp HOME (${tmpHome})`);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
afterAll(() => {
|
|
40
|
-
process.env.HOME = originalHome;
|
|
41
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
function registerActiveProject(cwd) {
|
|
45
|
-
const projectsDir = path.join(tmpHome, '.claude', 'projects');
|
|
46
|
-
const slugDir = path.join(projectsDir, `fake-project-slug-${path.basename(cwd)}`);
|
|
47
|
-
fs.mkdirSync(slugDir, { recursive: true });
|
|
48
|
-
fs.writeFileSync(path.join(slugDir, 'transcript.jsonl'), JSON.stringify({ cwd }) + '\n');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function makeFixtureProject(prefix) {
|
|
52
|
-
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
53
|
-
registerActiveProject(cwd);
|
|
54
|
-
// updatePrd writes through config.writeTextAtomic, which enforces
|
|
55
|
-
// validatePath's allowed-write-root boundary (os.homedir() by default).
|
|
56
|
-
// The live app widens this via pty.cjs's spawn / activeIndexMerge.cjs's
|
|
57
|
-
// boot registration as a side effect of opening the project; a test that
|
|
58
|
-
// never spawns a PTY has to register it explicitly, same as
|
|
59
|
-
// prdCreate.cjs's own createPrd does for a chat-only Epic.
|
|
60
|
-
config.addAllowedRoot(cwd);
|
|
61
|
-
const opsRoot = path.join(cwd, 'session-manager-operations');
|
|
62
|
-
const prdsDir = path.join(opsRoot, 'scheduler', 'epics', 'test-epic-1', 'prds');
|
|
63
|
-
const stateDir = path.join(opsRoot, 'scheduler', 'state');
|
|
64
|
-
fs.mkdirSync(prdsDir, { recursive: true });
|
|
65
|
-
fs.mkdirSync(stateDir, { recursive: true });
|
|
66
|
-
fs.writeFileSync(path.join(stateDir, 'queue.json'), JSON.stringify({ jobs: [] }, null, 2), 'utf8');
|
|
67
|
-
queueStore.bustCwdCache();
|
|
68
|
-
return { cwd, prdsDir, stateDir };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function writePrd(prdsDir, filename, cwd, extraFrontmatter = '') {
|
|
72
|
-
fs.writeFileSync(
|
|
73
|
-
path.join(prdsDir, filename),
|
|
74
|
-
`---\ntitle: ${filename}\ncwd: ${cwd}\nestimateMinutes: 10\ncreatedVia: scheduler-api\n${extraFrontmatter}---\n\n# Goal\nDo the thing.\n`,
|
|
75
|
-
'utf8',
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
test('updatePrd patches dependsOn to a new valid list naming an existing bare slug', async () => {
|
|
80
|
-
const { cwd, prdsDir } = makeFixtureProject('sm-update-dependson-valid-');
|
|
81
|
-
try {
|
|
82
|
-
writePrd(prdsDir, '3-widget-base.md', cwd);
|
|
83
|
-
writePrd(prdsDir, '4-widget-follow-up.md', cwd);
|
|
84
|
-
|
|
85
|
-
const result = await scheduler.remote.updatePrd({
|
|
86
|
-
slug: '4-widget-follow-up',
|
|
87
|
-
cwd,
|
|
88
|
-
frontmatter: { dependsOn: ['widget-base'] },
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
expect(result.ok).toBe(true);
|
|
92
|
-
const written = fs.readFileSync(path.join(prdsDir, '4-widget-follow-up.md'), 'utf8');
|
|
93
|
-
expect(written).toMatch(/^dependsOn: \[widget-base\]$/m);
|
|
94
|
-
} finally {
|
|
95
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test('updatePrd refuses a dependsOn entry that resolves to no existing PRD, with a near-match suggestion, and writes nothing', async () => {
|
|
100
|
-
const { cwd, prdsDir } = makeFixtureProject('sm-update-dependson-invalid-');
|
|
101
|
-
try {
|
|
102
|
-
writePrd(prdsDir, '3-widget-base.md', cwd);
|
|
103
|
-
writePrd(prdsDir, '4-widget-follow-up.md', cwd);
|
|
104
|
-
const before = fs.readFileSync(path.join(prdsDir, '4-widget-follow-up.md'), 'utf8');
|
|
105
|
-
|
|
106
|
-
const result = await scheduler.remote.updatePrd({
|
|
107
|
-
slug: '4-widget-follow-up',
|
|
108
|
-
cwd,
|
|
109
|
-
frontmatter: { dependsOn: ['wigdet-bsae'] },
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
expect(result.ok).toBe(false);
|
|
113
|
-
expect(result.error).toMatch(/does not resolve to any existing PRD/);
|
|
114
|
-
expect(result.error).toMatch(/widget-base/);
|
|
115
|
-
const after = fs.readFileSync(path.join(prdsDir, '4-widget-follow-up.md'), 'utf8');
|
|
116
|
-
expect(after).toBe(before);
|
|
117
|
-
} finally {
|
|
118
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test('updatePrd patches dependsOn to an explicit empty array, clearing a previously-set dependency without validation', async () => {
|
|
123
|
-
const { cwd, prdsDir } = makeFixtureProject('sm-update-dependson-clear-');
|
|
124
|
-
try {
|
|
125
|
-
writePrd(prdsDir, '3-widget-base.md', cwd);
|
|
126
|
-
writePrd(prdsDir, '4-widget-follow-up.md', cwd, 'dependsOn: [widget-base]\n');
|
|
127
|
-
|
|
128
|
-
const result = await scheduler.remote.updatePrd({
|
|
129
|
-
slug: '4-widget-follow-up',
|
|
130
|
-
cwd,
|
|
131
|
-
frontmatter: { dependsOn: [] },
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
expect(result.ok).toBe(true);
|
|
135
|
-
const written = fs.readFileSync(path.join(prdsDir, '4-widget-follow-up.md'), 'utf8');
|
|
136
|
-
expect(written).not.toContain('dependsOn');
|
|
137
|
-
} finally {
|
|
138
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
test('updatePrd patching an unrelated field leaves a PRD with no dependsOn unaffected', async () => {
|
|
143
|
-
const { cwd, prdsDir } = makeFixtureProject('sm-update-dependson-unrelated-');
|
|
144
|
-
try {
|
|
145
|
-
writePrd(prdsDir, '3-standalone.md', cwd);
|
|
146
|
-
|
|
147
|
-
const result = await scheduler.remote.updatePrd({
|
|
148
|
-
slug: '3-standalone',
|
|
149
|
-
cwd,
|
|
150
|
-
frontmatter: { estimateMinutes: 25 },
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
expect(result.ok).toBe(true);
|
|
154
|
-
const written = fs.readFileSync(path.join(prdsDir, '3-standalone.md'), 'utf8');
|
|
155
|
-
expect(written).not.toContain('dependsOn');
|
|
156
|
-
expect(written).toMatch(/^estimateMinutes: 25$/m);
|
|
157
|
-
} finally {
|
|
158
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
159
|
-
}
|
|
160
|
-
});
|