claude-code-session-manager 0.86.0 → 0.88.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 +26 -53
- package/dist/assets/AgentLibrary-BZ6IY2g1.js +3 -0
- package/dist/assets/{DataModel-Q4jhl24R.js → DataModel-dAoGAODX.js} +1 -1
- package/dist/assets/{History-Cj2FejEo.js → History-CF157HyX.js} +2 -2
- package/dist/assets/{Hooks-CaelQI6t.js → Hooks-CCPPipBk.js} +3 -3
- package/dist/assets/{HostBilko--v7cMR8I.js → HostBilko-Dlmz2m06.js} +1 -1
- package/dist/assets/{Library-DgI9oCCZ.js → Library-BaXcboWX.js} +1 -1
- package/dist/assets/{ListDetail-DYUZN-x-.js → ListDetail-CoUCzG5S.js} +1 -1
- package/dist/assets/MarkdownEditor-DTg3JlOT.js +1 -0
- package/dist/assets/{McpServers-ypCYURh3.js → McpServers-DdjY1sA3.js} +2 -2
- package/dist/assets/{Memory-C2qYp-3M.js → Memory-BJ3Jlw0C.js} +4 -4
- package/dist/assets/{Panel-Cj2kw-Zv.js → Panel-ygRSgc41.js} +1 -1
- package/dist/assets/Permissions-m0KAnccF.js +3 -0
- package/dist/assets/{Plugins-C1Vj8_dU.js → Plugins-CJRl6B3Q.js} +2 -2
- package/dist/assets/{ProvenanceBadge-DczPNM5U.js → ProvenanceBadge-w8cnlVvW.js} +1 -1
- package/dist/assets/{SaveBar-Cd_7U6Gb.js → SaveBar-BpyPcUIk.js} +1 -1
- package/dist/assets/Scheduler-D2ppxSfy.js +14 -0
- package/dist/assets/{ScopeSwitcher-DVSyI44-.js → ScopeSwitcher-EyuIwt-j.js} +1 -1
- package/dist/assets/Settings-BHSGGFEc.js +3 -0
- package/dist/assets/{SkillReferenceGraph-CUv1_Q2c.js → SkillReferenceGraph-BNaZ2JCF.js} +1 -1
- package/dist/assets/{Skills-C_YHkAy-.js → Skills-Dl3q75QV.js} +2 -2
- package/dist/assets/{SystemPrompt-B8R7T9xn.js → SystemPrompt-Bg6F-Cyp.js} +1 -1
- package/dist/assets/{TagLibrary-dj9YHWyy.js → TagLibrary-BSutflCy.js} +1 -1
- package/dist/assets/{TiptapBody-DnSBUjHE.js → TiptapBody-CXih4xrc.js} +1 -1
- package/dist/assets/{Toggle-CjV_BJn6.js → Toggle-2qtUHhA9.js} +1 -1
- package/dist/assets/{index-CXFQIPhO.js → index-B3emy2oI.js} +583 -583
- package/dist/assets/{index-CDo9xBR9.css → index-BHTX4OTc.css} +1 -1
- package/dist/assets/settingsSchema-CdzxaqwM.js +3 -0
- package/dist/assets/{whisperWorker-Dbia1OpC.js → whisperWorker-C7ZGQwKg.js} +7 -7
- package/dist/index.html +2 -2
- package/dist/vad/ort-wasm-simd-threaded.asyncify.mjs +106 -110
- package/dist/vad/ort-wasm-simd-threaded.asyncify.wasm +0 -0
- package/dist/vad/ort-wasm-simd-threaded.jsep.mjs +98 -98
- package/dist/vad/ort-wasm-simd-threaded.jsep.wasm +0 -0
- package/dist/vad/ort-wasm-simd-threaded.jspi.mjs +99 -102
- package/dist/vad/ort-wasm-simd-threaded.jspi.wasm +0 -0
- package/dist/vad/ort-wasm-simd-threaded.mjs +46 -46
- package/dist/vad/ort-wasm-simd-threaded.wasm +0 -0
- package/package.json +14 -17
- package/plugins/CLAUDE.md +61 -0
- package/plugins/session-manager-dev/.claude-plugin/plugin.json +1 -1
- package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +1 -1
- package/plugins/session-manager-dev/skills/ops-sweep/SKILL.md +1 -1
- package/scripts/README.md +59 -0
- package/scripts/audit-ops-hygiene.cjs +350 -0
- package/scripts/hooks/guard-destructive-git.cjs +10 -34
- package/scripts/hooks/guard-inline-implementation.cjs +14 -8
- package/scripts/hooks/guard-prd-writes.cjs +7 -36
- package/scripts/hooks/guard-self-schedule.cjs +175 -0
- package/scripts/ops-sweep.cjs +355 -0
- package/scripts/scheduler-mcp-server.cjs +35 -71
- package/src/main/__tests__/agentModelResolve.test.cjs +100 -9
- package/src/main/__tests__/bilkoHost-integration.test.cjs +3 -3
- package/src/main/__tests__/broadcastCoalescer.test.cjs +18 -0
- package/src/main/__tests__/chat-cancel-terminal.test.cjs +6 -9
- package/src/main/__tests__/chat-exit-close-race.test.cjs +3 -3
- package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +4 -5
- package/src/main/__tests__/chat-queue.test.cjs +2 -2
- package/src/main/__tests__/chat-stop-signal.test.cjs +2 -2
- package/src/main/__tests__/dep-orphan-archive-health.test.cjs +77 -0
- package/src/main/__tests__/dod-batchkey.test.cjs +2 -2
- package/src/main/__tests__/dod-drain-hook.test.cjs +2 -2
- package/src/main/__tests__/dod-report.test.cjs +2 -2
- package/src/main/__tests__/dod-reverify.test.cjs +2 -2
- package/src/main/__tests__/epicMint.test.cjs +4 -4
- package/src/main/__tests__/exchanges.test.cjs +2 -2
- package/src/main/__tests__/extractJson.test.cjs +2 -2
- package/src/main/__tests__/files-reject-credentials.test.cjs +1 -1
- package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +556 -0
- package/src/main/__tests__/health-build-freshness.test.cjs +39 -0
- package/src/main/__tests__/health-delegation-chain.test.cjs +17 -2
- package/src/main/__tests__/health-queue-dispatch.test.cjs +58 -7
- package/src/main/__tests__/health-tick-liveness.test.cjs +11 -3
- package/src/main/__tests__/health-usage-poller.test.cjs +70 -23
- package/src/main/__tests__/historyRollup.test.cjs +2 -2
- package/src/main/__tests__/kg-augment.test.cjs +2 -2
- package/src/main/__tests__/mcpStatus.test.cjs +2 -2
- package/src/main/__tests__/memoryAggregate.test.cjs +1 -1
- package/src/main/__tests__/memoryStale.test.cjs +1 -1
- package/src/main/__tests__/needsReviewLedger.test.cjs +162 -0
- package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +28 -4
- package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +48 -4
- package/src/main/__tests__/prd-group-allocator.test.cjs +2 -2
- package/src/main/__tests__/prdAdminRouteParity.test.cjs +2 -0
- package/src/main/__tests__/prdAdminRoutes.test.cjs +14 -2
- package/src/main/__tests__/prdAuthoringSeed.test.cjs +39 -0
- package/src/main/__tests__/prdCreateDisposition.test.cjs +201 -0
- package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +125 -0
- package/src/main/__tests__/prdLocations.test.cjs +100 -2
- package/src/main/__tests__/prdLocationsArchived.test.cjs +50 -1
- package/src/main/__tests__/prdSetDisposition.test.cjs +222 -0
- package/src/main/__tests__/proc-role-env.test.cjs +125 -0
- package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +304 -0
- package/src/main/__tests__/procname-sm-processes.test.cjs +127 -0
- package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +81 -401
- package/src/main/__tests__/projectPages.test.cjs +63 -149
- package/src/main/__tests__/queue-health-verdict.test.cjs +170 -0
- package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +117 -20
- package/src/main/__tests__/queue-starvation-per-project.test.cjs +14 -2
- package/src/main/__tests__/queueHistory.test.cjs +65 -2
- package/src/main/__tests__/rateLimitPollerStreak.test.cjs +38 -3
- package/src/main/__tests__/reconcileTiming.test.cjs +135 -0
- package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +181 -0
- package/src/main/__tests__/runVerify.test.cjs +5 -5
- package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +3 -3
- package/src/main/__tests__/scheduleJobTransitions.test.cjs +103 -3
- package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +143 -0
- package/src/main/__tests__/scheduler-autofix-select.test.cjs +2 -2
- package/src/main/__tests__/scheduler-autopromote.test.cjs +2 -2
- package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +3 -5
- package/src/main/__tests__/scheduler-boot-orphans.test.cjs +79 -98
- package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +121 -0
- package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +43 -0
- package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +161 -0
- package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +58 -0
- package/src/main/__tests__/scheduler-epic-digest.test.cjs +3 -5
- package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +2 -2
- package/src/main/__tests__/scheduler-gate-shadow.test.cjs +119 -0
- package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +390 -0
- package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +80 -0
- package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +25 -18
- package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +4 -4
- package/src/main/__tests__/scheduler-job-budget.test.cjs +172 -0
- package/src/main/__tests__/scheduler-launch-failure.test.cjs +3 -5
- package/src/main/__tests__/scheduler-looks-done.test.cjs +119 -10
- package/src/main/__tests__/scheduler-manual-pause.test.cjs +118 -0
- package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +26 -3
- package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +164 -0
- package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +17 -2
- package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +3 -5
- package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +41 -6
- package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +62 -6
- package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +3 -5
- package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +182 -3
- package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +87 -0
- package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +100 -0
- package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +3 -3
- package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +4 -4
- package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +110 -0
- package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +168 -0
- package/src/main/__tests__/scheduler-starve-escalation.test.cjs +18 -8
- package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +245 -0
- package/src/main/__tests__/scheduler-supervisor-record.test.cjs +81 -0
- package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +2 -2
- package/src/main/__tests__/scheduler-tick-wedge.test.cjs +172 -0
- package/src/main/__tests__/scheduler-transient-failure.test.cjs +2 -2
- package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +51 -11
- package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +3 -5
- package/src/main/__tests__/usageSingleFlight.test.cjs +157 -0
- package/src/main/__tests__/workTypeLibrary.test.cjs +1 -1
- package/src/main/bilkoHost.cjs +16 -7
- package/src/main/build-info.json +8 -0
- package/src/main/chatRunner.cjs +12 -7
- package/src/main/config.cjs +2 -3
- package/src/main/docEdit.cjs +4 -2
- package/src/main/health.cjs +268 -52
- package/src/main/heapSnapshot.cjs +2 -2
- package/src/main/historyAggregator.cjs +6 -1
- package/src/main/index.cjs +152 -50
- package/src/main/ipcSchemas.cjs +53 -17
- package/src/main/lib/__tests__/active-sessions.test.cjs +251 -0
- package/src/main/lib/__tests__/auditLog.test.cjs +38 -0
- package/src/main/lib/__tests__/bootSelfHeal.test.cjs +107 -0
- package/src/main/lib/__tests__/buildIdentity.test.cjs +121 -0
- package/src/main/lib/__tests__/cwdClassify.test.cjs +111 -0
- package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +95 -0
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +323 -44
- package/src/main/lib/__tests__/dispatchLoop.test.cjs +63 -0
- package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +239 -0
- package/src/main/lib/__tests__/gateFixtures.json +20 -0
- package/src/main/lib/__tests__/gitWorktree.test.cjs +97 -1
- package/src/main/lib/__tests__/guardShims.test.cjs +151 -0
- package/src/main/lib/__tests__/instanceLock.test.cjs +93 -7
- package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +78 -0
- package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +11 -0
- package/src/main/lib/__tests__/localAdminHttp.test.cjs +1 -1
- package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +6 -1
- package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +5 -5
- package/src/main/lib/__tests__/prdDisposition.test.cjs +224 -0
- package/src/main/lib/__tests__/procIdentity.test.cjs +119 -0
- package/src/main/lib/__tests__/procName.test.cjs +92 -0
- package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +67 -0
- package/src/main/lib/__tests__/reaperHelpers.test.cjs +179 -1
- package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +6 -7
- package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +37 -204
- package/src/main/lib/__tests__/schedulerPaths.test.cjs +226 -0
- package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +94 -0
- package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +56 -0
- package/src/main/lib/__tests__/sessionSlots.test.cjs +45 -0
- package/src/main/lib/__tests__/telemetryBacklog.test.cjs +1 -1
- package/src/main/lib/__tests__/upgradeDrain.test.cjs +130 -0
- package/src/main/lib/__tests__/usageCircuit.test.cjs +285 -0
- package/src/main/lib/__tests__/watchdog-helpers.test.cjs +375 -0
- package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +266 -0
- package/src/main/lib/activeIndexRebuild.cjs +1 -3
- package/{scripts → src/main}/lib/activeSessions.cjs +67 -89
- package/src/main/lib/adoptedRunSupervisor.cjs +136 -0
- package/src/main/lib/agentModelResolve.cjs +94 -24
- package/src/main/lib/agentPersonaSchema.cjs +2 -2
- package/src/main/lib/auditLog.cjs +30 -5
- package/src/main/lib/bootSelfHeal.cjs +88 -0
- package/src/main/lib/buildIdentity.cjs +113 -0
- package/src/main/lib/classifyPromptTicket.cjs +3 -2
- package/src/main/lib/claudeBin.cjs +37 -2
- package/src/main/lib/cleanEnv.cjs +27 -1
- package/src/main/lib/credentials.cjs +4 -2
- package/src/main/lib/cwdClassify.cjs +185 -0
- package/src/main/lib/definitionOfDone.cjs +296 -52
- package/src/main/lib/delegationReadiness.cjs +290 -225
- package/src/main/lib/dispatchLoop.cjs +40 -0
- package/src/main/lib/effectiveModelInfo.cjs +332 -0
- package/src/main/lib/ephemeralCwd.cjs +7 -28
- package/src/main/lib/epicMint.cjs +3 -3
- package/src/main/lib/gitWorktree.cjs +136 -19
- package/src/main/lib/guardShims.cjs +156 -0
- package/src/main/lib/historyRollup.cjs +6 -7
- package/src/main/lib/instanceLock.cjs +32 -5
- package/src/main/lib/jobDirtFilter.cjs +7 -2
- package/src/main/lib/jobSupervisorRecord.cjs +147 -0
- package/src/main/lib/jobWorktreeBootLive.cjs +9 -5
- package/src/main/lib/launchFailure.cjs +2 -1
- package/src/main/lib/localAdminHttp.cjs +9 -27
- package/src/main/lib/mcpToolCatalog.cjs +33 -78
- package/src/main/lib/needsReviewLedger.cjs +205 -0
- package/src/main/lib/opsErrorLog.cjs +1 -1
- package/src/main/lib/opsOwnership.cjs +27 -19
- package/src/main/lib/prdAuthoringSeed.cjs +36 -0
- package/src/main/lib/prdCreate.cjs +56 -1
- package/src/main/lib/prdDisposition.cjs +199 -0
- package/src/main/lib/prdFrontmatter.cjs +8 -2
- package/src/main/lib/prdLocations.cjs +214 -45
- package/src/main/lib/procIdentity.cjs +126 -0
- package/src/main/lib/procName.cjs +98 -0
- package/src/main/lib/projectHomeAdminRoutes.cjs +56 -327
- package/src/main/lib/projectRootResolve.cjs +1 -1
- package/src/main/lib/queueHistory.cjs +27 -8
- package/src/main/lib/queueStore.cjs +63 -38
- package/src/main/lib/quietMachineLease.cjs +19 -2
- package/src/main/lib/reaperHelpers.cjs +181 -15
- package/src/main/lib/reservationExpiry.cjs +30 -0
- package/src/main/lib/runClaudeP.cjs +4 -2
- package/src/main/lib/runLogRetention.cjs +3 -2
- package/src/main/lib/scheduleJobSchema.cjs +10 -2
- package/src/main/lib/scheduleJobTransitions.cjs +60 -0
- package/src/main/lib/schedulerBatch.cjs +27 -2
- package/src/main/lib/schedulerConfig.cjs +24 -0
- package/src/main/lib/schedulerPaths.cjs +175 -0
- package/src/main/lib/schedulerRuntimeState.cjs +59 -0
- package/src/main/lib/sessionSlots.cjs +47 -9
- package/src/main/lib/smProcNames.cjs +51 -0
- package/src/main/lib/upgradeDrain.cjs +188 -0
- package/src/main/lib/usageCircuit.cjs +206 -0
- package/{scripts → src/main}/lib/watchdogHelpers.cjs +71 -38
- package/src/main/lib/withTimeout.cjs +33 -0
- package/src/main/mcpStatus.cjs +4 -2
- package/src/main/pluginInstall.cjs +6 -2
- package/src/main/projectPages.cjs +41 -145
- package/src/main/pty.cjs +8 -1
- package/src/main/queueOps.cjs +10 -10
- package/src/main/runVerify.cjs +69 -3
- package/src/main/scheduler/prdParser.cjs +13 -0
- package/src/main/scheduler.cjs +2841 -482
- package/src/main/seedAgentPersonas.cjs +1 -1
- package/src/main/seedDevPlugin.cjs +1 -1
- package/src/main/seedSchedulerMcp.cjs +7 -6
- package/src/main/seedStatus.cjs +1 -1
- package/src/main/supervisor.cjs +5 -3
- package/src/main/templates/PRD_AUTHORING.md +50 -0
- package/src/main/usage.cjs +140 -58
- package/src/preload/api.d.ts +110 -65
- package/src/preload/index.cjs +12 -4
- package/src/seed/agents/project-home-builder.md +31 -48
- package/dist/assets/AgentLibrary-DTFL7y8G.js +0 -3
- package/dist/assets/MarkdownEditor-DCIubYWf.js +0 -1
- package/dist/assets/Permissions-BiYZNGYW.js +0 -3
- package/dist/assets/Scheduler-DcLBiJBq.js +0 -14
- package/dist/assets/Settings-Cv-pRyms.js +0 -3
- package/dist/assets/settingsSchema-BJVciriw.js +0 -3
- package/screenshots/.gitkeep +0 -0
- package/screenshots/README-screenshots.md +0 -13
- package/scripts/project-pages-logic/dist/logic.cjs +0 -4709
- package/scripts/render-project-pages/dist/renderer.cjs +0 -18900
- package/scripts/render-project-pages.cjs +0 -70
- package/scripts/validate-project-pages-summary.cjs +0 -62
- package/src/main/lib/projectPageSummarySchema.cjs +0 -181
- package/src/main/teams.cjs +0 -95
- package/src/main/templates/project-pages-catalog.json +0 -741
- package/src/main/templates/project-pages-default-home.html +0 -123
- package/src/main/templates/project-pages-pipeline.md +0 -417
- package/src/seed/prompts/code-review/ac-coverage-check.md +0 -8
- package/src/seed/prompts/code-review/correctness-only.md +0 -8
- package/src/seed/prompts/code-review/full-spectrum-high.md +0 -8
- package/src/seed/prompts/code-review/hallucination-check.md +0 -8
- package/src/seed/prompts/code-review/public-api-compat.md +0 -8
- package/src/seed/prompts/code-review/readability-naming.md +0 -8
- package/src/seed/prompts/debugging/bug-as-failing-test.md +0 -8
- package/src/seed/prompts/debugging/git-bisect-regression.md +0 -8
- package/src/seed/prompts/debugging/instrument-intermittent-bug.md +0 -8
- package/src/seed/prompts/debugging/localize-pipeline-failure.md +0 -8
- package/src/seed/prompts/debugging/reproduce-then-diagnose.md +0 -8
- package/src/seed/prompts/documentation/adr-from-change.md +0 -8
- package/src/seed/prompts/documentation/module-readme.md +0 -8
- package/src/seed/prompts/documentation/onboarding-plan.md +0 -8
- package/src/seed/prompts/documentation/refresh-claude-md.md +0 -8
- package/src/seed/prompts/documentation/tsdoc-public-exports.md +0 -8
- package/src/seed/prompts/git-pr/conventional-commit.md +0 -8
- package/src/seed/prompts/git-pr/draft-pr-title-body.md +0 -8
- package/src/seed/prompts/git-pr/pre-commit-safety-sweep.md +0 -8
- package/src/seed/prompts/git-pr/release-notes-block.md +0 -8
- package/src/seed/prompts/git-pr/split-large-pr.md +0 -8
- package/src/seed/prompts/performance/bundle-startup-audit.md +0 -8
- package/src/seed/prompts/performance/complexity-audit.md +0 -8
- package/src/seed/prompts/performance/cpu-profile-hot-path.md +0 -8
- package/src/seed/prompts/performance/db-query-plan-review.md +0 -8
- package/src/seed/prompts/performance/memory-leak-hunt.md +0 -8
- package/src/seed/prompts/qa/api-contract-tests.md +0 -8
- package/src/seed/prompts/qa/e2e-critical-path.md +0 -8
- package/src/seed/prompts/qa/failing-test-for-bug.md +0 -8
- package/src/seed/prompts/qa/find-missing-test-coverage.md +0 -8
- package/src/seed/prompts/qa/stabilize-flaky-test.md +0 -8
- package/src/seed/prompts/qa/tdd-red-first.md +0 -8
- package/src/seed/prompts/qa/visual-regression-review.md +0 -8
- package/src/seed/prompts/qa/wcag-axe-scan.md +0 -8
- package/src/seed/prompts/refactoring/dead-code-sweep.md +0 -8
- package/src/seed/prompts/refactoring/extract-duplicated-pattern.md +0 -8
- package/src/seed/prompts/refactoring/modernize-legacy-file.md +0 -8
- package/src/seed/prompts/refactoring/reduce-cyclomatic-complexity.md +0 -8
- package/src/seed/prompts/refactoring/tighten-module-boundaries.md +0 -8
- package/src/seed/prompts/security/authz-audit.md +0 -8
- package/src/seed/prompts/security/crypto-correctness.md +0 -8
- package/src/seed/prompts/security/cwe-top-25-hunt.md +0 -8
- package/src/seed/prompts/security/dependency-audit.md +0 -8
- package/src/seed/prompts/security/ipc-boundary-hardening.md +0 -8
- package/src/seed/prompts/security/owasp-top-10-staged-diff.md +0 -8
- package/src/seed/prompts/security/secret-credential-scan.md +0 -8
|
@@ -48,17 +48,10 @@ const OWNERS = Object.freeze({
|
|
|
48
48
|
'scheduler': 'scheduler',
|
|
49
49
|
// Project Home owns the synthesized Brief (generate + hand-edit).
|
|
50
50
|
'project-brief': 'project-home',
|
|
51
|
-
// Project Home
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
// the SAME folder is also written directly by a project-home-builder
|
|
56
|
-
// Epic's own Write tool, which never goes through config.cjs and so is
|
|
57
|
-
// NOT governed by this table at all (see
|
|
58
|
-
// session-manager-operations/project-pages/README.md). Declaring the
|
|
59
|
-
// namespace here only closes the fail-closed gap for the app's own write
|
|
60
|
-
// path — it does not claim exclusivity over the agent's Write-tool calls,
|
|
61
|
-
// which remain outside this law by construction.
|
|
51
|
+
// Project Home owns project-pages/home.html, written only via the
|
|
52
|
+
// project_home_write MCP tool -> /admin/project-home/write route
|
|
53
|
+
// (config.cjs's writeTextAtomic). See
|
|
54
|
+
// session-manager-operations/project-pages/README.md.
|
|
62
55
|
'project-pages': 'project-home',
|
|
63
56
|
// Structured per-tab error log lines (JSONL), tagged for tracing/analysis.
|
|
64
57
|
'logs': 'logs',
|
|
@@ -177,11 +170,13 @@ function assertOpsWrite(absPath, writer) {
|
|
|
177
170
|
// worktree-cwd hazard (PRD 1082; incidents 2026-08-30, 2026-09-01).
|
|
178
171
|
const { inOps } = parseOpsPath(absPath);
|
|
179
172
|
if (inOps) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const {
|
|
184
|
-
|
|
173
|
+
// innermostOpsRoot (lastIndexOf) is the fact THIS gate keys on; activeSessions
|
|
174
|
+
// truncates at the outermost instead — cwdClassify returns both, unified in
|
|
175
|
+
// neither direction.
|
|
176
|
+
const { classifyCwd } = require('./cwdClassify.cjs');
|
|
177
|
+
const projectRoot = path.dirname(classifyCwd(absPath).innermostOpsRoot);
|
|
178
|
+
const { kind, reason } = classifyCwd(projectRoot);
|
|
179
|
+
if (kind === 'ephemeral' || kind === 'worktree') {
|
|
185
180
|
const err = new Error(
|
|
186
181
|
`refusing to write ${OPS_ROOT_DIR}/ state under an ephemeral project root `
|
|
187
182
|
+ `(tmpdir or linked git worktree): "${projectRoot}" — see lib/opsOwnership.cjs resolveProjectRoot`,
|
|
@@ -189,6 +184,17 @@ function assertOpsWrite(absPath, writer) {
|
|
|
189
184
|
err.ephemeral = true;
|
|
190
185
|
throw err;
|
|
191
186
|
}
|
|
187
|
+
if (kind === 'unknown') {
|
|
188
|
+
// Fail closed on the unprovable case (worktree .git file whose admin
|
|
189
|
+
// back-reference is gone, garbled .git file): the exact shape behind the
|
|
190
|
+
// lost-Epics incidents. WRITES only — reads and dispatch stay open.
|
|
191
|
+
const err = new Error(
|
|
192
|
+
`refusing to write ${OPS_ROOT_DIR}/ state under "${projectRoot}": project identity `
|
|
193
|
+
+ `cannot be proven (${reason}) — see lib/cwdClassify.cjs`,
|
|
194
|
+
);
|
|
195
|
+
err.unknownCwd = true;
|
|
196
|
+
throw err;
|
|
197
|
+
}
|
|
192
198
|
}
|
|
193
199
|
}
|
|
194
200
|
|
|
@@ -236,10 +242,12 @@ function resolveProjectRoot(cwd, { opsInternal = 'normalize' } = {}) {
|
|
|
236
242
|
`resolveProjectRoot: cwd must be a project root, not a path inside ${OPS_ROOT_DIR}/, got "${cwd}"`,
|
|
237
243
|
);
|
|
238
244
|
}
|
|
239
|
-
// Lazy:
|
|
240
|
-
const {
|
|
245
|
+
// Lazy: cwdClassify → schedulerPaths; ephemeralCwd → cwdClassify.
|
|
246
|
+
const { classifyCwd } = require('./cwdClassify.cjs');
|
|
241
247
|
const { isEphemeralCwd } = require('./ephemeralCwd.cjs');
|
|
242
|
-
|
|
248
|
+
// `unknown` deliberately does NOT throw here: reads and dispatch must keep
|
|
249
|
+
// working; assertOpsWrite is the choke point that refuses the WRITE.
|
|
250
|
+
const root = classifyCwd(cwd).projectRoot;
|
|
243
251
|
if (isEphemeralCwd(root)) {
|
|
244
252
|
const err = new Error(
|
|
245
253
|
`resolveProjectRoot: refusing ephemeral cwd (tmpdir or linked git worktree), got "${cwd}"`,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Seed-when-the-stamp-differs for the bundled PRD_AUTHORING.md guide.
|
|
3
|
+
// Pure fs + injected writer so it is testable without an Electron app.
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
|
|
7
|
+
const STAMP_RE = /^<!--\s*PRD_AUTHORING\.md\s+(v\d+)\s*-->/;
|
|
8
|
+
|
|
9
|
+
/** Version stamp from line 1 of `text`, or null when absent. */
|
|
10
|
+
function readStamp(text) {
|
|
11
|
+
const first = String(text).split(/\r?\n/, 1)[0];
|
|
12
|
+
const m = STAMP_RE.exec(first);
|
|
13
|
+
return m ? m[1] : null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** True when dest should be (re)written from src: missing/unstamped/differing stamp. */
|
|
17
|
+
function shouldSeed(srcText, destText) {
|
|
18
|
+
if (destText == null) return true;
|
|
19
|
+
const destStamp = readStamp(destText);
|
|
20
|
+
return destStamp === null || destStamp !== readStamp(srcText);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Overwrite `dest` with `src` when shouldSeed. `write(abs, text)` is the atomic
|
|
25
|
+
* writer (config.writeTextAtomic). Resolves true when it wrote, false otherwise.
|
|
26
|
+
*/
|
|
27
|
+
async function seedAuthoringGuide({ src, dest, write }) {
|
|
28
|
+
if (!fs.existsSync(src)) return false;
|
|
29
|
+
const srcText = fs.readFileSync(src, 'utf8');
|
|
30
|
+
const destText = fs.existsSync(dest) ? fs.readFileSync(dest, 'utf8') : null;
|
|
31
|
+
if (!shouldSeed(srcText, destText)) return false;
|
|
32
|
+
await write(dest, srcText);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = { readStamp, shouldSeed, seedAuthoringGuide };
|
|
@@ -30,6 +30,7 @@ const { fixChainDepthOf, baseSlugOf } = require('./fixChainDepth.cjs');
|
|
|
30
30
|
const { DEFAULT_PRD_AGENT_TYPE, assertAgentTypeWritable } = require('./prdAgentType.cjs');
|
|
31
31
|
const { resolveDepSlug, findNearMatches } = require('./depSlugResolve.cjs');
|
|
32
32
|
const { isFixPlanSlug } = require('./fixPlanSlug.cjs');
|
|
33
|
+
const { isIncomplete, resolveChainTerminals } = require('./prdDisposition.cjs');
|
|
33
34
|
|
|
34
35
|
// A caller-supplied slug that already starts with its own `NN-` (e.g.
|
|
35
36
|
// "254-perf-x") used to silently become the double-prefixed row
|
|
@@ -74,7 +75,7 @@ function deriveSlugFromTitle(title) {
|
|
|
74
75
|
function buildPrdBody(input) {
|
|
75
76
|
const {
|
|
76
77
|
title, cwd, estimateMinutes, goal, acceptanceCriteria,
|
|
77
|
-
implementationNotes, outOfScope, sourcePromptId, sourceTabId, tag, agentType, dependsOn, quietMachine,
|
|
78
|
+
implementationNotes, outOfScope, sourcePromptId, sourceTabId, tag, agentType, dependsOn, quietMachine, disposition,
|
|
78
79
|
} = input;
|
|
79
80
|
|
|
80
81
|
// No `parallelGroup` frontmatter key by convention (SKILL.md) — the NN-
|
|
@@ -108,6 +109,11 @@ function buildPrdBody(input) {
|
|
|
108
109
|
fmLines.push(`agentType: ${agentType || DEFAULT_PRD_AGENT_TYPE}`);
|
|
109
110
|
// Explicit ordering (PRD 832): replaces the retired shared-NN convention.
|
|
110
111
|
if (dependsOn && dependsOn.length) fmLines.push(`dependsOn: [${dependsOn.join(', ')}]`);
|
|
112
|
+
// Wave-authoring decision (scheduler wave-disposition PRD) — only ever set
|
|
113
|
+
// when createPrd() actually had a disposition to record (see the call
|
|
114
|
+
// site above); a first-ever PRD in an Epic, or one with its own explicit
|
|
115
|
+
// dependsOn, has nothing to decide against and omits this key.
|
|
116
|
+
if (disposition) fmLines.push(`disposition: ${disposition}`);
|
|
111
117
|
// Opt-in exclusive-lease flag (PRD 1107): serializes this job against
|
|
112
118
|
// every other job machine-wide for its run, for a PRD whose acceptance
|
|
113
119
|
// criteria are wall-clock/timing measurements that CPU contention from
|
|
@@ -237,6 +243,55 @@ async function createPrd(input, remote) {
|
|
|
237
243
|
if (fallback) input = { ...input, sourcePromptId: fallback };
|
|
238
244
|
}
|
|
239
245
|
|
|
246
|
+
// Wave-disposition decision point (scheduler wave-disposition PRD): only
|
|
247
|
+
// matters for a PRD that would become a ROOT of its own wave — one the
|
|
248
|
+
// caller didn't already give an explicit dependsOn (that already fixes
|
|
249
|
+
// its position in some chain) — joining an Epic whose sourcePromptId this
|
|
250
|
+
// PRD shares. See prdDisposition.cjs's header for the full contract.
|
|
251
|
+
if (input.sourcePromptId && (!input.dependsOn || input.dependsOn.length === 0)) {
|
|
252
|
+
let epicRows = [];
|
|
253
|
+
try {
|
|
254
|
+
const listing = await remote.listPrds({ cwd: input.cwd, fields: 'full', limit: Number.MAX_SAFE_INTEGER });
|
|
255
|
+
epicRows = (listing?.prds ?? []).filter((p) => p.sourcePromptId === input.sourcePromptId);
|
|
256
|
+
} catch (e) {
|
|
257
|
+
console.warn(`[prdCreate] disposition resolution skipped (listPrds failed): ${e?.message ?? e}`);
|
|
258
|
+
}
|
|
259
|
+
if (epicRows.some((p) => isIncomplete(p.status))) {
|
|
260
|
+
let disposition = input.disposition ?? null;
|
|
261
|
+
if (!disposition) {
|
|
262
|
+
// A headless PRD executor's own job has SM_SCHEDULER_JOB_SLUG set on
|
|
263
|
+
// its env (scheduler.cjs stamps every spawned job's child env with
|
|
264
|
+
// it) — no human is present to ask, so the conservative default
|
|
265
|
+
// ('append') applies and is logged as a default, never as a silent
|
|
266
|
+
// choice. Anything else (a live interactive Epic chat session, or a
|
|
267
|
+
// direct admin-route call) is refused instead of guessed — see this
|
|
268
|
+
// PRD's AC2.
|
|
269
|
+
const nonInteractive = Boolean(process.env.SM_SCHEDULER_JOB_SLUG);
|
|
270
|
+
if (!nonInteractive) {
|
|
271
|
+
return {
|
|
272
|
+
ok: false,
|
|
273
|
+
status: 400,
|
|
274
|
+
error: `Epic ${input.sourcePromptId} already has incomplete PRDs — pass disposition: "append" ` +
|
|
275
|
+
'(extend the existing chain behind its current tail) or "new-head" (an independent root, ' +
|
|
276
|
+
'eligible to run in parallel) to record this wave\'s relationship to the existing plan.',
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
disposition = 'append';
|
|
280
|
+
console.warn(`[prdCreate] disposition defaulted to "append" for a non-interactive caller (epic ${input.sourcePromptId})`);
|
|
281
|
+
appendAuditEvent('prd_disposition_defaulted', { cwd: input.cwd, epicId: input.sourcePromptId, disposition });
|
|
282
|
+
}
|
|
283
|
+
if (disposition === 'append') {
|
|
284
|
+
// Only the Epic's still-incomplete rows count as "the active plan" to
|
|
285
|
+
// append behind — a completed, undepended-upon row would otherwise
|
|
286
|
+
// also read as a terminal, silently attaching this wave to already-
|
|
287
|
+
// finished work instead of purely the current chain's live tail(s).
|
|
288
|
+
const terminals = resolveChainTerminals(epicRows.filter((p) => isIncomplete(p.status)));
|
|
289
|
+
if (terminals.length) input = { ...input, dependsOn: terminals };
|
|
290
|
+
}
|
|
291
|
+
input = { ...input, disposition };
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
240
295
|
if (input.slug) {
|
|
241
296
|
const nnMatch = SLUG_HAS_NN_PREFIX_RE.exec(input.slug);
|
|
242
297
|
if (nnMatch) {
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* prdDisposition.cjs — the wave-authoring decision (scheduler wave-
|
|
5
|
+
* disposition PRD): when a new PRD wave joins an Epic that already has
|
|
6
|
+
* incomplete PRDs, does the wave APPEND behind the existing chain's tail, or
|
|
7
|
+
* start an independent NEW-HEAD root eligible to run in parallel? Before
|
|
8
|
+
* this module the choice didn't exist — every new root PRD silently landed
|
|
9
|
+
* as a parallel-eligible row, so waves interleaved with no recorded
|
|
10
|
+
* relationship and a human reading the backlog couldn't tell a plan from a
|
|
11
|
+
* pile.
|
|
12
|
+
*
|
|
13
|
+
* Two call sites:
|
|
14
|
+
* - prdCreate.cjs's createPrd() — AUTHORING TIME. Resolves 'append' into a
|
|
15
|
+
* concrete dependsOn via resolveChainTerminals() over the Epic's
|
|
16
|
+
* existing rows.
|
|
17
|
+
* - scheduler.cjs's `schedule:set-prd-disposition` IPC handler — CHANGING
|
|
18
|
+
* an already-written PRD's disposition from the Scheduler UI. Uses
|
|
19
|
+
* computeDispositionRewrite() to validate the rewrite is safe before
|
|
20
|
+
* handing the new dependsOn to remote.updatePrd (which itself refuses a
|
|
21
|
+
* non-pending/quarantined row — see scheduler.cjs's updatePrd).
|
|
22
|
+
*
|
|
23
|
+
* `rows` throughout is the same shape listPrdsInternal() already produces:
|
|
24
|
+
* { slug, status, dependsOn }. dependsOn entries are resolved against `rows`
|
|
25
|
+
* via depSlugResolve.cjs's resolveDepSlug — the SAME rule
|
|
26
|
+
* schedulerBatch.cjs's findBlockingDep and prdCreate.cjs's write-time FK
|
|
27
|
+
* check use, so a terminal/cycle computed here can never disagree with what
|
|
28
|
+
* the scheduler considers a row's real blockers at run time.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const { resolveDepSlug } = require('./depSlugResolve.cjs');
|
|
32
|
+
|
|
33
|
+
/** A row is "incomplete" (still part of the Epic's active plan) unless it
|
|
34
|
+
* has actually finished. Treats every other status — including a brand-new
|
|
35
|
+
* row with no queue entry yet (`status: null`) — as incomplete, since none
|
|
36
|
+
* of those represent shipped work a wave could safely ignore. */
|
|
37
|
+
function isIncomplete(status) {
|
|
38
|
+
return status !== 'completed';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Resolve each row's dependsOn entries to actual row slugs present in
|
|
42
|
+
* `rows`, via the shared resolution rule. A dep that doesn't resolve to
|
|
43
|
+
* anything in this row set (dangling, or lives outside this Epic) is
|
|
44
|
+
* dropped — it can't affect this Epic's own terminal computation. */
|
|
45
|
+
function resolvedDependents(rows) {
|
|
46
|
+
const slugs = rows.map((r) => r.slug);
|
|
47
|
+
const dependedUpon = new Set();
|
|
48
|
+
for (const r of rows) {
|
|
49
|
+
for (const dep of r.dependsOn ?? []) {
|
|
50
|
+
for (const resolved of resolveDepSlug(dep, slugs)) dependedUpon.add(resolved);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return dependedUpon;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Every row participating in a dependsOn cycle within `rows` (self-loops
|
|
57
|
+
* included) — mirrors backlogTree.ts's detectCycles (renderer-only, can't
|
|
58
|
+
* be required from this CJS main-process module; kept in sync by hand). */
|
|
59
|
+
function detectCycles(rows) {
|
|
60
|
+
const bySlug = new Map(rows.map((r) => [r.slug, r]));
|
|
61
|
+
const slugs = rows.map((r) => r.slug);
|
|
62
|
+
const color = new Map();
|
|
63
|
+
const cyclic = new Set();
|
|
64
|
+
const stack = [];
|
|
65
|
+
|
|
66
|
+
function visit(slug) {
|
|
67
|
+
color.set(slug, 1);
|
|
68
|
+
stack.push(slug);
|
|
69
|
+
const r = bySlug.get(slug);
|
|
70
|
+
const deps = new Set();
|
|
71
|
+
for (const dep of r?.dependsOn ?? []) {
|
|
72
|
+
for (const resolved of resolveDepSlug(dep, slugs)) deps.add(resolved);
|
|
73
|
+
}
|
|
74
|
+
for (const dep of deps) {
|
|
75
|
+
const c = color.get(dep);
|
|
76
|
+
if (c === 1) {
|
|
77
|
+
const idx = stack.indexOf(dep);
|
|
78
|
+
for (let i = idx; i < stack.length; i++) cyclic.add(stack[i]);
|
|
79
|
+
} else if (c === undefined) {
|
|
80
|
+
visit(dep);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
stack.pop();
|
|
84
|
+
color.set(slug, 2);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const r of rows) {
|
|
88
|
+
if (!color.has(r.slug)) visit(r.slug);
|
|
89
|
+
}
|
|
90
|
+
return cyclic;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Terminal (leaf) slugs of the dependency forest formed by `rows` — the
|
|
95
|
+
* row(s) nothing else in `rows` depends on. This is what an 'append'
|
|
96
|
+
* disposition attaches a new wave's root behind: depending on every current
|
|
97
|
+
* terminal means the new wave runs only once everything already queued (in
|
|
98
|
+
* every existing head) has finished, the conservative reading of "append".
|
|
99
|
+
* A row participating in a cycle is excluded — never used as a rewrite
|
|
100
|
+
* target, since a cycle indicates the existing graph shouldn't be extended
|
|
101
|
+
* until it's fixed by hand.
|
|
102
|
+
*/
|
|
103
|
+
function resolveChainTerminals(rows) {
|
|
104
|
+
if (!rows.length) return [];
|
|
105
|
+
const dependedUpon = resolvedDependents(rows);
|
|
106
|
+
const cyclic = detectCycles(rows);
|
|
107
|
+
return rows
|
|
108
|
+
.map((r) => r.slug)
|
|
109
|
+
.filter((slug) => !dependedUpon.has(slug) && !cyclic.has(slug));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Would setting `slug`'s dependsOn to `newDependsOn` create a cycle? Checks
|
|
114
|
+
* reachability from each (resolved) proposed dependency back to `slug`
|
|
115
|
+
* following the EXISTING graph in `rows` (never `slug`'s own current
|
|
116
|
+
* dependsOn, which is being replaced) — a direct self-reference is always a
|
|
117
|
+
* cycle, checked first without needing a graph walk.
|
|
118
|
+
*/
|
|
119
|
+
function wouldCreateCycle(rows, slug, newDependsOn) {
|
|
120
|
+
const slugs = rows.map((r) => r.slug);
|
|
121
|
+
const bySlug = new Map(rows.map((r) => [r.slug, r]));
|
|
122
|
+
const resolvedTargets = new Set();
|
|
123
|
+
for (const dep of newDependsOn) {
|
|
124
|
+
for (const resolved of resolveDepSlug(dep, slugs)) resolvedTargets.add(resolved);
|
|
125
|
+
}
|
|
126
|
+
if (resolvedTargets.has(slug)) return true;
|
|
127
|
+
|
|
128
|
+
const visited = new Set();
|
|
129
|
+
function reachesSlug(from) {
|
|
130
|
+
if (from === slug) return true;
|
|
131
|
+
if (visited.has(from)) return false;
|
|
132
|
+
visited.add(from);
|
|
133
|
+
const r = bySlug.get(from);
|
|
134
|
+
for (const dep of r?.dependsOn ?? []) {
|
|
135
|
+
for (const resolved of resolveDepSlug(dep, slugs)) {
|
|
136
|
+
if (reachesSlug(resolved)) return true;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
for (const target of resolvedTargets) {
|
|
142
|
+
if (reachesSlug(target)) return true;
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Validates and computes the new dependsOn for a disposition change on an
|
|
149
|
+
* already-written PRD (the Scheduler UI's "promote to head" / "attach
|
|
150
|
+
* behind another chain" action). Pure — returns the new dependsOn value on
|
|
151
|
+
* success; the caller (scheduler.cjs's IPC handler) is responsible for
|
|
152
|
+
* actually persisting it via remote.updatePrd, which independently refuses
|
|
153
|
+
* a non-pending/quarantined row (defense in depth, not duplicated here).
|
|
154
|
+
*
|
|
155
|
+
* Refuses (ok: false) when:
|
|
156
|
+
* - `slug` isn't a known row.
|
|
157
|
+
* - the row itself is 'running' or 'completed' — never touch live or
|
|
158
|
+
* shipped work.
|
|
159
|
+
* - any of the row's CURRENT dependsOn entries already resolved
|
|
160
|
+
* ('completed') — the row may already be scheduler-eligible, and
|
|
161
|
+
* rewriting its ordering out from under a resolved blocker risks
|
|
162
|
+
* resurrecting/racing already-finished work (see this module's header).
|
|
163
|
+
* - the proposed dependsOn would create a cycle.
|
|
164
|
+
*/
|
|
165
|
+
function computeDispositionRewrite({ slug, disposition, dependsOn, rows }) {
|
|
166
|
+
const row = rows.find((r) => r.slug === slug);
|
|
167
|
+
if (!row) return { ok: false, error: `PRD not found: ${slug}` };
|
|
168
|
+
if (row.status === 'running' || row.status === 'completed') {
|
|
169
|
+
return { ok: false, error: `cannot change disposition of a "${row.status}" PRD — it is no longer part of the open plan` };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const slugs = rows.map((r) => r.slug);
|
|
173
|
+
for (const dep of row.dependsOn ?? []) {
|
|
174
|
+
for (const resolved of resolveDepSlug(dep, slugs)) {
|
|
175
|
+
const depRow = rows.find((r) => r.slug === resolved);
|
|
176
|
+
if (depRow?.status === 'completed') {
|
|
177
|
+
return {
|
|
178
|
+
ok: false,
|
|
179
|
+
error: `refusing to rewrite dependsOn: blocker "${resolved}" has already completed — this PRD may ` +
|
|
180
|
+
'already be eligible to run; changing its ordering now risks resurrecting finished work',
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const newDependsOn = disposition === 'new-head' ? [] : Array.from(new Set(dependsOn ?? []));
|
|
187
|
+
if (newDependsOn.length && wouldCreateCycle(rows, slug, newDependsOn)) {
|
|
188
|
+
return { ok: false, error: `dependsOn ${JSON.stringify(newDependsOn)} would create a dependency cycle` };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return { ok: true, dependsOn: newDependsOn };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = {
|
|
195
|
+
isIncomplete,
|
|
196
|
+
resolveChainTerminals,
|
|
197
|
+
wouldCreateCycle,
|
|
198
|
+
computeDispositionRewrite,
|
|
199
|
+
};
|
|
@@ -77,8 +77,8 @@ function splitFrontmatter(raw) {
|
|
|
77
77
|
* never emitted, which is how `scheduler_update_prd` clears a dependency.
|
|
78
78
|
*/
|
|
79
79
|
|
|
80
|
-
const RECOGNIZED_KEYS = new Set(['title', 'cwd', 'estimateMinutes', 'parallelGroup', 'sourcePromptId', 'sourceTabId', 'tag', 'agentType', 'createdVia', 'issuedAt', 'dependsOn', 'quietMachine']);
|
|
81
|
-
const EMIT_ORDER = ['title', 'cwd', 'estimateMinutes', 'parallelGroup', 'sourcePromptId', 'sourceTabId', 'tag', 'agentType', 'createdVia', 'issuedAt', 'dependsOn', 'quietMachine'];
|
|
80
|
+
const RECOGNIZED_KEYS = new Set(['title', 'cwd', 'estimateMinutes', 'parallelGroup', 'sourcePromptId', 'sourceTabId', 'tag', 'agentType', 'createdVia', 'issuedAt', 'dependsOn', 'quietMachine', 'disposition']);
|
|
81
|
+
const EMIT_ORDER = ['title', 'cwd', 'estimateMinutes', 'parallelGroup', 'sourcePromptId', 'sourceTabId', 'tag', 'agentType', 'createdVia', 'issuedAt', 'dependsOn', 'quietMachine', 'disposition'];
|
|
82
82
|
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
83
83
|
|
|
84
84
|
function indentOf(line) {
|
|
@@ -179,6 +179,12 @@ function applyKey(fm, key, after) {
|
|
|
179
179
|
// a no-op line for the overwhelming majority of PRDs that omit it.
|
|
180
180
|
if (v === true) fm.quietMachine = true;
|
|
181
181
|
return;
|
|
182
|
+
case 'disposition':
|
|
183
|
+
// Wave-authoring decision ('append'/'new-head') — see
|
|
184
|
+
// src/renderer/lib/prdFrontmatter.ts's mirror of this field for the
|
|
185
|
+
// full rationale. Only these two values are recognized.
|
|
186
|
+
if (v === 'append' || v === 'new-head') fm.disposition = v;
|
|
187
|
+
return;
|
|
182
188
|
}
|
|
183
189
|
}
|
|
184
190
|
|