claude-code-session-manager 0.87.0 → 0.88.1
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-DyLWzZDf.js → AgentLibrary-kQF8_wAw.js} +1 -1
- package/dist/assets/{DataModel--mISIJ6h.js → DataModel-CY_mMnsr.js} +1 -1
- package/dist/assets/{History-C2ahUXTg.js → History-Sji2brb0.js} +1 -1
- package/dist/assets/{Hooks-BiC6oyR2.js → Hooks-CtqpO-p5.js} +1 -1
- package/dist/assets/{HostBilko-BPleEOld.js → HostBilko-DN0ydOCr.js} +1 -1
- package/dist/assets/{Library-Dc8Qst1R.js → Library-CoiLZTKh.js} +1 -1
- package/dist/assets/{ListDetail-DIXh-OLX.js → ListDetail-CmqiQ_io.js} +1 -1
- package/dist/assets/{MarkdownEditor-C90bkLXK.js → MarkdownEditor-HPoNeKhT.js} +1 -1
- package/dist/assets/{McpServers-DqcbLOLZ.js → McpServers-Bj1X3_NT.js} +1 -1
- package/dist/assets/{Memory-CW62MXlh.js → Memory-1PKjsM3b.js} +1 -1
- package/dist/assets/{Panel-Bw1FhRuF.js → Panel-I1s6ghPo.js} +1 -1
- package/dist/assets/{Permissions-BcUC-5y8.js → Permissions-BhiiZjHQ.js} +1 -1
- package/dist/assets/{Plugins-BnKx9flD.js → Plugins-gv3_fkPX.js} +2 -2
- package/dist/assets/{ProvenanceBadge-Bw5vNVPT.js → ProvenanceBadge-BGcgBd8V.js} +1 -1
- package/dist/assets/{SaveBar-CWr0O_w-.js → SaveBar-BGr9eZ4g.js} +1 -1
- package/dist/assets/{Scheduler-DYdLuUqq.js → Scheduler-Bdo_awPq.js} +7 -7
- package/dist/assets/{ScopeSwitcher-CrBLbg8s.js → ScopeSwitcher-ukl0qWaA.js} +1 -1
- package/dist/assets/{Settings-DluB-vN1.js → Settings-DJkFj22G.js} +1 -1
- package/dist/assets/{SkillReferenceGraph-CHLSseay.js → SkillReferenceGraph-0t1Qblp6.js} +1 -1
- package/dist/assets/{Skills-gNdo_HNK.js → Skills-CeVdBGE-.js} +1 -1
- package/dist/assets/{SystemPrompt-Cru05-Ia.js → SystemPrompt-CfKvNHi3.js} +1 -1
- package/dist/assets/{TagLibrary-DNHY0xou.js → TagLibrary-DAzNaUPd.js} +1 -1
- package/dist/assets/{TiptapBody-I4lmbCgP.js → TiptapBody--S_rGXoA.js} +1 -1
- package/dist/assets/{Toggle-bWMHjmRh.js → Toggle-Dszm0xnp.js} +1 -1
- package/dist/assets/{index-DV3PorRY.css → index-BHTX4OTc.css} +1 -1
- package/dist/assets/{index-fc_JjdxL.js → index-Dp4Rc--q.js} +356 -356
- package/dist/assets/{settingsSchema-BfhtZnGD.js → settingsSchema-BLbssMYo.js} +1 -1
- 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 +10 -13
- 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 +28 -71
- package/src/main/__tests__/bilkoHost-integration.test.cjs +3 -3
- 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 +2 -2
- 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 +15 -1
- package/src/main/__tests__/health-queue-dispatch.test.cjs +58 -7
- package/src/main/__tests__/health-tick-liveness.test.cjs +27 -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__/opsErrorLogTelemetryTap.test.cjs +25 -1
- package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +33 -3
- 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__/prdLocationsArchived.test.cjs +20 -13
- 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 +9 -9
- package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +117 -20
- package/src/main/__tests__/queueHistory.test.cjs +2 -2
- package/src/main/__tests__/rateLimitPollerStreak.test.cjs +38 -3
- 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 +2 -2
- 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 +78 -97
- 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 +46 -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-launch-failure.test.cjs +3 -5
- package/src/main/__tests__/scheduler-looks-done.test.cjs +26 -7
- 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-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 +23 -4
- 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 +81 -1
- package/src/main/__tests__/scheduler-stall-per-project.test.cjs +14 -0
- package/src/main/__tests__/scheduler-starve-escalation.test.cjs +4 -4
- 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 +37 -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 +4 -2
- package/src/main/config.cjs +2 -3
- package/src/main/docEdit.cjs +4 -2
- package/src/main/health.cjs +276 -52
- package/src/main/heapSnapshot.cjs +2 -2
- package/src/main/historyAggregator.cjs +1 -1
- package/src/main/index.cjs +61 -10
- package/src/main/ipcSchemas.cjs +6 -17
- package/src/main/lib/__tests__/auditLog.test.cjs +38 -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 +1 -1
- package/src/main/lib/__tests__/dispatchLoop.test.cjs +63 -0
- package/src/main/lib/__tests__/gateFixtures.json +20 -0
- package/src/main/lib/__tests__/gitWorktree.test.cjs +8 -1
- 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__/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__/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 +61 -0
- package/src/main/lib/__tests__/watchdog-helpers.test.cjs +63 -0
- package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +73 -0
- package/src/main/lib/activeIndexRebuild.cjs +1 -3
- package/src/main/lib/activeSessions.cjs +20 -88
- package/src/main/lib/adoptedRunSupervisor.cjs +136 -0
- package/src/main/lib/agentModelResolve.cjs +33 -1
- package/src/main/lib/agentPersonaSchema.cjs +2 -2
- package/src/main/lib/auditLog.cjs +30 -5
- 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/dispatchLoop.cjs +40 -0
- package/src/main/lib/effectiveModelInfo.cjs +9 -10
- package/src/main/lib/ephemeralCwd.cjs +7 -28
- package/src/main/lib/gitWorktree.cjs +95 -8
- package/src/main/lib/guardShims.cjs +3 -3
- package/src/main/lib/historyRollup.cjs +6 -7
- package/src/main/lib/instanceLock.cjs +32 -5
- package/src/main/lib/jobSupervisorRecord.cjs +147 -0
- package/src/main/lib/jobWorktreeBootLive.cjs +9 -5
- package/src/main/lib/localAdminHttp.cjs +9 -27
- package/src/main/lib/mcpToolCatalog.cjs +29 -77
- package/src/main/lib/opsOwnership.cjs +27 -19
- package/src/main/lib/prdAuthoringSeed.cjs +36 -0
- package/src/main/lib/prdLocations.cjs +48 -1
- 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/queueHistory.cjs +8 -7
- package/src/main/lib/queueStore.cjs +57 -37
- package/src/main/lib/quietMachineLease.cjs +19 -2
- 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 +2 -2
- package/src/main/lib/scheduleJobTransitions.cjs +29 -2
- package/src/main/lib/schedulerBatch.cjs +27 -2
- 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 +53 -6
- package/src/main/lib/watchdogHelpers.cjs +70 -37
- 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.cjs +1607 -383
- 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/usage.cjs +126 -62
- package/src/preload/api.d.ts +18 -64
- package/src/preload/index.cjs +2 -4
- package/src/seed/agents/project-home-builder.md +31 -48
- package/screenshots/.gitkeep +0 -0
- package/screenshots/README-screenshots.md +0 -13
- 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
- package/web/README.md +0 -41
- package/web/project-pages/logic/dist/logic.cjs +0 -4709
- package/web/project-pages/render.cjs +0 -70
- package/web/project-pages/renderer/dist/renderer.cjs +0 -18900
- package/web/project-pages/validate-summary.cjs +0 -62
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* audit-ops-hygiene.cjs — one-off (re-runnable) investigation for
|
|
4
|
+
* session-manager-operations/architecture/ops-maintenance-protocol.md
|
|
5
|
+
* Patterns C and D. Read-only: never moves, archives, or deletes anything.
|
|
6
|
+
*
|
|
7
|
+
* Pattern C — legacy flat `scheduler/prds/` layout: reports the current
|
|
8
|
+
* top-level file count vs `scheduler/prds-archived/`, and whether
|
|
9
|
+
* `scheduler/state/queue.json` still references any top-level (non
|
|
10
|
+
* epic-scoped) prdPath, to distinguish "stuck legacy debt" from
|
|
11
|
+
* "legitimately in-flight, already draining via normal completion."
|
|
12
|
+
*
|
|
13
|
+
* Pattern D — orphaned top-level `prompt-sessions/*.json` files (no
|
|
14
|
+
* matching `scheduler/epics/<id>/` dir): for each, inspects its own event
|
|
15
|
+
* chain for `prd_created` events, then — since a dispatched PRD auto-mints
|
|
16
|
+
* its OWN epic dir via epicMint.cjs, with a slug distinct from the
|
|
17
|
+
* originating prompt-session id — searches every PRD `.md` under
|
|
18
|
+
* `scheduler/` for a `sourcePromptId:` frontmatter match before concluding
|
|
19
|
+
* anything is actually lost.
|
|
20
|
+
*
|
|
21
|
+
* Pattern E — PRDs authored outside the sanctioned `scheduler_create_prd` MCP
|
|
22
|
+
* tool (the /develop skill's manual-write fallback is meant to be a rare,
|
|
23
|
+
* flagged last resort — see CLAUDE.md's "PRD authoring is API-only"). Every
|
|
24
|
+
* API-created PRD gets a `prd_create` record in the machine-wide audit log
|
|
25
|
+
* (`~/.claude/session-manager/audit-log.jsonl`, `src/main/lib/auditLog.cjs`)
|
|
26
|
+
* keyed by cwd+slug. This check is deliberately narrow: it only inspects PRD
|
|
27
|
+
* `.md` files `git status` reports as UNTRACKED (never committed yet) — a
|
|
28
|
+
* PRD's file mtime is USELESS as a "recently authored" signal because these
|
|
29
|
+
* files are committed to the target repo, so any `git clone`/`checkout`/
|
|
30
|
+
* `git clean` resets every tracked PRD's mtime to "now" regardless of when it
|
|
31
|
+
* was actually authored (a first draft of this check used mtime and would
|
|
32
|
+
* have false-positived on nearly every already-committed PRD after a fresh
|
|
33
|
+
* checkout). An untracked file, by contrast, really was just created in this
|
|
34
|
+
* working tree. A cwd that isn't a git repo, or has no untracked PRDs, is
|
|
35
|
+
* reported clean — this check simply doesn't apply there. Reported as a
|
|
36
|
+
* hygiene finding, never blocked, exactly like Patterns C/D.
|
|
37
|
+
*
|
|
38
|
+
* Usage: node scripts/audit-ops-hygiene.cjs [cwd] (defaults to cwd)
|
|
39
|
+
*/
|
|
40
|
+
'use strict';
|
|
41
|
+
|
|
42
|
+
const fs = require('node:fs');
|
|
43
|
+
const path = require('node:path');
|
|
44
|
+
const { execFileSync } = require('node:child_process');
|
|
45
|
+
|
|
46
|
+
const { auditLogPath } = require('../src/main/lib/schedulerPaths.cjs');
|
|
47
|
+
const projectCwd = process.argv[2] || process.cwd();
|
|
48
|
+
const OPS_ROOT = path.join(projectCwd, 'session-manager-operations');
|
|
49
|
+
const SESSIONS_DIR = path.join(OPS_ROOT, 'prompt-sessions');
|
|
50
|
+
const SCHEDULER_DIR = path.join(OPS_ROOT, 'scheduler');
|
|
51
|
+
const EPICS_DIR = path.join(SCHEDULER_DIR, 'epics');
|
|
52
|
+
const FLAT_PRDS_DIR = path.join(SCHEDULER_DIR, 'prds');
|
|
53
|
+
const ARCHIVED_PRDS_DIR = path.join(SCHEDULER_DIR, 'prds-archived');
|
|
54
|
+
const QUEUE_PATH = path.join(SCHEDULER_DIR, 'state', 'queue.json');
|
|
55
|
+
// Override hook for tests only — production always uses the real path.
|
|
56
|
+
function resolveAuditLogPath() {
|
|
57
|
+
return process.env.SM_AUDIT_LOG_PATH_OVERRIDE || auditLogPath();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function readJson(p, fallback) {
|
|
61
|
+
try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return fallback; }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function listDir(p) {
|
|
65
|
+
try { return fs.readdirSync(p, { withFileTypes: true }); } catch { return []; }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function auditPatternC() {
|
|
69
|
+
const flatMdFiles = listDir(FLAT_PRDS_DIR).filter((e) => e.isFile() && e.name.endsWith('.md')).map((e) => e.name);
|
|
70
|
+
const archivedCount = listDir(ARCHIVED_PRDS_DIR).filter((e) => e.isFile() && e.name.endsWith('.md')).length;
|
|
71
|
+
const queue = readJson(QUEUE_PATH, { jobs: [] });
|
|
72
|
+
const jobs = Array.isArray(queue.jobs) ? queue.jobs : [];
|
|
73
|
+
const flatQueueRefs = jobs.filter((j) => typeof j.prdPath === 'string' && j.prdPath.includes(`${path.sep}prds${path.sep}`) && !j.prdPath.includes(`${path.sep}epics${path.sep}`));
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
flatTopLevelMdCount: flatMdFiles.length,
|
|
77
|
+
flatTopLevelMdFiles: flatMdFiles,
|
|
78
|
+
archivedCount,
|
|
79
|
+
queueJobsTotal: jobs.length,
|
|
80
|
+
queueJobsReferencingFlatDir: flatQueueRefs.map((j) => ({ slug: j.slug, status: j.status, prdPath: j.prdPath })),
|
|
81
|
+
verdict: flatMdFiles.length === 0
|
|
82
|
+
? 'RESOLVED: flat prds/ is currently empty of .md files — consolidation/normal completion has fully drained it.'
|
|
83
|
+
: (flatQueueRefs.length > 0
|
|
84
|
+
? 'IN-FLIGHT: remaining flat files are referenced by live queue jobs — legitimate in-flight work, not stuck debt.'
|
|
85
|
+
: 'INVESTIGATE: remaining flat files have no live queue reference — check history for stuck/abandoned status before treating as debt.'),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const SOURCE_PROMPT_RE = /^sourcePromptId:\s*(.+?)\s*$/m;
|
|
90
|
+
|
|
91
|
+
function findPrdFilesForEpic(epicId) {
|
|
92
|
+
const hits = [];
|
|
93
|
+
function walk(dir) {
|
|
94
|
+
for (const ent of listDir(dir)) {
|
|
95
|
+
const full = path.join(dir, ent.name);
|
|
96
|
+
if (ent.isDirectory()) { walk(full); continue; }
|
|
97
|
+
if (!ent.name.endsWith('.md')) continue;
|
|
98
|
+
let head;
|
|
99
|
+
try { head = fs.readFileSync(full, 'utf8').slice(0, 2000); } catch { continue; }
|
|
100
|
+
const m = SOURCE_PROMPT_RE.exec(head);
|
|
101
|
+
if (m && m[1] === epicId) hits.push(full);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
walk(SCHEDULER_DIR);
|
|
105
|
+
return hits;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function auditPatternD() {
|
|
109
|
+
const toplevel = listDir(SESSIONS_DIR)
|
|
110
|
+
.filter((e) => e.isFile() && e.name.endsWith('.json') && e.name !== 'active-index.json')
|
|
111
|
+
.map((e) => e.name.slice(0, -'.json'.length))
|
|
112
|
+
.sort();
|
|
113
|
+
const epicDirs = new Set(listDir(EPICS_DIR).filter((e) => e.isDirectory()).map((e) => e.name));
|
|
114
|
+
|
|
115
|
+
const neverStarted = [];
|
|
116
|
+
const accountedForElsewhere = [];
|
|
117
|
+
const dataLoss = [];
|
|
118
|
+
const unreadable = [];
|
|
119
|
+
|
|
120
|
+
for (const epicId of toplevel) {
|
|
121
|
+
if (epicDirs.has(epicId)) continue; // has a matching epics/ dir — not orphaned
|
|
122
|
+
|
|
123
|
+
const data = readJson(path.join(SESSIONS_DIR, `${epicId}.json`), null);
|
|
124
|
+
if (!data) { unreadable.push(epicId); continue; }
|
|
125
|
+
|
|
126
|
+
const events = Array.isArray(data.events) ? data.events : [];
|
|
127
|
+
const prdEvents = events.filter((e) => e && e.kind === 'prd_created');
|
|
128
|
+
const session = data.session || {};
|
|
129
|
+
const record = {
|
|
130
|
+
id: epicId,
|
|
131
|
+
status: session.status,
|
|
132
|
+
goalText: (session.goalText || '').slice(0, 80),
|
|
133
|
+
prdCreatedCount: prdEvents.length,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (prdEvents.length === 0) { neverStarted.push(record); continue; }
|
|
137
|
+
|
|
138
|
+
const found = findPrdFilesForEpic(epicId);
|
|
139
|
+
if (found.length > 0) {
|
|
140
|
+
record.resolvedEpicDirs = [...new Set(found
|
|
141
|
+
.filter((f) => f.startsWith(EPICS_DIR + path.sep))
|
|
142
|
+
.map((f) => path.relative(EPICS_DIR, f).split(path.sep)[0]))];
|
|
143
|
+
accountedForElsewhere.push(record);
|
|
144
|
+
} else {
|
|
145
|
+
dataLoss.push(record);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
toplevelCount: toplevel.length,
|
|
151
|
+
epicDirsCount: epicDirs.size,
|
|
152
|
+
orphanedCount: toplevel.length - [...epicDirs].filter((d) => toplevel.includes(d)).length,
|
|
153
|
+
neverStarted,
|
|
154
|
+
accountedForElsewhere,
|
|
155
|
+
dataLoss,
|
|
156
|
+
unreadable,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Every `prd_create` audit event's `${cwd}::${slug}` key. */
|
|
161
|
+
function readPrdCreateAuditKeys() {
|
|
162
|
+
const keys = new Set();
|
|
163
|
+
let lines;
|
|
164
|
+
try { lines = fs.readFileSync(resolveAuditLogPath(), 'utf8').split('\n'); } catch { return keys; }
|
|
165
|
+
for (const line of lines) {
|
|
166
|
+
if (!line.trim()) continue;
|
|
167
|
+
let rec;
|
|
168
|
+
try { rec = JSON.parse(line); } catch { continue; }
|
|
169
|
+
if (rec?.kind === 'prd_create' && rec?.cwd && rec?.slug) {
|
|
170
|
+
keys.add(`${rec.cwd}::${rec.slug}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return keys;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* PRD `.md` files `git status --porcelain` reports as untracked (`??`),
|
|
178
|
+
* scoped to `session-manager-operations/scheduler/**\/prds/`. Returns null
|
|
179
|
+
* when `projectCwd` isn't a git repo (or `git` isn't available) — the
|
|
180
|
+
* caller then reports "not applicable" rather than a false CLEAN, since an
|
|
181
|
+
* already-committed bypass wouldn't show up here at all.
|
|
182
|
+
*/
|
|
183
|
+
function listUntrackedPrdFiles() {
|
|
184
|
+
let out;
|
|
185
|
+
try {
|
|
186
|
+
out = execFileSync('git', ['status', '--porcelain', '--untracked-files=all', '--', 'session-manager-operations/scheduler'], {
|
|
187
|
+
cwd: projectCwd,
|
|
188
|
+
encoding: 'utf8',
|
|
189
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
190
|
+
});
|
|
191
|
+
} catch {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
const hits = [];
|
|
195
|
+
for (const line of out.split('\n')) {
|
|
196
|
+
if (!line.startsWith('?? ')) continue;
|
|
197
|
+
const rel = line.slice(3).trim();
|
|
198
|
+
if (!rel.endsWith('.md')) continue;
|
|
199
|
+
if (path.basename(path.dirname(rel)) !== 'prds') continue; // excludes prds-archived/
|
|
200
|
+
hits.push(path.join(projectCwd, rel));
|
|
201
|
+
}
|
|
202
|
+
return hits;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function auditPatternE() {
|
|
206
|
+
const untracked = listUntrackedPrdFiles();
|
|
207
|
+
if (untracked === null) {
|
|
208
|
+
return {
|
|
209
|
+
applicable: false,
|
|
210
|
+
checkedCount: 0,
|
|
211
|
+
unattributedCount: 0,
|
|
212
|
+
unattributed: [],
|
|
213
|
+
verdict: 'NOT APPLICABLE: target cwd is not a git repo (or git is unavailable) — cannot distinguish freshly-authored PRDs from committed history.',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const keys = readPrdCreateAuditKeys();
|
|
218
|
+
const unattributed = [];
|
|
219
|
+
for (const file of untracked) {
|
|
220
|
+
const slug = path.basename(file, '.md');
|
|
221
|
+
const key = `${projectCwd}::${slug}`;
|
|
222
|
+
if (!keys.has(key)) {
|
|
223
|
+
unattributed.push({ file: path.relative(SCHEDULER_DIR, file), slug });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
applicable: true,
|
|
229
|
+
checkedCount: untracked.length,
|
|
230
|
+
unattributedCount: unattributed.length,
|
|
231
|
+
unattributed,
|
|
232
|
+
verdict: unattributed.length === 0
|
|
233
|
+
? 'CLEAN: every untracked (not-yet-committed) PRD has a matching prd_create record.'
|
|
234
|
+
: 'INVESTIGATE: untracked PRD(s) with no matching prd_create audit event — likely hand-authored via the /develop manual-write fallback (bypassing scheduler_create_prd). Confirm the bypass was reported and verify the file by hand.',
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Pattern F — referential-integrity report for the Agent/WorkType/Epic/PRD/Job
|
|
240
|
+
* ERD's unvalidated-string foreign keys (`PromptSession.agentType` -> a
|
|
241
|
+
* persona file, `PromptSession.tag` -> the WorkType union, queue-row
|
|
242
|
+
* `epicId`/`sourcePromptId` -> an Epic). "Throw on write, report on read":
|
|
243
|
+
* epicMint.cjs's ensureEpic refuses to MINT a bad reference; this pass only
|
|
244
|
+
* REPORTS references that were valid at creation and later went dangling
|
|
245
|
+
* (persona renamed/deleted, Epic archived) — that is legitimate history, not
|
|
246
|
+
* something this script repairs. Read-only, same as every other pattern here.
|
|
247
|
+
*/
|
|
248
|
+
function auditPatternF() {
|
|
249
|
+
const { WORK_TYPES } = require('../src/main/lib/workTypeLibrary.cjs');
|
|
250
|
+
const { personaFileExists } = require('../src/main/lib/epicMint.cjs');
|
|
251
|
+
|
|
252
|
+
const index = readJson(path.join(SESSIONS_DIR, 'active-index.json'), null);
|
|
253
|
+
const sessions = index && typeof index.sessions === 'object' && index.sessions ? index.sessions : {};
|
|
254
|
+
|
|
255
|
+
const danglingAgentType = [];
|
|
256
|
+
const invalidTag = [];
|
|
257
|
+
for (const [epicId, session] of Object.entries(sessions)) {
|
|
258
|
+
if (!session || typeof session !== 'object') continue;
|
|
259
|
+
if (session.agentType && !personaFileExists(projectCwd, session.agentType)) {
|
|
260
|
+
danglingAgentType.push({ epicId, agentType: session.agentType });
|
|
261
|
+
}
|
|
262
|
+
if (session.tag && !WORK_TYPES.includes(session.tag)) {
|
|
263
|
+
invalidTag.push({ epicId, tag: session.tag });
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const queue = readJson(QUEUE_PATH, { jobs: [] });
|
|
268
|
+
const jobs = Array.isArray(queue.jobs) ? queue.jobs : [];
|
|
269
|
+
const danglingJobRefs = [];
|
|
270
|
+
for (const job of jobs) {
|
|
271
|
+
const jobId = job.slug ?? null;
|
|
272
|
+
if (job.epicId && !Object.prototype.hasOwnProperty.call(sessions, job.epicId)) {
|
|
273
|
+
danglingJobRefs.push({ jobId, field: 'epicId', value: job.epicId });
|
|
274
|
+
}
|
|
275
|
+
if (job.sourcePromptId && !Object.prototype.hasOwnProperty.call(sessions, job.sourcePromptId)) {
|
|
276
|
+
danglingJobRefs.push({ jobId, field: 'sourcePromptId', value: job.sourcePromptId });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const totalFindings = danglingAgentType.length + invalidTag.length + danglingJobRefs.length;
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
danglingAgentTypeCount: danglingAgentType.length,
|
|
284
|
+
danglingAgentType,
|
|
285
|
+
invalidTagCount: invalidTag.length,
|
|
286
|
+
invalidTag,
|
|
287
|
+
danglingJobRefCount: danglingJobRefs.length,
|
|
288
|
+
danglingJobRefs,
|
|
289
|
+
verdict: totalFindings === 0
|
|
290
|
+
? 'CLEAN: every Epic agentType/tag and queue epicId/sourcePromptId reference resolves.'
|
|
291
|
+
: 'INVESTIGATE: dangling reference(s) found — advisory only, no repair performed (see ops-maintenance-protocol.md).',
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function main() {
|
|
296
|
+
const c = auditPatternC();
|
|
297
|
+
const d = auditPatternD();
|
|
298
|
+
const e = auditPatternE();
|
|
299
|
+
const f = auditPatternF();
|
|
300
|
+
|
|
301
|
+
console.log('=== Pattern C: flat scheduler/prds/ ===');
|
|
302
|
+
console.log(` top-level .md files: ${c.flatTopLevelMdCount}`);
|
|
303
|
+
console.log(` prds-archived/ .md files: ${c.archivedCount}`);
|
|
304
|
+
console.log(` queue jobs referencing flat dir: ${c.queueJobsReferencingFlatDir.length}`);
|
|
305
|
+
console.log(` verdict: ${c.verdict}`);
|
|
306
|
+
console.log();
|
|
307
|
+
console.log('=== Pattern D: orphaned prompt-sessions/*.json ===');
|
|
308
|
+
console.log(` top-level files: ${d.toplevelCount}, epics/ dirs: ${d.epicDirsCount}`);
|
|
309
|
+
console.log(` never-started (safe, no PRD history): ${d.neverStarted.length}`);
|
|
310
|
+
console.log(` accounted-for-elsewhere (PRD landed under a differently-named epics/ dir): ${d.accountedForElsewhere.length}`);
|
|
311
|
+
console.log(` DATA LOSS candidates (PRD history, no PRD file found anywhere): ${d.dataLoss.length}`);
|
|
312
|
+
if (d.dataLoss.length > 0) {
|
|
313
|
+
for (const r of d.dataLoss) console.log(` ESCALATE: ${r.id} (${r.prdCreatedCount} prd_created event(s))`);
|
|
314
|
+
}
|
|
315
|
+
if (d.unreadable.length > 0) console.log(` unreadable: ${d.unreadable.join(', ')}`);
|
|
316
|
+
console.log();
|
|
317
|
+
console.log('=== Pattern E: hand-authored PRDs (bypassed scheduler_create_prd) ===');
|
|
318
|
+
console.log(` PRDs checked: ${e.checkedCount}`);
|
|
319
|
+
console.log(` unattributed (no matching prd_create audit event): ${e.unattributedCount}`);
|
|
320
|
+
if (e.unattributed.length > 0) {
|
|
321
|
+
for (const u of e.unattributed) console.log(` FLAG: ${u.file}`);
|
|
322
|
+
}
|
|
323
|
+
console.log(` verdict: ${e.verdict}`);
|
|
324
|
+
console.log();
|
|
325
|
+
console.log('=== Pattern F: referential integrity (agentType / tag / queue epicId+sourcePromptId) ===');
|
|
326
|
+
console.log(` dangling agentType refs: ${f.danglingAgentTypeCount}`);
|
|
327
|
+
if (f.danglingAgentType.length > 0) {
|
|
328
|
+
for (const r of f.danglingAgentType) console.log(` FLAG: Epic ${r.epicId} -> agentType '${r.agentType}'`);
|
|
329
|
+
}
|
|
330
|
+
console.log(` invalid tag values: ${f.invalidTagCount}`);
|
|
331
|
+
if (f.invalidTag.length > 0) {
|
|
332
|
+
for (const r of f.invalidTag) console.log(` FLAG: Epic ${r.epicId} -> tag '${r.tag}'`);
|
|
333
|
+
}
|
|
334
|
+
console.log(` dangling queue job refs: ${f.danglingJobRefCount}`);
|
|
335
|
+
if (f.danglingJobRefs.length > 0) {
|
|
336
|
+
for (const r of f.danglingJobRefs) console.log(` FLAG: job ${r.jobId ?? '(no slug)'} -> ${r.field} '${r.value}'`);
|
|
337
|
+
}
|
|
338
|
+
console.log(` verdict: ${f.verdict}`);
|
|
339
|
+
|
|
340
|
+
return { patternC: c, patternD: d, patternE: e, patternF: f };
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (require.main === module) {
|
|
344
|
+
const result = main();
|
|
345
|
+
if (process.env.AUDIT_JSON_OUT) {
|
|
346
|
+
fs.writeFileSync(process.env.AUDIT_JSON_OUT, JSON.stringify(result, null, 2));
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
module.exports = { auditPatternC, auditPatternD, auditPatternE, auditPatternF };
|
|
@@ -67,36 +67,13 @@
|
|
|
67
67
|
* guard row (src/main/lib/delegationReadiness.cjs's installDestructiveGitGuard,
|
|
68
68
|
* which merges into any existing hooks block instead of clobbering it).
|
|
69
69
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* the hook runs with THIS repo as cwd. Pasting that relative string into
|
|
78
|
-
* another project yields a hook that exits non-zero WITHOUT code 2 — a
|
|
79
|
-
* non-blocking error — so it silently guards nothing. Any other project's
|
|
80
|
-
* `.claude/settings.json` must reference this file by its ABSOLUTE path:
|
|
81
|
-
*
|
|
82
|
-
* {
|
|
83
|
-
* "hooks": {
|
|
84
|
-
* "PreToolUse": [
|
|
85
|
-
* {
|
|
86
|
-
* "matcher": "Bash",
|
|
87
|
-
* "hooks": [
|
|
88
|
-
* {
|
|
89
|
-
* "type": "command",
|
|
90
|
-
* "command": "node /home/bilko/Projects/session-manager/scripts/hooks/guard-destructive-git.cjs"
|
|
91
|
-
* }
|
|
92
|
-
* ]
|
|
93
|
-
* }
|
|
94
|
-
* ]
|
|
95
|
-
* }
|
|
96
|
-
* }
|
|
97
|
-
*
|
|
98
|
-
* This is still opt-in per project, same as above — never auto-install this
|
|
99
|
-
* into every project's settings without the human choosing to add it there.
|
|
70
|
+
* Adopted by REFERENCE through the stable shim
|
|
71
|
+
* `~/.claude/session-manager/hooks/guard-destructive-git.cjs`, written by
|
|
72
|
+
* src/main/lib/guardShims.cjs (installed by src/main/lib/delegationReadiness.cjs).
|
|
73
|
+
* The shim carries no guard logic — it reads `app-root.json` and require()s this
|
|
74
|
+
* file from the currently running app, so an app upgrade never breaks an adopter.
|
|
75
|
+
* Never vendor: do not copy this file into another repo, and do not hardcode an
|
|
76
|
+
* absolute path to it in another project's `.claude/settings.json`.
|
|
100
77
|
*
|
|
101
78
|
* ── Uninstall ────────────────────────────────────────────────────────────
|
|
102
79
|
* Remove the `PreToolUse` entry above from `.claude/settings.json`. The
|
|
@@ -121,10 +98,9 @@ const { execFileSync } = require('node:child_process');
|
|
|
121
98
|
|
|
122
99
|
// Duplicated from src/main/lib/gitWorktree.cjs's KIND_CONFIG — see this
|
|
123
100
|
// file's header for why this is a deliberate duplication, not a require.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
];
|
|
101
|
+
// Same SM_WORKTREE_ROOT-else-tmpdir base as schedulerPaths.worktreeBase().
|
|
102
|
+
const WORKTREE_BASE = process.env.SM_WORKTREE_ROOT || os.tmpdir();
|
|
103
|
+
const WORKTREE_ROOTS = ['job', 'epic'].map((k) => path.join(WORKTREE_BASE, `session-manager-${k}-worktrees`));
|
|
128
104
|
const BRANCH_PREFIXES = ['sm-job/', 'sm-epic/'];
|
|
129
105
|
|
|
130
106
|
const MAX_SH_C_DEPTH = 5;
|
|
@@ -28,14 +28,13 @@
|
|
|
28
28
|
* everything for that one Epic only.
|
|
29
29
|
*
|
|
30
30
|
* ── Install (per-project, NOT machine-wide) ─────────────────────────────
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* running — add the command alongside guard-prd-writes.cjs in the SAME
|
|
31
|
+
* Adopted by REFERENCE through the stable shim
|
|
32
|
+
* `~/.claude/session-manager/hooks/guard-inline-implementation.cjs`, written by
|
|
33
|
+
* src/main/lib/guardShims.cjs (installed by src/main/lib/delegationReadiness.cjs's
|
|
34
|
+
* installInlineImplementationGuard(), via "Fix it" on the New Epic readiness
|
|
35
|
+
* banner). Never vendor: do not copy this file or hardcode an absolute path to it.
|
|
36
|
+
* The example below is THIS repo's own `.claude/settings.json` (relative command,
|
|
37
|
+
* cwd = repo root); add the command alongside guard-prd-writes.cjs in the SAME
|
|
39
38
|
* `Write|Edit|NotebookEdit` matcher's `hooks` array:
|
|
40
39
|
*
|
|
41
40
|
* {
|
|
@@ -78,6 +77,8 @@
|
|
|
78
77
|
const fs = require('node:fs');
|
|
79
78
|
const path = require('node:path');
|
|
80
79
|
const { execFileSync } = require('node:child_process');
|
|
80
|
+
// Pure fs helper only — deliberately NOT gitWorktree (keeps this hook light).
|
|
81
|
+
const { nearestGitEntry } = require('../../src/main/lib/cwdClassify.cjs');
|
|
81
82
|
|
|
82
83
|
const SOURCE_DIRS = ['src', 'scripts', 'plugins', 'bin'];
|
|
83
84
|
const DENY_TAGS = new Set(['feature', 'bug']);
|
|
@@ -122,6 +123,11 @@ function resolveOpsRootCwd(rawCwd) {
|
|
|
122
123
|
return rawCwd;
|
|
123
124
|
}
|
|
124
125
|
try {
|
|
126
|
+
// Only a `.git` FILE (linked worktree) needs git to find the shared dir; a
|
|
127
|
+
// `.git` directory IS the project root, so skip the spawn.
|
|
128
|
+
const entry = nearestGitEntry(rawCwd);
|
|
129
|
+
if (!entry) return rawCwd;
|
|
130
|
+
if (!entry.isFile) return entry.dir;
|
|
125
131
|
const commonDir = execFileSync(
|
|
126
132
|
'git',
|
|
127
133
|
['rev-parse', '--path-format=absolute', '--git-common-dir'],
|
|
@@ -43,42 +43,13 @@
|
|
|
43
43
|
* row (src/main/lib/delegationReadiness.cjs's installPrdWriteGuard, which
|
|
44
44
|
* merges into any existing hooks block instead of clobbering it).
|
|
45
45
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* `node scripts/hooks/guard-prd-writes.cjs` command only resolves when the
|
|
54
|
-
* hook runs with THIS repo as cwd. Pasting that relative string into another
|
|
55
|
-
* project yields a hook that exits non-zero WITHOUT code 2 — a non-blocking
|
|
56
|
-
* error — so it silently guards nothing. Any other project's
|
|
57
|
-
* `.claude/settings.json` must reference this file by its ABSOLUTE path:
|
|
58
|
-
*
|
|
59
|
-
* {
|
|
60
|
-
* "hooks": {
|
|
61
|
-
* "PreToolUse": [
|
|
62
|
-
* {
|
|
63
|
-
* "matcher": "Write|Edit|NotebookEdit",
|
|
64
|
-
* "hooks": [
|
|
65
|
-
* {
|
|
66
|
-
* "type": "command",
|
|
67
|
-
* "command": "node /home/bilko/Projects/session-manager/scripts/hooks/guard-prd-writes.cjs"
|
|
68
|
-
* }
|
|
69
|
-
* ]
|
|
70
|
-
* }
|
|
71
|
-
* ]
|
|
72
|
-
* }
|
|
73
|
-
* }
|
|
74
|
-
*
|
|
75
|
-
* This is still opt-in per project, same as above — never auto-install this
|
|
76
|
-
* into every project's settings without the human choosing to add it there.
|
|
77
|
-
*
|
|
78
|
-
* Roll out to another project by copying this file + the same settings.json
|
|
79
|
-
* entry into that project — deliberately not published as a global/user-
|
|
80
|
-
* scoped hook so a project can opt in individually (see this PRD's
|
|
81
|
-
* Implementation notes: "scope the hook to the session-manager repo first").
|
|
46
|
+
* Adopted by REFERENCE through the stable shim
|
|
47
|
+
* `~/.claude/session-manager/hooks/guard-prd-writes.cjs`, written by
|
|
48
|
+
* src/main/lib/guardShims.cjs (installed by src/main/lib/delegationReadiness.cjs).
|
|
49
|
+
* The shim carries no guard logic — it reads `app-root.json` and require()s this
|
|
50
|
+
* file from the currently running app, so an app upgrade never breaks an adopter.
|
|
51
|
+
* Never vendor: do not copy this file into another repo, and do not hardcode an
|
|
52
|
+
* absolute path to it in another project's `.claude/settings.json`.
|
|
82
53
|
*
|
|
83
54
|
* ── Uninstall ────────────────────────────────────────────────────────────
|
|
84
55
|
* Remove the `PreToolUse` entry above from `.claude/settings.json`. The
|