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
|
@@ -91,41 +91,104 @@ function reportExists(key, runsDir = RUNS_DIR) {
|
|
|
91
91
|
return false;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
// non-user-supplied strings. Commands containing these are marked unverifiable
|
|
96
|
-
// rather than running under a shell, since CLAUDE.md restricts shell:true to
|
|
97
|
-
// watchers.cjs and app:test-fire-hook only.
|
|
98
|
-
const SHELL_META_RE = /[|>&;<`]|\$[({]/;
|
|
94
|
+
const DEFAULT_GATE_TIMEOUT_MS = 300_000;
|
|
99
95
|
|
|
100
96
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* Commands containing shell metacharacters (pipe, redirect, subshell) are
|
|
107
|
-
* skipped — they cannot be run without shell:true which is prohibited here.
|
|
108
|
-
* The parser falls through to the next AC line in that case.
|
|
109
|
-
*
|
|
110
|
-
* Complexity: O(L) where L = number of lines in the body (not user-scaled;
|
|
111
|
-
* PRD bodies are bounded documents, typically < 200 lines).
|
|
112
|
-
*
|
|
113
|
-
* @param {string} prdBody PRD markdown with frontmatter already stripped.
|
|
114
|
-
* @returns {string|null}
|
|
97
|
+
* Quote-aware tokenizer for ONE command segment — no shell. Returns the argv
|
|
98
|
+
* tokens, or null when an unquoted shell metacharacter survives (pipe,
|
|
99
|
+
* redirect, `;`, lone `&`, backtick, `$(`/`${`) or a quote is unbalanced.
|
|
100
|
+
* Complexity: O(n) over the segment's characters.
|
|
115
101
|
*/
|
|
116
|
-
function
|
|
117
|
-
|
|
102
|
+
function tokenizeNoShell(seg) {
|
|
103
|
+
const tokens = [];
|
|
104
|
+
let cur = '';
|
|
105
|
+
let inTok = false;
|
|
106
|
+
let quote = null;
|
|
107
|
+
for (let i = 0; i < seg.length; i++) {
|
|
108
|
+
const c = seg[i];
|
|
109
|
+
if (quote) {
|
|
110
|
+
if (c === quote) quote = null;
|
|
111
|
+
else cur += c;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (c === '"' || c === "'") { quote = c; inTok = true; continue; }
|
|
115
|
+
if (/\s/.test(c)) {
|
|
116
|
+
if (inTok) { tokens.push(cur); cur = ''; inTok = false; }
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if ('|<>;&`'.includes(c) || (c === '$' && (seg[i + 1] === '(' || seg[i + 1] === '{'))) return null;
|
|
120
|
+
cur += c;
|
|
121
|
+
inTok = true;
|
|
122
|
+
}
|
|
123
|
+
if (quote) return null;
|
|
124
|
+
if (inTok) tokens.push(cur);
|
|
125
|
+
return tokens;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Split a command chain on `&&` outside quotes and backticks.
|
|
130
|
+
* Complexity: O(n).
|
|
131
|
+
*/
|
|
132
|
+
function splitOnAndAnd(text) {
|
|
133
|
+
const segs = [];
|
|
134
|
+
let cur = '';
|
|
135
|
+
let quote = null;
|
|
136
|
+
for (let i = 0; i < text.length; i++) {
|
|
137
|
+
const c = text[i];
|
|
138
|
+
if (quote) {
|
|
139
|
+
cur += c;
|
|
140
|
+
if (c === quote) quote = null;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (c === '"' || c === "'" || c === '`') { quote = c; cur += c; continue; }
|
|
144
|
+
if (c === '&' && text[i + 1] === '&') { segs.push(cur); cur = ''; i++; continue; }
|
|
145
|
+
cur += c;
|
|
146
|
+
}
|
|
147
|
+
segs.push(cur);
|
|
148
|
+
return segs;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Parse one `&&` chain into [{argv, timeoutMs, env, raw}]. Returns [] when any
|
|
153
|
+
* segment is empty or needs a shell — a half-parsed gate must never run.
|
|
154
|
+
* A leading `timeout N` (or `Ns`) token sets timeoutMs; leading literal
|
|
155
|
+
* `NAME=value` tokens become env (a `TMPDIR=` assignment is dropped — the
|
|
156
|
+
* shadow runner always supplies its own isolated TMPDIR; its value is
|
|
157
|
+
* typically the un-runnable `$(mktemp -d)`, which is handled here without a
|
|
158
|
+
* shell by simply never evaluating it).
|
|
159
|
+
*/
|
|
160
|
+
function parseChain(text) {
|
|
161
|
+
const out = [];
|
|
162
|
+
for (const seg of splitOnAndAnd(text)) {
|
|
163
|
+
const raw = seg.trim();
|
|
164
|
+
if (!raw) return [];
|
|
165
|
+
// A dropped TMPDIR=$(mktemp -d) prefix is the one substitution we accept.
|
|
166
|
+
const stripped = raw.replace(/^TMPDIR=\$\(mktemp -d\)\s+/, '');
|
|
167
|
+
const tokens = tokenizeNoShell(stripped);
|
|
168
|
+
if (!tokens || !tokens.length) return [];
|
|
169
|
+
const env = {};
|
|
170
|
+
while (tokens.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0])) {
|
|
171
|
+
const [k, ...rest] = tokens.shift().split('=');
|
|
172
|
+
if (k !== 'TMPDIR') env[k] = rest.join('=');
|
|
173
|
+
}
|
|
174
|
+
let timeoutMs = DEFAULT_GATE_TIMEOUT_MS;
|
|
175
|
+
if (tokens[0] === 'timeout' && /^\d+s?$/.test(tokens[1] || '')) {
|
|
176
|
+
timeoutMs = parseInt(tokens[1], 10) * 1000;
|
|
177
|
+
tokens.splice(0, 2);
|
|
178
|
+
}
|
|
179
|
+
if (!tokens.length) return [];
|
|
180
|
+
out.push({ argv: tokens, timeoutMs, env, raw });
|
|
181
|
+
}
|
|
182
|
+
return out;
|
|
183
|
+
}
|
|
118
184
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// immediately. Line-by-line parsing avoids that pitfall.
|
|
123
|
-
const lines = prdBody.split('\n');
|
|
185
|
+
/** Locate the `# Acceptance criteria` lines (whole body when the heading is absent). */
|
|
186
|
+
function acCandidateLines(body) {
|
|
187
|
+
const lines = body.split('\n');
|
|
124
188
|
let inAcSection = false;
|
|
125
189
|
let hasAcSection = false;
|
|
126
190
|
let acHeadingLevel = 0;
|
|
127
191
|
const acLines = [];
|
|
128
|
-
|
|
129
192
|
for (const line of lines) {
|
|
130
193
|
if (/^#+\s/i.test(line)) {
|
|
131
194
|
const level = line.match(/^(#+)/)[1].length;
|
|
@@ -134,42 +197,127 @@ function extractAcCommand(prdBody) {
|
|
|
134
197
|
hasAcSection = true;
|
|
135
198
|
acHeadingLevel = level;
|
|
136
199
|
} else if (inAcSection && level <= acHeadingLevel) {
|
|
137
|
-
// A sibling or parent heading ends the AC section;
|
|
138
|
-
// sub-headings (level > acHeadingLevel) stay inside it.
|
|
139
200
|
inAcSection = false;
|
|
140
201
|
}
|
|
141
202
|
continue;
|
|
142
203
|
}
|
|
143
204
|
if (inAcSection) acLines.push(line);
|
|
144
205
|
}
|
|
206
|
+
return hasAcSection ? acLines : lines;
|
|
207
|
+
}
|
|
145
208
|
|
|
146
|
-
|
|
147
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Read an explicit gate spec: frontmatter `gate:` (`none`, inline `[a, b]`, or
|
|
211
|
+
* a `- item` list) or a fenced ```gate block (one command chain per line).
|
|
212
|
+
* Returns { kind: 'none' } | { kind: 'commands', chains: string[] } | null.
|
|
213
|
+
*/
|
|
214
|
+
function readExplicitGate(prdText) {
|
|
215
|
+
const fmMatch = prdText.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
216
|
+
if (fmMatch) {
|
|
217
|
+
const fmLines = fmMatch[1].split(/\r?\n/);
|
|
218
|
+
for (let i = 0; i < fmLines.length; i++) {
|
|
219
|
+
const m = fmLines[i].match(/^gate:\s*(.*)$/);
|
|
220
|
+
if (!m) continue;
|
|
221
|
+
const rest = m[1].trim();
|
|
222
|
+
if (/^(['"]?)none\1$/i.test(rest)) return { kind: 'none' };
|
|
223
|
+
const chains = [];
|
|
224
|
+
if (rest.startsWith('[') && rest.endsWith(']')) {
|
|
225
|
+
// Inline list — items may hold commas inside quotes, so split quote-aware.
|
|
226
|
+
let cur = ''; let q = null;
|
|
227
|
+
for (const c of rest.slice(1, -1)) {
|
|
228
|
+
if (q) { if (c === q) q = null; else cur += c; continue; }
|
|
229
|
+
if (c === '"' || c === "'") { q = c; continue; }
|
|
230
|
+
if (c === ',') { chains.push(cur.trim()); cur = ''; continue; }
|
|
231
|
+
cur += c;
|
|
232
|
+
}
|
|
233
|
+
chains.push(cur.trim());
|
|
234
|
+
} else if (rest === '') {
|
|
235
|
+
for (let j = i + 1; j < fmLines.length; j++) {
|
|
236
|
+
const li = fmLines[j].match(/^\s+-\s+(.*)$/);
|
|
237
|
+
if (!li) break;
|
|
238
|
+
chains.push(li[1].trim().replace(/^(['"])(.*)\1$/, '$2'));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const kept = chains.filter(Boolean);
|
|
242
|
+
if (kept.length) return { kind: 'commands', chains: kept };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const fence = prdText.match(/^```gate[ \t]*\r?\n([\s\S]*?)^```/m);
|
|
246
|
+
if (fence) {
|
|
247
|
+
const chains = fence[1].split('\n').map((l) => l.trim()).filter((l) => l && !l.startsWith('#'));
|
|
248
|
+
if (chains.length === 1 && /^none$/i.test(chains[0])) return { kind: 'none' };
|
|
249
|
+
if (chains.length) return { kind: 'commands', chains };
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
148
253
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
254
|
+
/**
|
|
255
|
+
* Resolve a PRD's gate: explicit spec first (frontmatter `gate:` / ```gate
|
|
256
|
+
* fence), else the first acceptance-criteria line carrying a parseable
|
|
257
|
+
* `timeout N …` chain (backtick span preferred, else bare from the first
|
|
258
|
+
* `timeout N`). Accepts the PRD with or without frontmatter.
|
|
259
|
+
*
|
|
260
|
+
* @param {string} prdText
|
|
261
|
+
* @returns {{ source: 'none'|'explicit'|'ac-line'|'absent', sequence: Array<{argv:string[], timeoutMs:number, env:object, raw:string}> }}
|
|
262
|
+
*/
|
|
263
|
+
function resolveGate(prdText) {
|
|
264
|
+
if (!prdText || typeof prdText !== 'string') return { source: 'absent', sequence: [] };
|
|
265
|
+
const explicit = readExplicitGate(prdText);
|
|
266
|
+
if (explicit) {
|
|
267
|
+
if (explicit.kind === 'none') return { source: 'none', sequence: [] };
|
|
268
|
+
const sequence = [];
|
|
269
|
+
for (const chain of explicit.chains) {
|
|
270
|
+
const parsed = parseChain(chain);
|
|
271
|
+
if (!parsed.length) return { source: 'explicit', sequence: [] };
|
|
272
|
+
sequence.push(...parsed);
|
|
273
|
+
}
|
|
274
|
+
return { source: 'explicit', sequence };
|
|
275
|
+
}
|
|
276
|
+
const body = splitFrontmatter(prdText).body;
|
|
277
|
+
for (const line of acCandidateLines(body)) {
|
|
278
|
+
const backtickMatch = line.match(/`([^`]*\btimeout\s+\d+\s[^`]*)`/i);
|
|
152
279
|
if (backtickMatch) {
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
280
|
+
const seq = parseChain(backtickMatch[1]);
|
|
281
|
+
if (seq.length) return { source: 'ac-line', sequence: seq };
|
|
155
282
|
}
|
|
156
|
-
|
|
157
|
-
//
|
|
158
|
-
// Trim trailing all-lowercase-alpha tokens (prose words like "passes",
|
|
159
|
-
// "and", "the") while keeping at least 4 tokens (timeout, N, binary,
|
|
160
|
-
// first-arg). This prevents over-matching into prose that follows the
|
|
161
|
-
// command on the same AC line (e.g. "timeout 60 npm test and verify").
|
|
283
|
+
// Bare fallback: from the first `timeout N` to end of line, dropping
|
|
284
|
+
// trailing all-lowercase prose words (keeping ≥ 4 tokens, as before).
|
|
162
285
|
const rawMatch = line.match(/\btimeout\s+\d+\s+\S+(?:\s+\S+)*/);
|
|
163
286
|
if (rawMatch) {
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
if (
|
|
287
|
+
const segs = splitOnAndAnd(rawMatch[0]);
|
|
288
|
+
const tokens = segs[segs.length - 1].trim().split(/\s+/);
|
|
289
|
+
while (tokens.length > 4 && /^[a-z]+$/.test(tokens[tokens.length - 1])) tokens.pop();
|
|
290
|
+
segs[segs.length - 1] = tokens.join(' ');
|
|
291
|
+
const seq = parseChain(segs.join('&&'));
|
|
292
|
+
if (seq.length) return { source: 'ac-line', sequence: seq };
|
|
170
293
|
}
|
|
171
294
|
}
|
|
172
|
-
return
|
|
295
|
+
return { source: 'absent', sequence: [] };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* The gate as an ordered list of no-shell commands: [{argv, timeoutMs}, …].
|
|
300
|
+
* Empty when there is no parseable gate or the PRD opted out with `gate: none`
|
|
301
|
+
* (resolveGate distinguishes the two). Complexity: O(L) over the PRD's lines.
|
|
302
|
+
*
|
|
303
|
+
* @param {string} prdBody PRD markdown (frontmatter optional).
|
|
304
|
+
* @returns {Array<{argv:string[], timeoutMs:number, env:object, raw:string}>}
|
|
305
|
+
*/
|
|
306
|
+
function extractAcSequence(prdBody) {
|
|
307
|
+
return resolveGate(prdBody).sequence;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* The single-command view of the gate, as the original `timeout NNN cmd …`
|
|
312
|
+
* string, or null when the gate is absent or is a multi-command chain
|
|
313
|
+
* (reverifyAc runs one command; the chain is the shadow runner's job).
|
|
314
|
+
*
|
|
315
|
+
* @param {string} prdBody PRD markdown with frontmatter already stripped.
|
|
316
|
+
* @returns {string|null}
|
|
317
|
+
*/
|
|
318
|
+
function extractAcCommand(prdBody) {
|
|
319
|
+
const seq = extractAcSequence(prdBody);
|
|
320
|
+
return seq.length === 1 && seq[0].raw.startsWith('timeout') ? seq[0].raw : null;
|
|
173
321
|
}
|
|
174
322
|
|
|
175
323
|
/**
|
|
@@ -217,8 +365,8 @@ function reverifyAc(job, { timeoutMs = 60_000, prdsDir } = {}) {
|
|
|
217
365
|
const cmd = extractAcCommand(prdBody);
|
|
218
366
|
if (!cmd) return Promise.resolve(unverifiable());
|
|
219
367
|
|
|
220
|
-
// Simple whitespace split —
|
|
221
|
-
// commands that would need a shell. Paths with spaces are not expected in AC
|
|
368
|
+
// Simple whitespace split — extractAcCommand already excludes
|
|
369
|
+
// commands that would need a shell (tokenizeNoShell). Paths with spaces are not expected in AC
|
|
222
370
|
// commands (PRD authoring convention: use relative paths from cwd).
|
|
223
371
|
const argv = cmd.trim().split(/\s+/);
|
|
224
372
|
if (argv.length < 2) return Promise.resolve(unverifiable());
|
|
@@ -231,7 +379,7 @@ function reverifyAc(job, { timeoutMs = 60_000, prdsDir } = {}) {
|
|
|
231
379
|
child = spawn(argv[0], argv.slice(1), {
|
|
232
380
|
cwd: job.cwd,
|
|
233
381
|
stdio: 'ignore',
|
|
234
|
-
// No shell:true —
|
|
382
|
+
// No shell:true — tokenizeNoShell rejects commands with shell metacharacters.
|
|
235
383
|
});
|
|
236
384
|
} catch (err) {
|
|
237
385
|
resolve(unverifiable());
|
|
@@ -532,6 +680,99 @@ function writeReport(key, { acResults = [], riskFlags = [], runsDir } = {}) {
|
|
|
532
680
|
return reportPath;
|
|
533
681
|
}
|
|
534
682
|
|
|
683
|
+
|
|
684
|
+
// ─── Shadow gate runner ────────────────────────────────────────────────────────
|
|
685
|
+
// Runs a PRD's parsed gate sequence WITHOUT deciding anything: the caller
|
|
686
|
+
// records the outcome next to the verdict. Not a claude -p run, so it takes no
|
|
687
|
+
// slot from sessionSlots; instead a single module-level flag keeps at most one
|
|
688
|
+
// shadow gate in flight machine-wide (the scheduler is one process).
|
|
689
|
+
let gateInFlight = false;
|
|
690
|
+
const OUTPUT_TAIL_CHARS = 1000;
|
|
691
|
+
|
|
692
|
+
function runOneGateCommand(cmd, { cwd, env }) {
|
|
693
|
+
return new Promise((resolve) => {
|
|
694
|
+
const startNs = process.hrtime.bigint();
|
|
695
|
+
const ms = () => Math.round(Number(process.hrtime.bigint() - startNs) / 1e6);
|
|
696
|
+
const label = cmd.argv.join(' ');
|
|
697
|
+
let child;
|
|
698
|
+
try {
|
|
699
|
+
child = spawn(cmd.argv[0], cmd.argv.slice(1), {
|
|
700
|
+
cwd,
|
|
701
|
+
env: { ...env, ...cmd.env },
|
|
702
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
703
|
+
// No shell:true — the sequence was tokenized by tokenizeNoShell.
|
|
704
|
+
});
|
|
705
|
+
} catch {
|
|
706
|
+
resolve({ cmd: label, status: 'unavailable', code: null, ms: ms(), timedOut: false, tail: '' });
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
let tail = '';
|
|
710
|
+
const onData = (d) => { tail = (tail + d).slice(-OUTPUT_TAIL_CHARS); };
|
|
711
|
+
child.stdout.on('data', onData);
|
|
712
|
+
child.stderr.on('data', onData);
|
|
713
|
+
let settled = false;
|
|
714
|
+
let timedOut = false;
|
|
715
|
+
let escalate;
|
|
716
|
+
const killTimer = setTimeout(() => {
|
|
717
|
+
timedOut = true;
|
|
718
|
+
try { child.kill('SIGTERM'); } catch { /* already dead */ }
|
|
719
|
+
escalate = setTimeout(() => {
|
|
720
|
+
try { child.kill('SIGKILL'); } catch { /* race */ }
|
|
721
|
+
}, 5_000);
|
|
722
|
+
if (escalate.unref) escalate.unref();
|
|
723
|
+
}, cmd.timeoutMs);
|
|
724
|
+
if (killTimer.unref) killTimer.unref();
|
|
725
|
+
const finish = (r) => {
|
|
726
|
+
if (settled) return;
|
|
727
|
+
settled = true;
|
|
728
|
+
clearTimeout(killTimer);
|
|
729
|
+
clearTimeout(escalate);
|
|
730
|
+
resolve({ cmd: label, ms: ms(), timedOut, tail, ...r });
|
|
731
|
+
};
|
|
732
|
+
child.on('error', () => finish({ status: 'unavailable', code: null }));
|
|
733
|
+
child.on('close', (code) => {
|
|
734
|
+
const exitCode = typeof code === 'number' ? code : -1;
|
|
735
|
+
finish({ status: exitCode === 0 ? 'pass' : 'fail', code: exitCode });
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Run a gate sequence (extractAcSequence output) in `cwd` with `&&` semantics:
|
|
742
|
+
* stop at the first non-pass. Each run gets its own isolated TMPDIR (mkdtemp,
|
|
743
|
+
* removed afterwards) and CI=1, so a suite that sweeps its temp root can never
|
|
744
|
+
* touch a live one.
|
|
745
|
+
*
|
|
746
|
+
* @param {Array<{argv:string[], timeoutMs:number, env?:object}>} sequence
|
|
747
|
+
* @param {{ cwd: string }} opts
|
|
748
|
+
* @returns {Promise<{ status: 'green'|'red'|'unavailable'|'busy', results: object[] }>}
|
|
749
|
+
* 'busy' = another shadow gate is in flight; nothing ran, nothing to record.
|
|
750
|
+
*/
|
|
751
|
+
async function runGateSequence(sequence, { cwd }) {
|
|
752
|
+
if (gateInFlight) return { status: 'busy', results: [] };
|
|
753
|
+
if (!Array.isArray(sequence) || !sequence.length) return { status: 'unavailable', results: [] };
|
|
754
|
+
try { fs.statSync(cwd); } catch { return { status: 'unavailable', results: [] }; }
|
|
755
|
+
gateInFlight = true;
|
|
756
|
+
let tmp = null;
|
|
757
|
+
try {
|
|
758
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-gate-shadow-'));
|
|
759
|
+
const env = { ...process.env, TMPDIR: tmp, CI: '1' };
|
|
760
|
+
const results = [];
|
|
761
|
+
for (const cmd of sequence) {
|
|
762
|
+
const r = await runOneGateCommand(cmd, { cwd, env });
|
|
763
|
+
results.push(r);
|
|
764
|
+
if (r.status === 'unavailable') return { status: 'unavailable', results };
|
|
765
|
+
if (r.status === 'fail') return { status: 'red', results };
|
|
766
|
+
}
|
|
767
|
+
return { status: 'green', results };
|
|
768
|
+
} catch {
|
|
769
|
+
return { status: 'unavailable', results: [] };
|
|
770
|
+
} finally {
|
|
771
|
+
gateInFlight = false;
|
|
772
|
+
if (tmp) { try { fs.rmSync(tmp, { recursive: true, force: true }); } catch { /* best-effort */ } }
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
535
776
|
const WATERMARK_FILENAME = '.dod-watermark.json';
|
|
536
777
|
|
|
537
778
|
/**
|
|
@@ -573,6 +814,9 @@ module.exports = {
|
|
|
573
814
|
reportPathFor,
|
|
574
815
|
reportExists,
|
|
575
816
|
extractAcCommand,
|
|
817
|
+
extractAcSequence,
|
|
818
|
+
resolveGate,
|
|
819
|
+
runGateSequence,
|
|
576
820
|
extractSection,
|
|
577
821
|
reverifyAc,
|
|
578
822
|
reverifyBatch,
|